( search forums )
Deleted Topic
Soldat Forums - -
Deleted User
November 30, 1999, 12:00 am

Deleted User
February 10, 2005, 3:56 pm
ok, after an entire day to sniffing packets and reversing i have the full structure of the REFRESH data...

tnx anyway :)

Deleted User
February 17, 2005, 10:47 am
i'm going to post the structure i found, too many emails, i can't reply to all of you! :)

struct NicksString {
char iSize;
char Nickname[24];
};

struct Ips {
UCHAR piece[4];
};

struct NetworkPacket {
CHAR cCommand[8];
NicksString sPlayers[32];
CHAR iPlayersTeamID[32]; // -1 means inactive player
WORD iPlayersScores[32];
WORD iPlayersDeaths[32];
UCHAR iPlayersPings[32];
CHAR cPlayersID[32];
Ips iPlayersIP[32];
WORD iTeamsScore[4];
CHAR iMapNameSize;
CHAR cMapName[16];
DWORD TimeLimit; // /3600 for minutes
DWORD ActTime; // /3600 for minutes
WORD ScoreLimit;
CHAR GameMode;
};

bye! :-)

rusty
February 20, 2005, 10:06 pm
If it helps, I will be releasing the Java source code to SARJ soon with the next release - it's all commented in there pretty well.

Michal Marcinkowski
February 27, 2005, 1:48 pm
Here it is in Pascal code:

const
PLAYERNAME_CHARS = 24;

TMsg_Refresh = packed record
Name : array[1..32] of string[PLAYERNAME_CHARS];
Team : array[1..32] of byte;
Kills : array[1..32] of word;
Deaths : array[1..32] of word;
Ping : array[1..32] of byte;
Number : array[1..32] of byte;
IP : array[1..32,1..4] of byte;
TeamScore : array[1..4] of word;
MapName : string[16];
TimeLimit, CurrentTime : integer;
KillLimit : word;
GameStyle : byte;
end;

DeMo
July 9, 2005, 5:00 am
How did you decode the packets?
Cause they seem to be encripted in some way to me.. I've tried 2 packet sniffers and all the data they capture is just a lot of letters and numbers, I can't read anything!!

thelizno
July 12, 2005, 1:33 am
Im having probs with this aswell.

@ Michal, i get nothing out of that... to me it just looks like you are defining the variables?

Deleted User
July 12, 2005, 5:06 am
@thelizno
The packets arent encrypted... they are just packed together into decimal values... eg if my nickname is 13 characters long, there is 0D HEX 1 byte before my player name in the packet, 0D is HEX for 13, same thing applies for each of the other players names. All the 00's after the last player are just blank buffer space for any unfilled server space. Near the end of the packet you will find the other things such as the current map, 1 byte before the current map there is a HEX value of the length of the map name... all the other elements are decimal values converted to HEX, maximum value is 255 (FF). The code Michal posted is basically the order which you may find each of the values retrieved from the REFRESH command.

If you dont understand that, you might aswell forget about parsing the 'REFRESH' packet.

thelizno
July 12, 2005, 11:51 am
i see EnEsCe. i've managed to extract the data.. i just don't find a good solution for doing this.
thanks for your answer :))



quote:Originally posted by EnEsCe

If you dont understand that, you might aswell forget about parsing the 'REFRESH' packet.


no need to be a (Please refrain from swearing). im wont quit until i get this to work. :)
... there are of course alternatives to parsing it. but none that would work as good.

DeMo
July 12, 2005, 11:05 pm
How did u do it thelizno?
Look at my packet sniffer.. all stuff it captures seems to be encrypted.

This picture shows a packet received from the server during gameplay.
[IMAGE]

Deleted User
July 12, 2005, 11:14 pm
roflmao, thats not the refresh packet... AHHAHA

The refresh packet comes from the admin clients TCP connection, not Soldats UDP connection...
*Points at text in image saying "UDP Source"*

DeMo
July 13, 2005, 1:24 am
Yeah.. I was looking at the manual and them I saw that Admin works via TCP, not UDP.

I was trying to develop a standalone server browser.. something you could add your favorite servers and them see their status (game mode, map, players, scores...). This way you could choose and join a server without having to use Soldat's built-in server browser. Then, in a more advanced version I could even parse the lobby server response and get info for all servers.

There is an UDP port just for this.. usually the number is gameport+123, so it is 23196 for servers running on 23073, 23197 for servers on 23074 and so on. Problem is.. most people (and server admins) don't even know this port exists and it remains blocked on their router/firewall, and my browser can't access it to get the game info. :(

I was looking for an alternate way to get the info, and this REFRESH command seemed a nice one. But since it runs on the admin module (and needs the admin password), it won't work anyway.

Maybe Michal could provide the game info on the game port (UDP) after receiving a specified (non encrypted) command such as "INFO" or "GAMEINFO". Or maybe he could adda note to the manual so that server admins will enable gameport+123 on their router/firewall.

Deleted User
July 13, 2005, 2:59 am
OR you could use ASE protocol to query the server if the server has ASE enabled. (And if ASE becomes fully compatible with the dedicated server)

DeMo
July 13, 2005, 5:20 am
I think that's exactly what I'm doing.
This port (gameport+123) is in fact the ASE query port.

But I think that the server having ASE enabled isn't enough, they have to enable it and allow incoming connections to that port.

ramirez
September 27, 2005, 1:12 pm
I have absolutely NO idea who wrote that struct above, but it is wrong, wrong and wrong.
First of all, the REFRESH packet size is 1188, even assuming that the guy realized that compilers usually pack structs using different packing alignment than 1 (except if explicitly configured in the compiler options), the packet's size would not match (it's 1196, thus 8 bytes too much, which comes from the "cCommand", I assume that this space is reserved for "REFRESH" + the terminating null character, but anyone who has dealt with Soldat admin connection knows that you first read the REFRESH from the stream, and after that you read the actual packet).
Well, like I said, the biggest problem is the byte alignment for packing, most compilers uses alignment of 8 byte boundary by default, which would result for that struct to take actually 1200 bytes instead of the intended 1196, and as you might expect, that makes things not work as they should.

Anyway, if anyone wants a working C/C++ struct for the refresh packet, here's one I wrote for my own tools:
[code]typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;

#pragma pack(push, 1)
struct RefreshPacket {
struct {
byte iLen;
char cName[24];
} sName[32];
byte iTeam[32];
word iKills[32];
word iDeaths[32];
byte iPing[32];
byte iNumber[32];
union {
dword iLong;
byte iPiece[4];
} uIp[32];
word iTeamScore[4];
struct {
byte iLen;
char cMap[16];
} sMap;
dword iTimeLimit;
dword iCurrentTime;
word iKillLimit;
byte iGameStyle;
};
#pragma pack(pop)[/code]
It uses #pragma pack to set the packing alignment to 1 byte boundary (note that it only affects RefreshPacket struct, due to pushing the current packing value to the internal compiler stack first, and then retrieving it by popping it). Most (if not all) compilers support this pragma (MSVC, GCC based compilers etc.), if yours doesn't you can just set the packing alignment to 1 from the compiler settings, but note that this will affect all structs/unions/etc. you have.