2
0
Эх сурвалжийг харах

IPC changes and SocketManager changes all build!

Adam Ierymenko 11 жил өмнө
parent
commit
abc82d6a52

+ 2 - 7
node/Constants.hpp

@@ -114,14 +114,9 @@ error_no_byte_order_defined;
 #define ZT_ADDRESS_RESERVED_PREFIX 0xff
 
 /**
- * Default local UDP port
+ * Default local port for ZeroTier traffic
  */
-#define ZT_DEFAULT_UDP_PORT 9993
-
-/**
- * Local control port, also used for multiple invocation check
- */
-#define ZT_DEFAULT_CONTROL_UDP_PORT 39393
+#define ZT_DEFAULT_PORT 9993
 
 /**
  * Default payload MTU for UDP packets

+ 5 - 5
node/Defaults.cpp

@@ -56,35 +56,35 @@ static inline std::map< Identity,std::vector<InetAddress> > _mkSupernodeMap()
 	addrs.clear();
 	if (!id.fromString("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5"))
 		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(InetAddress("162.243.77.111",ZT_DEFAULT_UDP_PORT));
+	addrs.push_back(InetAddress("162.243.77.111",ZT_DEFAULT_PORT));
 	sn[id] = addrs;
 
 	// nyarlathotep.zerotier.com - San Francisco, California, USA
 	addrs.clear();
 	if (!id.fromString("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa"))
 		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(InetAddress("198.199.97.220",ZT_DEFAULT_UDP_PORT));
+	addrs.push_back(InetAddress("198.199.97.220",ZT_DEFAULT_PORT));
 	sn[id] = addrs;
 
 	// shub-niggurath.zerotier.com - Amsterdam, Netherlands
 	addrs.clear();
 	if (!id.fromString("36f63d6574:0:67a776487a1a99b32f413329f2b67c43fbf6152e42c6b66e89043e69d93e48314c7d709b58a83016bd2612dd89400b856e18c553da94892f7d3ca16bf2c92c24"))
 		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(InetAddress("198.211.127.172",ZT_DEFAULT_UDP_PORT));
+	addrs.push_back(InetAddress("198.211.127.172",ZT_DEFAULT_PORT));
 	sn[id] = addrs;
 
 	// mi-go.zerotier.com - Singapore
 	addrs.clear();
 	if (!id.fromString("abbb7f4622:0:89d2c6b2062b10f4ce314dfcb914c082566247090a6f74c8ba1c15c63b205f540758f0abae85287397152c9d8cf463cfe51e7a480946cd6a31495b24ca13253c"))
 		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(InetAddress("128.199.254.204",ZT_DEFAULT_UDP_PORT));
+	addrs.push_back(InetAddress("128.199.254.204",ZT_DEFAULT_PORT));
 	sn[id] = addrs;
 
 	// shoggoth.zerotier.com - Tokyo, Japan
 	addrs.clear();
 	if (!id.fromString("48e8f875cb:0:5ca54f55e1094f65589f3e6d74158b6964d418ddac3570757128f1c6a2498322d92fcdcd47de459f4d1f9b38df2afd0c7b3fc247ba3d773c38ba35288f24988e"))
 		throw std::runtime_error("invalid identity in Defaults");
-	addrs.push_back(InetAddress("108.61.200.101",ZT_DEFAULT_UDP_PORT));
+	addrs.push_back(InetAddress("108.61.200.101",ZT_DEFAULT_PORT));
 	sn[id] = addrs;
 
 	return sn;

+ 1 - 1
node/IpcConnection.cpp

@@ -156,7 +156,7 @@ void IpcConnection::threadMain()
 		_writeLock.unlock();
 	}
 
-	_handler(_arg,this,IPC_EVENT_CONNECTION_CLOSING,(const char *)0);
+	_handler(_arg,this,IPC_EVENT_CONNECTION_CLOSED,(const char *)0);
 #endif
 }
 

+ 1 - 1
node/IpcListener.cpp

@@ -124,7 +124,7 @@ void IpcListener::threadMain()
 			break;
 		}
 		try {
-			_handler(_arg,new IpcConnection(s,_handler,_arg),Ipcconnection::IPC_EVENT_NEW_CONNECTION,(const char *)0);
+			_handler(_arg,new IpcConnection(s,_handler,_arg),IpcConnection::IPC_EVENT_NEW_CONNECTION,(const char *)0);
 		} catch ( ... ) {} // handlers should not throw
 	}
 #endif

+ 3 - 3
node/IpcListener.hpp

@@ -37,9 +37,9 @@
 #include <stdexcept>
 
 #ifdef __WINDOWS__
-#define ZT_IPC_ENDPOINT "\\\\.\\pipe\\ZeroTierOne-control"
+#define ZT_IPC_ENDPOINT_BASE "\\\\.\\pipe\\ZeroTierOne-"
 #else
-#define ZT_IPC_ENDPOINT "/tmp/.ZeroTierOne-control"
+#define ZT_IPC_ENDPOINT_BASE "/tmp/.ZeroTierOne-"
 #endif
 
 namespace ZeroTier {
@@ -78,7 +78,7 @@ public:
 
 private:
 	std::string _endpoint;
-	void (*_handler)(void *,IpcConnection *,const char *);
+	void (*_handler)(void *,IpcConnection *,IpcConnection::EventType,const char *);
 	void *_arg;
 	volatile int _sock;
 	Thread _thread;

+ 118 - 152
node/Node.cpp

@@ -45,9 +45,7 @@
 #include <WinSock2.h>
 #include <Windows.h>
 #include <ShlObj.h>
-#endif
-
-#ifdef __UNIX_LIKE__
+#else
 #include <fcntl.h>
 #include <unistd.h>
 #include <signal.h>
@@ -55,176 +53,151 @@
 #endif
 
 #include "Node.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Logger.hpp"
+#include "Utils.hpp"
+#include "Defaults.hpp"
+#include "Identity.hpp"
 #include "Topology.hpp"
 #include "SocketManager.hpp"
-#include "Packet.hpp"
 #include "Switch.hpp"
-#include "Utils.hpp"
 #include "EthernetTap.hpp"
-#include "Logger.hpp"
-#include "InetAddress.hpp"
-#include "Salsa20.hpp"
-#include "RuntimeEnvironment.hpp"
+#include "CMWC4096.hpp"
 #include "NodeConfig.hpp"
-#include "Defaults.hpp"
 #include "SysEnv.hpp"
 #include "Network.hpp"
 #include "MulticastGroup.hpp"
 #include "Mutex.hpp"
 #include "Multicaster.hpp"
-#include "CMWC4096.hpp"
-#include "SHA512.hpp"
 #include "Service.hpp"
 #include "SoftwareUpdater.hpp"
 #include "Buffer.hpp"
+#include "IpcConnection.hpp"
 
 #include "../version.h"
 
 namespace ZeroTier {
 
-struct _LocalClientImpl
+// ---------------------------------------------------------------------------
+
+struct _NodeControlClientImpl
 {
-	unsigned char key[32];
-	int sock;
-	void (*resultHandler)(void *,unsigned long,const char *);
+	void (*resultHandler)(void *,const char *);
 	void *arg;
-	unsigned int controlPort;
-	InetAddress localDestAddr;
-	Mutex inUseLock;
-
-	void threadMain()
-		throw()
-	{
-	}
+	IpcConnection *ipcc;
+	std::string err;
 };
 
-static void _CBlocalClientHandler(const SharedPtr<Socket> &sock,void *arg,const InetAddress &from,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &data)
+static void _CBipcResultHandler(void *arg,IpcConnection *ipcc,IpcConnection::EventType event,const char *result)
 {
-	_LocalClientImpl *impl = (_LocalClientImpl *)arg;
-	if (!impl)
-		return;
-	if (!impl->resultHandler)
-		return; // sanity check
-	Mutex::Lock _l(impl->inUseLock);
-	try {
-		unsigned long convId = 0;
-		std::vector<std::string> results;
-		if (!NodeConfig::decodeControlMessagePacket(impl->key,data.data(),data.size(),convId,results))
-			return;
-		for(std::vector<std::string>::iterator r(results.begin());r!=results.end();++r)
-			impl->resultHandler(impl->arg,convId,r->c_str());
-	} catch ( ... ) {}
+	if ((event == IpcConnection::IPC_EVENT_COMMAND)&&(result))
+		((_NodeControlClientImpl *)arg)->resultHandler(((_NodeControlClientImpl *)arg)->arg,result);
 }
 
-Node::LocalClient::LocalClient(const char *authToken,unsigned int controlPort,void (*resultHandler)(void *,unsigned long,const char *),void *arg)
+Node::NodeControlClient::NodeControlClient(const char *hp,void (*resultHandler)(void *,const char *),void *arg,const char *authToken)
 	throw() :
-	_impl((void *)0)
+	_impl((void *)new _NodeControlClientImpl)
 {
-	_LocalClientImpl *impl = new _LocalClientImpl;
-
-	impl->sock = 
-
-	SocketManager *sm = (SocketManager *)0;
-	for(unsigned int i=0;i<5000;++i) {
-		try {
-			sm = new SocketManager(0,32768 + (rand() % 20000),&_CBlocalClientHandler,impl);
-			break;
-		} catch ( ... ) {
-			sm = (SocketManager *)0;
-		}
+	_NodeControlClientImpl *impl = (_NodeControlClientImpl *)_impl;
+
+	std::string at;
+	if (authToken)
+		at = authToken;
+	else if (!Utils::readFile((std::string(hp) + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),at))
+		impl->err = "no authentication token specified and authtoken.secret not readable";
+	else {
+		std::string myid;
+		if (Utils::readFile((std::string(hp) + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),myid)) {
+			std::string myaddr(myid.substr(0,myid.find(':')));
+			if (myaddr.length() != 10)
+				impl->err = "invalid address extracted from identity.public";
+			else {
+				try {
+					impl->resultHandler = resultHandler;
+					impl->arg = arg;
+					impl->ipcc = new IpcConnection((std::string(ZT_IPC_ENDPOINT_BASE) + myaddr).c_str(),&_CBipcResultHandler,_impl);
+					impl->ipcc->printf("auth %s"ZT_EOL_S,at.c_str());
+				} catch ( ... ) {
+					impl->err = "failure connecting to running ZeroTier One service";
+				}
+			}
+		} else impl->err = "unable to read identity.public";
 	}
-
-	if (sm) {
-		{
-			unsigned int csk[64];
-			SHA512::hash(csk,authToken,(unsigned int)strlen(authToken));
-			memcpy(impl->key,csk,32);
-		}
-
-		impl->sock = sock;
-		impl->resultHandler = resultHandler;
-		impl->arg = arg;
-		impl->controlPort = (controlPort) ? controlPort : (unsigned int)ZT_DEFAULT_CONTROL_UDP_PORT;
-		impl->localDestAddr = InetAddress::LO4;
-		impl->localDestAddr.setPort(impl->controlPort);
-		_impl = impl;
-	} else delete impl; // big problem, no ports?
 }
 
-Node::LocalClient::~LocalClient()
+Node::NodeControlClient::~NodeControlClient()
 {
 	if (_impl) {
-		((_LocalClientImpl *)_impl)->inUseLock.lock();
-		delete ((_LocalClientImpl *)_impl)->sock;
-		((_LocalClientImpl *)_impl)->inUseLock.unlock();
-		delete ((_LocalClientImpl *)_impl);
+		delete ((_NodeControlClientImpl *)_impl)->ipcc;
+		delete (_NodeControlClientImpl *)_impl;
 	}
 }
 
-unsigned long Node::LocalClient::send(const char *command)
+void Node::NodeControlClient::send(const char *command)
 	throw()
 {
-	if (!_impl)
-		return 0;
-	_LocalClientImpl *impl = (_LocalClientImpl *)_impl;
-	Mutex::Lock _l(impl->inUseLock);
-
 	try {
-		uint32_t convId = (uint32_t)rand();
-		if (!convId)
-			convId = 1;
-
-		std::vector<std::string> tmp;
-		tmp.push_back(std::string(command));
-		std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> > packets(NodeConfig::encodeControlMessage(impl->key,convId,tmp));
-
-		for(std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> >::iterator p(packets.begin());p!=packets.end();++p)
-			impl->sock->send(impl->localDestAddr,p->data(),p->size(),-1);
-
-		return convId;
-	} catch ( ... ) {
-		return 0;
-	}
+		((_NodeControlClientImpl *)_impl)->ipcc->printf("%s"ZT_EOL_S,command);
+	} catch ( ... ) {}
 }
 
-std::vector<std::string> Node::LocalClient::splitLine(const char *line)
+std::vector<std::string> Node::NodeControlClient::splitLine(const char *line)
 {
 	return Utils::split(line," ","\\","\"");
 }
 
-std::string Node::LocalClient::authTokenDefaultUserPath()
+const char *Node::NodeControlClient::authTokenDefaultUserPath()
 {
+	static std::string dlp;
+	static Mutex dlp_m;
+
+	Mutex::Lock _l(dlp_m);
+
 #ifdef __WINDOWS__
 
-	char buf[16384];
-	if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_APPDATA,NULL,0,buf)))
-		return (std::string(buf) + "\\ZeroTier\\One\\authtoken.secret");
-	else return std::string();
+	if (!dlp.length()) {
+		char buf[16384];
+		if (SUCCEEDED(SHGetFolderPathA(NULL,CSIDL_APPDATA,NULL,0,buf)))
+			dlp = (std::string(buf) + "\\ZeroTier\\One\\authtoken.secret");
+	}
 
 #else // not __WINDOWS__
 
-	const char *home = getenv("HOME");
-	if (home) {
+	if (!dlp.length()) {
+		const char *home = getenv("HOME");
+		if (home) {
 #ifdef __APPLE__
-		return (std::string(home) + "/Library/Application Support/ZeroTier/One/authtoken.secret");
+			dlp = (std::string(home) + "/Library/Application Support/ZeroTier/One/authtoken.secret");
 #else
-		return (std::string(home) + "/.zeroTierOneAuthToken");
+			dlp = (std::string(home) + "/.zeroTierOneAuthToken");
 #endif
-	} else return std::string();
+		}
+	}
 
 #endif // __WINDOWS__ or not __WINDOWS__
+
+	return dlp.c_str();
 }
 
-std::string Node::LocalClient::authTokenDefaultSystemPath()
+const char *Node::NodeControlClient::authTokenDefaultSystemPath()
 {
-	return (ZT_DEFAULTS.defaultHomePath + ZT_PATH_SEPARATOR_S"authtoken.secret");
+	static std::string dsp;
+	static Mutex dsp_m;
+
+	Mutex::Lock _l(dsp_m);
+
+	if (!dsp.length())
+		dsp = (ZT_DEFAULTS.defaultHomePath + ZT_PATH_SEPARATOR_S"authtoken.secret");
+
+	return dsp.c_str();
 }
 
+// ---------------------------------------------------------------------------
+
 struct _NodeImpl
 {
 	RuntimeEnvironment renv;
-	unsigned int port;
-	unsigned int controlPort;
+	unsigned int udpPort,tcpPort;
 	std::string reasonForTerminationStr;
 	volatile Node::ReasonForTermination reasonForTermination;
 	volatile bool started;
@@ -352,16 +325,35 @@ static void _netconfServiceMessageHandler(void *renv,Service &svc,const Dictiona
 }
 #endif // !__WINDOWS__
 
-Node::Node(const char *hp,unsigned int port,unsigned int controlPort)
+Node::Node(const char *hp,unsigned int udpPort,unsigned int tcpPort,bool resetIdentity)
 	throw() :
 	_impl(new _NodeImpl)
 {
 	_NodeImpl *impl = (_NodeImpl *)_impl;
-	if ((hp)&&(strlen(hp) > 0))
+
+	if ((hp)&&(hp[0]))
 		impl->renv.homePath = hp;
 	else impl->renv.homePath = ZT_DEFAULTS.defaultHomePath;
-	impl->port = (port) ? port : (unsigned int)ZT_DEFAULT_UDP_PORT;
-	impl->controlPort = (controlPort) ? controlPort : (unsigned int)ZT_DEFAULT_CONTROL_UDP_PORT;
+
+	if (resetIdentity) {
+		// Forget identity and peer database, peer keys, etc.
+		Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
+		Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
+		Utils::rm((impl->renv.homePath + ZT_PATH_SEPARATOR_S + "peers.persist").c_str());
+
+		// Truncate network config information in networks.d but leave the files since we
+		// still want to remember any networks we have joined. This will force re-config.
+		std::string networksDotD(impl->renv.homePath + ZT_PATH_SEPARATOR_S + "networks.d");
+		std::map< std::string,bool > nwfiles(Utils::listDirectory(networksDotD.c_str()));
+		for(std::map<std::string,bool>::iterator nwf(nwfiles.begin());nwf!=nwfiles.end();++nwf) {
+			FILE *foo = fopen((networksDotD + ZT_PATH_SEPARATOR_S + nwf->first).c_str(),"w");
+			if (foo)
+				fclose(foo);
+		}
+	}
+
+	impl->udpPort = ((udpPort > 0)&&(udpPort <= 0xffff)) ? udpPort : (unsigned int)ZT_DEFAULT_PORT;
+	impl->tcpPort = ((tcpPort > 0)&&(tcpPort <= 0xffff)) ? tcpPort : (unsigned int)ZT_DEFAULT_PORT;
 	impl->reasonForTermination = Node::NODE_RUNNING;
 	impl->started = false;
 	impl->running = false;
@@ -373,6 +365,13 @@ Node::~Node()
 	delete (_NodeImpl *)_impl;
 }
 
+static void _CBztTraffic(const SharedPtr<Socket> &fromSock,void *arg,const InetAddress &from,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &data)
+{
+	const RuntimeEnvironment *_r = (const RuntimeEnvironment *)arg;
+	if ((_r->sw)&&(!_r->shutdownInProgress))
+		_r->sw->onRemotePacket(fromSock,from,data);
+}
+
 Node::ReasonForTermination Node::run()
 	throw()
 {
@@ -452,15 +451,13 @@ Node::ReasonForTermination Node::run()
 		// Create the objects that make up runtime state.
 		_r->mc = new Multicaster();
 		_r->sw = new Switch(_r);
-		_r->demarc = new Demarc(_r);
+		_r->sm = new SocketManager(impl->udpPort,impl->tcpPort,&_CBztTraffic,_r);
 		_r->topology = new Topology(_r,Utils::fileExists((_r->homePath + ZT_PATH_SEPARATOR_S + "iddb.d").c_str()));
 		_r->sysEnv = new SysEnv();
 		try {
-			_r->nc = new NodeConfig(_r,configAuthToken.c_str(),impl->controlPort);
+			_r->nc = new NodeConfig(_r,configAuthToken.c_str());
 		} catch (std::exception &exc) {
-			char foo[1024];
-			Utils::snprintf(foo,sizeof(foo),"unable to bind to local control port %u: is another instance of ZeroTier One already running?",impl->controlPort);
-			return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,foo);
+			return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unable to initialize IPC socket: is ZeroTier One already running?");
 		}
 		_r->node = this;
 #ifdef ZT_AUTO_UPDATE
@@ -472,13 +469,6 @@ Node::ReasonForTermination Node::run()
 		}
 #endif
 
-		// Bind local port for core I/O
-		if (!_r->demarc->bindLocalUdp(impl->port)) {
-			char foo[1024];
-			Utils::snprintf(foo,sizeof(foo),"unable to bind to global I/O port %u: is another instance of ZeroTier One already running?",impl->controlPort);
-			return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,foo);
-		}
-
 		// Set initial supernode list
 		_r->topology->setSupernodes(ZT_DEFAULTS.supernodes);
 	} catch (std::bad_alloc &exc) {
@@ -669,14 +659,14 @@ void Node::terminate(ReasonForTermination reason,const char *reasonText)
 {
 	((_NodeImpl *)_impl)->reasonForTermination = reason;
 	((_NodeImpl *)_impl)->reasonForTerminationStr = ((reasonText) ? reasonText : "");
-	((_NodeImpl *)_impl)->renv.sw->whack();
+	((_NodeImpl *)_impl)->renv.sm->whack();
 }
 
 void Node::resync()
 	throw()
 {
 	((_NodeImpl *)_impl)->resynchronize = true;
-	((_NodeImpl *)_impl)->renv.sw->whack();
+	((_NodeImpl *)_impl)->renv.sm->whack();
 }
 
 class _VersionStringMaker
@@ -698,27 +688,3 @@ unsigned int Node::versionMinor() throw() { return ZEROTIER_ONE_VERSION_MINOR; }
 unsigned int Node::versionRevision() throw() { return ZEROTIER_ONE_VERSION_REVISION; }
 
 } // namespace ZeroTier
-
-extern "C" {
-
-ZeroTier::Node *zeroTierCreateNode(const char *hp,unsigned int port,unsigned int controlPort)
-{
-	return new ZeroTier::Node(hp,port,controlPort);
-}
-
-void zeroTierDeleteNode(ZeroTier::Node *n)
-{
-	delete n;
-}
-
-ZeroTier::Node::LocalClient *zeroTierCreateLocalClient(const char *authToken,unsigned int controlPort,void (*resultHandler)(void *,unsigned long,const char *),void *arg)
-{
-	return new ZeroTier::Node::LocalClient(authToken,controlPort,resultHandler,arg);
-}
-
-void zeroTierDeleteLocalClient(ZeroTier::Node::LocalClient *lc)
-{
-	delete lc;
-}
-
-} // extern "C"

+ 37 - 42
node/Node.hpp

@@ -50,20 +50,28 @@ public:
 	 * otherwise it will be unable to open a local UDP socket to
 	 * communicate with the service.
 	 */
