Selaa lähdekoodia

Add port and control port command line options to daemon and command line client, add new supernode keys to Defaults.

Adam Ierymenko 12 vuotta sitten
vanhempi
commit
300588c5e8
8 muutettua tiedostoa jossa 78 lisäystä ja 47 poistoa
  1. 9 4
      cli.cpp
  2. 24 2
      main.cpp
  3. 2 2
      node/Constants.hpp
  4. 4 6
      node/Defaults.cpp
  5. 28 26
      node/Node.cpp
  6. 7 4
      node/Node.hpp
  7. 2 2
      node/NodeConfig.cpp
  8. 2 1
      node/NodeConfig.hpp

+ 9 - 4
cli.cpp

@@ -45,9 +45,10 @@ static void printHelp(FILE *out,const char *exename)
 {
 {
 	fprintf(out,"Usage: %s [-switches] <command>"ZT_EOL_S,exename);
 	fprintf(out,"Usage: %s [-switches] <command>"ZT_EOL_S,exename);
 	fprintf(out,ZT_EOL_S);
 	fprintf(out,ZT_EOL_S);
-	fprintf(out,"Switches:"ZT_EOL_S);
-	fprintf(out,"  -t<token>        - Specify token on command line"ZT_EOL_S);
-	fprintf(out,"  -T<file>         - Read token from file"ZT_EOL_S);
+	fprintf(out,"Available switches:"ZT_EOL_S);
+	fprintf(out," -c<port>         - Communicate with daemon over this local port"ZT_EOL_S);
+	fprintf(out," -t<token>        - Specify token on command line"ZT_EOL_S);
+	fprintf(out," -T<file>         - Read token from file"ZT_EOL_S);
 	fprintf(out,ZT_EOL_S);
 	fprintf(out,ZT_EOL_S);
 	fprintf(out,"Use the 'help' command to get help from ZeroTier One itself."ZT_EOL_S);
 	fprintf(out,"Use the 'help' command to get help from ZeroTier One itself."ZT_EOL_S);
 }
 }
@@ -73,6 +74,7 @@ int main(int argc,char **argv)
 	std::string authToken;
 	std::string authToken;
 	std::string command;
 	std::string command;
 	bool pastSwitches = false;
 	bool pastSwitches = false;
