mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +02:00
Bunch of tap stuff, IP address assignment hookups, etc.
This commit is contained in:
parent
e205e5fdfe
commit
67f1f1892f
16 changed files with 227 additions and 1648 deletions
|
@ -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;
|
int portError;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this network enabled? If not, all frames to/from are dropped.
|
||||||
|
*/
|
||||||
|
int enabled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Network config revision as reported by netconf master
|
* Network config revision as reported by netconf master
|
||||||
*
|
*
|
||||||
|
|
|
@ -154,11 +154,6 @@
|
||||||
*/
|
*/
|
||||||
#define ZT_IF_MTU ZT1_MAX_MTU
|
#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
|
* Maximum number of packet fragments we'll support
|
||||||
*
|
*
|
||||||
|
@ -313,14 +308,14 @@
|
||||||
#define ZT_ANTIRECURSION_HISTORY_SIZE 16
|
#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
|
#define ZT_BEACON_INTERVAL 30000
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do not respond to any beacon more often than this
|
* 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
|
* Sanity limit on maximum bridge routes
|
||||||
|
|
|
@ -436,7 +436,12 @@ void Network::learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now)
|
||||||
void Network::setEnabled(bool enabled)
|
void Network::setEnabled(bool enabled)
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_lock);
|
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()
|
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->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->broadcastEnabled = (_config) ? (_config->enableBroadcast() ? 1 : 0) : 0;
|
||||||
ec->portError = _portError;
|
ec->portError = _portError;
|
||||||
|
ec->enabled = (_enabled) ? 1 : 0;
|
||||||
ec->netconfRevision = (_config) ? (unsigned long)_config->revision() : 0;
|
ec->netconfRevision = (_config) ? (unsigned long)_config->revision() : 0;
|
||||||
|
|
||||||
ec->multicastSubscriptionCount = std::min((unsigned int)_myMulticastGroups.size(),(unsigned int)ZT1_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS);
|
ec->multicastSubscriptionCount = std::min((unsigned int)_myMulticastGroups.size(),(unsigned int)ZT1_MAX_NETWORK_MULTICAST_SUBSCRIPTIONS);
|
||||||
|
|
|
@ -348,7 +348,7 @@ private:
|
||||||
const RuntimeEnvironment *RR;
|
const RuntimeEnvironment *RR;
|
||||||
uint64_t _id;
|
uint64_t _id;
|
||||||
MAC _mac; // local MAC address
|
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::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
|
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/Constants.hpp"
|
||||||
#include "../node/Utils.hpp"
|
#include "../node/Utils.hpp"
|
||||||
#include "../node/Mutex.hpp"
|
#include "../node/Mutex.hpp"
|
||||||
|
#include "OSUtils.hpp"
|
||||||
#include "OSXEthernetTap.hpp"
|
#include "OSXEthernetTap.hpp"
|
||||||
|
|
||||||
// ff:ff:ff:ff:ff:ff with no ADI
|
// 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 {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
static long globalTapsRunning = 0;
|
||||||
|
static Mutex globalTapCreateLock;
|
||||||
|
|
||||||
OSXEthernetTap::OSXEthernetTap(
|
OSXEthernetTap::OSXEthernetTap(
|
||||||
|
const char *homePath,
|
||||||
const MAC &mac,
|
const MAC &mac,
|
||||||
unsigned int mtu,
|
unsigned int mtu,
|
||||||
unsigned int metric,
|
unsigned int metric,
|
||||||
uint64_t nwid,
|
uint64_t nwid,
|
||||||
const char *desiredDevice,
|
|
||||||
const char *friendlyName,
|
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) :
|
void *arg) :
|
||||||
_handler(handler),
|
_handler(handler),
|
||||||
_arg(arg),
|
_arg(arg),
|
||||||
|
_nwid(nwid),
|
||||||
|
_homePath(homePath),
|
||||||
_mtu(mtu),
|
_mtu(mtu),
|
||||||
_metric(metric),
|
_metric(metric),
|
||||||
_fd(0),
|
_fd(0),
|
||||||
_enabled(true)
|
_enabled(true)
|
||||||
{
|
{
|
||||||
static Mutex globalTapCreateLock;
|
|
||||||
char devpath[64],ethaddr[64],mtustr[32],metstr[32];
|
char devpath[64],ethaddr[64],mtustr[32],metstr[32];
|
||||||
struct stat stattmp;
|
struct stat stattmp;
|
||||||
|
|
||||||
|
@ -335,11 +340,29 @@ OSXEthernetTap::OSXEthernetTap(
|
||||||
|
|
||||||
if (mtu > 2800)
|
if (mtu > 2800)
|
||||||
throw std::runtime_error("max tap MTU is 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.
|
// Try to reopen the last device we had, if we had one and it's still unused.
|
||||||
bool recalledDevice = false;
|
bool recalledDevice = false;
|
||||||
|
/*
|
||||||
if ((desiredDevice)&&(desiredDevice[0] == 'z')&&(desiredDevice[1] == 't')) {
|
if ((desiredDevice)&&(desiredDevice[0] == 'z')&&(desiredDevice[1] == 't')) {
|
||||||
if ((strchr(desiredDevice,'/'))||(strchr(desiredDevice,'.'))) // security sanity check
|
if ((strchr(desiredDevice,'/'))||(strchr(desiredDevice,'.'))) // security sanity check
|
||||||
throw std::runtime_error("invalid desiredDevice parameter");
|
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.
|
// Open the first unused tap device if we didn't recall a previous one.
|
||||||
if (!recalledDevice) {
|
if (!recalledDevice) {
|
||||||
|
@ -402,15 +426,37 @@ OSXEthernetTap::OSXEthernetTap(
|
||||||
::pipe(_shutdownSignalPipe);
|
::pipe(_shutdownSignalPipe);
|
||||||
|
|
||||||
_thread = Thread::start(this);
|
_thread = Thread::start(this);
|
||||||
|
|
||||||
|
++globalTapsRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSXEthernetTap::~OSXEthernetTap()
|
OSXEthernetTap::~OSXEthernetTap()
|
||||||
{
|
{
|
||||||
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
|
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
|
||||||
Thread::join(_thread);
|
Thread::join(_thread);
|
||||||
|
|
||||||
::close(_fd);
|
::close(_fd);
|
||||||
::close(_shutdownSignalPipe[0]);
|
::close(_shutdownSignalPipe[0]);
|
||||||
::close(_shutdownSignalPipe[1]);
|
::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)
|
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
|
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)
|
if (!ip)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::set<InetAddress> allIps(ips());
|
std::vector<InetAddress> allIps(ips());
|
||||||
if (allIps.count(ip) > 0)
|
if (std::binary_search(allIps.begin(),allIps.end(),ip))
|
||||||
return true; // IP/netmask already assigned
|
return true;
|
||||||
|
|
||||||
// Remove and reconfigure if address is the same but netmask is different
|
// 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 ((i->ipsEqual(ip))&&(i->netmaskBits() != ip.netmaskBits())) {
|
||||||
if (___removeIp(_dev,*i))
|
if (___removeIp(_dev,*i))
|
||||||
break;
|
break;
|
||||||
|
@ -463,26 +509,30 @@ bool OSXEthernetTap::addIP(const InetAddress &ip)
|
||||||
int exitcode = -1;
|
int exitcode = -1;
|
||||||
::waitpid(cpid,&exitcode,0);
|
::waitpid(cpid,&exitcode,0);
|
||||||
return (exitcode == 0);
|
return (exitcode == 0);
|
||||||
}
|
} // else return false...
|
||||||
|
|
||||||
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))
|
if (___removeIp(_dev,ip))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<InetAddress> OSXEthernetTap::ips() const
|
std::vector<InetAddress> OSXEthernetTap::ips() const
|
||||||
{
|
{
|
||||||
struct ifaddrs *ifa = (struct ifaddrs *)0;
|
struct ifaddrs *ifa = (struct ifaddrs *)0;
|
||||||
if (getifaddrs(&ifa))
|
if (getifaddrs(&ifa))
|
||||||
return std::set<InetAddress>();
|
return std::vector<InetAddress>();
|
||||||
|
|
||||||
std::set<InetAddress> r;
|
std::vector<InetAddress> r;
|
||||||
|
|
||||||
struct ifaddrs *p = ifa;
|
struct ifaddrs *p = ifa;
|
||||||
while (p) {
|
while (p) {
|
||||||
|
@ -491,14 +541,14 @@ std::set<InetAddress> OSXEthernetTap::ips() const
|
||||||
case AF_INET: {
|
case AF_INET: {
|
||||||
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
|
struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr;
|
||||||
struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask;
|
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;
|
} break;
|
||||||
case AF_INET6: {
|
case AF_INET6: {
|
||||||
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
|
struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr;
|
||||||
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
|
struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask;
|
||||||
uint32_t b[4];
|
uint32_t b[4];
|
||||||
memcpy(b,nm->sin6_addr.s6_addr,sizeof(b));
|
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;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -508,6 +558,9 @@ std::set<InetAddress> OSXEthernetTap::ips() const
|
||||||
if (ifa)
|
if (ifa)
|
||||||
freeifaddrs(ifa);
|
freeifaddrs(ifa);
|
||||||
|
|
||||||
|
std::sort(r.begin(),r.end());
|
||||||
|
std::unique(r.begin(),r.end());
|
||||||
|
|
||||||
return r;
|
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;
|
struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0;
|
||||||
if (!_intl_getifmaddrs(&ifmap)) {
|
if (!_intl_getifmaddrs(&ifmap)) {
|
||||||
struct _intl_ifmaddrs *p = 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 *in = (struct sockaddr_dl *)p->ifma_name;
|
||||||
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr;
|
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)))
|
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;
|
p = p->ifma_next;
|
||||||
}
|
}
|
||||||
_intl_freeifmaddrs(ifmap);
|
_intl_freeifmaddrs(ifmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
std::vector<InetAddress> allIps(ips());
|
||||||
std::set<InetAddress> allIps(ips());
|
for(std::vector<InetAddress>::iterator ip(allIps.begin());ip!=allIps.end();++ip)
|
||||||
for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i)
|
newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip));
|
||||||
newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
|
|
||||||
|
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;
|
_multicastGroups.swap(newGroups);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OSXEthernetTap::threadMain()
|
void OSXEthernetTap::threadMain()
|
||||||
|
@ -582,7 +631,6 @@ void OSXEthernetTap::threadMain()
|
||||||
MAC to,from;
|
MAC to,from;
|
||||||
int n,nfds,r;
|
int n,nfds,r;
|
||||||
char getBuf[8194];
|
char getBuf[8194];
|
||||||
Buffer<4096> data;
|
|
||||||
|
|
||||||
// Wait for a moment after startup -- wait for Network to finish
|
// Wait for a moment after startup -- wait for Network to finish
|
||||||
// constructing itself.
|
// constructing itself.
|
||||||
|
@ -619,8 +667,8 @@ void OSXEthernetTap::threadMain()
|
||||||
to.setTo(getBuf,6);
|
to.setTo(getBuf,6);
|
||||||
from.setTo(getBuf + 6,6);
|
from.setTo(getBuf + 6,6);
|
||||||
unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
|
unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]);
|
||||||
data.copyFrom(getBuf + 14,(unsigned int)r - 14);
|
// TODO: VLAN support
|
||||||
_handler(_arg,from,to,etherType,data);
|
_handler(_arg,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
r = 0;
|
r = 0;
|
||||||
|
|
|
@ -32,10 +32,11 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "../node/Constants.hpp"
|
#include "../node/Constants.hpp"
|
||||||
#include "../node/MAC.hpp"
|
#include "../node/MAC.hpp"
|
||||||
#include "../node/Buffer.hpp"
|
|
||||||
#include "../node/InetAddress.hpp"
|
#include "../node/InetAddress.hpp"
|
||||||
#include "../node/MulticastGroup.hpp"
|
#include "../node/MulticastGroup.hpp"
|
||||||
|
|
||||||
|
@ -50,35 +51,38 @@ class OSXEthernetTap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
OSXEthernetTap(
|
OSXEthernetTap(
|
||||||
|
const char *homePath,
|
||||||
const MAC &mac,
|
const MAC &mac,
|
||||||
unsigned int mtu,
|
unsigned int mtu,
|
||||||
unsigned int metric,
|
unsigned int metric,
|
||||||
uint64_t nwid,
|
uint64_t nwid,
|
||||||
const char *desiredDevice,
|
|
||||||
const char *friendlyName,
|
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);
|
void *arg);
|
||||||
|
|
||||||
~OSXEthernetTap();
|
~OSXEthernetTap();
|
||||||
|
|
||||||
void setEnabled(bool en);
|
void setEnabled(bool en);
|
||||||
bool enabled() const;
|
bool enabled() const;
|
||||||
bool addIP(const InetAddress &ip);
|
bool addIp(const InetAddress &ip);
|
||||||
bool removeIP(const InetAddress &ip);
|
bool removeIp(const InetAddress &ip);
|
||||||
std::set<InetAddress> ips() const;
|
std::vector<InetAddress> ips() const;
|
||||||
void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
|
void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len);
|
||||||
std::string deviceName() const;
|
std::string deviceName() const;
|
||||||
void setFriendlyName(const char *friendlyName);
|
void setFriendlyName(const char *friendlyName);
|
||||||
bool updateMulticastGroups(std::set<MulticastGroup> &groups);
|
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
|
||||||
|
|
||||||
void threadMain()
|
void threadMain()
|
||||||
throw();
|
throw();
|
||||||
|
|
||||||
private:
|
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;
|
void *_arg;
|
||||||
|
uint64_t _nwid;
|
||||||
Thread _thread;
|
Thread _thread;
|
||||||
|
std::string _homePath;
|
||||||
std::string _dev;
|
std::string _dev;
|
||||||
|
std::vector<MulticastGroup> _multicastGroups;
|
||||||
unsigned int _mtu;
|
unsigned int _mtu;
|
||||||
unsigned int _metric;
|
unsigned int _metric;
|
||||||
int _fd;
|
int _fd;
|
||||||
|
|
111
service/One.cpp
111
service/One.cpp
|
@ -45,6 +45,7 @@
|
||||||
#include "../node/Node.hpp"
|
#include "../node/Node.hpp"
|
||||||
#include "../node/Utils.hpp"
|
#include "../node/Utils.hpp"
|
||||||
#include "../node/InetAddress.hpp"
|
#include "../node/InetAddress.hpp"
|
||||||
|
#include "../node/MAC.hpp"
|
||||||
|
|
||||||
#include "../osdep/Phy.hpp"
|
#include "../osdep/Phy.hpp"
|
||||||
#include "../osdep/OSUtils.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_MESSAGE_SIZE (1024 * 1024 * 8)
|
||||||
#define ZT_MAX_HTTP_CONNECTIONS 64
|
#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 {
|
namespace ZeroTier {
|
||||||
|
|
||||||
// Used to convert HTTP header names to ASCII lower case
|
// 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 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 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 ShttpOnMessageBegin(http_parser *parser);
|
||||||
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length);
|
static int ShttpOnUrl(http_parser *parser,const char *ptr,size_t length);
|
||||||
static int ShttpOnStatus(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;
|
_nextBackgroundTaskDeadline = 0;
|
||||||
|
uint64_t lastTapMulticastGroupCheck = 0;
|
||||||
for(;;) {
|
for(;;) {
|
||||||
_run_m.lock();
|
_run_m.lock();
|
||||||
if (!_run) {
|
if (!_run) {
|
||||||
|
@ -220,13 +230,20 @@ public:
|
||||||
uint64_t now = OSUtils::now();
|
uint64_t now = OSUtils::now();
|
||||||
|
|
||||||
if (dl <= 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);
|
_node->processBackgroundTasks(now,&_nextBackgroundTaskDeadline);
|
||||||
|
|
||||||
dl = _nextBackgroundTaskDeadline;
|
dl = _nextBackgroundTaskDeadline;
|
||||||
now = OSUtils::now();
|
now = OSUtils::now();
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100;
|
const unsigned long delay = (dl > now) ? (unsigned long)(dl - now) : 100;
|
||||||
//printf("polling: %lums timeout\n",delay);
|
|
||||||
_phy.poll(delay);
|
_phy.poll(delay);
|
||||||
}
|
}
|
||||||
} catch (std::exception &exc) {
|
} catch (std::exception &exc) {
|
||||||
|
@ -244,6 +261,13 @@ public:
|
||||||
_phy.close(_httpConnections.begin()->first);
|
_phy.close(_httpConnections.begin()->first);
|
||||||
} catch ( ... ) {}
|
} 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;
|
delete _controlPlane;
|
||||||
_controlPlane = (ControlPlane *)0;
|
_controlPlane = (ControlPlane *)0;
|
||||||
delete _node;
|
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;
|
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)
|
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);
|
Mutex::Lock _l(_taps_m);
|
||||||
fflush(stderr);
|
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)
|
inline void onHttpRequestToServer(HttpConnection *htc)
|
||||||
|
@ -539,6 +627,17 @@ private:
|
||||||
return p;
|
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;
|
const std::string _homePath;
|
||||||
Phy<OneImpl *> _phy;
|
Phy<OneImpl *> _phy;
|
||||||
NetworkConfigMaster *_master;
|
NetworkConfigMaster *_master;
|
||||||
|
@ -552,6 +651,7 @@ private:
|
||||||
uint64_t _nextBackgroundTaskDeadline;
|
uint64_t _nextBackgroundTaskDeadline;
|
||||||
|
|
||||||
std::map< uint64_t,EthernetTap * > _taps;
|
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;
|
Mutex _taps_m;
|
||||||
|
|
||||||
std::map< PhySocket *,HttpConnection > _httpConnections; // no mutex for this since it's done in the main loop thread only
|
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)
|
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); }
|
{ 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)
|
static int ShttpOnMessageBegin(http_parser *parser)
|
||||||
{
|
{
|
||||||
HttpConnection *htc = reinterpret_cast<HttpConnection *>(parser->data);
|
HttpConnection *htc = reinterpret_cast<HttpConnection *>(parser->data);
|
||||||
|
|
|
@ -112,7 +112,7 @@ public:
|
||||||
virtual std::string fatalErrorMessage() const = 0;
|
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;
|
virtual std::string portDeviceName(uint64_t nwid) const = 0;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue