Merge pull request #2327 from BioDataAnalysis/bda_add_domain_sockets_for_windows
THRIFT-5187: Added Win32 support for domain sockets (AF_UNIX)
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 <david.sephirot@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 @@
}
}
} // 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 @@
}
} // 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::_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 @@
_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 @@
// 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 @@
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<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 @@
// 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 @@
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_