-	class LocalClient
+	class NodeControlClient
 	{
 	public:
 		/**
 		 * Create a new node config client
 		 *
-		 * @param authToken Authentication token
-		 * @param controlPort Control port or 0 for 39393 (default)
+		 * Initialization may fail. Call error() to check.
+		 *
+		 * @param hp Home path of ZeroTier One instance
 		 * @param resultHandler Function to call when commands provide results
+		 * @param arg First argument to result handler
+		 * @param authToken Authentication token or NULL (default) to read from authtoken.secret in home path
 		 */
-		LocalClient(const char *authToken,unsigned int controlPort,void (*resultHandler)(void *,unsigned long,const char *),void *arg)
+		NodeControlClient(const char *hp,void (*resultHandler)(void *,const char *),void *arg,const char *authToken = (const char *)0)
 			throw();
 
-		~LocalClient();
+		~NodeControlClient();
+
+		/**
+		 * @return Initialization error or NULL if none
+		 */
+		const char *error() const;
 
 		/**
 		 * Send a command to the local node
@@ -75,12 +83,13 @@ public:
 		 * @param command
 		 * @return Conversation ID that will be provided to result handler when/if results are sent back
 		 */
-		unsigned long send(const char *command)
+		void send(const char *command)
 			throw();
-		inline unsigned long send(const std::string &command) throw() { return send(command.c_str()); }
+		inline void send(const std::string &command)
+			throw() { return send(command.c_str()); }
 
 		/**
-		 * Split a line of results by space
+		 * Split a line of results
 		 *
 		 * @param line Line to split
 		 * @return Vector of fields
@@ -89,19 +98,19 @@ public:
 		static inline std::vector<std::string> splitLine(const std::string &line) { return splitLine(line.c_str()); }
 
 		/**
-		 * @return Default path for user-local authorization token for the current user or empty string if cannot be determined
+		 * @return Default path for current user's authtoken.secret
 		 */
-		static std::string authTokenDefaultUserPath();
+		static const char *authTokenDefaultUserPath();
 
 		/**
-		 * @return Default system path for auth token on this platform
+		 * @return Default path to system authtoken.secret
 		 */
-		static std::string authTokenDefaultSystemPath();
+		static const char *authTokenDefaultSystemPath();
 
 	private:
-		// LocalClient is not copyable
-		LocalClient(const LocalClient&);
-		const LocalClient& operator=(const LocalClient&);
+		// NodeControlClient is not copyable
+		NodeControlClient(const NodeControlClient&);
+		const NodeControlClient& operator=(const NodeControlClient&);
 
 		void *_impl;
 	};
