diff options
Diffstat (limited to 'src/mongo/util/net/sock.h')
-rw-r--r-- | src/mongo/util/net/sock.h | 476 |
1 files changed, 268 insertions, 208 deletions
diff --git a/src/mongo/util/net/sock.h b/src/mongo/util/net/sock.h index a2aec13c388..03d751c70fb 100644 --- a/src/mongo/util/net/sock.h +++ b/src/mongo/util/net/sock.h @@ -39,10 +39,10 @@ #include <errno.h> #ifdef __OpenBSD__ -# include <sys/uio.h> +#include <sys/uio.h> #endif -#endif // not _WIN32 +#endif // not _WIN32 #include <string> #include <utility> @@ -58,266 +58,326 @@ namespace mongo { #ifdef MONGO_CONFIG_SSL - class SSLManagerInterface; - class SSLConnection; +class SSLManagerInterface; +class SSLConnection; #endif - extern const int portSendFlags; - extern const int portRecvFlags; +extern const int portSendFlags; +extern const int portRecvFlags; - const int SOCK_FAMILY_UNKNOWN_ERROR=13078; +const int SOCK_FAMILY_UNKNOWN_ERROR = 13078; - void disableNagle(int sock); +void disableNagle(int sock); #if defined(_WIN32) - typedef short sa_family_t; - typedef int socklen_t; +typedef short sa_family_t; +typedef int socklen_t; - // This won't actually be used on windows - struct sockaddr_un { - short sun_family; - char sun_path[108]; // length from unix header - }; +// This won't actually be used on windows +struct sockaddr_un { + short sun_family; + char sun_path[108]; // length from unix header +}; -#else // _WIN32 +#else // _WIN32 - inline void closesocket(int s) { close(s); } - const int INVALID_SOCKET = -1; - typedef int SOCKET; +inline void closesocket(int s) { + close(s); +} +const int INVALID_SOCKET = -1; +typedef int SOCKET; -#endif // _WIN32 +#endif // _WIN32 - std::string makeUnixSockPath(int port); +std::string makeUnixSockPath(int port); - // 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. - std::string hostbyname(const char *hostname); +// 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. +std::string hostbyname(const char* hostname); - void enableIPv6(bool state=true); - bool IPv6Enabled(); - void setSockTimeouts(int sock, double secs); +void enableIPv6(bool state = true); +bool IPv6Enabled(); +void setSockTimeouts(int sock, double secs); + +/** + * wrapped around os representation of network address + */ +struct SockAddr { + SockAddr(); + explicit SockAddr(int sourcePort); /* listener side */ + SockAddr( + const char* ip, + int port); /* EndPoint (remote) side, or if you want to specify which interface locally */ + + template <typename T> + T& as() { + return *(T*)(&sa); + } + template <typename T> + const T& as() const { + return *(const T*)(&sa); + } + + std::string toString(bool includePort = true) const; + + bool isValid() const { + return _isValid; + } /** - * wrapped around os representation of network address + * @return one of AF_INET, AF_INET6, or AF_UNIX */ - struct SockAddr { - SockAddr(); - explicit SockAddr(int sourcePort); /* listener side */ - SockAddr(const char *ip, int port); /* EndPoint (remote) side, or if you want to specify which interface locally */ + sa_family_t getType() const; - template <typename T> T& as() { return *(T*)(&sa); } - template <typename T> const T& as() const { return *(const T*)(&sa); } - - std::string toString(bool includePort=true) const; + unsigned getPort() const; - bool isValid() const { return _isValid; } + std::string getAddr() const; - /** - * @return one of AF_INET, AF_INET6, or AF_UNIX - */ - sa_family_t getType() const; + bool isLocalHost() const; - unsigned getPort() const; + bool operator==(const SockAddr& r) const; - std::string getAddr() const; + bool operator!=(const SockAddr& r) const; - bool isLocalHost() const; + bool operator<(const SockAddr& r) const; - bool operator==(const SockAddr& r) const; + const sockaddr* raw() const { + return (sockaddr*)&sa; + } + sockaddr* raw() { + return (sockaddr*)&sa; + } - bool operator!=(const SockAddr& r) const; + socklen_t addressSize; - bool operator<(const SockAddr& r) const; +private: + struct sockaddr_storage sa; + bool _isValid; +}; - const sockaddr* raw() const {return (sockaddr*)&sa;} - sockaddr* raw() {return (sockaddr*)&sa;} +/** this is not cache and does a syscall */ +std::string getHostName(); - socklen_t addressSize; - private: - struct sockaddr_storage sa; - bool _isValid; - }; +/** this is cached, so if changes during the process lifetime + * will be stale */ +std::string getHostNameCached(); - /** this is not cache and does a syscall */ - std::string getHostName(); - - /** this is cached, so if changes during the process lifetime - * will be stale */ - std::string getHostNameCached(); +std::string prettyHostName(); - std::string prettyHostName(); - - /** - * thrown by Socket and SockAddr - */ - class SocketException : public DBException { - public: - const enum Type { CLOSED , RECV_ERROR , SEND_ERROR, RECV_TIMEOUT, SEND_TIMEOUT, FAILED_STATE, CONNECT_ERROR } _type; - - SocketException( Type t , const std::string& server , int code = 9001 , const std::string& extra="" ) - : DBException( std::string("socket exception [") + _getStringType( t ) + "] for " + server, code ), - _type(t), - _server(server), - _extra(extra) - {} - - virtual ~SocketException() throw() {} - - bool shouldPrint() const { return _type != CLOSED; } - virtual std::string toString() const; - virtual const std::string* server() const { return &_server; } - private: - - // TODO: Allow exceptions better control over their messages - static std::string _getStringType( Type t ){ - switch (t) { - case CLOSED: return "CLOSED"; - case RECV_ERROR: return "RECV_ERROR"; - case SEND_ERROR: return "SEND_ERROR"; - case RECV_TIMEOUT: return "RECV_TIMEOUT"; - case SEND_TIMEOUT: return "SEND_TIMEOUT"; - case FAILED_STATE: return "FAILED_STATE"; - case CONNECT_ERROR: return "CONNECT_ERROR"; - default: return "UNKNOWN"; // should never happen - } +/** + * thrown by Socket and SockAddr + */ +class SocketException : public DBException { +public: + const enum Type { + CLOSED, + RECV_ERROR, + SEND_ERROR, + RECV_TIMEOUT, + SEND_TIMEOUT, + FAILED_STATE, + CONNECT_ERROR + } _type; + + SocketException(Type t, + const std::string& server, + int code = 9001, + const std::string& extra = "") + : DBException(std::string("socket exception [") + _getStringType(t) + "] for " + server, + code), + _type(t), + _server(server), + _extra(extra) {} + + virtual ~SocketException() throw() {} + + bool shouldPrint() const { + return _type != CLOSED; + } + virtual std::string toString() const; + virtual const std::string* server() const { + return &_server; + } + +private: + // TODO: Allow exceptions better control over their messages + static std::string _getStringType(Type t) { + switch (t) { + case CLOSED: + return "CLOSED"; + case RECV_ERROR: + return "RECV_ERROR"; + case SEND_ERROR: + return "SEND_ERROR"; + case RECV_TIMEOUT: + return "RECV_TIMEOUT"; + case SEND_TIMEOUT: + return "SEND_TIMEOUT"; + case FAILED_STATE: + return "FAILED_STATE"; + case CONNECT_ERROR: + return "CONNECT_ERROR"; + default: + return "UNKNOWN"; // should never happen } + } - std::string _server; - std::string _extra; - }; - - - /** - * thin wrapped around file descriptor and system calls - * todo: ssl - */ - class Socket { - MONGO_DISALLOW_COPYING(Socket); - public: - - static const int errorPollIntervalSecs; - - Socket(int sock, const SockAddr& farEnd); - - /** In some cases the timeout will actually be 2x this value - eg we do a partial send, - then the timeout fires, then we try to send again, then the timeout fires again with - no data sent, then we detect that the other side is down. - - Generally you don't want a timeout, you should be very prepared for errors if you set one. - */ - Socket(double so_timeout = 0, logger::LogSeverity logLevel = logger::LogSeverity::Log() ); + std::string _server; + std::string _extra; +}; - ~Socket(); - /** The correct way to initialize and connect to a socket is as follows: (1) construct the - * SockAddr, (2) check whether the SockAddr isValid(), (3) if the SockAddr is valid, a - * Socket may then try to connect to that SockAddr. It is critical to check the return - * value of connect as a false return indicates that there was an error, and the Socket - * failed to connect to the given SockAddr. This failure may be due to ConnectBG returning - * an error, or due to a timeout on connection, or due to the system socket deciding the - * socket is invalid. - */ - bool connect(SockAddr& farEnd); - - void close(); - void send( const char * data , int len, const char *context ); - void send( const std::vector< std::pair< char *, int > > &data, const char *context ); - - // recv len or throw SocketException - void recv( char * data , int len ); - int unsafe_recv( char *buf, int max ); - - logger::LogSeverity getLogLevel() const { return _logLevel; } - void setLogLevel( logger::LogSeverity ll ) { _logLevel = ll; } +/** + * thin wrapped around file descriptor and system calls + * todo: ssl + */ +class Socket { + MONGO_DISALLOW_COPYING(Socket); - SockAddr remoteAddr() const { return _remote; } - std::string remoteString() const { return _remote.toString(); } - unsigned remotePort() const { return _remote.getPort(); } +public: + static const int errorPollIntervalSecs; - SockAddr localAddr() const { return _local; } + Socket(int sock, const SockAddr& farEnd); - void clearCounters() { _bytesIn = 0; _bytesOut = 0; } - long long getBytesIn() const { return _bytesIn; } - long long getBytesOut() const { return _bytesOut; } - int rawFD() const { return _fd; } + /** In some cases the timeout will actually be 2x this value - eg we do a partial send, + then the timeout fires, then we try to send again, then the timeout fires again with + no data sent, then we detect that the other side is down. - void setTimeout( double secs ); - bool isStillConnected(); + Generally you don't want a timeout, you should be very prepared for errors if you set one. + */ + Socket(double so_timeout = 0, logger::LogSeverity logLevel = logger::LogSeverity::Log()); - void setHandshakeReceived() { - _awaitingHandshake = false; - } + ~Socket(); - bool isAwaitingHandshake() { - return _awaitingHandshake; - } + /** The correct way to initialize and connect to a socket is as follows: (1) construct the + * SockAddr, (2) check whether the SockAddr isValid(), (3) if the SockAddr is valid, a + * Socket may then try to connect to that SockAddr. It is critical to check the return + * value of connect as a false return indicates that there was an error, and the Socket + * failed to connect to the given SockAddr. This failure may be due to ConnectBG returning + * an error, or due to a timeout on connection, or due to the system socket deciding the + * socket is invalid. + */ + bool connect(SockAddr& farEnd); + + void close(); + void send(const char* data, int len, const char* context); + void send(const std::vector<std::pair<char*, int>>& data, const char* context); + + // recv len or throw SocketException + void recv(char* data, int len); + int unsafe_recv(char* buf, int max); + + logger::LogSeverity getLogLevel() const { + return _logLevel; + } + void setLogLevel(logger::LogSeverity ll) { + _logLevel = ll; + } + + SockAddr remoteAddr() const { + return _remote; + } + std::string remoteString() const { + return _remote.toString(); + } + unsigned remotePort() const { + return _remote.getPort(); + } + + SockAddr localAddr() const { + return _local; + } + + void clearCounters() { + _bytesIn = 0; + _bytesOut = 0; + } + long long getBytesIn() const { + return _bytesIn; + } + long long getBytesOut() const { + return _bytesOut; + } + int rawFD() const { + return _fd; + } + + void setTimeout(double secs); + bool isStillConnected(); + + void setHandshakeReceived() { + _awaitingHandshake = false; + } + + bool isAwaitingHandshake() { + return _awaitingHandshake; + } #ifdef MONGO_CONFIG_SSL - /** secures inline - * ssl - Pointer to the global SSLManager. - * remoteHost - The hostname of the remote server. - */ - bool secure( SSLManagerInterface* ssl, const std::string& remoteHost); + /** secures inline + * ssl - Pointer to the global SSLManager. + * remoteHost - The hostname of the remote server. + */ + bool secure(SSLManagerInterface* ssl, const std::string& remoteHost); - void secureAccepted( SSLManagerInterface* ssl ); + void secureAccepted(SSLManagerInterface* ssl); #endif - - /** - * This function calls SSL_accept() if SSL-encrypted sockets - * are desired. SSL_accept() waits until the remote host calls - * SSL_connect(). The return value is the subject name of any - * client certificate provided during the handshake. - * - * @firstBytes is the first bytes received on the socket used - * to detect the connection SSL, @len is the number of bytes - * - * This function may throw SocketException. - */ - std::string doSSLHandshake(const char* firstBytes = NULL, int len = 0); - - /** - * @return the time when the socket was opened. - */ - uint64_t getSockCreationMicroSec() const { - return _fdCreationMicroSec; - } - void handleRecvError(int ret, int len); - MONGO_COMPILER_NORETURN void handleSendError(int ret, const char* context); + /** + * This function calls SSL_accept() if SSL-encrypted sockets + * are desired. SSL_accept() waits until the remote host calls + * SSL_connect(). The return value is the subject name of any + * client certificate provided during the handshake. + * + * @firstBytes is the first bytes received on the socket used + * to detect the connection SSL, @len is the number of bytes + * + * This function may throw SocketException. + */ + std::string doSSLHandshake(const char* firstBytes = NULL, int len = 0); + + /** + * @return the time when the socket was opened. + */ + uint64_t getSockCreationMicroSec() const { + return _fdCreationMicroSec; + } + + void handleRecvError(int ret, int len); + MONGO_COMPILER_NORETURN void handleSendError(int ret, const char* context); - private: - void _init(); +private: + void _init(); - /** sends dumbly, just each buffer at a time */ - void _send( const std::vector< std::pair< char *, int > > &data, const char *context ); + /** sends dumbly, just each buffer at a time */ + void _send(const std::vector<std::pair<char*, int>>& data, const char* context); - /** raw send, same semantics as ::send with an additional context parameter */ - int _send( const char * data , int len , const char * context ); + /** raw send, same semantics as ::send with an additional context parameter */ + int _send(const char* data, int len, const char* context); - /** raw recv, same semantics as ::recv */ - int _recv( char * buf , int max ); + /** raw recv, same semantics as ::recv */ + int _recv(char* buf, int max); - int _fd; - uint64_t _fdCreationMicroSec; - SockAddr _local; - SockAddr _remote; - double _timeout; + int _fd; + uint64_t _fdCreationMicroSec; + SockAddr _local; + SockAddr _remote; + double _timeout; - long long _bytesIn; - long long _bytesOut; - time_t _lastValidityCheckAtSecs; + long long _bytesIn; + long long _bytesOut; + time_t _lastValidityCheckAtSecs; #ifdef MONGO_CONFIG_SSL - std::unique_ptr<SSLConnection> _sslConnection; - SSLManagerInterface* _sslManager; + std::unique_ptr<SSLConnection> _sslConnection; + SSLManagerInterface* _sslManager; #endif - logger::LogSeverity _logLevel; // passed to log() when logging errors - - /** true until the first packet has been received or an outgoing connect has been made */ - bool _awaitingHandshake; + logger::LogSeverity _logLevel; // passed to log() when logging errors - }; + /** true until the first packet has been received or an outgoing connect has been made */ + bool _awaitingHandshake; +}; -} // namespace mongo +} // namespace mongo |