//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #ifndef ITHREADEDTCPSOCKET_H #define ITHREADEDTCPSOCKET_H #ifdef _WIN32 #pragma once #endif #include "iphelpers.h" class IThreadedTCPSocket; class CTCPPacket { public: // Access the contents of the packet. const char* GetData() const; int GetLen() const; // You can attach some user data to the packet. int GetUserData() const; void SetUserData( int userData ); // Free resources associated with the packet. void Release(); public: friend class CThreadedTCPSocket; ~CTCPPacket(); // Use Release(), not delete. int m_UserData; int m_Len; char m_Data[1]; }; inline const char* CTCPPacket::GetData() const { return m_Data; } inline int CTCPPacket::GetLen() const { return m_Len; } // The application implements this to handle packets that are received. // Note that the implementation must be thread-safe because these functions can be called // from various threads. class ITCPSocketHandler { public: enum { SocketError=0, ConnectionTimedOut }; // This is called right when the socket becomes ready to have data sent through it and // before OnPacketReceive is ever called. virtual void Init( IThreadedTCPSocket *pSocket ) = 0; // This is called when a packet arrives. NOTE: you are responsible for freeing the packet // by calling CTCPPacket::Release() on it. virtual void OnPacketReceived( CTCPPacket *pPacket ) = 0; // Handle errors inside the socket. After this is called, the socket is no longer alive. // Note: this might be called from ANY thread (the main thread, the send thread, or the receive thread). // // errorCode is one of the enums above (SocketError, ConnectionTimedOut, etc). virtual void OnError( int errorCode, const char *pErrorString ) = 0; }; // // This is the main threaded TCP socket class. // The way these work is that they have a thread for sending and a thread for receiving data. // // The send thread is continually pushing your data out the door. // // The receive thread is continually receiving data. When it receives data, it calls your HandlePacketFn // to allow the user to handle it. Be very careful in your HandlePacketFn, since it is in another thread. // Anything it accesses should be protected by mutexes and the like. // class IThreadedTCPSocket { public: // Cleanup everything and exit. // Note: if the receive thread is inside your HandlePacketFn returns, this function blocks until that function returns. virtual void Release() = 0; // Returns the address of whoever you are connected to. virtual CIPAddr GetRemoteAddr() const = 0; // Returns true if the socket is connected and ready to go. If this returns false, then the socket won't // send or receive data any more. It also means that your ITCPSocketHandler's OnError function has been called. virtual bool IsValid() = 0; // Send data. Any thread can call these functions, and they don't block. They make a copy of the data, then // enqueue it for sending. virtual bool Send( const void *pData, int len ) = 0; virtual bool SendChunks( void const * const *pChunks, const int *pChunkLengths, int nChunks ) = 0; }; // Use these to get incoming connections. class ITCPConnectSocket { public: // Call this to stop listening for connections and delete the object. virtual void Release() = 0; // Keep calling this as long as you want to wait for connections. // // If it returns true and pSocket is NULL, it means it hasn't connected yet. // If it returns true and pSocket is non-NULL, then it has connected. // If it returns false, then the connection attempt failed and all further Update() calls will return false. virtual bool Update( IThreadedTCPSocket **pSocket, unsigned long milliseconds=0 ) = 0; }; // This class is implemented by the app and passed into CreateListener. When the listener makes // a new connection, it calls CreateNewHandler() to have the app create something that will handle // the received packets and errors for the new socket. class IHandlerCreator { public: // This function must return a valid value. virtual ITCPSocketHandler* CreateNewHandler() = 0; }; // Use this to listen for TCP connections. The ITCPConnectSocket will keep returning connections // until you call Release(). ITCPConnectSocket* ThreadedTCP_CreateListener( IHandlerCreator *pHandlerCreator, // This handles messages from the socket. const unsigned short port, // Listen on this port. int nQueueLength = 5 // How many connections ); // Use this to connect to a remote process. After Update() returns a non-NULL value, you should // call Release() on the ITCPConnectSocket because it won't ever return another connection. ITCPConnectSocket* ThreadedTCP_CreateConnector( const CIPAddr &addr, // Who to connect to. const CIPAddr &localAddr, // Local address to bind to. Leave uninitialized (pass in CIPAddr()) and it will // an interface and a port for you. You can also just fill in the port, and it will // use that port and choose an interface for you. IHandlerCreator *pHandlerCreator// If it connects, it asks this thing to make a handler for the connection. ); // Enable or disable timeouts. void ThreadedTCP_EnableTimeouts( bool bEnable ); // This should be called at init time. If set to true, it'll set the send and recv threads to low priority. // (Default is true). void ThreadedTCP_SetTCPSocketThreadPriorities( bool bSetTCPSocketThreadPriorities ); #endif // ITHREADEDTCPSOCKET_H