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
pull/1/head
Tatsuhiro Tsujikawa 2009-12-06 08:25:41 +00:00
parent 766ad3baf2
commit 45f681b9dc
3 changed files with 67 additions and 47 deletions

View File

@ -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> 2009-12-05 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>
Updated po templates. Updated po templates.

View File

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

View File

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