Prechádzať zdrojové kódy

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

Adam Ierymenko 12 rokov pred
rodič
commit
a7c4cbe53a

+ 5 - 1
Makefile.linux

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

+ 1 - 1
cli.cpp

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

+ 4 - 4
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;

+ 7 - 4
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;

+ 8 - 0
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);

+ 6 - 48
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:

+ 1 - 1
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

+ 3 - 1
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());
 	}
 }
 

+ 6 - 6
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;
 			}
 		}

+ 7 - 4
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;

+ 0 - 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

+ 73 - 31
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

+ 3 - 7
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(;;) {

+ 7 - 4
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;

+ 2 - 3
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];

+ 7 - 4
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;

+ 0 - 1
objects.mk

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