diff --git a/include/libzt.h b/include/libzt.h index a2aab38..38ad5b5 100644 --- a/include/libzt.h +++ b/include/libzt.h @@ -75,6 +75,18 @@ extern "C" { #endif +/** + * @brief (optional) Sets the port for the background libzt service. If this function is called + * with a port number between 1-65535 it will attempt to bind to that port. If it is called with + * a port number of 0 it will attempt to randomly search for an available port. If this function + * is never called, the service will try to bind on LIBZT_DEFAULT_PORT which is 9994. + * + * @usage Should be called at the beginning of your application before `zts_startjoin()` + * @param portno Port number + * @return 0 if successful; or -1 if failed + */ +ZT_SOCKET_API int ZTCALL zts_set_service_port(int portno); + /** * @brief Starts libzt * diff --git a/include/libztDefs.h b/include/libztDefs.h index 92989fe..5a5e077 100644 --- a/include/libztDefs.h +++ b/include/libztDefs.h @@ -33,6 +33,10 @@ #ifndef LIBZT_DEFINES_H #define LIBZT_DEFINES_H +/** + * Default port that libzt will use to support all virtual communication + */ +#define LIBZT_DEFAULT_PORT 9994 /** * Use ZeroTier Virtual Socket layer to abstract network stack raw API */ diff --git a/src/ZT1Service.cpp b/src/ZT1Service.cpp index 14496d0..969d477 100644 --- a/src/ZT1Service.cpp +++ b/src/ZT1Service.cpp @@ -55,6 +55,8 @@ std::string netDir; // Where network .conf files are to be written ZeroTier::Mutex _multiplexer_lock; +int servicePort = LIBZT_DEFAULT_PORT; + #if defined(_WIN32) WSADATA wsaData; #include @@ -216,12 +218,12 @@ void *zts_start_service(void *thread_id) DEBUG_ERROR("homeDir is empty, could not construct path"); return NULL; } - - // Generate random port for new service instance - unsigned int randp = 0; - ZeroTier::Utils::getSecureRandom(&randp,sizeof(randp)); - // TODO: Better port random range selection - int servicePort = 9000 + (randp % 1000); + if (servicePort <= 0) { + DEBUG_INFO("no port specified, will bind to random port. use zts_set_service_port() if you want."); + } + else { + DEBUG_INFO("binding to port=%d", servicePort); + } for (;;) { zt1Service = ZeroTier::OneService::newInstance(homeDir.c_str(),servicePort); switch(zt1Service->run()) { @@ -229,7 +231,6 @@ void *zts_start_service(void *thread_id) case ZeroTier::OneService::ONE_NORMAL_TERMINATION: break; case ZeroTier::OneService::ONE_UNRECOVERABLE_ERROR: - DEBUG_ERROR("ZTO service port = %d", servicePort); DEBUG_ERROR("fatal error: %s",zt1Service->fatalErrorMessage().c_str()); break; case ZeroTier::OneService::ONE_IDENTITY_COLLISION: { @@ -292,6 +293,20 @@ int zts_get_address_at_index( return err; } +/****************************************************************************/ +/* ZeroTier Service Controls */ +/****************************************************************************/ + +int zts_set_service_port(int portno) +{ + if (portno > -1 && portno < 65535) { + // 0 is allowed, see docs + servicePort = portno; + return 0; + } + return -1; +} + int zts_get_address(const uint64_t nwid, struct sockaddr_storage *addr, const int address_family) { @@ -432,13 +447,16 @@ int zts_start(const char *path, bool blocking = false) if (blocking) { // block to prevent service calls before we're ready ZT_NodeStatus status; status.online = 0; + DEBUG_EXTRA("waiting for zerotier service thread to start"); while (zts_core_running() == false || zt1Service->getNode() == NULL) { api_sleep(ZTO_WRAPPER_CHECK_INTERVAL); } + DEBUG_EXTRA("waiting for node address assignment"); while (zt1Service->getNode()->address() <= 0) { api_sleep(ZTO_WRAPPER_CHECK_INTERVAL); } - DEBUG_INFO("node=%llx", zts_get_node_id()); + DEBUG_EXTRA("node=%llx", zts_get_node_id()); + DEBUG_EXTRA("waiting for node to come online"); while (status.online <= 0) { api_sleep(ZTO_WRAPPER_CHECK_INTERVAL); zt1Service->getNode()->status(&status); diff --git a/test/selftest.cpp b/test/selftest.cpp index a1f8364..d32b07e 100644 --- a/test/selftest.cpp +++ b/test/selftest.cpp @@ -2963,6 +2963,11 @@ int main(int argc , char *argv[]) // set start time here since we need to wait for both libzt instances to be online DEBUG_TEST("app-thread, waiting for libzt to come online...\n"); uint64_t nwid = strtoull(nwidstr.c_str(),NULL,16); + int portno = LIBZT_DEFAULT_PORT; + if (zts_set_service_port(portno) < 0) { + DEBUG_TEST("error, invalid zt service port number: %d", portno); + exit(0); + } zts_startjoin(path.c_str(), nwid); uint64_t nodeId = zts_get_node_id(); DEBUG_TEST("I am %llx, %s", nodeId, me.c_str());