Browse Source

Get client process id over ip/port when server runs on UNIX socket. (#1418)

* handle socket options for UNIX socket same as others

 * set FD_CLOEXEC by default
 * invoke `socket_options` callback if set

* Offer Client info even on UNIX socket based Server

HTTP Request header "REMOTE_PORT" contains client process id if possible
when Server works on UNIX socket.

* retrigger checks

* retrigger checks

* add support macOS

Co-authored-by: Changbin Park <[email protected]>
Changbin Park 3 years ago
parent
commit
93a51979c4
2 changed files with 46 additions and 0 deletions
  1. 21 0
      httplib.h
  2. 25 0
      test/test.cc

+ 21 - 0
httplib.h

@@ -2601,6 +2601,9 @@ socket_t create_socket(const std::string &host, const std::string &ip, int port,
       hints.ai_addrlen = static_cast<socklen_t>(
       hints.ai_addrlen = static_cast<socklen_t>(
           sizeof(addr) - sizeof(addr.sun_path) + addrlen);
           sizeof(addr) - sizeof(addr.sun_path) + addrlen);
 
 
+      fcntl(sock, F_SETFD, FD_CLOEXEC);
+      if (socket_options) { socket_options(sock); }
+
       if (!bind_or_connect(sock, hints)) {
       if (!bind_or_connect(sock, hints)) {
         close_socket(sock);
         close_socket(sock);
         sock = INVALID_SOCKET;
         sock = INVALID_SOCKET;
@@ -2871,6 +2874,24 @@ inline void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port) {
 
 
   if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr),
   if (!getpeername(sock, reinterpret_cast<struct sockaddr *>(&addr),
                    &addr_len)) {
                    &addr_len)) {
+#ifndef _WIN32
+    if (addr.ss_family == AF_UNIX) {
+#if defined(__linux__)
+        struct ucred ucred;
+        socklen_t len = sizeof(ucred);
+        if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) {
+            port = ucred.pid;
+        }
+#elif defined(SOL_LOCAL) && defined(SO_PEERPID)  // __APPLE__
+        pid_t pid;
+        socklen_t len = sizeof(pid);
+        if (getsockopt(sock, SOL_LOCAL, SO_PEERPID, &pid, &len) == 0) {
+            port = pid;
+        }
+#endif
+        return;
+    }
+#endif
     get_remote_ip_and_port(addr, addr_len, ip, port);
     get_remote_ip_and_port(addr, addr_len, ip, port);
   }
   }
 }
 }

+ 25 - 0
test/test.cc

@@ -5344,6 +5344,31 @@ TEST_F(UnixSocketTest, pathname) {
   t.join();
   t.join();
 }
 }
 
 
+#if defined(__linux__) \
+  || /* __APPLE__ */ (defined(SOL_LOCAL) && defined(SO_PEERPID))
+TEST_F(UnixSocketTest, PeerPid) {
+  httplib::Server svr;
+  std::string remote_port_val;
+  svr.Get(pattern_, [&](const httplib::Request &req, httplib::Response &res) {
+    res.set_content(content_, "text/plain");
+    remote_port_val = req.get_header_value("REMOTE_PORT");
+  });
+
+  std::thread t {[&] {
+    ASSERT_TRUE(svr.set_address_family(AF_UNIX).listen(pathname_, 80)); }};
+  while (!svr.is_running()) {
+    std::this_thread::sleep_for(std::chrono::milliseconds(1));
+  }
+  ASSERT_TRUE(svr.is_running());
+
+  client_GET(pathname_);
+  EXPECT_EQ(std::to_string(getpid()), remote_port_val);
+
+  svr.stop();
+  t.join();
+}
+#endif
+
 #ifdef __linux__
 #ifdef __linux__
 TEST_F(UnixSocketTest, abstract) {
 TEST_F(UnixSocketTest, abstract) {
   constexpr char svr_path[] {"\x00httplib-server.sock"};
   constexpr char svr_path[] {"\x00httplib-server.sock"};