Skip to content

Commit 3ff642c

Browse files
author
Bala Vignesh S
committed
feat: add Unix domain socket (UDS) listener support
Add support for listening on Unix domain sockets, enabling lower-latency same-host communication for reverse proxy setups (e.g., Nginx -> Drogon). Server API: app().addListener(/var/run/drogon.sock); Config file: {listeners: [{unix_socket: /var/run/drogon.sock}]} Changes: - Add HttpAppFramework::addListener(unixSocketPath) overload (POSIX only) - Add ListenerManager::addUnixListener() with UDS HttpServer creation - Add ConfigLoader support for 'unix_socket' field in listener config - Socket file is automatically cleaned up on server stop - Includes Trantor changes: InetAddress AF_UNIX support, Socket fixes Addresses #1153
1 parent fb41a64 commit 3ff642c

8 files changed

Lines changed: 130 additions & 2 deletions

File tree

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[submodule "trantor"]
22
path = trantor
3-
url = https://github.com/an-tao/trantor.git
3+
url = https://github.com/SBALAVIGNESH123/trantor.git
44
branch = master

lib/inc/drogon/HttpAppFramework.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,34 @@ class DROGON_EXPORT HttpAppFramework : public trantor::NonCopyable
871871
const std::vector<std::pair<std::string, std::string>> &sslConfCmds =
872872
{}) = 0;
873873

