IPv6 tweaks for Thrift
Summary: Need to pass hints including AI_ADDRCONFIG to getaddrinfo to make sure no IPv6 addresses come back on non-IPv6 enabled systems
Reviewed By: mcslee
Other Notes: Submitted by Paul Saab
git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@665368 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/lib/cpp/src/server/TNonblockingServer.cpp b/lib/cpp/src/server/TNonblockingServer.cpp
index ad1fb65..7735ec2 100644
--- a/lib/cpp/src/server/TNonblockingServer.cpp
+++ b/lib/cpp/src/server/TNonblockingServer.cpp
@@ -557,7 +557,7 @@
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
sprintf(port, "%d", port_);
// Wildcard address
diff --git a/lib/cpp/src/transport/TServerSocket.cpp b/lib/cpp/src/transport/TServerSocket.cpp
index ed86000..69d35bf 100644
--- a/lib/cpp/src/transport/TServerSocket.cpp
+++ b/lib/cpp/src/transport/TServerSocket.cpp
@@ -17,7 +17,7 @@
#include "TServerSocket.h"
#include <boost/shared_ptr.hpp>
-namespace facebook { namespace thrift { namespace transport {
+namespace facebook { namespace thrift { namespace transport {
using namespace std;
using boost::shared_ptr;
@@ -81,7 +81,7 @@
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
sprintf(port, "%d", port_);
// Wildcard address
@@ -98,7 +98,7 @@
if (res->ai_family == AF_INET6 || res->ai_next == NULL)
break;
}
-
+
serverSocket_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (serverSocket_ == -1) {
GlobalOutput("TServerSocket::listen() socket");
@@ -153,7 +153,7 @@
}
// prepare the port information
- // we may want to try to bind more than once, since SO_REUSEADDR doesn't
+ // we may want to try to bind more than once, since SO_REUSEADDR doesn't
// always seem to work. The client can configure the retry variables.
int retries = 0;
do {
@@ -166,7 +166,7 @@
// free addrinfo
freeaddrinfo(res0);
-
+
// throw an error if we failed to bind properly
if (retries > retryLimit_) {
char errbuf[1024];
@@ -207,7 +207,7 @@
if (ret < 0) {
// error cases
if (errno == EINTR && (numEintrs++ < maxEintrs)) {
- // EINTR needs to be handled manually and we can tolerate
+ // EINTR needs to be handled manually and we can tolerate
// a certain number
continue;
}
@@ -215,7 +215,7 @@
throw TTransportException(TTransportException::UNKNOWN);
} else if (ret > 0) {
// Check for an interrupt signal
- if (intSock2_ >= 0 && FD_ISSET(intSock2_, &fds)) {
+ if (intSock2_ >= 0 && FD_ISSET(intSock2_, &fds)) {
int8_t buf;
if (-1 == recv(intSock2_, &buf, sizeof(int8_t), 0)) {
GlobalOutput("TServerSocket::acceptImpl() interrupt receive");
@@ -228,7 +228,7 @@
}
} else {
GlobalOutput("TServerSocket::acceptImpl() select 0");
- throw TTransportException(TTransportException::UNKNOWN);
+ throw TTransportException(TTransportException::UNKNOWN);
}
}
@@ -237,7 +237,7 @@
int clientSocket = ::accept(serverSocket_,
(struct sockaddr *) &clientAddress,
(socklen_t *) &size);
-
+
if (clientSocket < 0) {
int errno_copy = errno;
GlobalOutput("TServerSocket::accept()");
@@ -256,7 +256,7 @@
GlobalOutput("TServerSocket::select() fcntl SETFL");
throw TTransportException(TTransportException::UNKNOWN, "fcntl(F_SETFL)", errno_copy);
}
-
+
shared_ptr<TSocket> client(new TSocket(clientSocket));
if (sendTimeout_ > 0) {
client->setSendTimeout(sendTimeout_);
@@ -264,7 +264,7 @@
if (recvTimeout_ > 0) {
client->setRecvTimeout(recvTimeout_);
}
-
+
return client;
}
diff --git a/lib/cpp/src/transport/TSocket.cpp b/lib/cpp/src/transport/TSocket.cpp
index 7da6d37..acf5288 100644
--- a/lib/cpp/src/transport/TSocket.cpp
+++ b/lib/cpp/src/transport/TSocket.cpp
@@ -20,7 +20,7 @@
#include "TSocket.h"
#include "TTransportException.h"
-namespace facebook { namespace thrift { namespace transport {
+namespace facebook { namespace thrift { namespace transport {
using namespace std;
using namespace facebook::thrift::concurrency;
@@ -37,7 +37,7 @@
// Mutex to protect syscalls to netdb
static Monitor s_netdb_monitor;
-TSocket::TSocket(string host, int port) :
+TSocket::TSocket(string host, int port) :
host_(host),
port_(port),
socket_(-1),
@@ -52,7 +52,7 @@
recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
}
-TSocket::TSocket() :
+TSocket::TSocket() :
host_(""),
port_(0),
socket_(-1),
@@ -81,13 +81,13 @@
recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
}
-
+
TSocket::~TSocket() {
close();
}
-bool TSocket::isOpen() {
- return (socket_ >= 0);
+bool TSocket::isOpen() {
+ return (socket_ >= 0);
}
bool TSocket::peek() {
@@ -135,7 +135,7 @@
setNoDelay(noDelay_);
// Set the socket to be non blocking for connect if a timeout exists
- int flags = fcntl(socket_, F_GETFL, 0);
+ int flags = fcntl(socket_, F_GETFL, 0);
if (connTimeout_ > 0) {
if (-1 == fcntl(socket_, F_SETFL, flags | O_NONBLOCK)) {
throw TTransportException(TTransportException::NOT_OPEN, "fcntl() failed");
@@ -149,10 +149,10 @@
// Conn timeout
struct timeval c = {(int)(connTimeout_/1000),
(int)((connTimeout_%1000)*1000)};
-
+
// Connect the socket
int ret = connect(socket_, res->ai_addr, res->ai_addrlen);
-
+
if (ret == 0) {
goto done;
}
@@ -221,9 +221,9 @@
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_PASSIVE;
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
sprintf(port, "%d", port_);
-
+
{
// Scope lock on host entry lookup
Synchronized s(s_netdb_monitor);
@@ -234,7 +234,7 @@
close();
throw TTransportException(TTransportException::NOT_OPEN, "Could not resolve host for client socket.");
}
-
+
// Cycle through all the returned addresses until one
// connects or push the exception up.
for (res = res0; res; res = res->ai_next) {
@@ -277,13 +277,13 @@
// EAGAIN is taken to indicate an out of resources error.
uint32_t eagainThresholdMicros = 0;
if (recvTimeout_) {
- // if a readTimeout is specified along with a max number of recv retries, then
+ // if a readTimeout is specified along with a max number of recv retries, then
// the threshold will ensure that the read timeout is not exceeded even in the
// case of resource errors
eagainThresholdMicros = (recvTimeout_*1000)/ ((maxRecvRetries_>0) ? maxRecvRetries_ : 2);
}
- try_again:
+ try_again:
// Read from the socket
struct timeval begin;
gettimeofday(&begin, NULL);
@@ -295,7 +295,7 @@
++g_socket_syscalls;
// Check for error on read
- if (got < 0) {
+ if (got < 0) {
if (errno == EAGAIN) {
// check if this is the lack of resources or timeout case
if (!eagainThresholdMicros || (readElapsedMicros < eagainThresholdMicros)) {
@@ -303,21 +303,21 @@
usleep(50);
goto try_again;
} else {
- throw TTransportException(TTransportException::TIMED_OUT,
+ throw TTransportException(TTransportException::TIMED_OUT,
"EAGAIN (unavailable resources)");
}
} else {
// infer that timeout has been hit
- throw TTransportException(TTransportException::TIMED_OUT,
+ throw TTransportException(TTransportException::TIMED_OUT,
"EAGAIN (timed out)");
}
}
-
+
// If interrupted, try again
if (errno == EINTR && retries++ < maxRecvRetries_) {
goto try_again;
}
-
+
// Now it's not a try again case, but a real probblez
string errStr = "TSocket::read() " + getSocketInfo();
GlobalOutput(errStr.c_str());
@@ -326,29 +326,29 @@
if (errno == ECONNRESET) {
throw TTransportException(TTransportException::NOT_OPEN, "ECONNRESET");
}
-
+
// This ish isn't open
if (errno == ENOTCONN) {
throw TTransportException(TTransportException::NOT_OPEN, "ENOTCONN");
}
-
+
// Timed out!
if (errno == ETIMEDOUT) {
throw TTransportException(TTransportException::TIMED_OUT, "ETIMEDOUT");
}
-
+
// Some other error, whatevz
char buff[1024];
sprintf(buff, "ERROR errno: %d", errno);
throw TTransportException(TTransportException::UNKNOWN, buff);
}
-
+
// The remote host has closed the socket
if (got == 0) {
close();
return 0;
}
-
+
// Pack data into string
return got;
}
@@ -359,7 +359,7 @@
}
uint32_t sent = 0;
-
+
while (sent < len) {
int flags = 0;
@@ -385,7 +385,7 @@
GlobalOutput(errStr.c_str());
throw TTransportException(TTransportException::UNKNOWN, "send", errno_copy);
}
-
+
// Fail on blocked send
if (b == 0) {
throw TTransportException(TTransportException::NOT_OPEN, "Socket send returned 0.");
@@ -466,7 +466,7 @@
if (socket_ < 0) {
return;
}
-
+
struct timeval s = {(int)(sendTimeout_/1000),
(int)((sendTimeout_%1000)*1000)};
int ret = setsockopt(socket_, SOL_SOCKET, SO_SNDTIMEO, &s, sizeof(s));
diff --git a/lib/py/src/transport/TSocket.py b/lib/py/src/transport/TSocket.py
index b2e08a1..0b44344 100644
--- a/lib/py/src/transport/TSocket.py
+++ b/lib/py/src/transport/TSocket.py
@@ -32,7 +32,7 @@
def open(self):
try:
- res0 = socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM)
+ res0 = socket.getaddrinfo(self.host, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE | socket.AI_ADDRCONFIG)
for res in res0:
self.handle = socket.socket(res[0], res[1])
try:
@@ -77,9 +77,9 @@
def __init__(self, port):
self.port = port
self.handle = None
-
+
def listen(self):
- res0 = socket.getaddrinfo(None, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE)
+ res0 = socket.getaddrinfo(None, self.port, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE | socket.AI_ADDRCONFIG)
for res in res0:
if res[0] is socket.AF_INET6 or res is res0[-1]:
break