diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /tracker/common | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'tracker/common')
| -rw-r--r-- | tracker/common/CompletionEvent.cpp | 37 | ||||
| -rw-r--r-- | tracker/common/CompletionEvent.h | 32 | ||||
| -rw-r--r-- | tracker/common/DebugConsole_Interface.h | 30 | ||||
| -rw-r--r-- | tracker/common/DebugTimer.h | 22 | ||||
| -rw-r--r-- | tracker/common/IGameList.h | 69 | ||||
| -rw-r--r-- | tracker/common/IServerRefreshResponse.h | 34 | ||||
| -rw-r--r-- | tracker/common/IceKey.H | 65 | ||||
| -rw-r--r-- | tracker/common/IceKey.cpp | 393 | ||||
| -rw-r--r-- | tracker/common/MasterMsgHandler.h | 32 | ||||
| -rw-r--r-- | tracker/common/Socket.cpp | 1035 | ||||
| -rw-r--r-- | tracker/common/Socket.h | 162 | ||||
| -rw-r--r-- | tracker/common/TrackerMessageFlags.h | 22 | ||||
| -rw-r--r-- | tracker/common/TrackerProtocol.h | 161 | ||||
| -rw-r--r-- | tracker/common/UtlMsgBuffer.cpp | 332 | ||||
| -rw-r--r-- | tracker/common/UtlMsgBuffer.h | 198 | ||||
| -rw-r--r-- | tracker/common/inetapi.h | 42 | ||||
| -rw-r--r-- | tracker/common/msgbuffer.cpp | 421 | ||||
| -rw-r--r-- | tracker/common/msgbuffer.h | 108 | ||||
| -rw-r--r-- | tracker/common/netapi.cpp | 277 | ||||
| -rw-r--r-- | tracker/common/server.h | 51 | ||||
| -rw-r--r-- | tracker/common/util.cpp | 70 | ||||
| -rw-r--r-- | tracker/common/util.h | 29 |
22 files changed, 3622 insertions, 0 deletions
diff --git a/tracker/common/CompletionEvent.cpp b/tracker/common/CompletionEvent.cpp new file mode 100644 index 0000000..dd4bfae --- /dev/null +++ b/tracker/common/CompletionEvent.cpp @@ -0,0 +1,37 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "CompletionEvent.h" +#include "winlite.h" + +//----------------------------------------------------------------------------- +// Purpose: creates an event +//----------------------------------------------------------------------------- +EventHandle_t Event_CreateEvent() +{ + return (EventHandle_t)::CreateEvent(NULL, false, false, NULL); +} + +//----------------------------------------------------------------------------- +// Purpose: sets the current thread to wait for either the event to be signalled, or the timeout to occur +//----------------------------------------------------------------------------- +void Event_WaitForEvent(EventHandle_t event, unsigned long timeoutMilliseconds) +{ + ::WaitForSingleObject((HANDLE)event, timeoutMilliseconds); +} + +//----------------------------------------------------------------------------- +// Purpose: signals an event to Activate +// Releases one thread waiting on the event. +// If the event has no threads waiting on it, the next thread to wait on it will be let right through +//----------------------------------------------------------------------------- +void Event_SignalEvent(EventHandle_t event) +{ + ::SetEvent((HANDLE)event); +} + + diff --git a/tracker/common/CompletionEvent.h b/tracker/common/CompletionEvent.h new file mode 100644 index 0000000..77075f9 --- /dev/null +++ b/tracker/common/CompletionEvent.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Wraps windows WaitForSingleEvent() calls +// +// $NoKeywords: $ +//============================================================================= + +#ifndef COMPLETIONEVENT_H +#define COMPLETIONEVENT_H +#ifdef _WIN32 +#pragma once +#endif + +// handle to an event +typedef unsigned long EventHandle_t; + +// creates an event +EventHandle_t Event_CreateEvent(); + +// sets the current thread to wait for either the event to be signalled, or the timeout to occur +void Event_WaitForEvent(EventHandle_t event, unsigned long timeoutMilliseconds); + +// set the timeout to this for it to never time out +#define TIMEOUT_INFINITE 0xFFFFFFFF + +// signals an event to Activate +// Releases one thread waiting on the event. +// If the event has no threads waiting on it, the next thread to wait on it will be let right through +void Event_SignalEvent(EventHandle_t event); + + +#endif // COMPLETIONEVENT_H diff --git a/tracker/common/DebugConsole_Interface.h b/tracker/common/DebugConsole_Interface.h new file mode 100644 index 0000000..4462046 --- /dev/null +++ b/tracker/common/DebugConsole_Interface.h @@ -0,0 +1,30 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef DEBUGCONSOLE_INTERFACE_H +#define DEBUGCONSOLE_INTERFACE_H +#pragma once + +#include "interface.h" + +//----------------------------------------------------------------------------- +// Purpose: Debugging console interface +//----------------------------------------------------------------------------- +class IDebugConsole : public IBaseInterface +{ +public: + virtual void Initialize( const char *consoleName, int logLevel ) = 0; + virtual void Print( int severity, PRINTF_FORMAT_STRING const char *msgDescriptor, ... ) = 0; + + // gets a line of command input + // returns true if anything returned, false otherwise + virtual bool GetInput(char *buffer, int bufferSize) = 0; +}; + +#define DEBUGCONSOLE_INTERFACE_VERSION "DebugConsole001" + +#endif // DEBUGCONSOLE_INTERFACE_H diff --git a/tracker/common/DebugTimer.h b/tracker/common/DebugTimer.h new file mode 100644 index 0000000..57fc1be --- /dev/null +++ b/tracker/common/DebugTimer.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef DEBUGTIMER_H +#define DEBUGTIMER_H +#ifdef _WIN32 +#pragma once +#endif + +// resets the timer +void Timer_Start(); + +// returns the time since Timer_Start() was called, in seconds +double Timer_End(); + + + +#endif // DEBUGTIMER_H diff --git a/tracker/common/IGameList.h b/tracker/common/IGameList.h new file mode 100644 index 0000000..8b7a008 --- /dev/null +++ b/tracker/common/IGameList.h @@ -0,0 +1,69 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef IGAMELIST_H +#define IGAMELIST_H +#ifdef _WIN32 +#pragma once +#endif + +struct serveritem_t; +#include "FindSteamServers.h" + +#define EMPTY_SERVER_NAME "0.0.0.0:0" + +//----------------------------------------------------------------------------- +// Purpose: Interface to accessing a game list +//----------------------------------------------------------------------------- +class IGameList +{ +public: + + enum InterfaceItem_e + { + FILTERS, + GETNEWLIST, + ADDSERVER, + ADDCURRENTSERVER, + }; + + // returns true if the game list supports the specified ui elements + virtual bool SupportsItem(InterfaceItem_e item) = 0; + + // starts the servers refreshing + virtual void StartRefresh() = 0; + + // gets a new server list + virtual void GetNewServerList() = 0; + + // stops current refresh/GetNewServerList() + virtual void StopRefresh() = 0; + + // returns true if the list is currently refreshing servers + virtual bool IsRefreshing() = 0; + + // gets information about specified server + virtual serveritem_t &GetServer(unsigned int serverID) = 0; + + // adds a new server to list + virtual void AddNewServer(serveritem_t &server) = 0; + + // marks that server list has been fully received + virtual void ListReceived(bool moreAvailable, const char *lastUniqueIP, ESteamServerType serverType) = 0; + + // called when Connect button is pressed + virtual void OnBeginConnect() = 0; + + // reapplies filters + virtual void ApplyFilters() = 0; + + // invalid server index + virtual int GetInvalidServerListID() = 0; +}; + + +#endif // IGAMELIST_H diff --git a/tracker/common/IServerRefreshResponse.h b/tracker/common/IServerRefreshResponse.h new file mode 100644 index 0000000..50ab088 --- /dev/null +++ b/tracker/common/IServerRefreshResponse.h @@ -0,0 +1,34 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef ISERVERREFRESHRESPONSE_H +#define ISERVERREFRESHRESPONSE_H +#ifdef _WIN32 +#pragma once +#endif + +struct serveritem_t; + +//----------------------------------------------------------------------------- +// Purpose: Callback interface for server updates +//----------------------------------------------------------------------------- +class IServerRefreshResponse +{ +public: + // called when the server has successfully responded + virtual void ServerResponded(serveritem_t &server) = 0; + + // called when a server response has timed out + virtual void ServerFailedToRespond(serveritem_t &server) = 0; + + // called when the current refresh list is complete + virtual void RefreshComplete() = 0; +}; + + + +#endif // ISERVERREFRESHRESPONSE_H diff --git a/tracker/common/IceKey.H b/tracker/common/IceKey.H new file mode 100644 index 0000000..d6590f4 --- /dev/null +++ b/tracker/common/IceKey.H @@ -0,0 +1,65 @@ +//========= Public Domain Code ================================================ +// +// Purpose: Header file for the C++ ICE encryption class. +// Taken from public domain code, as written by Matthew Kwan - July 1996 +// http://www.darkside.com.au/ice/ +//============================================================================= + +#ifndef _IceKey_H +#define _IceKey_H + +/* +The IceKey class is used for encrypting and decrypting 64-bit blocks of data +with the ICE (Information Concealment Engine) encryption algorithm. + +The constructor creates a new IceKey object that can be used to encrypt and decrypt data. +The level of encryption determines the size of the key, and hence its speed. +Level 0 uses the Thin-ICE variant, which is an 8-round cipher taking an 8-byte key. +This is the fastest option, and is generally considered to be at least as secure as DES, +although it is not yet certain whether it is as secure as its key size. + +For levels n greater than zero, a 16n-round cipher is used, taking 8n-byte keys. +Although not as fast as level 0, these are very very secure. + +Before an IceKey can be used to encrypt data, its key schedule must be set with the set() member function. +The length of the key required is determined by the level, as described above. + +The member functions encrypt() and decrypt() encrypt and decrypt respectively data +in blocks of eight chracters, using the specified key. + +Two functions keySize() and blockSize() are provided +which return the key and block size respectively, measured in bytes. +The key size is determined by the level, while the block size is always 8. + +The destructor zeroes out and frees up all memory associated with the key. +*/ + +class IceSubkey; + +class IceKey { + public: + IceKey (int n); + ~IceKey (); + + void set (const unsigned char *key); + + void encrypt (const unsigned char *plaintext, + unsigned char *ciphertext) const; + + void decrypt (const unsigned char *ciphertext, + unsigned char *plaintext) const; + + int keySize () const; + + int blockSize () const; + + private: + void scheduleBuild (unsigned short *k, int n, + const int *keyrot); + + int _size; + int _rounds; + IceSubkey *_keysched; +}; + +#endif diff --git a/tracker/common/IceKey.cpp b/tracker/common/IceKey.cpp new file mode 100644 index 0000000..f6b0c77 --- /dev/null +++ b/tracker/common/IceKey.cpp @@ -0,0 +1,393 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +//========= Public Domain Code ================================================ +// +// Purpose: C++ implementation of the ICE encryption algorithm. +// Taken from public domain code, as written by Matthew Kwan - July 1996 +// http://www.darkside.com.au/ice/ +//============================================================================= + +#include "mathlib/IceKey.H" + +#pragma warning(disable: 4244) + + + /* Structure of a single round subkey */ +class IceSubkey { + public: + unsigned long val[3]; +}; + + + /* The S-boxes */ +static unsigned long ice_sbox[4][1024]; +static int ice_sboxes_initialised = 0; + + + /* Modulo values for the S-boxes */ +static const int ice_smod[4][4] = { + {333, 313, 505, 369}, + {379, 375, 319, 391}, + {361, 445, 451, 397}, + {397, 425, 395, 505}}; + + /* XOR values for the S-boxes */ +static const int ice_sxor[4][4] = { + {0x83, 0x85, 0x9b, 0xcd}, + {0xcc, 0xa7, 0xad, 0x41}, + {0x4b, 0x2e, 0xd4, 0x33}, + {0xea, 0xcb, 0x2e, 0x04}}; + + /* Permutation values for the P-box */ +static const unsigned long ice_pbox[32] = { + 0x00000001, 0x00000080, 0x00000400, 0x00002000, + 0x00080000, 0x00200000, 0x01000000, 0x40000000, + 0x00000008, 0x00000020, 0x00000100, 0x00004000, + 0x00010000, 0x00800000, 0x04000000, 0x20000000, + 0x00000004, 0x00000010, 0x00000200, 0x00008000, + 0x00020000, 0x00400000, 0x08000000, 0x10000000, + 0x00000002, 0x00000040, 0x00000800, 0x00001000, + 0x00040000, 0x00100000, 0x02000000, 0x80000000}; + + /* The key rotation schedule */ +static const int ice_keyrot[16] = { + 0, 1, 2, 3, 2, 1, 3, 0, + 1, 3, 2, 0, 3, 1, 0, 2}; + + +/* + * 8-bit Galois Field multiplication of a by b, modulo m. + * Just like arithmetic multiplication, except that additions and + * subtractions are replaced by XOR. + */ + +static unsigned int +gf_mult ( + register unsigned int a, + register unsigned int b, + register unsigned int m +) { + register unsigned int res = 0; + + while (b) { + if (b & 1) + res ^= a; + + a <<= 1; + b >>= 1; + + if (a >= 256) + a ^= m; + } + + return (res); +} + + +/* + * Galois Field exponentiation. + * Raise the base to the power of 7, modulo m. + */ + +static unsigned long +gf_exp7 ( + register unsigned int b, + unsigned int m +) { + register unsigned int x; + + if (b == 0) + return (0); + + x = gf_mult (b, b, m); + x = gf_mult (b, x, m); + x = gf_mult (x, x, m); + return (gf_mult (b, x, m)); +} + + +/* + * Carry out the ICE 32-bit P-box permutation. + */ + +static unsigned long +ice_perm32 ( + register unsigned long x +) { + register unsigned long res = 0; + register const unsigned long *pbox = ice_pbox; + + while (x) { + if (x & 1) + res |= *pbox; + pbox++; + x >>= 1; + } + + return (res); +} + + +/* + * Initialise the ICE S-boxes. + * This only has to be done once. + */ + +static void +ice_sboxes_init (void) +{ + register int i; + + for (i=0; i<1024; i++) { + int col = (i >> 1) & 0xff; + int row = (i & 0x1) | ((i & 0x200) >> 8); + unsigned long x; + + x = gf_exp7 (col ^ ice_sxor[0][row], ice_smod[0][row]) << 24; + ice_sbox[0][i] = ice_perm32 (x); + + x = gf_exp7 (col ^ ice_sxor[1][row], ice_smod[1][row]) << 16; + ice_sbox[1][i] = ice_perm32 (x); + + x = gf_exp7 (col ^ ice_sxor[2][row], ice_smod[2][row]) << 8; + ice_sbox[2][i] = ice_perm32 (x); + + x = gf_exp7 (col ^ ice_sxor[3][row], ice_smod[3][row]); + ice_sbox[3][i] = ice_perm32 (x); + } +} + + +/* + * Create a new ICE key. + */ + +IceKey::IceKey (int n) +{ + if (!ice_sboxes_initialised) { + ice_sboxes_init (); + ice_sboxes_initialised = 1; + } + + if (n < 1) { + _size = 1; + _rounds = 8; + } else { + _size = n; + _rounds = n * 16; + } + + _keysched = new IceSubkey[_rounds]; +} + + +/* + * Destroy an ICE key. + */ + +IceKey::~IceKey () +{ + int i, j; + + for (i=0; i<_rounds; i++) + for (j=0; j<3; j++) + _keysched[i].val[j] = 0; + + _rounds = _size = 0; + + delete[] _keysched; +} + + +/* + * The single round ICE f function. + */ + +static unsigned long +ice_f ( + register unsigned long p, + const IceSubkey *sk +) { + unsigned long tl, tr; /* Expanded 40-bit values */ + unsigned long al, ar; /* Salted expanded 40-bit values */ + + /* Left half expansion */ + tl = ((p >> 16) & 0x3ff) | (((p >> 14) | (p << 18)) & 0xffc00); + + /* Right half expansion */ + tr = (p & 0x3ff) | ((p << 2) & 0xffc00); + + /* Perform the salt permutation */ + // al = (tr & sk->val[2]) | (tl & ~sk->val[2]); + // ar = (tl & sk->val[2]) | (tr & ~sk->val[2]); + al = sk->val[2] & (tl ^ tr); + ar = al ^ tr; + al ^= tl; + + al ^= sk->val[0]; /* XOR with the subkey */ + ar ^= sk->val[1]; + + /* S-box lookup and permutation */ + return (ice_sbox[0][al >> 10] | ice_sbox[1][al & 0x3ff] + | ice_sbox[2][ar >> 10] | ice_sbox[3][ar & 0x3ff]); +} + + +/* + * Encrypt a block of 8 bytes of data with the given ICE key. + */ + +void +IceKey::encrypt ( + const unsigned char *ptext, + unsigned char *ctext +) const +{ + register int i; + register unsigned long l, r; + + l = (((unsigned long) ptext[0]) << 24) + | (((unsigned long) ptext[1]) << 16) + | (((unsigned long) ptext[2]) << 8) | ptext[3]; + r = (((unsigned long) ptext[4]) << 24) + | (((unsigned long) ptext[5]) << 16) + | (((unsigned long) ptext[6]) << 8) | ptext[7]; + + for (i = 0; i < _rounds; i += 2) { + l ^= ice_f (r, &_keysched[i]); + r ^= ice_f (l, &_keysched[i + 1]); + } + + for (i = 0; i < 4; i++) { + ctext[3 - i] = r & 0xff; + ctext[7 - i] = l & 0xff; + + r >>= 8; + l >>= 8; + } +} + + +/* + * Decrypt a block of 8 bytes of data with the given ICE key. + */ + +void +IceKey::decrypt ( + const unsigned char *ctext, + unsigned char *ptext +) const +{ + register int i; + register unsigned long l, r; + + l = (((unsigned long) ctext[0]) << 24) + | (((unsigned long) ctext[1]) << 16) + | (((unsigned long) ctext[2]) << 8) | ctext[3]; + r = (((unsigned long) ctext[4]) << 24) + | (((unsigned long) ctext[5]) << 16) + | (((unsigned long) ctext[6]) << 8) | ctext[7]; + + for (i = _rounds - 1; i > 0; i -= 2) { + l ^= ice_f (r, &_keysched[i]); + r ^= ice_f (l, &_keysched[i - 1]); + } + + for (i = 0; i < 4; i++) { + ptext[3 - i] = r & 0xff; + ptext[7 - i] = l & 0xff; + + r >>= 8; + l >>= 8; + } +} + + +/* + * Set 8 rounds [n, n+7] of the key schedule of an ICE key. + */ + +void +IceKey::scheduleBuild ( + unsigned short *kb, + int n, + const int *keyrot +) { + int i; + + for (i=0; i<8; i++) { + register int j; + register int kr = keyrot[i]; + IceSubkey *isk = &_keysched[n + i]; + + for (j=0; j<3; j++) + isk->val[j] = 0; + + for (j=0; j<15; j++) { + register int k; + unsigned long *curr_sk = &isk->val[j % 3]; + + for (k=0; k<4; k++) { + unsigned short *curr_kb = &kb[(kr + k) & 3]; + register int bit = *curr_kb & 1; + + *curr_sk = (*curr_sk << 1) | bit; + *curr_kb = (*curr_kb >> 1) | ((bit ^ 1) << 15); + } + } + } +} + + +/* + * Set the key schedule of an ICE key. + */ + +void +IceKey::set ( + const unsigned char *key +) { + int i; + + if (_rounds == 8) { + unsigned short kb[4]; + + for (i=0; i<4; i++) + kb[3 - i] = (key[i*2] << 8) | key[i*2 + 1]; + + scheduleBuild (kb, 0, ice_keyrot); + return; + } + + for (i=0; i<_size; i++) { + int j; + unsigned short kb[4]; + + for (j=0; j<4; j++) + kb[3 - j] = (key[i*8 + j*2] << 8) | key[i*8 + j*2 + 1]; + + scheduleBuild (kb, i*8, ice_keyrot); + scheduleBuild (kb, _rounds - 8 - i*8, &ice_keyrot[8]); + } +} + + +/* + * Return the key size, in bytes. + */ + +int +IceKey::keySize () const +{ + return (_size * 8); +} + + +/* + * Return the block size, in bytes. + */ + +int +IceKey::blockSize () const +{ + return (8); +} diff --git a/tracker/common/MasterMsgHandler.h b/tracker/common/MasterMsgHandler.h new file mode 100644 index 0000000..094a2e4 --- /dev/null +++ b/tracker/common/MasterMsgHandler.h @@ -0,0 +1,32 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef MASTERMSGHANDLER_H +#define MASTERMSGHANDLER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "Socket.h" + +//----------------------------------------------------------------------------- +// Purpose: Socket handler for lan broadcast pings +//----------------------------------------------------------------------------- +class CMasterMsgHandler : public CMsgHandler +{ +public: + CMasterMsgHandler( IGameList *baseobject, HANDLERTYPE type, void *typeinfo = NULL ); + + virtual bool Process( netadr_t *from, CMsgBuffer *msg ); + +private: + IGameList *m_pGameList; +}; + + + +#endif // MASTERMSGHANDLER_H diff --git a/tracker/common/Socket.cpp b/tracker/common/Socket.cpp new file mode 100644 index 0000000..93109ba --- /dev/null +++ b/tracker/common/Socket.cpp @@ -0,0 +1,1035 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#if !defined( _X360 ) +#define FD_SETSIZE 1024 +#endif + +#include <assert.h> +#include "winlite.h" +#if !defined( _X360 ) +#include "winsock.h" +#else +#include "winsockx.h" +#endif +#include "msgbuffer.h" +#include "socket.h" +#include "inetapi.h" +#include "tier0/vcrmode.h" + +#include <VGUI/IVGui.h> + +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +//----------------------------------------------------------------------------- +// Purpose: All socket I/O occurs on a thread +//----------------------------------------------------------------------------- +class CSocketThread +{ +public: + typedef struct threadsocket_s + { + struct threadsocket_s *next; + CSocket *socket; + } threadsocket_t; + + // Construction + CSocketThread( void ); + virtual ~CSocketThread( void ); + + // Sockets add/remove themselves via their constructor + virtual void AddSocketToThread( CSocket *socket ); + virtual void RemoveSocketFromThread( CSocket *socket ); + + // Lock changes to socket list, etc. + virtual void Lock( void ); + // Unlock socket list, etc. + virtual void Unlock( void ); + + // Retrieve handle to shutdown event + virtual HANDLE GetShutdownHandle( void ); + // Get head of socket list + virtual threadsocket_t *GetSocketList( void ); + + // Sample clock for socket thread + virtual float GetClock( void ); + +private: + // Initialize the clock + void InitTimer( void ); + +private: + // Critical section used for synchronizing access to socket list + CRITICAL_SECTION cs; + // List of sockets we are listening on + threadsocket_t *m_pSocketList; + // Thread handle + HANDLE m_hThread; + // Thread id + DWORD m_nThreadId; + // Event to set when we want to tell the thread to shut itself down + HANDLE m_hShutdown; + + // High performance clock frequency + double m_dClockFrequency; + // Current accumulated time + double m_dCurrentTime; + // How many bits to shift raw 64 bit sample count by + int m_nTimeSampleShift; + // Previous 32 bit sample count + unsigned int m_uiPreviousTime; +}; + +// Singleton handler +static CSocketThread *GetSocketThread() +{ + static CSocketThread g_SocketThread; + return &g_SocketThread; +} + +//----------------------------------------------------------------------------- +// Purpose: Main winsock processing thread +// Input : threadobject - +// Output : static DWORD WINAPI +//----------------------------------------------------------------------------- +static DWORD WINAPI SocketThreadFunc( LPVOID threadobject ) +{ + // Get pointer to CSocketThread object + CSocketThread *socketthread = ( CSocketThread * )threadobject; + assert( socketthread ); + if ( !socketthread ) + { + return 0; + } + + // Keep looking for data until shutdown event is triggered + while ( 1 ) + { + // List of sockets + CSocketThread::threadsocket_t *sockets; + // file descriptor set for sockets + fd_set fdset; + // number of sockets with messages ready + int number; + // number of sockets added to fd_set + int count; + + // Check for shutdown event + if ( WAIT_OBJECT_0 == VCRHook_WaitForSingleObject( socketthread->GetShutdownHandle(), 0 ) ) + { + break; + } + + // Clear the set + FD_ZERO(&fdset); + + // No changes to list right now + socketthread->Lock(); + + // Add all active sockets to the fdset + count = 0; + for ( sockets = socketthread->GetSocketList(); sockets; sockets = sockets->next ) + { + FD_SET( static_cast<u_int>( sockets->socket->GetSocketNumber() ), &fdset ); + count = max( count, sockets->socket->GetSocketNumber() ); + } + + // Done + socketthread->Unlock(); + + if ( count ) + { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 100000; // 100 millisecond == 100000 usec + + // Block for 100000 usec, or until a message is in the queue + number = select( count + 1, &fdset, NULL, NULL, &tv ); +#if !defined( NO_VCR ) + VCRGenericValue( "", &number, sizeof( number ) ); +#endif + if ( number > 0 ) + { + // Iterate through socket list and see who has data waiting // + // No changes to list right now + socketthread->Lock(); + + // Check FD_SET for incoming network messages + for ( sockets = socketthread->GetSocketList(); sockets; sockets = sockets->next ) + { + bool bSet = FD_ISSET( sockets->socket->GetSocketNumber(), &fdset ); +#if !defined( NO_VCR ) + VCRGenericValue( "", &bSet, sizeof( bSet ) ); +#endif + if ( bSet ) + { + // keep reading as long as there is data on the socket + while (sockets->socket->ReceiveData()) + { + } + } + } + + // Done + socketthread->Unlock(); + } + } + + // no need to sleep here, much better let it sleep in the select + } + + ExitThread( 0 ); + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Construction +//----------------------------------------------------------------------------- +CSocketThread::CSocketThread( void ) +{ + InitTimer(); + + m_pSocketList = NULL; + + InitializeCriticalSection( &cs ); + + m_hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL ); + assert( m_hShutdown ); + + m_hThread = 0; + m_nThreadId = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CSocketThread::~CSocketThread( void ) +{ + Lock(); + if ( m_hThread ) + { + SetEvent( m_hShutdown ); + Sleep( 2 ); + TerminateThread( m_hThread, 0 ); + } + Unlock(); + + // Kill the socket +//!! need to validate this line +// assert( !m_pSocketList ); + + if ( m_hThread ) + { + CloseHandle( m_hThread ); + } + + CloseHandle( m_hShutdown ); + + DeleteCriticalSection( &cs ); +} + +//----------------------------------------------------------------------------- +// Purpose: Initialize socket thread timer +//----------------------------------------------------------------------------- +void CSocketThread::InitTimer( void ) +{ + BOOL success; + LARGE_INTEGER PerformanceFreq; + unsigned int lowpart, highpart; + + // Start clock at zero + m_dCurrentTime = 0.0; + + success = QueryPerformanceFrequency( &PerformanceFreq ); + assert( success ); + + // get 32 out of the 64 time bits such that we have around + // 1 microsecond resolution + lowpart = (unsigned int)PerformanceFreq.LowPart; + highpart = (unsigned int)PerformanceFreq.HighPart; + + m_nTimeSampleShift = 0; + + while ( highpart || ( lowpart > 2000000.0 ) ) + { + m_nTimeSampleShift++; + lowpart >>= 1; + lowpart |= (highpart & 1) << 31; + highpart >>= 1; + } + + m_dClockFrequency = 1.0 / (double)lowpart; + + // Get initial sample + unsigned int temp; + LARGE_INTEGER PerformanceCount; + QueryPerformanceCounter( &PerformanceCount ); + if ( !m_nTimeSampleShift ) + { + temp = (unsigned int)PerformanceCount.LowPart; + } + else + { + // Rotate counter to right by m_nTimeSampleShift places + temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) | + ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift)); + } + + // Set first time stamp + m_uiPreviousTime = temp; +} + +//----------------------------------------------------------------------------- +// Purpose: Thread local timer function +// Output : float +//----------------------------------------------------------------------------- +float CSocketThread::GetClock( void ) +{ + LARGE_INTEGER PerformanceCount; + unsigned int temp, t2; + double time; + + // Get sample counter + QueryPerformanceCounter( &PerformanceCount ); + + if ( !m_nTimeSampleShift ) + { + temp = (unsigned int)PerformanceCount.LowPart; + } + else + { + // Rotate counter to right by m_nTimeSampleShift places + temp = ((unsigned int)PerformanceCount.LowPart >> m_nTimeSampleShift) | + ((unsigned int)PerformanceCount.HighPart << (32 - m_nTimeSampleShift)); + } + + // check for turnover or backward time + if ( ( temp <= m_uiPreviousTime ) && + ( ( m_uiPreviousTime - temp ) < 0x10000000) ) + { + m_uiPreviousTime = temp; // so we can't get stuck + } + else + { + // gap in performance clocks + t2 = temp - m_uiPreviousTime; + + // Convert to time using frequencey of clock + time = (double)t2 * m_dClockFrequency; + + // Remember old time + m_uiPreviousTime = temp; + + // Increment clock + m_dCurrentTime += time; + } +#if !defined( NO_VCR ) + VCRGenericValue( "", &m_dCurrentTime, sizeof( m_dCurrentTime ) ); +#endif + // Convert to float + return (float)m_dCurrentTime; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns handle of shutdown event +// Output : HANDLE +//----------------------------------------------------------------------------- +HANDLE CSocketThread::GetShutdownHandle( void ) +{ + return m_hShutdown; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns head of socket list +// Output : CSocketThread::threadsocket_t +//----------------------------------------------------------------------------- +CSocketThread::threadsocket_t *CSocketThread::GetSocketList( void ) +{ + return m_pSocketList; +} + +int socketCount = 0; + +//----------------------------------------------------------------------------- +// Purpose: Locks object and adds socket to thread +//----------------------------------------------------------------------------- +void CSocketThread::AddSocketToThread( CSocket *socket ) +{ + // create the thread if it isn't there + if (!m_hThread) + { + m_hThread = VCRHook_CreateThread( NULL, 0, SocketThreadFunc, (void *)this, 0, &m_nThreadId ); + assert( m_hThread ); + } + + socketCount++; + + threadsocket_t *p = new threadsocket_t; + p->socket = socket; + + Lock(); + p->next = m_pSocketList; + m_pSocketList = p; + Unlock(); +} + +//----------------------------------------------------------------------------- +// Purpose: Locks list and removes specified socket from thread +//----------------------------------------------------------------------------- +void CSocketThread::RemoveSocketFromThread( CSocket *socket ) +{ + if (!m_hThread) + return; + + socketCount--; + + Lock(); + if ( m_pSocketList ) + { + threadsocket_t *p, *n; + p = m_pSocketList; + if ( p->socket == socket ) + { + m_pSocketList = m_pSocketList->next; + delete p; + } + else + { + while ( p->next ) + { + n = p->next; + if ( n->socket == socket ) + { + p->next = n->next; + delete n; + break; + } + p = n; + } + } + } + Unlock(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSocketThread::Lock( void ) +{ + VCRHook_EnterCriticalSection( &cs ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CSocketThread::Unlock( void ) +{ + LeaveCriticalSection( &cs ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructs a message handler for incoming socket messages +//----------------------------------------------------------------------------- +CMsgHandler::CMsgHandler( HANDLERTYPE type, void *typeinfo /*=NULL*/ ) +{ + m_Type = type; + m_pNext = NULL; + + // Assume no socket + SetSocket( NULL ); + + // Assume no special checking + m_ByteCode = 0; + m_szString[ 0 ] = 0; + + switch ( m_Type ) + { + default: + case MSGHANDLER_ALL: + break; + case MSGHANDLER_BYTECODE: + m_ByteCode = *(unsigned char *)typeinfo; + break; + case MSGHANDLER_STRING: + strcpy( m_szString, (char *)typeinfo ); + break; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMsgHandler::~CMsgHandler( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Default message handler for received messages +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CMsgHandler::Process( netadr_t *from, CMsgBuffer *msg ) +{ + // Swallow message by default + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Check for special handling +// Input : *from - +// *msg - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CMsgHandler::ProcessMessage( netadr_t *from, CMsgBuffer *msg ) +{ + bool bret = false; + unsigned char ch; + const char *str; + + // Crack bytecode or string code + switch( m_Type ) + { + case MSGHANDLER_BYTECODE: + msg->Push(); + ch = (unsigned char)msg->ReadByte(); + msg->Pop(); + if ( ch == m_ByteCode ) + { + bret = Process( from, msg ); + } + break; + case MSGHANDLER_STRING: + msg->Push(); + str = msg->ReadString(); + msg->Pop(); + if ( str && str[ 0 ] && !stricmp( m_szString, str ) ) + { + bret = Process( from, msg ); + } + break; + default: + case MSGHANDLER_ALL: + bret = Process( from, msg ); + break; + } + + return bret; +} + +//----------------------------------------------------------------------------- +// Purpose: Get next in chain of handlers +//----------------------------------------------------------------------------- +CMsgHandler *CMsgHandler::GetNext( void ) const +{ + return m_pNext; +} + +//----------------------------------------------------------------------------- +// Purpose: Set next in handler chain +// Input : *next - +//----------------------------------------------------------------------------- +void CMsgHandler::SetNext( CMsgHandler *next ) +{ + m_pNext = next; +} + +//----------------------------------------------------------------------------- +// Purpose: Get underlying socket object +// Output : CSocket +//----------------------------------------------------------------------------- +CSocket *CMsgHandler::GetSocket( void ) const +{ + return m_pSocket; +} + +//----------------------------------------------------------------------------- +// Purpose: Set underlying socket object +// Input : *socket - +//----------------------------------------------------------------------------- +void CMsgHandler::SetSocket( CSocket *socket ) +{ + m_pSocket = socket; +} + +//----------------------------------------------------------------------------- +// Purpose: Creates a non-blocking, broadcast capable, UDP socket. If port is +// specified, binds it to listen on that port, otherwise, chooses a random port. +//----------------------------------------------------------------------------- +CSocket::CSocket( const char *socketname, int port /*= -1*/ ) : m_SendBuffer(socketname) +{ + struct sockaddr_in address; + unsigned long _true = 1; + int i = 1; + + m_pSocketName = socketname; + + m_bValid = false; + m_bResolved = false; + m_pMessageHandlers = NULL; + m_nUserData = 0; + m_bBroadcastSend = false; + m_iTotalPackets = 0; + m_iCurrentPackets = 0; + m_iRetries = 0; + + m_pBufferCS = new CRITICAL_SECTION; + InitializeCriticalSection((CRITICAL_SECTION *)m_pBufferCS); + + // ensure the socketthread singleton has been created + GetSocketThread(); + + // Set up the socket + m_Socket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if ( m_Socket == -1 ) + { + //int err = WSAGetLastError(); + // WSANOTINITIALISED + return; + } + + // Set it to non-blocking + if ( ioctlsocket ( m_Socket, FIONBIO, &_true ) == -1 ) + { + closesocket( m_Socket ); + m_Socket = 0; + return; + } + + // Allow broadcast packets + if ( setsockopt( m_Socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i) ) == -1 ) + { + closesocket( m_Socket ); + m_Socket = 0; + return; + } + + // LATER: Support specifying interface name + //if (!net_interface || !net_interface[0] || !stricmp(net_interface, "localhost")) + address.sin_addr.s_addr = INADDR_ANY; + //else + // NET_StringToSockaddr (net_interface, (struct sockaddr *)&address); + + if ( port == -1 ) + { + address.sin_port = 0; + } + else + { + address.sin_port = htons( (short)port ); + } + + address.sin_family = AF_INET; + + // only bind if we're required to be on a certain port + if ( address.sin_port > 0) + { + // Bind the socket to specified port + if ( bind( m_Socket, (struct sockaddr *)&address, sizeof(address) ) == -1 ) + { + closesocket (m_Socket); + m_Socket = 0; + return; + } + } + + // Mark as valid + m_bValid = true; + + // Only add valid sockets to thread + GetSocketThread()->AddSocketToThread( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CSocket::~CSocket( void ) +{ + DeleteCriticalSection((CRITICAL_SECTION *)m_pBufferCS); + delete (CRITICAL_SECTION *)m_pBufferCS; + + // Try to remove socket from thread + GetSocketThread()->RemoveSocketFromThread( this ); + + // Ask message handlers to remove selves? + if ( m_bValid ) + { + ::shutdown(m_Socket, 0x01); + ::shutdown(m_Socket, 0x02); + closesocket( m_Socket ); + m_Socket = 0; + } + + // Remove handlers + CMsgHandler *handler = m_pMessageHandlers; + while ( handler ) + { + RemoveMessageHandler( handler ); + delete handler; + handler = m_pMessageHandlers; + } + m_pMessageHandlers = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: Add hander to head of chain +// Input : *handler - +//----------------------------------------------------------------------------- +void CSocket::AddMessageHandler( CMsgHandler *handler ) +{ + handler->SetNext( m_pMessageHandlers ); + m_pMessageHandlers = handler; + + // Set the socket pointer + handler->SetSocket( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: Removed indicated handler +// Input : *handler - +//----------------------------------------------------------------------------- +void CSocket::RemoveMessageHandler( CMsgHandler *handler ) +{ + if ( !handler ) + { + return; + } + + CMsgHandler *list = m_pMessageHandlers; + if ( list == handler ) + { + m_pMessageHandlers = m_pMessageHandlers->GetNext(); + return; + } + + while ( list ) + { + if ( list->GetNext() == handler ) + { + list->SetNext( handler->GetNext() ); + handler->SetNext( NULL ); + return; + } + list = list->GetNext(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Send message to specified address +// Input : *to - +// Output : int - number of bytes sent +//----------------------------------------------------------------------------- +int CSocket::SendMessage( netadr_t *to, CMsgBuffer *msg /*= NULL*/ ) +{ + m_bBroadcastSend = false; + m_ToAddress = *to; + + if ( !m_bValid ) + { + return 0; + } + + if ( !msg ) + { + msg = GetSendBuffer(); + } + + struct sockaddr addr; + net->NetAdrToSockAddr ( to, &addr ); + + int bytessent = sendto( m_Socket, (const char *)msg->GetData(), msg->GetCurSize(), 0, &addr, sizeof( addr ) ); + if ( bytessent == msg->GetCurSize() ) + { + return bytessent; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Send broadcast message on specified port +// Input : port - +// Output : int - number of bytes sent +//----------------------------------------------------------------------------- +int CSocket::Broadcast( int port, CMsgBuffer *msg /*= NULL*/ ) +{ + m_bBroadcastSend = true; + memset( &m_ToAddress, 0, sizeof( m_ToAddress ) ); + + if ( !m_bValid ) + { + return 0; + } + + if ( !msg ) + { + msg = GetSendBuffer(); + } + + struct sockaddr addr; + netadr_t to; + + to.port = (unsigned short)htons( (unsigned short)port ); + to.type = NA_BROADCAST; + + net->NetAdrToSockAddr ( &to, &addr ); + + int bytessent = sendto( m_Socket, (const char *)msg->GetData(), msg->GetCurSize(), 0, &addr, sizeof( addr ) ); + if ( bytessent == msg->GetCurSize() ) + { + return bytessent; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Retrieve internal message buffer +// Output : CMsgBuffer +//----------------------------------------------------------------------------- +CMsgBuffer *CSocket::GetSendBuffer( void ) +{ + return &m_SendBuffer; +} + +//----------------------------------------------------------------------------- +// Purpose: Called once per frame (outside of the socket thread) to allow socket to receive incoming messages +// and route them as appropriate +//----------------------------------------------------------------------------- +void CSocket::Frame( void ) +{ + // No data waiting + if (!m_MsgBuffers.Size()) + return; + + VCRHook_EnterCriticalSection( (CRITICAL_SECTION *)m_pBufferCS ); + + // pass up all the receive buffers + for (int i = 0; i < m_MsgBuffers.Size(); i++) + { + // See if there's a handler for this message + CMsgHandler *handler = m_pMessageHandlers; + netadr_t addr = m_MsgBuffers[i].GetNetAddress(); + while ( handler ) + { + // Swallow message? + if ( handler->ProcessMessage( &addr, &m_MsgBuffers[i] ) ) + break; + + handler = handler->GetNext(); + } + } + + // free the buffer list + m_MsgBuffers.RemoveAll(); + + LeaveCriticalSection((CRITICAL_SECTION *)m_pBufferCS); +} + +//----------------------------------------------------------------------------- +// Purpose: Is socket set up correctly +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CSocket::IsValid( void ) const +{ + return m_bValid; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float +//----------------------------------------------------------------------------- +float CSocket::GetClock( void ) +{ + return GetSocketThread()->GetClock(); +} + +//----------------------------------------------------------------------------- +// Purpose: Resolves the socket address +// Output : const netadr_t +//----------------------------------------------------------------------------- +const netadr_t *CSocket::GetAddress( void ) +{ + assert( m_bValid ); + + if ( !m_bResolved ) + { + m_bResolved = true; + // Determine resulting socket address + net->GetSocketAddress( m_Socket, &m_Address ); + } + + return &m_Address; +} + +//----------------------------------------------------------------------------- +// Purpose: Let the user store/retrieve a 32 bit value +// Input : userData - +//----------------------------------------------------------------------------- +void CSocket::SetUserData( unsigned int userData ) +{ + m_nUserData = userData; +} + +//----------------------------------------------------------------------------- +// Purpose: Let the user store/retrieve a 32 bit value +// Output : unsigned int +//----------------------------------------------------------------------------- +unsigned int CSocket::GetUserData(void ) const +{ + return m_nUserData; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the underlying socket id number for setting up the fd_set +//----------------------------------------------------------------------------- +int CSocket::GetSocketNumber( void ) const +{ + return m_Socket; +} + +//----------------------------------------------------------------------------- +// Purpose: Called once FD_ISSET is detected +//----------------------------------------------------------------------------- +bool CSocket::ReceiveData( void ) +{ + // Check for data + struct sockaddr from; + int fromlen; + int bytes; + unsigned char buffer[ CMsgBuffer::NET_MAXMESSAGE ]; + + fromlen = sizeof( from ); + bytes = VCRHook_recvfrom( m_Socket, (char *)buffer, CMsgBuffer::NET_MAXMESSAGE, 0, (struct sockaddr *)&from, &fromlen ); + + //int port = ntohs( ((struct sockaddr_in *)&from)->sin_port); + + // Socket error + if ( bytes == -1 ) + { + return false; + } + + // Too much data, ignore it + if ( bytes >= CMsgBuffer::NET_MAXMESSAGE ) + { + return false; + } + + // Packets must have -1 tag + if ( bytes < 4 ) + { + return false; + } + + // Mark the time no matter what since FD_SET said there was data and we should have it now + float recvTime = GetClock(); + + if( *(int *)&buffer[0] == -2 ) // its a split packet :) + { + int curPacket=0,offset=0; + SPLITPACKET *pak =reinterpret_cast<SPLITPACKET *>(&buffer[0]); + + if(m_iTotalPackets==0) // this is the first in the series + { + m_iTotalPackets = (pak->packetID & 0x0f); + m_iSeqNo = pak->sequenceNumber; + m_iRetries=0; + + m_iCurrentPackets=1;// packet numbers start at zero, total is the total number (i.e =2 for packet 0,1) + curPacket= (pak->packetID & 0xf0)>>4; + } + else if (m_iSeqNo == pak->sequenceNumber) + { + m_iCurrentPackets++; + curPacket= (pak->packetID & 0xf0)>>4; + } + else + { + m_iRetries++; + if(m_iRetries>MAX_RETRIES) // make sure we give up eventually on fragments + { + m_iTotalPackets=0; + } + return false; // TODO: add support for multiple fragments at one time? + } + + + if(curPacket==0) + { + offset=4; // strip the "-1" at the front of the first packet + } + + if(curPacket<MAX_PACKETS) // just in case... + { + m_CurPacket[curPacket].Clear(); // new packet, clear the buffer out + m_CurPacket[curPacket].WriteBuf(bytes-offset-sizeof(SPLITPACKET),&buffer[offset+sizeof(SPLITPACKET)]); + } + + if(m_iCurrentPackets==m_iTotalPackets) + { + + VCRHook_EnterCriticalSection((CRITICAL_SECTION *)m_pBufferCS); + + // Get from address + netadr_t addr; + net->SockAddrToNetAdr( &from, &addr ); + + // append to the receive buffer + int idx = m_MsgBuffers.AddToTail(); + CMsgBuffer &msgBuffer = m_MsgBuffers[idx]; + + msgBuffer.Clear(); + + // copy all our fragments together + for(int i=0;i<m_iTotalPackets;i++) + { + // buffer must be big enough for us to use, that is where the data originally came from :) + m_CurPacket[i].ReadBuf(m_CurPacket[i].GetCurSize(),buffer); + msgBuffer.WriteBuf(m_CurPacket[i].GetCurSize(),buffer); + } + msgBuffer.SetTime(recvTime); + msgBuffer.SetNetAddress(addr); + + LeaveCriticalSection((CRITICAL_SECTION *)m_pBufferCS); + + m_iTotalPackets = 0; // we have collected all the fragments for + //this packet, we can start on a new one now + + } + + + } + else if ( *(int *)&buffer[0] == -1 ) // Must have 255,255,255,255 oob tag + { + /* + // Fake packet loss + if ( rand() % 1000 < 200 ) + return; + */ + + VCRHook_EnterCriticalSection((CRITICAL_SECTION *)m_pBufferCS); + + // Get from address + netadr_t addr; + net->SockAddrToNetAdr( &from, &addr ); + + // append to the receive buffer + int idx = m_MsgBuffers.AddToTail(); + CMsgBuffer &msgBuffer = m_MsgBuffers[idx]; + + // Copy payload minus the -1 tag + msgBuffer.Clear(); + msgBuffer.WriteBuf( bytes - 4, &buffer[ 4 ] ); + msgBuffer.SetTime(recvTime); + msgBuffer.SetNetAddress(addr); + + LeaveCriticalSection((CRITICAL_SECTION *)m_pBufferCS); + } + + return true; +} diff --git a/tracker/common/Socket.h b/tracker/common/Socket.h new file mode 100644 index 0000000..8ff4569 --- /dev/null +++ b/tracker/common/Socket.h @@ -0,0 +1,162 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#if !defined( SOCKET_H ) +#define SOCKET_H +#ifdef _WIN32 +#pragma once +#endif + +#include "netadr.h" +#include "MsgBuffer.h" +#include "utlvector.h" + +#include <stdio.h> + +class CMsgBuffer; +class CSocket; +class IGameList; + +// Use this to pick apart the network stream, must be packed +#pragma pack(1) +typedef struct +{ + int netID; + int sequenceNumber; + char packetID; +} SPLITPACKET; +#pragma pack() + +#define MAX_PACKETS 16 // 4 bits for the packet count, so only +#define MAX_RETRIES 2 // the number of fragments from other packets to drop before we declare the outstanding + // fragment lost :) + +//----------------------------------------------------------------------------- +// Purpose: Instances a message handler for incoming messages. +//----------------------------------------------------------------------------- +class CMsgHandler +{ +public: + enum + { + MAX_HANDLER_STRING = 64 + }; + + typedef enum + { + MSGHANDLER_ALL = 0, + MSGHANDLER_BYTECODE, + MSGHANDLER_STRING + } HANDLERTYPE; + + // Construction + CMsgHandler( HANDLERTYPE type, void *typeinfo = 0 ); + virtual ~CMsgHandler( void ); + + // Message received, process it + virtual bool Process( netadr_t *from, CMsgBuffer *msg ) = 0; + + // For linking togethr handler chains + virtual CMsgHandler *GetNext( void ) const; + virtual void SetNext( CMsgHandler *next ); + + // Access/set associated socket + virtual CSocket *GetSocket( void ) const; + virtual void SetSocket( CSocket *socket ); + +private: + // Internal message received, crack type info and check it before calling process + bool ProcessMessage( netadr_t *from, CMsgBuffer *msg ); + + // Opaque pointer to underlying recipient class + IGameList *m_pBaseObject; + + // Next handler in chain + HANDLERTYPE m_Type; + unsigned char m_ByteCode; + char m_szString[ MAX_HANDLER_STRING ]; + + // Next handler in chain + CMsgHandler *m_pNext; + // Associated socket + CSocket *m_pSocket; + + friend CSocket; +}; + +//----------------------------------------------------------------------------- +// Purpose: Creates a non-blocking, broadcast capable, UDP socket. If port is +// specified, binds it to listen on that port, otherwise, chooses a random port. +//----------------------------------------------------------------------------- +class CSocket +{ +public: + // Construction/destruction + CSocket( const char *socketname, int port = -1 ); + virtual ~CSocket( void ); + + // Adds the message hander to the head of the sockets handler chain + virtual void AddMessageHandler( CMsgHandler *handler ); + // Removes the specified message handler + virtual void RemoveMessageHandler( CMsgHandler *handler ); + + // Send the message to the recipient, if msg == NULL, use the internal message buffer + virtual int SendMessage( netadr_t *to, CMsgBuffer *msg = NULL ); + // Broadcast the message on the specified port, if msg == NULL use the internal message buffer + virtual int Broadcast( int port, CMsgBuffer *msg = NULL ); + // Get access to the internal message buffer + virtual CMsgBuffer *GetSendBuffer( void ); + // Called once per frame to check for new data + virtual void Frame( void ); + // Check whether the socket was created and set up properly + virtual bool IsValid( void ) const; + // Get the address this socket is bound to + virtual const netadr_t *GetAddress( void ); + + // Allow creating object to store a 32 bit value and retrieve it + virtual void SetUserData( unsigned int userData ); + virtual unsigned int GetUserData(void ) const; + + // Allow other objects to get the raw socket interger + virtual int GetSocketNumber( void ) const; + // Called when FD_ISSET noted that the socket has incoming data + virtual bool ReceiveData( void ); + // Called to get current time + static float GetClock( void ); + +private: + const char *m_pSocketName; + // Socket listen address + bool m_bValid; + // Socket IP address + netadr_t m_Address; + // Has the IP address been resolved + bool m_bResolved; + // Internal message buffers + CUtlVector<CMsgBuffer> m_MsgBuffers; + CMsgBuffer m_SendBuffer; + // critical section for accessing buffers + void *m_pBufferCS; + // One or more listeners for the incoming message + CMsgHandler *m_pMessageHandlers; + // Winsock socket number + int m_Socket; + // User 32 bit value + unsigned int m_nUserData; + // Socket to which non Broadcast SendMessage was directed. The socket will wait for a response + // from that exact address + netadr_t m_ToAddress; + // Set to true if the send was a Broadcast, and therefore from != to address is okay + bool m_bBroadcastSend; + + int m_iTotalPackets; // total number of packets in a fragment + int m_iCurrentPackets; // current packet count + int m_iSeqNo; // the sequence number of the packet + int m_iRetries; + CMsgBuffer m_CurPacket[MAX_PACKETS]; // store for the packet +}; + +#endif // SOCKET_H
\ No newline at end of file diff --git a/tracker/common/TrackerMessageFlags.h b/tracker/common/TrackerMessageFlags.h new file mode 100644 index 0000000..445679c --- /dev/null +++ b/tracker/common/TrackerMessageFlags.h @@ -0,0 +1,22 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef TRACKERMESSAGEFLAGS_H +#define TRACKERMESSAGEFLAGS_H +#pragma once + +//----------------------------------------------------------------------------- +// Purpose: the set of flags that can modify a message +//----------------------------------------------------------------------------- +enum TrackerMessageFlags_e +{ + MESSAGEFLAG_SYSTEM = 1<<2, // message is from the tracker system + MESSAGEFLAG_MARKETING = 1<<3, // message is from the tracker system +}; + + +#endif // TRACKERMESSAGEFLAGS_H diff --git a/tracker/common/TrackerProtocol.h b/tracker/common/TrackerProtocol.h new file mode 100644 index 0000000..3a63433 --- /dev/null +++ b/tracker/common/TrackerProtocol.h @@ -0,0 +1,161 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Holds all the protocol bits and defines used in tracker networking +// +// $NoKeywords: $ +//============================================================================= + +#ifndef TRACKERPROTOCOL_H +#define TRACKERPROTOCOL_H +#ifdef _WIN32 +#pragma once +#endif + +// failed return versions of the messages are the TMSG_FAIL_OFFSET + 10000 +#define TMSG_FAIL_OFFSET 10000 + +//----------------------------------------------------------------------------- +// Purpose: List of all the tracker messages used +// msgID's are 32bits big +//----------------------------------------------------------------------------- +enum TrackerMsgID_t +{ + // generic messages + TMSG_NONE = 0, // no message id + TMSG_ACK = 1, // packet acknowledgement + + // server -> Client messages + TSVC_BASE = 1000, + + TSVC_CHALLENGE, + TSVC_LOGINOK, + TSVC_LOGINFAIL, + TSVC_DISCONNECT, + TSVC_FRIENDS, + TSVC_FRIENDUPDATE, + TSVC_HEARTBEAT, + TSVC_PINGACK, // acknowledgement of TCLS_PING packet + TSVC_FRIENDINFO, + TSVC_USERVALID, + TSVC_FRIENDSFOUND, + TSVC_NOFRIENDS, + TSVC_MESSAGE, // message passed through from another client + TSVC_GAMEINFO, // information about a friends' game + TSVC_AUTHREQUEST, // a user requesting auth from the receiving user + TSVC_CONNECTIONKEEPALIVE, // information that an attemption connect is taking time, and the user should wait + TSVC_ROUTEMESSAGEFAILED, // chat message failed to be routed through the servers + TSVC_REDIRECTLOGIN, // tells the client to redirect their login attempt to a different server + + // Client -> server messages + TCLS_BASE = 2000, + + TCLS_LOGIN, // login message + TCLS_RESPONSE, // response to login challenge + TCLS_PING, + TCLS_FRIENDSEARCH, + TCLS_HEARTBEAT, + TCLS_AUTHUSER, + TCLS_REQAUTH, + TCLS_FRIENDINFO, // friend info request + TCLS_SETINFO, + TCLS_ROUTETOFRIEND, // generic reroute of a message to a friend + + // Client -> Client messages + TCL_BASE = 3000, + TCL_MESSAGE, // chat text message + TCL_USERBLOCK, // soon to be obselete + TCL_ADDEDTOCHAT, + TCL_CHATADDUSER, + TCL_CHATUSERLEAVE, + TCL_TYPINGMESSAGE, + TCL_FRIENDNETMESSAGE, + + // server -> server messages + TSV_BASE = 4000, + + TSV_WHOISPRIMARY, + TSV_PRIMARYSRV, + TSV_REQUESTINFO, + TSV_TOPOLOGYINFO, + TSV_REQUESTTOPOLOGYINFO, + TSV_SERVERPING, + TSV_MONITORINFO, + TSV_LOCKUSERRANGE, + TSV_UNLOCKUSERRANGE, + TSV_REDIRECTTOUSER, + TSV_FORCEDISCONNECTUSER, + TSV_USERCHECKMESSAGES, + TSV_USERAUTHREQUEST, + TSV_USERSTATUSCHANGED, + TSV_USERRELOADFRIENDSLIST, + TSV_REGISTERSERVERINNETWORK, + TSV_SERVERSHUTTINGDOWN, + TSV_UPDATEACTIVEUSERRANGESTATUS, + + // game server -> Client + TCLG_BASE = 5000, + + // common msg failed ID's + TSVC_HEARTBEAT_FAIL = TSVC_HEARTBEAT + TMSG_FAIL_OFFSET, + + TCLS_HEARTBEAT_FAIL = TCLS_HEARTBEAT + TMSG_FAIL_OFFSET, + + TCL_MESSAGE_FAIL = TCL_MESSAGE + TMSG_FAIL_OFFSET, + +}; + +//----------------------------------------------------------------------------- +// Purpose: List of reasons explaining to user why they have been disconnected +// from the friends network +//----------------------------------------------------------------------------- +enum TrackerLogoffReason_t +{ + TRACKER_LOGOFF_NOREASON, + + // server reasons for disconnecting user + TRACKER_LOGOFF_LOGGEDINELSEWHERE, // user has logged into friends at a different location + TRACKER_LOGOFF_SERVERWORK, // server needs to do work (like lock the user range) + TRACKER_LOGOFF_SERVERSHUTDOWN, // server has been shutdown + TRACKER_LOGOFF_TIMEDOUT, // user hasn't heartbeat'd to server recently enough + TRACKER_LOGOFF_REQUESTED, // user has requested to logoff + TRACKER_LOGOFF_FIREWALL, // users' firewall won't allow enough packets through + TRACKER_LOGOFF_NOTCONNECTED, // user sent server a packet that implied they think they're logged in but they're not + TRACKER_LOGOFF_INVALIDSTEAMTICKET, // users steam ticket is invalid + + // client reasons for being disconnected + TRACKER_LOGOFF_JOINEDGAME, // user has logged off because they joined a game + TRACKER_LOGOFF_CONNECTIONTIMEOUT, // user connection has timed out + TRACKER_LOGOFF_SERVERMESSAGEFAIL, // a message to the server was not successfully transmitted + + TRACKER_LOGOFF_TOOMANYATTEMPTS, // too many login attempts have been performed + TRACKER_LOGOFF_OFFLINE, // steam is in offline mode so don't try to connect +}; + + +//----------------------------------------------------------------------------- +// Purpose: List of all the reasons a login attempt may fail +//----------------------------------------------------------------------------- +enum TrackerLoginFailReason_t +{ + TRACKER_LOGINFAIL_NOREASON = 0, + TRACKER_LOGINFAIL_NOSUCHUSER = -2, + TRACKER_LOGINFAIL_ALREADLOGGEDIN = -3, + TRACKER_LOGINFAIL_INVALIDSTEAMTICKET = -4, + TRACKER_LOGINFAIL_BUILDOUTOFDATE = -5, + TRACKER_LOGINFAIL_PLATFORMOUTOFDATE = -6, +}; + +//----------------------------------------------------------------------------- +// Purpose: Holds basic status for a friend +//----------------------------------------------------------------------------- +struct FriendStatus_t +{ + unsigned int friendID; + int status; + unsigned int sessionID; + unsigned int ip; + unsigned int port; + unsigned int serverID; +}; + +#endif // TRACKERPROTOCOL_H diff --git a/tracker/common/UtlMsgBuffer.cpp b/tracker/common/UtlMsgBuffer.cpp new file mode 100644 index 0000000..b547d6a --- /dev/null +++ b/tracker/common/UtlMsgBuffer.cpp @@ -0,0 +1,332 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "UtlMsgBuffer.h" + +#include <string.h> + +//----------------------------------------------------------------------------- +// Purpose: bitfields for use in variable descriptors +//----------------------------------------------------------------------------- +enum +{ + PACKBIT_CONTROLBIT = 0x01, // this must always be set + PACKBIT_INTNAME = 0x02, // if this is set then it's an int named variable, instead of a string + PACKBIT_BINARYDATA = 0x04, // signifies the data in this variable is binary, it's not a string +}; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CUtlMsgBuffer::CUtlMsgBuffer(unsigned short msgID, int initialSize) : m_Memory(0, initialSize) +{ + m_iMsgID = msgID; + m_iWritePos = 0; + m_iReadPos = 0; + m_iNextVarPos = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Constructor, takes initial data +//----------------------------------------------------------------------------- +CUtlMsgBuffer::CUtlMsgBuffer(unsigned short msgID, void const *data, int dataSize) : m_Memory(0, dataSize) +{ + m_iMsgID = msgID; + m_iWritePos = (short)dataSize; + m_iReadPos = 0; + m_iNextVarPos = 0; + + memcpy(Base(), data, dataSize); +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CUtlMsgBuffer::~CUtlMsgBuffer() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Copy +//----------------------------------------------------------------------------- +CUtlMsgBuffer &CUtlMsgBuffer::Copy(const CUtlMsgBuffer &rhs) +{ + m_iWritePos = rhs.m_iWritePos; + m_iReadPos = rhs.m_iReadPos; + m_iNextVarPos = rhs.m_iNextVarPos; + + m_Memory.EnsureCapacity(rhs.m_Memory.NumAllocated()); + if ( rhs.m_Memory.NumAllocated() > 0 ) + { + memcpy(Base(), rhs.Base(), rhs.m_Memory.NumAllocated()); + } + return *this; +} + +//----------------------------------------------------------------------------- +// Purpose: Writes string data to the message +// Input : *name - name of the variable +// *data - pointer to the string data to write +//----------------------------------------------------------------------------- +void CUtlMsgBuffer::WriteString(const char *name, const char *data) +{ + // write out the variable type + unsigned char vtype = PACKBIT_CONTROLBIT; // stringname var, string data + Write(&vtype, 1); + + // write out the variable name + Write(name, strlen(name) + 1); + + // write out the size of the data + unsigned short size = (unsigned short)(strlen(data) + 1); + Write(&size, 2); + + // write out the data itself + Write(data, size); +} + +//----------------------------------------------------------------------------- +// Purpose: Writes out a named block of data +//----------------------------------------------------------------------------- +void CUtlMsgBuffer::WriteBlob(const char *name, const void *data, int dataSize) +{ + // write out the variable type + unsigned char vtype = PACKBIT_CONTROLBIT | PACKBIT_BINARYDATA; // stringname var, binary data + Write(&vtype, 1); + + // write out the variable name + Write(name, strlen(name) + 1); + + // write out the size of the data + unsigned short size = (unsigned short)dataSize; + Write(&size, 2); + + // write out the data itself + Write(data, dataSize); +} + +//----------------------------------------------------------------------------- +// Purpose: Writes out another UtlMsgBuffer as an element of this one +//----------------------------------------------------------------------------- +void CUtlMsgBuffer::WriteBuffer(const char *name, const CUtlMsgBuffer *buffer) +{ + // write out the variable type + unsigned char vtype = PACKBIT_CONTROLBIT | PACKBIT_BINARYDATA; // stringname var, binary data + Write(&vtype, 1); + + // write out the variable name + Write(name, strlen(name) + 1); + + // write out the size of the data + unsigned short size = (unsigned short) buffer->DataSize(); + Write(&size, 2); + + // write out the data itself + Write(buffer->Base(), size); +} + +//----------------------------------------------------------------------------- +// Purpose: Reads from the buffer, increments read position +// returns false if past end of buffer +//----------------------------------------------------------------------------- +bool CUtlMsgBuffer::Read(void *buffer, int readAmount) +{ + if (m_iReadPos + readAmount >= m_iWritePos) + return false; + + memcpy(buffer, &m_Memory[m_iReadPos], readAmount); + m_iReadPos += readAmount; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Reads characterse from the buffer until a null is hit +//----------------------------------------------------------------------------- +bool CUtlMsgBuffer::ReadUntilNull(void *buffer, int bufferSize) +{ + int nullPos = m_iReadPos; + + // look through the buffer for the null terminator + while (nullPos < m_Memory.NumAllocated() && m_Memory[nullPos] != 0) + { + nullPos++; + } + + if (nullPos >= m_Memory.NumAllocated()) + { + // never found a null terminator + ((char *)buffer)[0] = 0; + return false; + } + + // copy from the null terminator + int copySize = nullPos - m_iReadPos; + if (copySize > bufferSize) + { + copySize = bufferSize - 1; + } + + // copy out the data and return + memcpy(buffer, &m_Memory[m_iReadPos], copySize); + ((char *)buffer)[copySize] = 0; + m_iReadPos += (copySize+1); + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Writes to the buffer, incrementing the write position +// assumes enough space has already been allocated for the write +//----------------------------------------------------------------------------- +void CUtlMsgBuffer::Write(void const *data, int size) +{ + // make sure it will fit + m_Memory.EnsureCapacity(m_iWritePos + size); + + // normal write + memcpy(&m_Memory[m_iWritePos], data, size); + + // increment write position + m_iWritePos += size; +} + +//----------------------------------------------------------------------------- +// Purpose: Reads in a named variable length data blob +// returns number of bytes read, 0 on failure +//----------------------------------------------------------------------------- +int CUtlMsgBuffer::ReadBlob(const char *name, void *data, int dataBufferSize) +{ + int dataSize = 0; + char *readData = (char *)FindVar(name, dataSize); + if (!readData) + { + memset(data, 0, dataBufferSize); + return 0; + } + + // ensure against buffer overflow + if (dataSize > dataBufferSize) + dataSize = dataBufferSize; + + // copy out data + memcpy(data, readData, dataSize); + return dataSize; +} + +//----------------------------------------------------------------------------- +// Purpose: Reads a blob of binary data into it's own buffer +//----------------------------------------------------------------------------- +bool CUtlMsgBuffer::ReadBuffer(const char *name, CUtlMsgBuffer &buffer) +{ + int dataSize = 0; + char *readData = (char *)FindVar(name, dataSize); + if (!readData) + { + return false; + } + + buffer.m_Memory.EnsureCapacity(dataSize); + memcpy(&buffer.m_Memory[0], readData, dataSize); + buffer.m_iReadPos = 0; + buffer.m_iWritePos = (short)dataSize; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: reads out the next variable available in the buffer +// fills out parameters with var details and data +// returns false if no more vars available +//----------------------------------------------------------------------------- +bool CUtlMsgBuffer::ReadNextVar(char varname[32], bool &stringData, void *data, int &dataSize) +{ + // read the type + unsigned char vtype = 1; + if (!Read(&vtype, 1)) + return false; + + // check for null-termination type + if (vtype == 0) + return false; + + stringData = !(vtype & PACKBIT_BINARYDATA); + + // read the variable name + if (!ReadUntilNull(varname, 31)) + return false; + + // read the data size + unsigned short size = 0; + if (!Read(&size, 2)) + return false; + + // ensure against buffer overflows + if (dataSize > size) + dataSize = size; + + // copy data + memcpy(data, &m_Memory[m_iReadPos], dataSize); + + // store of the next position, since that is probably where the next read needs to occur + m_iReadPos += size; + m_iNextVarPos = m_iReadPos; + return true; +} + + +//----------------------------------------------------------------------------- +// Purpose: sets the read/write position to be at the specified variable +// returns pointer to buffer position on success, NULL if not found +//----------------------------------------------------------------------------- +void *CUtlMsgBuffer::FindVar(const char *name, int &dataSize) +{ + // reset to where we Think the next var will be read from + m_iReadPos = m_iNextVarPos; + int loopCount = 2; + + // loop through looking for the specified variable + while (loopCount--) + { + unsigned char vtype = 1; + while (Read(&vtype, 1)) + { + // check for null-termination type + if (vtype == 0) + break; + + // read the variable name + char varname[32]; + if (!ReadUntilNull(varname, 31)) + break; + + // read the data size + unsigned short size = 0; + if (!Read(&size, 2)) + break; + + // is this our variable? + if (!stricmp(varname, name)) + { + dataSize = size; + void *data = &m_Memory[m_iReadPos]; + + // store of the next position, since that is probably where the next read needs to occur + m_iReadPos += size; + m_iNextVarPos = m_iReadPos; + return data; + } + + // skip over the data block to the next variable + m_iReadPos += size; + if (m_iReadPos >= m_iWritePos) + break; + } + + // we haven't found the data yet, Start again + m_iReadPos = 0; + } + + return NULL; +} diff --git a/tracker/common/UtlMsgBuffer.h b/tracker/common/UtlMsgBuffer.h new file mode 100644 index 0000000..1b4a818 --- /dev/null +++ b/tracker/common/UtlMsgBuffer.h @@ -0,0 +1,198 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Generic named data buffer, declaration and implementation +// +//============================================================================= + +#ifndef UTLMSGBUFFER_H +#define UTLMSGBUFFER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "UtlMemory.h" + +#pragma warning(disable: 4244) // warning C4244: '=' : conversion from 'int' to 'short', possible loss of data + +//----------------------------------------------------------------------------- +// Purpose: Generic named data buffer +//----------------------------------------------------------------------------- +class CUtlMsgBuffer +{ +public: + CUtlMsgBuffer(unsigned short msgID, int initialSize); + CUtlMsgBuffer(unsigned short msgID, void const *data, int dataSize); + ~CUtlMsgBuffer(); + + unsigned short GetMsgID() const { return m_iMsgID; } + void SetMsgID(unsigned short msgID) { m_iMsgID = msgID; } + + // read functions + bool ReadInt(const char *name, int &data); + bool ReadUInt(const char *name, unsigned int &data); + bool ReadString(const char *name, char *data, int dataBufferSize); + bool ReadBuffer(const char *name, CUtlMsgBuffer &buffer); + // returns number of bytes read, 0 on failure + int ReadBlob(const char *name, void *data, int dataBufferSize); + + // reads out the next variable available in the buffer + // fills out parameters with var details and data + // returns false if no more vars available + bool ReadNextVar(char name[32], bool &stringData, void *data, int &dataSize); + + // write functions + void WriteInt(const char *name, int data); + void WriteUInt(const char *name, unsigned int data); + void WriteString(const char *name, const char *data); + void WriteBlob(const char *name, const void *data, int dataSize); + void WriteBuffer(const char *name, const CUtlMsgBuffer *buffer); + + // returns a pointer to the data buffer, and its size, of the specified variable + void *FindVar(const char *name, int &dataSizeOut); + + // pads the buffer to the specified boundary (in bytes) + void PadBuffer(int boundary); + + // makes sure the message has this much space allocated + void EnsureCapacity(int dataSize); + + // returns the number of bytes used by the message + int DataSize() const; + + // returns a pointer to the base data + void *Base(); + + // returns a const pointer to the base data + const void *Base() const; + + // advances the write pointer - used when you write directly into the buffer + void SetWritePos(int size); + + CUtlMsgBuffer& Copy(const CUtlMsgBuffer &rhs); + + // copy constructor + CUtlMsgBuffer(const CUtlMsgBuffer &rhs) + { + m_iMsgID = rhs.m_iMsgID; + m_iWritePos = rhs.m_iWritePos; + m_iReadPos = rhs.m_iReadPos; + m_iNextVarPos = rhs.m_iNextVarPos; + + m_Memory.EnsureCapacity(rhs.m_Memory.NumAllocated()); + if ( rhs.m_Memory.NumAllocated() > 0 ) + { + memcpy(Base(), rhs.Base(), rhs.m_Memory.NumAllocated()); + } + } + +private: + + bool Read(void *buffer, int readAmount); + bool ReadUntilNull(void *buffer, int bufferSize); + void Write(void const *data, int size); + + CUtlMemory<char> m_Memory; + + unsigned short m_iMsgID; + short m_iWritePos; // position in buffer we are currently writing to + short m_iReadPos; // current reading position + short m_iNextVarPos; // a guess at which variable is most likely to be read next +}; + +//----------------------------------------------------------------------------- +// Purpose: returns the number of bytes used by the message +//----------------------------------------------------------------------------- +inline int CUtlMsgBuffer::DataSize() const +{ + // return the highest read/write mark + if (m_iWritePos > m_iReadPos) + return m_iWritePos; + + return m_iReadPos; +} + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to the base data +//----------------------------------------------------------------------------- +inline void *CUtlMsgBuffer::Base() +{ + return &m_Memory[0]; +} + +//----------------------------------------------------------------------------- +// Purpose: returns a pointer to the base data +//----------------------------------------------------------------------------- +inline const void *CUtlMsgBuffer::Base() const +{ + return &m_Memory[0]; +} + +//----------------------------------------------------------------------------- +// Purpose: ensures capacity +//----------------------------------------------------------------------------- +inline void CUtlMsgBuffer::EnsureCapacity(int dataSize) +{ + m_Memory.EnsureCapacity(dataSize); +} + +//----------------------------------------------------------------------------- +// Purpose: pads the buffer to the specified boundary (in bytes) +//----------------------------------------------------------------------------- +inline void CUtlMsgBuffer::PadBuffer(int boundary) +{ + // pad the buffer to be the right size for encryption + int pad = (boundary - (DataSize() % boundary)); + Write("\0\0\0\0\0\0\0\0\0\0\0\0", pad); +} + +//----------------------------------------------------------------------------- +// Purpose: Reads in a named 4-byte int, returns true on sucess, false on failure +//----------------------------------------------------------------------------- +inline bool CUtlMsgBuffer::ReadInt(const char *name, int &data) +{ + return (ReadBlob(name, &data, 4) == 4); +} + +//----------------------------------------------------------------------------- +// Purpose: Reads in a named 4-byte unsigned int, returns true on sucess, false on failure +//----------------------------------------------------------------------------- +inline bool CUtlMsgBuffer::ReadUInt(const char *name, unsigned int &data) +{ + return (ReadBlob(name, &data, 4) == 4); +} + +//----------------------------------------------------------------------------- +// Purpose: Reads in a named variable length character string +// returns true on sucess, false on failure +//----------------------------------------------------------------------------- +inline bool CUtlMsgBuffer::ReadString(const char *name, char *data, int dataBufferSize) +{ + return (ReadBlob(name, data, dataBufferSize) > 0); +} + +//----------------------------------------------------------------------------- +// Purpose: Writes out an integer to the message +//----------------------------------------------------------------------------- +inline void CUtlMsgBuffer::WriteInt(const char *name, int data) +{ + WriteBlob(name, &data, 4); +} + +//----------------------------------------------------------------------------- +// Purpose: Writes out an unsigned integer to the message +//----------------------------------------------------------------------------- +inline void CUtlMsgBuffer::WriteUInt(const char *name, unsigned int data) +{ + WriteBlob(name, &data, 4); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +inline void CUtlMsgBuffer::SetWritePos(int size) +{ + m_iWritePos = size; +} + + +#endif // UTLMSGBUFFER_H diff --git a/tracker/common/inetapi.h b/tracker/common/inetapi.h new file mode 100644 index 0000000..dfc4d35 --- /dev/null +++ b/tracker/common/inetapi.h @@ -0,0 +1,42 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#if !defined( INETAPI_H ) +#define INETAPI_H +#ifdef _WIN32 +#pragma once +#endif + +#include "netadr.h" + +//----------------------------------------------------------------------------- +// Purpose: Internal winsock helpers for launcher +//----------------------------------------------------------------------------- +class INetAPI +{ +public: + // Convert a netadr_t to sockaddr + virtual void NetAdrToSockAddr( netadr_t *a, struct sockaddr *s ) = 0; + // Convert a sockaddr to netadr_t + virtual void SockAddrToNetAdr( struct sockaddr *s, netadr_t *a ) = 0; + + // Convert a netadr_t to a string + virtual char *AdrToString( netadr_t *a ) = 0; + // Convert a string address to a netadr_t, doing DNS if needed + virtual bool StringToAdr( const char *s, netadr_t *a ) = 0; + // Look up IP address for socket + virtual void GetSocketAddress( int socket, netadr_t *a ) = 0; + + virtual bool CompareAdr( netadr_t *a, netadr_t *b ) =0; + + // return the IP of the local host + virtual void GetLocalIP(netadr_t *a)=0; + +}; + +extern INetAPI *net; + +#endif // INETAPI_H
\ No newline at end of file diff --git a/tracker/common/msgbuffer.cpp b/tracker/common/msgbuffer.cpp new file mode 100644 index 0000000..7bd576a --- /dev/null +++ b/tracker/common/msgbuffer.cpp @@ -0,0 +1,421 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#include <string.h> +#include <assert.h> +#include "msgbuffer.h" +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> + +#pragma warning(disable: 4244) // warning C4244: '=' : conversion from 'int' to 'unsigned char', possible loss of data + +//----------------------------------------------------------------------------- +// Purpose: Allocate message buffer +// Input : *buffername - +// *ef - +//----------------------------------------------------------------------------- +CMsgBuffer::CMsgBuffer( const char *buffername, void (*ef)( const char *fmt, ... ) /*= NULL*/ ) +{ + m_pszBufferName = buffername; + m_pfnErrorFunc = ef; + m_bAllowOverflow = false; // if false, Error + m_bOverFlowed = false; // set to true if the buffer size failed + m_nMaxSize = NET_MAXMESSAGE; + m_nPushedCount = 0; + m_bPushed = false; + m_nReadCount = 0; + m_bBadRead = false; + + Clear(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CMsgBuffer::~CMsgBuffer( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: Temporarily remember the read position so we can reset it +//----------------------------------------------------------------------------- +void CMsgBuffer::Push( void ) +{ + // ??? Allow multiple pushes without matching pops ??? + assert( !m_bPushed ); + + m_nPushedCount = m_nReadCount; + m_bPushed = true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMsgBuffer::Pop( void ) +{ + assert( m_bPushed ); + + m_nReadCount = m_nPushedCount; + m_bPushed = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : allowed - +//----------------------------------------------------------------------------- +void CMsgBuffer::SetOverflow( bool allowed ) +{ + m_bAllowOverflow = allowed; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CMsgBuffer::GetMaxSize( void ) +{ + return m_nMaxSize; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : void * +//----------------------------------------------------------------------------- +void * CMsgBuffer::GetData( void ) +{ + return m_rgData; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CMsgBuffer::GetCurSize( void ) +{ + return m_nCurSize; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int CMsgBuffer::GetReadCount( void ) +{ + return m_nReadCount; +} + +//----------------------------------------------------------------------------- +// Purpose: data accessor +//----------------------------------------------------------------------------- +void CMsgBuffer::SetTime(float time) +{ + m_fRecvTime = time; +} + +//----------------------------------------------------------------------------- +// Purpose: data accessor +//----------------------------------------------------------------------------- +float CMsgBuffer::GetTime() +{ + return m_fRecvTime; +} + +//----------------------------------------------------------------------------- +// Purpose: data accessor +//----------------------------------------------------------------------------- +void CMsgBuffer::SetNetAddress(netadr_t &adr) +{ + m_NetAddr = adr; +} + +//----------------------------------------------------------------------------- +// Purpose: data accessor +//----------------------------------------------------------------------------- +netadr_t &CMsgBuffer::GetNetAddress() +{ + return m_NetAddr; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMsgBuffer::WriteByte( int c ) +{ + unsigned char *buf; + buf = (unsigned char *)GetSpace( 1 ); + buf[0] = c; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : c - +//----------------------------------------------------------------------------- +void CMsgBuffer::WriteShort ( int c ) +{ + unsigned char *buf; + buf = (unsigned char *)GetSpace( 2 ); + buf[0] = c&0xff; + buf[1] = c>>8; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : c - +//----------------------------------------------------------------------------- +void CMsgBuffer::WriteLong (int c) +{ + unsigned char *buf; + + buf = (unsigned char *)GetSpace( 4 ); + buf[0] = c&0xff; + buf[1] = (c>>8)&0xff; + buf[2] = (c>>16)&0xff; + buf[3] = c>>24; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : f - +//----------------------------------------------------------------------------- +void CMsgBuffer::WriteFloat (float f) +{ + union + { + float f; + int l; + } dat; + + dat.f = f; + Write( &dat.l, 4 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *s - +//----------------------------------------------------------------------------- +void CMsgBuffer::WriteString (const char *s) +{ + if ( !s ) + { + Write ("", 1); + } + else + { + Write ( s, strlen( s ) + 1 ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : iSize - +// *buf - +//----------------------------------------------------------------------------- +void CMsgBuffer::WriteBuf( int iSize, void *buf ) +{ + if ( !buf ) + { + return; + } + + Write( buf, iSize ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMsgBuffer::BeginReading (void) +{ + m_nReadCount = 0; + m_bBadRead = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int CMsgBuffer::ReadByte +//----------------------------------------------------------------------------- +int CMsgBuffer::ReadByte (void) +{ + int c; + + if ( m_nReadCount + 1 > m_nCurSize ) + { + m_bBadRead = true; + return -1; + } + + c = ( unsigned char )m_rgData[ m_nReadCount ]; + m_nReadCount++; + return c; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int CMsgBuffer::ReadShort +//----------------------------------------------------------------------------- +int CMsgBuffer::ReadShort (void) +{ + int c; + + if ( m_nReadCount + 2 > m_nCurSize ) + { + m_bBadRead = true; + return -1; + } + + c = (short)(m_rgData[m_nReadCount] + (m_rgData[m_nReadCount+1]<<8)); + m_nReadCount += 2; + + return c; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int CMsgBuffer::ReadLong +//----------------------------------------------------------------------------- +int CMsgBuffer::ReadLong (void) +{ + int c; + + if (m_nReadCount+4 > m_nCurSize) + { + m_bBadRead = true; + return -1; + } + + c = m_rgData[m_nReadCount] + + (m_rgData[m_nReadCount+1]<<8) + + (m_rgData[m_nReadCount+2]<<16) + + (m_rgData[m_nReadCount+3]<<24); + + m_nReadCount += 4; + + return c; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : float CMsgBuffer::ReadFloat +//----------------------------------------------------------------------------- +float CMsgBuffer::ReadFloat (void) +{ + union + { + unsigned char b[4]; + float f; + } dat; + + dat.b[0] = m_rgData[m_nReadCount]; + dat.b[1] = m_rgData[m_nReadCount+1]; + dat.b[2] = m_rgData[m_nReadCount+2]; + dat.b[3] = m_rgData[m_nReadCount+3]; + m_nReadCount += 4; + return dat.f; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : iSize - +// *pbuf - +// Output : int +//----------------------------------------------------------------------------- +int CMsgBuffer::ReadBuf( int iSize, void *pbuf ) +{ + if (m_nReadCount + iSize > m_nCurSize) + { + m_bBadRead = true; + return -1; + } + + memcpy( pbuf, &m_rgData[m_nReadCount], iSize ); + m_nReadCount += iSize; + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char * +//----------------------------------------------------------------------------- +char *CMsgBuffer::ReadString (void) +{ + static char string[ NET_MAXMESSAGE ]; + int l,c; + + l = 0; + do + { + c = (char)ReadByte(); + if ( c == -1 || c == 0 ) + break; + string[l] = c; + l++; + } while ( l < sizeof(string)-1 ); + + string[ l ] = 0; + + return string; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CMsgBuffer::Clear( void ) +{ + m_nCurSize = 0; + m_bOverFlowed = false; + m_nReadCount = 0; + m_bBadRead = false; + memset( m_rgData, 0, sizeof( m_rgData ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : length - +//----------------------------------------------------------------------------- +void *CMsgBuffer::GetSpace( int length ) +{ + void *d; + + if (m_nCurSize + length > m_nMaxSize) + { + if ( !m_bAllowOverflow ) + { + if ( m_pfnErrorFunc ) + { + ( *m_pfnErrorFunc )( "CMsgBuffer(%s), no room for %i bytes, %i / %i already in use\n", + m_pszBufferName, length, m_nCurSize, m_nMaxSize ); + } + return NULL; + } + + if (length > m_nMaxSize) + { + if ( m_pfnErrorFunc ) + { + ( *m_pfnErrorFunc )( "CMsgBuffer(%s), no room for %i bytes, %i is max\n", + m_pszBufferName, length, m_nMaxSize ); + } + return NULL; + } + + m_bOverFlowed = true; + Clear(); + } + + d = m_rgData + m_nCurSize; + m_nCurSize += length; + return d; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *m_rgData - +// length - +//----------------------------------------------------------------------------- +void CMsgBuffer::Write(const void *m_rgData, int length) +{ + memcpy( GetSpace(length), m_rgData, length ); +}
\ No newline at end of file diff --git a/tracker/common/msgbuffer.h b/tracker/common/msgbuffer.h new file mode 100644 index 0000000..ac2bfd9 --- /dev/null +++ b/tracker/common/msgbuffer.h @@ -0,0 +1,108 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#if !defined( MSGBUFFER_H ) +#define MSGBUFFER_H +#ifdef _WIN32 +#pragma once +#endif + +#include "netadr.h" + +//----------------------------------------------------------------------------- +// Purpose: Generic byte level message buffer with read/write support +//----------------------------------------------------------------------------- +class CMsgBuffer +{ +public: + enum + { + NET_MAXMESSAGE = 8192 + }; + + // Buffers must be named + CMsgBuffer( const char *buffername = "unnamed", void (*ef)( PRINTF_FORMAT_STRING const char *fmt, ... ) = 0 ); + virtual ~CMsgBuffer( void ); + + // Reset the buffer for writing + void Clear( void ); + // Get current # of bytes + int GetCurSize( void ); + // Get max # of bytes + int GetMaxSize( void ); + // Get pointer to raw data + void *GetData( void ); + // Set/unset the allow overflow flag + void SetOverflow( bool allowed ); + // Start reading from buffer + void BeginReading( void ); + // Get current read byte + int GetReadCount( void ); + + // Push read count ( to peek at data ) + void Push( void ); + void Pop( void ); + + // Writing functions + void WriteByte(int c); + void WriteShort(int c); + void WriteLong(int c); + void WriteFloat(float f); + void WriteString(const char *s); + void WriteBuf( int iSize, void *buf ); + + // Reading functions + int ReadByte( void ); + int ReadShort( void ); + int ReadLong( void ); + float ReadFloat( void ); + char *ReadString( void ); + int ReadBuf( int iSize, void *pbuf ); + + // setting and storing time received + void SetTime(float time); + float GetTime(); + + // net address received from + void SetNetAddress(netadr_t &adr); + netadr_t &GetNetAddress(); + +private: + // Ensures sufficient space to append an object of length + void *GetSpace( int length ); + // Copy buffer in at current writing point + void Write( const void *data, int length ); + +private: + // Name of buffer in case of debugging/errors + const char *m_pszBufferName; + // Optional error callback + void ( *m_pfnErrorFunc )( PRINTF_FORMAT_STRING const char *fmt, ... ); + + // Current read pointer + int m_nReadCount; + // Push/pop read state + int m_nPushedCount; + bool m_bPushed; + // Did we hit the end of the read buffer? + bool m_bBadRead; + // Max size of buffer + int m_nMaxSize; + // Current bytes written + int m_nCurSize; + // if false, call m_pfnErrorFunc + bool m_bAllowOverflow; + // set to true when buffer hits end + bool m_bOverFlowed; + // Internal storage + unsigned char m_rgData[ NET_MAXMESSAGE ]; + // time received + float m_fRecvTime; + // address received from + netadr_t m_NetAddr; +}; + +#endif // !MSGBUFFER_H
\ No newline at end of file diff --git a/tracker/common/netapi.cpp b/tracker/common/netapi.cpp new file mode 100644 index 0000000..914f5f3 --- /dev/null +++ b/tracker/common/netapi.cpp @@ -0,0 +1,277 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= +#include <stdio.h> +#include <stdlib.h> +#if defined( WIN32 ) +#if !defined( _X360 ) +#include "winsock.h" +#else +#include "winsockx.h" +#endif +#elif defined( POSIX ) +#include <sys/socket.h> +#include <netdb.h> +#include <resolv.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#else +#error +#endif +#include "inetapi.h" + +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +// memdbgon must be the last include file in a .cpp file!!! +#include <tier0/memdbgon.h> +#pragma warning(disable: 4706) // warning C4706: assignment within conditional expression + +//----------------------------------------------------------------------------- +// Purpose: Implements INetAPI +//----------------------------------------------------------------------------- +class CNetAPI : public INetAPI +{ +public: + virtual void NetAdrToSockAddr( netadr_t *a, struct sockaddr *s ); + virtual void SockAddrToNetAdr( struct sockaddr *s, netadr_t *a ); + + virtual char *AdrToString( netadr_t *a ); + virtual bool StringToAdr( const char *s, netadr_t *a ); + + virtual void GetSocketAddress( int socket, netadr_t *a ); + + virtual bool CompareAdr( netadr_t *a, netadr_t *b ); + + virtual void GetLocalIP(netadr_t *a); +}; + +// Expose interface +static CNetAPI g_NetAPI; +INetAPI *net = ( INetAPI * )&g_NetAPI; + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *a - +// *s - +//----------------------------------------------------------------------------- +void CNetAPI::NetAdrToSockAddr (netadr_t *a, struct sockaddr *s) +{ + memset (s, 0, sizeof(*s)); + + if (a->type == NA_BROADCAST) + { + ((struct sockaddr_in *)s)->sin_family = AF_INET; + ((struct sockaddr_in *)s)->sin_port = a->port; + ((struct sockaddr_in *)s)->sin_addr.s_addr = INADDR_BROADCAST; + } + else if (a->type == NA_IP) + { + ((struct sockaddr_in *)s)->sin_family = AF_INET; + ((struct sockaddr_in *)s)->sin_addr.s_addr = *(int *)&a->ip; + ((struct sockaddr_in *)s)->sin_port = a->port; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *s - +// *a - +//----------------------------------------------------------------------------- +void CNetAPI::SockAddrToNetAdr( struct sockaddr *s, netadr_t *a ) +{ + if (s->sa_family == AF_INET) + { + a->type = NA_IP; + *(int *)&a->ip = ((struct sockaddr_in *)s)->sin_addr.s_addr; + a->port = ((struct sockaddr_in *)s)->sin_port; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *a - +// Output : char +//----------------------------------------------------------------------------- +char *CNetAPI::AdrToString( netadr_t *a ) +{ + static char s[64]; + + memset(s, 0, 64); + + if ( a ) + { + if ( a->type == NA_LOOPBACK ) + { + sprintf (s, "loopback"); + } + else if ( a->type == NA_IP ) + { + sprintf(s, "%i.%i.%i.%i:%i", a->ip[0], a->ip[1], a->ip[2], a->ip[3], ntohs( a->port ) ); + } + } + return s; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *s - +// *sadr - +// Output : static bool +//----------------------------------------------------------------------------- +static bool StringToSockaddr( const char *s, struct sockaddr *sadr ) +{ + struct hostent *h; + char *colon; + char copy[128]; + struct sockaddr_in *p; + + memset (sadr, 0, sizeof(*sadr)); + + p = ( struct sockaddr_in * )sadr; + p->sin_family = AF_INET; + p->sin_port = 0; + + strcpy (copy, s); + + // strip off a trailing :port if present + for ( colon = copy ; *colon ; colon++ ) + { + if (*colon == ':') + { + // terminate + *colon = 0; + // Start at next character + p->sin_port = htons( ( short )atoi( colon + 1 ) ); + } + } + + // Numeric IP, no DNS + if ( copy[0] >= '0' && copy[0] <= '9' && strstr( copy, "." ) ) + { + *(int *)&p->sin_addr = inet_addr( copy ); + } + else + { + // DNS it + if ( !( h = gethostbyname( copy ) ) ) + { + return false; + } + // Use first result + *(int *)&p->sin_addr = *(int *)h->h_addr_list[0]; + } + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *s - +// *a - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CNetAPI::StringToAdr( const char *s, netadr_t *a ) +{ + struct sockaddr sadr; + + if ( !strcmp ( s, "localhost" ) ) + { + memset ( a, 0, sizeof( *a ) ); + a->type = NA_LOOPBACK; + return true; + } + + if ( !StringToSockaddr (s, &sadr) ) + { + return false; + } + + SockAddrToNetAdr( &sadr, a ); + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Lookup the IP address for the specified IP socket +// Input : socket - +// *a - +//----------------------------------------------------------------------------- +void CNetAPI::GetSocketAddress( int socket, netadr_t *a ) +{ + char buff[512]; + struct sockaddr_in address; + int namelen; +// int net_error = 0; + + memset( a, 0, sizeof( *a ) ); + gethostname(buff, 512); + // Ensure that it doesn't overrun the buffer + buff[512-1] = 0; + + StringToAdr(buff, a ); + + namelen = sizeof(address); + if ( getsockname( socket, (struct sockaddr *)&address, (int *)&namelen) == 0 ) + { + a->port = address.sin_port; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Full IP address compare +// Input : *a - +// *b - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CNetAPI::CompareAdr( netadr_t *a, netadr_t *b ) +{ + if ( a->type != b->type ) + { + return false; + } + + if ( a->type == NA_LOOPBACK ) + { + return true; + } + + if ( a->type == NA_IP && + a->ip[0] == b->ip[0] && + a->ip[1] == b->ip[1] && + a->ip[2] == b->ip[2] && + a->ip[3] == b->ip[3] && + a->port == b->port ) + { + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Full IP address compare +// Input : *a - +// *b - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- + +void CNetAPI::GetLocalIP(netadr_t *a) +{ + char s[64]; + + if(!::gethostname(s,64)) + { + struct hostent *localip = ::gethostbyname(s); + if(localip) + { + a->type=NA_IP; + a->port=0; + memcpy(a->ip,localip->h_addr_list[0],4); + } + } +} diff --git a/tracker/common/server.h b/tracker/common/server.h new file mode 100644 index 0000000..9e510fe --- /dev/null +++ b/tracker/common/server.h @@ -0,0 +1,51 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef SERVER_H +#define SERVER_H + +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Data describing a single server +//----------------------------------------------------------------------------- +struct serveritem_t +{ + serveritem_t() + { + pings[0] = 0; + pings[1] = 0; + pings[2] = 0; + } + + unsigned char ip[4]; + int port; + int received; + float time; + int ping; // current ping time, derived from pings[] + int pings[3]; // last 3 ping times + bool hadSuccessfulResponse; // server has responded successfully in the past + bool doNotRefresh; // server is marked as not responding and should no longer be refreshed + char gameDir[32]; // current game directory + char map[32]; // current map + char gameDescription[64]; // game description + char name[64]; // server name + int players; + int maxPlayers; + int botPlayers; + bool proxy; + bool password; + unsigned int serverID; + int listEntryID; + char rconPassword[64]; // the rcon password for this server + bool loadedFromFile; // true if this entry was loaded from file rather than comming from the master +}; + + +#endif // SERVER_H diff --git a/tracker/common/util.cpp b/tracker/common/util.cpp new file mode 100644 index 0000000..d28b1c7 --- /dev/null +++ b/tracker/common/util.cpp @@ -0,0 +1,70 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "util.h" +#include <string.h> + +#define NUM_BUFFERS 4 +#define MAX_INFO_TOKEN_LENGTH 512 +const char *CUtil::InfoGetValue( const char *s, const char *key ) +{ + char pkey[MAX_INFO_TOKEN_LENGTH]; + // Use multiple buffers so compares + // work without stomping on each other + static char value[NUM_BUFFERS][MAX_INFO_TOKEN_LENGTH]; + static int valueindex; + char *o; + + valueindex = (valueindex + 1) % NUM_BUFFERS; + + if (*s == '\\') + s++; + while (1) + { + o = pkey; + while (*s != '\\') + { + if (!*s) + return ""; + *o++ = *s++; + } + *o = 0; + s++; + + o = value[valueindex]; + + while (*s != '\\' && *s) + { + if (!*s) + return ""; + *o++ = *s++; + } + *o = 0; + + if (!strcmp (key, pkey) ) + return value[valueindex]; + + if (!*s) + return ""; + s++; + } +} + +//----------------------------------------------------------------------------- +// Purpose: This function is supposed to localise the strings, but for now just return internal value +// Input : *stringName - +// Output : const char +//----------------------------------------------------------------------------- +const char *CUtil::GetString(const char *stringName) +{ + return stringName; +} + +static CUtil g_Util; +CUtil *util = &g_Util; + + diff --git a/tracker/common/util.h b/tracker/common/util.h new file mode 100644 index 0000000..5c827b9 --- /dev/null +++ b/tracker/common/util.h @@ -0,0 +1,29 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef UTIL_H +#define UTIL_H +#ifdef _WIN32 +#pragma once +#endif + +//----------------------------------------------------------------------------- +// Purpose: Utility function for the server browser +//----------------------------------------------------------------------------- +class CUtil +{ +public: + const char *InfoGetValue(const char *s, const char *key); + const char *GetString(const char *stringName); + +}; + +extern CUtil *util; + + + +#endif // UTIL_H |