@@ -129,7 +138,12 @@ public:
 		/**
 		 * A serious unrecoverable error has occurred.
 		 */
-		NODE_UNRECOVERABLE_ERROR = 3
+		NODE_UNRECOVERABLE_ERROR = 3,
+
+		/**
+		 * An address collision occurred (typically this should cause re-invocation with resetIdentity set to true)
+		 */
+		NODE_ADDRESS_COLLISION = 4
 	};
 
 	/**
@@ -137,11 +151,12 @@ public:
 	 *
 	 * The node is not executed until run() is called.
 	 *
-	 * @param hp Home directory path
-	 * @param port Port to bind for talking to the ZT1 network or 0 for 9993 (default)
-	 * @param controlPort Port to bind locally for control packets or 0 for 39393 (default)
+	 * @param hp Home directory path or NULL for system-wide default for this platform (default: NULL)
+	 * @param udpPort UDP port or 0 for default (9993) (default: 0)
+	 * @param tcpPort TCP port or 0 for default (9993) (default: 0)
+	 * @param resetIdentity If true, delete identity before starting and regenerate (default: false)
 	 */
-	Node(const char *hp,unsigned int port,unsigned int controlPort)
+	Node(const char *hp = (const char *)0,unsigned int udpPort = 0,unsigned int tcpPort = 0,bool resetIdentity = false)
 		throw();
 
 	~Node();