874+
#ifndef _WIN32
875+
/// Add a Unix domain socket listener.
876+
/**
877+
* @param unixSocketPath The filesystem path for the Unix domain socket.
878+
*
879+
* @note Unix domain sockets provide lower latency than TCP for same-host
880+
* communication, making them ideal for reverse proxy setups (e.g.,
881+
* Nginx -> Drogon). The socket file is automatically cleaned up when the
882+
* server stops.
883+
*
884+
* This is only supported on POSIX systems (Linux, macOS, FreeBSD).
885+
*
886+
* Example usage:
887+
* @code
888+
* app().addListener("/var/run/drogon.sock");
889+
* // Then use: curl --unix-socket /var/run/drogon.sock http://localhost/
890+
* @endcode
891+
*
892+
* @note
893+
* This operation can also be performed via the configuration file:
894+
* @code
895+
* "listeners": [{"unix_socket": "/var/run/drogon.sock"}]
896+
* @endcode
897+
*/
898+
virtual HttpAppFramework &addListener(
899+
const std::string &unixSocketPath) = 0;
900+
#endif
901+
874902
/// Enable sessions supporting.
875903
/**
876904
* @param timeout The number of seconds which is the timeout of a session

lib/src/ConfigLoader.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,18 @@ static void loadListeners(const Json::Value &listeners)
646646
LOG_TRACE << "Has " << listeners.size() << " listeners";
647647
for (auto const &listener : listeners)
648648
{
649+
#ifndef _WIN32
650+
// Check for Unix domain socket listener
651+
auto unixSocketPath =
652+
listener.get("unix_socket", "").asString();
653+
if (!unixSocketPath.empty())
654+
{
655+
LOG_TRACE << "Add Unix domain socket listener: "
656+
<< unixSocketPath;
657+
drogon::app().addListener(unixSocketPath);
658+
continue;
659+
}
660+
#endif
649661
auto addr = listener.get("address", "0.0.0.0").asString();
650662
auto port = (uint16_t)listener.get("port", 0).asUInt();
651663
auto useSSL = listener.get("https", false).asBool();

lib/src/HttpAppFrameworkImpl.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,6 +412,16 @@ HttpAppFramework &HttpAppFrameworkImpl::addListener(
412412
return *this;
413413
}
414414

415+
#ifndef _WIN32
416+
HttpAppFramework &HttpAppFrameworkImpl::addListener(
417+
const std::string &unixSocketPath)
418+
{
419+
assert(!running_);
420+
listenerManagerPtr_->addUnixListener(unixSocketPath);
421+
return *this;
422+
}
423+
#endif
424+
415425
HttpAppFramework &HttpAppFrameworkImpl::setMaxConnectionNum(
416426
size_t maxConnections)
417427
{

lib/src/HttpAppFrameworkImpl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ class HttpAppFrameworkImpl final : public HttpAppFramework
7272
bool useOldTLS,
7373
const std::vector<std::pair<std::string, std::string>> &sslConfCmds)
7474
override;
75+
#ifndef _WIN32
76+
HttpAppFramework &addListener(const std::string &unixSocketPath) override;
77+
#endif
7578
HttpAppFramework &setThreadNum(size_t threadNum) override;
7679

7780
size_t getThreadNum() const override

lib/src/ListenerManager.cc

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ void ListenerManager::addListener(
6565
ip, port, useSSL, certFile, keyFile, useOldTLS, sslConfCmds);
6666
}
6767

68+
#ifndef _WIN32
69+
void ListenerManager::addUnixListener(const std::string &socketPath)
70+
{
71+
LOG_TRACE << "Add Unix domain socket listener: " << socketPath;
72+
unixListeners_.emplace_back(socketPath);
73+
}
74+
#endif
75+
6876
std::vector<trantor::InetAddress> ListenerManager::getListeners() const
6977
{
7078
std::vector<trantor::InetAddress> listeners;
@@ -194,6 +202,47 @@ void ListenerManager::createListeners(
194202
}
195203
}
196204
#endif
205+
206+
#ifndef _WIN32
207+
// Create Unix domain socket listeners
208+
for (auto const &udsListener : unixListeners_)
209+
{
210+
InetAddress listenAddress(udsListener.socketPath_, trantor::UnixDomain);
211+
trantor::EventLoop *loop;
212+
#ifdef __linux__
213+
// On Linux with SO_REUSEPORT, use the main loop for UDS
214+
loop = HttpAppFrameworkImpl::instance().getLoop();
215+
#else
216+
if (!listeningThread_)
217+
{
218+
listeningThread_ =
219+
std::make_unique<EventLoopThread>("DrogonListeningLoop");
220+
listeningThread_->run();
221+
}
222+
loop = listeningThread_->getLoop();
223+
#endif
224+
auto serverPtr =
225+
std::make_shared<HttpServer>(loop, listenAddress, "drogon-unix");
226+
if (beforeListenSetSockOptCallback_)
227+
{
228+
serverPtr->setBeforeListenSockOptCallback(
229+
beforeListenSetSockOptCallback_);
230+
}
231+
if (afterAcceptSetSockOptCallback_)
232+
{
233+
serverPtr->setAfterAcceptSockOptCallback(
234+
afterAcceptSetSockOptCallback_);
235+
}
236+
if (connectionCallback_)
237+
{
238+
serverPtr->setConnectionCallback(connectionCallback_);
239+
}
240+
serverPtr->setIoLoops(ioLoops);
241+
servers_.push_back(serverPtr);
242+
LOG_INFO << "Unix domain socket listener created: "
243+
<< udsListener.socketPath_;
244+
}
245+
#endif
197246
}
198247

199248
void ListenerManager::startListening()
@@ -210,6 +259,15 @@ void ListenerManager::stopListening()
210259
{
211260
serverPtr->stop();
212261
}
262+
#ifndef _WIN32
263+
// Clean up Unix domain socket files
264+
for (auto const &udsListener : unixListeners_)
265+
{
266+
::unlink(udsListener.socketPath_.c_str());
267+
LOG_TRACE << "Removed Unix domain socket file: "
268+
<< udsListener.socketPath_;
269+
}
270+
#endif
213271
if (listeningThread_)
214272
{
215273
auto loop = listeningThread_->getLoop();

lib/src/ListenerManager.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ class ListenerManager : public trantor::NonCopyable
4242
bool useOldTLS = false,
4343
const std::vector<std::pair<std::string, std::string>>
4444
&sslConfCmds = {});
45+
#ifndef _WIN32
46+
void addUnixListener(const std::string &socketPath);
47+
#endif
4548
std::vector<trantor::InetAddress> getListeners() const;
4649
void createListeners(
4750
const std::string &globalCertFile,
@@ -102,6 +105,20 @@ class ListenerManager : public trantor::NonCopyable
102105
std::vector<ListenerInfo> listeners_;
103106
std::vector<std::shared_ptr<HttpServer>> servers_;
104107

108+
#ifndef _WIN32
109+
struct UnixListenerInfo
110+
{
111+
explicit UnixListenerInfo(std::string socketPath)
112+
: socketPath_(std::move(socketPath))
113+
{
114+
}
115+
116+
std::string socketPath_;
117+
};
118+
119+
std::vector<UnixListenerInfo> unixListeners_;
120+
#endif
121+
105122
// should have value when and only when on OS that one port can only be
106123
// listened by one thread
107124
std::unique_ptr<trantor::EventLoopThread> listeningThread_;

0 commit comments

Comments
 (0)