CLI debugging, got rid of nasty old Thread class and replaced with newer cleaner portable idiom.

This commit is contained in:
Adam Ierymenko 2013-08-05 16:06:16 -04:00
parent 3368330b77
commit a7c4cbe53a
17 changed files with 141 additions and 303 deletions

View File

@ -24,12 +24,16 @@ LIBS=ext/bin/libcrypto/linux-$(ARCH)/libcrypto.a -lm -ldl
include objects.mk
all: one launcher
all: one cli launcher
one: $(OBJS)
$(CXX) $(CXXFLAGS) -o zerotier-one main.cpp $(OBJS) $(LIBS)
$(STRIP) zerotier-one
cli: $(OBJS)
$(CXX) $(CXXFLAGS) -o zerotier-cli cli.cpp $(OBJS) $(LIBS)
$(STRIP) zerotier-cli
selftest: $(OBJS)
$(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.cpp $(OBJS) $(LIBS)
$(STRIP) zerotier-selftest

View File

@ -113,7 +113,7 @@ int main(int argc,char **argv)
lastResultTime = Utils::now();
while ((Utils::now() - lastResultTime) < 300)
Thread::sleep(50);
Thread<void>::sleep(50);
if (!numResults) {
fprintf(stdout,"ERROR: no results received. Is ZeroTier One running?"ZT_EOL_S);

View File

@ -187,7 +187,7 @@ EthernetTap::EthernetTap(
TRACE("tap %s created",_dev);
start();
_thread = Thread<EthernetTap>::start(this);
}
#endif // __LINUX__
@ -271,14 +271,14 @@ EthernetTap::EthernetTap(
::pipe(_shutdownSignalPipe);
start();
_thread = Thread<EthernetTap>::start(this);
}
#endif // __APPLE__
EthernetTap::~EthernetTap()
{
::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit
join();
Thread<EthernetTap>::join(_thread);
::close(_fd);
}
@ -549,7 +549,7 @@ bool EthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
}
#endif // __APPLE__
void EthernetTap::main()
void EthernetTap::threadMain()
throw()
{
fd_set readfds,nullfds;

View File

@ -51,7 +51,7 @@ class RuntimeEnvironment;
/**
* System ethernet tap device
*/
class EthernetTap : protected Thread
class EthernetTap
{
public:
/**
@ -79,7 +79,7 @@ public:
*
* This may block for a few seconds while thread exits.
*/
virtual ~EthernetTap();
~EthernetTap();
/**
* Perform OS dependent actions on network configuration change detection
@ -169,8 +169,10 @@ public:
*/
bool updateMulticastGroups(std::set<MulticastGroup> &groups);
protected:
virtual void main()
/**
* Thread main method; do not call elsewhere
*/
void threadMain()
throw();
private:
@ -178,6 +180,7 @@ private:
const unsigned int _mtu;
const RuntimeEnvironment *_r;
Thread<EthernetTap> _thread;
std::set<InetAddress> _ips;
Mutex _ips_m;

View File

@ -108,6 +108,8 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t id)
_id(id),
_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()
@ -118,6 +120,7 @@ void Network::setConfiguration(const Network::Config &conf)
{
Mutex::Lock _l(_lock);
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;
_myCertificate = conf.certificateOfMembership();
_lastConfigUpdate = Utils::now();
@ -126,6 +129,11 @@ void Network::setConfiguration(const Network::Config &conf)
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);
outp.append((uint64_t)_id);
_r->sw->send(outp,true);

View File

@ -99,10 +99,10 @@ public:
{
}
/**
* @return Read-only underlying dictionary
*/
inline const Dictionary &dictionary() const { return *this; }
inline std::string toString() const
{
return Dictionary::toString();
}
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];
sprintf(buf,"%.16llx",(unsigned long long)id);
(*this)["nwid"] = buf;
return Dictionary::toString();
}
inline uint64_t networkId() const
@ -221,11 +219,6 @@ public:
return strtoull(get("nwid").c_str(),(char **)0,16);
}
inline void setPeerAddress(Address &a)
{
(*this)["peer"] = a.toString();
}
inline Address peerAddress() const
throw(std::invalid_argument)
{
@ -265,41 +258,6 @@ public:
sa.insert(InetAddress(*i));
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:

View File

@ -426,7 +426,7 @@ Node::ReasonForTermination Node::run()
if (lastDelayDelta >= ZT_SLEEP_WAKE_DETECTION_THRESHOLD) {
resynchronize = true;
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

View File

@ -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)
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 ( ... ) {
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());
}
}

View File

@ -62,7 +62,7 @@ Service::Service(const RuntimeEnvironment *renv,const char *name,const char *pat
_childStderr(0),
_run(true)
{
start();
_thread = Thread<Service>::start(this);
}
Service::~Service()
@ -77,14 +77,14 @@ Service::~Service()
pid = 0;
break;
}
Thread::sleep(100);
Thread<Service>::sleep(100);
}
if (pid > 0) {
::kill(pid,SIGKILL);
waitpid(pid,&st,0);
}
}
join();
Thread<Service>::join(_thread);
}
bool Service::send(const Dictionary &msg)
@ -107,7 +107,7 @@ bool Service::send(const Dictionary &msg)
return true;
}
void Service::main()
void Service::threadMain()
throw()
{
char buf[131072];
@ -136,7 +136,7 @@ void Service::main()
close(in[0]);
close(out[1]);
close(err[1]);
Thread::sleep(500); // give child time to start
Thread<Service>::sleep(500); // give child time to start
_childStdin = in[1];
_childStdout = out[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);
Thread::sleep(1000); // wait to relaunch
Thread<Service>::sleep(1000); // wait to relaunch
continue;
}
}

