You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@thrift.apache.org by em...@apache.org on 2021/09/01 09:05:08 UTC

[thrift] branch master updated: Added support for Unix domain sockets on Windows

This is an automated email from the ASF dual-hosted git repository.

emmenlau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/thrift.git


The following commit(s) were added to refs/heads/master by this push:
     new 18bf591  Added support for Unix domain sockets on Windows
     new 0f5aebb  Merge pull request #2327 from BioDataAnalysis/bda_add_domain_sockets_for_windows
18bf591 is described below

commit 18bf59153521a813296142929308fbb0c3f4db65
Author: Mario Emmenlauer <me...@biodataanalysis.de>
AuthorDate: Thu Nov 19 13:54:12 2020 +0100

    Added support for Unix domain sockets on Windows
---
 lib/cpp/src/thrift/transport/SocketCommon.cpp  | 25 ++--------
 lib/cpp/src/thrift/transport/SocketCommon.h    | 11 +++--
 lib/cpp/src/thrift/transport/TServerSocket.cpp | 63 ++++++++++++++------------
 lib/cpp/src/thrift/transport/TSocket.cpp       | 20 ++++----
 lib/cpp/src/thrift/windows/config.h            | 15 ++++++
 5 files changed, 69 insertions(+), 65 deletions(-)

diff --git a/lib/cpp/src/thrift/transport/SocketCommon.cpp b/lib/cpp/src/thrift/transport/SocketCommon.cpp
index 570f39a..0b064c7 100644
--- a/lib/cpp/src/thrift/transport/SocketCommon.cpp
+++ b/lib/cpp/src/thrift/transport/SocketCommon.cpp
@@ -19,32 +19,17 @@
  * @author: David Suárez <da...@gmail.com>
  */
 
-#ifndef THRIFT_SOCKETCOMMON_H
-#define THRIFT_SOCKETCOMMON_H
-
-#ifndef _WIN32
-
-#include <thrift/thrift-config.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_SYS_UN_H
-#include <sys/un.h>
-#endif
-
-#include <string>
-
+#include <thrift/transport/SocketCommon.h>
 #include <thrift/transport/PlatformSocket.h>
 #include <thrift/transport/TTransportException.h>
 #include <thrift/TOutput.h>
 
+#include <cstring>
+
 namespace apache {
 namespace thrift {
 namespace transport {
 
-
 socklen_t fillUnixSocketAddr(struct sockaddr_un& address, std::string& path)
 {
     // abstract namespace socket ?
@@ -79,7 +64,3 @@ socklen_t fillUnixSocketAddr(struct sockaddr_un& address, std::string& path)
 }
 }
 } // apache::thrift::transport
-
-#endif // _WIN32
-
-#endif //THRIFT_SOCKETCOMMON_H
diff --git a/lib/cpp/src/thrift/transport/SocketCommon.h b/lib/cpp/src/thrift/transport/SocketCommon.h
index 78839c4..bd1032f 100644
--- a/lib/cpp/src/thrift/transport/SocketCommon.h
+++ b/lib/cpp/src/thrift/transport/SocketCommon.h
@@ -22,17 +22,20 @@
 #ifndef THRIFT_SOCKETCOMMON_H
 #define THRIFT_SOCKETCOMMON_H
 
-#ifndef _WIN32
-
 #include <thrift/thrift-config.h>
 
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
-
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
+#ifdef HAVE_AF_UNIX_H
+#include <afunix.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
 
 #include <string>
 
@@ -46,6 +49,4 @@ socklen_t fillUnixSocketAddr(struct sockaddr_un& address, std::string& path);
 }
 } // apache::thrift::transport
 
-#endif // _WIN32
-
 #endif //THRIFT_SOCKETCOMMON_H
