summaryrefslogtreecommitdiff
path: root/src/mongo/util/net/sock.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/util/net/sock.cpp')
-rw-r--r--src/mongo/util/net/sock.cpp1490
1 files changed, 744 insertions, 746 deletions
diff --git a/src/mongo/util/net/sock.cpp b/src/mongo/util/net/sock.cpp
index 42a5dcdba04..d9deed4036e 100644
--- a/src/mongo/util/net/sock.cpp
+++ b/src/mongo/util/net/sock.cpp
@@ -34,17 +34,17 @@
#include "mongo/util/net/sock.h"
#if !defined(_WIN32)
-# include <sys/socket.h>
-# include <sys/types.h>
-# include <sys/un.h>
-# include <netinet/in.h>
-# include <netinet/tcp.h>
-# include <arpa/inet.h>
-# include <errno.h>
-# include <netdb.h>
-# if defined(__OpenBSD__)
-# include <sys/uio.h>
-# endif
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#if defined(__OpenBSD__)
+#include <sys/uio.h>
+#endif
#endif
#include "mongo/config.h"
@@ -63,930 +63,928 @@
namespace mongo {
- using std::endl;
- using std::pair;
- using std::string;
- using std::stringstream;
- using std::vector;
-
- MONGO_FP_DECLARE(throwSockExcep);
-
- static bool ipv6 = false;
- void enableIPv6(bool state) { ipv6 = state; }
- bool IPv6Enabled() { return ipv6; }
-
- void setSockTimeouts(int sock, double secs) {
- bool report = shouldLog(logger::LogSeverity::Debug(4));
- DEV report = true;
+using std::endl;
+using std::pair;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+MONGO_FP_DECLARE(throwSockExcep);
+
+static bool ipv6 = false;
+void enableIPv6(bool state) {
+ ipv6 = state;
+}
+bool IPv6Enabled() {
+ return ipv6;
+}
+
+void setSockTimeouts(int sock, double secs) {
+ bool report = shouldLog(logger::LogSeverity::Debug(4));
+ DEV report = true;
#if defined(_WIN32)
- DWORD timeout = secs * 1000; // Windows timeout is a DWORD, in milliseconds.
- int status =
- setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO,
- reinterpret_cast<char*>(&timeout), sizeof(DWORD) );
- if (report && (status == SOCKET_ERROR))
- log() << "unable to set SO_RCVTIMEO: "
- << errnoWithDescription(WSAGetLastError()) << endl;
- status = setsockopt( sock, SOL_SOCKET, SO_SNDTIMEO,
- reinterpret_cast<char*>(&timeout), sizeof(DWORD) );
- DEV if (report && (status == SOCKET_ERROR))
- log() << "unable to set SO_SNDTIMEO: "
- << errnoWithDescription(WSAGetLastError()) << endl;
+ DWORD timeout = secs * 1000; // Windows timeout is a DWORD, in milliseconds.
+ int status =
+ setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&timeout), sizeof(DWORD));
+ if (report && (status == SOCKET_ERROR))
+ log() << "unable to set SO_RCVTIMEO: " << errnoWithDescription(WSAGetLastError()) << endl;
+ status =
+ setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&timeout), sizeof(DWORD));
+ DEV if (report && (status == SOCKET_ERROR)) log()
+ << "unable to set SO_SNDTIMEO: " << errnoWithDescription(WSAGetLastError()) << endl;
#else
- struct timeval tv;
- tv.tv_sec = (int)secs;
- tv.tv_usec = (int)((long long)(secs*1000*1000) % (1000*1000));
- bool ok = setsockopt( sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv) ) == 0;
- if( report && !ok ) log() << "unable to set SO_RCVTIMEO" << endl;
- ok = setsockopt( sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, sizeof(tv) ) == 0;
- DEV if( report && !ok ) log() << "unable to set SO_SNDTIMEO" << endl;
+ struct timeval tv;
+ tv.tv_sec = (int)secs;
+ tv.tv_usec = (int)((long long)(secs * 1000 * 1000) % (1000 * 1000));
+ bool ok = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)) == 0;
+ if (report && !ok)
+ log() << "unable to set SO_RCVTIMEO" << endl;
+ ok = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv)) == 0;
+ DEV if (report && !ok) log() << "unable to set SO_SNDTIMEO" << endl;
#endif
- }
+}
#if defined(_WIN32)
- void disableNagle(int sock) {
- int x = 1;
- if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &x, sizeof(x)) )
- error() << "disableNagle failed: " << errnoWithDescription() << endl;
- if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &x, sizeof(x)) )
- error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
- }
+void disableNagle(int sock) {
+ int x = 1;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char*)&x, sizeof(x)))
+ error() << "disableNagle failed: " << errnoWithDescription() << endl;
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&x, sizeof(x)))
+ error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
+}
#else
-
- void disableNagle(int sock) {
- int x = 1;
+
+void disableNagle(int sock) {
+ int x = 1;
#ifdef SOL_TCP
- int level = SOL_TCP;
+ int level = SOL_TCP;
#else
- int level = SOL_SOCKET;
+ int level = SOL_SOCKET;
#endif
- if ( setsockopt(sock, level, TCP_NODELAY, (char *) &x, sizeof(x)) )
- error() << "disableNagle failed: " << errnoWithDescription() << endl;
+ if (setsockopt(sock, level, TCP_NODELAY, (char*)&x, sizeof(x)))
+ error() << "disableNagle failed: " << errnoWithDescription() << endl;
#ifdef SO_KEEPALIVE
- if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &x, sizeof(x)) )
- error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
-
-# ifdef __linux__
- socklen_t len = sizeof(x);
- if ( getsockopt(sock, level, TCP_KEEPIDLE, (char *) &x, &len) )
- error() << "can't get TCP_KEEPIDLE: " << errnoWithDescription() << endl;
-
- if (x > 300) {
- x = 300;
- if ( setsockopt(sock, level, TCP_KEEPIDLE, (char *) &x, sizeof(x)) ) {
- error() << "can't set TCP_KEEPIDLE: " << errnoWithDescription() << endl;
- }
- }
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char*)&x, sizeof(x)))
+ error() << "SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
- len = sizeof(x); // just in case it changed
- if ( getsockopt(sock, level, TCP_KEEPINTVL, (char *) &x, &len) )
- error() << "can't get TCP_KEEPINTVL: " << errnoWithDescription() << endl;
+#ifdef __linux__
+ socklen_t len = sizeof(x);
+ if (getsockopt(sock, level, TCP_KEEPIDLE, (char*)&x, &len))
+ error() << "can't get TCP_KEEPIDLE: " << errnoWithDescription() << endl;
- if (x > 300) {
- x = 300;
- if ( setsockopt(sock, level, TCP_KEEPINTVL, (char *) &x, sizeof(x)) ) {
- error() << "can't set TCP_KEEPINTVL: " << errnoWithDescription() << endl;
- }
+ if (x > 300) {
+ x = 300;
+ if (setsockopt(sock, level, TCP_KEEPIDLE, (char*)&x, sizeof(x))) {
+ error() << "can't set TCP_KEEPIDLE: " << errnoWithDescription() << endl;
}
-# endif
-#endif
+ }
+
+ len = sizeof(x); // just in case it changed
+ if (getsockopt(sock, level, TCP_KEEPINTVL, (char*)&x, &len))
+ error() << "can't get TCP_KEEPINTVL: " << errnoWithDescription() << endl;
+ if (x > 300) {
+ x = 300;
+ if (setsockopt(sock, level, TCP_KEEPINTVL, (char*)&x, sizeof(x))) {
+ error() << "can't set TCP_KEEPINTVL: " << errnoWithDescription() << endl;
+ }
}
+#endif
+#endif
+}
#endif
- string getAddrInfoStrError(int code) {
+string getAddrInfoStrError(int code) {
#if !defined(_WIN32)
- return gai_strerror(code);
+ return gai_strerror(code);
#else
- /* gai_strerrorA is not threadsafe on windows. don't use it. */
- return errnoWithDescription(code);
+ /* gai_strerrorA is not threadsafe on windows. don't use it. */
+ return errnoWithDescription(code);
#endif
- }
-
- // --- SockAddr
- SockAddr::SockAddr() {
- addressSize = sizeof(sa);
- memset(&sa, 0, sizeof(sa));
- sa.ss_family = AF_UNSPEC;
- _isValid = true;
- }
-
- SockAddr::SockAddr(int sourcePort) {
- memset(as<sockaddr_in>().sin_zero, 0, sizeof(as<sockaddr_in>().sin_zero));
- as<sockaddr_in>().sin_family = AF_INET;
- as<sockaddr_in>().sin_port = htons(sourcePort);
- as<sockaddr_in>().sin_addr.s_addr = htonl(INADDR_ANY);
- addressSize = sizeof(sockaddr_in);
- _isValid = true;
- }
-
- SockAddr::SockAddr(const char * _iporhost , int port) {
- string target = _iporhost;
- if( target == "localhost" ) {
- target = "127.0.0.1";
- }
-
- if( mongoutils::str::contains(target, '/') ) {
+}
+
+// --- SockAddr
+SockAddr::SockAddr() {
+ addressSize = sizeof(sa);
+ memset(&sa, 0, sizeof(sa));
+ sa.ss_family = AF_UNSPEC;
+ _isValid = true;
+}
+
+SockAddr::SockAddr(int sourcePort) {
+ memset(as<sockaddr_in>().sin_zero, 0, sizeof(as<sockaddr_in>().sin_zero));
+ as<sockaddr_in>().sin_family = AF_INET;
+ as<sockaddr_in>().sin_port = htons(sourcePort);
+ as<sockaddr_in>().sin_addr.s_addr = htonl(INADDR_ANY);
+ addressSize = sizeof(sockaddr_in);
+ _isValid = true;
+}
+
+SockAddr::SockAddr(const char* _iporhost, int port) {
+ string target = _iporhost;
+ if (target == "localhost") {
+ target = "127.0.0.1";
+ }
+
+ if (mongoutils::str::contains(target, '/')) {
#ifdef _WIN32
- uassert(13080, "no unix socket support on windows", false);
+ uassert(13080, "no unix socket support on windows", false);
#endif
- uassert(13079, "path to unix socket too long",
- target.size() < sizeof(as<sockaddr_un>().sun_path));
- as<sockaddr_un>().sun_family = AF_UNIX;
- strcpy(as<sockaddr_un>().sun_path, target.c_str());
- addressSize = sizeof(sockaddr_un);
- _isValid = true;
- return;
- }
+ uassert(13079,
+ "path to unix socket too long",
+ target.size() < sizeof(as<sockaddr_un>().sun_path));
+ as<sockaddr_un>().sun_family = AF_UNIX;
+ strcpy(as<sockaddr_un>().sun_path, target.c_str());
+ addressSize = sizeof(sockaddr_un);
+ _isValid = true;
+ return;
+ }
- addrinfo* addrs = NULL;
- addrinfo hints;
- memset(&hints, 0, sizeof(addrinfo));
- hints.ai_socktype = SOCK_STREAM;
- //hints.ai_flags = AI_ADDRCONFIG; // This is often recommended but don't do it.
- // SERVER-1579
- hints.ai_flags |= AI_NUMERICHOST; // first pass tries w/o DNS lookup
- hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET);
+ addrinfo* addrs = NULL;
+ addrinfo hints;
+ memset(&hints, 0, sizeof(addrinfo));
+ hints.ai_socktype = SOCK_STREAM;
+ // hints.ai_flags = AI_ADDRCONFIG; // This is often recommended but don't do it.
+ // SERVER-1579
+ hints.ai_flags |= AI_NUMERICHOST; // first pass tries w/o DNS lookup
+ hints.ai_family = (IPv6Enabled() ? AF_UNSPEC : AF_INET);
- StringBuilder ss;
- ss << port;
- int ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs);
+ StringBuilder ss;
+ ss << port;
+ int ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs);
- // old C compilers on IPv6-capable hosts return EAI_NODATA error
+// old C compilers on IPv6-capable hosts return EAI_NODATA error
#ifdef EAI_NODATA
- int nodata = (ret == EAI_NODATA);
+ int nodata = (ret == EAI_NODATA);
#else
- int nodata = false;
+ int nodata = false;
#endif
- if ( (ret == EAI_NONAME || nodata) ) {
- // iporhost isn't an IP address, allow DNS lookup
- hints.ai_flags &= ~AI_NUMERICHOST;
- ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs);
- }
-
- if (ret) {
- // we were unsuccessful
- if( target != "0.0.0.0" ) { // don't log if this as it is a
- // CRT construction and log() may not work yet.
- log() << "getaddrinfo(\"" << target << "\") failed: " <<
- getAddrInfoStrError(ret) << endl;
- _isValid = false;
- return;
- }
- *this = SockAddr(port);
+ if ((ret == EAI_NONAME || nodata)) {
+ // iporhost isn't an IP address, allow DNS lookup
+ hints.ai_flags &= ~AI_NUMERICHOST;
+ ret = getaddrinfo(target.c_str(), ss.str().c_str(), &hints, &addrs);
+ }
+
+ if (ret) {
+ // we were unsuccessful
+ if (target != "0.0.0.0") { // don't log if this as it is a
+ // CRT construction and log() may not work yet.
+ log() << "getaddrinfo(\"" << target << "\") failed: " << getAddrInfoStrError(ret)
+ << endl;
+ _isValid = false;
return;
}
-
- //TODO: handle other addresses in linked list;
- fassert(16501, addrs->ai_addrlen <= sizeof(sa));
- memcpy(&sa, addrs->ai_addr, addrs->ai_addrlen);
- addressSize = addrs->ai_addrlen;
- freeaddrinfo(addrs);
- _isValid = true;
+ *this = SockAddr(port);
+ return;
}
- bool SockAddr::isLocalHost() const {
- switch (getType()) {
- case AF_INET: return getAddr() == "127.0.0.1";
- case AF_INET6: return getAddr() == "::1";
- case AF_UNIX: return true;
- default: return false;
- }
- fassert(16502, false);
- return false;
+ // TODO: handle other addresses in linked list;
+ fassert(16501, addrs->ai_addrlen <= sizeof(sa));
+ memcpy(&sa, addrs->ai_addr, addrs->ai_addrlen);
+ addressSize = addrs->ai_addrlen;
+ freeaddrinfo(addrs);
+ _isValid = true;
+}
+
+bool SockAddr::isLocalHost() const {
+ switch (getType()) {
+ case AF_INET:
+ return getAddr() == "127.0.0.1";
+ case AF_INET6:
+ return getAddr() == "::1";
+ case AF_UNIX:
+ return true;
+ default:
+ return false;
}
+ fassert(16502, false);
+ return false;
+}
- string SockAddr::toString(bool includePort) const {
- string out = getAddr();
- if (includePort && getType() != AF_UNIX && getType() != AF_UNSPEC)
- out += mongoutils::str::stream() << ':' << getPort();
- return out;
- }
-
- sa_family_t SockAddr::getType() const {
- return sa.ss_family;
- }
-
- unsigned SockAddr::getPort() const {
- switch (getType()) {
- case AF_INET: return ntohs(as<sockaddr_in>().sin_port);
- case AF_INET6: return ntohs(as<sockaddr_in6>().sin6_port);
- case AF_UNIX: return 0;
- case AF_UNSPEC: return 0;
- default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return 0;
- }
+string SockAddr::toString(bool includePort) const {
+ string out = getAddr();
+ if (includePort && getType() != AF_UNIX && getType() != AF_UNSPEC)
+ out += mongoutils::str::stream() << ':' << getPort();
+ return out;
+}
+
+sa_family_t SockAddr::getType() const {
+ return sa.ss_family;
+}
+
+unsigned SockAddr::getPort() const {
+ switch (getType()) {
+ case AF_INET:
+ return ntohs(as<sockaddr_in>().sin_port);
+ case AF_INET6:
+ return ntohs(as<sockaddr_in6>().sin6_port);
+ case AF_UNIX:
+ return 0;
+ case AF_UNSPEC:
+ return 0;
+ default:
+ massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
+ return 0;
}
-
- std::string SockAddr::getAddr() const {
- switch (getType()) {
+}
+
+std::string SockAddr::getAddr() const {
+ switch (getType()) {
case AF_INET:
case AF_INET6: {
- const int buflen=128;
+ const int buflen = 128;
char buffer[buflen];
int ret = getnameinfo(raw(), addressSize, buffer, buflen, NULL, 0, NI_NUMERICHOST);
- massert(13082, mongoutils::str::stream() << "getnameinfo error "
- << getAddrInfoStrError(ret), ret == 0);
+ massert(13082,
+ mongoutils::str::stream() << "getnameinfo error " << getAddrInfoStrError(ret),
+ ret == 0);
return buffer;
}
-
- case AF_UNIX:
- return (as<sockaddr_un>().sun_path[0] != '\0' ? as<sockaddr_un>().sun_path :
- "anonymous unix socket");
- case AF_UNSPEC:
+
+ case AF_UNIX:
+ return (as<sockaddr_un>().sun_path[0] != '\0' ? as<sockaddr_un>().sun_path
+ : "anonymous unix socket");
+ case AF_UNSPEC:
return "(NONE)";
- default:
- massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return "";
- }
+ default:
+ massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
+ return "";
}
+}
- bool SockAddr::operator==(const SockAddr& r) const {
- if (getType() != r.getType())
- return false;
-
- if (getPort() != r.getPort())
- return false;
-
- switch (getType()) {
- case AF_INET:
+bool SockAddr::operator==(const SockAddr& r) const {
+ if (getType() != r.getType())
+ return false;
+
+ if (getPort() != r.getPort())
+ return false;
+
+ switch (getType()) {
+ case AF_INET:
return as<sockaddr_in>().sin_addr.s_addr == r.as<sockaddr_in>().sin_addr.s_addr;
- case AF_INET6:
- return memcmp(as<sockaddr_in6>().sin6_addr.s6_addr,
- r.as<sockaddr_in6>().sin6_addr.s6_addr,
+ case AF_INET6:
+ return memcmp(as<sockaddr_in6>().sin6_addr.s6_addr,
+ r.as<sockaddr_in6>().sin6_addr.s6_addr,
sizeof(in6_addr)) == 0;
- case AF_UNIX:
+ case AF_UNIX:
return strcmp(as<sockaddr_un>().sun_path, r.as<sockaddr_un>().sun_path) == 0;
- case AF_UNSPEC:
- return true; // assume all unspecified addresses are the same
- default:
+ case AF_UNSPEC:
+ return true; // assume all unspecified addresses are the same
+ default:
massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
- }
- return false;
}
-
- bool SockAddr::operator!=(const SockAddr& r) const {
- return !(*this == r);
- }
-
- bool SockAddr::operator<(const SockAddr& r) const {
- if (getType() < r.getType())
- return true;
- else if (getType() > r.getType())
- return false;
-
- if (getPort() < r.getPort())
- return true;
- else if (getPort() > r.getPort())
- return false;
-
- switch (getType()) {
- case AF_INET:
+ return false;
+}
+
+bool SockAddr::operator!=(const SockAddr& r) const {
+ return !(*this == r);
+}
+
+bool SockAddr::operator<(const SockAddr& r) const {
+ if (getType() < r.getType())
+ return true;
+ else if (getType() > r.getType())
+ return false;
+
+ if (getPort() < r.getPort())
+ return true;
+ else if (getPort() > r.getPort())
+ return false;
+
+ switch (getType()) {
+ case AF_INET:
return as<sockaddr_in>().sin_addr.s_addr < r.as<sockaddr_in>().sin_addr.s_addr;
- case AF_INET6:
- return memcmp(as<sockaddr_in6>().sin6_addr.s6_addr,
- r.as<sockaddr_in6>().sin6_addr.s6_addr,
+ case AF_INET6:
+ return memcmp(as<sockaddr_in6>().sin6_addr.s6_addr,
+ r.as<sockaddr_in6>().sin6_addr.s6_addr,
sizeof(in6_addr)) < 0;
- case AF_UNIX:
+ case AF_UNIX:
return strcmp(as<sockaddr_un>().sun_path, r.as<sockaddr_un>().sun_path) < 0;
- case AF_UNSPEC:
+ case AF_UNSPEC:
return false;
- default:
+ default:
massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
- }
- return false;
}
+ return false;
+}
- string makeUnixSockPath(int port) {
- return mongoutils::str::stream() << serverGlobalParams.socket << "/mongodb-" << port
- << ".sock";
- }
+string makeUnixSockPath(int port) {
+ return mongoutils::str::stream() << serverGlobalParams.socket << "/mongodb-" << port << ".sock";
+}
- // If an ip address is passed in, just return that. If a hostname is passed
- // in, look up its ip and return that. Returns "" on failure.
- string hostbyname(const char *hostname) {
- SockAddr sockAddr(hostname, 0);
- if (!sockAddr.isValid() || sockAddr.getAddr() == "0.0.0.0")
- return "";
- else
- return sockAddr.getAddr();
- }
-
- // --- my --
+// If an ip address is passed in, just return that. If a hostname is passed
+// in, look up its ip and return that. Returns "" on failure.
+string hostbyname(const char* hostname) {
+ SockAddr sockAddr(hostname, 0);
+ if (!sockAddr.isValid() || sockAddr.getAddr() == "0.0.0.0")
+ return "";
+ else
+ return sockAddr.getAddr();
+}
- DiagStr& _hostNameCached = *(new DiagStr); // this is also written to from commands/cloud.cpp
+// --- my --
- string getHostName() {
- char buf[256];
- int ec = gethostname(buf, 127);
- if ( ec || *buf == 0 ) {
- log() << "can't get this server's hostname " << errnoWithDescription() << endl;
- return "";
- }
- return buf;
- }
+DiagStr& _hostNameCached = *(new DiagStr); // this is also written to from commands/cloud.cpp
- /** we store our host name once */
- string getHostNameCached() {
- string temp = _hostNameCached.get();
- if (_hostNameCached.empty()) {
- temp = getHostName();
- _hostNameCached = temp;
- }
- return temp;
+string getHostName() {
+ char buf[256];
+ int ec = gethostname(buf, 127);
+ if (ec || *buf == 0) {
+ log() << "can't get this server's hostname " << errnoWithDescription() << endl;
+ return "";
}
+ return buf;
+}
- string prettyHostName() {
- StringBuilder s;
- s << getHostNameCached();
- if (serverGlobalParams.port != ServerGlobalParams::DefaultDBPort)
- s << ':' << mongo::serverGlobalParams.port;
- return s.str();
+/** we store our host name once */
+string getHostNameCached() {
+ string temp = _hostNameCached.get();
+ if (_hostNameCached.empty()) {
+ temp = getHostName();
+ _hostNameCached = temp;
}
+ return temp;
+}
+
+string prettyHostName() {
+ StringBuilder s;
+ s << getHostNameCached();
+ if (serverGlobalParams.port != ServerGlobalParams::DefaultDBPort)
+ s << ':' << mongo::serverGlobalParams.port;
+ return s.str();
+}
- // --------- SocketException ----------
+// --------- SocketException ----------
#ifdef MSG_NOSIGNAL
- const int portSendFlags = MSG_NOSIGNAL;
- const int portRecvFlags = MSG_NOSIGNAL;
+const int portSendFlags = MSG_NOSIGNAL;
+const int portRecvFlags = MSG_NOSIGNAL;
#else
- const int portSendFlags = 0;
- const int portRecvFlags = 0;
+const int portSendFlags = 0;
+const int portRecvFlags = 0;
#endif
- string SocketException::toString() const {
- stringstream ss;
- ss << _ei.code << " socket exception [" << _getStringType(_type) << "] ";
-
- if ( _server.size() )
- ss << "server [" << _server << "] ";
-
- if ( _extra.size() )
- ss << _extra;
-
- return ss.str();
- }
+string SocketException::toString() const {
+ stringstream ss;
+ ss << _ei.code << " socket exception [" << _getStringType(_type) << "] ";
+
+ if (_server.size())
+ ss << "server [" << _server << "] ";
- // ------------ Socket -----------------
+ if (_extra.size())
+ ss << _extra;
- static int socketGetLastError() {
+ return ss.str();
+}
+
+// ------------ Socket -----------------
+
+static int socketGetLastError() {
#ifdef _WIN32
- return WSAGetLastError();
+ return WSAGetLastError();
#else
- return errno;
+ return errno;
#endif
+}
+
+static SockAddr getLocalAddrForBoundSocketFd(int fd) {
+ SockAddr result;
+ int rc = getsockname(fd, result.raw(), &result.addressSize);
+ if (rc != 0) {
+ warning() << "Could not resolve local address for socket with fd " << fd << ": "
+ << getAddrInfoStrError(socketGetLastError());
+ result = SockAddr();
+ }
+ return result;
+}
+
+Socket::Socket(int fd, const SockAddr& remote)
+ : _fd(fd),
+ _remote(remote),
+ _timeout(0),
+ _lastValidityCheckAtSecs(time(0)),
+ _logLevel(logger::LogSeverity::Log()) {
+ _init();
+ if (fd >= 0) {
+ _local = getLocalAddrForBoundSocketFd(_fd);
}
+}
- static SockAddr getLocalAddrForBoundSocketFd(int fd) {
- SockAddr result;
- int rc = getsockname(fd, result.raw(), &result.addressSize);
- if (rc != 0) {
- warning() << "Could not resolve local address for socket with fd " << fd << ": " <<
- getAddrInfoStrError(socketGetLastError());
- result = SockAddr();
- }
- return result;
- }
-
- Socket::Socket(int fd , const SockAddr& remote) :
- _fd(fd), _remote(remote), _timeout(0), _lastValidityCheckAtSecs(time(0)),
- _logLevel(logger::LogSeverity::Log()) {
- _init();
- if (fd >= 0) {
- _local = getLocalAddrForBoundSocketFd(_fd);
- }
- }
+Socket::Socket(double timeout, logger::LogSeverity ll) : _logLevel(ll) {
+ _fd = -1;
+ _timeout = timeout;
+ _lastValidityCheckAtSecs = time(0);
+ _init();
+}
- Socket::Socket( double timeout, logger::LogSeverity ll ) : _logLevel(ll) {
- _fd = -1;
- _timeout = timeout;
- _lastValidityCheckAtSecs = time(0);
- _init();
- }
+Socket::~Socket() {
+ close();
+}
- Socket::~Socket() {
- close();
- }
-
- void Socket::_init() {
- _bytesOut = 0;
- _bytesIn = 0;
- _awaitingHandshake = true;
+void Socket::_init() {
+ _bytesOut = 0;
+ _bytesIn = 0;
+ _awaitingHandshake = true;
#ifdef MONGO_CONFIG_SSL
- _sslManager = 0;
+ _sslManager = 0;
#endif
- }
+}
- void Socket::close() {
- if ( _fd >= 0 ) {
- // Stop any blocking reads/writes, and prevent new reads/writes
+void Socket::close() {
+ if (_fd >= 0) {
+// Stop any blocking reads/writes, and prevent new reads/writes
#if defined(_WIN32)
- shutdown( _fd, SD_BOTH );
+ shutdown(_fd, SD_BOTH);
#else
- shutdown( _fd, SHUT_RDWR );
+ shutdown(_fd, SHUT_RDWR);
#endif
- closesocket( _fd );
- _fd = -1;
- }
+ closesocket(_fd);
+ _fd = -1;
}
+}
#ifdef MONGO_CONFIG_SSL
- bool Socket::secure(SSLManagerInterface* mgr, const std::string& remoteHost) {
- fassert(16503, mgr);
- if ( _fd < 0 ) {
- return false;
- }
- _sslManager = mgr;
- _sslConnection.reset(_sslManager->connect(this));
- mgr->parseAndValidatePeerCertificate(_sslConnection.get(), remoteHost);
- return true;
- }
-
- void Socket::secureAccepted( SSLManagerInterface* ssl ) {
- _sslManager = ssl;
+bool Socket::secure(SSLManagerInterface* mgr, const std::string& remoteHost) {
+ fassert(16503, mgr);
+ if (_fd < 0) {
+ return false;
}
-
- std::string Socket::doSSLHandshake(const char* firstBytes, int len) {
- if (!_sslManager) return "";
- fassert(16506, _fd);
- if (_sslConnection.get()) {
- throw SocketException(SocketException::RECV_ERROR,
- "Attempt to call SSL_accept on already secure Socket from " +
+ _sslManager = mgr;
+ _sslConnection.reset(_sslManager->connect(this));
+ mgr->parseAndValidatePeerCertificate(_sslConnection.get(), remoteHost);
+ return true;
+}
+
+void Socket::secureAccepted(SSLManagerInterface* ssl) {
+ _sslManager = ssl;
+}
+
+std::string Socket::doSSLHandshake(const char* firstBytes, int len) {
+ if (!_sslManager)
+ return "";
+ fassert(16506, _fd);
+ if (_sslConnection.get()) {
+ throw SocketException(SocketException::RECV_ERROR,
+ "Attempt to call SSL_accept on already secure Socket from " +
remoteString());
- }
- _sslConnection.reset(_sslManager->accept(this, firstBytes, len));
- return _sslManager->parseAndValidatePeerCertificate(_sslConnection.get(), "");
}
+ _sslConnection.reset(_sslManager->accept(this, firstBytes, len));
+ return _sslManager->parseAndValidatePeerCertificate(_sslConnection.get(), "");
+}
#endif
- class ConnectBG : public BackgroundJob {
- public:
- ConnectBG(int sock, SockAddr remote) : _sock(sock), _remote(remote) { }
+class ConnectBG : public BackgroundJob {
+public:
+ ConnectBG(int sock, SockAddr remote) : _sock(sock), _remote(remote) {}
- void run() {
+ void run() {
#if defined(_WIN32)
- if ((_res = _connect()) == SOCKET_ERROR) {
- _errnoWithDescription = errnoWithDescription();
- }
+ if ((_res = _connect()) == SOCKET_ERROR) {
+ _errnoWithDescription = errnoWithDescription();
+ }
#else
- while ((_res = _connect()) == -1) {
- const int error = errno;
- if (error != EINTR) {
- _errnoWithDescription = errnoWithDescription(error);
- break;
- }
+ while ((_res = _connect()) == -1) {
+ const int error = errno;
+ if (error != EINTR) {
+ _errnoWithDescription = errnoWithDescription(error);
+ break;
}
-#endif
}
+#endif
+ }
- std::string name() const { return "ConnectBG"; }
- std::string getErrnoWithDescription() const { return _errnoWithDescription; }
- int inError() const { return _res; }
+ std::string name() const {
+ return "ConnectBG";
+ }
+ std::string getErrnoWithDescription() const {
+ return _errnoWithDescription;
+ }
+ int inError() const {
+ return _res;
+ }
- private:
- int _connect() const {
- return ::connect(_sock, _remote.raw(), _remote.addressSize);
- }
+private:
+ int _connect() const {
+ return ::connect(_sock, _remote.raw(), _remote.addressSize);
+ }
- int _sock;
- int _res;
- SockAddr _remote;
- std::string _errnoWithDescription;
- };
+ int _sock;
+ int _res;
+ SockAddr _remote;
+ std::string _errnoWithDescription;
+};
- bool Socket::connect(SockAddr& remote) {
- _remote = remote;
+bool Socket::connect(SockAddr& remote) {
+ _remote = remote;
- _fd = socket(remote.getType(), SOCK_STREAM, 0);
- if ( _fd == INVALID_SOCKET ) {
- LOG(_logLevel) << "ERROR: connect invalid socket " << errnoWithDescription() << endl;
- return false;
- }
+ _fd = socket(remote.getType(), SOCK_STREAM, 0);
+ if (_fd == INVALID_SOCKET) {
+ LOG(_logLevel) << "ERROR: connect invalid socket " << errnoWithDescription() << endl;
+ return false;
+ }
- if ( _timeout > 0 ) {
- setTimeout( _timeout );
- }
+ if (_timeout > 0) {
+ setTimeout(_timeout);
+ }
- static const unsigned int connectTimeoutMillis = 5000;
- ConnectBG bg(_fd, remote);
- bg.go();
- if ( bg.wait(connectTimeoutMillis) ) {
- if ( bg.inError() ) {
- warning() << "Failed to connect to "
- << _remote.getAddr() << ":" << _remote.getPort()
- << ", reason: " << bg.getErrnoWithDescription() << endl;
- close();
- return false;
- }
- }
- else {
- // time out the connect
+ static const unsigned int connectTimeoutMillis = 5000;
+ ConnectBG bg(_fd, remote);
+ bg.go();
+ if (bg.wait(connectTimeoutMillis)) {
+ if (bg.inError()) {
+ warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort()
+ << ", reason: " << bg.getErrnoWithDescription() << endl;
close();
- bg.wait(); // so bg stays in scope until bg thread terminates
- warning() << "Failed to connect to "
- << _remote.getAddr() << ":" << _remote.getPort()
- << " after " << connectTimeoutMillis << " milliseconds, giving up." << endl;
return false;
}
+ } else {
+ // time out the connect
+ close();
+ bg.wait(); // so bg stays in scope until bg thread terminates
+ warning() << "Failed to connect to " << _remote.getAddr() << ":" << _remote.getPort()
+ << " after " << connectTimeoutMillis << " milliseconds, giving up." << endl;
+ return false;
+ }
- if (remote.getType() != AF_UNIX)
- disableNagle(_fd);
+ if (remote.getType() != AF_UNIX)
+ disableNagle(_fd);
#ifdef SO_NOSIGPIPE
- // ignore SIGPIPE signals on osx, to avoid process exit
- const int one = 1;
- setsockopt( _fd , SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int));
+ // ignore SIGPIPE signals on osx, to avoid process exit
+ const int one = 1;
+ setsockopt(_fd, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(int));
#endif
- _local = getLocalAddrForBoundSocketFd(_fd);
+ _local = getLocalAddrForBoundSocketFd(_fd);
- _fdCreationMicroSec = curTimeMicros64();
+ _fdCreationMicroSec = curTimeMicros64();
- _awaitingHandshake = false;
+ _awaitingHandshake = false;
- return true;
- }
+ return true;
+}
- // throws if SSL_write or send fails
- int Socket::_send( const char * data , int len, const char * context ) {
+// throws if SSL_write or send fails
+int Socket::_send(const char* data, int len, const char* context) {
#ifdef MONGO_CONFIG_SSL
- if ( _sslConnection.get() ) {
- return _sslManager->SSL_write( _sslConnection.get() , data , len );
- }
-#endif
- int ret = ::send( _fd , data , len , portSendFlags );
- if (ret < 0) {
- handleSendError(ret, context);
- }
- return ret;
+ if (_sslConnection.get()) {
+ return _sslManager->SSL_write(_sslConnection.get(), data, len);
}
-
- // sends all data or throws an exception
- void Socket::send( const char * data , int len, const char *context ) {
- while( len > 0 ) {
- int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+#endif
+ int ret = ::send(_fd, data, len, portSendFlags);
+ if (ret < 0) {
+ handleSendError(ret, context);
+ }
+ return ret;
+}
+
+// sends all data or throws an exception
+void Socket::send(const char* data, int len, const char* context) {
+ while (len > 0) {
+ int ret = -1;
+ if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
- WSASetLastError(WSAENETUNREACH);
+ WSASetLastError(WSAENETUNREACH);
#else
- errno = ENETUNREACH;
+ errno = ENETUNREACH;
#endif
- handleSendError(ret, context);
- }
- else {
- ret = _send(data, len, context);
- }
-
- _bytesOut += ret;
+ handleSendError(ret, context);
+ } else {
+ ret = _send(data, len, context);
+ }
- fassert(16507, ret <= len);
- len -= ret;
- data += ret;
+ _bytesOut += ret;
- }
+ fassert(16507, ret <= len);
+ len -= ret;
+ data += ret;
}
+}
- void Socket::_send( const vector< pair< char *, int > > &data, const char *context ) {
- for (vector< pair<char *, int> >::const_iterator i = data.begin();
- i != data.end();
- ++i) {
- char * data = i->first;
- int len = i->second;
- send( data, len, context );
- }
+void Socket::_send(const vector<pair<char*, int>>& data, const char* context) {
+ for (vector<pair<char*, int>>::const_iterator i = data.begin(); i != data.end(); ++i) {
+ char* data = i->first;
+ int len = i->second;
+ send(data, len, context);
}
+}
- /** sends all data or throws an exception
- * @param context descriptive for logging
- */
- void Socket::send( const vector< pair< char *, int > > &data, const char *context ) {
-
+/** sends all data or throws an exception
+ * @param context descriptive for logging
+ */
+void Socket::send(const vector<pair<char*, int>>& data, const char* context) {
#ifdef MONGO_CONFIG_SSL
- if ( _sslConnection.get() ) {
- _send( data , context );
- return;
- }
+ if (_sslConnection.get()) {
+ _send(data, context);
+ return;
+ }
#endif
#if defined(_WIN32)
- // TODO use scatter/gather api
- _send( data , context );
+ // TODO use scatter/gather api
+ _send(data, context);
#else
- vector<struct iovec> d( data.size() );
- int i = 0;
- for (vector< pair<char *, int> >::const_iterator j = data.begin();
- j != data.end();
- ++j) {
- if ( j->second > 0 ) {
- d[ i ].iov_base = j->first;
- d[ i ].iov_len = j->second;
- ++i;
- _bytesOut += j->second;
- }
- }
- struct msghdr meta;
- memset( &meta, 0, sizeof( meta ) );
- meta.msg_iov = &d[ 0 ];
- meta.msg_iovlen = d.size();
-
- while( meta.msg_iovlen > 0 ) {
- int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+ vector<struct iovec> d(data.size());
+ int i = 0;
+ for (vector<pair<char*, int>>::const_iterator j = data.begin(); j != data.end(); ++j) {
+ if (j->second > 0) {
+ d[i].iov_base = j->first;
+ d[i].iov_len = j->second;
+ ++i;
+ _bytesOut += j->second;
+ }
+ }
+ struct msghdr meta;
+ memset(&meta, 0, sizeof(meta));
+ meta.msg_iov = &d[0];
+ meta.msg_iovlen = d.size();
+
+ while (meta.msg_iovlen > 0) {
+ int ret = -1;
+ if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
- WSASetLastError(WSAENETUNREACH);
+ WSASetLastError(WSAENETUNREACH);
#else
- errno = ENETUNREACH;
+ errno = ENETUNREACH;
#endif
+ } else {
+ ret = ::sendmsg(_fd, &meta, portSendFlags);
+ }
+
+ if (ret == -1) {
+ if (errno != EAGAIN || _timeout == 0) {
+ LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription()
+ << ' ' << remoteString() << endl;
+ throw SocketException(SocketException::SEND_ERROR, remoteString());
+ } else {
+ LOG(_logLevel) << "Socket " << context << " send() remote timeout "
+ << remoteString() << endl;
+ throw SocketException(SocketException::SEND_TIMEOUT, remoteString());
}
- else {
- ret = ::sendmsg(_fd, &meta, portSendFlags);
- }
-
- if (ret == -1) {
- if ( errno != EAGAIN || _timeout == 0 ) {
- LOG(_logLevel) << "Socket " << context <<
- " send() " << errnoWithDescription() << ' ' << remoteString() << endl;
- throw SocketException( SocketException::SEND_ERROR , remoteString() );
- }
- else {
- LOG(_logLevel) << "Socket " << context <<
- " send() remote timeout " << remoteString() << endl;
- throw SocketException( SocketException::SEND_TIMEOUT , remoteString() );
- }
- }
- else {
- struct iovec *& i = meta.msg_iov;
- while( ret > 0 ) {
- if ( i->iov_len > unsigned( ret ) ) {
- i->iov_len -= ret;
- i->iov_base = (char*)(i->iov_base) + ret;
- ret = 0;
- }
- else {
- ret -= i->iov_len;
- ++i;
- --(meta.msg_iovlen);
- }
+ } else {
+ struct iovec*& i = meta.msg_iov;
+ while (ret > 0) {
+ if (i->iov_len > unsigned(ret)) {
+ i->iov_len -= ret;
+ i->iov_base = (char*)(i->iov_base) + ret;
+ ret = 0;
+ } else {
+ ret -= i->iov_len;
+ ++i;
+ --(meta.msg_iovlen);
}
}
}
-#endif
}
+#endif
+}
- void Socket::recv( char * buf , int len ) {
- while( len > 0 ) {
- int ret = -1;
- if (MONGO_FAIL_POINT(throwSockExcep)) {
+void Socket::recv(char* buf, int len) {
+ while (len > 0) {
+ int ret = -1;
+ if (MONGO_FAIL_POINT(throwSockExcep)) {
#if defined(_WIN32)
- WSASetLastError(WSAENETUNREACH);
+ WSASetLastError(WSAENETUNREACH);
#else
- errno = ENETUNREACH;
+ errno = ENETUNREACH;
#endif
- if (ret <= 0) {
- handleRecvError(ret, len);
- continue;
- }
- }
- else {
- ret = unsafe_recv(buf, len);
+ if (ret <= 0) {
+ handleRecvError(ret, len);
+ continue;
}
-
- fassert(16508, ret <= len);
- len -= ret;
- buf += ret;
+ } else {
+ ret = unsafe_recv(buf, len);
}
- }
- int Socket::unsafe_recv( char *buf, int max ) {
- int x = _recv( buf , max );
- _bytesIn += x;
- return x;
+ fassert(16508, ret <= len);
+ len -= ret;
+ buf += ret;
}
+}
+
+int Socket::unsafe_recv(char* buf, int max) {
+ int x = _recv(buf, max);
+ _bytesIn += x;
+ return x;
+}
- // throws if SSL_read fails or recv returns an error
- int Socket::_recv( char *buf, int max ) {
+// throws if SSL_read fails or recv returns an error
+int Socket::_recv(char* buf, int max) {
#ifdef MONGO_CONFIG_SSL
- if ( _sslConnection.get() ){
- return _sslManager->SSL_read( _sslConnection.get() , buf , max );
- }
+ if (_sslConnection.get()) {
+ return _sslManager->SSL_read(_sslConnection.get(), buf, max);
+ }
#endif
- int ret = ::recv( _fd , buf , max , portRecvFlags );
- if (ret <= 0) {
- handleRecvError(ret, max); // If no throw return and call _recv again
- return 0;
- }
- return ret;
+ int ret = ::recv(_fd, buf, max, portRecvFlags);
+ if (ret <= 0) {
+ handleRecvError(ret, max); // If no throw return and call _recv again
+ return 0;
}
+ return ret;
+}
- void Socket::handleSendError(int ret, const char* context) {
-
+void Socket::handleSendError(int ret, const char* context) {
#if defined(_WIN32)
- const int mongo_errno = WSAGetLastError();
- if ( mongo_errno == WSAETIMEDOUT && _timeout != 0 ) {
+ const int mongo_errno = WSAGetLastError();
+ if (mongo_errno == WSAETIMEDOUT && _timeout != 0) {
#else
- const int mongo_errno = errno;
- if ( ( mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK ) && _timeout != 0 ) {
+ const int mongo_errno = errno;
+ if ((mongo_errno == EAGAIN || mongo_errno == EWOULDBLOCK) && _timeout != 0) {
#endif
- LOG(_logLevel) << "Socket " << context <<
- " send() timed out " << remoteString() << endl;
- throw SocketException(SocketException::SEND_TIMEOUT , remoteString());
- }
- else {
- LOG(_logLevel) << "Socket " << context << " send() "
- << errnoWithDescription(mongo_errno) << ' ' << remoteString() << endl;
- throw SocketException(SocketException::SEND_ERROR , remoteString());
- }
+ LOG(_logLevel) << "Socket " << context << " send() timed out " << remoteString() << endl;
+ throw SocketException(SocketException::SEND_TIMEOUT, remoteString());
+ } else {
+ LOG(_logLevel) << "Socket " << context << " send() " << errnoWithDescription(mongo_errno)
+ << ' ' << remoteString() << endl;
+ throw SocketException(SocketException::SEND_ERROR, remoteString());
}
+}
- void Socket::handleRecvError(int ret, int len) {
- if (ret == 0) {
- LOG(3) << "Socket recv() conn closed? " << remoteString() << endl;
- throw SocketException(SocketException::CLOSED , remoteString());
- }
-
- // ret < 0
+void Socket::handleRecvError(int ret, int len) {
+ if (ret == 0) {
+ LOG(3) << "Socket recv() conn closed? " << remoteString() << endl;
+ throw SocketException(SocketException::CLOSED, remoteString());
+ }
+
+// ret < 0
#if defined(_WIN32)
- int e = WSAGetLastError();
+ int e = WSAGetLastError();
#else
- int e = errno;
-# if defined(EINTR)
- if (e == EINTR) {
- LOG(_logLevel) << "EINTR returned from recv(), retrying";
- return;
- }
-# endif
+ int e = errno;
+#if defined(EINTR)
+ if (e == EINTR) {
+ LOG(_logLevel) << "EINTR returned from recv(), retrying";
+ return;
+ }
+#endif
#endif
#if defined(_WIN32)
- // Windows
- if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) {
+ // Windows
+ if ((e == EAGAIN || e == WSAETIMEDOUT) && _timeout > 0) {
#else
- if (e == EAGAIN && _timeout > 0) {
+ if (e == EAGAIN && _timeout > 0) {
#endif
- // this is a timeout
- LOG(_logLevel) << "Socket recv() timeout " << remoteString() <<endl;
- throw SocketException(SocketException::RECV_TIMEOUT, remoteString());
- }
-
- LOG(_logLevel) << "Socket recv() " <<
- errnoWithDescription(e) << " " << remoteString() <<endl;
- throw SocketException(SocketException::RECV_ERROR , remoteString());
- }
-
- void Socket::setTimeout( double secs ) {
- setSockTimeouts( _fd, secs );
- }
-
- // TODO: allow modification?
- //
- // <positive value> : secs to wait between stillConnected checks
- // 0 : always check
- // -1 : never check
- const int Socket::errorPollIntervalSecs( 5 );
-
- // Patch to allow better tolerance of flaky network connections that get broken
- // while we aren't looking.
- // TODO: Remove when better async changes come.
- //
- // isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine
- // if any disconnection-type events have happened on the socket.
- bool Socket::isStillConnected() {
- if (_fd == -1) {
- // According to the man page, poll will respond with POLLVNAL for invalid or
- // unopened descriptors, but it doesn't seem to be properly implemented in
- // some platforms - it can return 0 events and 0 for revent. Hence this workaround.
- return false;
- }
-
- if ( errorPollIntervalSecs < 0 ) return true;
- if ( ! isPollSupported() ) return true; // nothing we can do
+ // this is a timeout
+ LOG(_logLevel) << "Socket recv() timeout " << remoteString() << endl;
+ throw SocketException(SocketException::RECV_TIMEOUT, remoteString());
+ }
+
+ LOG(_logLevel) << "Socket recv() " << errnoWithDescription(e) << " " << remoteString() << endl;
+ throw SocketException(SocketException::RECV_ERROR, remoteString());
+}
+
+void Socket::setTimeout(double secs) {
+ setSockTimeouts(_fd, secs);
+}
+
+// TODO: allow modification?
+//
+// <positive value> : secs to wait between stillConnected checks
+// 0 : always check
+// -1 : never check
+const int Socket::errorPollIntervalSecs(5);
+
+// Patch to allow better tolerance of flaky network connections that get broken
+// while we aren't looking.
+// TODO: Remove when better async changes come.
+//
+// isStillConnected() polls the socket at max every Socket::errorPollIntervalSecs to determine
+// if any disconnection-type events have happened on the socket.
+bool Socket::isStillConnected() {
+ if (_fd == -1) {
+ // According to the man page, poll will respond with POLLVNAL for invalid or
+ // unopened descriptors, but it doesn't seem to be properly implemented in
+ // some platforms - it can return 0 events and 0 for revent. Hence this workaround.
+ return false;
+ }
- time_t now = time( 0 );
- time_t idleTimeSecs = now - _lastValidityCheckAtSecs;
+ if (errorPollIntervalSecs < 0)
+ return true;
+ if (!isPollSupported())
+ return true; // nothing we can do
- // Only check once every 5 secs
- if ( idleTimeSecs < errorPollIntervalSecs ) return true;
- // Reset our timer, we're checking the connection
- _lastValidityCheckAtSecs = now;
+ time_t now = time(0);
+ time_t idleTimeSecs = now - _lastValidityCheckAtSecs;
- // It's been long enough, poll to see if our socket is still connected
+ // Only check once every 5 secs
+ if (idleTimeSecs < errorPollIntervalSecs)
+ return true;
+ // Reset our timer, we're checking the connection
+ _lastValidityCheckAtSecs = now;
- pollfd pollInfo;
- pollInfo.fd = _fd;
- // We only care about reading the EOF message on clean close (and errors)
- pollInfo.events = POLLIN;
+ // It's been long enough, poll to see if our socket is still connected
- // Poll( info[], size, timeout ) - timeout == 0 => nonblocking
- int nEvents = socketPoll( &pollInfo, 1, 0 );
+ pollfd pollInfo;
+ pollInfo.fd = _fd;
+ // We only care about reading the EOF message on clean close (and errors)
+ pollInfo.events = POLLIN;
- LOG( 2 ) << "polling for status of connection to " << remoteString()
- << ", " << ( nEvents == 0 ? "no events" :
- nEvents == -1 ? "error detected" :
- "event detected" ) << endl;
+ // Poll( info[], size, timeout ) - timeout == 0 => nonblocking
+ int nEvents = socketPoll(&pollInfo, 1, 0);
- if ( nEvents == 0 ) {
- // No events incoming, return still connected AFAWK
- return true;
- }
- else if ( nEvents < 0 ) {
- // Poll itself failed, this is weird, warn and log errno
- warning() << "Socket poll() failed during connectivity check"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")"
- << causedBy(errnoWithDescription()) << endl;
+ LOG(2) << "polling for status of connection to " << remoteString() << ", "
+ << (nEvents == 0 ? "no events" : nEvents == -1 ? "error detected" : "event detected")
+ << endl;
- // Return true since it's not clear that we're disconnected.
- return true;
- }
-
- dassert( nEvents == 1 );
- dassert( pollInfo.revents > 0 );
+ if (nEvents == 0) {
+ // No events incoming, return still connected AFAWK
+ return true;
+ } else if (nEvents < 0) {
+ // Poll itself failed, this is weird, warn and log errno
+ warning() << "Socket poll() failed during connectivity check"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << causedBy(errnoWithDescription())
+ << endl;
+
+ // Return true since it's not clear that we're disconnected.
+ return true;
+ }
- // Return false at this point, some event happened on the socket, but log what the
- // actual event was.
+ dassert(nEvents == 1);
+ dassert(pollInfo.revents > 0);
- if ( pollInfo.revents & POLLIN ) {
+ // Return false at this point, some event happened on the socket, but log what the
+ // actual event was.
- // There shouldn't really be any data to recv here, so make sure this
- // is a clean hangup.
+ if (pollInfo.revents & POLLIN) {
+ // There shouldn't really be any data to recv here, so make sure this
+ // is a clean hangup.
- const int testBufLength = 1024;
- char testBuf[testBufLength];
+ const int testBufLength = 1024;
+ char testBuf[testBufLength];
- int recvd = ::recv( _fd, testBuf, testBufLength, portRecvFlags );
+ int recvd = ::recv(_fd, testBuf, testBufLength, portRecvFlags);
- if ( recvd < 0 ) {
- // An error occurred during recv, warn and log errno
- warning() << "Socket recv() failed during connectivity check"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")"
- << causedBy(errnoWithDescription()) << endl;
- }
- else if ( recvd > 0 ) {
- // We got nonzero data from this socket, very weird?
- // Log and warn at runtime, log and abort at devtime
- // TODO: Dump the data to the log somehow?
- error() << "Socket found pending " << recvd
- << " bytes of data during connectivity check"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")" << endl;
- DEV {
- std::string hex = hexdump(testBuf, recvd);
- error() << "Hex dump of stale log data: " << hex << endl;
- }
- dassert( false );
- }
- else {
- // recvd == 0, socket closed remotely, just return false
- LOG( 0 ) << "Socket closed remotely, no longer connected"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")" << endl;
- }
- }
- else if ( pollInfo.revents & POLLHUP ) {
- // A hangup has occurred on this socket
- LOG( 0 ) << "Socket hangup detected, no longer connected" << " (idle "
- << idleTimeSecs << " secs," << " remote host " << remoteString() << ")"
- << endl;
- }
- else if ( pollInfo.revents & POLLERR ) {
- // An error has occurred on this socket
- LOG( 0 ) << "Socket error detected, no longer connected" << " (idle "
- << idleTimeSecs << " secs," << " remote host " << remoteString() << ")"
- << endl;
- }
- else if ( pollInfo.revents & POLLNVAL ) {
- // Socket descriptor itself is weird
- // Log and warn at runtime, log and abort at devtime
- error() << "Socket descriptor detected as invalid"
- << " (idle " << idleTimeSecs << " secs,"
- << " remote host " << remoteString() << ")" << endl;
- dassert( false );
- }
- else {
- // Don't know what poll is saying here
+ if (recvd < 0) {
+ // An error occurred during recv, warn and log errno
+ warning() << "Socket recv() failed during connectivity check"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")"
+ << causedBy(errnoWithDescription()) << endl;
+ } else if (recvd > 0) {
+ // We got nonzero data from this socket, very weird?
// Log and warn at runtime, log and abort at devtime
- error() << "Socket had unknown event (" << static_cast<int>(pollInfo.revents) << ")"
+ // TODO: Dump the data to the log somehow?
+ error() << "Socket found pending " << recvd
+ << " bytes of data during connectivity check"
<< " (idle " << idleTimeSecs << " secs,"
<< " remote host " << remoteString() << ")" << endl;
- dassert( false );
- }
-
- return false;
- }
+ DEV {
+ std::string hex = hexdump(testBuf, recvd);
+ error() << "Hex dump of stale log data: " << hex << endl;
+ }
+ dassert(false);
+ } else {
+ // recvd == 0, socket closed remotely, just return false
+ LOG(0) << "Socket closed remotely, no longer connected"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ }
+ } else if (pollInfo.revents & POLLHUP) {
+ // A hangup has occurred on this socket
+ LOG(0) << "Socket hangup detected, no longer connected"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ } else if (pollInfo.revents & POLLERR) {
+ // An error has occurred on this socket
+ LOG(0) << "Socket error detected, no longer connected"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ } else if (pollInfo.revents & POLLNVAL) {
+ // Socket descriptor itself is weird
+ // Log and warn at runtime, log and abort at devtime
+ error() << "Socket descriptor detected as invalid"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ dassert(false);
+ } else {
+ // Don't know what poll is saying here
+ // Log and warn at runtime, log and abort at devtime
+ error() << "Socket had unknown event (" << static_cast<int>(pollInfo.revents) << ")"
+ << " (idle " << idleTimeSecs << " secs,"
+ << " remote host " << remoteString() << ")" << endl;
+ dassert(false);
+ }
+
+ return false;
+}
#if defined(_WIN32)
- struct WinsockInit {
- WinsockInit() {
- WSADATA d;
- if ( WSAStartup(MAKEWORD(2,2), &d) != 0 ) {
- log() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
- quickExit(EXIT_NTSERVICE_ERROR);
- }
+struct WinsockInit {
+ WinsockInit() {
+ WSADATA d;
+ if (WSAStartup(MAKEWORD(2, 2), &d) != 0) {
+ log() << "ERROR: wsastartup failed " << errnoWithDescription() << endl;
+ quickExit(EXIT_NTSERVICE_ERROR);
}
- } winsock_init;
+ }
+} winsock_init;
#endif
-} // namespace mongo
+} // namespace mongo