summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
Diffstat (limited to 'node')
-rw-r--r--node/EthernetTap.cpp8
-rw-r--r--node/EthernetTap.hpp11
-rw-r--r--node/Network.cpp8
-rw-r--r--node/Network.hpp54
-rw-r--r--node/Node.cpp2
-rw-r--r--node/NodeConfig.cpp4
-rw-r--r--node/Service.cpp12
-rw-r--r--node/Service.hpp11
-rw-r--r--node/Thread.cpp182
-rw-r--r--node/Thread.hpp104
-rw-r--r--node/Topology.cpp10
-rw-r--r--node/Topology.hpp11
-rw-r--r--node/UdpSocket.cpp5
-rw-r--r--node/UdpSocket.hpp11
14 files changed, 134 insertions, 299 deletions
diff --git a/node/EthernetTap.cpp b/node/EthernetTap.cpp
index c45d50c2..870baceb 100644
--- a/node/EthernetTap.cpp
+++ b/node/EthernetTap.cpp
@@ -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;
diff --git a/node/EthernetTap.hpp b/node/EthernetTap.hpp
index 3bc7cad8..6fb4c134 100644
--- a/node/EthernetTap.hpp
+++ b/node/EthernetTap.hpp
@@ -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;
diff --git a/node/Network.cpp b/node/Network.cpp
index 37761aff..6deb31fe 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -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);
diff --git a/node/Network.hpp b/node/Network.hpp
index 4155d5d8..d3bb5ad7 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -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:
diff --git a/node/Node.cpp b/node/Node.cpp
index ef2a801c..da752bb2 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -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
diff --git a/node/NodeConfig.cpp b/node/NodeConfig.cpp
index 4a174535..0a6c014f 100644
--- a/node/NodeConfig.cpp
+++ b/node/NodeConfig.cpp
@@ -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());
}
}
diff --git a/node/Service.cpp b/node/Service.cpp
index c614e4e4..0d4702f8 100644
--- a/node/Service.cpp
+++ b/node/Service.cpp
@@ -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;
}
}
diff --git a/node/Service.hpp b/node/Service.hpp
index c8b729c7..0b00d81d 100644
--- a/node/Service.hpp
+++ b/node/Service.hpp
@@ -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;
diff --git a/node/Thread.cpp b/node/Thread.cpp
deleted file mode 100644
index f650f6fc..00000000
--- a/node/Thread.cpp
+++ /dev/null
@@ -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
diff --git a/node/Thread.hpp b/node/Thread.hpp
index 9b399a00..444da2be 100644
--- a/node/Thread.hpp
+++ b/node/Thread.hpp
@@ -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));
+ }
- /**
- * Start thread -- can only be called once
- */
- void start();
+ Thread(const Thread &t)
+ throw()
+ {
+ memcpy(&_tid,&(t._tid),sizeof(_tid));
+ }
- /**
- * Wait for thread to terminate
- *
- * More than one thread should not simultaneously use join().
- */
- void join();
+ inline Thread &operator=(const Thread &t)
+ throw()
+ {
+ memcpy(&_tid,&(t._tid),sizeof(_tid));
+ return *this;
+ }
/**
- * @return True if thread is running
+ * Start a new thread
+ *
+ * @param instance Instance whose threadMain() method gets called by new thread
+ * @return Thread identifier
+ * @throws std::runtime_error Unable to create thread
*/
- inline bool running() const { return (*_running > 0); }
+ 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;
+ }
/**
- * Internal bounce method; do not call or override
+ * Join to a thread, waiting for it to terminate
+ *
+ * @param t Thread to join
*/
- 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
diff --git a/node/Topology.cpp b/node/Topology.cpp
index 8487684e..ff012eaa 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -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(;;) {
diff --git a/node/Topology.hpp b/node/Topology.hpp
index 104ad344..b917738e 100644
--- a/node/Topology.hpp
+++ b/node/Topology.hpp
@@ -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;
diff --git a/node/UdpSocket.cpp b/node/UdpSocket.cpp
index 6178d16e..db2c4b56 100644
--- a/node/UdpSocket.cpp
+++ b/node/UdpSocket.cpp
@@ -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];
diff --git a/node/UdpSocket.hpp b/node/UdpSocket.hpp
index a3223f1f..3f624387 100644
--- a/node/UdpSocket.hpp
+++ b/node/UdpSocket.hpp
@@ -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;