Skip to content

Instantly share code, notes, and snippets.

@Neo-Desktop
Created August 1, 2020 14:55

Revisions

  1. Neo-Desktop created this gist Aug 1, 2020.
    110 changes: 110 additions & 0 deletions query.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,110 @@
    <?php

    const MASTER_SERVER = "master2.starsiege.pw";
    const MASTER_PORT = 29000;

    const PROTOCOL_VERSION = 0x10;
    const STATUS_REQUEST = 0x03;
    const GAME_SERVER_STATUS_RESPONSE = 0x04;
    const MASTER_SERVER_STATUS_RESPONSE = 0x06;
    const GAME_INFO_REQUEST = 0x07;
    const GAME_INFO_RESPONSE = 0x08;

    $query = queryMasterServer(MASTER_SERVER, MASTER_PORT);

    if (count($query['servers']) <= 0) {
    printf("Error server count was 0");
    exit;
    }
    printf("Acquired %d servers in %s ms\n", count($query['servers']), $query['request_duration']);


    $gameServers = [];
    $start = microtime(true);
    foreach ($query['servers'] as $id => $server) {
    $gameServers[] = queryGameServers($server["host"], $server["port"], $id);
    }
    $end = microtime(true);

    printf("Queried %d servers in %s ms\n", count($query['servers']), $end - $start);
    //print_r($gameServers);


    function queryMasterServer($host, $port, $requestID = 0) {
    $fp = @fsockopen("udp://".$host, $port, $errno, $errstr, 1);
    if (!$fp)
    {
    printf("Error opening socket to: %s:%d\nError#:%d\nError:%s", $host, $port, $errno, $errstr);
    return [];
    }

    //time the search
    $start = microtime(true);

    //request server info
    $request = pack("C4v2", PROTOCOL_VERSION, STATUS_REQUEST, 0xff, 0x00, $requestID, 0x00);
    fwrite($fp, $request, 8);
    $packet = [];
    $packet['header'] = fread($fp, 8);
    $packet['hostname_length'] = fread($fp, 1);
    $packet['motd'] = "";
    do {
    $byte = fread($fp, 1);
    if (ord($byte) > 0) {
    $packet['motd'] .= $byte;
    }
    }
    while (ord($byte) != 0);

    $packet['server_count'] = ord(fread($fp, 1));
    $packet['servers'] = [];
    for ($i=0; $i < $packet['server_count']; $i++) {
    fread($fp, 1); // separator \0x06

    $ip = sprintf("%d.%d.%d.%d", unpack("C", fread($fp, 1))[1], unpack("C", fread($fp, 1))[1], unpack("C", fread($fp, 1))[1], unpack("C", fread($fp, 1))[1]);
    $packet['servers'][$i]["host"] = ($ip == "127.0.0.1") ? $host : $ip;
    $packet['servers'][$i]["port"] = unpack("v", fread($fp, 2))[1];
    }

    $end = microtime(true);
    $packet['request_duration'] = $end - $start;

    fclose($fp);
    return $packet;
    }

    function queryGameServers($host, $port, $requestID = 0) {
    $fp = @fsockopen("udp://".$host, $port, $errno, $errstr, 1);
    if (!$fp)
    {
    printf("Error opening socket to: %s:%d\nError#:%d\nError:%s", $host, $port, $errno, $errstr);
    return [];
    }
    // socket_set_timeout($fp, 1, 500);

    printf("\tQuerying %s:%d\n", $host, $port);

    //time the search
    $start = microtime(true);

    //request server info
    $request = pack("C4v2", PROTOCOL_VERSION, STATUS_REQUEST, 0xff, 0x00, $requestID, 0x00);
    fwrite($fp, $request, 8);

    // fixed packet size: 40 bytes
    $packet['header'] = fread($fp, 06); // header (6 bytes)
    $packet['status_bytes'] = fread($fp, 07); // status (7 bytes)
    $packet['version'] = fread($fp, 10); // game server version string (10 bytes)
    $packet['server_name'] = fread($fp, 17); // server name (23 bytes)

    //request game info
    // $request = pack("C4v2", PROTOCOL_VERSION, GAME_INFO_REQUEST, 0xff, 0x00, $requestID, 0x00);
    // fwrite($fp, $request, 8);

    $end = microtime(true);
    $packet["request_duration"] = $end - $start;

    fclose($fp);

    return $packet;
    }