diff --git a/lib/cpp/src/thrift/transport/TServerSocket.cpp b/lib/cpp/src/thrift/transport/TServerSocket.cpp
index 671cabc..8d6e7ef 100644
--- a/lib/cpp/src/thrift/transport/TServerSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TServerSocket.cpp
@@ -249,26 +249,28 @@ void TServerSocket::setInterruptableChildren(bool enable) {
 }
 
 void TServerSocket::_setup_sockopts() {
-
-  // Set THRIFT_NO_SOCKET_CACHING to prevent 2MSL delay on accept
-  int one = 1;
-  if (-1 == setsockopt(serverSocket_,
-                       SOL_SOCKET,
-                       THRIFT_NO_SOCKET_CACHING,
-                       cast_sockopt(&one),
-                       sizeof(one))) {
-// ignore errors coming out of this setsockopt on Windows.  This is because
-// SO_EXCLUSIVEADDRUSE requires admin privileges on WinXP, but we don't
-// want to force servers to be an admin.
-#ifndef _WIN32
-    int errno_copy = THRIFT_GET_SOCKET_ERROR;
-    GlobalOutput.perror("TServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ",
-                        errno_copy);
-    close();
-    throw TTransportException(TTransportException::NOT_OPEN,
-                              "Could not set THRIFT_NO_SOCKET_CACHING",
-                              errno_copy);
-#endif
+  if (!isUnixDomainSocket()) {
+    // Set THRIFT_NO_SOCKET_CACHING to prevent 2MSL delay on accept.
+    // This does not work with Domain sockets on most platforms. And
+    // on Windows it completely breaks the socket. Therefore do not
+    // use this on Domain sockets.
+    int one = 1;
+    if (-1 == setsockopt(serverSocket_,
+                        SOL_SOCKET,
+                        THRIFT_NO_SOCKET_CACHING,
+                        cast_sockopt(&one),
+                        sizeof(one))) {
+      // NOTE: SO_EXCLUSIVEADDRUSE socket option can only be used by members
+      // of the Administrators security group on Windows XP and earlier. But
+      // we do not target WinXP anymore so no special checks required.
+      int errno_copy = THRIFT_GET_SOCKET_ERROR;
+      GlobalOutput.perror("TServerSocket::listen() setsockopt() THRIFT_NO_SOCKET_CACHING ",
+                          errno_copy);
+      close();
+      throw TTransportException(TTransportException::NOT_OPEN,
+                                "Could not set THRIFT_NO_SOCKET_CACHING",
+                                errno_copy);
+    }
   }
 
   // Set TCP buffer sizes
@@ -437,12 +439,9 @@ void TServerSocket::listen() {
     _setup_sockopts();
     _setup_unixdomain_sockopts();
 
-/*
- * TODO: seems that windows now support unix sockets,
- *       see: https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
- */
-#ifndef _WIN32
-
+    // Windows supports Unix domain sockets since it ships the header
+    // HAVE_AF_UNIX_H (see https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/)
+#if (!defined(_WIN32) || defined(HAVE_AF_UNIX_H))
     struct sockaddr_un address;
     socklen_t structlen = fillUnixSocketAddr(address, path_);
 
@@ -454,7 +453,7 @@ void TServerSocket::listen() {
       // use short circuit evaluation here to only sleep if we need to
     } while ((retries++ < retryLimit_) && (THRIFT_SLEEP_SEC(retryDelay_) == 0));
 #else
-    GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
+    GlobalOutput.perror("TServerSocket::open() Unix Domain socket path not supported on this version of Windows", -99);
     throw TTransportException(TTransportException::NOT_OPEN,
                               " Unix Domain socket path not supported");
 #endif
@@ -537,9 +536,14 @@ void TServerSocket::listen() {
   if (retries > retryLimit_) {
     char errbuf[1024];
     if (isUnixDomainSocket()) {
-      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TServerSocket::listen() PATH %s", path_.c_str());
+#ifdef _WIN32
+      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TServerSocket::listen() Could not bind to domain socket path %s, error %d", path_.c_str(), WSAGetLastError());
+#else
+      // Fixme: This does not currently handle abstract domain sockets:
+      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TServerSocket::listen() Could not bind to domain socket path %s", path_.c_str());
+#endif
     } else {
-      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TServerSocket::listen() BIND %d", port_);
+      THRIFT_SNPRINTF(errbuf, sizeof(errbuf), "TServerSocket::listen() Could not bind to port %d", port_);
     }
     GlobalOutput(errbuf);
     close();
@@ -664,6 +668,7 @@ shared_ptr<TTransport> TServerSocket::acceptImpl() {
   }
 
   shared_ptr<TSocket> client = createSocket(clientSocket);
+  client->setPath(path_);
   if (sendTimeout_ > 0) {
     client->setSendTimeout(sendTimeout_);
   }
diff --git a/lib/cpp/src/thrift/transport/TSocket.cpp b/lib/cpp/src/thrift/transport/TSocket.cpp
index 1542c08..9991fd6 100644
--- a/lib/cpp/src/thrift/transport/TSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSocket.cpp
@@ -331,23 +331,18 @@ void TSocket::openConnection(struct addrinfo* res) {
   // Connect the socket
   int ret;
   if (isUnixDomainSocket()) {
-
-/*
- * TODO: seems that windows now support unix sockets,
- *       see: https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
- */
-#ifndef _WIN32
-
+    // Windows supports Unix domain sockets since it ships the header
+    // HAVE_AF_UNIX_H (see https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/)
+#if (!defined(_WIN32) || defined(HAVE_AF_UNIX_H))
     struct sockaddr_un address;
     socklen_t structlen = fillUnixSocketAddr(address, path_);
 
     ret = connect(socket_, (struct sockaddr*)&address, structlen);
 #else
-    GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
+    GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on this version of Windows", -99);
     throw TTransportException(TTransportException::NOT_OPEN,
                               " Unix Domain socket path not supported");
 #endif
-
   } else {
     ret = connect(socket_, res->ai_addr, static_cast<int>(res->ai_addrlen));
   }
@@ -804,6 +799,13 @@ void TSocket::setKeepAlive(bool keepAlive) {
     return;
   }
 
+#ifdef _WIN32
+  if (isUnixDomainSocket()) {
+      // Windows Domain sockets do not support SO_KEEPALIVE.
+      return;
+  }
+#endif
+
   int value = keepAlive_;
   int ret
       = setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, const_cast_sockopt(&value), sizeof(value));
diff --git a/lib/cpp/src/thrift/windows/config.h b/lib/cpp/src/thrift/windows/config.h
index a218d90..ce10c55 100644
--- a/lib/cpp/src/thrift/windows/config.h
+++ b/lib/cpp/src/thrift/windows/config.h
@@ -59,6 +59,7 @@
 // windows
 #include <Winsock2.h>
 #include <ws2tcpip.h>
+
 #ifndef __MINGW32__
   #ifdef _WIN32_WCE
   #pragma comment(lib, "Ws2.lib")
@@ -72,4 +73,18 @@
   #endif
 #endif // __MINGW32__
 
+// Replicate the logic of afunix.h on Windows (the header is only present on
+// newer Windows SDKs)
+#ifdef HAVE_AF_UNIX_H
+#include <afunix.h>
+#else
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+typedef struct sockaddr_un {
+  ADDRESS_FAMILY sun_family;    // AF_UNIX
+  char sun_path[UNIX_PATH_MAX]; // pathname
+} SOCKADDR_UN, *PSOCKADDR_UN;
+#endif // HAVE_AF_UNIX_H
+
 #endif // _THRIFT_WINDOWS_CONFIG_H_