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"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class cEchoServerCallbacks:
|
|
|
|
public cNetwork::cListenCallbacks
|
|
|
|
{
|
|
|
|
virtual void OnAccepted(cTCPLink & a_Link) override
|
|
|
|
{
|
2015-01-12 04:54:28 -05:00
|
|
|
LOGD("New client accepted (%s:%d), sending welcome message.", a_Link.GetRemoteIP().c_str(), a_Link.GetRemotePort());
|
2015-01-12 03:38:00 -05:00
|
|
|
// Send a welcome message to each connecting client:
|
|
|
|
a_Link.Send("Welcome to the simple echo server.\r\n");
|
|
|
|
LOGD("Welcome message queued.");
|
|
|
|
}
|
2015-01-15 15:10:14 -05:00
|
|
|
|
|
|
|
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-01-12 03:38:00 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** cTCPLink callbacks that echo everything they receive back to the remote peer. */
|
|
|
|
class cEchoLinkCallbacks:
|
|
|
|
public cTCPLink::cCallbacks
|
|
|
|
{
|
|
|
|
virtual void OnReceivedData(cTCPLink & a_Link, const char * a_Data, size_t a_Size) override
|
|
|
|
{
|
|
|
|
// Echo the incoming data back to outgoing data:
|
2015-01-12 04:17:11 -05:00
|
|
|
LOGD("%p (%s:%d): Data received (%u bytes), echoing back.", &a_Link, a_Link.GetRemoteIP().c_str(), a_Link.GetRemotePort(), static_cast<unsigned>(a_Size));
|
2015-01-12 03:38:00 -05:00
|
|
|
a_Link.Send(a_Data, a_Size);
|
|
|
|
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')
|
|
|
|
{
|
|
|
|
a_Link.Close();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2015-01-12 03:38:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void OnRemoteClosed(cTCPLink & a_Link) override
|
|
|
|
{
|
2015-01-12 04:17:11 -05:00
|
|
|
LOGD("%p (%s:%d): Remote has closed the connection.", &a_Link, a_Link.GetRemoteIP().c_str(), a_Link.GetRemotePort());
|
2015-01-12 03:38:00 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
virtual void OnError(cTCPLink & a_Link, int a_ErrorCode) override
|
|
|
|
{
|
2015-01-12 04:17:11 -05:00
|
|
|
LOGD("%p (%s:%d): Error %d in the cEchoLinkCallbacks.", &a_Link, a_Link.GetRemoteIP().c_str(), a_Link.GetRemotePort(), a_ErrorCode);
|
2015-01-12 03:38:00 -05:00
|
|
|
}
|
|
|
|
};
|
2015-01-11 05:21:18 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
2015-01-12 03:38:00 -05:00
|
|
|
LOGD("EchoServer: starting up");
|
|
|
|
cServerHandlePtr Server = cNetwork::Listen(9876, std::make_shared<cEchoServerCallbacks>(), std::make_shared<cEchoLinkCallbacks>());
|
|
|
|
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-12 08:58:52 -05:00
|
|
|
LOGD("Server has been closed.");
|
|
|
|
|
|
|
|
printf("Press enter to exit test.\n");
|
|
|
|
std::getline(std::cin, line);
|
2015-01-12 03:38:00 -05:00
|
|
|
|
|
|
|
LOG("Network test finished.");
|
2015-01-11 05:21:18 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|