View File

@ -60,7 +60,7 @@ class RuntimeEnvironment;
* logged via the standard Logger instance. If the subprocess dies, an
* attempt is made to restart it every second.
*/
class Service : protected Thread
class Service
{
public:
/**
@ -78,7 +78,7 @@ public:
void (*handler)(void *,Service &,const Dictionary &),
void *arg);
virtual ~Service();
~Service();
/**
* Send a message to service subprocess
@ -106,12 +106,15 @@ public:
return (_pid > 0);
}
protected:
virtual void main()
/**
* Thread main method; do not call elsewhere
*/
void threadMain()
throw();
private:
const RuntimeEnvironment *_r;
Thread<Service> _thread;
std::string _path;
std::string _name;
void *_arg;

View File

@ -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

View File

@ -28,62 +28,104 @@
#ifndef _ZT_THREAD_HPP
#define _ZT_THREAD_HPP
#include "NonCopyable.hpp"
#include <stdexcept>
#include "Constants.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 {
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:
Thread();
virtual ~Thread();
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
*/
void start();
/**
* Wait for thread to terminate
* Start a new thread
*
* 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); }
/**
* Internal bounce method; do not call or override
*/
void __intl_run();
static inline void join(const Thread &t)
{
pthread_join(t._tid,(void **)0);
}
/**
* Sleep the current thread
*
* @param ms Milliseconds to sleep
* @param ms Number of milliseconds to sleep
*/
static void sleep(unsigned long ms);
protected:
/**
* Override to set a thread main function
*/
virtual void main()
throw();
static inline void sleep(unsigned long ms)
{
usleep(ms * 1000);
}
private:
void *_impl;
AtomicCounter _running;
volatile bool _notInit;
pthread_t _tid;
};
} // namespace ZeroTier
#endif // __WINDOWS__ / !__WINDOWS__
#endif

View File

@ -38,7 +38,6 @@ namespace ZeroTier {
Topology::Topology(const RuntimeEnvironment *renv,const char *dbpath)
throw(std::runtime_error) :
Thread(),
_r(renv),
_amSupernode(false)
{
@ -55,7 +54,7 @@ Topology::Topology(const RuntimeEnvironment *renv,const char *dbpath)
Utils::lockDownFile(dbpath,false); // node.db caches secrets
start();
_thread = Thread<Topology>::start(this);
}
Topology::~Topology()
@ -68,10 +67,7 @@ Topology::~Topology()
_peerDeepVerifyJobs.back().type = _PeerDeepVerifyJob::EXIT_THREAD;
}
_peerDeepVerifyJobs_c.signal();
while (running())
Thread::sleep(10); // wait for thread to terminate without join()
Thread<Topology>::join(_thread);
KISSDB_close(&_dbm);
}
@ -223,7 +219,7 @@ void Topology::clean()
_peerDeepVerifyJobs_c.signal();
}
void Topology::main()
void Topology::threadMain()
throw()
{
for(;;) {

View File

@ -55,7 +55,7 @@ class RuntimeEnvironment;
/**
* Database of network topology
*/
class Topology : protected Thread
class Topology
{
public:
/**
@ -74,7 +74,7 @@ public:
Topology(const RuntimeEnvironment *renv,const char *dbpath)
throw(std::runtime_error);
virtual ~Topology();
~Topology();
/**
* Set up supernodes for this network
@ -276,8 +276,10 @@ public:
std::vector< SharedPtr<Peer> > &_v;
};
protected:
virtual void main()
/**
* Thread main method; do not call elsewhere
*/
void threadMain()
throw();
private:
@ -297,6 +299,7 @@ private:
};
const RuntimeEnvironment *const _r;
Thread<Topology> _thread;
std::map< Address,SharedPtr<Peer> > _activePeers;
Mutex _activePeers_m;

View File

@ -55,7 +55,6 @@ UdpSocket::UdpSocket(
void (*packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int),
void *arg)
throw(std::runtime_error) :
Thread(),
_packetHandler(packetHandler),
_arg(arg),
_localPort(localPort),
@ -121,7 +120,7 @@ UdpSocket::UdpSocket(
}
}
start();
_thread = Thread<UdpSocket>::start(this);
}
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()
{
char buf[32768];

View File

@ -40,7 +40,7 @@ namespace ZeroTier {
*
* The socket listens in a background thread and sends packets to Switch.
*/
class UdpSocket : protected Thread
class UdpSocket
{
public:
/**
@ -61,7 +61,7 @@ public:
void *arg)
throw(std::runtime_error);
virtual ~UdpSocket();
~UdpSocket();
/**
* @return Locally bound port
@ -87,11 +87,14 @@ public:
bool send(const InetAddress &to,const void *data,unsigned int len,int hopLimit)
throw();
protected:
virtual void main()
/**
* Thread main method; do not call elsewhere
*/
void threadMain()
throw();
private:
Thread<UdpSocket> _thread;
void (*_packetHandler)(UdpSocket *,void *,const InetAddress &,const void *,unsigned int);
void *_arg;
int _localPort;

View File

@ -21,7 +21,6 @@ OBJS=\
node/Service.o \
node/Switch.o \
node/SysEnv.o \
node/Thread.o \
node/Topology.o \
node/UdpSocket.o \
node/Utils.o