2008-06-06 15:43:15 +02:00
|
|
|
// sock.h
|
|
|
|
|
2009-10-27 20:58:27 +01:00
|
|
|
/* 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.
|
|
|
|
*/
|
2008-07-20 23:37:33 +02:00
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#pragma once
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2010-04-27 21:27:52 +02:00
|
|
|
#include "../pch.h"
|
2009-01-21 21:50:49 +01:00
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sstream>
|
|
|
|
#include "goodies.h"
|
2010-04-02 23:51:10 +02:00
|
|
|
#include "../db/jsobj.h"
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2010-04-02 23:51:10 +02:00
|
|
|
#define SOCK_FAMILY_UNKNOWN_ERROR 13078
|
2009-07-27 19:50:25 +02:00
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
namespace mongo {
|
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#if defined(_WIN32)
|
2009-07-27 19:50:25 +02:00
|
|
|
|
2010-04-03 01:37:43 +02:00
|
|
|
typedef short sa_family_t;
|
2009-01-15 16:17:11 +01:00
|
|
|
typedef int socklen_t;
|
|
|
|
inline int getLastError() {
|
|
|
|
return WSAGetLastError();
|
|
|
|
}
|
2010-04-08 06:19:48 +02:00
|
|
|
inline const char* gai_strerror(int code) {
|
|
|
|
return ::gai_strerrorA(code);
|
2010-04-08 06:17:12 +02:00
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
inline void disableNagle(int sock) {
|
|
|
|
int x = 1;
|
|
|
|
if ( setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (char *) &x, sizeof(x)) )
|
2009-01-15 17:26:38 +01:00
|
|
|
out() << "ERROR: disableNagle failed" << endl;
|
2010-05-17 03:55:48 +02:00
|
|
|
if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &x, sizeof(x)) )
|
|
|
|
out() << "ERROR: SO_KEEPALIVE failed" << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
inline void prebindOptions( int sock ) {
|
|
|
|
}
|
2010-04-02 23:51:10 +02:00
|
|
|
|
|
|
|
// This won't actually be used on windows
|
|
|
|
struct sockaddr_un {
|
|
|
|
short sun_family;
|
|
|
|
char sun_path[108]; // length from unix header
|
|
|
|
};
|
2010-04-03 02:04:56 +02:00
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#else
|
2009-01-14 23:09:51 +01:00
|
|
|
|
|
|
|
} // namespace mongo
|
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
2010-04-02 23:51:10 +02:00
|
|
|
#include <sys/un.h>
|
2008-06-06 15:43:15 +02:00
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <errno.h>
|
2008-07-28 00:36:47 +02:00
|
|
|
#include <netdb.h>
|
2009-01-14 23:09:51 +01:00
|
|
|
|
|
|
|
namespace mongo {
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline void closesocket(int s) {
|
|
|
|
close(s);
|
|
|
|
}
|
|
|
|
const int INVALID_SOCKET = -1;
|
|
|
|
typedef int SOCKET;
|
2009-12-21 16:06:14 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline void disableNagle(int sock) {
|
|
|
|
int x = 1;
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2008-12-29 02:28:49 +01:00
|
|
|
#ifdef SOL_TCP
|
2009-01-15 16:17:11 +01:00
|
|
|
int level = SOL_TCP;
|
2008-12-29 02:28:49 +01:00
|
|
|
#else
|
2009-01-15 16:17:11 +01:00
|
|
|
int level = SOL_SOCKET;
|
2008-12-29 02:28:49 +01:00
|
|
|
#endif
|
2008-02-29 19:09:19 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
if ( setsockopt(sock, level, TCP_NODELAY, (char *) &x, sizeof(x)) )
|
2010-05-17 03:55:48 +02:00
|
|
|
log() << "ERROR: disableNagle failed: " << errnoWithDescription() << endl;
|
|
|
|
|
|
|
|
#ifdef SO_KEEPALIVE
|
|
|
|
if ( setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, (char *) &x, sizeof(x)) )
|
|
|
|
log() << "ERROR: SO_KEEPALIVE failed: " << errnoWithDescription() << endl;
|
|
|
|
#endif
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
inline void prebindOptions( int sock ) {
|
|
|
|
DEV log() << "doing prebind option" << endl;
|
|
|
|
int x = 1;
|
|
|
|
if ( setsockopt( sock , SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)) < 0 )
|
2009-01-15 17:26:38 +01:00
|
|
|
out() << "Failed to set socket opt, SO_REUSEADDR" << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2008-06-06 15:43:15 +02:00
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2010-04-06 00:12:18 +02:00
|
|
|
inline string makeUnixSockPath(int port){
|
|
|
|
return "/tmp/mongodb-" + BSONObjBuilder::numStr(port) + ".sock";
|
|
|
|
}
|
|
|
|
|
2010-04-08 21:14:20 +02:00
|
|
|
inline void setSockTimeouts(int sock, int secs) {
|
2009-01-15 16:17:11 +01:00
|
|
|
struct timeval tv;
|
2010-04-08 21:14:20 +02:00
|
|
|
tv.tv_sec = secs;
|
|
|
|
tv.tv_usec = 0;
|
|
|
|
massert( 13083, "unable to set SO_RCVTIMEO",
|
2010-04-08 22:47:13 +02:00
|
|
|
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv) ) == 0 );
|
2010-04-08 21:14:20 +02:00
|
|
|
massert( 13084, "unable to set SO_SNDTIMEO",
|
2010-04-08 22:47:13 +02:00
|
|
|
setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char *) &tv, sizeof(tv) ) == 0 );
|
2008-10-24 23:51:28 +02:00
|
|
|
}
|
|
|
|
|
2009-01-21 21:32:58 +01:00
|
|
|
// 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.
|
2009-01-15 16:17:11 +01:00
|
|
|
string hostbyname(const char *hostname);
|
2008-07-28 00:36:47 +02:00
|
|
|
|
2010-04-08 21:14:38 +02:00
|
|
|
void enableIPv6(bool state=true);
|
|
|
|
bool IPv6Enabled();
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
struct SockAddr {
|
|
|
|
SockAddr() {
|
2010-04-03 03:26:57 +02:00
|
|
|
addressSize = sizeof(sa);
|
2009-01-15 16:17:11 +01:00
|
|
|
memset(&sa, 0, sizeof(sa));
|
2010-04-03 03:26:57 +02:00
|
|
|
sa.ss_family = AF_UNSPEC;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
SockAddr(int sourcePort); /* listener side */
|
|
|
|
SockAddr(const char *ip, int port); /* EndPoint (remote) side, or if you want to specify which interface locally */
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2010-04-01 23:31:05 +02:00
|
|
|
template <typename T>
|
|
|
|
T& as() { return *(T*)(&sa); }
|
|
|
|
template <typename T>
|
|
|
|
const T& as() const { return *(const T*)(&sa); }
|
|
|
|
|
2010-04-01 23:19:46 +02:00
|
|
|
string toString(bool includePort=true) const{
|
2010-04-02 23:51:10 +02:00
|
|
|
string out = getAddr();
|
2010-04-03 03:26:57 +02:00
|
|
|
if (includePort && getType() != AF_UNIX && getType() != AF_UNSPEC)
|
2010-04-02 23:51:10 +02:00
|
|
|
out += ':' + BSONObjBuilder::numStr(getPort());
|
|
|
|
return out;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2009-11-24 19:38:57 +01:00
|
|
|
operator string() const{
|
|
|
|
return toString();
|
|
|
|
}
|
|
|
|
|
2010-04-02 23:51:10 +02:00
|
|
|
// returns one of AF_INET, AF_INET6, or AF_UNIX
|
|
|
|
sa_family_t getType() const {
|
|
|
|
return sa.ss_family;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned getPort() const {
|
|
|
|
switch (getType()){
|
2010-04-05 21:44:10 +02:00
|
|
|
case AF_INET: return ntohs(as<sockaddr_in>().sin_port);
|
|
|
|
case AF_INET6: return ntohs(as<sockaddr_in6>().sin6_port);
|
2010-04-02 23:51:10 +02:00
|
|
|
case AF_UNIX: return 0;
|
2010-04-03 03:26:57 +02:00
|
|
|
case AF_UNSPEC: return 0;
|
2010-04-02 23:51:10 +02:00
|
|
|
default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
string getAddr() const {
|
|
|
|
switch (getType()){
|
2010-04-08 05:02:18 +02:00
|
|
|
case AF_INET:
|
|
|
|
case AF_INET6: {
|
|
|
|
const int buflen=128;
|
|
|
|
char buffer[buflen];
|
|
|
|
int ret = getnameinfo(raw(), addressSize, buffer, buflen, NULL, 0, NI_NUMERICHOST);
|
|
|
|
massert(13082, gai_strerror(ret), ret == 0);
|
|
|
|
return buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
case AF_UNIX: return (addressSize > 2 ? as<sockaddr_un>().sun_path : "anonymous unix socket");
|
2010-04-03 03:26:57 +02:00
|
|
|
case AF_UNSPEC: return "(NONE)";
|
2010-04-02 23:51:10 +02:00
|
|
|
default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false); return "";
|
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2010-04-05 15:51:03 +02:00
|
|
|
bool isLocalHost() const;
|
2009-05-13 18:28:59 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
bool operator==(const SockAddr& r) const {
|
2010-04-02 23:51:10 +02:00
|
|
|
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, sizeof(in6_addr)) == 0;
|
|
|
|
case AF_UNIX: return strcmp(as<sockaddr_un>().sun_path, r.as<sockaddr_un>().sun_path) == 0;
|
2010-04-03 03:26:57 +02:00
|
|
|
case AF_UNSPEC: return true; // assume all unspecified addresses are the same
|
2010-04-02 23:51:10 +02:00
|
|
|
default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
|
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
bool operator!=(const SockAddr& r) const {
|
|
|
|
return !(*this == r);
|
|
|
|
}
|
|
|
|
bool operator<(const SockAddr& r) const {
|
2010-04-02 23:51:10 +02:00
|
|
|
if (getType() < r.getType())
|
|
|
|
return true;
|
|
|
|
else if (getType() > r.getType())
|
2009-01-15 16:17:11 +01:00
|
|
|
return false;
|
2010-04-02 23:51:10 +02:00
|
|
|
|
|
|
|
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, sizeof(in6_addr)) < 0;
|
|
|
|
case AF_UNIX: return strcmp(as<sockaddr_un>().sun_path, r.as<sockaddr_un>().sun_path) < 0;
|
2010-04-03 03:26:57 +02:00
|
|
|
case AF_UNSPEC: return false;
|
2010-04-02 23:51:10 +02:00
|
|
|
default: massert(SOCK_FAMILY_UNKNOWN_ERROR, "unsupported address family", false);
|
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2010-04-02 18:50:18 +02:00
|
|
|
|
|
|
|
const sockaddr* raw() const {return (sockaddr*)&sa;}
|
|
|
|
sockaddr* raw() {return (sockaddr*)&sa;}
|
|
|
|
|
|
|
|
socklen_t addressSize;
|
|
|
|
private:
|
|
|
|
struct sockaddr_storage sa;
|
2009-01-15 16:17:11 +01:00
|
|
|
};
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2010-04-08 20:20:52 +02:00
|
|
|
extern SockAddr unknownAddress; // ( "0.0.0.0", 0 )
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
const int MaxMTU = 16384;
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline string getHostName() {
|
|
|
|
char buf[256];
|
|
|
|
int ec = gethostname(buf, 127);
|
|
|
|
if ( ec || *buf == 0 ) {
|
2010-04-24 20:03:14 +02:00
|
|
|
log() << "can't get this server's hostname " << errnoWithDescription() << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return buf;
|
2008-12-04 20:33:18 +01:00
|
|
|
}
|
|
|
|
|
2010-01-09 02:58:12 +01:00
|
|
|
class ListeningSockets {
|
|
|
|
public:
|
|
|
|
ListeningSockets() : _sockets( new set<int>() ){
|
|
|
|
}
|
|
|
|
|
|
|
|
void add( int sock ){
|
2010-03-15 17:42:01 +01:00
|
|
|
scoped_lock lk( _mutex );
|
2010-01-09 02:58:12 +01:00
|
|
|
_sockets->insert( sock );
|
|
|
|
}
|
|
|
|
void remove( int sock ){
|
2010-03-15 17:42:01 +01:00
|
|
|
scoped_lock lk( _mutex );
|
2010-01-09 02:58:12 +01:00
|
|
|
_sockets->erase( sock );
|
|
|
|
}
|
|
|
|
|
|
|
|
void closeAll(){
|
|
|
|
set<int>* s;
|
|
|
|
{
|
2010-03-15 17:42:01 +01:00
|
|
|
scoped_lock lk( _mutex );
|
2010-01-09 02:58:12 +01:00
|
|
|
s = _sockets;
|
|
|
|
_sockets = new set<int>();
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( set<int>::iterator i=s->begin(); i!=s->end(); i++ ){
|
|
|
|
int sock = *i;
|
2010-02-23 17:06:26 +01:00
|
|
|
log() << "\t going to close listening socket: " << sock << endl;
|
2010-01-09 02:58:12 +01:00
|
|
|
closesocket( sock );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
static ListeningSockets* get();
|
2008-12-04 20:33:18 +01:00
|
|
|
|
2010-01-09 02:58:12 +01:00
|
|
|
private:
|
2010-03-15 17:42:01 +01:00
|
|
|
mongo::mutex _mutex;
|
2010-01-09 02:58:12 +01:00
|
|
|
set<int>* _sockets;
|
|
|
|
static ListeningSockets* _instance;
|
|
|
|
};
|
2009-01-14 23:09:51 +01:00
|
|
|
|
2010-04-23 20:19:55 +02:00
|
|
|
#undef SOCK_FAMILY_UNKNOWN_ERROR
|
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
} // namespace mongo
|