@@ -181,19 +196,12 @@ public:
 		throw();
 
 	/**
-	 * Forget p2p links and resynchronize with peers
+	 * Forget p2p links now and resynchronize with peers
 	 */
 	void resync()
 		throw();
 
-	/**
-	 * Get the ZeroTier version in major.minor.revision string format
-	 *
-	 * @return Version in string form
-	 */
-	static const char *versionString()
-		throw();
-
+	static const char *versionString() throw();
 	static unsigned int versionMajor() throw();
 	static unsigned int versionMinor() throw();
 	static unsigned int versionRevision() throw();
@@ -208,17 +216,4 @@ private:
 
 } // namespace ZeroTier
 
-extern "C" {
-
-// Functions with C-style linkage for easy DLL symbol table
-// lookup. These just create instances of Node and LocalClient.
-
-ZeroTier::Node *zeroTierCreateNode(const char *hp,unsigned int port,unsigned int controlPort);
-void zeroTierDeleteNode(ZeroTier::Node *n);
-
-ZeroTier::Node::LocalClient *zeroTierCreateLocalClient(const char *authToken,unsigned int controlPort,void (*resultHandler)(void *,unsigned long,const char *),void *arg);
-void zeroTierDeleteLocalClient(ZeroTier::Node::LocalClient *lc);
-
-} // extern "C"
-
 #endif

+ 3 - 3
node/NodeConfig.cpp

@@ -53,7 +53,7 @@ namespace ZeroTier {
 
 NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken) :
 	_r(renv),
-	_ipcListener(ZT_IPC_ENDPOINT,&_CBcommandHandler,this),
+	_ipcListener((std::string(ZT_IPC_ENDPOINT_BASE) + renv->identity.address().toString()).c_str(),&_CBcommandHandler,this),
 	_authToken(authToken)
 {
 	{
@@ -177,8 +177,8 @@ public:
 
 void NodeConfig::_doCommand(IpcConnection *ipcc,const char *commandLine)
 {
-	if (!commandLine)
-		return; // sanity check
+	if ((!commandLine)||(!commandLine[0]))
+		return;
 	std::vector<std::string> r;
 	std::vector<std::string> cmd(Utils::split(commandLine,"\r\n \t","\\","'"));
 

+ 29 - 30
node/PacketDecoder.cpp

@@ -40,7 +40,6 @@
 #include "Peer.hpp"
 #include "NodeConfig.hpp"
 #include "Service.hpp"
-#include "Demarc.hpp"
 #include "SoftwareUpdater.hpp"
 
 namespace ZeroTier {
@@ -82,7 +81,7 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
 
 		switch(verb()) {
 			case Packet::VERB_NOP:
-				peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_NOP,0,Packet::VERB_NOP,Utils::now());
+				peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_NOP,0,Packet::VERB_NOP,Utils::now());
 				return true;
 			case Packet::VERB_HELLO:
 				return _doHELLO(_r); // legal, but why? :)
@@ -156,7 +155,7 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 				break;
 		}
 
-		peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,Utils::now());
+		peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_ERROR,inRePacketId,inReVerb,Utils::now());
 	} catch (std::exception &ex) {
 		TRACE("dropped ERROR from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
 	} catch ( ... ) {
@@ -200,7 +199,7 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r)
 						outp.append(packetId());
 						outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
 						outp.armor(key,true);
-						_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+						_fromSock->send(_remoteAddress,outp.data(),outp.size());
 					} else {
 						LOG("rejected HELLO from %s(%s): packet failed authentication",source().toString().c_str(),_remoteAddress.toString().c_str());
 					}
@@ -227,7 +226,7 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r)
 						outp.append(packetId());
 						outp.append((unsigned char)Packet::ERROR_IDENTITY_COLLISION);
 						outp.armor(key,true);
-						_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+						_fromSock->send(_remoteAddress,outp.data(),outp.size());
 					} else {
 						LOG("rejected HELLO from %s(%s): packet failed authentication",source().toString().c_str(),_remoteAddress.toString().c_str());
 					}
@@ -246,7 +245,7 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r)
 			peer = _r->topology->addPeer(newPeer);
 		}
 
-		peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP,Utils::now());
+		peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_HELLO,0,Packet::VERB_NOP,Utils::now());
 		peer->setRemoteVersion(vMajor,vMinor,vRevision);
 
 		// If a supernode has a version higher than ours, this causes a software
@@ -263,7 +262,7 @@ bool PacketDecoder::_doHELLO(const RuntimeEnvironment *_r)
 		outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
 		outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
 		outp.armor(peer->key(),true);
