diff options
Diffstat (limited to 'util/net/sock.h')
| -rw-r--r-- | util/net/sock.h | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/util/net/sock.h b/util/net/sock.h new file mode 100644 index 0000000..1cd5133 --- /dev/null +++ b/util/net/sock.h @@ -0,0 +1,256 @@ +// @file sock.h + +/* Copyright 2009 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "../../pch.h" + +#include <stdio.h> +#include <sstream> +#include "../goodies.h" +#include "../../db/cmdline.h" +#include "../mongoutils/str.h" + +#ifndef _WIN32 + +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <errno.h> + +#ifdef __openbsd__ +# include <sys/uio.h> +#endif + +#endif // _WIN32 + +#ifdef MONGO_SSL +#include <openssl/ssl.h> +#endif + +namespace mongo { + + const int SOCK_FAMILY_UNKNOWN_ERROR=13078; + + void disableNagle(int sock); + +#if defined(_WIN32) + + 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 + }; + +#else // _WIN32 + + inline void closesocket(int s) { close(s); } + const int INVALID_SOCKET = -1; + typedef int SOCKET; + +#endif // _WIN32 + + inline string makeUnixSockPath(int port) { + return mongoutils::str::stream() << cmdLine.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); + + void enableIPv6(bool state=true); + bool IPv6Enabled(); + void setSockTimeouts(int sock, double secs); + + /** + * wrapped around os representation of network address + */ + struct SockAddr { + SockAddr() { + addressSize = sizeof(sa); + memset(&sa, 0, sizeof(sa)); + sa.ss_family = AF_UNSPEC; + } + 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); } + + string toString(bool includePort=true) const; + + /** + * @return one of AF_INET, AF_INET6, or AF_UNIX + */ + sa_family_t getType() const; + + unsigned getPort() const; + + string getAddr() const; + + bool isLocalHost() const; + + bool operator==(const SockAddr& r) 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;} + + socklen_t addressSize; + private: + struct sockaddr_storage sa; + }; + + extern SockAddr unknownAddress; // ( "0.0.0.0", 0 ) + + /** this is not cache and does a syscall */ + string getHostName(); + + /** this is cached, so if changes during the process lifetime + * will be stale */ + string getHostNameCached(); + + /** + * 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 , string server , int code = 9001 , string extra="" ) + : DBException( "socket exception" , code ) , _type(t) , _server(server), _extra(extra){ } + virtual ~SocketException() throw() {} + + bool shouldPrint() const { return _type != CLOSED; } + virtual string toString() const; + + private: + string _server; + string _extra; + }; + +#ifdef MONGO_SSL + class SSLManager : boost::noncopyable { + public: + SSLManager( bool client ); + + void setupPEM( const string& keyFile , const string& password ); + void setupPubPriv( const string& privateKeyFile , const string& publicKeyFile ); + + /** + * creates an SSL context to be used for this file descriptor + * caller should delete + */ + SSL * secure( int fd ); + + static int password_cb( char *buf,int num, int rwflag,void *userdata ); + + private: + bool _client; + SSL_CTX* _context; + string _password; + }; +#endif + + /** + * thin wrapped around file descriptor and system calls + * todo: ssl + */ + class Socket { + public: + 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, int logLevel = 0 ); + + bool connect(SockAddr& farEnd); + void close(); + + void send( const char * data , int len, const char *context ); + void send( const vector< 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 ); + + int getLogLevel() const { return _logLevel; } + void setLogLevel( int ll ) { _logLevel = ll; } + + SockAddr remoteAddr() const { return _remote; } + string remoteString() const { return _remote.toString(); } + unsigned remotePort() const { return _remote.getPort(); } + + void clearCounters() { _bytesIn = 0; _bytesOut = 0; } + long long getBytesIn() const { return _bytesIn; } + long long getBytesOut() const { return _bytesOut; } + + void setTimeout( double secs ); + +#ifdef MONGO_SSL + /** secures inline */ + void secure( SSLManager * ssl ); + + void secureAccepted( SSLManager * ssl ); +#endif + + /** + * call this after a fork for server sockets + */ + void postFork(); + + private: + void _init(); + /** raw send, same semantics as ::send */ + int _send( const char * data , int len ); + + /** sends dumbly, just each buffer at a time */ + void _send( const vector< pair< char *, int > > &data, const char *context ); + + /** raw recv, same semantics as ::recv */ + int _recv( char * buf , int max ); + + int _fd; + SockAddr _remote; + double _timeout; + + long long _bytesIn; + long long _bytesOut; + +#ifdef MONGO_SSL + shared_ptr<SSL> _ssl; + SSLManager * _sslAccepted; +#endif + + protected: + int _logLevel; // passed to log() when logging errors + + }; + + +} // namespace mongo |
