Browse Source

2009-12-06 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Store all addresses found by getifaddrs() and getaddrinfo().  In
	bind, try all addresses until success
	* src/SocketCore.cc
	* src/SocketCore.h
Tatsuhiro Tsujikawa 16 years ago
parent
commit
45f681b9dc
3 changed files with 67 additions and 47 deletions
  1. 7 0
      ChangeLog
  2. 58 44
      src/SocketCore.cc
  3. 2 3
      src/SocketCore.h

+ 7 - 0
ChangeLog

@@ -1,3 +1,10 @@
+2009-12-06  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Store all addresses found by getifaddrs() and getaddrinfo().  In
+	bind, try all addresses until success
+	* src/SocketCore.cc
+	* src/SocketCore.h
+
 2009-12-05  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Updated po templates.

+ 58 - 44
src/SocketCore.cc

@@ -87,9 +87,8 @@ SocketCore::PollMethod SocketCore::_pollMethod = SocketCore::POLL_METHOD_SELECT;
 
 int SocketCore::_protocolFamily = AF_UNSPEC;
 
-SharedHandle<struct sockaddr_storage> SocketCore::_bindAddr;
-
-socklen_t SocketCore::_bindAddrLen = 0;
+std::vector<std::pair<struct sockaddr_storage, socklen_t> >
+SocketCore::_bindAddrs;
 
 #ifdef ENABLE_SSL
 SharedHandle<TLSContext> SocketCore::_tlsContext;