-		_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+		_fromSock->send(_remoteAddress,outp.data(),outp.size());
 	} catch (std::exception &ex) {
 		TRACE("dropped HELLO from %s(%s): %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
 	} catch ( ... ) {
@@ -324,7 +323,7 @@ bool PacketDecoder::_doOK(const RuntimeEnvironment *_r,const SharedPtr<Peer> &pe
 				break;
 		}
 
-		peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,Utils::now());
+		peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,Utils::now());
 	} catch (std::exception &ex) {
 		TRACE("dropped OK from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
 	} catch ( ... ) {
@@ -343,7 +342,7 @@ bool PacketDecoder::_doWHOIS(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 			outp.append(packetId());
 			id.serialize(outp,false);
 			outp.armor(peer->key(),true);
-			_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+			_fromSock->send(_remoteAddress,outp.data(),outp.size());
 			//TRACE("sent WHOIS response to %s for %s",source().toString().c_str(),Address(payload(),ZT_ADDRESS_LENGTH).toString().c_str());
 		} else {
 			Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
@@ -352,13 +351,13 @@ bool PacketDecoder::_doWHOIS(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 			outp.append((unsigned char)Packet::ERROR_OBJ_NOT_FOUND);
 			outp.append(payload(),ZT_ADDRESS_LENGTH);
 			outp.armor(peer->key(),true);
-			_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+			_fromSock->send(_remoteAddress,outp.data(),outp.size());
 			//TRACE("sent WHOIS ERROR to %s for %s (not found)",source().toString().c_str(),Address(payload(),ZT_ADDRESS_LENGTH).toString().c_str());
 		}
 	} else {
 		TRACE("dropped WHOIS from %s(%s): missing or invalid address",source().toString().c_str(),_remoteAddress.toString().c_str());
 	}
-	peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,Utils::now());
+	peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_WHOIS,0,Packet::VERB_NOP,Utils::now());
 	return true;
 }
 
@@ -387,7 +386,7 @@ bool PacketDecoder::_doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr<P
 				if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
 					InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
 					TRACE("RENDEZVOUS from %s says %s might be at %s, starting NAT-t",source().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
-					peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,Utils::now());
+					peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_RENDEZVOUS,0,Packet::VERB_NOP,Utils::now());
 					_r->sw->contact(withPeer,atAddr);
 				} else {
 					TRACE("dropped corrupt RENDEZVOUS from %s(%s) (bad address or port)",source().toString().c_str(),_remoteAddress.toString().c_str());
@@ -426,7 +425,7 @@ bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 				// we receive unicast frames from it. This is called "implicit social
 				// ordering" in other docs.
 				_r->mc->bringCloser(network->id(),source());
-				peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,Utils::now());
+				peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,Utils::now());
 			} else {
 				TRACE("dropped FRAME from %s(%s): sender not a member of closed network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),network->id());
 
@@ -436,7 +435,7 @@ bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 				outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
 				outp.append(network->id());
 				outp.armor(peer->key(),true);
-				_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+				_fromSock->send(_remoteAddress,outp.data(),outp.size());
 
 				return true;
 			}
@@ -569,11 +568,11 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 			source().toString().c_str(),
 			frameLen,
 			startingFifoItems);
-		_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+		_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 
 		// At this point the frame is basically valid, so we can call it a receive
-		peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,Utils::now());
+		peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,Utils::now());
 
 		// This gets updated later in most cases but start with the global limit.
 		unsigned int maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH;
@@ -592,7 +591,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 					mctdepth,
 					(_r->topology->amSupernode() ? 'S' : '-'),
 					_r->identity.address().toString().c_str());
-				_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+				_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 				TRACE("dropped MULTICAST_FRAME from %s(%s): duplicate",source().toString().c_str(),_remoteAddress.toString().c_str());
 				return true;
@@ -619,7 +618,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 						outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
 						outp.append(nwid);
 						outp.armor(peer->key(),true);
-						_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+						_fromSock->send(_remoteAddress,outp.data(),outp.size());
 
 						// We do not terminate here, since if the member just has an out of
 						// date cert or hasn't sent us a cert yet we still want to propagate
@@ -638,7 +637,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 							mctdepth,
 							(_r->topology->amSupernode() ? 'S' : '-'),
 							_r->identity.address().toString().c_str());
-						_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+						_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 						TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,sourceMac.toString().c_str(),origin.toString().c_str());
 						return true;
@@ -654,7 +653,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 							mctdepth,
 							(_r->topology->amSupernode() ? 'S' : '-'),
 							_r->identity.address().toString().c_str());
-						_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+						_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 						TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: ethertype %u is not allowed",source().toString().c_str(),nwid,_remoteAddress.toString().c_str(),etherType);
 						return true;
@@ -671,7 +670,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 							mctdepth,
 							(_r->topology->amSupernode() ? 'S' : '-'),
 							_r->identity.address().toString().c_str());
-						_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+						_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 						TRACE("dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str());
 						return true;
@@ -692,7 +691,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 				mctdepth,
 				(_r->topology->amSupernode() ? 'S' : '-'),
 				_r->identity.address().toString().c_str());
-			_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+			_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 			TRACE("not forwarding MULTICAST_FRAME from %s(%s): depth == 0xffff (do not forward)",source().toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
@@ -707,7 +706,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 				mctdepth,
 				(_r->topology->amSupernode() ? 'S' : '-'),
 				_r->identity.address().toString().c_str());
-			_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+			_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 			TRACE("not forwarding MULTICAST_FRAME from %s(%s): max propagation depth reached",source().toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
@@ -766,7 +765,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 				mctdepth,
 				(_r->topology->amSupernode() ? 'S' : '-'),
 				_r->identity.address().toString().c_str());
-			_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+			_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 			//TRACE("not forwarding MULTICAST_FRAME from %s(%s): no next hop",source().toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
@@ -787,7 +786,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
 			origin.toString().c_str(),
 			nextHop.toString().c_str(),
 			numAdded);
-		_r->demarc->send(Demarc::ANY_PORT,ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct),-1);
+		_r->sm->send(ZT_DEFAULTS.multicastTraceWatcher,false,mct,strlen(mct));
 #endif
 
 		// Send to next hop, reusing this packet as scratch space
@@ -824,7 +823,7 @@ bool PacketDecoder::_doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedP
 			}
 		}
 
-		peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,now);
+		peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,now);
 	} catch (std::exception &ex) {
 		TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
 	} catch ( ... ) {
@@ -860,7 +859,7 @@ bool PacketDecoder::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *
 			}
 		}
 
-		peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP,Utils::now());
+		peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE,0,Packet::VERB_NOP,Utils::now());
 	} catch (std::exception &ex) {
 		TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());
 	} catch ( ... ) {
@@ -899,11 +898,11 @@ bool PacketDecoder::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *_r,const
 			outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
 			outp.append(nwid);
 			outp.armor(peer->key(),true);
-			_r->demarc->send(_localPort,_remoteAddress,outp.data(),outp.size(),-1);
+			_fromSock->send(_remoteAddress,outp.data(),outp.size());
 #ifndef __WINDOWS__
 		}
 #endif // !__WINDOWS__
-		peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,Utils::now());
+		peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REQUEST,0,Packet::VERB_NOP,Utils::now());
 	} catch (std::exception &exc) {
 		TRACE("dropped NETWORK_CONFIG_REQUEST from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
 	} catch ( ... ) {
@@ -924,7 +923,7 @@ bool PacketDecoder::_doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *_r,const
 				nw->requestConfiguration();
 			}
 		}
