summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2010-09-13 17:27:53 -0400
committerMathias Stearn <mathias@10gen.com>2010-09-13 18:43:56 -0400
commit86f511ead098c9d8512a61b70dad906a9a864779 (patch)
tree1ecbd91d229afe571701513c2b035de198fc5e3d
parente481f0f5d14f7743474e5c3c0a29d236f8db8e6c (diff)
downloadmongo-86f511ead098c9d8512a61b70dad906a9a864779.tar.gz
use getifaddrs() on linux SERVER-1515
-rw-r--r--util/message.cpp102
1 files changed, 100 insertions, 2 deletions
diff --git a/util/message.cpp b/util/message.cpp
index 9b08c0813e8..3914f7cf2c3 100644
--- a/util/message.cpp
+++ b/util/message.cpp
@@ -28,6 +28,10 @@
#include "../db/cmdline.h"
#include "../client/dbclient.h"
+#ifdef __linux__
+# include <ifaddrs.h>
+#endif
+
#ifndef _WIN32
#include <sys/resource.h>
#else
@@ -714,6 +718,83 @@ namespace mongo {
namespace {
map<string, bool> isSelfCache; // host, isSelf
+
+#ifdef __linux__
+
+ vector<string> getMyAddrs(){
+ ifaddrs * addrs;
+
+ int status = getifaddrs(&addrs);
+ massert(13469, "getifaddrs failure: " + errnoWithDescription(errno), status == 0);
+
+ vector<string> out;
+
+ // based on example code from linux getifaddrs manpage
+ for (ifaddrs * addr = addrs; addr != NULL; addr = addr->ifa_next){
+ int family = addr->ifa_addr->sa_family;
+ char host[NI_MAXHOST];
+
+ if (family == AF_INET || family == AF_INET6) {
+ status = getnameinfo(addr->ifa_addr,
+ (family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)),
+ host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+
+ massert(13470, string("getnameinfo() failed: ") + gai_strerror(status), status == 0);
+
+ out.push_back(host);
+ }
+
+ }
+
+ if (logLevel >= 1){
+ log(1) << "getMyAddrs():";
+ for (vector<string>::const_iterator it=out.begin(), end=out.end(); it!=end; ++it){
+ log(1) << " [" << *it << ']';
+ }
+ log(1) << endl;
+ }
+
+ return out;
+ }
+
+ vector<string> getAllIPs(StringData iporhost){
+ addrinfo* addrs = NULL;
+ addrinfo hints;
+ memset(&hints, 0, sizeof(addrinfo));
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET);
+
+ int ret = getaddrinfo(iporhost.data(), "0", &hints, &addrs);
+ massert(13471, string("getaddrinfo(\"") + iporhost.data() + "\") failed: " + gai_strerror(ret), ret == 0);
+
+ vector<string> out;
+ for (addrinfo* addr = addrs; addr != NULL; addr = addr->ai_next){
+ int family = addr->ai_family;
+ char host[NI_MAXHOST];
+
+ if (family == AF_INET || family == AF_INET6) {
+ int status = getnameinfo(addr->ai_addr, addr->ai_addrlen, host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
+
+ massert(13472, string("getnameinfo() failed: ") + gai_strerror(status), status == 0);
+
+ out.push_back(host);
+ }
+
+ }
+
+ freeaddrinfo(addrs);
+
+ if (logLevel >= 1){
+ log(1) << "getallIPs(\"" << iporhost << "\"):";
+ for (vector<string>::const_iterator it=out.begin(), end=out.end(); it!=end; ++it){
+ log(1) << " [" << *it << ']';
+ }
+ log(1) << endl;
+ }
+
+ return out;
+ }
+#endif
}
bool HostAndPort::isSelf() const {
@@ -729,14 +810,31 @@ namespace mongo {
return it->second;
}
+#ifdef __linux__
+
+ static const vector<string> myaddrs = getMyAddrs();
+ const vector<string> addrs = getAllIPs(_host);
+
+ bool ret=false;
+ for (vector<string>::const_iterator i=myaddrs.begin(), iend=myaddrs.end(); i!=iend; ++i){
+ for (vector<string>::const_iterator j=addrs.begin(), jend=addrs.end(); j!=jend; ++j){
+ if (*i == *j){
+ ret = true;
+ break;
+ }
+ }
+ }
+
+#else
SockAddr addr (_host.c_str(), 0); // port 0 is dynamically assigned
SOCKET sock = ::socket(addr.getType(), SOCK_STREAM, 0);
assert(sock != INVALID_SOCKET);
bool ret = (::bind(sock, addr.raw(), addr.addressSize) == 0);
- isSelfCache[_host] = ret;
-
closesocket(sock);
+#endif
+
+ isSelfCache[_host] = ret;
return ret;
}