|
@@ -42,8 +42,13 @@
|
|
#include <sys/socket.h>
|
|
#include <sys/socket.h>
|
|
#include <arpa/inet.h>
|
|
#include <arpa/inet.h>
|
|
#include <signal.h>
|
|
#include <signal.h>
|
|
|
|
+#include <netinet/in.h>
|
|
|
|
+#include <netinet/tcp.h>
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+// Uncomment to turn off TCP Nagle
|
|
|
|
+//#define ZT_TCP_NODELAY
|
|
|
|
+
|
|
// Allow us to use the same value on Windows and *nix
|
|
// Allow us to use the same value on Windows and *nix
|
|
#ifndef INVALID_SOCKET
|
|
#ifndef INVALID_SOCKET
|
|
#define INVALID_SOCKET (-1)
|
|
#define INVALID_SOCKET (-1)
|
|
@@ -58,8 +63,8 @@
|
|
namespace ZeroTier {
|
|
namespace ZeroTier {
|
|
|
|
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
-// hack from StackOverflow, behaves a bit like pipe() on *nix systems
|
|
|
|
-static inline void __winpipe(SOCKET fds[2])
|
|
|
|
|
|
+// hack copied from StackOverflow, behaves a bit like pipe() on *nix systems
|
|
|
|
+static inline void winPipeHack(SOCKET fds[2])
|
|
{
|
|
{
|
|
struct sockaddr_in inaddr;
|
|
struct sockaddr_in inaddr;
|
|
struct sockaddr addr;
|
|
struct sockaddr addr;
|
|
@@ -98,10 +103,11 @@ SocketManager::SocketManager(
|
|
FD_ZERO(&_readfds);
|
|
FD_ZERO(&_readfds);
|
|
FD_ZERO(&_writefds);
|
|
FD_ZERO(&_writefds);
|
|
|
|
|
|
|
|
+ // Create a pipe or socket pair that can be used to interrupt select()
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
{
|
|
{
|
|
SOCKET tmps[2] = { INVALID_SOCKET,INVALID_SOCKET };
|
|
SOCKET tmps[2] = { INVALID_SOCKET,INVALID_SOCKET };
|
|
- __winpipe(tmps);
|
|
|
|
|
|
+ winPipeHack(tmps);
|
|
_whackSendPipe = tmps[0];
|
|
_whackSendPipe = tmps[0];
|
|
_whackReceivePipe = tmps[1];
|
|
_whackReceivePipe = tmps[1];
|
|
u_long iMode=1;
|
|
u_long iMode=1;
|
|
@@ -129,15 +135,12 @@ SocketManager::SocketManager(
|
|
_tcpV6ListenSocket = ::socket(AF_INET6,SOCK_STREAM,0);
|
|
_tcpV6ListenSocket = ::socket(AF_INET6,SOCK_STREAM,0);
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
if (_tcpV6ListenSocket == INVALID_SOCKET) {
|
|
if (_tcpV6ListenSocket == INVALID_SOCKET) {
|
|
- _closeSockets();
|
|
|
|
- throw std::runtime_error("unable to create IPv6 SOCK_STREAM socket");
|
|
|
|
- }
|
|
|
|
#else
|
|
#else
|
|
if (_tcpV6ListenSocket <= 0) {
|
|
if (_tcpV6ListenSocket <= 0) {
|
|
|
|
+#endif
|
|
_closeSockets();
|
|
_closeSockets();
|
|
throw std::runtime_error("unable to create IPv6 SOCK_STREAM socket");
|
|
throw std::runtime_error("unable to create IPv6 SOCK_STREAM socket");
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
|
|
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
{
|
|
{
|
|
@@ -178,15 +181,12 @@ SocketManager::SocketManager(
|
|
_tcpV4ListenSocket = ::socket(AF_INET,SOCK_STREAM,0);
|
|
_tcpV4ListenSocket = ::socket(AF_INET,SOCK_STREAM,0);
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
if (_tcpV4ListenSocket == INVALID_SOCKET) {
|
|
if (_tcpV4ListenSocket == INVALID_SOCKET) {
|
|
- _closeSockets();
|
|
|
|
- throw std::runtime_error("unable to create IPv4 SOCK_STREAM socket");
|
|
|
|
- }
|
|
|
|
#else
|
|
#else
|
|
if (_tcpV4ListenSocket <= 0) {
|
|
if (_tcpV4ListenSocket <= 0) {
|
|
|
|
+#endif
|
|
_closeSockets();
|
|
_closeSockets();
|
|
throw std::runtime_error("unable to create IPv4 SOCK_STREAM socket");
|
|
throw std::runtime_error("unable to create IPv4 SOCK_STREAM socket");
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
|
|
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
{
|
|
{
|
|
@@ -368,10 +368,10 @@ bool SocketManager::send(const InetAddress &to,bool tcp,const void *msg,unsigned
|
|
::closesocket(s);
|
|
::closesocket(s);
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
- {
|
|
|
|
- u_long iMode=1;
|
|
|
|
- ioctlsocket(s,FIONBIO,&iMode);
|
|
|
|
- }
|
|
|
|
|
|
+ { u_long iMode=1; ioctlsocket(s,FIONBIO,&iMode); }
|
|
|
|
+#ifdef ZT_TCP_NODELAY
|
|
|
|
+ { BOOL f = TRUE; setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
|
|
|
|
+#endif
|
|
#else
|
|
#else
|
|
int s = ::socket(to.isV4() ? AF_INET : AF_INET6,SOCK_STREAM,0);
|
|
int s = ::socket(to.isV4() ? AF_INET : AF_INET6,SOCK_STREAM,0);
|
|
if (s <= 0)
|
|
if (s <= 0)
|
|
@@ -381,6 +381,9 @@ bool SocketManager::send(const InetAddress &to,bool tcp,const void *msg,unsigned
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
fcntl(s,F_SETFL,O_NONBLOCK);
|
|
fcntl(s,F_SETFL,O_NONBLOCK);
|
|
|
|
+#ifdef ZT_TCP_NODELAY
|
|
|
|
+ { int f = 1; setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
|
|
|
|
+#endif
|
|
#endif
|
|
#endif
|
|
|
|
|
|
bool connecting = false;
|
|
bool connecting = false;
|
|
@@ -405,6 +408,7 @@ bool SocketManager::send(const InetAddress &to,bool tcp,const void *msg,unsigned
|
|
if (connecting)
|
|
if (connecting)
|
|
FD_SET(s,&_writefds);
|
|
FD_SET(s,&_writefds);
|
|
_fdSetLock.unlock();
|
|
_fdSetLock.unlock();
|
|
|
|
+ whack();
|
|
|
|
|
|
return true;
|
|
return true;
|
|
} else if (to.isV4()) {
|
|
} else if (to.isV4()) {
|
|
@@ -453,11 +457,11 @@ void SocketManager::poll(unsigned long timeout)
|
|
select(_nfds + 1,&rfds,&wfds,&efds,(timeout > 0) ? &tv : (struct timeval *)0);
|
|
select(_nfds + 1,&rfds,&wfds,&efds,(timeout > 0) ? &tv : (struct timeval *)0);
|
|
|
|
|
|
if (FD_ISSET(_whackReceivePipe,&rfds)) {
|
|
if (FD_ISSET(_whackReceivePipe,&rfds)) {
|
|
- char tmp;
|
|
|
|
|
|
+ char tmp[16];
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
- ::recv(_whackReceivePipe,&tmp,1,0);
|
|
|
|
|
|
+ ::recv(_whackReceivePipe,&tmp,16,0);
|
|
#else
|
|
#else
|
|
- ::read(_whackReceivePipe,&tmp,1);
|
|
|
|
|
|
+ ::read(_whackReceivePipe,&tmp,16);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
@@ -476,10 +480,15 @@ void SocketManager::poll(unsigned long timeout)
|
|
try {
|
|
try {
|
|
_tcpSockets[fromia] = SharedPtr<Socket>(new TcpSocket(this,sockfd,false,fromia));
|
|
_tcpSockets[fromia] = SharedPtr<Socket>(new TcpSocket(this,sockfd,false,fromia));
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
- u_long iMode=1;
|
|
|
|
- ioctlsocket(sockfd,FIONBIO,&iMode);
|
|
|
|
|
|
+ { u_long iMode=1; ioctlsocket(sockfd,FIONBIO,&iMode); }
|
|
|
|
+#ifdef ZT_TCP_NODELAY
|
|
|
|
+ { BOOL f = TRUE; setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
|
|
|
|
+#endif
|
|
#else
|
|
#else
|
|
fcntl(sockfd,F_SETFL,O_NONBLOCK);
|
|
fcntl(sockfd,F_SETFL,O_NONBLOCK);
|
|
|
|
+#ifdef ZT_TCP_NODELAY
|
|
|
|
+ { int f = 1; setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
|
|
|
|
+#endif
|
|
#endif
|
|
#endif
|
|
_fdSetLock.lock();
|
|
_fdSetLock.lock();
|
|
FD_SET(sockfd,&_readfds);
|
|
FD_SET(sockfd,&_readfds);
|
|
@@ -509,10 +518,15 @@ void SocketManager::poll(unsigned long timeout)
|
|
try {
|
|
try {
|
|
_tcpSockets[fromia] = SharedPtr<Socket>(new TcpSocket(this,sockfd,false,fromia));
|
|
_tcpSockets[fromia] = SharedPtr<Socket>(new TcpSocket(this,sockfd,false,fromia));
|
|
#ifdef __WINDOWS__
|
|
#ifdef __WINDOWS__
|
|
- u_long iMode=1;
|
|
|
|
- ioctlsocket(sockfd,FIONBIO,&iMode);
|
|
|
|
|
|
+ { u_long iMode=1; ioctlsocket(sockfd,FIONBIO,&iMode); }
|
|
|
|
+#ifdef ZT_TCP_NODELAY
|
|
|
|
+ { BOOL f = TRUE; setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
|
|
|
|
+#endif
|
|
#else
|
|
#else
|
|
fcntl(sockfd,F_SETFL,O_NONBLOCK);
|
|
fcntl(sockfd,F_SETFL,O_NONBLOCK);
|
|
|
|
+#ifdef ZT_TCP_NODELAY
|
|
|
|
+ { int f = 1; setsockopt(sockfd,IPPROTO_TCP,TCP_NODELAY,(char *)&f,sizeof(f)); }
|
|
|
|
+#endif
|
|
#endif
|
|
#endif
|
|
_fdSetLock.lock();
|
|
_fdSetLock.lock();
|
|
FD_SET(sockfd,&_readfds);
|
|
FD_SET(sockfd,&_readfds);
|
|
@@ -538,7 +552,7 @@ void SocketManager::poll(unsigned long timeout)
|
|
bool closedSockets = false;
|
|
bool closedSockets = false;
|
|
{ // grab copy of TCP sockets list because _tcpSockets[] might be changed in a handler
|
|
{ // grab copy of TCP sockets list because _tcpSockets[] might be changed in a handler
|
|
Mutex::Lock _l2(_tcpSockets_m);
|
|
Mutex::Lock _l2(_tcpSockets_m);
|
|
- if (_tcpSockets.size()) {
|
|
|
|
|
|
+ if (!_tcpSockets.empty()) {
|
|
ts.reserve(_tcpSockets.size());
|
|
ts.reserve(_tcpSockets.size());
|
|
uint64_t now = Utils::now();
|
|
uint64_t now = Utils::now();
|
|
for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();) {
|
|
for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();) {
|