+	unsigned int controlPort = 0;
 	for(int i=1;i<argc;++i) {
 	for(int i=1;i<argc;++i) {
 		if ((argv[i][0] == '-')&&(!pastSwitches)) {
 		if ((argv[i][0] == '-')&&(!pastSwitches)) {
 			if (strlen(argv[i]) <= 1) {
 			if (strlen(argv[i]) <= 1) {
@@ -80,6 +82,9 @@ int main(int argc,char **argv)
 				return -1;
 				return -1;
 			}
 			}
 			switch(argv[i][1]) {
 			switch(argv[i][1]) {
+				case 'c':
+					controlPort = Utils::strToUInt(argv[i] + 2);
+					break;
 				case 't':
 				case 't':
 					authToken.assign(argv[i] + 2);
 					authToken.assign(argv[i] + 2);
 					break;
 					break;
@@ -129,7 +134,7 @@ int main(int argc,char **argv)
 		return -2;
 		return -2;
 	}
 	}
 
 
-	Node::LocalClient client(authToken.c_str(),&resultHandler,(void *)0);
+	Node::LocalClient client(authToken.c_str(),controlPort,&resultHandler,(void *)0);
 	client.send(command.c_str());
 	client.send(command.c_str());
 
 
 	doneCondition.wait(1000);
 	doneCondition.wait(1000);

+ 24 - 2
main.cpp

@@ -60,7 +60,13 @@ static Node *node = (Node *)0;
 
 
 static void printHelp(const char *cn,FILE *out)
 static void printHelp(const char *cn,FILE *out)
 {
 {
-	fprintf(out,"ZeroTier One version %d.%d.%d"ZT_EOL_S"(c)2012-2013 ZeroTier Networks LLC"ZT_EOL_S"Licensed under the GNU General Public License v3"ZT_EOL_S""ZT_EOL_S"Usage: %s [home directory]"ZT_EOL_S,Node::versionMajor(),Node::versionMinor(),Node::versionRevision(),cn);
+	fprintf(out,"ZeroTier One version %d.%d.%d"ZT_EOL_S"(c)2012-2013 ZeroTier Networks LLC"ZT_EOL_S,Node::versionMajor(),Node::versionMinor(),Node::versionRevision());
+	fprintf(out,"Licensed under the GNU General Public License v3"ZT_EOL_S""ZT_EOL_S);
+	fprintf(out,"Usage: %s [-switches] [home directory]"ZT_EOL_S""ZT_EOL_S,cn);
+	fprintf(out,"Available switches:"ZT_EOL_S);
+	fprintf(out," -h                - Display this help"ZT_EOL_S);
+	fprintf(out," -p<port>          - Bind to this port for network I/O"ZT_EOL_S);
+	fprintf(out," -c<port>          - Bind to this port for local control packets"ZT_EOL_S);
 }
 }
 
 
 #ifdef __UNIX_LIKE__
 #ifdef __UNIX_LIKE__
@@ -114,9 +120,25 @@ int main(int argc,char **argv)
 #endif
 #endif
 
 
 	const char *homeDir = (const char *)0;
 	const char *homeDir = (const char *)0;
+	unsigned int port = 0;
+	unsigned int controlPort = 0;
 	for(int i=1;i<argc;++i) {
 	for(int i=1;i<argc;++i) {
 		if (argv[i][0] == '-') {
 		if (argv[i][0] == '-') {
 			switch(argv[i][1]) {
 			switch(argv[i][1]) {
+				case 'p':
+					port = Utils::strToUInt(argv[i] + 2);
+					if (port > 65535) {
+						printHelp(argv[0],stderr);
+						return -1;
+					}
+					break;
+				case 'c':
+					controlPort = Utils::strToUInt(argv[i] + 2);
+					if (controlPort > 65535) {
+						printHelp(argv[0],stderr);
+						return -1;
+					}
+					break;
 				case 'h':
 				case 'h':
 				case '?':
 				case '?':
 				default:
 				default:
@@ -142,7 +164,7 @@ int main(int argc,char **argv)
 
 
 	int exitCode = 0;
 	int exitCode = 0;
 
 
-	node = new Node(homeDir);
+	node = new Node(homeDir,port,controlPort);
 	const char *termReason = (char *)0;
 	const char *termReason = (char *)0;
 	switch(node->run()) {
 	switch(node->run()) {
 		case Node::NODE_UNRECOVERABLE_ERROR:
 		case Node::NODE_UNRECOVERABLE_ERROR:

+ 2 - 2
node/Constants.hpp

@@ -131,12 +131,12 @@ error_no_ZT_ARCH_defined;
 /**
 /**
  * Default local UDP port
  * Default local UDP port
  */
  */
-#define ZT_DEFAULT_UDP_PORT 8993
+#define ZT_DEFAULT_UDP_PORT 9993
 
 
 /**
 /**
  * Local control port, also used for multiple invocation check
  * Local control port, also used for multiple invocation check
  */
  */
-#define ZT_CONTROL_UDP_PORT 39393
+#define ZT_DEFAULT_CONTROL_UDP_PORT 39393
 
 
 /**
 /**
  * Default payload MTU for UDP packets
  * Default payload MTU for UDP packets

+ 4 - 6
node/Defaults.cpp

@@ -50,30 +50,28 @@ static inline std::map< Identity,std::vector<InetAddress> > _mkSupernodeMap()
 	std::vector<InetAddress> addrs;
 	std::vector<InetAddress> addrs;
 
 
 	// Nothing special about a supernode... except that they are
 	// Nothing special about a supernode... except that they are
-	// designated as such.
+	// designated as such and trusted to provide WHOIS lookup.
 
 
-#if 0
 	// cthulhu.zerotier.com - New York, New York, USA
 	// cthulhu.zerotier.com - New York, New York, USA
 	addrs.clear();
 	addrs.clear();
-	if (!id.fromString("271ee006a0:1:AgGXs3I+9CWrEmGMxc50x3E+trwtaa2ZMXDU6ezz92fFJXzlhRKGUY/uAToHDdH9XiLxtcA+kUQAZdC4Dy2xtqXxjw==:QgH5Nlx4oWEGVrwhNocqem+3VNd4qzt7RLrmuvqZvKPRS9R70LJYJQLlKZj0ri55Pzg+Mlwy4a4nAgfnRAWA+TW6R0EjSmq72MG585XGNfWBVk3LxMvxlNWErnVNFr2BQS9yzVp4pRjPLdCW4RB3dwEHBUgJ78rwMxQ6IghVCl8CjkDapg=="))
+	if (!id.fromString("a0fa79d81c:2:0bb348bb38883a29054659a37c204f2c0b082985cb51b36fad31366dfedd616c20aacc5e33ceee2b054670639563238c4fe50bb8716c1ac7996762c0eaefbb23:b7e91f4c77815327c59ff0979f33861e665d002a357448572954c85919be61f768ee6a4d4e42318ffd9cfcc08cadedcd0277a33a950e316a1d7b5bf082919400c44cad1e725fc2035e2d7087d0c8bf51adc5875b643d759a475f899cfbf3e1a4"))
 		throw std::runtime_error("invalid identity in Defaults");
 		throw std::runtime_error("invalid identity in Defaults");
 	addrs.push_back(InetAddress("198.199.73.93",ZT_DEFAULT_UDP_PORT));
 	addrs.push_back(InetAddress("198.199.73.93",ZT_DEFAULT_UDP_PORT));
 	sn[id] = addrs;
 	sn[id] = addrs;
 
 
 	// nyarlathotep.zerotier.com - San Francisco, California, USA
 	// nyarlathotep.zerotier.com - San Francisco, California, USA
 	addrs.clear();
 	addrs.clear();
-	if (!id.fromString("fa9be4008b:1:AwCHXEi/PJuhtOPUZxnBSMiuGvj6XeRMWu9R9aLR3JD1qluADLQzUPSP2+81Dqvgi2wkQ2cqEpOlDPeUCvtlZwdXEA==:QgH4usG/wzsoUCtO2LL3qkwugtoXEz1PUJbmUzY8vbwzc5bckmVPjMqb4q2CF71+QVPV1K6shIV2EKkBMRSS/D/44EGEwC6tjFGZqmmogaC0P1uQeukTAF4qta46YgC4YQx54/Vd/Yfl8n1Bwmgm0gBB4W1ZQir3p+wp37MGlEN0rlXxqA=="))
+	if (!id.fromString("1521e171ab:2:43bcdc31f2d75667163f3384bc8866e95ce39b4735999e7760494f6480e0fb70f45675f887f8fdfe50e47b082f3fcfc589381f78b3d3bd1dcbf888ccf14d7935:5026836a5732ed890e778f46ded38410dda51c448f82ab76dd0d2c0152bddd5f05fee2fedf8c9f4ccf1f6181f2cdc1f723c59a143a9928c560b2da652f656507f490acfe70e8f5b2a2bba0eca4ea85b03ce00480afd00d49fc756a03bb740592"))
 		throw std::runtime_error("invalid identity in Defaults");
 		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_UDP_PORT));
 	sn[id] = addrs;
 	sn[id] = addrs;
 
 
 	// shub-niggurath.zerotier.com - Amsterdam, Netherlands
 	// shub-niggurath.zerotier.com - Amsterdam, Netherlands
 	addrs.clear();
 	addrs.clear();
-	if (!id.fromString("48099ecd05:1:AwHO7o1FdDj1nEArfchTDa6EG7Eh2GLdiH86BhcoNv0BHJN4tmrf0Y7/2SZiQFpTTwJf93iph84Dci5+k52u/qkHTQ==:QgGbir8CNxBFFPPj8Eo3Bnp2UmbnZxu/pOq3Ke0WaLBBhHzVuwM+88g7CaDxbZ0AY2VkFc9hmE3VG+xi7g0H86yfVUIBHZnb7N+DCtf8/mphZIHNgmasakRi4hU11kGyLi1nTVTnrmCfAb7w+8SCp64Q5RNvBC/Pvz7pxSwSdjIHkVqRaeo="))
+	if (!id.fromString("11c3bddb9a:2:27e1c10a937dde0d6013e7a93755040ff93a98f5bcad809722a6dcde0b255f07da523f9eae818079be0deccbd4572d2e746fe7b8ba8ae6a7a15bdf0456062c37:5f0a7ea9615388a5532c8ce58f9352ba8950c8b3db261d60c02e1ed5a1a42a5e79bc757b38d8a94d00d8e738a6a33cd9b1586022bdff77c9c49ae16609cf5d03f0f60e36a67467c01870ccf26f61793853b93fb6eab53f65f20f623898e9d28d"))
 		throw std::runtime_error("invalid identity in Defaults");
 		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_UDP_PORT));
 	sn[id] = addrs;
 	sn[id] = addrs;
-#endif
 
 
 	return sn;
 	return sn;
 }
 }

+ 28 - 26
node/Node.cpp

@@ -88,6 +88,7 @@ struct _LocalClientImpl
 	UdpSocket *sock;
 	UdpSocket *sock;
 	void (*resultHandler)(void *,unsigned long,const char *);
 	void (*resultHandler)(void *,unsigned long,const char *);
 	void *arg;
 	void *arg;
+	unsigned int controlPort;
 	InetAddress localDestAddr;
 	InetAddress localDestAddr;
 	Mutex inUseLock;
 	Mutex inUseLock;
 };
 };
@@ -111,7 +112,7 @@ static void _CBlocalClientHandler(UdpSocket *sock,void *arg,const InetAddress &r
 	} catch ( ... ) {}
 	} catch ( ... ) {}
 }
 }
 
 
-Node::LocalClient::LocalClient(const char *authToken,void (*resultHandler)(void *,unsigned long,const char *),void *arg)
+Node::LocalClient::LocalClient(const char *authToken,unsigned int controlPort,void (*resultHandler)(void *,unsigned long,const char *),void *arg)
 	throw() :
 	throw() :
 	_impl((void *)0)
 	_impl((void *)0)
 {
 {
@@ -138,8 +139,9 @@ Node::LocalClient::LocalClient(const char *authToken,void (*resultHandler)(void
 		impl->sock = sock;
 		impl->sock = sock;
 		impl->resultHandler = resultHandler;
 		impl->resultHandler = resultHandler;
 		impl->arg = arg;
 		impl->arg = arg;
+		impl->controlPort = (controlPort) ? controlPort : (unsigned int)ZT_DEFAULT_CONTROL_UDP_PORT;
 		impl->localDestAddr = InetAddress::LO4;
 		impl->localDestAddr = InetAddress::LO4;
-		impl->localDestAddr.setPort(ZT_CONTROL_UDP_PORT);
+		impl->localDestAddr.setPort(impl->controlPort);
 		_impl = impl;
 		_impl = impl;
 	} else delete impl;
 	} else delete impl;
 }
 }
@@ -183,6 +185,8 @@ unsigned long Node::LocalClient::send(const char *command)
 struct _NodeImpl
 struct _NodeImpl
 {
 {
 	RuntimeEnvironment renv;
 	RuntimeEnvironment renv;
+	unsigned int port;
+	unsigned int controlPort;
 	std::string reasonForTerminationStr;
 	std::string reasonForTerminationStr;
 	volatile Node::ReasonForTermination reasonForTermination;
 	volatile Node::ReasonForTermination reasonForTermination;
 	volatile bool started;
 	volatile bool started;
@@ -272,7 +276,7 @@ static void _netconfServiceMessageHandler(void *renv,Service &svc,const Dictiona
 }
 }
 #endif // !__WINDOWS__
 #endif // !__WINDOWS__
 
 
-Node::Node(const char *hp)
+Node::Node(const char *hp,unsigned int port,unsigned int controlPort)
 	throw() :
 	throw() :
 	_impl(new _NodeImpl)
 	_impl(new _NodeImpl)
 {
 {
@@ -280,6 +284,8 @@ Node::Node(const char *hp)
 	if ((hp)&&(strlen(hp) > 0))
 	if ((hp)&&(strlen(hp) > 0))
 		impl->renv.homePath = hp;
 		impl->renv.homePath = hp;
 	else impl->renv.homePath = ZT_DEFAULTS.defaultHomePath;
 	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;
 	impl->reasonForTermination = Node::NODE_RUNNING;
 	impl->reasonForTermination = Node::NODE_RUNNING;
 	impl->started = false;
 	impl->started = false;
 	impl->running = false;
 	impl->running = false;
@@ -327,7 +333,7 @@ Node::ReasonForTermination Node::run()
 					return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not write identity.public (home path not writable?)");
 					return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not write identity.public (home path not writable?)");
 			}
 			}
 		} else {
 		} else {
-			LOG("no identity found, generating one... this might take a few seconds...");
+			LOG("no identity found or identity invalid, generating one... this might take a few seconds...");
 			_r->identity.generate();
 			_r->identity.generate();
 			LOG("generated new identity: %s",_r->identity.address().toString().c_str());
 			LOG("generated new identity: %s",_r->identity.address().toString().c_str());
 			idser = _r->identity.toString(true);
 			idser = _r->identity.toString(true);
@@ -365,36 +371,29 @@ Node::ReasonForTermination Node::run()
 		}
 		}
 		Utils::lockDownFile(configAuthTokenPath.c_str(),false);
 		Utils::lockDownFile(configAuthTokenPath.c_str(),false);
 
 
-		// Create the core objects in RuntimeEnvironment: node config, demarcation
-		// point, switch, network topology database, and system environment
-		// watcher.
+		// Create the objects that make up runtime state.
 		_r->multicaster = new Multicaster();
 		_r->multicaster = new Multicaster();
 		_r->sw = new Switch(_r);
 		_r->sw = new Switch(_r);
 		_r->demarc = new Demarc(_r);
 		_r->demarc = new Demarc(_r);
 		_r->topology = new Topology(_r,(_r->homePath + ZT_PATH_SEPARATOR_S + "peer.db").c_str());
 		_r->topology = new Topology(_r,(_r->homePath + ZT_PATH_SEPARATOR_S + "peer.db").c_str());
 		_r->sysEnv = new SysEnv(_r);
 		_r->sysEnv = new SysEnv(_r);
 		try {
 		try {
-			_r->nc = new NodeConfig(_r,configAuthToken.c_str());
+			_r->nc = new NodeConfig(_r,configAuthToken.c_str(),impl->controlPort);
 		} catch (std::exception &exc) {
 		} catch (std::exception &exc) {
-			// An exception here currently means that another instance of ZeroTier
-			// One is running.
-			return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,(std::string("another instance of ZeroTier One appears to be running, or local control UDP port cannot be bound: ") + exc.what()).c_str());
+			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);
 		}
 		}
 		_r->node = this;
 		_r->node = this;
 
 
-		// TODO: make configurable
-		bool boundPort = false;
-		for(unsigned int p=ZT_DEFAULT_UDP_PORT;p<(ZT_DEFAULT_UDP_PORT + 128);++p) {
-			if (_r->demarc->bindLocalUdp(p)) {
-				boundPort = true;
-				break;
-			}
+		// 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);
 		}
 		}
-		if (!boundPort)
-			return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"could not bind any local UDP ports");
 
 
-		// TODO: bootstrap off network so we don't have to update code for
-		// changes in supernodes.
+		// Set initial supernode list
 		_r->topology->setSupernodes(ZT_DEFAULTS.supernodes);
 		_r->topology->setSupernodes(ZT_DEFAULTS.supernodes);
 	} catch (std::bad_alloc &exc) {
 	} catch (std::bad_alloc &exc) {
 		return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"memory allocation failure");
 		return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"memory allocation failure");
@@ -404,6 +403,8 @@ Node::ReasonForTermination Node::run()
 		return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unknown exception during initialization");
 		return impl->terminateBecause(Node::NODE_UNRECOVERABLE_ERROR,"unknown exception during initialization");
 	}
 	}
 
 
+	// Start external service subprocesses, which is only used by special nodes
+	// right now and isn't available on Windows.
 #ifndef __WINDOWS__
 #ifndef __WINDOWS__
 	try {
 	try {
 		std::string netconfServicePath(_r->homePath + ZT_PATH_SEPARATOR_S + "services.d" + ZT_PATH_SEPARATOR_S + "netconf.service");
 		std::string netconfServicePath(_r->homePath + ZT_PATH_SEPARATOR_S + "services.d" + ZT_PATH_SEPARATOR_S + "netconf.service");
@@ -416,6 +417,7 @@ Node::ReasonForTermination Node::run()
 	}
 	}
 #endif
 #endif
 
 
+	// Core I/O loop
 	try {
 	try {
 		uint64_t lastNetworkAutoconfCheck = 0;
 		uint64_t lastNetworkAutoconfCheck = 0;
 		uint64_t lastPingCheck = 0;
 		uint64_t lastPingCheck = 0;
@@ -614,9 +616,9 @@ const unsigned char EMBEDDED_VERSION_STAMP[20] = {
 
 
 extern "C" {
 extern "C" {
 
 
-ZeroTier::Node *zeroTierCreateNode(const char *hp)
+ZeroTier::Node *zeroTierCreateNode(const char *hp,unsigned int port,unsigned int controlPort)
 {
 {
-	return new ZeroTier::Node(hp);
+	return new ZeroTier::Node(hp,port,controlPort);
 }
 }
 
 
 void zeroTierDeleteNode(ZeroTier::Node *n)
 void zeroTierDeleteNode(ZeroTier::Node *n)
@@ -624,9 +626,9 @@ void zeroTierDeleteNode(ZeroTier::Node *n)
 	delete n;
 	delete n;
 }
 }
 
 
-ZeroTier::Node::LocalClient *zeroTierCreateLocalClient(const char *authToken,void (*resultHandler)(void *,unsigned long,const char *),void *arg)
+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,resultHandler,arg);
+	return new ZeroTier::Node::LocalClient(authToken,controlPort,resultHandler,arg);
 }
 }
 
 
 void zeroTierDeleteLocalClient(ZeroTier::Node::LocalClient *lc)
 void zeroTierDeleteLocalClient(ZeroTier::Node::LocalClient *lc)

+ 7 - 4
node/Node.hpp

@@ -50,9 +50,10 @@ public:
 		 * Create a new node config client
 		 * Create a new node config client
 		 *
 		 *
 		 * @param authToken Authentication token
 		 * @param authToken Authentication token
+		 * @param controlPort Control port or 0 for 39393 (default)
 		 * @param resultHandler Function to call when commands provide results
 		 * @param resultHandler Function to call when commands provide results
 		 */
 		 */
-		LocalClient(const char *authToken,void (*resultHandler)(void *,unsigned long,const char *),void *arg)
+		LocalClient(const char *authToken,unsigned int controlPort,void (*resultHandler)(void *,unsigned long,const char *),void *arg)
 			throw();
 			throw();
 
 
 		~LocalClient();
 		~LocalClient();
@@ -95,8 +96,10 @@ public:
 	 * The node is not executed until run() is called.
 	 * The node is not executed until run() is called.
 	 *
 	 *
 	 * @param hp Home directory path
 	 * @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)
 	 */
 	 */
-	Node(const char *hp)
+	Node(const char *hp,unsigned int port,unsigned int controlPort)
 		throw();
 		throw();
 
 
 	~Node();
 	~Node();
@@ -170,10 +173,10 @@ extern "C" {
 // Functions with C-style linkage for easy DLL symbol table
 // Functions with C-style linkage for easy DLL symbol table
 // lookup. These just create instances of Node and LocalClient.
 // lookup. These just create instances of Node and LocalClient.
 
 
-ZeroTier::Node *zeroTierCreateNode(const char *hp);
+ZeroTier::Node *zeroTierCreateNode(const char *hp,unsigned int port,unsigned int controlPort);
 void zeroTierDeleteNode(ZeroTier::Node *n);
 void zeroTierDeleteNode(ZeroTier::Node *n);
 
 
-ZeroTier::Node::LocalClient *zeroTierCreateLocalClient(const char *authToken,void (*resultHandler)(void *,unsigned long,const char *),void *arg);
+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);
 void zeroTierDeleteLocalClient(ZeroTier::Node::LocalClient *lc);
 
 
 } // extern "C"
 } // extern "C"

+ 2 - 2
node/NodeConfig.cpp

@@ -62,10 +62,10 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken)
+NodeConfig::NodeConfig(const RuntimeEnvironment *renv,const char *authToken,unsigned int controlPort)
 	throw(std::runtime_error) :
 	throw(std::runtime_error) :
 	_r(renv),
 	_r(renv),
-	_controlSocket(true,ZT_CONTROL_UDP_PORT,false,&_CBcontrolPacketHandler,this)
+	_controlSocket(true,controlPort,false,&_CBcontrolPacketHandler,this)
 {
 {
 	{
 	{
 		unsigned int csk[64];
 		unsigned int csk[64];

+ 2 - 1
node/NodeConfig.hpp

@@ -59,9 +59,10 @@ public:
 	/**
 	/**
 	 * @param renv Runtime environment
 	 * @param renv Runtime environment
 	 * @param authToken Configuration authentication token
 	 * @param authToken Configuration authentication token
+	 * @param controlPort Control port for local control packet I/O
 	 * @throws std::runtime_error Unable to bind to local control port
 	 * @throws std::runtime_error Unable to bind to local control port
 	 */
 	 */
-	NodeConfig(const RuntimeEnvironment *renv,const char *authToken)
+	NodeConfig(const RuntimeEnvironment *renv,const char *authToken,unsigned int controlPort)
 		throw(std::runtime_error);
 		throw(std::runtime_error);
 
 
 	~NodeConfig();
 	~NodeConfig();