//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: master header file for socketlib.lib // // $Header: $ // $NoKeywords: $ //===========================================================================// #ifndef SOCKETLIB_H #define SOCKETLIB_H #ifdef _WIN32 #pragma once #endif #include "tier0/basetypes.h" #include "utlbuffer.h" typedef int64 SocketHandle_t; //=========================================================================== // Error Codes used by socketlib //=========================================================================== enum SocketErrorCode_t { SOCKET_SUCCESS = 0, SOCKET_ERR_OPERATION_NOT_SUPPORTED, SOCKET_ERR_CREATE_FAILED, SOCKET_ERR_READ_OPERATION_FAILED, SOCKET_ERR_WRITE_OPERATION_FAILED, SOCKET_ERR_CONNECT_FAILED, SOCKET_ERR_LISTEN_FAILED, SOCKET_ERR_ACCEPT_FAILED, SOCKET_ERR_POLLING_OPERATION_FAILED, SOCKET_ERR_BIND_OPERATION_FAILED, SOCKET_ERR_ENABLE_NON_BLOCKING_MODE_FAILED, SOCKET_ERR_HOST_NOT_FOUND, SOCKET_ERR_GENERAL_SOCKET_ERROR, SOCKET_ERR_READ_OPERATION_WOULD_BLOCK, SOCKET_ERR_WRITE_OPERATION_WOULD_BLOCK, SOCKET_ERR_CONNECTION_CLOSED, SOCKET_ERR_CONNECTION_RESET, SOCKET_ERR_NO_INCOMING_CONNECTIONS, SOCKET_ERR_NO_AVAILABLE_ENDPOINTS, SOCKET_ERR_BAD_USER_DATA, SOCKET_ERR_INVALID_CONNECTION, SOCKET_ERR_CANT_WRITE, SOCKET_ERR_MIXING_PACKET_SENDS, SOCKET_ERR_PARTIAL_PACKET_OVERFLOW, }; const int MAX_SERVER_CONNECTIONS = 4; // Maximum number of concurrent connections allowed to a server. // In the future, this can be set higher and class CSocketConnection should use a growable array of Sockets. const int MAX_SERVER_CONNECTION_BACKLOG = 16; // Maximum number of connections allowed in the listening backlog. const int INVALID_ENDPOINT_INDEX = -1; // Represents an invalid endpoint index. enum ConnectionType_t // Type of connection: client or server. { CT_INDETERMINATE = 0, CT_CLIENT, CT_SERVER, }; enum SocketProtocol_t // Protocol to use for the socket. { SP_INDETERMINATE = 0, SP_UDP, SP_VDP, SP_TCP, }; enum SocketState_t // State of a given socket. { SSTATE_UNINITIALIZED = 0, // Socket is in completely uninitialized state. SSTATE_LISTENING, // Server socket is listening for connections. SSTATE_CONNECTION_IN_PROGRESS, // Socket is initialized and in the process of connecting to a client/server. SSTATE_CONNECTED, // Socket is initialized and connected to a client/server. }; //----------------------------------------------------------------------- // Platform and build specific defines, change these as needed //----------------------------------------------------------------------- #if defined( PLATFORM_X360 ) #define VDP_SUPPORT_ENABLED 1 #else #define VDP_SUPPORT_ENABLED 0 #endif #if defined( _DEBUG ) #define UNSECURE_SOCKETS_ENABLED 1 #else #define UNSECURE_SOCKETS_ENABLED 0 #endif // ---------------------------------------------------------------------------- // Basic platform-specific socket definitions go here to avoid // polluting other source files with common #defines. // ---------------------------------------------------------------------------- #if defined( PLATFORM_X360 ) #include #include #elif defined( PLATFORM_WINDOWS_PC ) #include #else #error No build platform macro (PLATFORM_*) defined #endif inline SocketHandle_t GetSocketHandle( SOCKET socket ) { return static_cast( socket ); } inline SOCKET GetPlatformSocket( SocketHandle_t handle ) { return static_cast( handle ); } static const SocketHandle_t InvalidSocketHandle = static_cast( INVALID_SOCKET ); // ---------------------------------------------------------------------------- // CSocketConnection // Represents a client or server network connection. // // todo: Rework connection class to treat endpoints as standalone objects and unify // interface with named pipes. // ---------------------------------------------------------------------------- class CSocketConnection { public: CSocketConnection(); ~CSocketConnection(); SocketErrorCode_t Init( ConnectionType_t connectionType, SocketProtocol_t socketProtocol ); // Initializes the connection class as either client or server with specified protocol. // Does not acquire any system resources. void Cleanup(); // Cleans up the class and restores it to the default uninitialized state. SocketErrorCode_t Listen( uint16 localPort, int numAllowedConnections ); // (Server-only) Listens for active client connections. SocketErrorCode_t TryAcceptIncomingConnection( int *newEndpointIndex ); // (Server-only) Attempts to accept an incoming connection, if one is available. int GetFirstAvailableListeningEndpoint(); // (Server-only) Gets the index of the first endpoint which is listening for connections. SocketState_t GetListeningSocketState(); // (Server-only) Gets the status of the listening socket on a server. SocketErrorCode_t ConnectToServer( const char *hostName, uint16 hostPort ); // (Client-only) Connects to a remote host using endpoint 0. // In most cases, the status of endpoint 0 will be SSTATE_CONNECTION_IN_PROGRESS. // The caller must periodically call PollClientConnectionState until the socket is connected before it is usable. SocketErrorCode_t PollClientConnectionState( bool *isConnected ); // (Client-only) Checks the status of endpoint 0 to see if it is connected successfully to a server. SocketState_t GetEndpointSocketState( int endpointIndex ); // Gets the status of the specified endpoint. (Clients only use endpoint 0.) SocketErrorCode_t CanReadFromEndpoint( int endpointIndex, bool *canRead ); // Gets a value indicating whether the endpoint can be successfully read from. SocketErrorCode_t CanWriteToEndpoint( int endpointIndex, bool *canWrite ); // Gets a value indicating whether the endpoint can be successfully written to. SocketErrorCode_t ReadFromEndpoint( int endpointIndex, byte *destinationBuffer, int bufferSize, int *bytesRead ); // Reads data from the specified endpoint. SocketErrorCode_t WriteToEndpoint( int endpointIndex, byte *sourceBuffer, int bufferSize, int *bytesWritten ); // Writes data to the specified endpoint. const char* GetLastSystemErrorString() const; // Gets a string containing the last underlying system error reported. // Only valid immediately after a function returns an unsuccessful error code. const char* GetLastErrorString() const; // Gets a string containing the last underlying system error reported. SocketHandle_t GetListeningSocket() const; SocketHandle_t GetEndpointSocket( int nEndpointIndex ) const; void ResetEndpoint( int endpointIndex ); SocketErrorCode_t SetSocketOpt( int endpointIndex, int level, int optname, const void *optval, int optlen ); private: SocketHandle_t CreateNewSocket(); SocketHandle_t m_ListeningSocket; SocketHandle_t m_EndpointSockets[ MAX_SERVER_CONNECTIONS ]; SocketState_t m_ListeningSocketState; SocketState_t m_EndpointStates[ MAX_SERVER_CONNECTIONS ]; ConnectionType_t m_ConnectionType; SocketProtocol_t m_SocketProtocol; SocketErrorCode_t m_LastError; int m_LastSystemError; }; //----------------------------------------------------------------------------- // Inline functions from CSocketConnection //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- inline SocketHandle_t CSocketConnection::GetListeningSocket() const { return m_ListeningSocket; } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- inline SocketHandle_t CSocketConnection::GetEndpointSocket( int nEndpointIndex ) const { AssertMsg( nEndpointIndex >= 0 && nEndpointIndex < MAX_SERVER_CONNECTIONS, "Endpoint index out of range" ); return m_EndpointSockets[ nEndpointIndex ]; } // ---------------------------------------------------------------------------- // Start up and shutdown functions // Calls to these functions have to bracket any usage of this socket code // ---------------------------------------------------------------------------- void SocketLibInit(); void SocketLibShutdown(); // Handy conversion to text of those nasty HRESULT codes const char* ConvertWinsockErrorToString( int errorCode ); const char* ConvertSocketLibErrorToString( SocketErrorCode_t errorCode ); // Bitwise representation of a network message header. struct MessageHeader_t { uint32 m_nLength; }; // Byte swaps (in-place) a message header between system byte-order and network byte-order. void ByteSwapInPlaceMessageHeader( MessageHeader_t* messageHeader ); // ---------------------------------------------------------------------------- // Signature of a callback invoked once per message parsed by the CSocketMessageBuilder::FeedData function. // header = Header of the message read. // message = Message payload (m_nLength is given by the header) // userContext = Context provided by caller to FeedData // ---------------------------------------------------------------------------- typedef void ( *NetworkMessageHandler )( const MessageHeader_t& header, const byte* message, void* userContext ); // ---------------------------------------------------------------------------- // Helper class to parse messages from a stream source. // This class maintains state between successive calls to FeedData so that partial messages // can be stored until fully parsed and dispatched. // ---------------------------------------------------------------------------- class CSocketMessageBuilder { public: CSocketMessageBuilder( int initialSize = 0, int growSize = 0 ); ~CSocketMessageBuilder(); void SetMaxExpectedMsgSize( int expectedSize ); // Parses the given stream data and fires a callback for each full message parsed. // This function has the side-effect of updating the CSocketMessageBuilder's internal parsing state // so that partial messages can be glued together. void FeedData( const void *data, int dataLength, NetworkMessageHandler networkMessageHandlerFunc, void *userContext ); void AssignConnection( CSocketConnection* pConnection, int endpoint ); SocketErrorCode_t SendDataPacket( const void* RESTRICT data, int dataLength ); SocketErrorCode_t SendDataPacket( CSocketConnection* pConnection, int endpoint, const void* RESTRICT data, int dataLength ); SocketErrorCode_t BeginSendPartialDataPacket( uint32 totalSize, const void* RESTRICT data, int dataLength ); SocketErrorCode_t BeginSendPartialDataPacket( CSocketConnection* pConnection, int endpoint, uint32 totalSize, const void* RESTRICT data, int dataLength ); bool WaitForIncomingMessage( DWORD timeOutValue ); void* GetIncomingMessageData(); uint32 GetIncomingMessageLen(); void FeedDataManual( const void* RESTRICT data, int dataLength ); bool HasCompleteMessageManual( ); bool GetCurrentMessageManual( void*& msgData, uint32& msgSize ); bool DiscardCurrentMessageManual(); bool IsSendingPartialMessage() { return m_bSendingPartialMessage; } int32 PartialMessageBytesRemaining() { return m_bSendingPartialMessage ? m_PartialMessageBytesTotal - m_PartialMessageBytesSent : 0; } private: MessageHeader_t m_MessageHeader; uint32 m_nHeaderBytesRead; uint32 m_nMessageBytesRead; CSocketConnection* m_pConnection; int m_nConnectionEndpoint; CUtlBuffer m_MessageData; uint32 m_PartialMessageBytesSent; // used to combine multiple calls to SendDataPacket/BeginSendPartialDataPacket into one message packet uint32 m_PartialMessageBytesTotal; bool m_bSendingPartialMessage; int m_nRecvBufSize; byte* m_pRecvBuf; bool m_bSwappedHeader; }; #endif // SOCKETLIB_H