|
|
|
|
@ -60,6 +60,7 @@
|
|
|
|
|
#include "../osdep/PortMapper.hpp" |
|
|
|
|
#include "../osdep/Binder.hpp" |
|
|
|
|
#include "../osdep/ManagedRoute.hpp" |
|
|
|
|
#include "../osdep/BlockingQueue.hpp" |
|
|
|
|
|
|
|
|
|
#include "OneService.hpp" |
|
|
|
|
#include "SoftwareUpdater.hpp" |
|
|
|
|
@ -174,9 +175,6 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; }
|
|
|
|
|
// TCP activity timeout
|
|
|
|
|
#define ZT_TCP_ACTIVITY_TIMEOUT 60000 |
|
|
|
|
|
|
|
|
|
// Number of receive path threads to start
|
|
|
|
|
#define ZT_INCOMING_PACKET_THREAD_POOL_SIZE 8 |
|
|
|
|
|
|
|
|
|
#if ZT_VAULT_SUPPORT |
|
|
|
|
size_t curlResponseWrite(void *ptr, size_t size, size_t nmemb, std::string *data) |
|
|
|
|
{ |
|
|
|
|
@ -440,6 +438,15 @@ struct TcpConnection
|
|
|
|
|
Mutex writeq_m; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct OneServiceIncomingPacket |
|
|
|
|
{ |
|
|
|
|
uint64_t now; |
|
|
|
|
int64_t sock; |
|
|
|
|
struct sockaddr_storage from; |
|
|
|
|
unsigned int size; |
|
|
|
|
uint8_t data[ZT_MAX_MTU]; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class OneServiceImpl : public OneService |
|
|
|
|
{ |
|
|
|
|
public: |
|
|
|
|
@ -465,17 +472,11 @@ public:
|
|
|
|
|
unsigned int _tertiaryPort; |
|
|
|
|
volatile unsigned int _udpPortPickerCounter; |
|
|
|
|
|
|
|
|
|
#ifdef ZT_INCOMING_PACKET_THREAD_POOL_SIZE |
|
|
|
|
struct { |
|
|
|
|
uint8_t data[2048]; |
|
|
|
|
std::thread thr; |
|
|
|
|
int64_t sock; |
|
|
|
|
struct sockaddr_storage from; |
|
|
|
|
int size; |
|
|
|
|
std::condition_variable cond; |
|
|
|
|
std::mutex lock; |
|
|
|
|
} _incomingPacketWorker[ZT_INCOMING_PACKET_THREAD_POOL_SIZE]; |
|
|
|
|
#endif |
|
|
|
|
unsigned long _incomingPacketConcurrency; |
|
|
|
|
std::vector<OneServiceIncomingPacket *> _incomingPacketMemoryPool; |
|
|
|
|
BlockingQueue<OneServiceIncomingPacket *> _incomingPacketQueue; |
|
|
|
|
std::vector<std::thread> _incomingPacketThreads; |
|
|
|
|
Mutex _incomingPacketMemoryPoolLock,_incomingPacketThreadsLock; |
|
|
|
|
|
|
|
|
|
// Local configuration and memo-ized information from it
|
|
|
|
|
json _localConfig; |
|
|
|
|
@ -606,37 +607,33 @@ public:
|
|
|
|
|
_ports[1] = 0; |
|
|
|
|
_ports[2] = 0; |
|
|
|
|
|
|
|
|
|
#ifdef ZT_INCOMING_PACKET_THREAD_POOL_SIZE |
|
|
|
|
for(unsigned int tn=0;tn<ZT_INCOMING_PACKET_THREAD_POOL_SIZE;++tn) { |
|
|
|
|
_incomingPacketWorker[tn].thr = std::thread([this,tn]() { |
|
|
|
|
std::unique_lock<std::mutex> l(_incomingPacketWorker[tn].lock); |
|
|
|
|
_incomingPacketConcurrency = std::max((unsigned long)1,std::min((unsigned long)16,(unsigned long)std::thread::hardware_concurrency())); |
|
|
|
|
for(long t=0;t<_incomingPacketConcurrency;++t) { |
|
|
|
|
_incomingPacketThreads.push_back(std::thread([this]() { |
|
|
|
|
OneServiceIncomingPacket *pkt = nullptr; |
|
|
|
|
for(;;) { |
|
|
|
|
_incomingPacketWorker[tn].cond.wait(l); |
|
|
|
|
if (_incomingPacketWorker[tn].size < 0) { |
|
|
|
|
if (!_incomingPacketQueue.get(pkt)) |
|
|
|
|
break; |
|
|
|
|
if (!pkt) |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
const ZT_ResultCode rc = _node->processWirePacket(nullptr,pkt->now,pkt->sock,&(pkt->from),pkt->data,pkt->size,&_nextBackgroundTaskDeadline); |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock l(_incomingPacketMemoryPoolLock); |
|
|
|
|
_incomingPacketMemoryPool.push_back(pkt); |
|
|
|
|
} |
|
|
|
|
if (ZT_ResultCode_isFatal(rc)) { |
|
|
|
|
char tmp[256]; |
|
|
|
|
OSUtils::ztsnprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); |
|
|
|
|
Mutex::Lock _l(_termReason_m); |
|
|
|
|
_termReason = ONE_UNRECOVERABLE_ERROR; |
|
|
|
|
_fatalErrorMessage = tmp; |
|
|
|
|
this->terminate(); |
|
|
|
|
break; |
|
|
|
|
} else if (_incomingPacketWorker[tn].size > 0) { |
|
|
|
|
const ZT_ResultCode rc = _node->processWirePacket( |
|
|
|
|
(void *)0, |
|
|
|
|
OSUtils::now(), |
|
|
|
|
_incomingPacketWorker[tn].sock, |
|
|
|
|
&(_incomingPacketWorker[tn].from), |
|
|
|
|
_incomingPacketWorker[tn].data, |
|
|
|
|
(unsigned int)_incomingPacketWorker[tn].size, |
|
|
|
|
&_nextBackgroundTaskDeadline); |
|
|
|
|
if (ZT_ResultCode_isFatal(rc)) { |
|
|
|
|
char tmp[256]; |
|
|
|
|
OSUtils::ztsnprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); |
|
|
|
|
Mutex::Lock _l(_termReason_m); |
|
|
|
|
_termReason = ONE_UNRECOVERABLE_ERROR; |
|
|
|
|
_fatalErrorMessage = tmp; |
|
|
|
|
this->terminate(); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
})); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
#if ZT_VAULT_SUPPORT |
|
|
|
|
curl_global_init(CURL_GLOBAL_DEFAULT); |
|
|
|
|
@ -645,24 +642,27 @@ public:
|
|
|
|
|
|
|
|
|
|
virtual ~OneServiceImpl() |
|
|
|
|
{ |
|
|
|
|
#ifdef ZT_INCOMING_PACKET_THREAD_POOL_SIZE |
|
|
|
|
for(unsigned int tn=0;tn<ZT_INCOMING_PACKET_THREAD_POOL_SIZE;++tn) { |
|
|
|
|
_incomingPacketWorker[tn].lock.lock(); |
|
|
|
|
_incomingPacketWorker[tn].size = -1; |
|
|
|
|
_incomingPacketWorker[tn].lock.unlock(); |
|
|
|
|
_incomingPacketWorker[tn].cond.notify_all(); |
|
|
|
|
} |
|
|
|
|
for(unsigned int tn=0;tn<ZT_INCOMING_PACKET_THREAD_POOL_SIZE;++tn) { |
|
|
|
|
_incomingPacketWorker[tn].thr.join(); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
_incomingPacketQueue.stop(); |
|
|
|
|
_incomingPacketThreadsLock.lock(); |
|
|
|
|
for(auto t=_incomingPacketThreads.begin();t!=_incomingPacketThreads.end();++t) |
|
|
|
|
t->join(); |
|
|
|
|
_incomingPacketThreadsLock.unlock(); |
|
|
|
|
|
|
|
|
|
_binder.closeAll(_phy); |
|
|
|
|
_phy.close(_localControlSocket4); |
|
|
|
|
_phy.close(_localControlSocket6); |
|
|
|
|
|
|
|
|
|
#if ZT_VAULT_SUPPORT |
|
|
|
|
curl_global_cleanup(); |
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
_incomingPacketMemoryPoolLock.lock(); |
|
|
|
|
while (!_incomingPacketMemoryPool.empty()) { |
|
|
|
|
delete _incomingPacketMemoryPool.back(); |
|
|
|
|
_incomingPacketMemoryPool.pop_back(); |
|
|
|
|
} |
|
|
|
|
_incomingPacketMemoryPoolLock.unlock(); |
|
|
|
|
|
|
|
|
|
#ifdef ZT_USE_MINIUPNPC |
|
|
|
|
delete _portMapper; |
|
|
|
|
#endif |
|
|
|
|
@ -1900,39 +1900,27 @@ public:
|
|
|
|
|
|
|
|
|
|
inline void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len) |
|
|
|
|
{ |
|
|
|
|
const uint64_t now = OSUtils::now(); |
|
|
|
|
if ((len >= 16)&&(reinterpret_cast<const InetAddress *>(from)->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) |
|
|
|
|
_lastDirectReceiveFromGlobal = OSUtils::now(); |
|
|
|
|
#ifdef ZT_INCOMING_PACKET_THREAD_POOL_SIZE |
|
|
|
|
unsigned long cksum = 0; |
|
|
|
|
for(unsigned int i=0;i<sizeof(struct sockaddr_storage);++i) { |
|
|
|
|
cksum += ((uint8_t *)from)[i]; |
|
|
|
|
} |
|
|
|
|
const unsigned long tn = cksum % ZT_INCOMING_PACKET_THREAD_POOL_SIZE; |
|
|
|
|
_incomingPacketWorker[tn].lock.lock(); |
|
|
|
|
memcpy(_incomingPacketWorker[tn].data,data,len); |
|
|
|
|
_incomingPacketWorker[tn].sock = reinterpret_cast<int64_t>(sock); |
|
|
|
|
memcpy(&_incomingPacketWorker[tn].from,from,sizeof(struct sockaddr_storage)); |
|
|
|
|
_incomingPacketWorker[tn].size = (int)len; |
|
|
|
|
_incomingPacketWorker[tn].lock.unlock(); |
|
|
|
|
_incomingPacketWorker[tn].cond.notify_all(); |
|
|
|
|
#else |
|
|
|
|
const ZT_ResultCode rc = _node->processWirePacket( |
|
|
|
|
(void *)0, |
|
|
|
|
OSUtils::now(), |
|
|
|
|
reinterpret_cast<int64_t>(sock), |
|
|
|
|
reinterpret_cast<const struct sockaddr_storage *>(from), // Phy<> uses sockaddr_storage, so it'll always be that big
|
|
|
|
|
data, |
|
|
|
|
len, |
|
|
|
|
&_nextBackgroundTaskDeadline); |
|
|
|
|
if (ZT_ResultCode_isFatal(rc)) { |
|
|
|
|
char tmp[256]; |
|
|
|
|
OSUtils::ztsnprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); |
|
|
|
|
Mutex::Lock _l(_termReason_m); |
|
|
|
|
_termReason = ONE_UNRECOVERABLE_ERROR; |
|
|
|
|
_fatalErrorMessage = tmp; |
|
|
|
|
this->terminate(); |
|
|
|
|
_lastDirectReceiveFromGlobal = now; |
|
|
|
|
|
|
|
|
|
OneServiceIncomingPacket *pkt; |
|
|
|
|
_incomingPacketMemoryPoolLock.lock(); |
|
|
|
|
if (_incomingPacketMemoryPool.empty()) { |
|
|
|
|
pkt = new OneServiceIncomingPacket; |
|
|
|
|
} else { |
|
|
|
|
pkt = _incomingPacketMemoryPool.back(); |
|
|
|
|
_incomingPacketMemoryPool.pop_back(); |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
_incomingPacketMemoryPoolLock.unlock(); |
|
|
|
|
|
|
|
|
|
pkt->now = now; |
|
|
|
|
pkt->sock = reinterpret_cast<int64_t>(sock); |
|
|
|
|
ZT_FAST_MEMCPY(&(pkt->from),from,sizeof(struct sockaddr_storage)); |
|
|
|
|
pkt->size = (unsigned int)len; |
|
|
|
|
ZT_FAST_MEMCPY(pkt->data,data,len); |
|
|
|
|
|
|
|
|
|
_incomingPacketQueue.postLimit(pkt,16 * _incomingPacketConcurrency); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) |
|
|
|
|
|