Browse Source

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

Adam Ierymenko 12 years ago
parent
commit
a7c4cbe53a
17 changed files with 140 additions and 302 deletions
  1. 5 1
      Makefile.linux
  2. 1 1
      cli.cpp
  3. 4 4
      node/EthernetTap.cpp
  4. 7 4
      node/EthernetTap.hpp
  5. 8 0
      node/Network.cpp
  6. 6 48
      node/Network.hpp
  7. 1 1
      node/Node.cpp
  8. 3 1
      node/NodeConfig.cpp
  9. 6 6
      node/Service.cpp
  10. 7 4
      node/Service.hpp
  11. 0 182
      node/Thread.cpp
  12. 73 31
      node/Thread.hpp
  13. 3 7
      node/Topology.cpp
  14. 7 4
      node/Topology.hpp
  15. 2 3
      node/UdpSocket.cpp
  16. 7 4
      node/UdpSocket.hpp
  17. 0 1
      objects.mk

+ 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