Jump to content

Query servers


xestre

Recommended Posts

Recently I started getting into server queries, attempting to retrieve data from game servers. I started with the source games (think of CS:S, TF2 etc etc) and it works quite well my script shown below.

 



<?php
$handle = fsockopen("udp://127.0.0.1", 7777, $errno, $errstr);
stream_set_timeout($handle, 2);
fwrite($handle, "\xff\xff\xff\xff\x54\x53\x6f\x75\x72\x63\x65\x20\x45\x6e\x67\x69\x6e\x65\x20\x51\x75\x65\x72\x79\x00");
$response = fread($handle, 256);
echo $response;
?>


 

https://developer.valvesoftware.com/wiki/Server_queries#A2S_INFO you'll see what is needed in order to request data.

 

However the problem arises when I want to query an other game, that is not of the source engine. Given the picture below.

 

lfsLtpU.png

 

It needs to be a non-blocking UDP connection, but I've got no idea how to create such request. I know that for the first 3 bytes I need: 0x4d, 0x49, 0x56, however how I do continue? Can someone help me out with PHP? 

 

Thanks in advance.

 

 

Link to comment
Share on other sites

  • 3 months later...

Bump. Curious too, I am writing socket code atm, trying to get a generic code for multiple games but having no luck due to the variables are different for each game, though I would of expected some kind of standardisation with the variables ie host, server_type, players, max_player, name etc.  One thing I do keep running into is: $port is a reserved variable so be aware of that if you are running through a function or set a constant.

 

The code you have provided for TF2 gives output: 

ITF2 Servercp_dustbowltfTeam Fortressdw2198641i%8@TF2Stats,alltalk,cp,increased_maxplayers,norespawntime,respawntimes

But I have noticed for games like Minecraft they use the tcp:// other then the udp:// as shown below (requires a handshake):

@stream_socket_client('tcp://'.$url.':'.$xport, $errno, $errstr, 1)

Also not 100% on the hex command lines, these would also vary per server type (I assume): http://ddecode.com/hexdecoder/?results=552bf941214641e4743cf5709401132a

\xff\xff\xff\xff\x54\x53\x6f\x75\x72\x63\x65\x20\x45\x6e\x67\x69\x6e\x65\x20\x51\x75\x65\x72\x79\x00

This is details for Steam queries for source engine/valve (I don't know how to make use of it): https://developer.valvesoftware.com/wiki/Server_queries

 

Wish us both luck. If I find something I'll share it. If any GURU's out there that know about sockets look forward in hearing from you too.

Link to comment
Share on other sites

I prefer to make PHP classes that resemble the structures/packets you'll be using to query a server. You can then either use the __toString or make a pack method that will generate the byte sequences that need sent. For example for the Source server header packet might be represented as such:

class SourceHeader {
	public $header;
	public $id;
	public $total;
	public $number;
	public $size;

	public function pack(){
		return pack("VVCCv", $this->header, $this->id, $this->total, $this->number, $this->size);
	}

	public static function createFromBuffer($buffer){
		$fields = unpack("Vheader/Vid/Ctotal/Cnumber/vsize", $buffer);
		$obj = new self;
		$obj->header = $fields['header'];
		$obj->id = $fields['id'];
		$obj->total = $fields['total'];
		$obj->number = $fields['number'];
		$obj->size = $fields['size'];
		return $obj;
	}
}
Of course you'll need to add some extra code to handle things like different versions possibly returning more or less fields. For example in the above if $obj->header&0x800000 == 1 then there are two additional fields size (another one separate from the one listed) and crc32 sum representing the size and checksum of the uncompressed data. Also the size field listed may or may not exist depending on the engine and it's version.

 

By making things classes like that though it helps keep things organized, readable, and lets you only have to mess with generating the binary strings in one place.

 

As for the UDP sockets, you'd just create one using stream_socket_client, send data using stream_socket_sendto, and read data using stream_socket_recvfrom. Such as:

$header = new SourceHeader;
$header->header = -1;

$socket = stream_socket_client('udp://game.server.address:port');
stream_socket_sendto($socket, $header->pack());
I've never messed with querying game servers, so I have no idea how exactly the interactions go for it. It has also been quite a while since I've done anything with UDP sockets, so the above is based on memory and a few minutes looking over the php and valve manuals. There are likely bugs that would need worked out, and definitally error handling that needs worked in.
Link to comment
Share on other sites

querying game servers is sort of tricky. One reason is due to the games changing engines which then makes any code you have not work right or at all.

 

For a reference as how to accomplish the task go to http://www.greycube.com/site/download.php?view.56

 

look into lgsl/lgsl_files/lgsl_class.php as well as lgsl/lgsl_files/lgsl_protocol.php

 

some of the queries are outdated due to engine changes for some games and some other games have been added that were not included in the download file but just search forums, you will find all the answers there.

 

 

good luck

Link to comment
Share on other sites

The data that can be returned from the different game server and the optional parameters that can be used when making those queries will vary greatly. But, instead of trying to build the low level code to make those connections and retrieve data, you might want to see if there is already something existing that supports all the game servers you want such as this: http://gameq.sourceforge.net/ (>170 games supported). Although, I see that there are several more current bames not supported (BF3 & BF4).

 

I would start with a package like that. Then for the other games you want to support, see if there are any similar existing packages. Then you can build a middle-tier class that will communicate with them all. E.g. based on the game data being requested, your class would determine which package to use and return the data in a consistent format. Then you would have just one interface for getting data.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.