@@ -192,7 +191,7 @@ void SocketCore::bind(uint16_t port, int flags)
 {
   closeConnection();
 
-  if(flags == 0 || _bindAddr.isNull()) {
+  if(flags == 0 || _bindAddrs.empty()) {
     struct addrinfo hints;
     struct addrinfo* res;
     memset(&hints, 0, sizeof(hints));
@@ -217,11 +216,16 @@ void SocketCore::bind(uint16_t port, int flags)
     }
     freeaddrinfo(res);
   } else {
-    sock_t fd = bindInternal
-      (_bindAddr->ss_family, _sockType, 0,
-       reinterpret_cast<const struct sockaddr*>(_bindAddr.get()), _bindAddrLen);
-    if(fd != (sock_t)-1) {
-      sockfd = fd;
+    for(std::vector<std::pair<struct sockaddr_storage, socklen_t> >::
+	  const_iterator i = _bindAddrs.begin(); i != _bindAddrs.end(); ++i) {
+      sock_t fd = bindInternal
+	((*i).first.ss_family, _sockType, 0,
+	 reinterpret_cast<const struct sockaddr*>
+	 (&(*i).first), (*i).second);
+      if(fd != (sock_t)-1) {
+	sockfd = fd;
+	break;
+      }
     }
   }
   if(sockfd == (sock_t) -1) {
@@ -310,11 +314,19 @@ void SocketCore::establishConnection(const std::string& host, uint16_t port)
       CLOSE(fd);
       continue;
     }
-
-    if(!_bindAddr.isNull()) {
-      if(::bind(fd, reinterpret_cast<const struct sockaddr*>(_bindAddr.get()),
-		_bindAddrLen) == -1) {
-	LogFactory::getInstance()->debug(EX_SOCKET_BIND, strerror(errno));
+    if(!_bindAddrs.empty()) {
+      bool bindSuccess = false;
+      for(std::vector<std::pair<struct sockaddr_storage, socklen_t> >::
+	    const_iterator i = _bindAddrs.begin(); i != _bindAddrs.end(); ++i) {
+	if(::bind(fd,reinterpret_cast<const struct sockaddr*>(&(*i).first),
+		  (*i).second) == -1) {
+	  LogFactory::getInstance()->debug(EX_SOCKET_BIND, strerror(errno));
+	} else {
+	  bindSuccess = true;
+	  break;
+	}
+      }
+      if(!bindSuccess) {
 	CLOSE(fd);
 	continue;
       }
@@ -1127,10 +1139,7 @@ void SocketCore::useSelect()
 
 void SocketCore::bindAddress(const std::string& interface)
 {
-  SharedHandle<struct sockaddr_storage> bindAddr(new struct sockaddr_storage());
-  socklen_t bindAddrLen = 0;
-  memset(bindAddr.get(), 0, sizeof(struct sockaddr_storage));
-  bool found = false;
+  std::vector<std::pair<struct sockaddr_storage, socklen_t> > bindAddrs;
   LogFactory::getInstance()->debug("Finding interface %s", interface.c_str());
 #ifdef HAVE_GETIFADDRS
   // First find interface in interface addresses
@@ -1162,22 +1171,23 @@ void SocketCore::bindAddress(const std::string& interface)
 	continue;
       }
       if(std::string(ifa->ifa_name) == interface) {
-	bindAddrLen =
+	socklen_t bindAddrLen =
 	  family == AF_INET?sizeof(struct sockaddr_in):
 	  sizeof(struct sockaddr_in6);
-	memcpy(bindAddr.get(), ifa->ifa_addr, bindAddrLen);
-	found = true;
-	break;
+	struct sockaddr_storage bindAddr;
+	memset(&bindAddr, 0, sizeof(bindAddr));
+	memcpy(&bindAddr, ifa->ifa_addr, bindAddrLen);
+	bindAddrs.push_back(std::make_pair(bindAddr, bindAddrLen));
       }
     }
   }
 #endif // HAVE_GETIFADDRS
-  if(!found) {
+  if(bindAddrs.empty()) {
     struct addrinfo hints;
     struct addrinfo* res = 0;
     memset(&hints, 0, sizeof(hints));
     hints.ai_family = _protocolFamily;
-    hints.ai_socktype = 0;
+    hints.ai_socktype = SOCK_STREAM;
     hints.ai_flags = 0;
     hints.ai_protocol = 0;
     int s;
@@ -1190,37 +1200,41 @@ void SocketCore::bindAddress(const std::string& interface)
       auto_delete<struct addrinfo*> resDeleter(res, freeaddrinfo);
       struct addrinfo* rp;
       for(rp = res; rp; rp = rp->ai_next) {
-	bindAddrLen = rp->ai_addrlen;
-	memcpy(bindAddr.get(), rp->ai_addr, rp->ai_addrlen);
+	socklen_t bindAddrLen = rp->ai_addrlen;
+	struct sockaddr_storage bindAddr;
+	memset(&bindAddr, 0, sizeof(bindAddr));
+	memcpy(&bindAddr, rp->ai_addr, rp->ai_addrlen);
 	// Try to bind socket with this address. If it fails, the
 	// address is not for this machine.
 	try {
 	  SocketCore socket;
 	  socket.bind
-	    (reinterpret_cast<const struct sockaddr*>(bindAddr.get()),
-	     bindAddrLen);
+	    (reinterpret_cast<const struct sockaddr*>(&bindAddr), bindAddrLen);
+	  bindAddrs.push_back(std::make_pair(bindAddr, bindAddrLen));
 	} catch(RecoverableException& e) {
-	  throw DL_ABORT_EX2
-	    (StringFormat(MSG_INTERFACE_NOT_FOUND,
-			  interface.c_str(), e.what()).str(), e);
+	  continue;
 	}
-	found = true;
-	break;
       }
     }
   }
-  if(found) {
-    char host[NI_MAXHOST];
-    int s;
-    s = getnameinfo(reinterpret_cast<struct sockaddr*>(bindAddr.get()),
-		    bindAddrLen,
-		    host, NI_MAXHOST, 0, NI_MAXSERV,
-		    NI_NUMERICHOST);
-    if(s == 0) {
-      LogFactory::getInstance()->debug("Sockets will bind to %s", host);
+  if(bindAddrs.empty()) {
+      throw DL_ABORT_EX
+	(StringFormat(MSG_INTERFACE_NOT_FOUND,
+		      interface.c_str(), "not available").str());
+  } else {
+    _bindAddrs = bindAddrs;
+    for(std::vector<std::pair<struct sockaddr_storage, socklen_t> >::
+	  const_iterator i = _bindAddrs.begin(); i != _bindAddrs.end(); ++i) {
+      char host[NI_MAXHOST];
+      int s;
+      s = getnameinfo(reinterpret_cast<const struct sockaddr*>(&(*i).first),
+		      (*i).second,
+		      host, NI_MAXHOST, 0, NI_MAXSERV,
+		      NI_NUMERICHOST);
+      if(s == 0) {
+	LogFactory::getInstance()->debug("Sockets will bind to %s", host);
+      }
     }
-    _bindAddr = bindAddr;
-    _bindAddrLen = bindAddrLen;
   }
 }
 

+ 2 - 3
src/SocketCore.h

@@ -44,6 +44,7 @@
 #include <string>
 #include <cstdlib>
 #include <utility>
+#include <vector>
 
 #ifdef HAVE_LIBSSL
 // for SSL
@@ -92,9 +93,7 @@ private:
 
   static int _protocolFamily;
 
-  static SharedHandle<struct sockaddr_storage> _bindAddr;
-
-  static socklen_t _bindAddrLen;
+  static std::vector<std::pair<struct sockaddr_storage, socklen_t> > _bindAddrs;
 
   bool blocking;
   int secure;