For those interested in a bit on how SIGS worked, here's what I've found out. This info was extracted from a CD install of OP2 with the 3 official updated applied.
It uses TCP connections for all communications. It breaks and remakes connections depending on what it's doing, and can have more than one active connection.
A total of 118 messages are used. Each message has from 0 to 23 data fields, with a total of 342 data fields across all messages. The number of data fields of each type breaks down as follows:
int (big endian) : 131
float : 1
short (big endian) : 10
char : 28
string (null terminated) : 164
buffer (4 byte length prefixed) : 8
The exact data format (in terms of what type of data fields are used, and the order they are in) is known for each packet type. Although, there are a few packets where the client tries to unpack fields that apparently don't exist.
Despite the above, the meaning of each field is still unknown for the majority of the data fields. So although we know a certain packet has an int followed by a string in it, it is still unknown what the packet as a whole means, what the int means, and what the string data type is supposed to hold.
The client is extremely sensitive to correct data being returned. If incorrect data is returned, or an expected packet is not received, the client will most likely either hang or crash.
A simple test server has been written with hardcoded responses to each received packet from the client in an attempt to discover more about how the protocol works. This simple test server is nowhere close to what needs to be written for a real server though. To change what it returns requires a recompile. Further, it takes two instances of the test server running to handle one connecting client (and doesn't share data between the two instances). The only purpose to this server is to see how the client reacts to different messages in an attempt to figure out how the protocol works.
The simple test server can fool the client into getting through basic login and an initial room join. Images of the various clients states can be found
here.
After version checking and login, the client goes into a receive loop for the lobby server. From there, it can process 22 message types. Of these messages, about 15 are fairly well understood.
When a room is joined, the client goes into a receive loop for the room server. From here it can process 23 message types. Of these messages, about 11 are fairly well understood.
Although some of the packets for creating and joining games are known, the data fields for these packets are largely unknown and no successful game create or game join has been accomplished at this point.
There are 7 known message receive loops, not including the version check/update and login process. Of these 1 is not used, but simply serves as a really basic model for the others to follow (think inheritance), leaving 6 message receive loops to consider. It appears 3 of them are for the lobby server, room server, and game server. The remaining receive loops only handle 2 or 3 messages. There seems to be code for opening UDP sockets in the client, but it is not known how to use UDP, or if this is even active code.
The SIGS DLLs appear to have been written with an MS C++ compiler with exception handling turned on. There is a lot of copying data around along with constructor and destructor calls. This combined with the exception handling code makes for much harder code to read. It's also frustrating to see a string get copied 3 times before it's actually used (or sometimes ignored), largely through a series of automatic constructor calls that were probably inserted by the compiler. There is also heavy use of classes and inheritance, Windows API calls, callback functions, and window message handling. Suffice it to say it's not the easiest code to read through.
Edit: Updated UDP assumptions.