mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +02:00
CLI debugging, got rid of nasty old Thread class and replaced with newer cleaner portable idiom.
This commit is contained in:
parent
3368330b77
commit
a7c4cbe53a
17 changed files with 141 additions and 303 deletions
|
@ -24,12 +24,16 @@ LIBS=ext/bin/libcrypto/linux-$(ARCH)/libcrypto.a -lm -ldl
|
||||||
|
|
||||||
include objects.mk
|
include objects.mk
|
||||||
|
|
||||||
all: one launcher
|
all: one cli launcher
|
||||||
|
|
||||||
one: $(OBJS)
|
one: $(OBJS)
|
||||||
$(CXX) $(CXXFLAGS) -o zerotier-one main.cpp $(OBJS) $(LIBS)
|
$(CXX) $(CXXFLAGS) -o zerotier-one main.cpp $(OBJS) $(LIBS)
|
||||||
$(STRIP) zerotier-one
|
$(STRIP) zerotier-one
|
||||||
|
|
||||||
|
cli: $(OBJS)
|
||||||
|
$(CXX) $(CXXFLAGS) -o zerotier-cli cli.cpp $(OBJS) $(LIBS)
|
||||||
|
$(STRIP) zerotier-cli
|
||||||
|
|
||||||
selftest: $(OBJS)
|
selftest: $(OBJS)
|
||||||
$(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.cpp $(OBJS) $(LIBS)
|
$(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.cpp $(OBJS) $(LIBS)
|
||||||
$(STRIP) zerotier-selftest
|
$(STRIP) zerotier-selftest
|
||||||
|
|
2
cli.cpp
2
cli.cpp
|
@ -113,7 +113,7 @@ int main(int argc,char **argv)
|
||||||
|
|
||||||
lastResultTime = Utils::now();
|
lastResultTime = Utils::now();
|
||||||
while ((Utils::now() - lastResultTime) < 300)
|
while ((Utils::now() - lastResultTime) < 300)
|
||||||
Thread::sleep(50);
|
Thread<void>::sleep(50);
|
||||||
|
|
||||||
if (!numResults) {
|
if (!numResults) {
|
||||||
fprintf(stdout,"ERROR: no results received. Is ZeroTier One running?"ZT_EOL_S);
|
fprintf(stdout,"ERROR: no results received. Is ZeroTier One running?"ZT_EOL_S);
|
||||||
|
|
|
@ -187,7 +187,7 @@ EthernetTap::EthernetTap(
|
||||||
|
|
||||||
TRACE("tap %s created",_dev);
|
TRACE("tap %s created",_dev);
|
||||||
|
|
||||||
start();
|
_thread = Thread<EthernetTap>::start(this);
|
||||||
}
|
}
|
||||||
#endif // __LINUX__
|
#endif // __LINUX__
|
||||||
|
|
||||||
|
@ -271,14 +271,14 @@ EthernetTap::EthernetTap(
|
||||||
|
|
||||||
::pipe(_shutdownSignalPipe);
|
::pipe(_shutdownSignalPipe);
|
||||||
|
|
||||||
start();
|
_thread = Thread<EthernetTap>::start(this);
|
||||||
}
|
}
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
EthernetTap::~EthernetTap()
|
EthernetTap::~EthernetTap()
|
||||||
{
|
{
|
||||||
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
|
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
|
||||||
join();
|
Thread<EthernetTap>::join(_thread);
|
||||||
::close(_fd);
|
::close(_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,7 +549,7 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
|
||||||
}
|
}
|
||||||
#endif // __APPLE__
|
#endif // __APPLE__
|
||||||
|
|
||||||
void EthernetTap::main()
|
void EthernetTap::threadMain()
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
fd_set readfds,nullfds;
|
fd_set readfds,nullfds;
|
||||||
|
|
|
@ -51,7 +51,7 @@ class RuntimeEnvironment;
|
||||||
/**
|
/**
|
||||||
* System ethernet tap device
|
* System ethernet tap device
|
||||||
*/
|
*/
|
||||||
class EthernetTap : protected Thread
|
class EthernetTap
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +79,7 @@ public:
|
||||||
*
|
*
|
||||||
* This may block for a few seconds while thread exits.
|
* This may block for a few seconds while thread exits.
|
||||||
*/
|
*/
|
||||||
virtual ~EthernetTap();
|
~EthernetTap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform OS dependent actions on network configuration change detection
|
* Perform OS dependent actions on network configuration change detection
|
||||||
|
@ -169,8 +169,10 @@ public:
|
||||||
*/
|
*/
|
||||||
bool updateMulticastGroups(std::set<MulticastGroup> &groups);
|
bool updateMulticastGroups(std::set<MulticastGroup> &groups);
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
virtual void main()
|
* Thread main method; do not call elsewhere
|
||||||
|
*/
|
||||||
|
void threadMain()
|
||||||
throw();
|
throw();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -178,6 +180,7 @@ private:
|
||||||
const unsigned int _mtu;
|
const unsigned int _mtu;
|
||||||
|
|
||||||
const RuntimeEnvironment *_r;
|
const RuntimeEnvironment *_r;
|
||||||
|
Thread<EthernetTap> _thread;
|
||||||
|
|
||||||
std::set<InetAddress> _ips;
|
std::set<InetAddress> _ips;
|
||||||
Mutex _ips_m;
|
Mutex _ips_m;
|
||||||
|
|
|
@ -108,6 +108,8 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t id)
|
||||||
_id(id),
|
_id(id),
|
||||||
_lastConfigUpdate(0)
|
_lastConfigUpdate(0)
|
||||||
{
|
{
|
||||||
|
if (controller() == _r->identity.address())
|
||||||
|
throw std::runtime_error("configuration error: cannot add a network for which I am the netconf master");
|
||||||
}
|
}
|
||||||
|
|
||||||
Network::~Network()
|
Network::~Network()
|
||||||
|
@ -118,6 +120,7 @@ void Network::setConfiguration(const Network::Config &conf)
|
||||||
{
|
{
|
||||||
Mutex::Lock _l(_lock);
|
Mutex::Lock _l(_lock);
|
||||||
if ((conf.networkId() == _id)&&(conf.peerAddress() == _r->identity.address())) { // sanity check
|
if ((conf.networkId() == _id)&&(conf.peerAddress() == _r->identity.address())) { // sanity check
|
||||||
|
TRACE("network %.16llx got netconf:\n%s",(unsigned long long)_id,conf.toString().c_str());
|
||||||
_configuration = conf;
|
_configuration = conf;
|
||||||
_myCertificate = conf.certificateOfMembership();
|
_myCertificate = conf.certificateOfMembership();
|
||||||
_lastConfigUpdate = Utils::now();
|
_lastConfigUpdate = Utils::now();
|
||||||
|
@ -126,6 +129,11 @@ void Network::setConfiguration(const Network::Config &conf)
|
||||||
|
|
||||||
void Network::requestConfiguration()
|
void Network::requestConfiguration()
|
||||||
{
|
{
|
||||||
|
if (controller() == _r->identity.address()) {
|
||||||
|
LOG("unable to request network configuration for network %.16llx: I am the network master, cannot query self",(unsigned long long)_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
TRACE("requesting netconf for network %.16llx from netconf master %s",(unsigned long long)_id,controller().toString().c_str());
|
||||||
Packet outp(controller(),_r->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST);
|
Packet outp(controller(),_r->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST);
|
||||||
outp.append((uint64_t)_id);
|
outp.append((uint64_t)_id);
|
||||||
_r->sw->send(outp,true);
|
_r->sw->send(outp,true);
|
||||||
|
|
|
@ -99,10 +99,10 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
inline std::string toString() const
|
||||||
* @return Read-only underlying dictionary
|
{
|
||||||
*/
|
return Dictionary::toString();
|
||||||
inline const Dictionary &dictionary() const { return *this; }
|
}
|
||||||
|
|
||||||
inline void setNetworkId(uint64_t id)
|
inline void setNetworkId(uint64_t id)
|
||||||
{
|
{
|
||||||
|
@ -208,11 +208,9 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setNetworkId(uint64_t id)
|
inline std::string toString() const
|
||||||
{
|
{
|
||||||
char buf[32];
|
return Dictionary::toString();
|
||||||
sprintf(buf,"%.16llx",(unsigned long long)id);
|
|
||||||
(*this)["nwid"] = buf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t networkId() const
|
inline uint64_t networkId() const
|
||||||
|
@ -221,11 +219,6 @@ public:
|
||||||
return strtoull(get("nwid").c_str(),(char **)0,16);
|
return strtoull(get("nwid").c_str(),(char **)0,16);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void setPeerAddress(Address &a)
|
|
||||||
{
|
|
||||||
(*this)["peer"] = a.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline Address peerAddress() const
|
inline Address peerAddress() const
|
||||||
throw(std::invalid_argument)
|
throw(std::invalid_argument)
|
||||||
{
|
{
|
||||||
|
@ -265,41 +258,6 @@ public:
|
||||||
sa.insert(InetAddress(*i));
|
sa.insert(InetAddress(*i));
|
||||||
return sa;
|
return sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set static IPv4 and IPv6 addresses
|
|
||||||
*
|
|
||||||
* This sets the ipv4Static and ipv6Static fields to comma-delimited
|
|
||||||
* lists of assignments. The port field in InetAddress must be the
|
|
||||||
* number of bits in the netmask.
|
|
||||||
*
|
|
||||||
* @param begin Start of container or array of addresses (InetAddress)
|
|
||||||
* @param end End of container or array of addresses (InetAddress)
|
|
||||||
* @tparam I Type of container or array
|
|
||||||
*/
|
|
||||||
template<typename I>
|
|
||||||
inline void setStaticInetAddresses(const I &begin,const I &end)
|
|
||||||
{
|
|
||||||
std::string v4;
|
|
||||||
std::string v6;
|
|
||||||
for(I i(begin);i!=end;++i) {
|
|
||||||
if (i->isV4()) {
|
|
||||||
if (v4.length())
|
|
||||||
v4.push_back(',');
|
|
||||||
v4.append(i->toString());
|
|
||||||
} else if (i->isV6()) {
|
|
||||||
if (v6.length())
|
|
||||||
v6.push_back(',');
|
|
||||||
v6.append(i->toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (v4.length())
|
|
||||||
(*this)["ipv4Static"] = v4;
|
|
||||||
else erase("ipv4Static");
|
|
||||||
if (v6.length())
|
|
||||||
(*this)["ipv6Static"] = v6;
|
|
||||||
else erase("ipv6Static");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -426,7 +426,7 @@ Node::ReasonForTermination Node::run()
|
||||||
if (lastDelayDelta >= ZT_SLEEP_WAKE_DETECTION_THRESHOLD) {
|
if (lastDelayDelta >= ZT_SLEEP_WAKE_DETECTION_THRESHOLD) {
|
||||||
resynchronize = true;
|
resynchronize = true;
|
||||||
LOG("probable suspend/resume detected, pausing a moment for things to settle...");
|
LOG("probable suspend/resume detected, pausing a moment for things to settle...");
|
||||||
Thread::sleep(ZT_SLEEP_WAKE_SETTLE_TIME);
|
Thread<Node>::sleep(ZT_SLEEP_WAKE_SETTLE_TIME);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Periodically check our network environment, sending pings out to all
|
// Periodically check our network environment, sending pings out to all
|
||||||
|
|
|
@ -243,8 +243,10 @@ void NodeConfig::_CBcontrolPacketHandler(UdpSocket *sock,void *arg,const InetAdd
|
||||||
for(std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> >::iterator p(resultPackets.begin());p!=resultPackets.end();++p)
|
for(std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> >::iterator p(resultPackets.begin());p!=resultPackets.end();++p)
|
||||||
sock->send(remoteAddr,p->data(),p->size(),-1);
|
sock->send(remoteAddr,p->data(),p->size(),-1);
|
||||||
}
|
}
|
||||||
|
} catch (std::exception &exc) {
|
||||||
|
TRACE("exception handling control bus packet from %s: %s",remoteAddr.toString().c_str(),exc.what());
|
||||||
} catch ( ... ) {
|
} catch ( ... ) {
|
||||||
TRACE("exception handling control bus packet from %s",remoteAddr.toString().c_str());
|
TRACE("exception handling control bus packet from %s: (unknown)",remoteAddr.toString().c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ Service::Service(const RuntimeEnvironment *renv,const char *name,const char *pat
|
||||||
_childStderr(0),
|
_childStderr(0),
|
||||||
_run(true)
|
_run(true)
|
||||||
{
|
{
|
||||||
start();
|
_thread = Thread<Service>::start(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Service::~Service()
|
Service::~Service()
|
||||||
|
@ -77,14 +77,14 @@ Service::~Service()
|
||||||
pid = 0;
|
pid = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Thread::sleep(100);
|
Thread<Service>::sleep(100);
|
||||||
}
|
}
|
||||||
if (pid > 0) {
|
if (pid > 0) {
|
||||||
::kill(pid,SIGKILL);
|
::kill(pid,SIGKILL);
|
||||||
waitpid(pid,&st,0);
|
waitpid(pid,&st,0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
join();
|
Thread<Service>::join(_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Service::send(const Dictionary &msg)
|
bool Service::send(const Dictionary &msg)
|
||||||
|
@ -107,7 +107,7 @@ bool Service::send(const Dictionary &msg)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Service::main()
|
void Service::threadMain()
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
char buf[131072];
|
char buf[131072];
|
||||||
|
@ -136,7 +136,7 @@ void Service::main()
|
||||||
close(in[0]);
|
close(in[0]);
|
||||||
close(out[1]);
|
close(out[1]);
|
||||||
close(err[1]);
|
close(err[1]);
|
||||||
Thread::sleep(500); // give child time to start
|
Thread<Service>::sleep(500); // give child time to start
|
||||||
_childStdin = in[1];
|
_childStdin = in[1];
|
||||||
_childStdout = out[0];
|
_childStdout = out[0];
|
||||||
_childStderr = err[0];
|
_childStderr = err[0];
|
||||||
|
@ -168,7 +168,7 @@ void Service::main()
|
||||||
|
|
||||||
LOG("service %s exited with exit code: %d, delaying 1s to attempt relaunch",_name.c_str(),st);
|
LOG("service %s exited with exit code: %d, delaying 1s to attempt relaunch",_name.c_str(),st);
|
||||||
|
|
||||||
Thread::sleep(1000); // wait to relaunch
|
Thread<Service>::sleep(1000); // wait to relaunch
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ class RuntimeEnvironment;
|
||||||
* logged via the standard Logger instance. If the subprocess dies, an
|
* logged via the standard Logger instance. If the subprocess dies, an
|
||||||
* attempt is made to restart it every second.
|
* attempt is made to restart it every second.
|
||||||
*/
|
*/
|
||||||
class Service : protected Thread
|
class Service
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +78,7 @@ public:
|
||||||
void (*handler)(void *,Service &,const Dictionary &),
|
void (*handler)(void *,Service &,const Dictionary &),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
virtual ~Service();
|
~Service();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send a message to service subprocess
|
* Send a message to service subprocess
|
||||||
|
@ -106,12 +106,15 @@ public:
|
||||||
return (_pid > 0);
|
return (_pid > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
virtual void main()
|
* Thread main method; do not call elsewhere
|
||||||
|
*/
|
||||||
|
void threadMain()
|
||||||
throw();
|
throw();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const RuntimeEnvironment *_r;
|
const RuntimeEnvironment *_r;
|
||||||
|
Thread<Service> _thread;
|
||||||
std::string _path;
|
std::string _path;
|
||||||
std::string _name;
|
std::string _name;
|
||||||
void *_arg;
|
void *_arg;
|
||||||
|
|
182
node/Thread.cpp
182
node/Thread.cpp
|
@ -1,182 +0,0 @@
|
||||||
/*
|
|
||||||
* ZeroTier One - Global Peer to Peer Ethernet
|
|
||||||
* Copyright (C) 2012-2013 ZeroTier Networks LLC
|
|
||||||
*
|
|
||||||
* 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 "Thread.hpp"
|
|
||||||
|
|
||||||
#if defined(__APPLE__) || defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
static void *__m_thread_main(void *ptr)
|
|
||||||
{
|
|
||||||
((ZeroTier::Thread *)ptr)->__intl_run();
|
|
||||||
return (void *)0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
|
||||||
|
|
||||||
Thread::Thread() :
|
|
||||||
_impl(malloc(sizeof(pthread_t))),
|
|
||||||
_running()
|
|
||||||
{
|
|
||||||
memset(_impl,0,sizeof(pthread_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::~Thread()
|
|
||||||
{
|
|
||||||
free(_impl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::start()
|
|
||||||
{
|
|
||||||
if (!*_running) {
|
|
||||||
++_running;
|
|
||||||
pthread_create((pthread_t *)_impl,(const pthread_attr_t *)0,&__m_thread_main,(void *)this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::join()
|
|
||||||
{
|
|
||||||
void *tmp;
|
|
||||||
if (*_running)
|
|
||||||
pthread_join(*((pthread_t *)_impl),&tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::sleep(unsigned long ms)
|
|
||||||
{
|
|
||||||
usleep(ms * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::__intl_run()
|
|
||||||
{
|
|
||||||
for(;;) {
|
|
||||||
_notInit = false;
|
|
||||||
this->main();
|
|
||||||
if (_notInit) // UGLY ASS HACK: see main()
|
|
||||||
usleep(50);
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
--_running;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::main()
|
|
||||||
throw()
|
|
||||||
{
|
|
||||||
_notInit = true; // UGLY ASS HACK: retry if subclass has not defined virtual function pointer yet
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ZeroTier
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
|
|
||||||
#include <Windows.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
DWORD WINAPI __m_thread_main(LPVOID lpParam)
|
|
||||||
{
|
|
||||||
((ZeroTier::Thread *)lpParam)->__intl_run();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct __m_thread_info
|
|
||||||
{
|
|
||||||
HANDLE threadHandle;
|
|
||||||
DWORD threadId;
|
|
||||||
bool started;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace ZeroTier {
|
|
||||||
|
|
||||||
Thread::Thread() :
|
|
||||||
_impl(malloc(sizeof(__m_thread_info))),
|
|
||||||
_running()
|
|
||||||
{
|
|
||||||
memset(_impl,0,sizeof(__m_thread_info));
|
|
||||||
}
|
|
||||||
|
|
||||||
Thread::~Thread()
|
|
||||||
{
|
|
||||||
if (((__m_thread_info *)_impl)->started)
|
|
||||||
CloseHandle(((__m_thread_info *)_impl)->threadHandle);
|
|
||||||
free(_impl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::start()
|
|
||||||
{
|
|
||||||
if (!*_running) {
|
|
||||||
++_running;
|
|
||||||
if ((((__m_thread_info *)_impl)->threadHandle = CreateThread(NULL,0,__m_thread_main,this,0,&(((__m_thread_info *)_impl)->threadId))) != NULL) {
|
|
||||||
((__m_thread_info *)_impl)->started = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::join()
|
|
||||||
{
|
|
||||||
if (*_running)
|
|
||||||
WaitForSingleObject(((__m_thread_info *)_impl)->threadHandle,INFINITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::__intl_run()
|
|
||||||
{
|
|
||||||
for(;;) {
|
|
||||||
_notInit = false;
|
|
||||||
this->main();
|
|
||||||
if (_notInit)
|
|
||||||
Thread::sleep(50);
|
|
||||||
else break;
|
|
||||||
}
|
|
||||||
--_running;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Thread::main()
|
|
||||||
throw()
|
|
||||||
{
|
|
||||||
_notInit = true; // HACK: retry if subclass has not defined virtual function pointer yet
|
|
||||||
}
|
|
||||||
|
|
||||||
struct _Thread_RunInBackgroundData
|
|
||||||
{
|
|
||||||
void (*func)(void *);
|
|
||||||
void *ptr;
|
|
||||||
HANDLE threadHandle;
|
|
||||||
DWORD threadId;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace ZeroTier
|
|
||||||
|
|
||||||
#endif
|
|
106
node/Thread.hpp
106
node/Thread.hpp
|
@ -28,62 +28,104 @@
|
||||||
#ifndef _ZT_THREAD_HPP
|
#ifndef _ZT_THREAD_HPP
|
||||||
#define _ZT_THREAD_HPP
|
#define _ZT_THREAD_HPP
|
||||||
|
|
||||||
#include "NonCopyable.hpp"
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "Constants.hpp"
|
||||||
#include "AtomicCounter.hpp"
|
#include "AtomicCounter.hpp"
|
||||||
|
|
||||||
|
#ifdef __WINDOWS__
|
||||||
|
|
||||||
|
todo need windows;
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
template<typename C>
|
||||||
|
static void *___zt_threadMain(void *instance)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
((C *)instance)->threadMain();
|
||||||
|
} catch ( ... ) {}
|
||||||
|
return (void *)0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrapper for OS-dependent thread functions like pthread_create, etc.
|
* A thread of a given class type
|
||||||
|
*
|
||||||
|
* @tparam C Class using Thread
|
||||||
*/
|
*/
|
||||||
class Thread : NonCopyable
|
template<typename C>
|
||||||
|
class Thread
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Thread();
|
Thread()
|
||||||
virtual ~Thread();
|
throw()
|
||||||
|
{
|
||||||
|
memset(&_tid,0,sizeof(_tid));
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread(const Thread &t)
|
||||||
|
throw()
|
||||||
|
{
|
||||||
|
memcpy(&_tid,&(t._tid),sizeof(_tid));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Thread &operator=(const Thread &t)
|
||||||
|
throw()
|
||||||
|
{
|
||||||
|
memcpy(&_tid,&(t._tid),sizeof(_tid));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start thread -- can only be called once
|
* Start a new thread
|
||||||
*/
|
|
||||||
void start();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Wait for thread to terminate
|
|
||||||
*
|
*
|
||||||
* More than one thread should not simultaneously use join().
|
* @param instance Instance whose threadMain() method gets called by new thread
|
||||||
|
* @return Thread identifier
|
||||||
|
* @throws std::runtime_error Unable to create thread
|
||||||
*/
|
*/
|
||||||
void join();
|
static inline Thread start(C *instance)
|
||||||
|
throw(std::runtime_error)
|
||||||
|
{
|
||||||
|
Thread t;
|
||||||
|
if (pthread_create(&t._tid,(const pthread_attr_t *)0,&___zt_threadMain<C>,instance))
|
||||||
|
throw std::runtime_error("pthread_create() failed, unable to create thread");
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return True if thread is running
|
* Join to a thread, waiting for it to terminate
|
||||||
|
*
|
||||||
|
* @param t Thread to join
|
||||||
*/
|
*/
|
||||||
inline bool running() const { return (*_running > 0); }
|
static inline void join(const Thread &t)
|
||||||
|
{
|
||||||
/**
|
pthread_join(t._tid,(void **)0);
|
||||||
* Internal bounce method; do not call or override
|
}
|
||||||
*/
|
|
||||||
void __intl_run();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sleep the current thread
|
* Sleep the current thread
|
||||||
*
|
*
|
||||||
* @param ms Milliseconds to sleep
|
* @param ms Number of milliseconds to sleep
|
||||||
*/
|
*/
|
||||||
static void sleep(unsigned long ms);
|
static inline void sleep(unsigned long ms)
|
||||||
|
{
|
||||||
protected:
|
usleep(ms * 1000);
|
||||||
/**
|
}
|
||||||
* Override to set a thread main function
|
|
||||||
*/
|
|
||||||
virtual void main()
|
|
||||||
throw();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void *_impl;
|
pthread_t _tid;
|
||||||
AtomicCounter _running;
|
|
||||||
volatile bool _notInit;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
#endif // __WINDOWS__ / !__WINDOWS__
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -38,7 +38,6 @@ namespace ZeroTier {
|
||||||
|
|
||||||
Topology::Topology(const RuntimeEnvironment *renv,const char *dbpath)
|
Topology::Topology(const RuntimeEnvironment *renv,const char *dbpath)
|
||||||
throw(std::runtime_error) :
|
throw(std::runtime_error) :
|
||||||
Thread(),
|
|
||||||
_r(renv),
|
_r(renv),
|
||||||
_amSupernode(false)
|
_amSupernode(false)
|
||||||
{
|
{
|
||||||
|
@ -55,7 +54,7 @@ Topology::Topology(const RuntimeEnvironment *renv,const char *dbpath)
|
||||||
|
|
||||||
Utils::lockDownFile(dbpath,false); // node.db caches secrets
|
Utils::lockDownFile(dbpath,false); // node.db caches secrets
|
||||||
|
|
||||||
start();
|
_thread = Thread<Topology>::start(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Topology::~Topology()
|
Topology::~Topology()
|
||||||
|
@ -68,10 +67,7 @@ Topology::~Topology()
|
||||||
_peerDeepVerifyJobs.back().type = _PeerDeepVerifyJob::EXIT_THREAD;
|
_peerDeepVerifyJobs.back().type = _PeerDeepVerifyJob::EXIT_THREAD;
|
||||||
}
|
}
|
||||||
_peerDeepVerifyJobs_c.signal();
|
_peerDeepVerifyJobs_c.signal();
|
||||||
|
Thread<Topology>::join(_thread);
|
||||||
while (running())
|
|
||||||
Thread::sleep(10); // wait for thread to terminate without join()
|
|
||||||
|
|
||||||
KISSDB_close(&_dbm);
|
KISSDB_close(&_dbm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,7 +219,7 @@ void Topology::clean()
|
||||||
_peerDeepVerifyJobs_c.signal();
|
_peerDeepVerifyJobs_c.signal();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Topology::main()
|
void Topology::threadMain()
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
|
|
@ -55,7 +55,7 @@ class RuntimeEnvironment;
|
||||||
/**
|
/**
|
||||||
* Database of network topology
|
* Database of network topology
|
||||||
*/
|
*/
|
||||||
class Topology : protected Thread
|
class Topology
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -74,7 +74,7 @@ public:
|
||||||
Topology(const RuntimeEnvironment *renv,const char *dbpath)
|
Topology(const RuntimeEnvironment *renv,const char *dbpath)
|
||||||
throw(std::runtime_error);
|
throw(std::runtime_error);
|
||||||
|
|
||||||
virtual ~Topology();
|
~Topology();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up supernodes for this network
|
* Set up supernodes for this network
|
||||||
|
@ -276,8 +276,10 @@ public:
|
||||||
std::vector< SharedPtr<Peer> > &_v;
|
std::vector< SharedPtr<Peer> > &_v;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
virtual void main()
|
* Thread main method; do not call elsewhere
|
||||||
|
*/
|
||||||
|
void threadMain()
|
||||||
throw();
|
throw();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -297,6 +299,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
const RuntimeEnvironment *const _r;
|
const RuntimeEnvironment *const _r;
|
||||||
|
Thread<Topology> _thread;
|
||||||
|
|
||||||
std::map< Address,SharedPtr<Peer> > _activePeers;
|
std::map< Address,SharedPtr<Peer> > _activePeers;
|
||||||
Mutex _activePeers_m;
|
Mutex _activePeers_m;
|
||||||
|
|
|
@ -55,7 +55,6 @@ UdpSocket::UdpSocket(
|
||||||
void (*packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int),
|
void (*packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int),
|
||||||
void *arg)
|
void *arg)
|
||||||
throw(std::runtime_error) :
|
throw(std::runtime_error) :
|
||||||
Thread(),
|
|
||||||
_packetHandler(packetHandler),
|
_packetHandler(packetHandler),
|
||||||
_arg(arg),
|
_arg(arg),
|
||||||
_localPort(localPort),
|
_localPort(localPort),
|
||||||
|
@ -121,7 +120,7 @@ UdpSocket::UdpSocket(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start();
|
_thread = Thread<UdpSocket>::start(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
UdpSocket::~UdpSocket()
|
UdpSocket::~UdpSocket()
|
||||||
|
@ -146,7 +145,7 @@ bool UdpSocket::send(const InetAddress &to,const void *data,unsigned int len,int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UdpSocket::main()
|
void UdpSocket::threadMain()
|
||||||
throw()
|
throw()
|
||||||
{
|
{
|
||||||
char buf[32768];
|
char buf[32768];
|
||||||
|
|
|
@ -40,7 +40,7 @@ namespace ZeroTier {
|
||||||
*
|
*
|
||||||
* The socket listens in a background thread and sends packets to Switch.
|
* The socket listens in a background thread and sends packets to Switch.
|
||||||
*/
|
*/
|
||||||
class UdpSocket : protected Thread
|
class UdpSocket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -61,7 +61,7 @@ public:
|
||||||
void *arg)
|
void *arg)
|
||||||
throw(std::runtime_error);
|
throw(std::runtime_error);
|
||||||
|
|
||||||
virtual ~UdpSocket();
|
~UdpSocket();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Locally bound port
|
* @return Locally bound port
|
||||||
|
@ -87,11 +87,14 @@ public:
|
||||||
bool send(const InetAddress &to,const void *data,unsigned int len,int hopLimit)
|
bool send(const InetAddress &to,const void *data,unsigned int len,int hopLimit)
|
||||||
throw();
|
throw();
|
||||||
|
|
||||||
protected:
|
/**
|
||||||
virtual void main()
|
* Thread main method; do not call elsewhere
|
||||||
|
*/
|
||||||
|
void threadMain()
|
||||||
throw();
|
throw();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Thread<UdpSocket> _thread;
|
||||||
void (*_packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int);
|
void (*_packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int);
|
||||||
void *_arg;
|
void *_arg;
|
||||||
int _localPort;
|
int _localPort;
|
||||||
|
|
|
@ -21,7 +21,6 @@ OBJS=\
|
||||||
node/Service.o \
|
node/Service.o \
|
||||||
node/Switch.o \
|
node/Switch.o \
|
||||||
node/SysEnv.o \
|
node/SysEnv.o \
|
||||||
node/Thread.o \
|
|
||||||
node/Topology.o \
|
node/Topology.o \
|
||||||
node/UdpSocket.o \
|
node/UdpSocket.o \
|
||||||
node/Utils.o
|
node/Utils.o
|
||||||
|
|
Loading…
Add table
Reference in a new issue