summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt1
-rw-r--r--tests/Network/CMakeLists.txt60
-rw-r--r--tests/Network/EchoServer.cpp132
-rw-r--r--tests/Network/Google.cpp118
-rw-r--r--tests/Network/NameLookup.cpp80
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;
+}
+
+
+
+