-		peer->onReceive(_r,_localPort,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,Utils::now());
+		peer->onReceive(_r,_remoteAddress,hops(),packetId(),Packet::VERB_NETWORK_CONFIG_REFRESH,0,Packet::VERB_NOP,Utils::now());
 	} catch (std::exception &exc) {
 		TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),exc.what());
 	} catch ( ... ) {

+ 5 - 4
node/PacketDecoder.hpp

@@ -37,6 +37,7 @@
 #include "SharedPtr.hpp"
 #include "AtomicCounter.hpp"
 #include "Peer.hpp"
+#include "Socket.hpp"
 
 /*
  * The big picture:
@@ -70,16 +71,16 @@ public:
 	 * Create a new packet-in-decode
 	 *
 	 * @param b Source buffer with raw packet data
-	 * @param localPort Local port on which packet was received
+	 * @param fromSock Socket on which packet was received
 	 * @param remoteAddress Address from which packet came
 	 * @throws std::out_of_range Range error processing packet
 	 */
 	template<unsigned int C2>
-	PacketDecoder(const Buffer<C2> &b,Demarc::Port localPort,const InetAddress &remoteAddress)
+	PacketDecoder(const Buffer<C2> &b,const SharedPtr<Socket> &fromSock,const InetAddress &remoteAddress)
  		throw(std::out_of_range) :
  		Packet(b),
  		_receiveTime(Utils::now()),
- 		_localPort(localPort),
+ 		_fromSock(fromSock),
  		_remoteAddress(remoteAddress),
  		_step(DECODE_WAITING_FOR_SENDER_LOOKUP),
  		__refCount()
@@ -124,7 +125,7 @@ private:
 	bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 
 	uint64_t _receiveTime;
-	Demarc::Port _localPort;
+	SharedPtr<Socket> _fromSock;
 	InetAddress _remoteAddress;
 
 	enum {

+ 6 - 8
node/Peer.cpp

@@ -67,7 +67,6 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 
 void Peer::onReceive(
 	const RuntimeEnvironment *_r,
-	Demarc::Port localPort,
 	const InetAddress &remoteAddr,
 	unsigned int hops,
 	uint64_t packetId,
@@ -80,7 +79,6 @@ void Peer::onReceive(
 		// Update last receive info for our direct path
 		WanPath *const wp = (remoteAddr.isV4() ? &_ipv4p : &_ipv6p);
 		wp->lastReceive = now;
-		wp->localPort = ((localPort) ? localPort : Demarc::ANY_PORT);
 		if (!wp->fixed)
 			wp->addr = remoteAddr;
 
@@ -101,14 +99,14 @@ void Peer::onReceive(
 bool Peer::send(const RuntimeEnvironment *_r,const void *data,unsigned int len,uint64_t now)
 {
 	if ((_ipv6p.isActive(now))||((!(_ipv4p.addr))&&(_ipv6p.addr))) {
-		if (_r->demarc->send(_ipv6p.addr,data,len,-1)) {
+		if (_r->sm->send(_ipv6p.addr,false,data,len)) {
 			_ipv6p.lastSend = now;
 			return true;
 		}
 	}
 
 	if (_ipv4p.addr) {
-		if (_r->sm->send(_ipv4p.addr,data,len,-1)) {
+		if (_r->sm->send(_ipv4p.addr,false,data,len)) {
 			_ipv4p.lastSend = now;
 			return true;
 		}
@@ -121,14 +119,14 @@ bool Peer::sendFirewallOpener(const RuntimeEnvironment *_r,uint64_t now)
 {
 	bool sent = false;
 	if (_ipv4p.addr) {
-		if (_r->demarc->send(_ipv4p.localPort,_ipv4p.addr,"\0",1,ZT_FIREWALL_OPENER_HOPS)) {
+		if (_r->sm->sendFirewallOpener(_ipv4p.addr,ZT_FIREWALL_OPENER_HOPS)) {
 			_ipv4p.lastFirewallOpener = now;
 			sent = true;
 		}
 	}
 
 	if (_ipv6p.addr) {
-		if (_r->demarc->send(_ipv6p.localPort,_ipv6p.addr,"\0",1,ZT_FIREWALL_OPENER_HOPS)) {
+		if (_r->sm->sendFirewallOpener(_ipv6p.addr,ZT_FIREWALL_OPENER_HOPS)) {
 			_ipv6p.lastFirewallOpener = now;
 			sent = true;
 		}
@@ -142,7 +140,7 @@ bool Peer::sendPing(const RuntimeEnvironment *_r,uint64_t now)
 	bool sent = false;
 	if (_ipv4p.addr) {
 		TRACE("PING %s(%s)",_id.address().toString().c_str(),_ipv4p.addr.toString().c_str());
-		if (_r->sw->sendHELLO(SharedPtr<Peer>(this),_ipv4p.localPort,_ipv4p.addr)) {
+		if (_r->sw->sendHELLO(SharedPtr<Peer>(this),_ipv4p.addr,false)) {
 			_ipv4p.lastSend = now;
 			sent = true;
 		}
@@ -150,7 +148,7 @@ bool Peer::sendPing(const RuntimeEnvironment *_r,uint64_t now)
 
 	if (_ipv6p.addr) {
 		TRACE("PING %s(%s)",_id.address().toString().c_str(),_ipv6p.addr.toString().c_str());
-		if (_r->sw->sendHELLO(SharedPtr<Peer>(this),_ipv6p.localPort,_ipv6p.addr)) {
+		if (_r->sw->sendHELLO(SharedPtr<Peer>(this),_ipv6p.addr,false)) {
 			_ipv6p.lastSend = now;
 			sent = true;
 		}

+ 1 - 1
node/SocketManager.cpp

@@ -427,7 +427,7 @@ void SocketManager::poll(unsigned long timeout)
 			ts.reserve(_tcpSockets.size());
 			uint64_t now = Utils::now();
 			for(std::map< InetAddress,SharedPtr<Socket> >::iterator s(_tcpSockets.begin());s!=_tcpSockets.end();) {
-				if ((now - ((TcpSocket *)s->second.get())->_lastActivity) < ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT) {
+				if ((now - ((TcpSocket *)s->second.ptr())->_lastActivity) < ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT) {
 					ts.push_back(s->second);
 					++s;
 				} else {

+ 26 - 15
node/Switch.cpp

@@ -47,7 +47,6 @@
 #include "RuntimeEnvironment.hpp"
 #include "Peer.hpp"
 #include "NodeConfig.hpp"
-#include "Demarc.hpp"
 #include "CMWC4096.hpp"
 
 #include "../version.h"
@@ -64,14 +63,14 @@ Switch::~Switch()
 {
 }
 
-void Switch::onRemotePacket(Demarc::Port localPort,const InetAddress &fromAddr,const Buffer<4096> &data)
+void Switch::onRemotePacket(const SharedPtr<Socket> &fromSock,const InetAddress &fromAddr,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &data)
 {
 	try {
 		if (data.size() > ZT_PROTO_MIN_FRAGMENT_LENGTH) {
 			if (data[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR)
-				_handleRemotePacketFragment(localPort,fromAddr,data);
+				_handleRemotePacketFragment(fromSock,fromAddr,data);
 			else if (data.size() >= ZT_PROTO_MIN_PACKET_LENGTH)
-				_handleRemotePacketHead(localPort,fromAddr,data);
+				_handleRemotePacketHead(fromSock,fromAddr,data);
 		}
 	} catch (std::exception &ex) {
 		TRACE("dropped packet from %s: unexpected exception: %s",fromAddr.toString().c_str(),ex.what());
@@ -207,7 +206,7 @@ void Switch::sendHELLO(const Address &dest)
 	send(outp,false);
 }
 
-bool Switch::sendHELLO(const SharedPtr<Peer> &dest,Demarc::Port localPort,const InetAddress &remoteAddr)
+bool Switch::sendHELLO(const SharedPtr<Socket> &fromSock,const SharedPtr<Peer> &dest,const InetAddress &remoteAddr)
 {
 	uint64_t now = Utils::now();
 	Packet outp(dest->address(),_r->identity.address(),Packet::VERB_HELLO);
@@ -218,7 +217,21 @@ bool Switch::sendHELLO(const SharedPtr<Peer> &dest,Demarc::Port localPort,const
 	outp.append(now);
 	_r->identity.serialize(outp,false);
 	outp.armor(dest->key(),false);
-	return (_r->demarc->send(localPort,remoteAddr,outp.data(),outp.size(),-1) != Demarc::NULL_PORT);
+	return fromSock->send(remoteAddr,outp.data(),outp.size());
+}
+
+bool Switch::sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &remoteAddr,bool tcp)
+{
+	uint64_t now = Utils::now();
+	Packet outp(dest->address(),_r->identity.address(),Packet::VERB_HELLO);
+	outp.append((unsigned char)ZT_PROTO_VERSION);
+	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR);
+	outp.append((unsigned char)ZEROTIER_ONE_VERSION_MINOR);
+	outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
+	outp.append(now);
+	_r->identity.serialize(outp,false);
+	outp.armor(dest->key(),false);
+	return _r->sm->send(remoteAddr,tcp,outp.data(),outp.size());
 }
 
 bool Switch::unite(const Address &p1,const Address &p2,bool force)
@@ -311,12 +324,11 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 
 void Switch::contact(const SharedPtr<Peer> &peer,const InetAddress &atAddr)
 {
-	Demarc::Port fromPort = _r->demarc->pick(atAddr);
-	_r->demarc->send(fromPort,atAddr,"\0",1,ZT_FIREWALL_OPENER_HOPS);
+	_r->sm->sendFirewallOpener(atAddr,ZT_FIREWALL_OPENER_HOPS);
 
 	{
 		Mutex::Lock _l(_contactQueue_m);
-		_contactQueue.push_back(ContactQueueEntry(peer,Utils::now() + ZT_RENDEZVOUS_NAT_T_DELAY,fromPort,atAddr));
+		_contactQueue.push_back(ContactQueueEntry(peer,Utils::now() + ZT_RENDEZVOUS_NAT_T_DELAY,atAddr));
 	}
 
 	// Kick main loop out of wait so that it can pick up this
@@ -334,7 +346,7 @@ unsigned long Switch::doTimerTasks()
 		for(std::list<ContactQueueEntry>::iterator qi(_contactQueue.begin());qi!=_contactQueue.end();) {
 			if (now >= qi->fireAtTime) {
 				TRACE("sending NAT-T HELLO to %s(%s)",qi->peer->address().toString().c_str(),qi->inaddr.toString().c_str());
-				sendHELLO(qi->peer,qi->localPort,qi->inaddr);
+				sendHELLO(qi->peer,qi->inaddr,false);
 				_contactQueue.erase(qi++);
 			} else {
 				nextDelay = std::min(nextDelay,(unsigned long)(qi->fireAtTime - now));
@@ -529,7 +541,7 @@ const char *Switch::etherTypeName(const unsigned int etherType)
 	return "UNKNOWN";
 }
 
-void Switch::_handleRemotePacketFragment(Demarc::Port localPort,const InetAddress &fromAddr,const Buffer<4096> &data)
+void Switch::_handleRemotePacketFragment(const SharedPtr<Socket> &fromSock,const InetAddress &fromAddr,const Buffer<4096> &data)
 {
 	Packet::Fragment fragment(data);
 	Address destination(fragment.destination());
@@ -598,9 +610,9 @@ void Switch::_handleRemotePacketFragment(Demarc::Port localPort,const InetAddres
 	}
 }
 
-void Switch::_handleRemotePacketHead(Demarc::Port localPort,const InetAddress &fromAddr,const Buffer<4096> &data)
+void Switch::_handleRemotePacketHead(const SharedPtr<Socket> &fromSock,const InetAddress &fromAddr,const Buffer<4096> &data)
 {
-	SharedPtr<PacketDecoder> packet(new PacketDecoder(data,localPort,fromAddr));
+	SharedPtr<PacketDecoder> packet(new PacketDecoder(data,fromSock,fromAddr));
 
 	Address source(packet->source());
 	Address destination(packet->destination());
@@ -711,8 +723,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt)
 
 		tmp.armor(peer->key(),encrypt);
 
-		Demarc::Port localPort;
-		if ((localPort = via->send(_r,tmp.data(),chunkSize,now))) {
+		if (via->send(_r,tmp.data(),chunkSize,now)) {
 			if (chunkSize < tmp.size()) {
 				// Too big for one bite, fragment the rest
 				unsigned int fragStart = chunkSize;

+ 19 - 11
node/Switch.hpp

@@ -44,9 +44,9 @@
 #include "Array.hpp"
 #include "Network.hpp"
 #include "SharedPtr.hpp"
-#include "SocketManager.hpp"
 #include "Multicaster.hpp"
 #include "PacketDecoder.hpp"
+#include "Socket.hpp"
 
 /* Ethernet frame types that might be relevant to us */
 #define ZT_ETHERTYPE_IPV4 0x0800
@@ -78,11 +78,11 @@ public:
 	/**
 	 * Called when a packet is received from the real network
 	 *
-	 * @param localPort Local port on which packet was received
+	 * @param fromSock Originating socket
 	 * @param fromAddr Internet IP address of origin
 	 * @param data Packet data
 	 */
-	void onRemotePacket(Demarc::Port localPort,const InetAddress &fromAddr,const Buffer<4096> &data);
+	void onRemotePacket(const SharedPtr<Socket> &fromSock,const InetAddress &fromAddr,Buffer<ZT_SOCKET_MAX_MESSAGE_LEN> &data);
 
 	/**
 	 * Called when a packet comes from a local Ethernet tap
@@ -122,12 +122,22 @@ public:
 	/**
 	 * Send a HELLO announcement immediately to the indicated address
 	 *
-	 * @param localPort Originating local port or ANY_PORT to pick
-	 * @param remoteAddr IP address to send to
+	 * @param fromSock Send from this local socket
 	 * @param dest Destination peer
+	 * @param remoteAddr Remote address
 	 * @return True if send appears successful
 	 */
-	bool sendHELLO(const SharedPtr<Peer> &dest,Demarc::Port localPort,const InetAddress &remoteAddr);
+	bool sendHELLO(const SharedPtr<Socket> &fromSock,const SharedPtr<Peer> &dest,const InetAddress &remoteAddr);
+
+	/**
+	 * Send a HELLO announcement immediately to the indicated address
+	 *
+	 * @param dest Destination peer
+	 * @param remoteAddr Remote address
+	 * @param tcp Attempt to use TCP?
+	 * @return True if send appears successful
+	 */
+	bool sendHELLO(const SharedPtr<Peer> &dest,const InetAddress &remoteAddr,bool tcp);
 
 	/**
 	 * Send RENDEZVOUS to two peers to permit them to directly connect
@@ -214,12 +224,12 @@ public:
 
 private:
 	void _handleRemotePacketFragment(
-		Demarc::Port localPort,
+		const SharedPtr<Socket> &fromSock,
 		const InetAddress &fromAddr,
 		const Buffer<4096> &data);
 
 	void _handleRemotePacketHead(
-		Demarc::Port localPort,
+		const SharedPtr<Socket> &fromSock,
 		const InetAddress &fromAddr,
 		const Buffer<4096> &data);
 
@@ -279,15 +289,13 @@ private:
 	struct ContactQueueEntry
 	{
 		ContactQueueEntry() {}
-		ContactQueueEntry(const SharedPtr<Peer> &p,uint64_t ft,Demarc::Port lp,const InetAddress &a) :
+		ContactQueueEntry(const SharedPtr<Peer> &p,uint64_t ft,const InetAddress &a) :
 			peer(p),
 			fireAtTime(ft),
-			localPort(lp),
 			inaddr(a) {}
 
 		SharedPtr<Peer> peer;
 		uint64_t fireAtTime;
-		Demarc::Port localPort;
 		InetAddress inaddr;
 	};
 	std::list<ContactQueueEntry> _contactQueue;

+ 18 - 44
selftest.cpp

@@ -44,7 +44,6 @@
 #include "node/Salsa20.hpp"
 #include "node/MAC.hpp"
 #include "node/Peer.hpp"
-#include "node/Condition.hpp"
 #include "node/NodeConfig.hpp"
 #include "node/Dictionary.hpp"
 #include "node/EthernetTap.hpp"
@@ -66,7 +65,7 @@ using namespace ZeroTier;
 
 static unsigned char fuzzbuf[1048576];
 
-static Condition webDoneCondition;
+static volatile bool webDone = false;
 static std::string webSha512ShouldBe;
 static void testHttpHandler(void *arg,int code,const std::string &url,bool onDisk,const std::string &body)
 {
@@ -77,45 +76,52 @@ static void testHttpHandler(void *arg,int code,const std::string &url,bool onDis
 			std::cout << "got " << body.length() << " bytes, response code " << code << ", SHA-512 OK" << std::endl;
 		else std::cout << "got " << body.length() << " bytes, response code " << code << ", SHA-512 FAILED!" << std::endl;
 	} else std::cout << "ERROR " << code << ": " << body << std::endl;
-	webDoneCondition.signal();
+	webDone = true;
 }
 
 static int testHttp()
 {
 	webSha512ShouldBe = "221b348c8278ad2063c158fb15927c35dc6bb42880daf130d0574025f88ec350811c34fae38a014b576d3ef5c98af32bb540e68204810db87a51fa9b239ea567";
 	std::cout << "[http] fetching http://download.zerotier.com/dev/1k ... "; std::cout.flush();
+	webDone = false;
 	HttpClient::GET("http://download.zerotier.com/dev/1k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	webDoneCondition.wait();
+	while (!webDone) Thread::sleep(500);
 
 	webSha512ShouldBe = "342e1a058332aad2d7a5412c1d9cd4ad02b4038178ca0c3ed9d34e3cf0905c118b684e5d2a935a158195d453d7d69e9c6e201e252620fb53f29611794a5d4b0c";
 	std::cout << "[http] fetching http://download.zerotier.com/dev/2k ... "; std::cout.flush();
+	webDone = false;
 	HttpClient::GET("http://download.zerotier.com/dev/2k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	webDoneCondition.wait();
+	while (!webDone) Thread::sleep(500);
 
 	webSha512ShouldBe = "439562e1471dd6bdb558cb680f38dd7742e521497e280cb1456a31f74b9216b7d98145b3896c2f68008e6ac0c1662a4cb70562caeac294c5d01f378b22a21292";
 	std::cout << "[http] fetching http://download.zerotier.com/dev/4k ... "; std::cout.flush();
+	webDone = false;
 	HttpClient::GET("http://download.zerotier.com/dev/4k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	webDoneCondition.wait();
+	while (!webDone) Thread::sleep(500);
 
 	webSha512ShouldBe = "fbd3901a9956158b9d290efa1af4fff459d8c03187c98b0e630d10a19fab61940e668652257763973f6cde34f2aa81574f9a50b1979b675b45ddd18d69a4ceb8";
 	std::cout << "[http] fetching http://download.zerotier.com/dev/8k ... "; std::cout.flush();
+	webDone = false;
 	HttpClient::GET("http://download.zerotier.com/dev/8k",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	webDoneCondition.wait();
+	while (!webDone) Thread::sleep(500);
 
 	webSha512ShouldBe = "098ae593f8c3a962f385f9f008ec2116ad22eea8bc569fc88a06a0193480fdfb27470345c427116d19179fb2a74df21d95fe5f1df575a9f2d10d99595708b765";
 	std::cout << "[http] fetching http://download.zerotier.com/dev/4m ... "; std::cout.flush();
+	webDone = false;
 	HttpClient::GET("http://download.zerotier.com/dev/4m",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	webDoneCondition.wait();
+	while (!webDone) Thread::sleep(500);
 
 	webSha512ShouldBe = "";
 	std::cout << "[http] fetching http://download.zerotier.com/dev/NOEXIST ... "; std::cout.flush();
+	webDone = false;
 	HttpClient::GET("http://download.zerotier.com/dev/NOEXIST",HttpClient::NO_HEADERS,30,&testHttpHandler,(void *)0);
-	webDoneCondition.wait();
+	while (!webDone) Thread::sleep(500);
 
 	webSha512ShouldBe = "";
 	std::cout << "[http] fetching http://1.1.1.1/SHOULD_TIME_OUT ... "; std::cout.flush();
+	webDone = false;
 	HttpClient::GET("http://1.1.1.1/SHOULD_TIME_OUT",HttpClient::NO_HEADERS,4,&testHttpHandler,(void *)0);
-	webDoneCondition.wait();
+	while (!webDone) Thread::sleep(500);
 
 	return 0;
 }
@@ -512,38 +518,6 @@ static int testOther()
 	}
 	std::cout << "PASS" << std::endl;
 
-	std::cout << "[other] Testing command bus encode/decode... "; std::cout.flush();
-	try {
-		static char key[32] = { 0 };
-		for(unsigned int k=0;k<100;++k) {
-			std::vector<std::string> original;
-			for(unsigned int i=0,j=rand() % 256,l=(rand() % 1024)+1;i<j;++i)
-				original.push_back(std::string(l,'x'));
-			std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> > packets(NodeConfig::encodeControlMessage(key,1,original));
-			//std::cout << packets.size() << ' '; std::cout.flush();
-			std::vector<std::string> after;
-			for(std::vector< Buffer<ZT_NODECONFIG_MAX_PACKET_SIZE> >::iterator i(packets.begin());i!=packets.end();++i) {
-				unsigned long convId = 9999;
-				if (!NodeConfig::decodeControlMessagePacket(key,i->data(),i->size(),convId,after)) {
-					std::cout << "FAIL (decode)" << std::endl;
-					return -1;
-				}
-				if (convId != 1) {
-					std::cout << "FAIL (conversation ID)" << std::endl;
-					return -1;
-				}
-			}
-			if (after != original) {
-				std::cout << "FAIL (compare)" << std::endl;
-				return -1;
-			}
-		}
-	} catch (std::exception &exc) {
-		std::cout << "FAIL (" << exc.what() << ")" << std::endl;
-		return -1;
-	}
-	std::cout << "PASS" << std::endl;
-
 	std::cout << "[other] Testing Dictionary... "; std::cout.flush();
 	for(int k=0;k<1000;++k) {
 		Dictionary a,b;
@@ -617,8 +591,8 @@ int main(int argc,char **argv)
 
 	std::cout << "[info] sizeof(void *) == " << sizeof(void *) << std::endl;
 	std::cout << "[info] default home: " << ZT_DEFAULTS.defaultHomePath << std::endl;
-	std::cout << "[info] system authtoken.secret: " << Node::LocalClient::authTokenDefaultSystemPath() << std::endl;
-	std::cout << "[info] user authtoken.secret: " << Node::LocalClient::authTokenDefaultUserPath() << std::endl;
+	std::cout << "[info] system authtoken.secret: " << Node::NodeControlClient::authTokenDefaultSystemPath() << std::endl;
+	std::cout << "[info] user authtoken.secret: " << Node::NodeControlClient::authTokenDefaultUserPath() << std::endl;
 
 	srand((unsigned int)time(0));