diff options
Diffstat (limited to 'tests')
-rw-r--r-- | tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tests/Network/CMakeLists.txt | 60 | ||||
-rw-r--r-- | tests/Network/EchoServer.cpp | 132 | ||||
-rw-r--r-- | tests/Network/Google.cpp | 118 | ||||
-rw-r--r-- | tests/Network/NameLookup.cpp | 80 |
5 files changed, 391 insertions, 0 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 1fbd88f04..265640cc8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,3 +5,4 @@ enable_testing() include_directories(${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(ChunkData) +add_subdirectory(Network) diff --git a/tests/Network/CMakeLists.txt b/tests/Network/CMakeLists.txt new file mode 100644 index 000000000..c0af50e2c --- /dev/null +++ b/tests/Network/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required (VERSION 2.6) + +enable_testing() + +include_directories(${CMAKE_SOURCE_DIR}/src/) +include_directories(${CMAKE_SOURCE_DIR}/lib/libevent/include) + +add_definitions(-DTEST_GLOBALS=1) + +# Create a single Network library that contains all the networking code: +set (Network_SRCS + ${CMAKE_SOURCE_DIR}/src/OSSupport/CriticalSection.cpp + ${CMAKE_SOURCE_DIR}/src/OSSupport/Event.cpp + ${CMAKE_SOURCE_DIR}/src/OSSupport/HostnameLookup.cpp + ${CMAKE_SOURCE_DIR}/src/OSSupport/IPLookup.cpp + ${CMAKE_SOURCE_DIR}/src/OSSupport/NetworkSingleton.cpp + ${CMAKE_SOURCE_DIR}/src/OSSupport/ServerHandleImpl.cpp + ${CMAKE_SOURCE_DIR}/src/OSSupport/TCPLinkImpl.cpp + ${CMAKE_SOURCE_DIR}/src/StringUtils.cpp +) + +set (Network_HDRS + ${CMAKE_SOURCE_DIR}/src/OSSupport/CriticalSection.h + ${CMAKE_SOURCE_DIR}/src/OSSupport/Event.h + ${CMAKE_SOURCE_DIR}/src/OSSupport/HostnameLookup.h + ${CMAKE_SOURCE_DIR}/src/OSSupport/IPLookup.h + ${CMAKE_SOURCE_DIR}/src/OSSupport/Network.h + ${CMAKE_SOURCE_DIR}/src/OSSupport/NetworkSingleton.h + ${CMAKE_SOURCE_DIR}/src/OSSupport/ServerHandleImpl.h + ${CMAKE_SOURCE_DIR}/src/OSSupport/TCPLinkImpl.h + ${CMAKE_SOURCE_DIR}/src/StringUtils.h +) + +add_library(Network + ${Network_SRCS} + ${Network_HDRS} +) + +target_link_libraries(Network event_core event_extra) +if (MSVC) + target_link_libraries(Network ws2_32.lib) +endif() + + + + +# Define individual tests: + +# Google: download the google.com frontpage using http client socket: +add_executable(Google-exe Google.cpp) +target_link_libraries(Google-exe Network) +add_test(NAME Google-test COMMAND Google-exe) + +# EchoServer: Listen on port 9876, echo everything back: +add_executable(EchoServer EchoServer.cpp) +target_link_libraries(EchoServer Network) + +# NameLookup: Lookup hostname-to-IP and IP-to-hostname: +add_executable(NameLookup NameLookup.cpp) +target_link_libraries(NameLookup Network) diff --git a/tests/Network/EchoServer.cpp b/tests/Network/EchoServer.cpp new file mode 100644 index 000000000..728db0b7c --- /dev/null +++ b/tests/Network/EchoServer.cpp @@ -0,0 +1,132 @@ + +// EchoServer.cpp + +// Implements an Echo server using the LibEvent-based cNetwork API, as a test of that API + +#include "Globals.h" +#include <iostream> +#include <string> +#include "OSSupport/Network.h" + + + + + +/** cTCPLink callbacks that echo everything they receive back to the remote peer. */ +class cEchoLinkCallbacks: + public cTCPLink::cCallbacks +{ + // cTCPLink::cCallbacks overrides: + virtual void OnLinkCreated(cTCPLinkPtr a_Link) override + { + ASSERT(m_Link == nullptr); + m_Link = a_Link; + } + + + virtual void OnReceivedData(const char * a_Data, size_t a_Size) override + { + ASSERT(m_Link != nullptr); + + // Echo the incoming data back to outgoing data: + 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); + LOGD("Echo queued"); + + // Search for a Ctrl+Z, if found, drop the connection: + for (size_t i = 0; i < a_Size; i++) + { + if (a_Data[i] == '\x1a') + { + m_Link->Close(); + m_Link.reset(); + return; + } + } + } + + + virtual void OnRemoteClosed(void) override + { + 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(); + } + + + virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override + { + 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(); + } + + /** The link attached to this callbacks instance. */ + cTCPLinkPtr m_Link; +}; + + + + + +class cEchoServerCallbacks: + public cNetwork::cListenCallbacks +{ + virtual cTCPLink::cCallbacksPtr OnIncomingConnection(const AString & a_RemoteIPAddress, UInt16 a_RemotePort) + { + 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()); + } +}; + + + + + +int main() +{ + LOGD("EchoServer: starting up"); + cServerHandlePtr Server = cNetwork::Listen(9876, std::make_shared<cEchoServerCallbacks>()); + if (!Server->IsListening()) + { + LOGWARNING("Cannot listen on port 9876"); + abort(); + } + ASSERT(Server->IsListening()); + + // Wait for the user to terminate the server: + printf("Press enter to close the server.\n"); + AString line; + std::getline(std::cin, line); + + // Close the server and all its active connections: + LOG("Server terminating."); + Server->Close(); + ASSERT(!Server->IsListening()); + LOGD("Server has been closed."); + + printf("Press enter to exit test.\n"); + std::getline(std::cin, line); + + LOG("Network test finished."); + return 0; +} + + + + diff --git a/tests/Network/Google.cpp b/tests/Network/Google.cpp new file mode 100644 index 000000000..2b8830c24 --- /dev/null +++ b/tests/Network/Google.cpp @@ -0,0 +1,118 @@ + +// Google.cpp + +// Implements a HTTP download of the google's front page using the LibEvent-based cNetwork API + +#include "Globals.h" +#include <thread> +#include "OSSupport/Event.h" +#include "OSSupport/Network.h" + + + + + +/** Connect callbacks that send a HTTP GET request for google.com when connected. */ +class cHTTPConnectCallbacks: + public cNetwork::cConnectCallbacks +{ + cEvent & m_Event; + virtual void OnConnected(cTCPLink & a_Link) override + { + LOGD("Connected, sending HTTP GET"); + if (!a_Link.Send("GET / HTTP/1.0\r\nHost:google.com\r\n\r\n")) + { + LOGWARNING("Sending HTTP GET failed"); + } + LOGD("HTTP GET queued."); + } + + virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override + { + LOGD("Error while connecting HTTP: %d (%s)", a_ErrorCode, a_ErrorMsg.c_str()); + m_Event.Set(); + } + +public: + cHTTPConnectCallbacks(cEvent & a_Event): + m_Event(a_Event) + { + } +}; + + + + + +/** cTCPLink callbacks that dump everything it received to the log. */ +class cDumpCallbacks: + public cTCPLink::cCallbacks +{ + cEvent & m_Event; + cTCPLinkPtr m_Link; + + virtual void OnLinkCreated(cTCPLinkPtr a_Link) override + { + ASSERT(m_Link == nullptr); + m_Link = a_Link; + } + + virtual void OnReceivedData(const char * a_Data, size_t a_Size) override + { + ASSERT(m_Link != nullptr); + + // Log the incoming data size: + AString Hex; + CreateHexDump(Hex, a_Data, a_Size, 16); + LOGD("Incoming data: %u bytes:\n%s", static_cast<unsigned>(a_Size), Hex.c_str()); + } + + virtual void OnRemoteClosed(void) override + { + ASSERT(m_Link != nullptr); + + LOGD("Remote has closed the connection."); + m_Link.reset(); + m_Event.Set(); + } + + virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override + { + ASSERT(m_Link != nullptr); + + LOGD("Error %d (%s) in the cDumpCallbacks.", a_ErrorCode, a_ErrorMsg.c_str()); + m_Link.reset(); + m_Event.Set(); + } + +public: + cDumpCallbacks(cEvent & a_Event): + m_Event(a_Event) + { + } +}; + + + + + +int main() +{ + cEvent evtFinish; + + LOGD("Network test: Connecting to google.com:80, reading front page via HTTP."); + if (!cNetwork::Connect("google.com", 80, std::make_shared<cHTTPConnectCallbacks>(evtFinish), std::make_shared<cDumpCallbacks>(evtFinish))) + { + LOGWARNING("Cannot queue connection to google.com"); + abort(); + } + LOGD("Connect request has been queued."); + + evtFinish.Wait(); + LOGD("Network test finished"); + return 0; +} + + + + diff --git a/tests/Network/NameLookup.cpp b/tests/Network/NameLookup.cpp new file mode 100644 index 000000000..822a96baf --- /dev/null +++ b/tests/Network/NameLookup.cpp @@ -0,0 +1,80 @@ + +// NameLookup.cpp + +// Implements a DNS name lookup using the LibEvent-based cNetwork API + +#include "Globals.h" +#include <thread> +#include "OSSupport/Event.h" +#include "OSSupport/Network.h" + + + + + +class cFinishLookupCallbacks: + public cNetwork::cResolveNameCallbacks +{ + cEvent & m_Event; + + virtual void OnNameResolved(const AString & a_Name, const AString & a_IP) override + { + LOGD("%s resolves to IP %s", a_Name.c_str(), a_IP.c_str()); + } + + virtual void OnError(int a_ErrorCode, const AString & a_ErrorMsg) override + { + LOGD("Error %d (%s) while performing lookup!", a_ErrorCode, a_ErrorMsg.c_str()); + exit(a_ErrorCode); + } + + virtual void OnFinished(void) override + { + LOGD("Resolving finished."); + m_Event.Set(); + } + +public: + cFinishLookupCallbacks(cEvent & a_Event): + m_Event(a_Event) + { + } +}; + + + + + +int main() +{ + cEvent evtFinish; + + // Look up google.com (has multiple IP addresses): + LOGD("Network test: Looking up google.com"); + if (!cNetwork::HostnameToIP("google.com", std::make_shared<cFinishLookupCallbacks>(evtFinish))) + { + LOGWARNING("Cannot resolve google.com to IP"); + abort(); + } + LOGD("Name lookup has been successfully queued"); + evtFinish.Wait(); + LOGD("Lookup finished."); + + // Look up 8.8.8.8 (Google free DNS): + LOGD("Network test: Looking up IP 8.8.8.8"); + if (!cNetwork::IPToHostName("8.8.8.8", std::make_shared<cFinishLookupCallbacks>(evtFinish))) + { + LOGWARNING("Cannot resolve 8.8.8.8 to name"); + abort(); + } + LOGD("IP lookup has been successfully queued"); + evtFinish.Wait(); + LOGD("IP lookup finished."); + + LOGD("Network test finished"); + return 0; +} + + + + |