2015-01-11 05:21:18 -05:00
// EchoServer.cpp
// Implements an Echo server using the LibEvent-based cNetwork API, as a test of that API
2015-01-12 03:38:00 -05:00
# include "Globals.h"
# include <iostream>
# include <string>
# include "OSSupport/Network.h"
2015-01-26 08:46:20 -05:00
# include "OSSupport/NetworkSingleton.h"
2015-01-12 03:38:00 -05:00
/** cTCPLink callbacks that echo everything they receive back to the remote peer. */
class cEchoLinkCallbacks :
public cTCPLink : : cCallbacks
{
2015-01-22 07:00:32 -05:00
// cTCPLink::cCallbacks overrides:
virtual void OnLinkCreated ( cTCPLinkPtr a_Link ) override
2015-01-12 03:38:00 -05:00
{
2015-01-22 07:00:32 -05:00
ASSERT ( m_Link = = nullptr ) ;
m_Link = a_Link ;
}
virtual void OnReceivedData ( const char * a_Data , size_t a_Size ) override
{
ASSERT ( m_Link ! = nullptr ) ;
2015-01-12 03:38:00 -05:00
// Echo the incoming data back to outgoing data:
2015-01-22 07:00:32 -05:00
LOGD ( " %p (%s:%d): Data received (%u bytes), echoing back. " , m_Link . get ( ) , m_Link - > GetRemoteIP ( ) . c_str ( ) , m_Link - > GetRemotePort ( ) , static_cast < unsigned > ( a_Size ) ) ;
m_Link - > Send ( a_Data , a_Size ) ;
2015-01-12 03:38:00 -05:00
LOGD ( " Echo queued " ) ;
2015-01-12 08:58:52 -05:00
// Search for a Ctrl+Z, if found, drop the connection:
for ( size_t i = 0 ; i < a_Size ; i + + )
{
if ( a_Data [ i ] = = ' \x1a ' )
{
2015-01-22 07:00:32 -05:00
m_Link - > Close ( ) ;
m_Link . reset ( ) ;
2015-01-12 08:58:52 -05:00
return ;
}
}
2015-01-12 03:38:00 -05:00
}
2015-01-22 07:00:32 -05:00
virtual void OnRemoteClosed ( void ) override
2015-01-12 03:38:00 -05:00
{
2015-01-22 07:00:32 -05:00
ASSERT ( m_Link ! = nullptr ) ;
LOGD ( " %p (%s:%d): Remote has closed the connection. " , m_Link . get ( ) , m_Link - > GetRemoteIP ( ) . c_str ( ) , m_Link - > GetRemotePort ( ) ) ;
m_Link . reset ( ) ;
2015-01-12 03:38:00 -05:00
}
2015-01-22 07:00:32 -05:00
virtual void OnError ( int a_ErrorCode , const AString & a_ErrorMsg ) override
2015-01-12 03:38:00 -05:00
{
2015-01-22 07:00:32 -05:00
ASSERT ( m_Link ! = nullptr ) ;
LOGD ( " %p (%s:%d): Error %d in the cEchoLinkCallbacks: %s " , m_Link . get ( ) , m_Link - > GetRemoteIP ( ) . c_str ( ) , m_Link - > GetRemotePort ( ) , a_ErrorCode , a_ErrorMsg . c_str ( ) ) ;
m_Link . reset ( ) ;
2015-01-12 03:38:00 -05:00
}
2015-01-22 07:00:32 -05:00
/** The link attached to this callbacks instance. */
cTCPLinkPtr m_Link ;
2015-01-12 03:38:00 -05:00
} ;
2015-01-11 05:21:18 -05:00
2015-01-21 15:12:11 -05:00
class cEchoServerCallbacks :
public cNetwork : : cListenCallbacks
{
2016-03-13 14:39:51 -04:00
virtual cTCPLink : : cCallbacksPtr OnIncomingConnection ( const AString & a_RemoteIPAddress , UInt16 a_RemotePort ) override
2015-01-21 15:12:11 -05:00
{
LOGD ( " New incoming connection(%s:%d). " , a_RemoteIPAddress . c_str ( ) , a_RemotePort ) ;
return std : : make_shared < cEchoLinkCallbacks > ( ) ;
}
virtual void OnAccepted ( cTCPLink & a_Link ) override
{
LOGD ( " New client accepted (%s:%d), sending welcome message. " , a_Link . GetRemoteIP ( ) . c_str ( ) , a_Link . GetRemotePort ( ) ) ;
// Send a welcome message to each connecting client:
a_Link . Send ( " Welcome to the simple echo server. \r \n " ) ;
LOGD ( " Welcome message queued. " ) ;
}
virtual void OnError ( int a_ErrorCode , const AString & a_ErrorMsg ) override
{
LOGWARNING ( " An error occured while listening for connections: %d (%s). " , a_ErrorCode , a_ErrorMsg . c_str ( ) ) ;
}
} ;
2015-02-20 10:08:21 -05:00
static void DoTest ( void )
2015-01-11 05:21:18 -05:00
{
2015-01-12 03:38:00 -05:00
LOGD ( " EchoServer: starting up " ) ;
2015-01-21 15:12:11 -05:00
cServerHandlePtr Server = cNetwork : : Listen ( 9876 , std : : make_shared < cEchoServerCallbacks > ( ) ) ;
2015-01-12 03:38:00 -05:00
if ( ! Server - > IsListening ( ) )
{
LOGWARNING ( " Cannot listen on port 9876 " ) ;
abort ( ) ;
}
ASSERT ( Server - > IsListening ( ) ) ;
// Wait for the user to terminate the server:
2015-01-12 08:58:52 -05:00
printf ( " Press enter to close the server. \n " ) ;
2015-01-12 03:38:00 -05:00
AString line ;
std : : getline ( std : : cin , line ) ;
// Close the server and all its active connections:
LOG ( " Server terminating. " ) ;
Server - > Close ( ) ;
ASSERT ( ! Server - > IsListening ( ) ) ;
2015-01-30 15:24:02 -05:00
Server . reset ( ) ;
2015-01-12 08:58:52 -05:00
LOGD ( " Server has been closed. " ) ;
2015-01-26 08:46:20 -05:00
}
int main ( )
{
DoTest ( ) ;
2015-01-12 08:58:52 -05:00
printf ( " Press enter to exit test. \n " ) ;
2015-01-26 08:46:20 -05:00
AString line ;
2015-01-12 08:58:52 -05:00
std : : getline ( std : : cin , line ) ;
2015-01-26 08:46:20 -05:00
cNetworkSingleton : : Get ( ) . Terminate ( ) ;
2015-01-12 03:38:00 -05:00
LOG ( " Network test finished. " ) ;
2015-01-11 05:21:18 -05:00
return 0 ;
}