mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-22 22:27:05 +00:00
325 lines
12 KiB
C
325 lines
12 KiB
C
|
//========= 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 <xtl.h>
|
||
|
#include <winsockx.h>
|
||
|
#elif defined( PLATFORM_WINDOWS_PC )
|
||
|
#include <winsock2.h>
|
||
|
#else
|
||
|
#error No build platform macro (PLATFORM_*) defined
|
||
|
#endif
|
||
|
|
||
|
inline SocketHandle_t GetSocketHandle( SOCKET socket )
|
||
|
{
|
||
|
return static_cast<SocketHandle_t>( socket );
|
||
|
}
|
||
|
|
||
|
inline SOCKET GetPlatformSocket( SocketHandle_t handle )
|
||
|
{
|
||
|
return static_cast<SOCKET>( handle );
|
||
|
}
|
||
|
|
||
|
static const SocketHandle_t InvalidSocketHandle = static_cast<SocketHandle_t>( 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
|
||
|
|