Transport 2 SDK
From GameSpy SDK
Transport 2 SDK
Overview
The GameSpy Transport SDK 2 (GT2) is a library that allows two applications to communicate over the Internet, making use of UDP for both reliable and unreliable messaging. It can be used to write any sort of networked application, including both peer-to-peer and dedicated server games. Someone with little or no networking experience can easily learn GT2, without having to learn all the complexities of Sockets/Winsock, and without having to deal with all the overhead involved in DirectPlay.
GT2 is basic enough to be easily and quickly added to an application, while also being powerful and flexible enough to fit within virtually any networking architecture. And, because GT2 is at a lower level than something like DirectPlay, it is extremely efficient in its use of memory, bandwidth, and processor time. So, GT2 delivers optimal performance, in a simple API, while avoiding the hidden traps involved in low level libraries such as Sockets/Winsock and cutting out the overhead and loss of flexibility that comes with a higher level library such as DirectPlay.
The SDK is written in standard ANSI C and has been tested on Win32, Unix, Mac, and consoles. The library has been designed to be easy to use, fast, and memory efficient (particularly useful on console systems with tight memory requirements). Just include all of the source files in your project, and you can start easily communicating over the Internet.
The SDK also includes five samples. gt2testc is a simple ANSI C sample that is good for testing without a graphical interface (e.g., on a console), gt2test is a Windows MFC sample that is good for testing all the various features of GT2, gt2proxy is a GT2 proxy, gt2hostmig shows host migration using GT2 and, optionally, the Query & Reporting SDK, and gt2action is a sample game that uses GT2 for it's networking.
The rest of this document presents a simple set of instructions for using GT2. See the reference documentation for more detailed information on each function.
File Manifest
The following files should be included with this package. If any of the files are missing, please contact devsupport@gamespy.com.
- File
- Description
- gt2.h
- GT2 header (all user functions are prototyped here)
- gt2Main.c,h
- The main entry point for most GT2 functionality
- gt2Auth.c,h
- This code deals with authentication during connection negotiation
- gt2Buffer.c,h
- Code that deals with reading/writing from buffers
- gt2Callback.c,h
- Code for calling callbacks
- gt2Connection.c,h
- This code manages GTConnection objects
- gt2Encode.c,h
- Sub-library for encoding/decoding messages in a binary format
- gt2Filter.c,h
- This code manages filtering
- gt2Message.c,h
- Code for sending and receiving messages
- gt2Socket.c,h
- This code manages GTSocket objects
- gt2Utility.c,h
- Code for various utility functions such as the address functions
- nonport.c,h
- Platform-specific code
- darray.c,h
- Code for managing dynamic arrays
- hastable.c,h
- Code for managing hashtables
- /gt2testc/
- ANSI-C sample
- /gt2test/
- Windows MFC sample
- /gt2proxy/
- GT2 Proxy Sample
- /gt2hostmig/
- GT2 Host-migration sample
- /gt2nat/
- GT2 Socket Sharing sample. The GT2Socket's underlying socket is also used to do server reporting through the GameSpy Query and Reporting SDK
- /gt2action/
- A real-time multiplayer game that uses GT.
- GT2Action requires GLUT, a ccross-platform utility library that provides windowing for OpenGL applications. The officla GLUT site is http://www.opengl.org/developers/documentation/glut.html. GLUT for Windows is available at http://www.xmission.com/~nate/glut.html.
Implementation
Sockets and Connections
There are just two object types used by GT2: GT2Socket and GT2Connection. A GT2Socket object ("socket") represents a UDP socket on the local machine, and a GT2Connection object ("connection") represents a connection, or link, between two GT2Socket's (in other words, two applications). For most applications, only one socket needs to be created. All incoming connections can be accepted on the socket, and all outgoing connections can be made using the socket.
Thinking
In order for GT2 to do necessary processing on sockets and connections, the program must allow it to frequently "think". This is done by calling gt2Think, which will process the socket that is passed to it, along with all of that socket's connections. Within gt2Think, GT2 will check for new incoming connections on sockets that are listening for connections, do any negotiationing needed for pending connections, check for incoming data on connections, check for closed connections, and send any data buffered for a connection.
Internet Addresses
When creating a socket you can optionally specify the IP/hostname and/or port to use on the local machine. You also must specify the IP and port of the remote system being connected to when initiating a connection. These addresses are specified as strings of the form "[IP | hostname][:port]". In other words, if there is a colon in the string, the part before the colon is the IP/hostname, and the part after the colon is the port. If there is no colon, then the whole string is the IP/hostname. When specifying a local address, both the IP/hostname and port are optional. If the IP is not present, then no local IP will be bound to. If the port is not present, then the system will pick an available port to bind to. The utility functions gt2AddressToString and gt2StringToAddress are provided to allow for conversion from a string to an IP and port, and vice versa.
Byte Order
Because the order of the bytes inside a multi-byte variable (such as an int or a short) can vary from system to system, there is the concept of a "network byte order" and a "host byte order". The host byte order is the byte ordering scheme use on the local machine, and network byte order is the byte ordering scheme that is the standard for networking and, specifically, the Internet. In several GT2 functions and callbacks, an IP address and port number are passed around. Whenever GT2 deals with an IP address, it passes it or expects it in NETWORK byte order, and whenever GT2 deals with a port, it passes it or expects it in HOST byte order.
The reason network byte ordering is used for IP addresses is that this is the standard used by the sockets/Winsock functions, and this ensures that the first byte pointed to is the first number in the dotted IP, the second byte is the second number, and so on. The reason host byte ordering is used for port numbers is that this enables the application to pass port numbers directly between it's interface and GT2, or hardcode in a port number (for example with a define), without having to do any byte order conversions.
Byte ordering must also be taken into consideration when sending multi-byte variables in GT2 messages. The safest way to send an int or a short is to use the GT2 byte ordering functions to convert the numbers to network byte order when sending them, then converting them back to host byte order when they are received. This allows one code path to handle sending data between machines that use either the same or different byte ordering schemes.
AdHoc Support
AdHoc is supported in order to allow developers to write to a common layer for both adhoc and infrastructure modes on a hand held console. Adhoc support is provided through an adhoc specific gt2CreateSocket function, gt2CreateAdHocSocket. AdHoc sockets use MAC addresses instead of IP addresses to determining end points. Two functions gt2IpToMac and gt2MacToIP are used to convert back and forth between MAC addresses and IPs. GT2 stores internally a table to convert fully back to 48 bit mac from a 32 bit IP. Always call gt2MacToIP when dealing with a new MAC address, as this the address into the table. Aside from that, gt2 is used entirely the same as in infrastructure (regular IP) mode.
Sockets
A socket is an endpoint on the local machine that allows an application to communicate with other applications (through their own sockets) that are typically on remote machines, although they can also be on the local machine (the other application will often be referred to as the "remote machine", even though technically it may be the same machine). A single socket allows an application to both accept connections from remote machines and make connections to remote machines. For most applications, only one socket needs to be created. All incoming connections can be accepted on the socket, and all outgoing connections can be made using the socket.
A socket is created with the gt2CreateSocket function. If the function returns GT2Success then the socket was successfully created and bound to the local address (if one was provided). The socket that the "socket" parameter points to is valid until it is closed with gt2CloseSocket, or an error is reported to the gt2SocketErrorCallback callback parameter. It is now ready to be used for making outgoing connections, and can be readied for allowing incoming connections by calling gt2Listen (see below). If the return result is anything other than GT2Success, GT2 was unable to create the socket.
GT2Result gt2CreateSocket ( GT2Socket * socket, const char * localAddress, int outgoingBufferSize, int incomingBufferSize, gt2SocketErrorCallback callback );
- socket
- This is a pointer to a GT2Socket variable where the socket will be stored.
- localAddress
- This is the address to bind to locally. Typically of the form ":<port>", e.g., ":7777". Can be NULL or "".
- outgoingBufferSize
- This is the byte size of the buffer for reliable outgoing messages.
- This is a per-connection buffer. Can be 0 to use the internal default.
- incomingBufferSize
- This is the byte size of the buffer for out-of-order reliable incoming messages.
- This is a per-connection buffer. Can be 0 to use the internal default.
- callback
- This callback is called if there is a fatal error with the socket.
gt2SocketErrorCallback
This callback is used to notify the application of a closed socket or fatal socket error condition. Once this callback returns, the socket and all of its connections are invalid and can no longer be used.
typedef void (* gt2SocketErrorCallback) ( GT2Socket socket );
- socket
- The socket that had the error
gt2CloseSocket
This function is used to close a socket and any of its connections. Neither the socket nor any of its connections can be used once this call returns. The socket's will all be hard-closed (see gt2CloseConnectionHard).
void gt2CloseSocket ( GT2Socket socket );
- socket
- The socket to be closed.
gt2Think
Does any thinking for this socket and its connections. Callbacks are typically called from within this function (although they can also be called from other places). It is possible that during this think the socket or any of its connections may be closed, so care must be taken if calling other GT2 functions immediately after thinking. The more frequently this function is called, the faster GT2 will be able to respond (and reply to) messages. The general rule is to call it at frequently as you can, although calling it faster than every 10-20 milliseconds is probably unnecessary. If you are using gt2Ping to measure ping times, then the accuracy of the latency measurement will increase with the frequency at which this function is called.
void gt2Think ( GT2Socket socket );
- socket
- The socket to let think.
gt2Listen
If you want to be able to accept incoming connections from over the Internet, you must first create a socket, then start listening on it with gt2Listen. A gt2ConnectAttemptCallback is provided to handle possible incoming connection attempts. As soon as this function is called, the socket can start accepting incoming connections. If an attempt is made to connect to this socket after gt2Listen is called on it, the callback will be called. If this function is called with a NULL callback the socket stops listening for incoming connection attempts.
void gt2Listen ( GT2Socket socket, gt2ConnectionAttemptCallback callback );
- socket
- The socket to start listening on.
- callback
- This callback is called when an incoming connection is attempted.
- Can be NULL to refuse incoming connection attempts (the default).
gt2ConnectAttemptCallback
This notifies the socket that a remote system is attempting a connection. The IP and port of the remote system is provided, along with an optional initial message, and a latency estimate. These can be used to validate/authenticate the connecting system. This connection must either be accepted with gt2Accept, or rejected with gt2Reject. These can be called from within this callback, however they do not need to be. They can be called at any time after this callback is received. This is very useful for systems that need to check with another machine to authenticate the user (such as for a CDKey system). The latency is only an estimate, however it can be used for things such as only allowing low-ping or high-ping users onto a server.
typedef void (* gt2ConnectAttemptCallback) ( GT2Socket socket, GT2Connection connection, unsigned int ip, unsigned short port, int latency, GT2Byte * message, int len );
- socket
- This is the socket to which someone is attempting to connect.
- connection
- This is the connection object for the incoming connection.
- ip
- The IP from which the connect attempt is coming.
- port
- The port from which the connect attempt is coming.
- latency
- An estimate of the round-trip time between the two machines (in milliseconds).
- message
- Optional initial data sent with the connect attempt. May be NULL.
- len
- Length of the initial data. May be 0.
gt2Accept
Accepts an incoming connection attempt. Once this has been called, the GT2Connection can be used normally. The connected callback member of the callbacks will be ignored, as it is only used when initiating a connection. If this returns GT2False, that means the connection was closed between when the gt2ConnectAttemptCallback was called, and the connection was accepted. This would be caused by a remote close, or a time-out if it took too long to accept the connection. In this case, the connection is closed and cannot be used.
GT2Bool gt2Accept ( GT2Connection connection, GT2ConnectionCallbacks * callbacks );
- connection
- The connection being accepted
- callbacks
- The set of callbacks associated with the connection
gt2Reject
Use this call to reject an incoming connection. An optional rejection message can be sent. The connection is closed after this call and cannot be used.
void gt2Reject ( GT2Connection connection, const GT2Byte * message, int len );
- connection
- The connection being rejected.
- message
- Rejection message. May be NULL. Note that a 7 byte header needs to be accounted for.
- len
- Length of the rejection message. May be 0.
- A len of -1 is equivalent to (strlen(message) + 1)
Connecting
The gt2Connect function is used to initiate a connection attempt to a remote socket on the Internet. After the remote socket is contacted, both it and the local connector will authenticate the other during a negotation phase. Once the remote socket accepts the connection attempt, the connection will be established. The connection lasts until the closed callback gets called, which can happen because one side closed the connection with gt2CloseConnection (or gt2CloseConnectionHard), there was some sort of error on the connection, or the socket either connection uses is closed.
This call returns GT2Success if there are no problems starting the connection attempt, otherwise the return values signals the reason for the failure. If this call is blocking (blocking set to GT2True), then the return value signals the result of the entire connection attempt: GT2Success means the attempt succeeded, any other value means it failed. If the result is GT2Sucess, then the GT2Connection variable pointed to by the connection parameter will be set to this connection's GT2Connection object.
If this call is blocking, and it fails, the GT2ConnectionCallbacks's connected callback may or may not be called. If there is some sort of initial failure (such as an error resolving the remote address, or allocating memory for the connection), the callback will not be called. If it fails after starting the negotiation process, then the callback will be called.
GT2Result gt2Connect ( GT2Socket socket, GT2Connection * connection, const char * remoteAddress, const GT2Byte * message, int len, int timeout, GT2ConnectionCallbacks * callbacks, GT2Bool blocking );
- socket
- The socket to use to make the connection attempt.
- connection
- Pointer to the variable that the connection object will be stored in.
- remoteAddress
- The address to connect to. Must contain an IP/hostname and port.
- Typically something like "myserver.someplace.com:12345"
- message
- Initial message. May be NULL. Note that a 7 byte header needs to be accounted for.
- len
- Length of the initial message. May be 0.
- A len of -1 is equivalent to (strlen(message) + 1)
- timeout
- Time in milliseconds to wait before aborting the attempt.
- If 0, keep trying until connected.
- callbacks
- The set of callbacks associated with the connection.
- blocking
- If GPTrue, don't return until the attempt has finished (success or failure).
typedef struct
{
gt2ConnectedCallback connected;
gt2ReceivedCallback received;
gt2ClosedCallback closed;
gt2PingCallback ping;
} GT2ConnectionCallbacks;
gt2ConnectedCallback
This callback is called when a connection attempt with gt2Connect finishes. If result is GT2Success, then this connection attempt succeeded. The connection object can now be used for sending/receiving messages. Any other result indicates connection failure, and the connection object cannot be used again after this callback returns. If the result is GT2Rejected, then message contains an optional rejection message sent by the listener. If result is not GT2Rejected, then message will be NULL and len will be 0.
typedef void (* gt2ConnectedCallback) ( GT2Connection connection, GT2ConnectResult result, GT2Byte * message, int len );
- connection
- The connection that just finished connecting.
- result
- The result of the connect attempt. See gt2.h for all possible values.
- Anything aside from GT2Success indicates failure.
- message
- If result is GT2Rejected, this is the rejection message. May be NULL.
- len
- If result is GT2Rejected, the length of the messasge. May be 0.
gt2ReceivedCallback
This callback is called when a message is sent from the remote system with a gt2Send. If the message is sent reliably, then it will always be received with this callback. If it is not sent reliably, then the message might not arrive, or might arrive out of order.
typedef void (* gt2ReceivedCallback) ( GT2Connection connection, GT2Byte * message, int len, GT2Bool reliable );
- connection
- The connection that received the message.
- message
- The message that was sent. May be NULL.
- len
- The length of the message. May be 0
- reliable
- Whether or not the message was sent reliably.
gt2ClosedCallback
This callback is called when the connection has been closed, which can be caused by either side calling gt2CloseConnection (or gt2CloseConnectionHard), either side closing the socket, or some sort of error. The connection cannot be used again once this callback returns.
typedef void (* gt2ClosedCallback) ( GT2Connection connection, GT2CloseReason reason );
- connection
- The connection that was closed.
- reason
- The reason that the connection closed. See gt2.h for all possible values.
gt2PingCallback
This callback is called when a response to a ping sent on this connection is received. It gives a measure of the time it takes for a datagram to make a round-trip from one connection to the other. The latency reported in this callback will typically be larger than that reported by using ICMP pings between the two machines (the "ping" program uses ICMP pings), because ICMP pings happen at a lower level in the operating system. However, the ping reported in this callback will much more accurately reflect the latency of the application, as the application's messages must go through the same path as these pings, as opposed to ICMP.
Because pings are unreliable, a ping sent with gt2Ping is not guaranteed to make it through the entire round-trip. So not every call to gt2Ping will result in this callback being called. In addition, unreliable messages may be repeated (although this is a very rare occurrence), which means this callback could be called multiple times for a single call to gt2Ping.
typedef void (* gt2PingCallback) ( GT2Connection connection, int latency );
- connection
- The connection that the ping was sent and received on.
- latency
- The round-trip time for the ping, in milliseconds.
Sending
Once a connection has been established, messages can be sent back and forth on it. To send a message, use the gt2Send function. If message is NULL or len is 0, then an empty message will be sent. When an empty message is received, message will be NULL and len will be 0. If the message is sent reliably, it is guaranteed to arrive, arrive only once, and arrive in order (relative to other reliable messages). If the message is sent unreliably, then it is not guaranteed to arrive, and if it does arrive, it is not guaranteed to arrive in order, or only once.
void gt2Send ( GT2Connection connection, const GT2Byte * message, int len, GT2Bool reliable );
- connection
- The connection on which to send the message.
- message
- The message to send. May be NULL. Note that a 7 byte header needs to be accounted for if messages are reliable.
- len
- The length of the message. May be 0
- reliable
- Whether or not the message was sent reliably.
Closing Connections
There are two different ways a connection can be closed: they can be closed normally, or they can be "hard" closed. When a connection is closed normally, the connection's state is set to closing (i.e., gt2GetConnectionState will return GT2Closing), and a message is sent to the remote side telling it that the connection is closing. When confirmation is received that the remote side has received the message, the message is marked as closed (gt2GetConnectionState will return GT2Closed), the connection's closed callback is called, then the connection is freed. Because this normal method of closing requires the closer to wait for confirmation from the remote side, the connection is not immediately fully closed or freed. If the connection is "hard" closed, then an (unreliable) message is sent to the remote side of the connection informing them that the connection is closed, the closed callback is called, then the connection is freed. Because it does not need to wait for confirmation, the connection can be freed sooner. However, if the message informing the remote side of the closure is lost, it may take the remote side some time to figure out that the connection was closed.
The remote side will typically find out either after trying to send a message that gets rejected locally (because the recipient has closed), or when the remote side's GT2 attempts to send a keep-alive message, which will also get rejected locally. The method to be used depends on the specifics of your application, but, in general, a normal close should be used when possible, as it will close the connection more gracefully, ensuring that both sides of the connection know that the connection is closed.
There are four functions that can be used for closing connections. Two of them do a normal close, and the other two do a hard close. Two of them close a single connection, and the other two close all of a socket's connections. The two functions that do hard closes will call the closed callback(s) from within the function, while the two that do normal closes will call the callback(s) at some later time.
void gt2CloseConnection(GT2Connection connection); void gt2CloseConnectionHard(GT2Connection connection); void gt2CloseAllConnections(GT2Socket socket); void gt2CloseAllConnectionsHard(GT2Socket socket);
- connection
- The connection to close.
- socket
- Close all of this socket's connections.
Filtering
GT2 allows an application to add one or more "filters" to any connection. These filters can either just monitor messages being sent and received, or they can actually modify the data before it gets sent or received. Any number of filters can be set on any connection, and the order of the filtering will be in the order they were added (oldest to newest). A filter is added by passing a callback to a function that adds the callback as either a send (gt2AddSendFilter) or receive (gt2AddReceiveFilter) filter. Then that callback will be called when a message is either sent or received (depending on what type of filter it is).
After a callback has been called, that filter it is responsible for letting GT2 know when its done with the message. This is done by calling either gt2FilteredSend for an outgoing message or gt2FilteredReceive for an incoming message. The filter has several options. If the filter does not call the appropriate function, then the message will be dropped (even if it was sent/received as reliable). The filter can call the appropriate function from within the callback with the same data that was passed into the callback. This will cause the message to continue without any modifications. Or, the filter can call the appropriate function with modified data, either from within the callback or at a later time.
gt2SendFilterCallback/gt2ReceiveFilterCallback
These are the filter callbacks, and are passed to gt2AddSendFilter/gt2AddReceiveFilter to be added as filters. The callbacks will be called in the order they were added. gt2FilteredSend or gt2FilteredReceive is typically called in response to one of these callbacks, either from within the callback, or at a later time. Note that if called after the callback has returned, the message pointer passed into the callback may no longer be valid. So if the message will be needed after the callback has returned, the data must be copied off.
typedef void (* gt2SendFilterCallback) ( GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable ); typedef void (* gt2ReceiveFilterCallback) ( GT2Connection connection, int filterID, GT2Byte * message, int len, GT2Bool reliable );
- connection
- The connection on which the message is being sent or was received.
- filterID
- The filterID for this callback.
- Must be passed to gt2FilteredSend/gt2FilteredReceive.
- Message
- The message that was sent/received. May be NULL.
- Note that for send, this is conts. but not receive.
- len
- The length of the message. May be 0.
- reliable
- Whether or not the message was sent or is being sent reliably.
gt2AddSendFilter/gt2AddReceiveFilter
These function are used to add a filter callback to the connection's filter list. The callback will get called with a message is either being sent or has been received. Callbacks will be called in the order they were added to the connection's filter list. These functions return GT2False if they were unable to add the filter to the list for any reason.
GT2Bool gt2AddSendFilter ( GT2Connection connection, gt2SendFilterCallback callback ); GT2Bool gt2AddReceiveFilter ( GT2Connection connection, gt2ReceiveFilterCallback callback );
- connection
- The connection on which the filter is being added.
- callback
- The callback to add to the filter list.
gt2RemoveSendFilter/gt2RemoveReceiveFilter
These functions are used to remove a filter callback from a connection's filter list. Filters should NOT be removed while a message is being filtered. If any are, filters could be skipped, or messages could be dropped. If the callback is NULL, all of the send or receive filters will be removed.
void gt2RemoveSendFilter ( GT2Connection connection, gt2SendFilterCallback callback ); void gt2RemoveReceiveFilter ( GT2Connection connection, gt2ReceiveFilterCallback callback );
- connection
- The connection on which the filter is being removed.
- callback
- The callback to remove from the filter list.
gt2FilteredSend/gt2FilteredReceive
These functions are used to pass on a message after a filter callback has been called. This will cause the message to either be passed to the next filter or, if this was the last filter, to be sent or received. If this is called from the filter callback, the message passed in can be the same message that was passed into the callback.
void gt2FilteredSend ( GT2Connection connection, int filterID, const GT2Byte * message, int len, GT2Bool reliable ); void gt2FilteredReceive ( GT2Connection connection, int filterID, GT2Byte * message, int len, GT2Bool reliable );
- connection
- The connection on which the message is being filtered.
- filterID
- This must be the same ID passed to the filter callback.
- Message
- The message being sent/received. May be NULL. Note that a 7 byte header needs to be accounted for when sending a reliable message.
- Note that for send, this is conts. but not receive.
- len
- The length of the message. May be 0.
- reliable
- For sending, this determines if the message should be sent reliably.
- For receiving, this determines if the message was received reliably.
- This value does not need to be the same value passed to the filter.
Encode/Decode
GT2 comes with an encode/decode sub-library that allows messages to be encoded with a format string into an array of bytes. For example, if a message consists of an int, a short, and a float, one function call can encode them into a 12 byte buffer (2 bytes for the message type, 4 for the int, 2 for the short, and 4 for the float). This array of bytes can then be sent as a regular GT2 message. On the other end of the connection, the message type can then be checked with gtEncodedMessageType. Once the correct type is determined, one function call can decode the 12 byte buffer into the original int, short, and float.
Format String
The format string used by the encoding function is simply a list of characters that signal what variable types are being encoded. For the full list of types, see gt2Encode.h. A sample format string for encoding an int, a short, a float, then a string would look like "iofs". GT2 supports encoding most of the standard C data types, regular C strings, wide strings, a "raw" array of bytes, and bits. If bits are adjacent in a format string, then they will be packed together.
gtEncodedMessageType
This function is used to determine the type of an encoded message stored in a buffer (such as a buffer passed to a gt2ReceivedCallback.
GTMessageType gtEncodedMessageType ( char * inBuffer );
- inBuffer
- The buffer/message from which to get the type.
gtEncode[NoType[V]
These functions are used to encode the message. They take a format string, a buffer to encode into, a buffer size, and then all of the parameters to be encoded. For gtEncode and gtEncodeNoType, the parameters are passed on the end of the function, and for gtEncodeV and gtEncodeNoTypeV, the parameters are passed in as an args list. gtEncode and gtEncodeV take a message type to encode at the start of the buffer, while gtEncodeNoType and gtEncodeNoTypeV do not encode a type. This can be used for messages that have an unknown number of arguments. The first part of the message is encoded with a type, and it also contains information that lets the other end of the connection know what the rest of the message will look like. Then the rest of the message is encoded without a type. These functions return the number of bytes written to the buffer, or -1 if there is not enough space in the buffer to encode the entire message.
int gtEncode ( GTMessageType msgType, const char * fmtString, char * outBuffer, int outLength, ... ); int gtEncodeV ( GTMessageType msgType, const char * fmtString, char * outBuffer, int outLength, va_list * args ); int gtEncodeNoType ( const char * fmtString, char * outBuffer, int outLength, ... ); int gtEncodeNoTypeV ( const char * fmtString, char * outBuffer, int outLength, va_list * args );
- msgType
- The type to encode in the message.
- fmtString
- The format string that determines how the message is encoded.
- outBuffer
- The buffer to encode into.
- outLength
- The length of the outBuffer.
- ../args
- The arguments that are encoded into the buffer according to the format string.
gtDecode[NoType][V]
These functions are used to decode an encoded message. They take a format string, a buffer to decode from, a buffer size, and then a set of parameters to decode into (as with the scanf functions). For gtDecode and gtDecodeNoType, the parameters are passed on the end of the function, and for gtDecodeV and gtDecodeNoTypeV, the parameters are passed in as an args list. gtDecode and gtDecodeV will skip over a 2 bytes message type at the start of the buffer, while gtDecodeNoType and gtDecodeNoTypeV do not skip anything. This can be used for messages that have an unknown number of arguments. First the message type is checked with gtEncodedMessageType, and the first part of the message decoded with gtDecode or gtDecodeV. This part of the message can then be used to determine the format of the rest of the message, which can then be decoded with one or more calls to gtDecodeNoType or gtDecodeNoTypeV. These functions return the number of bytes read from the buffer, or -1 if there was a problem with the buffer.
int gtDecode ( const char * fmtString, char * inBuffer, int inLength, ... ); int gtDecodeV ( const char * fmtString, char * inBuffer, int inLength, va_list * args ); int gtDecodeNoType ( const char * fmtString, char * inBuffer, int inLength, ... ); int gtDecodeNoTypeV ( const char * fmtString, char * inBuffer, int inLength, va_list * args );
- fmtString
- The format string that determines how the message is decoded.
- inBuffer
- The buffer to decode from.
- inLength
- The length of the decode buffer.
- ../args
- The decoded message parameters are stored in these arguments.
Socket Sharing
GT2 allows for a GT2Socket object to share its underlying socket, which allows it to be used for multiple purposes, such as using the socket for both GT2 and the GameSpy Query and Reporting SDK. The documentation below covers how the socket can be shared, see the Query and Reporting SDK documentation for the specifics on how to have it use the socket.
To get a GT2Socket object's underlying socket, use gt2GetSocketSOCKET. This socket will be valid until either gt2CloseSocket is called with the GT2Socket, or the GT2Socket's gt2SocketErrorCallback gets called. For systems where SOCKET is not natively defined, it is defined in nonport.h (part of the GameSpy Common code), which is included by gt2.h.
SOCKET gt2GetSocketSOCKET ( GT2Socket socket );
- socket
- The GT2Socket for which to get the underlying socket.
gt2SetUnrecognizedMessageCallback
This is used to set a callback to be called everytime a socket receives a message that it cannot match up to an existing connection. If a GT2Socket object's underlying socket is being shared, this allows an application to check for data that was not meant for GT2. See the documentation below for the callback for how to handle the data. If the callback parameter is NULL, then any previously set callback will be removed.
void gt2SetUnrecognizedMessageCallback ( GT2Socket socket, gt2UnrecognizedMessageCallback callback );
- socket
- This is the socket to which someone is attempting to connect.
- callback
- The callback to be called for unrecognized messages. May be NULL.
gtUnrecognizedMessageCallback
This callback is called whenever a message is received that cannot be matched to an existing connection. The application must determine if the message was meant for it or not. If the application decides to handle the message, it should return GT2True from this function. This will tell the GT2Socket to ignore the message. If the application does not handle the message, it should return GT2False. If it returns GT2False, GT2 will send a message back to the machine that sent the original message, indicating that there is no existing connection for the message.
typedef GT2Bool (* gt2UnrecognizedMessageCallback) ( GT2Socket socket, unsigned int ip, unsigned short port, GT2Byte * message, int len );
- socket
- This is the GT2Socket on which the message was received.
- ip
- The IP the message came from (in network byte order).
- port
- The port the remote machine (in host byte order).
- message
- The message contents. May be NULL.
- len
- The length of the message. May be 0.