2008-06-06 15:43:15 +02:00
|
|
|
// sock.h
|
|
|
|
|
2008-07-20 23:37:33 +02:00
|
|
|
/**
|
|
|
|
* Copyright (C) 2008 10gen Inc.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-07-20 23:37:33 +02:00
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License, version 3,
|
|
|
|
* as published by the Free Software Foundation.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-07-20 23:37:33 +02:00
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
2008-12-29 02:28:49 +01:00
|
|
|
*
|
2008-07-20 23:37:33 +02:00
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#pragma once
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2009-01-21 21:50:49 +01:00
|
|
|
#include "../stdafx.h"
|
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <sstream>
|
|
|
|
#include "goodies.h"
|
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
namespace mongo {
|
|
|
|
|
2008-06-06 15:43:15 +02:00
|
|
|
#if defined(_WIN32)
|
2008-12-16 23:48:48 +01:00
|
|
|
//#include <winsock2.h>
|
|
|
|
//#include <ws2tcpip.h>
|
2009-01-15 16:17:11 +01:00
|
|
|
typedef int socklen_t;
|
|
|
|
inline int getLastError() {
|
|
|
|
return WSAGetLastError();
|
|
|
|
}
|
|
|
|
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;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
|
|
|
inline void prebindOptions( int sock ) {
|
|
|
|
}
|
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>
|
|
|
|
#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;
|
2008-07-28 00:36:47 +02:00
|
|
|
//#define h_errno errno
|
2009-01-15 16:17:11 +01:00
|
|
|
inline int getLastError() {
|
|
|
|
return errno;
|
|
|
|
}
|
|
|
|
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)) )
|
|
|
|
log() << "ERROR: disableNagle failed" << endl;
|
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
|
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline void setSockReceiveTimeout(int sock, int secs) {
|
2008-10-24 23:51:28 +02:00
|
|
|
// todo - finish - works?
|
2009-01-15 16:17:11 +01:00
|
|
|
struct timeval tv;
|
|
|
|
tv.tv_sec = 0;//secs;
|
|
|
|
tv.tv_usec = 1000;
|
|
|
|
int rc = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv));
|
|
|
|
if ( rc ) {
|
2009-01-15 17:26:38 +01:00
|
|
|
out() << "ERROR: setsockopt RCVTIMEO failed rc:" << rc << " errno:" << getLastError() << " secs:" << secs << " sock:" << sock << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
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
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
struct SockAddr {
|
|
|
|
SockAddr() {
|
|
|
|
addressSize = sizeof(sockaddr_in);
|
|
|
|
memset(&sa, 0, sizeof(sa));
|
|
|
|
}
|
|
|
|
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
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
struct sockaddr_in sa;
|
|
|
|
socklen_t addressSize;
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
bool isLocalHost() const {
|
2008-06-06 15:43:15 +02:00
|
|
|
#if defined(_WIN32)
|
2009-01-15 16:17:11 +01:00
|
|
|
return sa.sin_addr.S_un.S_addr == 0x100007f;
|
2008-06-06 15:43:15 +02:00
|
|
|
#else
|
2009-01-15 16:17:11 +01:00
|
|
|
return sa.sin_addr.s_addr == 0x100007f;
|
2008-06-06 15:43:15 +02:00
|
|
|
#endif
|
2009-01-15 16:17:11 +01:00
|
|
|
}
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
string toString() {
|
|
|
|
stringstream out;
|
|
|
|
out << inet_ntoa(sa.sin_addr) << ':'
|
|
|
|
<< sa.sin_port;
|
|
|
|
return out.str();
|
|
|
|
}
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
unsigned getPort() {
|
|
|
|
return sa.sin_port;
|
|
|
|
}
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
bool operator==(const SockAddr& r) const {
|
|
|
|
return sa.sin_addr.s_addr == r.sa.sin_addr.s_addr &&
|
|
|
|
sa.sin_port == r.sa.sin_port;
|
|
|
|
}
|
|
|
|
bool operator!=(const SockAddr& r) const {
|
|
|
|
return !(*this == r);
|
|
|
|
}
|
|
|
|
bool operator<(const SockAddr& r) const {
|
|
|
|
if ( sa.sin_port >= r.sa.sin_port )
|
|
|
|
return false;
|
|
|
|
return sa.sin_addr.s_addr < r.sa.sin_addr.s_addr;
|
|
|
|
}
|
|
|
|
};
|
2008-06-06 15:43:15 +02:00
|
|
|
|
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
|
|
|
class UDPConnection {
|
|
|
|
public:
|
|
|
|
UDPConnection() {
|
2008-12-29 02:28:49 +01:00
|
|
|
sock = 0;
|
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
~UDPConnection() {
|
|
|
|
if ( sock ) {
|
|
|
|
closesocket(sock);
|
|
|
|
sock = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bool init(const SockAddr& myAddr);
|
|
|
|
int recvfrom(char *buf, int len, SockAddr& sender);
|
|
|
|
int sendto(char *buf, int len, const SockAddr& EndPoint);
|
|
|
|
int mtu(const SockAddr& sa) {
|
|
|
|
return sa.isLocalHost() ? 16384 : 1480;
|
|
|
|
}
|
2008-12-29 02:28:49 +01:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
SOCKET sock;
|
|
|
|
};
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline int UDPConnection::recvfrom(char *buf, int len, SockAddr& sender) {
|
|
|
|
return ::recvfrom(sock, buf, len, 0, (sockaddr *) &sender.sa, &sender.addressSize);
|
|
|
|
}
|
2008-06-06 15:43:15 +02:00
|
|
|
|
2009-01-15 16:17:11 +01:00
|
|
|
inline int UDPConnection::sendto(char *buf, int len, const SockAddr& EndPoint) {
|
|
|
|
if ( 0 && rand() < (RAND_MAX>>4) ) {
|
2009-01-15 17:26:38 +01:00
|
|
|
out() << " NOTSENT ";
|
|
|
|
// out() << curTimeMillis() << " .TEST: NOT SENDING PACKET" << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return ::sendto(sock, buf, len, 0, (sockaddr *) &EndPoint.sa, EndPoint.addressSize);
|
2008-12-29 02:28:49 +01:00
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
|
|
|
|
inline bool UDPConnection::init(const SockAddr& myAddr) {
|
|
|
|
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
|
|
if ( sock == INVALID_SOCKET ) {
|
2009-01-15 17:26:38 +01:00
|
|
|
out() << "invalid socket? " << errno << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
return false;
|
|
|
|
}
|
2009-01-15 17:26:38 +01:00
|
|
|
//out() << sizeof(sockaddr_in) << ' ' << myAddr.addressSize << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
if ( ::bind(sock, (sockaddr *) &myAddr.sa, myAddr.addressSize) != 0 ) {
|
2009-01-15 17:26:38 +01:00
|
|
|
out() << "udp init failed" << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
closesocket(sock);
|
|
|
|
sock = 0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
socklen_t optLen;
|
|
|
|
int rcvbuf;
|
|
|
|
if (getsockopt(sock,
|
|
|
|
SOL_SOCKET,
|
|
|
|
SO_RCVBUF,
|
|
|
|
(char*)&rcvbuf,
|
|
|
|
&optLen) != -1)
|
2009-01-15 17:26:38 +01:00
|
|
|
out() << "SO_RCVBUF:" << rcvbuf << endl;
|
2009-01-15 16:17:11 +01:00
|
|
|
return true;
|
2008-12-29 02:28:49 +01:00
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
|
|
|
|
inline SockAddr::SockAddr(int sourcePort) {
|
|
|
|
memset(sa.sin_zero, 0, sizeof(sa.sin_zero));
|
|
|
|
sa.sin_family = AF_INET;
|
|
|
|
sa.sin_port = htons(sourcePort);
|
|
|
|
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
|
addressSize = sizeof(sa);
|
|
|
|
}
|
|
|
|
|
|
|
|
inline SockAddr::SockAddr(const char *ip, int port) {
|
|
|
|
memset(sa.sin_zero, 0, sizeof(sa.sin_zero));
|
|
|
|
sa.sin_family = AF_INET;
|
|
|
|
sa.sin_port = htons(port);
|
|
|
|
sa.sin_addr.s_addr = inet_addr(ip);
|
|
|
|
addressSize = sizeof(sa);
|
2008-12-29 02:28:49 +01:00
|
|
|
}
|
2009-01-15 16:17:11 +01:00
|
|
|
|
|
|
|
inline string getHostName() {
|
|
|
|
char buf[256];
|
|
|
|
int ec = gethostname(buf, 127);
|
|
|
|
if ( ec || *buf == 0 ) {
|
|
|
|
log() << "can't get this server's hostname errno:" << ec << endl;
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return buf;
|
2008-12-04 20:33:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-01-14 23:09:51 +01:00
|
|
|
|
|
|
|
} // namespace mongo
|