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