diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /networksystem/networksystem.cpp | |
| download | archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.tar.xz archived-source-engine-2018-hl2-src-3bf9df6b2785fa6d951086978a3e66f49427166a.zip | |
Diffstat (limited to 'networksystem/networksystem.cpp')
| -rw-r--r-- | networksystem/networksystem.cpp | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/networksystem/networksystem.cpp b/networksystem/networksystem.cpp new file mode 100644 index 0000000..b8650ec --- /dev/null +++ b/networksystem/networksystem.cpp @@ -0,0 +1,491 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//===========================================================================// + +#include "networksystem.h" +#include "filesystem.h" +#include "UDP_Socket.h" +#include "sm_protocol.h" +#include "NetChannel.h" +#include "UDP_Process.h" +#include <winsock.h> +#include "networkclient.h" +#include "networkserver.h" +#include "networksystem/inetworkmessage.h" +#include "mathlib/mathlib.h" +#include "tier2/tier2.h" + + +//----------------------------------------------------------------------------- +// Singleton instance +//----------------------------------------------------------------------------- +static CNetworkSystem g_NetworkSystem; +CNetworkSystem *g_pNetworkSystemImp = &g_NetworkSystem; +EXPOSE_SINGLE_INTERFACE_GLOBALVAR( CNetworkSystem, INetworkSystem, + NETWORKSYSTEM_INTERFACE_VERSION, g_NetworkSystem ); + + +//----------------------------------------------------------------------------- +// Constructor, destructor +//----------------------------------------------------------------------------- +CNetworkSystem::CNetworkSystem() +{ + m_bWinsockInitialized = false; + m_bNetworkEventCreated = false; + m_bInMidPacket = false; + m_pServer = NULL; + m_pClient = NULL; + m_nGroupBits = 1; + m_nTypeBits = LargestPowerOfTwoLessThanOrEqual( net_num_messages ); +} + +CNetworkSystem::~CNetworkSystem() +{ +} + + +//----------------------------------------------------------------------------- +// Initialization, shutdown +//----------------------------------------------------------------------------- +InitReturnVal_t CNetworkSystem::Init() +{ + InitReturnVal_t nRetVal = BaseClass::Init(); + if ( nRetVal != INIT_OK ) + return nRetVal; + + // initialize winsock 2.0 + WSAData wsaData; + + if ( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) + { + Warning( "Error! Failed to load network socket library.\n"); + return INIT_OK; + } + else + { + m_bWinsockInitialized = true; + } + + LPHOSTENT lp = gethostbyname("localhost"); + if ( !lp ) + { + Warning( "Error! Failed to query local host info\n"); + return INIT_OK; + } + m_LocalHostName = lp->h_name; + + lp = gethostbyname( m_LocalHostName ); + if ( !lp ) + { + Warning( "Error! Failed to query local host info\n"); + return INIT_OK; + } + + sockaddr ip; + m_LocalAddressString = inet_ntoa( *((in_addr*)(lp->h_addr_list[0])) ); + StringToSockaddr( m_LocalAddressString, &ip ); + m_LocalAddress.SetFromSockadr( &ip ); + return INIT_OK; +} + +void CNetworkSystem::Shutdown() +{ + if ( m_bWinsockInitialized ) + { + WSACleanup(); + } + CleanupNetworkMessages(); + BaseClass::Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Connect, disconnect +//----------------------------------------------------------------------------- +bool CNetworkSystem::Connect( CreateInterfaceFn factory ) +{ + if ( !BaseClass::Connect( factory ) ) + return false; + + if ( !g_pFullFileSystem ) + { + Warning( "The network system requires the filesystem to run!\n" ); + return false; + } + + return INIT_OK; +} + + +//----------------------------------------------------------------------------- +// Returns the current time +//----------------------------------------------------------------------------- +float CNetworkSystem::GetTime( void ) +{ + return Plat_FloatTime(); +} + + +//----------------------------------------------------------------------------- +// Installs network message factories to be used with all connections +//----------------------------------------------------------------------------- +bool CNetworkSystem::RegisterMessage( INetworkMessage *pMessage ) +{ + if ( m_pServer || m_pClient ) + { + Warning( "Cannot register messages after connection has started.\n" ); + return false; + } + + if ( pMessage->GetGroup() == 0 ) + { + Warning( "Network message group 0 is reserved by the network system.\n" ); + return false; + } + + // Look for already registered message + if ( m_NetworkMessages.Find( pMessage ) >= 0 ) + return false; + + // Allocate more space in messages + int nGroupBits = LargestPowerOfTwoLessThanOrEqual( pMessage->GetGroup() ); + int nTypeBits = LargestPowerOfTwoLessThanOrEqual( pMessage->GetType() ); + m_nGroupBits = max( nGroupBits, m_nGroupBits ); + m_nTypeBits = max( nTypeBits, m_nTypeBits ); + + m_NetworkMessages.AddToTail( pMessage ); + return true; +} + +void CNetworkSystem::CleanupNetworkMessages( ) +{ + int nCount = m_NetworkMessages.Count(); + for ( int i = 0; i < nCount; ++i ) + { + m_NetworkMessages[i]->Release(); + } + + m_NetworkMessages.RemoveAll(); +} + + +//----------------------------------------------------------------------------- +// Finds a network message given a particular message type +//----------------------------------------------------------------------------- +INetworkMessage* CNetworkSystem::FindNetworkMessage( int group, int type ) +{ + int nCount = m_NetworkMessages.Count(); + for (int i=0; i < nCount; i++ ) + { + if ( ( m_NetworkMessages[i]->GetGroup() == group ) && ( m_NetworkMessages[i]->GetType() == type ) ) + return m_NetworkMessages[i]; + } + return NULL; +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CNetworkSystem::StringToSockaddr( const char *s, struct sockaddr *sadr ) +{ + struct hostent *h; + char *colon; + char copy[128]; + + Q_memset (sadr, 0, sizeof(*sadr)); + ((struct sockaddr_in *)sadr)->sin_family = AF_INET; + ((struct sockaddr_in *)sadr)->sin_port = 0; + + Q_strncpy (copy, s, sizeof( copy ) ); + // strip off a trailing :port if present + for (colon = copy ; *colon ; colon++) + if (*colon == ':') + { + *colon = 0; + ((struct sockaddr_in *)sadr)->sin_port = htons((short)atoi(colon+1)); + } + + if (copy[0] >= '0' && copy[0] <= '9' && Q_strstr( copy, "." ) ) + { + *(int *)&((struct sockaddr_in *)sadr)->sin_addr = inet_addr(copy); + } + else + { +// if ( net_nodns ) +// return false; // DNS names disabled + + if ( (h = gethostbyname(copy)) == NULL ) + return false; + + *(int *)&((struct sockaddr_in *)sadr)->sin_addr = *(int *)h->h_addr_list[0]; + } + + return true; +} + + +//----------------------------------------------------------------------------- +// Returns the local address +//----------------------------------------------------------------------------- +const char* CNetworkSystem::GetLocalHostName( void ) const +{ + return m_LocalHostName; +} + +const char* CNetworkSystem::GetLocalAddress( void ) const +{ + return m_LocalAddressString; +} + + +//----------------------------------------------------------------------------- +// Start, shutdown a server +//----------------------------------------------------------------------------- +bool CNetworkSystem::StartServer( unsigned short nServerListenPort ) +{ + if ( !m_bWinsockInitialized ) + return false; + + Assert( !m_pServer ); + m_pServer = new CNetworkServer; + return m_pServer->Init( nServerListenPort ); +} + +void CNetworkSystem::ShutdownServer( ) +{ + if ( m_pServer ) + { + m_pServer->Shutdown(); + delete m_pServer; + m_pServer = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Server update +//----------------------------------------------------------------------------- +void CNetworkSystem::ServerReceiveMessages() +{ + if ( m_pServer ) + { + m_pServer->ReadPackets(); + } +} + +void CNetworkSystem::ServerSendMessages() +{ + if ( m_pServer ) + { + m_pServer->SendUpdates(); + } +} + + +//----------------------------------------------------------------------------- +// Start, shutdown a client +//----------------------------------------------------------------------------- +bool CNetworkSystem::StartClient( unsigned short nClientListenPort ) +{ + if ( !m_bWinsockInitialized ) + return false; + + Assert( !m_pClient ); + m_pClient = new CNetworkClient; + return m_pClient->Init( nClientListenPort ); +} + +void CNetworkSystem::ShutdownClient( ) +{ + if ( m_pClient ) + { + m_pClient->Shutdown(); + delete m_pClient; + m_pClient = NULL; + } +} + + +//----------------------------------------------------------------------------- +// Server update +//----------------------------------------------------------------------------- +void CNetworkSystem::ClientReceiveMessages() +{ + if ( m_pClient ) + { + m_pClient->ReadPackets(); + } +} + +void CNetworkSystem::ClientSendMessages() +{ + if ( m_pClient ) + { + m_pClient->SendUpdate(); + } +} + + +//----------------------------------------------------------------------------- +// Server update +//----------------------------------------------------------------------------- +INetChannel* CNetworkSystem::ConnectClientToServer( const char *pServer, int nServerListenPort ) +{ + if ( m_pClient ) + { + if ( m_pClient->Connect( pServer, nServerListenPort ) ) + return m_pClient->GetNetChannel(); + } + return NULL; +} + +void CNetworkSystem::DisconnectClientFromServer( INetChannel* pChannel ) +{ + if ( m_pClient && ( m_pClient->GetNetChannel() == pChannel ) ) + { + m_pClient->Disconnect(); + } +} + + +//----------------------------------------------------------------------------- +// Queues up a network packet +//----------------------------------------------------------------------------- +void CNetworkSystem::EnqueueConnectionlessNetworkPacket( CNetPacket *pPacket, IConnectionlessPacketHandler *pHandler ) +{ + int i = m_PacketQueue.AddToTail( ); + + PacketInfo_t& info = m_PacketQueue[i]; + info.m_pPacket = pPacket; + info.m_pHandler = pHandler; + info.m_pNetChannel = NULL; +} + +void CNetworkSystem::EnqueueNetworkPacket( CNetPacket *pPacket, CNetChannel *pNetChannel ) +{ + int i = m_PacketQueue.AddToTail( ); + + PacketInfo_t& info = m_PacketQueue[i]; + info.m_pPacket = pPacket; + info.m_pHandler = NULL; + info.m_pNetChannel = pNetChannel; +} + + +//----------------------------------------------------------------------------- +// Network event iteration helpers +//----------------------------------------------------------------------------- +bool CNetworkSystem::StartProcessingNewPacket() +{ + PacketInfo_t& info = m_PacketQueue[ m_nProcessingPacket ]; + if ( info.m_pHandler ) + { + UDP_ProcessConnectionlessPacket( info.m_pPacket, info.m_pHandler ); + return false; + } + + if ( !info.m_pNetChannel ) + { + // Not an error that may happen during connect or disconnect + Warning( "Sequenced packet without connection from %s\n" , info.m_pPacket->m_From.ToString() ); + return false; + } + + return info.m_pNetChannel->StartProcessingPacket( info.m_pPacket ); +} + +bool CNetworkSystem::AdvanceProcessingNetworkPacket( ) +{ + m_PacketQueue[ m_nProcessingPacket ].m_pPacket->Release(); + m_PacketQueue[ m_nProcessingPacket ].m_pPacket = NULL; + + ++m_nProcessingPacket; + bool bOverflowed = ( m_nProcessingPacket >= m_PacketQueue.Count() ); + if ( bOverflowed ) + { + m_PacketQueue.RemoveAll(); + m_nProcessingPacket = 0; + } + return !bOverflowed; +} + + +//----------------------------------------------------------------------------- +// Network event iteration +//----------------------------------------------------------------------------- +NetworkEvent_t *CNetworkSystem::FirstNetworkEvent( ) +{ + Assert( !m_bInMidPacket && !m_nProcessingPacket ); + m_nProcessingPacket = 0; + m_bInMidPacket = false; + return NextNetworkEvent(); +} + +NetworkEvent_t *CNetworkSystem::NextNetworkEvent( ) +{ + int nPacketCount = m_PacketQueue.Count(); + if ( m_nProcessingPacket >= nPacketCount ) + return NULL; + + while( true ) + { + // Continue processing the packet we're currently on + if ( m_bInMidPacket ) + { + PacketInfo_t& info = m_PacketQueue[ m_nProcessingPacket ]; + while( info.m_pNetChannel->ProcessPacket( info.m_pPacket ) ) + { + Assert( m_bNetworkEventCreated ); + m_bNetworkEventCreated = false; + return (NetworkEvent_t*)m_EventMessageBuffer; + } + info.m_pNetChannel->EndProcessingPacket( info.m_pPacket ); + m_bInMidPacket = false; + + if ( !AdvanceProcessingNetworkPacket() ) + return NULL; + } + + // Keep reading packets until we find one that either generates an event, + // one that encounters a packet we need to process, or we exhaust the event queue + while( !StartProcessingNewPacket() ) + { + bool bOverflowed = !AdvanceProcessingNetworkPacket(); + + if ( m_bNetworkEventCreated ) + { + m_bNetworkEventCreated = false; + return (NetworkEvent_t*)m_EventMessageBuffer; + } + + if ( bOverflowed ) + return NULL; + } + + m_bInMidPacket = true; + } +} + + +//----------------------------------------------------------------------------- +// Network event creation +//----------------------------------------------------------------------------- +NetworkEvent_t* CNetworkSystem::CreateNetworkEvent( int nSizeInBytes ) +{ + Assert( nSizeInBytes <= sizeof( m_EventMessageBuffer ) ); + + // If this assertion fails, it means two or more network events were created + // before the main network event loop had a chance to inform external code + Assert( !m_bNetworkEventCreated ); + m_bNetworkEventCreated = true; + return ( NetworkEvent_t* )m_EventMessageBuffer; +} + +bool CNetworkSystem::IsNetworkEventCreated() +{ + return m_bNetworkEventCreated; +} + |