mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-19 04:57:53 +00:00
Bunch of tap stuff, IP address assignment hookups, etc.
This commit is contained in:
parent
e205e5fdfe
commit
67f1f1892f
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "BSDEthernetTapFactory.hpp"
|
||||
#include "BSDEthernetTap.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
BSDEthernetTapFactory::BSDEthernetTapFactory()
|
||||
{
|
||||
}
|
||||
|
||||
BSDEthernetTapFactory::~BSDEthernetTapFactory()
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d)
|
||||
delete *d;
|
||||
}
|
||||
|
||||
EthernetTap *BSDEthernetTapFactory::open(
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *desiredDevice,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||
void *arg)
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
EthernetTap *t = new BSDEthernetTap(mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg);
|
||||
_devices.push_back(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
void BSDEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices)
|
||||
{
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) {
|
||||
if (*d == tap) {
|
||||
_devices.erase(d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete tap;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_BSDETHERNETTAPFACTORY_HPP
|
||||
#define ZT_BSDETHERNETTAPFACTORY_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "EthernetTapFactory.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class BSDEthernetTapFactory : public EthernetTapFactory
|
||||
{
|
||||
public:
|
||||
BSDEthernetTapFactory();
|
||||
virtual ~BSDEthernetTapFactory();
|
||||
|
||||
virtual EthernetTap *open(
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *desiredDevice,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||
void *arg);
|
||||
virtual void close(EthernetTap *tap,bool destroyPersistentDevices);
|
||||
|
||||
private:
|
||||
std::vector<EthernetTap *> _devices;
|
||||
Mutex _devices_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -1,74 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include "LinuxEthernetTapFactory.hpp"
|
||||
#include "LinuxEthernetTap.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
LinuxEthernetTapFactory::LinuxEthernetTapFactory()
|
||||
{
|
||||
}
|
||||
|
||||
LinuxEthernetTapFactory::~LinuxEthernetTapFactory()
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d)
|
||||
delete *d;
|
||||
}
|
||||
|
||||
EthernetTap *LinuxEthernetTapFactory::open(
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *desiredDevice,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||
void *arg)
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
EthernetTap *t = new LinuxEthernetTap(mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg);
|
||||
_devices.push_back(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
void LinuxEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices)
|
||||
{
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) {
|
||||
if (*d == tap) {
|
||||
_devices.erase(d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete tap;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_LINUXETHERNETTAPFACTORY_HPP
|
||||
#define ZT_LINUXETHERNETTAPFACTORY_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "../node/EthernetTapFactory.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class LinuxEthernetTapFactory : public EthernetTapFactory
|
||||
{
|
||||
public:
|
||||
LinuxEthernetTapFactory();
|
||||
virtual ~LinuxEthernetTapFactory();
|
||||
|
||||
virtual EthernetTap *open(
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *desiredDevice,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||
void *arg);
|
||||
virtual void close(EthernetTap *tap,bool destroyPersistentDevices);
|
||||
|
||||
private:
|
||||
std::vector<EthernetTap *> _devices;
|
||||
Mutex _devices_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -1,989 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
/* Native SocketManager for Windows and Unix */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "NativeSocketManager.hpp"
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <signal.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#endif // !__WINDOWS__
|
||||
|
||||
// Uncomment to turn off TCP Nagle
|
||||
//#define ZT_TCP_NODELAY
|
||||
|
||||
// Allow us to use the same value on Windows and *nix
|
||||
#ifndef INVALID_SOCKET
|
||||
#define INVALID_SOCKET (-1)
|
||||
#endif
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#define CLOSE_SOCKET(s) ::closesocket(s)
|
||||
#else
|
||||
#define CLOSE_SOCKET(s) ::close(s)
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Socket implementations
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class NativeSocket : public Socket
|
||||
{
|
||||
public:
|
||||
#ifdef __WINDOWS__
|
||||
NativeSocket(const Type &t,SOCKET s) : Socket(t),_sock(s) {}
|
||||
SOCKET _sock;
|
||||
#else
|
||||
NativeSocket(const Type &t,int s) : Socket(t),_sock(s) {}
|
||||
int _sock;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Native UDP socket
|
||||
*/
|
||||
class NativeUdpSocket : public NativeSocket
|
||||
{
|
||||
public:
|
||||
#ifdef __WINDOWS__
|
||||
NativeUdpSocket(Type t,SOCKET s) : NativeSocket(t,s) {}
|
||||
#else
|
||||
NativeUdpSocket(Type t,int s) : NativeSocket(t,s) {}
|
||||
#endif
|
||||
|
||||
virtual ~NativeUdpSocket()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
::closesocket(_sock);
|
||||
#else
|
||||
::close(_sock);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen)
|
||||
{
|
||||
if (to.isV6()) {
|
||||
#ifdef __WINDOWS__
|
||||
return ((int)sendto(_sock,(const char *)msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
|
||||
#else
|
||||
return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef __WINDOWS__
|
||||
return ((int)sendto(_sock,(const char *)msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
|
||||
#else
|
||||
return ((int)sendto(_sock,msg,msglen,0,to.saddr(),to.saddrLen()) == (int)msglen);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
inline bool notifyAvailableForRead(const SharedPtr<Socket> &self,NativeSocketManager *sm,void (*handler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg)
|
||||
{
|
||||
Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> buf;
|
||||
InetAddress from;
|
||||
socklen_t salen = from.saddrSpaceLen();
|
||||
int n = (int)recvfrom(_sock,(char *)(buf.data()),ZT_SOCKET_MAX_MESSAGE_LEN,0,from.saddr(),&salen);
|
||||
if (n > 0) {
|
||||
buf.setSize((unsigned int)n);
|
||||
try {
|
||||
handler(self,arg,from,buf);
|
||||
} catch ( ... ) {} // handlers should not throw
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool notifyAvailableForWrite(const SharedPtr<Socket> &self,NativeSocketManager *sm)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A TCP socket encapsulating ZeroTier packets over a TCP stream connection
|
||||
*
|
||||
* This implements a simple packet encapsulation that is designed to look like
|
||||
* a TLS connection. It's not a TLS connection, but it sends TLS format record
|
||||
* headers. It could be extended in the future to implement a fake TLS
|
||||
* handshake.
|
||||
*
|
||||
* At the moment, each packet is just made to look like TLS application data:
|
||||
* <[1] TLS content type> - currently 0x17 for "application data"
|
||||
* <[1] TLS major version> - currently 0x03 for TLS 1.2
|
||||
* <[1] TLS minor version> - currently 0x03 for TLS 1.2
|
||||
* <[2] payload length> - 16-bit length of payload in bytes
|
||||
* <[...] payload> - Message payload
|
||||
*
|
||||
* The primary purpose of TCP sockets is to work over ports like HTTPS(443),
|
||||
* allowing users behind particularly fascist firewalls to at least reach
|
||||
* ZeroTier's supernodes. UDP is the preferred method of communication as
|
||||
* encapsulating L2 and L3 protocols over TCP is inherently inefficient
|
||||
* due to double-ACKs. So TCP is only used as a fallback.
|
||||
*/
|
||||
class NativeTcpSocket : public NativeSocket
|
||||
{
|
||||
public:
|
||||
#ifdef __WINDOWS__
|
||||
NativeTcpSocket(NativeSocketManager *sm,SOCKET s,Socket::Type t,bool c,const InetAddress &r) :
|
||||
#else
|
||||
NativeTcpSocket(NativeSocketManager *sm,int s,Socket::Type t,bool c,const InetAddress &r) :
|
||||
#endif
|
||||
NativeSocket(t,s),
|
||||
_lastActivity(Utils::now()),
|
||||
_sm(sm),
|
||||
_inptr(0),
|
||||
_outptr(0),
|
||||
_connecting(c),
|
||||
_remote(r) {}
|
||||
|
||||
virtual ~NativeTcpSocket()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
::closesocket(_sock);
|
||||
#else
|
||||
::close(_sock);
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual bool send(const InetAddress &to,const void *msg,unsigned int msglen)
|
||||
{
|
||||
if (msglen > ZT_SOCKET_MAX_MESSAGE_LEN)
|
||||
return false; // message too big
|
||||
if (!msglen)
|
||||
return true; // sanity check
|
||||
|
||||
Mutex::Lock _l(_writeLock);
|
||||
|
||||
bool writeInProgress = ((_outptr != 0)||(_connecting));
|
||||
|
||||
if ((_outptr + 5 + msglen) > (unsigned int)sizeof(_outbuf))
|
||||
return false;
|
||||
|
||||
_outbuf[_outptr++] = 0x17; // look like TLS data
|
||||
_outbuf[_outptr++] = 0x03;
|
||||
_outbuf[_outptr++] = 0x03; // look like TLS 1.2
|
||||
_outbuf[_outptr++] = (unsigned char)((msglen >> 8) & 0xff);
|
||||
_outbuf[_outptr++] = (unsigned char)(msglen & 0xff);
|
||||
for(unsigned int i=0;i<msglen;++i)
|
||||
_outbuf[_outptr++] = ((const unsigned char *)msg)[i];
|
||||
|
||||
if (!writeInProgress) {
|
||||
// If no output was enqueued before this, try to send() it and then
|
||||
// start a queued write if any remains after that.
|
||||
|
||||
int n = (int)::send(_sock,(const char *)_outbuf,_outptr,0);
|
||||
if (n > 0)
|
||||
memmove(_outbuf,_outbuf + (unsigned int)n,_outptr -= (unsigned int)n);
|
||||
|
||||
if (_outptr) {
|
||||
_sm->_startNotifyWrite(this);
|
||||
_sm->whack();
|
||||
}
|
||||
} // else just leave in _outbuf[] to get written when stream is available for write
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool notifyAvailableForRead(const SharedPtr<Socket> &self,NativeSocketManager *sm,void (*handler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg)
|
||||
{
|
||||
unsigned char buf[65536];
|
||||
|
||||
int n = (int)::recv(_sock,(char *)buf,sizeof(buf),0);
|
||||
if (n <= 0)
|
||||
return false; // read error, stream probably closed
|
||||
|
||||
unsigned int p = _inptr,pl = 0;
|
||||
for(int k=0;k<n;++k) {
|
||||
_inbuf[p++] = buf[k];
|
||||
if (p >= (int)sizeof(_inbuf))
|
||||
return false; // read overrun, packet too large or invalid
|
||||
|
||||
if ((!pl)&&(p >= 5)) {
|
||||
if (_inbuf[0] == 0x17) {
|
||||
// fake TLS data frame, next two bytes are TLS version and are ignored
|
||||
pl = (((unsigned int)_inbuf[3] << 8) | (unsigned int)_inbuf[4]) + 5;
|
||||
} else return false; // in the future we may support fake TLS handshakes
|
||||
}
|
||||
|
||||
if ((pl)&&(p >= pl)) {
|
||||
Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> data(_inbuf + 5,pl - 5);
|
||||
memmove(_inbuf,_inbuf + pl,p -= pl);
|
||||
try {
|
||||
handler(self,arg,_remote,data);
|
||||
} catch ( ... ) {} // handlers should not throw
|
||||
pl = 0;
|
||||
}
|
||||
}
|
||||
_inptr = p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool notifyAvailableForWrite(const SharedPtr<Socket> &self,NativeSocketManager *sm)
|
||||
{
|
||||
Mutex::Lock _l(_writeLock);
|
||||
|
||||
if (_connecting)
|
||||
_connecting = false;
|
||||
|
||||
if (_outptr) {
|
||||
int n = (int)::send(_sock,(const char *)_outbuf,_outptr,0);
|
||||
#ifdef __WINDOWS__
|
||||
if (n == SOCKET_ERROR) {
|
||||
switch(WSAGetLastError()) {
|
||||
case WSAEINTR:
|
||||
case WSAEWOULDBLOCK:
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if (n <= 0) {
|
||||
switch(errno) {
|
||||
#ifdef EAGAIN
|
||||
case EAGAIN:
|
||||
#endif
|
||||
#if defined(EWOULDBLOCK) && ( !defined(EAGAIN) || (EWOULDBLOCK != EAGAIN) )
|
||||
case EWOULDBLOCK:
|
||||
#endif
|
||||
#ifdef EINTR
|
||||
case EINTR:
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
} else memmove(_outbuf,_outbuf + (unsigned int)n,_outptr -= (unsigned int)n);
|
||||
}
|
||||
|
||||
if (!_outptr)
|
||||
sm->_stopNotifyWrite(this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned char _inbuf[ZT_SOCKET_MAX_MESSAGE_LEN];
|
||||
unsigned char _outbuf[ZT_SOCKET_MAX_MESSAGE_LEN * 4];
|
||||
uint64_t _lastActivity; // updated whenever data is received, checked directly by SocketManager for stale TCP cleanup
|
||||
NativeSocketManager *_sm;
|
||||
unsigned int _inptr;
|
||||
unsigned int _outptr;
|
||||
bool _connecting; // manipulated directly by SocketManager, true if connect() is in progress
|
||||
InetAddress _remote;
|
||||
Mutex _writeLock;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
// 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 addr;
|
||||
SOCKET lst=::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP);
|
||||
memset(&inaddr, 0, sizeof(inaddr));
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
inaddr.sin_family = AF_INET;
|
||||
inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
inaddr.sin_port = 0;
|
||||
int yes=1;
|
||||
setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes));
|
||||
bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr));
|
||||
listen(lst,1);
|
||||
int len=sizeof(inaddr);
|
||||
getsockname(lst, &addr,&len);
|
||||
fds[0]=::socket(AF_INET, SOCK_STREAM,0);
|
||||
connect(fds[0],&addr,len);
|
||||
fds[1]=accept(lst,0,0);
|
||||
closesocket(lst);
|
||||
}
|
||||
#endif
|
||||
|
||||
NativeSocketManager::NativeSocketManager(int localUdpPort,int localTcpPort) :
|
||||
SocketManager(),
|
||||
_whackSendPipe(INVALID_SOCKET),
|
||||
_whackReceivePipe(INVALID_SOCKET),
|
||||
_tcpV4ListenSocket(INVALID_SOCKET),
|
||||
_tcpV6ListenSocket(INVALID_SOCKET),
|
||||
_nfds(0)
|
||||
{
|
||||
FD_ZERO(&_readfds);
|
||||
FD_ZERO(&_writefds);
|
||||
|
||||
// Create a pipe or socket pair that can be used to interrupt select()
|
||||
#ifdef __WINDOWS__
|
||||
{
|
||||
SOCKET tmps[2] = { INVALID_SOCKET,INVALID_SOCKET };
|
||||
winPipeHack(tmps);
|
||||
_whackSendPipe = tmps[0];
|
||||
_whackReceivePipe = tmps[1];
|
||||
u_long iMode=1;
|
||||
ioctlsocket(tmps[1],FIONBIO,&iMode);
|
||||
}
|
||||
#else
|
||||
{
|
||||
int tmpfds[2];
|
||||
if (::pipe(tmpfds))
|
||||
throw std::runtime_error("pipe() failed");
|
||||
_whackSendPipe = tmpfds[1];
|
||||
_whackReceivePipe = tmpfds[0];
|
||||
fcntl(_whackReceivePipe,F_SETFL,O_NONBLOCK);
|
||||
}
|
||||
#endif
|
||||
FD_SET(_whackReceivePipe,&_readfds);
|
||||
|
||||
if (localTcpPort > 0) {
|
||||
if (localTcpPort > 0xffff) {
|
||||
_closeSockets();
|
||||
throw std::runtime_error("invalid local TCP port number");
|
||||
}
|
||||
|
||||
{ // bind TCP IPv6
|
||||
_tcpV6ListenSocket = ::socket(AF_INET6,SOCK_STREAM,0);
|
||||
#ifdef __WINDOWS__
|
||||
if (_tcpV6ListenSocket != INVALID_SOCKET) {
|
||||
{
|
||||
BOOL f;
|
||||
f = TRUE; ::setsockopt(_tcpV6ListenSocket,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f));
|
||||
f = TRUE; ::setsockopt(_tcpV6ListenSocket,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
|
||||
u_long iMode=1;
|
||||
ioctlsocket(_tcpV6ListenSocket,FIONBIO,&iMode);
|
||||
}
|
||||
#else
|
||||
if (_tcpV6ListenSocket > 0) {
|
||||
{
|
||||
int f;
|
||||
f = 1; ::setsockopt(_tcpV6ListenSocket,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
|
||||
f = 1; ::setsockopt(_tcpV6ListenSocket,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
|
||||
fcntl(_tcpV6ListenSocket,F_SETFL,O_NONBLOCK);
|
||||
}
|
||||
#endif // __WINDOWS__ / not __WINDOWS__
|
||||
|
||||
struct sockaddr_in6 sin6;
|
||||
memset(&sin6,0,sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_port = htons(localTcpPort);
|
||||
memcpy(&(sin6.sin6_addr),&in6addr_any,sizeof(struct in6_addr));
|
||||
if (::bind(_tcpV6ListenSocket,(const struct sockaddr *)&sin6,sizeof(sin6))) {
|
||||
_closeSockets();
|
||||
throw std::runtime_error("unable to bind to local TCP port");
|
||||
}
|
||||
|
||||
if (::listen(_tcpV6ListenSocket,1024)) {
|
||||
_closeSockets();
|
||||
throw std::runtime_error("listen() failed");
|
||||
}
|
||||
|
||||
FD_SET(_tcpV6ListenSocket,&_readfds);
|
||||
}
|
||||
}
|
||||
|
||||
{ // bind TCP IPv4
|
||||
_tcpV4ListenSocket = ::socket(AF_INET,SOCK_STREAM,0);
|
||||
#ifdef __WINDOWS__
|
||||
if (_tcpV4ListenSocket == INVALID_SOCKET) {
|
||||
#else
|
||||
if (_tcpV4ListenSocket <= 0) {
|
||||
#endif
|
||||
_closeSockets();
|
||||
throw std::runtime_error("unable to create IPv4 SOCK_STREAM socket");
|
||||
}
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
{
|
||||
BOOL f = TRUE; ::setsockopt(_tcpV4ListenSocket,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
|
||||
u_long iMode=1;
|
||||
ioctlsocket(_tcpV4ListenSocket,FIONBIO,&iMode);
|
||||
}
|
||||
#else
|
||||
{
|
||||
int f = 1; ::setsockopt(_tcpV4ListenSocket,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
|
||||
fcntl(_tcpV4ListenSocket,F_SETFL,O_NONBLOCK);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct sockaddr_in sin4;
|
||||
memset(&sin4,0,sizeof(sin4));
|
||||
sin4.sin_family = AF_INET;
|
||||
sin4.sin_port = htons(localTcpPort);
|
||||
sin4.sin_addr.s_addr = INADDR_ANY;
|
||||
if (::bind(_tcpV4ListenSocket,(const struct sockaddr *)&sin4,sizeof(sin4))) {
|
||||
_closeSockets();
|
||||
throw std::runtime_error("unable to bind to local TCP port");
|
||||
}
|
||||
|
||||
if (::listen(_tcpV4ListenSocket,1024)) {
|
||||
_closeSockets();
|
||||
throw std::runtime_error("listen() failed");
|
||||
}
|
||||
|
||||
FD_SET(_tcpV4ListenSocket,&_readfds);
|
||||
}
|
||||
}
|
||||
|
||||
if (localUdpPort > 0) {
|
||||
if (localUdpPort > 0xffff) {
|
||||
_closeSockets();
|
||||
throw std::runtime_error("invalid local UDP port number");
|
||||
}
|
||||
|
||||
{ // bind UDP IPv6
|
||||
#ifdef __WINDOWS__
|
||||
SOCKET s = ::socket(AF_INET6,SOCK_DGRAM,0);
|
||||
if (s != INVALID_SOCKET) {
|
||||
#else
|
||||
int s = ::socket(AF_INET6,SOCK_DGRAM,0);
|
||||
if (s > 0) {
|
||||
#endif
|
||||
|
||||
{
|
||||
int bs = 1048576;
|
||||
while (bs >= 65536) {
|
||||
int tmpbs = bs;
|
||||
if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
|
||||
break;
|
||||
bs -= 16384;
|
||||
}
|
||||
bs = 1048576;
|
||||
while (bs >= 65536) {
|
||||
int tmpbs = bs;
|
||||
if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
|
||||
break;
|
||||
bs -= 16384;
|
||||
}
|
||||
#ifdef __WINDOWS__
|
||||
BOOL f;
|
||||
f = TRUE; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(const char *)&f,sizeof(f));
|
||||
f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
|
||||
f = FALSE; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,(const char *)&f,sizeof(f));
|
||||
f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f));
|
||||
#else
|
||||
int f;
|
||||
f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f));
|
||||
f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
|
||||
f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f));
|
||||
#ifdef IP_DONTFRAG
|
||||
f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f));
|
||||
#endif
|
||||
#ifdef IP_MTU_DISCOVER
|
||||
f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f));
|
||||
#endif
|
||||
#ifdef IPV6_MTU_DISCOVER
|
||||
f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
struct sockaddr_in6 sin6;
|
||||
memset(&sin6,0,sizeof(sin6));
|
||||
sin6.sin6_family = AF_INET6;
|
||||
sin6.sin6_port = htons(localUdpPort);
|
||||
memcpy(&(sin6.sin6_addr),&in6addr_any,sizeof(struct in6_addr));
|
||||
if (::bind(s,(const struct sockaddr *)&sin6,sizeof(sin6))) {
|
||||
CLOSE_SOCKET(s);
|
||||
_closeSockets();
|
||||
throw std::runtime_error("unable to bind to port");
|
||||
}
|
||||
|
||||
_udpV6Socket = SharedPtr<Socket>(new NativeUdpSocket(Socket::ZT_SOCKET_TYPE_UDP_V6,s));
|
||||
#ifdef __WINDOWS__
|
||||
u_long iMode=1;
|
||||
ioctlsocket(s,FIONBIO,&iMode);
|
||||
#else
|
||||
fcntl(s,F_SETFL,O_NONBLOCK);
|
||||
#endif
|
||||
FD_SET(s,&_readfds);
|
||||
}
|
||||
}
|
||||
|
||||
{ // bind UDP IPv4
|
||||
#ifdef __WINDOWS__
|
||||
SOCKET s = ::socket(AF_INET,SOCK_DGRAM,0);
|
||||
if (s == INVALID_SOCKET) {
|
||||
_closeSockets();
|
||||
throw std::runtime_error("unable to create IPv4 SOCK_DGRAM socket");
|
||||
}
|
||||
#else
|
||||
int s = ::socket(AF_INET,SOCK_DGRAM,0);
|
||||
if (s <= 0) {
|
||||
_closeSockets();
|
||||
throw std::runtime_error("unable to create IPv4 SOCK_DGRAM socket");
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
int bs = 1048576;
|
||||
while (bs >= 65536) {
|
||||
int tmpbs = bs;
|
||||
if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
|
||||
break;
|
||||
bs -= 16384;
|
||||
}
|
||||
bs = 1048576;
|
||||
while (bs >= 65536) {
|
||||
int tmpbs = bs;
|
||||
if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&tmpbs,sizeof(tmpbs)) == 0)
|
||||
break;
|
||||
bs -= 16384;
|
||||
}
|
||||
#ifdef __WINDOWS__
|
||||
BOOL f;
|
||||
f = FALSE; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(const char *)&f,sizeof(f));
|
||||
f = FALSE; setsockopt(s,IPPROTO_IP,IP_DONTFRAGMENT,(const char *)&f,sizeof(f));
|
||||
f = TRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char *)&f,sizeof(f));
|
||||
#else
|
||||
int f;
|
||||
f = 0; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f));
|
||||
f = 1; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(void *)&f,sizeof(f));
|
||||
#ifdef IP_DONTFRAG
|
||||
f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f));
|
||||
#endif
|
||||
#ifdef IP_MTU_DISCOVER
|
||||
f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
struct sockaddr_in sin4;
|
||||
memset(&sin4,0,sizeof(sin4));
|
||||
sin4.sin_family = AF_INET;
|
||||
sin4.sin_port = htons(localUdpPort);
|
||||
sin4.sin_addr.s_addr = INADDR_ANY;
|
||||
if (::bind(s,(const struct sockaddr *)&sin4,sizeof(sin4))) {
|
||||
CLOSE_SOCKET(s);
|
||||
_closeSockets();
|
||||
throw std::runtime_error("unable to bind to port");
|
||||
}
|
||||
|
||||
_udpV4Socket = SharedPtr<Socket>(new NativeUdpSocket(Socket::ZT_SOCKET_TYPE_UDP_V4,s));
|
||||
#ifdef __WINDOWS__
|
||||
u_long iMode=1;
|
||||
ioctlsocket(s,FIONBIO,&iMode);
|
||||
#else
|
||||
fcntl(s,F_SETFL,O_NONBLOCK);
|
||||
#endif
|
||||
FD_SET(s,&_readfds);
|
||||
}
|
||||
}
|
||||
|
||||
_updateNfds();
|
||||
}
|
||||
|
||||
NativeSocketManager::~NativeSocketManager()
|
||||
{
|
||||
Mutex::Lock _l(_pollLock);
|
||||
_closeSockets();
|
||||
}
|
||||
|
||||
bool NativeSocketManager::send(const InetAddress &to,bool tcp,bool autoConnectTcp,const void *msg,unsigned int msglen)
|
||||
{
|
||||
if (tcp) {
|
||||
SharedPtr<Socket> ts;
|
||||
{
|
||||
Mutex::Lock _l(_tcpSockets_m);
|
||||
std::map< InetAddress,SharedPtr<Socket> >::iterator opents(_tcpSockets.find(to));
|
||||
if (opents != _tcpSockets.end())
|
||||
ts = opents->second;
|
||||
}
|
||||
if (ts)
|
||||
return ts->send(to,msg,msglen);
|
||||
|
||||
if (!autoConnectTcp)
|
||||
return false;
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
SOCKET s = ::socket(to.isV4() ? AF_INET : AF_INET6,SOCK_STREAM,0);
|
||||
if (s == INVALID_SOCKET)
|
||||
return false;
|
||||
{ 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
|
||||
int s = ::socket(to.isV4() ? AF_INET : AF_INET6,SOCK_STREAM,0);
|
||||
if (s <= 0)
|
||||
return false;
|
||||
if (s >= FD_SETSIZE) {
|
||||
::close(s);
|
||||
return false;
|
||||
}
|
||||
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
|
||||
|
||||
bool connecting = false;
|
||||
if (::connect(s,to.saddr(),to.saddrLen())) {
|
||||
#ifdef __WINDOWS__
|
||||
if (WSAGetLastError() != WSAEWOULDBLOCK) {
|
||||
#else
|
||||
if (errno != EINPROGRESS) {
|
||||
#endif
|
||||
CLOSE_SOCKET(s);
|
||||
return false;
|
||||
} else connecting = true;
|
||||
}
|
||||
|
||||
ts = SharedPtr<Socket>(new NativeTcpSocket(this,s,Socket::ZT_SOCKET_TYPE_TCP_OUT,connecting,to));
|
||||
if (!ts->send(to,msg,msglen)) {
|
||||
_fdSetLock.lock();
|
||||
FD_CLR(s,&_readfds);
|
||||
FD_CLR(s,&_writefds);
|
||||
_fdSetLock.unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_tcpSockets_m);
|
||||
_tcpSockets[to] = ts;
|
||||
}
|
||||
|
||||
_fdSetLock.lock();
|
||||
FD_SET(s,&_readfds);
|
||||
if (connecting)
|
||||
FD_SET(s,&_writefds);
|
||||
_fdSetLock.unlock();
|
||||
|
||||
_updateNfds();
|
||||
whack();
|
||||
|
||||
return true;
|
||||
} else if (to.isV4()) {
|
||||
if (_udpV4Socket)
|
||||
return _udpV4Socket->send(to,msg,msglen);
|
||||
} else if (to.isV6()) {
|
||||
if (_udpV6Socket)
|
||||
return _udpV6Socket->send(to,msg,msglen);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void NativeSocketManager::poll(unsigned long timeout,void (*handler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg)
|
||||
{
|
||||
fd_set rfds,wfds,efds;
|
||||
struct timeval tv;
|
||||
std::vector< SharedPtr<Socket> > ts;
|
||||
#ifdef __WINDOWS__
|
||||
SOCKET sockfd;
|
||||
#else
|
||||
int sockfd;
|
||||
#endif
|
||||
|
||||
Mutex::Lock _l(_pollLock);
|
||||
|
||||
_fdSetLock.lock();
|
||||
memcpy(&rfds,&_readfds,sizeof(rfds));
|
||||
memcpy(&wfds,&_writefds,sizeof(wfds));
|
||||
_fdSetLock.unlock();
|
||||
FD_ZERO(&efds);
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
// Windows signals failed connects in exceptfds
|
||||
{
|
||||
Mutex::Lock _l2(_tcpSockets_m);
|
||||
for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();++s) {
|
||||
if (((NativeTcpSocket *)s->second.ptr())->_connecting)
|
||||
FD_SET(((NativeTcpSocket *)s->second.ptr())->_sock,&efds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
tv.tv_sec = (long)(timeout / 1000);
|
||||
tv.tv_usec = (long)((timeout % 1000) * 1000);
|
||||
select(_nfds + 1,&rfds,&wfds,&efds,(timeout > 0) ? &tv : (struct timeval *)0);
|
||||
|
||||
if (FD_ISSET(_whackReceivePipe,&rfds)) {
|
||||
char tmp[16];
|
||||
#ifdef __WINDOWS__
|
||||
::recv(_whackReceivePipe,tmp,16,0);
|
||||
#else
|
||||
::read(_whackReceivePipe,tmp,16);
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((_tcpV4ListenSocket != INVALID_SOCKET)&&(FD_ISSET(_tcpV4ListenSocket,&rfds))) {
|
||||
struct sockaddr_in from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
sockfd = accept(_tcpV4ListenSocket,(struct sockaddr *)&from,&fromlen);
|
||||
#ifdef __WINDOWS__
|
||||
if (sockfd != INVALID_SOCKET) {
|
||||
#else
|
||||
if (sockfd > 0) {
|
||||
if (sockfd < FD_SETSIZE) {
|
||||
#endif
|
||||
InetAddress fromia((const struct sockaddr *)&from);
|
||||
Mutex::Lock _l2(_tcpSockets_m);
|
||||
try {
|
||||
_tcpSockets[fromia] = SharedPtr<Socket>(new NativeTcpSocket(this,sockfd,Socket::ZT_SOCKET_TYPE_TCP_IN,false,fromia));
|
||||
#ifdef __WINDOWS__
|
||||
{ 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
|
||||
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
|
||||
_fdSetLock.lock();
|
||||
FD_SET(sockfd,&_readfds);
|
||||
_fdSetLock.unlock();
|
||||
if ((int)sockfd > (int)_nfds)
|
||||
_nfds = (int)sockfd;
|
||||
} catch ( ... ) {
|
||||
CLOSE_SOCKET(sockfd);
|
||||
}
|
||||
#ifndef __WINDOWS__
|
||||
} else {
|
||||
CLOSE_SOCKET(sockfd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if ((_tcpV6ListenSocket != INVALID_SOCKET)&&(FD_ISSET(_tcpV6ListenSocket,&rfds))) {
|
||||
struct sockaddr_in6 from;
|
||||
socklen_t fromlen = sizeof(from);
|
||||
sockfd = accept(_tcpV6ListenSocket,(struct sockaddr *)&from,&fromlen);
|
||||
#ifdef __WINDOWS__
|
||||
if (sockfd != INVALID_SOCKET) {
|
||||
#else
|
||||
if (sockfd > 0) {
|
||||
if (sockfd < FD_SETSIZE) {
|
||||
#endif
|
||||
InetAddress fromia((const struct sockaddr *)&from);
|
||||
Mutex::Lock _l2(_tcpSockets_m);
|
||||
try {
|
||||
_tcpSockets[fromia] = SharedPtr<Socket>(new NativeTcpSocket(this,sockfd,Socket::ZT_SOCKET_TYPE_TCP_IN,false,fromia));
|
||||
#ifdef __WINDOWS__
|
||||
{ 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
|
||||
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
|
||||
_fdSetLock.lock();
|
||||
FD_SET(sockfd,&_readfds);
|
||||
_fdSetLock.unlock();
|
||||
if ((int)sockfd > (int)_nfds)
|
||||
_nfds = (int)sockfd;
|
||||
} catch ( ... ) {
|
||||
CLOSE_SOCKET(sockfd);
|
||||
}
|
||||
#ifndef __WINDOWS__
|
||||
} else {
|
||||
CLOSE_SOCKET(sockfd);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
NativeUdpSocket *usock = (NativeUdpSocket *)_udpV4Socket.ptr();
|
||||
if ((usock)&&(FD_ISSET(usock->_sock,&rfds))) {
|
||||
usock->notifyAvailableForRead(_udpV4Socket,this,handler,arg);
|
||||
}
|
||||
usock = (NativeUdpSocket *)_udpV6Socket.ptr();
|
||||
if ((usock)&&(FD_ISSET(usock->_sock,&rfds))) {
|
||||
usock->notifyAvailableForRead(_udpV6Socket,this,handler,arg);
|
||||
}
|
||||
}
|
||||
|
||||
bool closedSockets = false;
|
||||
{ // grab copy of TCP sockets list because _tcpSockets[] might be changed in a handler
|
||||
Mutex::Lock _l2(_tcpSockets_m);
|
||||
if (!_tcpSockets.empty()) {
|
||||
ts.reserve(_tcpSockets.size());
|
||||
uint64_t now = Utils::now();
|
||||
for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();) {
|
||||
NativeTcpSocket *tsock = (NativeTcpSocket *)s->second.ptr();
|
||||
#ifdef __WINDOWS__
|
||||
if ( ((now - tsock->_lastActivity) < ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT) && (! ((tsock->_connecting)&&(FD_ISSET(tsock->_sock,&efds))) ) ) {
|
||||
#else
|
||||
if ((now - tsock->_lastActivity) < ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT) {
|
||||
#endif
|
||||
ts.push_back(s->second);
|
||||
++s;
|
||||
} else {
|
||||
_fdSetLock.lock();
|
||||
FD_CLR(tsock->_sock,&_readfds);
|
||||
FD_CLR(tsock->_sock,&_writefds);
|
||||
_fdSetLock.unlock();
|
||||
_tcpSockets.erase(s++);
|
||||
closedSockets = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for(std::vector< SharedPtr<Socket> >::iterator s(ts.begin());s!=ts.end();++s) {
|
||||
NativeTcpSocket *tsock = (NativeTcpSocket *)s->ptr();
|
||||
if (FD_ISSET(tsock->_sock,&wfds)) {
|
||||
if (!tsock->notifyAvailableForWrite(*s,this)) {
|
||||
{
|
||||
Mutex::Lock _l2(_tcpSockets_m);
|
||||
_tcpSockets.erase(tsock->_remote);
|
||||
}
|
||||
_fdSetLock.lock();
|
||||
FD_CLR(tsock->_sock,&_readfds);
|
||||
FD_CLR(tsock->_sock,&_writefds);
|
||||
_fdSetLock.unlock();
|
||||
closedSockets = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(tsock->_sock,&rfds)) {
|
||||
if (!tsock->notifyAvailableForRead(*s,this,handler,arg)) {
|
||||
{
|
||||
Mutex::Lock _l2(_tcpSockets_m);
|
||||
_tcpSockets.erase(tsock->_remote);
|
||||
}
|
||||
_fdSetLock.lock();
|
||||
FD_CLR(tsock->_sock,&_readfds);
|
||||
FD_CLR(tsock->_sock,&_writefds);
|
||||
_fdSetLock.unlock();
|
||||
closedSockets = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (closedSockets)
|
||||
_updateNfds();
|
||||
}
|
||||
|
||||
void NativeSocketManager::whack()
|
||||
{
|
||||
_whackSendPipe_m.lock();
|
||||
#ifdef __WINDOWS__
|
||||
::send(_whackSendPipe,(const char *)this,1,0);
|
||||
#else
|
||||
::write(_whackSendPipe,(const void *)this,1); // data is arbitrary, just send a byte
|
||||
#endif
|
||||
_whackSendPipe_m.unlock();
|
||||
}
|
||||
|
||||
void NativeSocketManager::closeTcpSockets()
|
||||
{
|
||||
{
|
||||
Mutex::Lock _l2(_tcpSockets_m);
|
||||
_fdSetLock.lock();
|
||||
for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();++s) {
|
||||
FD_CLR(((NativeTcpSocket *)s->second.ptr())->_sock,&_readfds);
|
||||
FD_CLR(((NativeTcpSocket *)s->second.ptr())->_sock,&_writefds);
|
||||
}
|
||||
_fdSetLock.unlock();
|
||||
_tcpSockets.clear();
|
||||
}
|
||||
_updateNfds();
|
||||
}
|
||||
|
||||
void NativeSocketManager::_startNotifyWrite(const NativeSocket *sock)
|
||||
{
|
||||
_fdSetLock.lock();
|
||||
FD_SET(sock->_sock,&_writefds);
|
||||
_fdSetLock.unlock();
|
||||
}
|
||||
|
||||
void NativeSocketManager::_stopNotifyWrite(const NativeSocket *sock)
|
||||
{
|
||||
_fdSetLock.lock();
|
||||
FD_CLR(sock->_sock,&_writefds);
|
||||
_fdSetLock.unlock();
|
||||
}
|
||||
|
||||
void NativeSocketManager::_closeSockets()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
if (_whackSendPipe != INVALID_SOCKET)
|
||||
::closesocket(_whackSendPipe);
|
||||
if (_whackReceivePipe != INVALID_SOCKET)
|
||||
::closesocket(_whackReceivePipe);
|
||||
if (_tcpV4ListenSocket != INVALID_SOCKET)
|
||||
::closesocket(_tcpV4ListenSocket);
|
||||
if (_tcpV6ListenSocket != INVALID_SOCKET)
|
||||
::closesocket(_tcpV6ListenSocket);
|
||||
#else
|
||||
if (_whackSendPipe > 0)
|
||||
::close(_whackSendPipe);
|
||||
if (_whackReceivePipe > 0)
|
||||
::close(_whackReceivePipe);
|
||||
if (_tcpV4ListenSocket > 0)
|
||||
::close(_tcpV4ListenSocket);
|
||||
if (_tcpV4ListenSocket > 0)
|
||||
::close(_tcpV6ListenSocket);
|
||||
#endif
|
||||
}
|
||||
|
||||
void NativeSocketManager::_updateNfds()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
SOCKET nfds = _whackSendPipe;
|
||||
#else
|
||||
int nfds = _whackSendPipe;
|
||||
#endif
|
||||
if (_whackReceivePipe > nfds)
|
||||
nfds = _whackReceivePipe;
|
||||
if (_tcpV4ListenSocket > nfds)
|
||||
nfds = _tcpV4ListenSocket;
|
||||
if (_tcpV6ListenSocket > nfds)
|
||||
nfds = _tcpV6ListenSocket;
|
||||
if ((_udpV4Socket)&&(((NativeUdpSocket *)_udpV4Socket.ptr())->_sock > nfds))
|
||||
nfds = ((NativeUdpSocket *)_udpV4Socket.ptr())->_sock;
|
||||
if ((_udpV6Socket)&&(((NativeUdpSocket *)_udpV6Socket.ptr())->_sock > nfds))
|
||||
nfds = ((NativeUdpSocket *)_udpV6Socket.ptr())->_sock;
|
||||
Mutex::Lock _l(_tcpSockets_m);
|
||||
for(std::map< InetAddress,SharedPtr<Socket> >::const_iterator s(_tcpSockets.begin());s!=_tcpSockets.end();++s) {
|
||||
if (((NativeTcpSocket *)s->second.ptr())->_sock > nfds)
|
||||
nfds = ((NativeTcpSocket *)s->second.ptr())->_sock;
|
||||
}
|
||||
_nfds = (int)nfds;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
@ -1,117 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_NATIVESOCKETMANAGER_HPP
|
||||
#define ZT_NATIVESOCKETMANAGER_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/SharedPtr.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../node/SocketManager.hpp"
|
||||
#include "../node/Socket.hpp"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <WinSock2.h>
|
||||
#include <WS2tcpip.h>
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class NativeSocket;
|
||||
class NativeUdpSocket;
|
||||
class NativeTcpSocket;
|
||||
|
||||
/**
|
||||
* Native socket manager for Unix and Windows
|
||||
*/
|
||||
class NativeSocketManager : public SocketManager
|
||||
{
|
||||
friend class NativeUdpSocket;
|
||||
friend class NativeTcpSocket;
|
||||
|
||||
public:
|
||||
NativeSocketManager(int localUdpPort,int localTcpPort);
|
||||
virtual ~NativeSocketManager();
|
||||
|
||||
virtual bool send(const InetAddress &to,bool tcp,bool autoConnectTcp,const void *msg,unsigned int msglen);
|
||||
virtual void poll(unsigned long timeout,void (*handler)(const SharedPtr<Socket> &,void *,const InetAddress &,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &),void *arg);
|
||||
virtual void whack();
|
||||
virtual void closeTcpSockets();
|
||||
|
||||
private:
|
||||
// Used by TcpSocket to register/unregister for write availability notification
|
||||
void _startNotifyWrite(const NativeSocket *sock);
|
||||
void _stopNotifyWrite(const NativeSocket *sock);
|
||||
|
||||
// Called in SocketManager destructor or in constructor cleanup before exception throwing
|
||||
void _closeSockets();
|
||||
|
||||
// Called in SocketManager to recompute _nfds for select() based implementation
|
||||
void _updateNfds();
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
SOCKET _whackSendPipe;
|
||||
SOCKET _whackReceivePipe;
|
||||
SOCKET _tcpV4ListenSocket;
|
||||
SOCKET _tcpV6ListenSocket;
|
||||
#else
|
||||
int _whackSendPipe;
|
||||
int _whackReceivePipe;
|
||||
int _tcpV4ListenSocket;
|
||||
int _tcpV6ListenSocket;
|
||||
#endif
|
||||
Mutex _whackSendPipe_m;
|
||||
|
||||
SharedPtr<Socket> _udpV4Socket;
|
||||
SharedPtr<Socket> _udpV6Socket;
|
||||
|
||||
fd_set _readfds;
|
||||
fd_set _writefds;
|
||||
volatile int _nfds;
|
||||
Mutex _fdSetLock;
|
||||
|
||||
std::map< InetAddress,SharedPtr<Socket> > _tcpSockets;
|
||||
Mutex _tcpSockets_m;
|
||||
|
||||
Mutex _pollLock;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -1,122 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "OSXEthernetTapFactory.hpp"
|
||||
#include "OSXEthernetTap.hpp"
|
||||
|
||||
#include "../node/Utils.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
OSXEthernetTapFactory::OSXEthernetTapFactory(const char *pathToTapKext,const char *tapKextName) :
|
||||
_pathToTapKext((pathToTapKext) ? pathToTapKext : ""),
|
||||
_tapKextName((tapKextName) ? tapKextName : "")
|
||||
{
|
||||
struct stat stattmp;
|
||||
|
||||
if ((_pathToTapKext.length())&&(_tapKextName.length())) {
|
||||
if (stat("/dev/zt0",&stattmp)) {
|
||||
long kextpid = (long)vfork();
|
||||
if (kextpid == 0) {
|
||||
::chdir(_pathToTapKext.c_str());
|
||||
Utils::redirectUnixOutputs("/dev/null",(const char *)0);
|
||||
::execl("/sbin/kextload","/sbin/kextload","-q","-repository",_pathToTapKext.c_str(),_tapKextName.c_str(),(const char *)0);
|
||||
::_exit(-1);
|
||||
} else if (kextpid > 0) {
|
||||
int exitcode = -1;
|
||||
::waitpid(kextpid,&exitcode,0);
|
||||
} else throw std::runtime_error("unable to create subprocess with fork()");
|
||||
}
|
||||
}
|
||||
|
||||
if (stat("/dev/zt0",&stattmp)) {
|
||||
::usleep(500); // give tap device driver time to start up and try again
|
||||
if (stat("/dev/zt0",&stattmp))
|
||||
throw std::runtime_error("/dev/zt# tap devices do not exist and unable to load kernel extension");
|
||||
}
|
||||
}
|
||||
|
||||
OSXEthernetTapFactory::~OSXEthernetTapFactory()
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d)
|
||||
delete *d;
|
||||
|
||||
if ((_pathToTapKext.length())&&(_tapKextName.length())) {
|
||||
// Attempt to unload kext. If anything else is using a /dev/zt# node, this
|
||||
// fails and the kext stays in the kernel.
|
||||
char tmp[16384];
|
||||
sprintf(tmp,"%s/%s",_pathToTapKext.c_str(),_tapKextName.c_str());
|
||||
long kextpid = (long)vfork();
|
||||
if (kextpid == 0) {
|
||||
Utils::redirectUnixOutputs("/dev/null",(const char *)0);
|
||||
::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0);
|
||||
::_exit(-1);
|
||||
} else if (kextpid > 0) {
|
||||
int exitcode = -1;
|
||||
::waitpid(kextpid,&exitcode,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EthernetTap *OSXEthernetTapFactory::open(
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *desiredDevice,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||
void *arg)
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
EthernetTap *t = new OSXEthernetTap(mac,mtu,metric,nwid,desiredDevice,friendlyName,handler,arg);
|
||||
_devices.push_back(t);
|
||||
return t;
|
||||
}
|
||||
|
||||
void OSXEthernetTapFactory::close(EthernetTap *tap,bool destroyPersistentDevices)
|
||||
{
|
||||
{
|
||||
Mutex::Lock _l(_devices_m);
|
||||
for(std::vector<EthernetTap *>::iterator d(_devices.begin());d!=_devices.end();++d) {
|
||||
if (*d == tap) {
|
||||
_devices.erase(d);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete tap;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_OSXETHERNETTAPFACTORY_HPP
|
||||
#define ZT_OSXETHERNETTAPFACTORY_HPP
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "../node/EthernetTapFactory.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class OSXEthernetTapFactory : public EthernetTapFactory
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create OSX ethernet tap factory
|
||||
*
|
||||
* If kext paths are specified, an attempt will be made to load the kext
|
||||
* on launch if not present and unload it on shutdown.
|
||||
*
|
||||
* @param pathToTapKext Full path to the location of the tap kext
|
||||
* @param tapKextName Name of tap kext as found within tap kext path (usually "tap.kext")
|
||||
* @throws std::runtime_error Tap not available and unable to load kext
|
||||
*/
|
||||
OSXEthernetTapFactory(const char *pathToTapKext,const char *tapKextName);
|
||||
|
||||
virtual ~OSXEthernetTapFactory();
|
||||
|
||||
virtual EthernetTap *open(
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *desiredDevice,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||
void *arg);
|
||||
virtual void close(EthernetTap *tap,bool destroyPersistentDevices);
|
||||
|
||||
private:
|
||||
std::vector<EthernetTap *> _devices;
|
||||
Mutex _devices_m;
|
||||
std::string _pathToTapKext;
|
||||
std::string _tapKextName;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -456,6 +456,11 @@ typedef struct
|
||||
*/
|
||||
int portError;
|
||||
|
||||
/**
|
||||
* Is this network enabled? If not, all frames to/from are dropped.
|
||||
*/
|
||||
int enabled;
|
||||
|
||||
/**
|
||||
* Network config revision as reported by netconf master
|
||||
*
|
||||
|
@ -154,11 +154,6 @@
|
||||
*/
|
||||
#define ZT_IF_MTU ZT1_MAX_MTU
|
||||
|
||||
/**
|
||||
* Default interface metric for ZeroTier taps -- should be higher than physical ports
|
||||
*/
|
||||
#define ZT_DEFAULT_IF_METRIC 32768
|
||||
|
||||
/**
|
||||
* Maximum number of packet fragments we'll support
|
||||
*
|
||||
@ -313,14 +308,14 @@
|
||||
#define ZT_ANTIRECURSION_HISTORY_SIZE 16
|
||||
|
||||
/**
|
||||
* How often to broadcast beacons over physical local LANs
|
||||
* How often to send LAN beacons
|
||||
*/
|
||||
#define ZT_BEACON_INTERVAL 30000
|
||||
|
||||
/**
|
||||
* Do not respond to any beacon more often than this
|
||||
*/
|
||||
#define ZT_MIN_BEACON_RESPONSE_INTERVAL (ZT_BEACON_INTERVAL / 32)
|
||||
#define ZT_MIN_BEACON_RESPONSE_INTERVAL 2500
|
||||
|
||||
/**
|
||||
* Sanity limit on maximum bridge routes
|
||||
|
@ -436,7 +436,12 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now)
|
||||
void Network::setEnabled(bool enabled)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
_enabled = enabled;
|
||||
if (_enabled != enabled) {
|
||||
_enabled = enabled;
|
||||
ZT1_VirtualNetworkConfig ctmp;
|
||||
_externalConfig(&ctmp);
|
||||
_portError = RR->node->configureVirtualNetworkPort(_id,ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE,&ctmp);
|
||||
}
|
||||
}
|
||||
|
||||
void Network::destroy()
|
||||
@ -478,6 +483,7 @@ void Network::_externalConfig(ZT1_VirtualNetworkConfig *ec) const
|
||||
ec->bridge = (_config) ? ((_config->allowPassiveBridging() || (std::find(_config->activeBridges().begin(),_config->activeBridges().end(),RR->identity.address()) != _config->activeBridges().end())) ? 1 : 0) : 0;
|
||||
ec->broadcastEnabled = (_config) ? (_config->enableBroadcast() ? 1 : 0) : 0;
|
||||
ec->portError = _portError;
|
||||
ec->enabled = (_enabled) ? 1 : 0;
|
||||
ec->netconfRevision = (_config) ? (unsigned long)_config->revision() : 0;
|
||||
|
||||
ec->multicastSubscriptionCount = std::min((unsigned int)_myMulticastGroups.size(),(unsigned int)ZT1_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS);
|
||||
|
@ -348,7 +348,7 @@ private:
|
||||
const RuntimeEnvironment *RR;
|
||||
uint64_t _id;
|
||||
MAC _mac; // local MAC address
|
||||
volatile bool _enabled;
|
||||
bool _enabled;
|
||||
|
||||
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to including those behind us (updated periodically)
|
||||
std::map< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups bridged to us and when we last saw activity on each
|
||||
|
@ -263,6 +263,7 @@ static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp)
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "OSXEthernetTap.hpp"
|
||||
|
||||
// ff:ff:ff:ff:ff:ff with no ADI
|
||||
@ -311,23 +312,27 @@ static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptR
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
static long globalTapsRunning = 0;
|
||||
static Mutex globalTapCreateLock;
|
||||
|
||||
OSXEthernetTap::OSXEthernetTap(
|
||||
const char *homePath,
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *desiredDevice,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||
void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len),
|
||||
void *arg) :
|
||||
_handler(handler),
|
||||
_arg(arg),
|
||||
_nwid(nwid),
|
||||
_homePath(homePath),
|
||||
_mtu(mtu),
|
||||
_metric(metric),
|
||||
_fd(0),
|
||||
_enabled(true)
|
||||
{
|
||||
static Mutex globalTapCreateLock;
|
||||
char devpath[64],ethaddr[64],mtustr[32],metstr[32];
|
||||
struct stat stattmp;
|
||||
|
||||
@ -335,11 +340,29 @@ OSXEthernetTap::OSXEthernetTap(
|
||||
|
||||
if (mtu > 2800)
|
||||
throw std::runtime_error("max tap MTU is 2800");
|
||||
if (stat("/dev/zt0",&stattmp))
|
||||
throw std::runtime_error("/dev/zt# tap devices do not exist");
|
||||
|
||||
if (stat("/dev/zt0",&stattmp)) {
|
||||
if (homePath) {
|
||||
long kextpid = (long)vfork();
|
||||
if (kextpid == 0) {
|
||||
::chdir(homePath);
|
||||
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
|
||||
::execl("/sbin/kextload","/sbin/kextload","-q","-repository",homePath,"tap.kext",(const char *)0);
|
||||
::_exit(-1);
|
||||
} else if (kextpid > 0) {
|
||||
int exitcode = -1;
|
||||
::waitpid(kextpid,&exitcode,0);
|
||||
}
|
||||
::usleep(500); // give tap device driver time to start up and try again
|
||||
if (stat("/dev/zt0",&stattmp))
|
||||
throw std::runtime_error("/dev/zt# tap devices do not exist and cannot load tap.kext");
|
||||
}
|
||||
throw std::runtime_error("/dev/zt# tap devices do not exist and tap.kext not available");
|
||||
}
|
||||
|
||||
// Try to reopen the last device we had, if we had one and it's still unused.
|
||||
bool recalledDevice = false;
|
||||
/*
|
||||
if ((desiredDevice)&&(desiredDevice[0] == 'z')&&(desiredDevice[1] == 't')) {
|
||||
if ((strchr(desiredDevice,'/'))||(strchr(desiredDevice,'.'))) // security sanity check
|
||||
throw std::runtime_error("invalid desiredDevice parameter");
|
||||
@ -352,6 +375,7 @@ OSXEthernetTap::OSXEthernetTap(
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Open the first unused tap device if we didn't recall a previous one.
|
||||
if (!recalledDevice) {
|
||||
@ -402,15 +426,37 @@ OSXEthernetTap::OSXEthernetTap(
|
||||
::pipe(_shutdownSignalPipe);
|
||||
|
||||
_thread = Thread::start(this);
|
||||
|
||||
++globalTapsRunning;
|
||||
}
|
||||
|
||||
OSXEthernetTap::~OSXEthernetTap()
|
||||
{
|
||||
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
|
||||
Thread::join(_thread);
|
||||
|
||||
::close(_fd);
|
||||
::close(_shutdownSignalPipe[0]);
|
||||
::close(_shutdownSignalPipe[1]);
|
||||
|
||||
{
|
||||
Mutex::Lock _gl(globalTapCreateLock);
|
||||
if (--globalTapsRunning <= 0) {
|
||||
globalTapsRunning = 0; // sanity check -- should not be possible
|
||||
|
||||
char tmp[16384];
|
||||
sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext");
|
||||
long kextpid = (long)vfork();
|
||||
if (kextpid == 0) {
|
||||
OSUtils::redirectUnixOutputs("/dev/null",(const char *)0);
|
||||
::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0);
|
||||
::_exit(-1);
|
||||
} else if (kextpid > 0) {
|
||||
int exitcode = -1;
|
||||
::waitpid(kextpid,&exitcode,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OSXEthernetTap::setEnabled(bool en)
|
||||
@ -438,17 +484,17 @@ static bool ___removeIp(const std::string &_dev,const InetAddress &ip)
|
||||
return false; // never reached, make compiler shut up about return value
|
||||
}
|
||||
|
||||
bool OSXEthernetTap::addIP(const InetAddress &ip)
|
||||
bool OSXEthernetTap::addIp(const InetAddress &ip)
|
||||
{
|
||||
if (!ip)
|
||||
return false;
|
||||
|
||||
std::set<InetAddress> allIps(ips());
|
||||
if (allIps.count(ip) > 0)
|
||||
return true; // IP/netmask already assigned
|
||||
std::vector<InetAddress> allIps(ips());
|
||||
if (std::binary_search(allIps.begin(),allIps.end(),ip))
|
||||
return true;
|
||||
|
||||
// Remove and reconfigure if address is the same but netmask is different
|
||||
for(std::set<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
|
||||
for(std::vector<InetAddress>::iterator i(allIps.begin());i!=allIps.end();++i) {
|
||||
if ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
|
||||
if (___removeIp(_dev,*i))
|
||||
break;
|
||||
@ -463,26 +509,30 @@ bool OSXEthernetTap::addIP(const InetAddress &ip)
|
||||
int exitcode = -1;
|
||||
::waitpid(cpid,&exitcode,0);
|
||||
return (exitcode == 0);
|
||||
}
|
||||
} // else return false...
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool OSXEthernetTap::removeIP(const InetAddress &ip)
|
||||
bool OSXEthernetTap::removeIp(const InetAddress &ip)
|
||||
{
|
||||
if (ips().count(ip) > 0) {
|
||||
if (!ip)
|
||||
return true;
|
||||
std::vector<InetAddress> allIps(ips());
|
||||
if (!std::binary_search(allIps.begin(),allIps.end(),ip)) {
|
||||
if (___removeIp(_dev,ip))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::set<InetAddress> OSXEthernetTap::ips() const
|
||||
std::vector<InetAddress> OSXEthernetTap::ips() const
|
||||
{
|
||||
struct ifaddrs *ifa = (struct ifaddrs *)0;
|
||||
if (getifaddrs(&ifa))
|
||||
return std::set<InetAddress>();
|
||||
return std::vector<InetAddress>();
|
||||
|
||||
std::set<InetAddress> r;
|
||||
std::vector<InetAddress> r;
|
||||
|
||||
struct ifaddrs *p = ifa;
|
||||
while (p) {
|
||||
@ -491,14 +541,14 @@ std::set<InetAddress> OSXEthernetTap::ips() const
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
|
||||
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
|
||||
r.insert(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
|
||||
r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr)));
|
||||
} break;
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
|
||||
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
|
||||
uint32_t b[4];
|
||||
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
|
||||
r.insert(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
|
||||
r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3])));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
@ -508,6 +558,9 @@ std::set<InetAddress> OSXEthernetTap::ips() const
|
||||
if (ifa)
|
||||
freeifaddrs(ifa);
|
||||
|
||||
std::sort(r.begin(),r.end());
|
||||
std::unique(r.begin(),r.end());
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -533,9 +586,10 @@ void OSXEthernetTap::setFriendlyName(const char *friendlyName)
|
||||
{
|
||||
}
|
||||
|
||||
bool OSXEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
|
||||
void OSXEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed)
|
||||
{
|
||||
std::set<MulticastGroup> newGroups;
|
||||
std::vector<MulticastGroup> newGroups;
|
||||
|
||||
struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0;
|
||||
if (!_intl_getifmaddrs(&ifmap)) {
|
||||
struct _intl_ifmaddrs *p = ifmap;
|
||||
@ -544,35 +598,30 @@ bool OSXEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
|
||||
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name;
|
||||
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
|
||||
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen)))
|
||||
newGroups.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
|
||||
newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0));
|
||||
}
|
||||
p = p->ifma_next;
|
||||
}
|
||||
_intl_freeifmaddrs(ifmap);
|
||||
}
|
||||
|
||||
{
|
||||
std::set<InetAddress> allIps(ips());
|
||||
for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i)
|
||||
newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
|
||||
std::vector<InetAddress> allIps(ips());
|
||||
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
|
||||
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
|
||||
|
||||
std::sort(newGroups.begin(),newGroups.end());
|
||||
std::unique(newGroups.begin(),newGroups.end());
|
||||
|
||||
for(std::vector<MulticastGroup>::iterator m(newGroups.begin());m!=newGroups.end();++m) {
|
||||
if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m))
|
||||
added.push_back(*m);
|
||||
}
|
||||
for(std::vector<MulticastGroup>::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) {
|
||||
if (!std::binary_search(newGroups.begin(),newGroups.end(),*m))
|
||||
removed.push_back(*m);
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
|
||||
for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) {
|
||||
if (!groups.count(*mg)) {
|
||||
groups.insert(*mg);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
|
||||
if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
|
||||
groups.erase(mg++);
|
||||
changed = true;
|
||||
} else ++mg;
|
||||
}
|
||||
|
||||
return changed;
|
||||
_multicastGroups.swap(newGroups);
|
||||
}
|
||||
|
||||
void OSXEthernetTap::threadMain()
|
||||
@ -582,7 +631,6 @@ void OSXEthernetTap::threadMain()
|
||||
MAC to,from;
|
||||
int n,nfds,r;
|
||||
char getBuf[8194];
|
||||
Buffer<4096> data;
|
||||
|
||||
// Wait for a moment after startup -- wait for Network to finish
|
||||
// constructing itself.
|
||||
@ -619,8 +667,8 @@ void OSXEthernetTap::threadMain()
|
||||
to.setTo(getBuf,6);
|
||||
from.setTo(getBuf + 6,6);
|
||||
unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
|
||||
data.copyFrom(getBuf + 14,(unsigned int)r - 14);
|
||||
_handler(_arg,from,to,etherType,data);
|
||||
// TODO: VLAN support
|
||||
_handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14);
|
||||
}
|
||||
|
||||
r = 0;
|
||||
|
@ -32,10 +32,11 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/MAC.hpp"
|
||||
#include "../node/Buffer.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/MulticastGroup.hpp"
|
||||
|
||||
@ -50,35 +51,38 @@ class OSXEthernetTap
|
||||
{
|
||||
public:
|
||||
OSXEthernetTap(
|
||||
const char *homePath,
|
||||
const MAC &mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
const char *desiredDevice,
|
||||
const char *friendlyName,
|
||||
void (*handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &),
|
||||
void (*handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int),
|
||||
void *arg);
|
||||
|
||||
~OSXEthernetTap();
|
||||
|
||||
void setEnabled(bool en);
|
||||
bool enabled() const;
|
||||
bool addIP(const InetAddress &ip);
|
||||
bool removeIP(const InetAddress &ip);
|
||||
std::set<InetAddress> ips() const;
|
||||
bool addIp(const InetAddress &ip);
|
||||
bool removeIp(const InetAddress &ip);
|
||||
std::vector<InetAddress> ips() const;
|
||||
void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
|
||||
std::string deviceName() const;
|
||||
void setFriendlyName(const char *friendlyName);
|
||||
bool updateMulticastGroups(std::set<MulticastGroup> &groups);
|
||||
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
|
||||
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
private:
|
||||
void (*_handler)(void *,const MAC &,const MAC &,unsigned int,const Buffer<4096> &);
|
||||
void (*_handler)(void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int);
|
||||
void *_arg;
|
||||
uint64_t _nwid;
|
||||
Thread _thread;
|
||||
std::string _homePath;
|
||||
std::string _dev;
|
||||
std::vector<MulticastGroup> _multicastGroups;
|
||||
unsigned int _mtu;
|
||||
unsigned int _metric;
|
||||
int _fd;
|
||||
|
111
service/One.cpp
111
service/One.cpp
@ -45,6 +45,7 @@
|
||||
#include "../node/Node.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/MAC.hpp"
|
||||
|
||||
#include "../osdep/Phy.hpp"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
@ -61,6 +62,12 @@ namespace ZeroTier { typedef OSXEthernetTap EthernetTap; }
|
||||
#define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 8)
|
||||
#define ZT_MAX_HTTP_CONNECTIONS 64
|
||||
|
||||
// Interface metric for ZeroTier taps
|
||||
#define ZT_IF_METRIC 32768
|
||||
|
||||
// How often to check for new multicast subscriptions on a tap device
|
||||
#define ZT_TAP_CHECK_MULTICAST_INTERVAL 30000
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
// Used to convert HTTP header names to ASCII lower case
|
||||
@ -75,6 +82,8 @@ static int SnodeDataStorePutFunction(ZT1_Node *node,void *uptr,const char *name,
|
||||
static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,const struct sockaddr_storage *addr,unsigned int desperation,const void *data,unsigned int len);
|
||||
static void SnodeVirtualNetworkFrameFunction(ZT1_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
|
||||
|
||||
static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
|
||||
|
||||
static int ShttpOnMessageBegin(http_parser *parser);
|
||||
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length);
|
||||
static int ShttpOnStatus(http_parser *parser,const char *ptr,size_t length);
|
||||
@ -206,6 +215,7 @@ public:
|
||||
}
|
||||
|
||||
_nextBackgroundTaskDeadline = 0;
|
||||
uint64_t lastTapMulticastGroupCheck = 0;
|
||||
for(;;) {
|
||||
_run_m.lock();
|
||||
if (!_run) {
|
||||
@ -220,13 +230,20 @@ public:
|
||||
uint64_t now = OSUtils::now();
|
||||
|
||||
if (dl <= now) {
|
||||
if ((now - lastTapMulticastGroupCheck) >= ZT_TAP_CHECK_MULTICAST_INTERVAL) {
|
||||
lastTapMulticastGroupCheck = now;
|
||||
Mutex::Lock _l(_taps_m);
|
||||
for(std::map< uint64_t,EthernetTap *>::const_iterator t(_taps.begin());t!=_taps.end();++t)
|
||||
_updateMulticastGroups(t->first,t->second);
|
||||
}
|
||||
|
||||
_node->processBackgroundTasks(now,&_nextBackgroundTaskDeadline);
|
||||
|
||||
dl = _nextBackgroundTaskDeadline;
|
||||
now = OSUtils::now();
|
||||
}
|
||||
|
||||
const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100;
|
||||
//printf("polling: %lums timeout\n",delay);
|
||||
_phy.poll(delay);
|
||||
}
|
||||
} catch (std::exception &exc) {
|
||||
@ -244,6 +261,13 @@ public:
|
||||
_phy.close(_httpConnections.begin()->first);
|
||||
} catch ( ... ) {}
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_taps_m);
|
||||
for(std::map< uint64_t,EthernetTap * >::iterator t(_taps.begin());t!=_taps.end();++t)
|
||||
delete t->second;
|
||||
_taps.clear();
|
||||
}
|
||||
|
||||
delete _controlPlane;
|
||||
_controlPlane = (ControlPlane *)0;
|
||||
delete _node;
|
||||
@ -365,8 +389,65 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwconf)
|
||||
inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwc)
|
||||
{
|
||||
Mutex::Lock _l(_taps_m);
|
||||
std::map< uint64_t,EthernetTap * >::iterator t(_taps.find(nwid));
|
||||
switch(op) {
|
||||
case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_UP:
|
||||
if (t == _taps.end()) {
|
||||
try {
|
||||
char friendlyName[1024];
|
||||
Utils::snprintf(friendlyName,sizeof(friendlyName),"ZeroTier One [%.16llx]",nwid);
|
||||
t = _taps.insert(std::pair< uint64_t,EthernetTap *>(nwid,new EthernetTap(
|
||||
_homePath.c_str(),
|
||||
MAC(nwc->mac),
|
||||
nwc->mtu,
|
||||
ZT_IF_METRIC,
|
||||
nwid,
|
||||
friendlyName,
|
||||
StapFrameHandler,
|
||||
(void *)this))).first;
|
||||
} catch ( ... ) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
// fall through...
|
||||
case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE:
|
||||
if (t != _taps.end()) {
|
||||
t->second->setEnabled(nwc->enabled != 0);
|
||||
|
||||
std::vector<InetAddress> &assignedIps = _tapAssignedIps[nwid];
|
||||
std::vector<InetAddress> newAssignedIps;
|
||||
for(unsigned int i=0;i<nwc->assignedAddressCount;++i)
|
||||
newAssignedIps.push_back(InetAddress(nwc->assignedAddresses[i]));
|
||||
std::sort(newAssignedIps.begin(),newAssignedIps.end());
|
||||
std::unique(newAssignedIps.begin(),newAssignedIps.end());
|
||||
for(std::vector<InetAddress>::iterator ip(newAssignedIps.begin());ip!=newAssignedIps.end();++ip) {
|
||||
if (!std::binary_search(assignedIps.begin(),assignedIps.end(),*ip))
|
||||
t->second->addIp(*ip);
|
||||
}
|
||||
for(std::vector<InetAddress>::iterator ip(assignedIps.begin());ip!=assignedIps.end();++ip) {
|
||||
if (!std::binary_search(newAssignedIps.begin(),newAssignedIps.end(),*ip))
|
||||
t->second->removeIp(*ip);
|
||||
}
|
||||
assignedIps.swap(newAssignedIps);
|
||||
|
||||
_updateMulticastGroups(t->first,t->second);
|
||||
if (nwc->broadcastEnabled)
|
||||
_node->multicastSubscribe(nwid,0xffffffffffffULL,0);
|
||||
else _node->multicastUnsubscribe(nwid,0xffffffffffffULL,0);
|
||||
}
|
||||
break;
|
||||
case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN:
|
||||
case ZT1_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY:
|
||||
if (t != _taps.end()) {
|
||||
delete t->second;
|
||||
_taps.erase(t);
|
||||
_tapAssignedIps.erase(nwid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -466,8 +547,15 @@ public:
|
||||
|
||||
inline void nodeVirtualNetworkFrameFunction(uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
|
||||
{
|
||||
fprintf(stderr,"VIRTUAL NETWORK FRAME from %.16llx : %.12llx -> %.12llx %.4x %u bytes\n",nwid,sourceMac,destMac,etherType,len);
|
||||
fflush(stderr);
|
||||
Mutex::Lock _l(_taps_m);
|
||||
std::map< uint64_t,EthernetTap * >::const_iterator t(_taps.find(nwid));
|
||||
if (t != _taps.end())
|
||||
t->second->put(MAC(sourceMac),MAC(destMac),etherType,data,len);
|
||||
}
|
||||
|
||||
inline void tapFrameHandler(uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
|
||||
{
|
||||
_node->processVirtualNetworkFrame(OSUtils::now(),nwid,from.toInt(),to.toInt(),etherType,vlanId,data,len,&_nextBackgroundTaskDeadline);
|
||||
}
|
||||
|
||||
inline void onHttpRequestToServer(HttpConnection *htc)
|
||||
@ -539,6 +627,17 @@ private:
|
||||
return p;
|
||||
}
|
||||
|
||||
void _updateMulticastGroups(uint64_t nwid,EthernetTap *tap)
|
||||
{
|
||||
// assumes _taps_m is locked
|
||||
std::vector<MulticastGroup> added,removed;
|
||||
tap->scanMulticastGroups(added,removed);
|
||||
for(std::vector<MulticastGroup>::iterator m(added.begin());m!=added.end();++m)
|
||||
_node->multicastSubscribe(nwid,m->mac().toInt(),m->adi());
|
||||
for(std::vector<MulticastGroup>::iterator m(removed.begin());m!=removed.end();++m)
|
||||
_node->multicastUnsubscribe(nwid,m->mac().toInt(),m->adi());
|
||||
}
|
||||
|
||||
const std::string _homePath;
|
||||
Phy<OneImpl *> _phy;
|
||||
NetworkConfigMaster *_master;
|
||||
@ -552,6 +651,7 @@ private:
|
||||
uint64_t _nextBackgroundTaskDeadline;
|
||||
|
||||
std::map< uint64_t,EthernetTap * > _taps;
|
||||
std::map< uint64_t,std::vector<InetAddress> > _tapAssignedIps; // ZeroTier assigned IPs, not user or dhcp assigned
|
||||
Mutex _taps_m;
|
||||
|
||||
std::map< PhySocket *,HttpConnection > _httpConnections; // no mutex for this since it's done in the main loop thread only
|
||||
@ -577,6 +677,9 @@ static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,const struct so
|
||||
static void SnodeVirtualNetworkFrameFunction(ZT1_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
|
||||
{ reinterpret_cast<OneImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,sourceMac,destMac,etherType,vlanId,data,len); }
|
||||
|
||||
static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
|
||||
{ reinterpret_cast<OneImpl *>(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); }
|
||||
|
||||
static int ShttpOnMessageBegin(http_parser *parser)
|
||||
{
|
||||
HttpConnection *htc = reinterpret_cast<HttpConnection *>(parser->data);
|
||||
|
@ -112,7 +112,7 @@ public:
|
||||
virtual std::string fatalErrorMessage() const = 0;
|
||||
|
||||
/**
|
||||
* @return System device name corresponding with a given ZeroTier network ID
|
||||
* @return System device name corresponding with a given ZeroTier network ID or empty string if not opened yet or network ID not found
|
||||
*/
|
||||
virtual std::string portDeviceName(uint64_t nwid) const = 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user