summaryrefslogtreecommitdiff
path: root/utils/vmpi/ThreadedTCPSocketEmu.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/vmpi/ThreadedTCPSocketEmu.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'utils/vmpi/ThreadedTCPSocketEmu.cpp')
-rw-r--r--utils/vmpi/ThreadedTCPSocketEmu.cpp344
1 files changed, 344 insertions, 0 deletions
diff --git a/utils/vmpi/ThreadedTCPSocketEmu.cpp b/utils/vmpi/ThreadedTCPSocketEmu.cpp
new file mode 100644
index 0000000..f8257a5
--- /dev/null
+++ b/utils/vmpi/ThreadedTCPSocketEmu.cpp
@@ -0,0 +1,344 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <windows.h>
+#include "tcpsocket.h"
+#include "IThreadedTCPSocket.h"
+#include "ThreadedTCPSocketEmu.h"
+#include "ThreadHelpers.h"
+
+
+
+// ---------------------------------------------------------------------------------------- //
+// CThreadedTCPSocketEmu. This uses IThreadedTCPSocket to emulate the polling-type interface
+// in ITCPSocket.
+// ---------------------------------------------------------------------------------------- //
+
+// This class uses the IThreadedTCPSocket interface to emulate the old ITCPSocket.
+class CThreadedTCPSocketEmu : public ITCPSocket, public ITCPSocketHandler, public IHandlerCreator
+{
+public:
+
+ CThreadedTCPSocketEmu()
+ {
+ m_pSocket = NULL;
+ m_LocalPort = 0xFFFF;
+ m_pConnectSocket = NULL;
+ m_RecvPacketsEvent.Init( false, false );
+ m_bError = false;
+ }
+
+ virtual ~CThreadedTCPSocketEmu()
+ {
+ Term();
+ }
+
+ void Init( IThreadedTCPSocket *pSocket )
+ {
+ m_pSocket = pSocket;
+ }
+
+ void Term()
+ {
+ if ( m_pSocket )
+ {
+ m_pSocket->Release();
+ m_pSocket = NULL;
+ }
+
+ if ( m_pConnectSocket )
+ {
+ m_pConnectSocket->Release();
+ m_pConnectSocket = NULL;
+ }
+ }
+
+
+// ITCPSocketHandler implementation.
+private:
+
+
+ virtual void OnPacketReceived( CTCPPacket *pPacket )
+ {
+ CCriticalSectionLock csLock( &m_RecvPacketsCS );
+ csLock.Lock();
+
+ m_RecvPackets.AddToTail( pPacket );
+ m_RecvPacketsEvent.SetEvent();
+ }
+
+
+ virtual void OnError( int errorCode, const char *pErrorString )
+ {
+ CCriticalSectionLock csLock( &m_ErrorStringCS );
+ csLock.Lock();
+
+ m_ErrorString.CopyArray( pErrorString, strlen( pErrorString ) + 1 );
+ m_bError = true;
+ }
+
+
+// IHandlerCreator implementation.
+public:
+
+ // This is used for connecting.
+ virtual ITCPSocketHandler* CreateNewHandler()
+ {
+ return this;
+ }
+
+
+// ITCPSocket implementation.
+public:
+
+ virtual void Release()
+ {
+ delete this;
+ }
+
+ virtual bool BindToAny( const unsigned short port )
+ {
+ m_LocalPort = port;
+ return true;
+ }
+
+ virtual bool BeginConnect( const CIPAddr &addr )
+ {
+ // They should have "bound" to a port before trying to connect.
+ Assert( m_LocalPort != 0xFFFF );
+
+ if ( m_pConnectSocket )
+ m_pConnectSocket->Release();
+
+ m_pConnectSocket = ThreadedTCP_CreateConnector(
+ addr,
+ CIPAddr( 0, 0, 0, 0, m_LocalPort ),
+ this );
+
+ return m_pConnectSocket != 0;
+ }
+
+ virtual bool UpdateConnect()
+ {
+ Assert( !m_pSocket );
+ if ( !m_pConnectSocket )
+ return false;
+
+ if ( m_pConnectSocket->Update( &m_pSocket ) )
+ {
+ if ( m_pSocket )
+ {
+ // Ok, we're connected now.
+ m_pConnectSocket->Release();
+ m_pConnectSocket = NULL;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else
+ {
+ Assert( false );
+ m_pConnectSocket->Release();
+ m_pConnectSocket = NULL;
+ return false;
+ }
+ }
+
+ virtual bool IsConnected()
+ {
+ if ( m_bError )
+ {
+ Term();
+ return false;
+ }
+ else
+ {
+ return m_pSocket != NULL;
+ }
+ }
+
+ virtual void GetDisconnectReason( CUtlVector<char> &reason )
+ {
+ CCriticalSectionLock csLock( &m_ErrorStringCS );
+ csLock.Lock();
+
+ reason = m_ErrorString;
+ }
+
+ virtual bool Send( const void *pData, int size )
+ {
+ Assert( m_pSocket );
+ if ( !m_pSocket )
+ return false;
+
+ return m_pSocket->Send( pData, size );
+ }
+
+ virtual bool SendChunks( void const * const *pChunks, const int *pChunkLengths, int nChunks )
+ {
+ Assert( m_pSocket );
+ if ( !m_pSocket || !m_pSocket->IsValid() )
+ return false;
+
+ return m_pSocket->SendChunks( pChunks, pChunkLengths, nChunks );
+ }
+
+ virtual bool Recv( CUtlVector<unsigned char> &data, double flTimeout )
+ {
+ // Use our m_RecvPacketsEvent event to determine if there is data to receive yet.
+ DWORD nMilliseconds = (DWORD)( flTimeout * 1000.0f );
+ DWORD ret = WaitForSingleObject( m_RecvPacketsEvent.GetEventHandle(), nMilliseconds );
+ if ( ret == WAIT_OBJECT_0 )
+ {
+ // Ok, there's a packet.
+ CCriticalSectionLock csLock( &m_RecvPacketsCS );
+ csLock.Lock();
+
+ Assert( m_RecvPackets.Count() > 0 );
+
+ int iHead = m_RecvPackets.Head();
+ CTCPPacket *pPacket = m_RecvPackets[ iHead ];
+
+ data.CopyArray( (const unsigned char*)pPacket->GetData(), pPacket->GetLen() );
+
+ pPacket->Release();
+ m_RecvPackets.Remove( iHead );
+
+ // Re-set the event if there are more packets left to receive.
+ if ( m_RecvPackets.Count() > 0 )
+ {
+ m_RecvPacketsEvent.SetEvent();
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+
+private:
+
+ IThreadedTCPSocket *m_pSocket;
+
+ unsigned short m_LocalPort; // The port we bind to when we want to connect.
+ ITCPConnectSocket *m_pConnectSocket;
+
+
+ // All the received data is stored in here.
+ CEvent m_RecvPacketsEvent;
+ CCriticalSection m_RecvPacketsCS;
+ CUtlLinkedList<CTCPPacket*, int> m_RecvPackets;
+
+ CCriticalSection m_ErrorStringCS;
+ CUtlVector<char> m_ErrorString;
+ bool m_bError; // Set to true when there's an error. Next chance we get in the main thread, we'll close the socket.
+};
+
+
+ITCPSocket* CreateTCPSocketEmu()
+{
+ return new CThreadedTCPSocketEmu;
+}
+
+
+// ---------------------------------------------------------------------------------------- //
+// CThreadedTCPListenSocketEmu implementation.
+// ---------------------------------------------------------------------------------------- //
+
+class CThreadedTCPListenSocketEmu : public ITCPListenSocket, public IHandlerCreator
+{
+public:
+ CThreadedTCPListenSocketEmu()
+ {
+ m_pListener = NULL;
+ m_pLastCreatedSocket = NULL;
+ }
+
+ virtual ~CThreadedTCPListenSocketEmu()
+ {
+ if ( m_pListener )
+ m_pListener->Release();
+ }
+
+ bool StartListening( const unsigned short port, int nQueueLength )
+ {
+ m_pListener = ThreadedTCP_CreateListener(
+ this,
+ port,
+ nQueueLength );
+
+ return m_pListener != 0;
+ }
+
+
+// ITCPListenSocket implementation.
+private:
+
+ virtual void Release()
+ {
+ delete this;
+ }
+
+ virtual ITCPSocket* UpdateListen( CIPAddr *pAddr )
+ {
+ if ( !m_pListener )
+ return NULL;
+
+ IThreadedTCPSocket *pSocket;
+ if ( m_pListener->Update( &pSocket ) && pSocket )
+ {
+ *pAddr = pSocket->GetRemoteAddr();
+
+ // This is pretty hacky, but this stuff is just around for test code.
+ CThreadedTCPSocketEmu *pLast = m_pLastCreatedSocket;
+ pLast->Init( pSocket );
+ m_pLastCreatedSocket = NULL;
+ return pLast;
+ }
+ else
+ {
+ return NULL;
+ }
+ }
+
+
+// IHandlerCreator implementation.
+private:
+
+ virtual ITCPSocketHandler* CreateNewHandler()
+ {
+ m_pLastCreatedSocket = new CThreadedTCPSocketEmu;
+ return m_pLastCreatedSocket;
+ }
+
+
+private:
+
+ ITCPConnectSocket *m_pListener;
+ CThreadedTCPSocketEmu *m_pLastCreatedSocket;
+};
+
+ITCPListenSocket* CreateTCPListenSocketEmu( const unsigned short port, int nQueueLength )
+{
+ CThreadedTCPListenSocketEmu *pSocket = new CThreadedTCPListenSocketEmu;
+ if ( pSocket->StartListening( port, nQueueLength ) )
+ {
+ return pSocket;
+ }
+ else
+ {
+ delete pSocket;
+ return NULL;
+ }
+}
+