aboutsummaryrefslogtreecommitdiff
path: root/src/zenhttp/transports/dlltransport.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2023-10-11 14:59:25 +0200
committerGitHub <[email protected]>2023-10-11 14:59:25 +0200
commit11f7f70b825c5b6784f5e2609463a1a9d1a0dabc (patch)
tree98f65537f52327c354193afa98a29f9f838b42ff /src/zenhttp/transports/dlltransport.cpp
parenthide HttpAsioServer interface behind factory function (#463) (diff)
downloadzen-11f7f70b825c5b6784f5e2609463a1a9d1a0dabc.tar.xz
zen-11f7f70b825c5b6784f5e2609463a1a9d1a0dabc.zip
pluggable asio transport (#460)
added pluggable transport based on asio. This is in an experimental state and is not yet a replacement for httpasio even though that is the ultimate goal also moved plugin API header into dedicated part of the tree to clarify that it is meant to be usable in isolation, without any dependency on zencore et al moved transport implementations into dedicated source directory in zenhttp note that this adds code to the build but nothing should change at runtime since the instantiation of the new code is conditional and is inactive by default
Diffstat (limited to 'src/zenhttp/transports/dlltransport.cpp')
-rw-r--r--src/zenhttp/transports/dlltransport.cpp250
1 files changed, 250 insertions, 0 deletions
diff --git a/src/zenhttp/transports/dlltransport.cpp b/src/zenhttp/transports/dlltransport.cpp
new file mode 100644
index 000000000..04fb6caaa
--- /dev/null
+++ b/src/zenhttp/transports/dlltransport.cpp
@@ -0,0 +1,250 @@
+// Copyright Epic Games, Inc. All Rights Reserved.
+
+#include "dlltransport.h"
+
+#include <zencore/except.h>
+#include <zencore/logging.h>
+#include <zencore/scopeguard.h>
+
+#include <exception>
+#include <thread>
+#include <vector>
+
+#if ZEN_WITH_PLUGINS
+
+namespace zen {
+
+struct DllTransportConnection : public TransportConnection
+{
+public:
+ DllTransportConnection();
+ ~DllTransportConnection();
+
+ void Initialize(TransportServerConnection& ServerConnection);
+ void HandleConnection();
+
+ // TransportConnection
+
+ virtual int64_t WriteBytes(const void* Buffer, size_t DataSize) override;
+ virtual void Shutdown(bool Receive, bool Transmit) override;
+ virtual void CloseConnection() override;
+
+private:
+ Ref<TransportServerConnection> m_ConnectionHandler;
+ bool m_IsTerminated = false;
+};
+
+DllTransportConnection::DllTransportConnection()
+{
+}
+
+DllTransportConnection::~DllTransportConnection()
+{
+}
+
+void
+DllTransportConnection::Initialize(TransportServerConnection& ServerConnection)
+{
+ m_ConnectionHandler = &ServerConnection; // TODO: this is awkward
+}
+
+void
+DllTransportConnection::HandleConnection()
+{
+}
+
+void
+DllTransportConnection::CloseConnection()
+{
+ if (m_IsTerminated)
+ {
+ return;
+ }
+
+ m_IsTerminated = true;
+}
+
+int64_t
+DllTransportConnection::WriteBytes(const void* Buffer, size_t DataSize)
+{
+ ZEN_UNUSED(Buffer, DataSize);
+ return DataSize;
+}
+
+void
+DllTransportConnection::Shutdown(bool Receive, bool Transmit)
+{
+ ZEN_UNUSED(Receive, Transmit);
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+struct LoadedDll
+{
+ std::string Name;
+ std::filesystem::path LoadedFromPath;
+ Ref<TransportPlugin> Plugin;
+};
+
+class DllTransportPluginImpl
+{
+public:
+ DllTransportPluginImpl(uint16_t BasePort, unsigned int ThreadCount);
+ ~DllTransportPluginImpl();
+
+ uint16_t Start(TransportServer* ServerInterface);
+ void Stop();
+ bool IsAvailable();
+ void LoadDll(std::string_view Name);
+
+private:
+ TransportServer* m_ServerInterface = nullptr;
+ RwLock m_Lock;
+ std::vector<LoadedDll> m_Transports;
+ uint16_t m_BasePort = 0;
+ int m_ThreadCount = 0;
+};
+
+DllTransportPluginImpl::DllTransportPluginImpl(uint16_t BasePort, unsigned int ThreadCount)
+: m_BasePort(BasePort)
+, m_ThreadCount(ThreadCount != 0 ? ThreadCount : Max(std::thread::hardware_concurrency(), 8u))
+{
+}
+
+DllTransportPluginImpl::~DllTransportPluginImpl()
+{
+}
+
+uint16_t
+DllTransportPluginImpl::Start(TransportServer* ServerIface)
+{
+ m_ServerInterface = ServerIface;
+
+ RwLock::ExclusiveLockScope _(m_Lock);
+
+ for (LoadedDll& Transport : m_Transports)
+ {
+ try
+ {
+ Transport.Plugin->Initialize(ServerIface);
+ }
+ catch (const std::exception&)
+ {
+ // TODO: report
+ }
+ }
+
+ return m_BasePort;
+}
+
+void
+DllTransportPluginImpl::Stop()
+{
+ RwLock::ExclusiveLockScope _(m_Lock);
+
+ for (LoadedDll& Transport : m_Transports)
+ {
+ try
+ {
+ Transport.Plugin->Shutdown();
+ }
+ catch (const std::exception&)
+ {
+ // TODO: report
+ }
+ }
+}
+
+bool
+DllTransportPluginImpl::IsAvailable()
+{
+ return true;
+}
+
+void
+DllTransportPluginImpl::LoadDll(std::string_view Name)
+{
+ ExtendableStringBuilder<128> DllPath;
+ DllPath << Name << ".dll";
+ HMODULE DllHandle = LoadLibraryA(DllPath.c_str());
+
+ if (!DllHandle)
+ {
+ std::error_code Ec = MakeErrorCodeFromLastError();
+
+ throw std::system_error(Ec, fmt::format("failed to load transport DLL from '{}'", DllPath));
+ }
+
+ TransportPlugin* CreateTransportPlugin();
+
+ PfnCreateTransportPlugin CreatePlugin = (PfnCreateTransportPlugin)GetProcAddress(DllHandle, "CreateTransportPlugin");
+
+ if (!CreatePlugin)
+ {
+ std::error_code Ec = MakeErrorCodeFromLastError();
+
+ FreeLibrary(DllHandle);
+
+ throw std::system_error(Ec, fmt::format("API mismatch detected in transport DLL loaded from '{}'", DllPath));
+ }
+
+ LoadedDll NewDll;
+
+ NewDll.Name = Name;
+ NewDll.LoadedFromPath = DllPath.c_str();
+ NewDll.Plugin = CreatePlugin();
+
+ m_Transports.emplace_back(std::move(NewDll));
+}
+
+//////////////////////////////////////////////////////////////////////////
+
+DllTransportPlugin::DllTransportPlugin(uint16_t BasePort, unsigned int ThreadCount)
+: m_Impl(std::make_unique<DllTransportPluginImpl>(BasePort, ThreadCount))
+{
+}
+
+DllTransportPlugin::~DllTransportPlugin()
+{
+ m_Impl->Stop();
+}
+
+uint32_t
+DllTransportPlugin::AddRef() const
+{
+ return RefCounted::AddRef();
+}
+
+uint32_t
+DllTransportPlugin::Release() const
+{
+ return RefCounted::Release();
+}
+
+void
+DllTransportPlugin::Initialize(TransportServer* ServerInterface)
+{
+ m_Impl->Start(ServerInterface);
+}
+
+void
+DllTransportPlugin::Shutdown()
+{
+ m_Impl->Stop();
+}
+
+bool
+DllTransportPlugin::IsAvailable()
+{
+ return m_Impl->IsAvailable();
+}
+
+void
+DllTransportPlugin::LoadDll(std::string_view Name)
+{
+ return m_Impl->LoadDll(Name);
+}
+
+} // namespace zen
+
+#endif