summaryrefslogtreecommitdiff
path: root/tracker/common
diff options
context:
space:
mode:
Diffstat (limited to 'tracker/common')
-rw-r--r--tracker/common/CompletionEvent.cpp37
-rw-r--r--tracker/common/CompletionEvent.h32
-rw-r--r--tracker/common/DebugConsole_Interface.h30
-rw-r--r--tracker/common/DebugTimer.h22
-rw-r--r--tracker/common/IGameList.h69
-rw-r--r--tracker/common/IServerRefreshResponse.h34
-rw-r--r--tracker/common/IceKey.H65
-rw-r--r--tracker/common/IceKey.cpp393
-rw-r--r--tracker/common/MasterMsgHandler.h32
-rw-r--r--tracker/common/Socket.cpp1035
-rw-r--r--tracker/common/Socket.h162
-rw-r--r--tracker/common/TrackerMessageFlags.h22
-rw-r--r--tracker/common/TrackerProtocol.h161
-rw-r--r--tracker/common/UtlMsgBuffer.cpp332
-rw-r--r--tracker/common/UtlMsgBuffer.h198
-rw-r--r--tracker/common/inetapi.h42
-rw-r--r--tracker/common/msgbuffer.cpp421
-rw-r--r--tracker/common/msgbuffer.h108
-rw-r--r--tracker/common/netapi.cpp277
-rw-r--r--tracker/common/server.h51
-rw-r--r--tracker/common/util.cpp70
-rw-r--r--tracker/common/util.h29
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