diff options
| author | Joseph Henry <[email protected]> | 2020-05-01 19:15:38 -0700 |
|---|---|---|
| committer | Joseph Henry <[email protected]> | 2020-05-01 19:15:38 -0700 |
| commit | a0b50530d37d9c13d30a68bf1d4686485be36327 (patch) | |
| tree | 50251ec3ef7f18468ec3eb2d379d835ea8c64d1f /src | |
| parent | 2c709277b9632bd8e3af8b66f51d3f5a53f84e8e (diff) | |
Add portability and consistency fixes for C API, remove cruft, slight internal restructuring1.3.3
Diffstat (limited to 'src')
| -rw-r--r-- | src/Controls.cpp | 1062 | ||||
| -rw-r--r-- | src/Controls.hpp | 107 | ||||
| -rw-r--r-- | src/Events.cpp | 245 | ||||
| -rw-r--r-- | src/Events.hpp | 106 | ||||
| -rw-r--r-- | src/NodeService.cpp (renamed from src/Service.cpp) | 326 | ||||
| -rw-r--r-- | src/NodeService.hpp (renamed from src/Service.hpp) | 67 | ||||
| -rw-r--r-- | src/Options.h | 80 | ||||
| -rw-r--r-- | src/Sockets.cpp | 574 | ||||
| -rw-r--r-- | src/VirtualTap.cpp | 541 | ||||
| -rw-r--r-- | src/VirtualTap.hpp | 195 | ||||
| -rw-r--r-- | src/lwipDriver.cpp | 535 | ||||
| -rw-r--r-- | src/lwipDriver.hpp | 173 |
12 files changed, 1887 insertions, 2124 deletions
diff --git a/src/Controls.cpp b/src/Controls.cpp index d2c00f5..b8ea3cc 100644 --- a/src/Controls.cpp +++ b/src/Controls.cpp @@ -14,569 +14,129 @@ /** * @file * - * ZeroTier service controls + * Network control interface */ -#if defined(__linux__) -#include <sys/resource.h> -#endif +#include <inttypes.h> +#include <sys/types.h> #include "Node.hpp" -#include "ZeroTierOne.h" +#include "Mutex.hpp" #include "OSUtils.hpp" -#include "Service.hpp" -#include "VirtualTap.hpp" #include "Debug.hpp" -#include "concurrentqueue.h" -#include "ZeroTier.h" -#include "lwipDriver.hpp" - -#if defined(_WIN32) -WSADATA wsaData; -#include <Windows.h> -#endif - -#ifdef SDK_JNI -#include <jni.h> -#endif - -namespace ZeroTier { - -#ifdef __cplusplus -extern "C" { -#endif -// Custom errno to prevent conflicts with platform's own errno -int zts_errno; -#ifdef __cplusplus -} -#endif - -struct serviceParameters -{ - int port; - std::string path; -}; - -int _port; -std::string _path; - -/* - * A lock used to protect any call which relies on the presence of a valid - * pointer to the ZeroTier service. - */ -Mutex _service_lock; - -/* - * A lock used to protect callback method pointers. With a coarser-grained - * lock it would be possible for one thread to alter the callback method - * pointer causing undefined behaviour. - */ -Mutex _callback_lock; - -bool _freeHasBeenCalled = false; -bool _run_service = false; -bool _run_callbacks = false; -bool _run_lwip_tcpip = false; - -bool _network_caching_enabled = true; -bool _peer_caching_enabled = true; - -//bool _startupError = false; - -// Global reference to ZeroTier service -OneService *service; - -// User-provided callback for ZeroTier events -#ifdef SDK_JNI - // Global references to JNI objects and VM kept for future callbacks - static JavaVM *jvm = NULL; - static jobject objRef = NULL; - static jmethodID _userCallbackMethodRef = NULL; -#endif - -void (*_userEventCallbackFunc)(struct zts_callback_msg *); - -moodycamel::ConcurrentQueue<struct zts_callback_msg*> _callbackMsgQueue; - -////////////////////////////////////////////////////////////////////////////// -// Internal ZeroTier Service Controls (user application shall not use these)// -////////////////////////////////////////////////////////////////////////////// - -void postEvent(int eventCode, void *arg) -{ - struct zts_callback_msg *msg = new zts_callback_msg(); - - msg->node = NULL; - msg->network = NULL; - msg->netif = NULL; - msg->route = NULL; - msg->path = NULL; - msg->peer = NULL; - msg->addr = NULL; - - msg->eventCode = eventCode; - - if (NODE_EVENT_TYPE(eventCode)) { - msg->node = (struct zts_node_details*)arg; - } if (NETWORK_EVENT_TYPE(eventCode)) { - msg->network = (struct zts_network_details*)arg; - } if (NETIF_EVENT_TYPE(eventCode)) { - msg->netif = (struct zts_netif_details*)arg; - } if (ROUTE_EVENT_TYPE(eventCode)) { - msg->route = (struct zts_virtual_network_route*)arg; - } if (PATH_EVENT_TYPE(eventCode)) { - msg->path = (struct zts_physical_path*)arg; - } if (PEER_EVENT_TYPE(eventCode)) { - msg->peer = (struct zts_peer_details*)arg; - } if (ADDR_EVENT_TYPE(eventCode)) { - msg->addr = (struct zts_addr_details*)arg; - } +#include "NodeService.hpp" +#include "VirtualTap.hpp" +#include "Events.hpp" +#include "ZeroTierSockets.h" - _callbackMsgQueue.enqueue(msg); -} +using namespace ZeroTier; -void postEvent(int eventCode) { - postEvent(eventCode, (void*)0); -} - -void freeEvent(struct zts_callback_msg *msg) -{ - if (!msg) { - return; - } - if (msg->node) { delete msg->node; } - if (msg->network) { delete msg->network; } - if (msg->netif) { delete msg->netif; } - if (msg->route) { delete msg->route; } - if (msg->path) { delete msg->path; } - if (msg->peer) { delete msg->peer; } - if (msg->addr) { delete msg->addr; } -} - -void _process_callback_event_helper(struct zts_callback_msg *msg) -{ #ifdef SDK_JNI -/* Old style callback messages are simply a uint64_t with a network/peer/node -if of some sort and an associated message code id. This is deprecated and here -only for legacy reasons. */ -#if 1 - if(_userCallbackMethodRef) { - JNIEnv *env; -#if defined(__ANDROID__) - jint rs = jvm->AttachCurrentThread(&env, NULL); -#else - jint rs = jvm->AttachCurrentThread((void **)&env, NULL); -#endif - assert (rs == JNI_OK); - uint64_t arg = 0; - uint64_t id = 0; - if (NODE_EVENT_TYPE(msg->eventCode)) { - id = msg->node ? msg->node->address : 0; - } - if (NETWORK_EVENT_TYPE(msg->eventCode)) { - id = msg->network ? msg->network->nwid : 0; - } - if (PEER_EVENT_TYPE(msg->eventCode)) { - id = msg->peer ? msg->peer->address : 0; - } - env->CallVoidMethod(objRef, _userCallbackMethodRef, id, msg->eventCode); - freeEvent(msg); - } -#else - if(_userCallbackMethodRef) { - JNIEnv *env; - jint rs = jvm->AttachCurrentThread(&env, NULL); - assert (rs == JNI_OK); - uint64_t arg = 0; - if (NODE_EVENT_TYPE(msg->eventCode)) { - DEBUG_INFO("NODE_EVENT_TYPE(%d)", msg->eventCode); - arg = msg->node->address; - } - if (NETWORK_EVENT_TYPE(msg->eventCode)) { - DEBUG_INFO("NETWORK_EVENT_TYPE(%d)", msg->eventCode); - arg = msg->network->nwid; - } - if (PEER_EVENT_TYPE(msg->eventCode)) { - DEBUG_INFO("PEER_EVENT_TYPE(%d)", msg->eventCode); - arg = msg->peer->address; - } - env->CallVoidMethod(objRef, _userCallbackMethodRef, arg, msg->eventCode); - freeEvent(msg); -#endif -#else - if (_userEventCallbackFunc) { - _userEventCallbackFunc(msg); - freeEvent(msg); - } + #include <jni.h> #endif -} -void _process_callback_event(struct zts_callback_msg *msg) +namespace ZeroTier { - _callback_lock.lock(); - _process_callback_event_helper(msg); - _callback_lock.unlock(); -} + extern NodeService *service; + extern Mutex serviceLock; + extern void (*_userEventCallbackFunc)(void *); + extern uint8_t allowNetworkCaching; + extern uint8_t allowPeerCaching; + extern uint8_t allowLocalConf; -bool _is_callback_registered() -{ - _callback_lock.lock(); - bool retval = false; #ifdef SDK_JNI - retval = (jvm && objRef && _userCallbackMethodRef); -#else - retval = _userEventCallbackFunc; -#endif - _callback_lock.unlock(); - return retval; -} - -void _clear_registered_callback() -{ - _callback_lock.lock(); -#ifdef SDK_JNI - objRef = NULL; - _userCallbackMethodRef = NULL; -#else - _userEventCallbackFunc = NULL; -#endif - _callback_lock.unlock(); -} - -int _zts_node_online() -{ - return service && service->getNode() && service->getNode()->online(); -} - -int _zts_can_perform_service_operation() -{ - return service - && service->isRunning() - && service->getNode() - && service->getNode()->online() - && !_freeHasBeenCalled; -} - -void _api_sleep(int interval_ms) -{ -#if defined (_WIN32) - Sleep(interval_ms); -#else - struct timespec sleepValue = {0}; - sleepValue.tv_nsec = interval_ms * 500000; - nanosleep(&sleepValue, NULL); + // References to JNI objects and VM kept for future callbacks + JavaVM *jvm = NULL; + jobject objRef = NULL; + jmethodID _userCallbackMethodRef = NULL; #endif } -int _change_nice(int increment) +int zts_allow_network_caching(uint8_t allowed = 1) { -#ifndef _WIN32 - if (increment == 0) { - return 0; - } - int priority = getpriority(PRIO_PROCESS, 0); - return setpriority(PRIO_PROCESS, 0, priority+increment); -#endif - return 0; -} - -////////////////////////////////////////////////////////////////////////////// -// Callback thread // -////////////////////////////////////////////////////////////////////////////// - -#if defined(_WIN32) -DWORD WINAPI _zts_run_callbacks(LPVOID thread_id) -#else -void *_zts_run_callbacks(void *thread_id) -#endif -{ - _change_nice(CALLBACK_THREAD_NICENESS); -#if defined(__APPLE__) - pthread_setname_np(ZTS_EVENT_CALLBACK_THREAD_NAME); -#endif - while (_run_callbacks || _callbackMsgQueue.size_approx() > 0) - { - struct zts_callback_msg *msg; - size_t sz = _callbackMsgQueue.size_approx(); - for (size_t j = 0; j < sz; j++) { - if (_callbackMsgQueue.try_dequeue(msg)) { - _process_callback_event(msg); - delete msg; - } - } - _api_sleep(ZTS_CALLBACK_PROCESSING_INTERVAL); - } -#if SDK_JNI - JNIEnv *env; - jint rs = jvm->DetachCurrentThread(); - pthread_exit(0); -#endif - return NULL; -} - -////////////////////////////////////////////////////////////////////////////// -// Service thread // -////////////////////////////////////////////////////////////////////////////// - -// Starts a ZeroTier service in the background -#if defined(_WIN32) -DWORD WINAPI _zts_run_service(LPVOID arg) -#else -void *_zts_run_service(void *arg) -#endif -{ -#if defined(__APPLE__) - pthread_setname_np(ZTS_SERVICE_THREAD_NAME); -#endif - //struct serviceParameters *params = arg; - //DEBUG_INFO("path=%s", params->path.c_str()); - int err; - - _change_nice(SERVICE_THREAD_NICENESS); - - try { - std::vector<std::string> hpsp(OSUtils::split(_path.c_str(), ZT_PATH_SEPARATOR_S,"","")); - std::string ptmp; - if (_path[0] == ZT_PATH_SEPARATOR) { - ptmp.push_back(ZT_PATH_SEPARATOR); - } - for (std::vector<std::string>::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) { - if (ptmp.length() > 0) { - ptmp.push_back(ZT_PATH_SEPARATOR); - } - ptmp.append(*pi); - if ((*pi != ".")&&(*pi != "..")) { - if (OSUtils::mkdir(ptmp) == false) { - DEBUG_ERROR("home path does not exist, and could not create"); - err = true; - perror("error\n"); - } - } - } - for(;;) { - _service_lock.lock(); - service = OneService::newInstance(_path.c_str(),_port); - _service_lock.unlock(); - switch(service->run()) { - case OneService::ONE_STILL_RUNNING: - case OneService::ONE_NORMAL_TERMINATION: - postEvent(ZTS_EVENT_NODE_NORMAL_TERMINATION); - break; - case OneService::ONE_UNRECOVERABLE_ERROR: - DEBUG_ERROR("fatal error: %s", service->fatalErrorMessage().c_str()); - err = true; - postEvent(ZTS_EVENT_NODE_UNRECOVERABLE_ERROR); - break; - case OneService::ONE_IDENTITY_COLLISION: { - err = true; - delete service; - service = (OneService *)0; - std::string oldid; - OSUtils::readFile((_path + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); - if (oldid.length()) { - OSUtils::writeFile((_path + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); - OSUtils::rm((_path + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); - OSUtils::rm((_path + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); - } - postEvent(ZTS_EVENT_NODE_IDENTITY_COLLISION); - } continue; // restart! - } - break; // terminate loop -- normally we don't keep restarting - } - _service_lock.lock(); - _run_service = false; - delete service; - service = (OneService *)0; - _service_lock.unlock(); - postEvent(ZTS_EVENT_NODE_DOWN); - } catch ( ... ) { - DEBUG_ERROR("unexpected exception starting ZeroTier instance"); - } - //delete params; - // TODO: Find a more elegant solution - _api_sleep(ZTS_CALLBACK_PROCESSING_INTERVAL*2); - _run_callbacks = false; -#ifndef _WIN32 - pthread_exit(0); -#endif - return NULL; -} - -#ifdef __cplusplus -extern "C" { -#endif - -////////////////////////////////////////////////////////////////////////////// -// ZeroTier Service Controls // -////////////////////////////////////////////////////////////////////////////// - -#ifdef SDK_JNI -/* - * Called from Java, saves a static reference to the VM so it can be used - * later to call a user-specified callback method from C. - */ -JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_init( - JNIEnv *env, jobject thisObj) -{ - jint rs = env->GetJavaVM(&jvm); - return rs != JNI_OK ? ZTS_ERR_GENERAL : ZTS_ERR_OK; -} -#endif - -int zts_join(const uint64_t nwid) -{ - Mutex::Lock _l(_service_lock); - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } - else { - service->join(nwid); - } - return ZTS_ERR_OK; -} -#ifdef SDK_JNI -JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_join( - JNIEnv *env, jobject thisObj, jlong nwid) -{ - return zts_join((uint64_t)nwid); -} -#endif - -int zts_leave(const uint64_t nwid) -{ - Mutex::Lock _l(_service_lock); - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } - else { - service->leave(nwid); - } - return ZTS_ERR_OK; -} -#ifdef SDK_JNI -JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_leave( - JNIEnv *env, jobject thisObj, jlong nwid) -{ - return zts_leave((uint64_t)nwid); -} -#endif - -int zts_leave_all() -{ - Mutex::Lock _l(_service_lock); - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } - else { - service->leaveAll(); + Mutex::Lock _l(serviceLock); + if(!service) { + allowNetworkCaching = allowed; + return ZTS_ERR_OK; } - return ZTS_ERR_OK; + return ZTS_ERR_SERVICE; } -#ifdef SDK_JNI -#endif -int zts_orbit(uint64_t moonWorldId, uint64_t moonSeed) +int zts_allow_peer_caching(uint8_t allowed = 1) { - Mutex::Lock _l(_service_lock); - void *tptr = NULL; - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } else { - service->getNode()->orbit(tptr, moonWorldId, moonSeed); + Mutex::Lock _l(serviceLock); + if(!service) { + allowPeerCaching = allowed; + return ZTS_ERR_OK; } - return ZTS_ERR_OK; + return ZTS_ERR_SERVICE; } -#ifdef SDK_JNI -#endif -int zts_deorbit(uint64_t moonWorldId) +int zts_allow_local_conf(uint8_t allowed = 1) { - Mutex::Lock _l(_service_lock); - void *tptr = NULL; - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } else { - service->getNode()->deorbit(tptr, moonWorldId); + Mutex::Lock _l(serviceLock); + if(!service) { + allowLocalConf = allowed; + return ZTS_ERR_OK; } - return ZTS_ERR_OK; -} -#ifdef SDK_JNI -#endif - -void zts_set_network_caching(bool enabled) -{ - _network_caching_enabled = enabled; -} - -void zts_set_peer_caching(bool enabled) -{ - _peer_caching_enabled = enabled; + return ZTS_ERR_SERVICE; } -int zts_start( - const char *path, void (*callback)(struct zts_callback_msg*), int port) +int zts_start(const char *path, void (*callback)(void *), uint16_t port) { - Mutex::Lock _l(_service_lock); - lwip_driver_init(); - if (service || _run_service) { + Mutex::Lock _l(serviceLock); + _lwip_driver_init(); + if (service || _getState(ZTS_STATE_NODE_RUNNING)) { // Service is already initialized - return ZTS_ERR_INVALID_OP; + return ZTS_ERR_SERVICE; } - if (_freeHasBeenCalled) { + if (_getState(ZTS_STATE_FREE_CALLED)) { // Stack (presumably lwIP) has been dismantled, // an application restart is required now - return ZTS_ERR_INVALID_OP; + return ZTS_ERR_SERVICE; } #ifdef SDK_JNI _userEventCallbackFunc = callback; -#endif +#else _userEventCallbackFunc = callback; - if (!_is_callback_registered()) { +#endif + if (!_isCallbackRegistered()) { // Must have a callback - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } if (!path) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } if (port < 0 || port > 0xFFFF) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } - - _path = std::string(path); - _port = port; - serviceParameters *params = new serviceParameters(); - /* params->port = port; - DEBUG_INFO("path=%s", path); params->path = std::string(path); - DEBUG_INFO("path=%s", params->path.c_str()); if (params->path.length() == 0) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } - */ int err; int retval = ZTS_ERR_OK; - _run_callbacks = true; - _run_service = true; + + _setState(ZTS_STATE_CALLBACKS_RUNNING); + _setState(ZTS_STATE_NODE_RUNNING); // Start the ZT service thread -#if defined(_WIN32) - // Initialize WinSock. Used in Phy for loopback pipe - WSAStartup(MAKEWORD(2, 2), &wsaData); - HANDLE serviceThread = CreateThread(NULL, 0, _zts_run_service, (void*)params, 0, NULL); - HANDLE callbackThread = CreateThread(NULL, 0, _zts_run_callbacks, NULL, 0, NULL); +#if defined(__WINDOWS__) + HANDLE serviceThread = CreateThread(NULL, 0, _runNodeService, (void*)params, 0, NULL); + HANDLE callbackThread = CreateThread(NULL, 0, _runCallbacks, NULL, 0, NULL); #else pthread_t service_thread; pthread_t callback_thread; - if ((err = pthread_create(&service_thread, NULL, _zts_run_service, NULL)) != 0) { + if ((err = pthread_create(&service_thread, NULL, _runNodeService, (void*)params)) != 0) { retval = err; } - if ((err = pthread_create(&callback_thread, NULL, _zts_run_callbacks, NULL)) != 0) { + if ((err = pthread_create(&callback_thread, NULL, _runCallbacks, NULL)) != 0) { retval = err; } #endif @@ -584,32 +144,31 @@ int zts_start( pthread_setname_np(service_thread, ZTS_SERVICE_THREAD_NAME); pthread_setname_np(callback_thread, ZTS_EVENT_CALLBACK_THREAD_NAME); #endif - if (retval != ZTS_ERR_OK) { - _run_callbacks = false; - _run_service = false; - _clear_registered_callback(); - delete params; + _clrState(ZTS_STATE_CALLBACKS_RUNNING); + _clrState(ZTS_STATE_NODE_RUNNING); + _clearRegisteredCallback(); + //delete params; } return retval; } #ifdef SDK_JNI -JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_start( +JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_start( JNIEnv *env, jobject thisObj, jstring path, jobject callback, jint port) { if (!path) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } jclass eventListenerClass = env->GetObjectClass(callback); if(eventListenerClass == NULL) { DEBUG_ERROR("Couldn't find class for ZeroTierEventListener instance"); - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } jmethodID eventListenerCallbackMethod = env->GetMethodID(eventListenerClass, "onZeroTierEvent", "(JI)V"); if(eventListenerCallbackMethod == NULL) { DEBUG_ERROR("Couldn't find onZeroTierEvent method"); - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } // Reference used for later calls objRef = env->NewGlobalRef(callback); @@ -627,11 +186,11 @@ JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_start( int zts_stop() { - Mutex::Lock _l(_service_lock); - if (_zts_can_perform_service_operation()) { - _run_service = false; + Mutex::Lock _l(serviceLock); + if (_canPerformServiceOperation()) { + _clrState(ZTS_STATE_NODE_RUNNING); service->terminate(); -#if defined(_WIN32) +#if defined(__WINDOWS__) WSACleanup(); #endif return ZTS_ERR_OK; @@ -648,40 +207,44 @@ JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_stop( int zts_restart() { - _service_lock.lock(); + serviceLock.lock(); // Store callback references #ifdef SDK_JNI static jmethodID _tmpUserCallbackMethodRef = _userCallbackMethodRef; #else - void (*_tmpUserEventCallbackFunc)(struct zts_callback_msg *); + void (*_tmpUserEventCallbackFunc)(void *); _tmpUserEventCallbackFunc = _userEventCallbackFunc; #endif - int tmpPort = _port; - std::string tmpPath = _path; + int userProvidedPort = 0; + std::string userProvidedPath; + if (service) { + userProvidedPort = service->_userProvidedPort; + userProvidedPath = service->_userProvidedPath; + } // Stop the service - if (_zts_can_perform_service_operation()) { - _run_service = false; + if (_canPerformServiceOperation()) { + _clrState(ZTS_STATE_NODE_RUNNING); service->terminate(); -#if defined(_WIN32) +#if defined(__WINDOWS__) WSACleanup(); #endif } else { - _service_lock.unlock(); + serviceLock.unlock(); return ZTS_ERR_SERVICE; } // Start again with same parameters as initial call - _service_lock.unlock(); + serviceLock.unlock(); while (service) { - _api_sleep(ZTS_CALLBACK_PROCESSING_INTERVAL); + zts_delay_ms(ZTS_CALLBACK_PROCESSING_INTERVAL); } /* Some of the logic in Java_com_zerotier_libzt_ZeroTier_start is replicated here */ #ifdef SDK_JNI _userCallbackMethodRef = _tmpUserCallbackMethodRef; - return zts_start(tmpPath.c_str(), NULL, tmpPort); + return zts_start(userProvidedPath.c_str(), NULL, userProvidedPort); #else - return ::zts_start(tmpPath.c_str(), _tmpUserEventCallbackFunc, tmpPort); + //return zts_start(userProvidedPath.c_str(), _tmpUserEventCallbackFunc, userProvidedPort); #endif } #ifdef SDK_JNI @@ -694,11 +257,11 @@ JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_restart( int zts_free() { - Mutex::Lock _l(_service_lock); - if (_freeHasBeenCalled) { - return ZTS_ERR_INVALID_OP; + Mutex::Lock _l(serviceLock); + if (_getState(ZTS_STATE_FREE_CALLED)) { + return ZTS_ERR_SERVICE; } - _freeHasBeenCalled = true; + _setState(ZTS_STATE_FREE_CALLED); return zts_stop(); // TODO: add stack shutdown logic } @@ -712,9 +275,9 @@ JNIEXPORT void JNICALL Java_com_zerotier_libzt_ZeroTier_free( uint64_t zts_get_node_id() { - Mutex::Lock _l(_service_lock); - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; + Mutex::Lock _l(serviceLock); + if (!_canPerformServiceOperation()) { + return ZTS_ERR_OK; // Not really } return service->getNode()->address(); } @@ -726,10 +289,161 @@ JNIEXPORT jlong JNICALL Java_com_zerotier_libzt_ZeroTier_get_1node_1id( } #endif +int zts_get_node_status() +{ + Mutex::Lock _l(serviceLock); + // Don't check _canPerformServiceOperation() here. + return service + && service->getNode() + && service->getNode()->online() ? ZTS_EVENT_NODE_ONLINE : ZTS_EVENT_NODE_OFFLINE; +} +#ifdef SDK_JNI +JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1node_1status( + JNIEnv *env, jobject thisObj) +{ + return zts_get_node_status(); +} +#endif + +int zts_get_network_status(uint64_t networkId) +{ + Mutex::Lock _l(serviceLock); + if (!networkId) { + return ZTS_ERR_ARG; + } + if (!_canPerformServiceOperation()) { + return ZTS_ERR_SERVICE; + } + /* + TODO: + ZTS_EVENT_NETWORK_READY_IP4 + ZTS_EVENT_NETWORK_READY_IP6 + ZTS_EVENT_NETWORK_READY_IP4_IP6 + */ + return ZTS_ERR_NO_RESULT; +} +#ifdef SDK_JNI +JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1network_1status( + JNIEnv *env, jobject thisObj, jlong networkId) +{ + return zts_get_network_status(networkId); +} +#endif + +int zts_get_peer_status(uint64_t peerId) +{ + Mutex::Lock _l(serviceLock); + int retval = ZTS_ERR_OK; + if (!_canPerformServiceOperation()) { + return ZTS_ERR_SERVICE; + } + return service->getPeerStatus(peerId); +} +#ifdef SDK_JNI +JNIEXPORT jlong JNICALL Java_com_zerotier_libzt_ZeroTier_get_1peer_1status( + JNIEnv *env, jobject thisObj, jlong peerId) +{ + return zts_get_peer_status(peerId); +} +#endif + +#ifdef SDK_JNI +/* + * Called from Java, saves a static reference to the VM so it can be used + * later to call a user-specified callback method from C. + */ +JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_init( + JNIEnv *env, jobject thisObj) +{ + jint rs = env->GetJavaVM(&jvm); + return rs != JNI_OK ? ZTS_ERR_GENERAL : ZTS_ERR_OK; +} +#endif + +int zts_join(const uint64_t nwid) +{ + Mutex::Lock _l(serviceLock); + if (!_canPerformServiceOperation()) { + return ZTS_ERR_SERVICE; + } + else { + service->join(nwid); + } + return ZTS_ERR_OK; +} +#ifdef SDK_JNI +JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_join( + JNIEnv *env, jobject thisObj, jlong nwid) +{ + return zts_join((uint64_t)nwid); +} +#endif + +int zts_leave(const uint64_t nwid) +{ + Mutex::Lock _l(serviceLock); + if (!_canPerformServiceOperation()) { + return ZTS_ERR_SERVICE; + } + else { + service->leave(nwid); + } + return ZTS_ERR_OK; +} +#ifdef SDK_JNI +JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_leave( + JNIEnv *env, jobject thisObj, jlong nwid) +{ + return zts_leave((uint64_t)nwid); +} +#endif + +int zts_leave_all() +{ + Mutex::Lock _l(serviceLock); + if (!_canPerformServiceOperation()) { + return ZTS_ERR_SERVICE; + } + else { + service->leaveAll(); + } + return ZTS_ERR_OK; +} +#ifdef SDK_JNI +#endif + +int zts_orbit(uint64_t moonWorldId, uint64_t moonSeed) +{ + Mutex::Lock _l(serviceLock); + void *tptr = NULL; + if (!_canPerformServiceOperation()) { + return ZTS_ERR_SERVICE; + } else { + service->getNode()->orbit(tptr, moonWorldId, moonSeed); + } + return ZTS_ERR_OK; +} +#ifdef SDK_JNI +#endif + +int zts_deorbit(uint64_t moonWorldId) +{ + Mutex::Lock _l(serviceLock); + void *tptr = NULL; + if (!_canPerformServiceOperation()) { + return ZTS_ERR_SERVICE; + } else { + service->getNode()->deorbit(tptr, moonWorldId); + } + return ZTS_ERR_OK; +} +#ifdef SDK_JNI +#endif + int zts_get_6plane_addr(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId) { if (!addr || !nwid || !nodeId) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } InetAddress _6planeAddr = InetAddress::makeIpv66plane(nwid,nodeId); struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr; @@ -740,7 +454,7 @@ int zts_get_6plane_addr(struct sockaddr_storage *addr, const uint64_t nwid, cons int zts_get_rfc4193_addr(struct sockaddr_storage *addr, const uint64_t nwid, const uint64_t nodeId) { if (!addr || !nwid || !nodeId) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } InetAddress _rfc4193Addr = InetAddress::makeIpv6rfc4193(nwid,nodeId); struct sockaddr_in6 *in6 = (struct sockaddr_in6*)addr; @@ -748,6 +462,7 @@ int zts_get_rfc4193_addr(struct sockaddr_storage *addr, const uint64_t nwid, con return ZTS_ERR_OK; } + uint64_t zts_generate_adhoc_nwid_from_range(uint16_t startPortOfRange, uint16_t endPortOfRange) { char nwidStr[INET6_ADDRSTRLEN]; @@ -755,40 +470,20 @@ uint64_t zts_generate_adhoc_nwid_from_range(uint16_t startPortOfRange, uint16_t return strtoull(nwidStr, NULL, 16); } -////////////////////////////////////////////////////////////////////////////// -// Peers // -////////////////////////////////////////////////////////////////////////////// - -int zts_get_peer_count() +int zts_get_peers(struct zts_peer_details *pds, uint32_t *num) { - Mutex::Lock _l(_service_lock); - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } - return service->getNode()->peers()->peerCount; -} -#ifdef SDK_JNI -JNIEXPORT jlong JNICALL Java_com_zerotier_libzt_ZeroTier_get_1peer_1count( - JNIEnv *env, jobject thisObj) -{ - return zts_get_peer_count(); -} -#endif - -int zts_get_peers(struct zts_peer_details *pds, unsigned int *num) -{ - Mutex::Lock _l(_service_lock); + Mutex::Lock _l(serviceLock); if (!pds || !num) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } - if (!_zts_can_perform_service_operation()) { + if (!_canPerformServiceOperation()) { return ZTS_ERR_SERVICE; } ZT_PeerList *pl = service->getNode()->peers(); if (pl) { if (*num < pl->peerCount) { service->getNode()->freeQueryResult((void *)pl); - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } *num = pl->peerCount; for(unsigned long i=0;i<pl->peerCount;++i) { @@ -807,11 +502,11 @@ int zts_get_peers(struct zts_peer_details *pds, unsigned int *num) int zts_get_peer(struct zts_peer_details *pd, uint64_t peerId) { - Mutex::Lock _l(_service_lock); + Mutex::Lock _l(serviceLock); if (!pd || !peerId) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } - if (!_zts_can_perform_service_operation()) { + if (!_canPerformServiceOperation()) { return ZTS_ERR_SERVICE; } ZT_PeerList *pl = service->getNode()->peers(); @@ -835,30 +530,6 @@ int zts_get_peer(struct zts_peer_details *pd, uint64_t peerId) #ifdef SDK_JNI #endif -////////////////////////////////////////////////////////////////////////////// -// Networks // -////////////////////////////////////////////////////////////////////////////// - -size_t zts_get_num_joined_networks() -{ - Mutex::Lock _l(_service_lock); - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } - return service->networkCount(); -} -#ifdef SDK_JNI -JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1num_1joined_1networks( - JNIEnv *env, jobject thisObj) -{ - return zts_get_num_joined_networks(); -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// Network Details // -////////////////////////////////////////////////////////////////////////////// - void _get_network_details_helper(uint64_t nwid, struct zts_network_details *nd) { /* @@ -905,10 +576,10 @@ void _get_all_network_details(struct zts_network_details *nds, int *num) int zts_get_network_details(uint64_t nwid, struct zts_network_details *nd) { /* - _service_lock.lock(); + serviceLock.lock(); int retval = ZTS_ERR_OK; if (!nd || nwid == 0) { - retval = ZTS_ERR_INVALID_ARG; + retval = ZTS_ERR_ARG; } if (!service || _freeHasBeenCalled || _serviceIsShuttingDown) { retval = ZTS_ERR_SERVICE; @@ -916,7 +587,7 @@ int zts_get_network_details(uint64_t nwid, struct zts_network_details *nd) if (retval == ZTS_ERR_OK) { _get_network_details(nwid, nd); } - _service_lock.unlock(); + serviceLock.unlock(); return retval; */ return 0; @@ -927,10 +598,10 @@ int zts_get_network_details(uint64_t nwid, struct zts_network_details *nd) int zts_get_all_network_details(struct zts_network_details *nds, int *num) { /* - _service_lock.lock(); + serviceLock.lock(); int retval = ZTS_ERR_OK; if (!nds || !num) { - retval = ZTS_ERR_INVALID_ARG; + retval = ZTS_ERR_ARG; } if (!service || _freeHasBeenCalled || _serviceIsShuttingDown) { retval = ZTS_ERR_SERVICE; @@ -938,7 +609,7 @@ int zts_get_all_network_details(struct zts_network_details *nds, int *num) if (retval == ZTS_ERR_OK) { _get_all_network_details(nds, num); } - _service_lock.unlock(); + serviceLock.unlock(); return retval; */ return 0; @@ -946,206 +617,13 @@ int zts_get_all_network_details(struct zts_network_details *nds, int *num) #ifdef SDK_JNI #endif -////////////////////////////////////////////////////////////////////////////// -// Statistics // -////////////////////////////////////////////////////////////////////////////// - -#include "lwip/stats.h" - -extern struct stats_ lwip_stats; - -int zts_get_all_stats(struct zts_stats *statsDest) -{ -#if LWIP_STATS - if (!statsDest) { - return ZTS_ERR_INVALID_ARG; - } - memset(statsDest, 0, sizeof(struct zts_stats)); - // Copy lwIP stats - memcpy(&(statsDest->link), &(lwip_stats.link), sizeof(struct stats_proto)); - memcpy(&(statsDest->etharp), &(lwip_stats.etharp), sizeof(struct stats_proto)); - memcpy(&(statsDest->ip_frag), &(lwip_stats.ip_frag), sizeof(struct stats_proto)); - memcpy(&(statsDest->ip), &(lwip_stats.ip), sizeof(struct stats_proto)); - memcpy(&(statsDest->icmp), &(lwip_stats.icmp), sizeof(struct stats_proto)); - //memcpy(&(statsDest->igmp), &(lwip_stats.igmp), sizeof(struct stats_igmp)); - memcpy(&(statsDest->udp), &(lwip_stats.udp), sizeof(struct stats_proto)); - memcpy(&(statsDest->tcp), &(lwip_stats.tcp), sizeof(struct stats_proto)); - // mem omitted - // memp omitted - memcpy(&(statsDest->sys), &(lwip_stats.sys), sizeof(struct stats_sys)); - memcpy(&(statsDest->ip6), &(lwip_stats.ip6), sizeof(struct stats_proto)); - memcpy(&(statsDest->icmp6), &(lwip_stats.icmp6), sizeof(struct stats_proto)); - memcpy(&(statsDest->ip6_frag), &(lwip_stats.ip6_frag), sizeof(struct stats_proto)); - memcpy(&(statsDest->mld6), &(lwip_stats.mld6), sizeof(struct stats_igmp)); - memcpy(&(statsDest->nd6), &(lwip_stats.nd6), sizeof(struct stats_proto)); - memcpy(&(statsDest->ip_frag), &(lwip_stats.ip_frag), sizeof(struct stats_proto)); - // mib2 omitted - // Copy ZT stats - // ... - return ZTS_ERR_OK; -#else - return ZTS_ERR_NO_RESULT; -#endif -} -#ifdef SDK_JNI - // No implementation for JNI -#endif - -int zts_get_protocol_stats(int protocolType, void *protoStatsDest) +void zts_delay_ms(long interval_ms) { -#if LWIP_STATS - if (!protoStatsDest) { - return ZTS_ERR_INVALID_ARG; - } - memset(protoStatsDest, 0, sizeof(struct stats_proto)); - switch (protocolType) - { - case ZTS_STATS_PROTOCOL_LINK: - memcpy(protoStatsDest, &(lwip_stats.link), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_ETHARP: - memcpy(protoStatsDest, &(lwip_stats.etharp), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_IP: - memcpy(protoStatsDest, &(lwip_stats.ip), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_UDP: - memcpy(protoStatsDest, &(lwip_stats.udp), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_TCP: - memcpy(protoStatsDest, &(lwip_stats.tcp), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_ICMP: - memcpy(protoStatsDest, &(lwip_stats.icmp), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_IP_FRAG: - memcpy(protoStatsDest, &(lwip_stats.ip_frag), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_IP6: - memcpy(protoStatsDest, &(lwip_stats.ip6), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_ICMP6: - memcpy(protoStatsDest, &(lwip_stats.icmp6), sizeof(struct stats_proto)); - break; - case ZTS_STATS_PROTOCOL_IP6_FRAG: - memcpy(protoStatsDest, &(lwip_stats.ip6_frag), sizeof(struct stats_proto)); - break; - default: - return ZTS_ERR_INVALID_ARG; - } - return ZTS_ERR_OK; +#if defined(__WINDOWS__) + Sleep(interval_ms); #else - return ZTS_ERR_NO_RESULT; -#endif -} -#ifdef SDK_JNI -JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1protocol_1stats( - JNIEnv *env, jobject thisObj, jint protocolType, jobject protoStatsObj) -{ - struct stats_proto stats; - int retval = zts_get_protocol_stats(protocolType, &stats); - // Copy stats into Java object - jclass c = env->GetObjectClass(protoStatsObj); - if (!c) { - return ZTS_ERR_INVALID_ARG; - } - jfieldID fid; - fid = env->GetFieldID(c, "xmit", "I"); - env->SetIntField(protoStatsObj, fid, stats.xmit); - fid = env->GetFieldID(c, "recv", "I"); - env->SetIntField(protoStatsObj, fid, stats.recv); - fid = env->GetFieldID(c, "fw", "I"); - env->SetIntField(protoStatsObj, fid, stats.fw); - fid = env->GetFieldID(c, "drop", "I"); - env->SetIntField(protoStatsObj, fid, stats.drop); - fid = env->GetFieldID(c, "chkerr", "I"); - env->SetIntField(protoStatsObj, fid, stats.chkerr); - fid = env->GetFieldID(c, "lenerr", "I"); - env->SetIntField(protoStatsObj, fid, stats.lenerr); - fid = env->GetFieldID(c, "memerr", "I"); - env->SetIntField(protoStatsObj, fid, stats.memerr); - fid = env->GetFieldID(c, "rterr", "I"); - env->SetIntField(protoStatsObj, fid, stats.rterr); - fid = env->GetFieldID(c, "proterr", "I"); - env->SetIntField(protoStatsObj, fid, stats.proterr); - fid = env->GetFieldID(c, "opterr", "I"); - env->SetIntField(protoStatsObj, fid, stats.opterr); - fid = env->GetFieldID(c, "err", "I"); - env->SetIntField(protoStatsObj, fid, stats.err); - fid = env->GetFieldID(c, "cachehit", "I"); - env->SetIntField(protoStatsObj, fid, stats.cachehit); - return retval; -} -#endif - -////////////////////////////////////////////////////////////////////////////// -// Multipath/QoS // -////////////////////////////////////////////////////////////////////////////// - -////////////////////////////////////////////////////////////////////////////// -// Status getters // -////////////////////////////////////////////////////////////////////////////// - -int zts_get_node_status() -{ - Mutex::Lock _l(_service_lock); - // Don't check _zts_can_perform_service_operation() here. - return service - && service->getNode() - && service->getNode()->online() ? ZTS_EVENT_NODE_ONLINE : ZTS_EVENT_NODE_OFFLINE; -} -#ifdef SDK_JNI -JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1node_1status( - JNIEnv *env, jobject thisObj) -{ - return zts_get_node_status(); -} -#endif - -int zts_get_network_status(uint64_t networkId) -{ - Mutex::Lock _l(_service_lock); - if (!networkId) { - return ZTS_ERR_INVALID_ARG; - } - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } - /* - TODO: - ZTS_EVENT_NETWORK_READY_IP4 - ZTS_EVENT_NETWORK_READY_IP6 - ZTS_EVENT_NETWORK_READY_IP4_IP6 - */ - return ZTS_ERR_NO_RESULT; -} -#ifdef SDK_JNI -JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1network_1status( - JNIEnv *env, jobject thisObj, jlong networkId) -{ - return zts_get_network_status(networkId); -} -#endif - -int zts_get_peer_status(uint64_t peerId) -{ - Mutex::Lock _l(_service_lock); - int retval = ZTS_ERR_OK; - if (!_zts_can_perform_service_operation()) { - return ZTS_ERR_SERVICE; - } - return service->getPeerStatus(peerId); -} -#ifdef SDK_JNI -JNIEXPORT jlong JNICALL Java_com_zerotier_libzt_ZeroTier_get_1peer_1status( - JNIEnv *env, jobject thisObj, jlong peerId) -{ - return zts_get_peer_status(peerId); -} + struct timespec sleepValue = {0}; + sleepValue.tv_nsec = interval_ms * 500000; + nanosleep(&sleepValue, NULL); #endif - -#ifdef __cplusplus } -#endif - -} // namespace ZeroTier
\ No newline at end of file diff --git a/src/Controls.hpp b/src/Controls.hpp deleted file mode 100644 index 06b464d..0000000 --- a/src/Controls.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c)2013-2020 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2024-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -/** - * @file - * - * Header for ZeroTier service controls - */ - -#ifndef LIBZT_CONTROLS_HPP -#define LIBZT_CONTROLS_HPP - -#ifdef _WIN32 -#include <Windows.h> -#endif - -namespace ZeroTier { - -////////////////////////////////////////////////////////////////////////////// -// ZeroTier Internal Service Controls // -////////////////////////////////////////////////////////////////////////////// - -/** - * Add a callback event message to the queue. This can be safely called - * from other threads since a lock-free queue is used. - * - * @param eventCode The event ID for this event - * @param msg Pointer to a structure of pointers to other message-relevant - * data structures. - */ -void postEvent(int eventCode, void *arg); - -/** - * Add a callback event message to the queue. This can be safely called - * from other threads since a lock-free queue is used. Note: For use in - * situations when no additional information needs to be conveyed to the - * user application. - * - * @param eventCode The event ID for this event - */ -void postEvent(int eventCode); - -/** - * Free whatever was allocated to contain the callback message - * - * @param msg Message to be freed - */ -void freeEvent(struct zts_callback_msg *msg); - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @brief Starts a ZeroTier service in the background - * - * @usage For internal use only. - * @param - * @return - */ -#if defined(_WIN32) -DWORD WINAPI _zts_run_service(LPVOID thread_id); -#else -void *_zts_run_service(void *thread_id); -#endif - -/** - * @brief [Should not be called from user application] This function must be surrounded by - * ZT service locks. It will determine if it is currently safe and allowed to operate on - * the service. - * @usage Can be called at any time - * @return 1 or 0 - */ -int _zts_can_perform_service_operation(); - -/** - * @brief [Should not be called from user application] Returns whether or not the node is - * online. - * @usage Can be called at any time - * @return 1 or 0 - */ -int _zts_node_online(); - -/** - * @brief [Should not be called from user application] Adjusts the delay multiplier for the - * network stack driver thread. - * @usage Can be called at any time - */ -void _hibernate_if_needed(); - -#ifdef __cplusplus -} -#endif - -} // namespace ZeroTier - -#endif // _H
\ No newline at end of file diff --git a/src/Events.cpp b/src/Events.cpp new file mode 100644 index 0000000..3cbd332 --- /dev/null +++ b/src/Events.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c)2013-2020 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2024-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +/** + * @file + * + * Callback event processing logic + */ + +#include "concurrentqueue.h" + +#ifdef SDK_JNI + #include <jni.h> +#endif + +#include "Node.hpp" +#include "OSUtils.hpp" + +#include "Debug.hpp" +#include "Events.hpp" +#include "ZeroTierSockets.h" +#include "NodeService.hpp" + +#define NODE_EVENT_TYPE(code) code >= ZTS_EVENT_NODE_UP && code <= ZTS_EVENT_NODE_NORMAL_TERMINATION +#define NETWORK_EVENT_TYPE(code) code >= ZTS_EVENT_NETWORK_NOT_FOUND && code <= ZTS_EVENT_NETWORK_DOWN +#define STACK_EVENT_TYPE(code) code >= ZTS_EVENT_STACK_UP && code <= ZTS_EVENT_STACK_DOWN +#define NETIF_EVENT_TYPE(code) code >= ZTS_EVENT_NETIF_UP && code <= ZTS_EVENT_NETIF_LINK_DOWN +#define PEER_EVENT_TYPE(code) code >= ZTS_EVENT_PEER_DIRECT && code <= ZTS_EVENT_PEER_UNREACHABLE +#define PATH_EVENT_TYPE(code) code >= ZTS_EVENT_PATH_DISCOVERED && code <= ZTS_EVENT_PATH_DEAD +#define ROUTE_EVENT_TYPE(code) code >= ZTS_EVENT_ROUTE_ADDED && code <= ZTS_EVENT_ROUTE_REMOVED +#define ADDR_EVENT_TYPE(code) code >= ZTS_EVENT_ADDR_ADDED_IP4 && code <= ZTS_EVENT_ADDR_REMOVED_IP6 + +namespace ZeroTier { + +extern NodeService *service; + +// Global state variable shared between Socket, Control, Event and NodeService logic. +uint8_t _serviceStateFlags; + +// Lock to guard access to callback function pointers. +Mutex _callbackLock; + +void (*_userEventCallbackFunc)(void *); + +moodycamel::ConcurrentQueue<struct ::zts_callback_msg*> _callbackMsgQueue; + +void _enqueueEvent(int16_t eventCode, void *arg) +{ + struct ::zts_callback_msg *msg = new ::zts_callback_msg(); + + msg->node = NULL; + msg->network = NULL; + msg->netif = NULL; + msg->route = NULL; + msg->path = NULL; + msg->peer = NULL; + msg->addr = NULL; + + msg->eventCode = eventCode; + + if (NODE_EVENT_TYPE(eventCode)) { + msg->node = (struct zts_node_details*)arg; + } if (NETWORK_EVENT_TYPE(eventCode)) { + msg->network = (struct zts_network_details*)arg; + } if (NETIF_EVENT_TYPE(eventCode)) { + msg->netif = (struct zts_netif_details*)arg; + } if (ROUTE_EVENT_TYPE(eventCode)) { + msg->route = (struct zts_virtual_network_route*)arg; + } if (PATH_EVENT_TYPE(eventCode)) { + msg->path = (struct zts_physical_path*)arg; + } if (PEER_EVENT_TYPE(eventCode)) { + msg->peer = (struct zts_peer_details*)arg; + } if (ADDR_EVENT_TYPE(eventCode)) { + msg->addr = (struct zts_addr_details*)arg; + } + _callbackMsgQueue.enqueue(msg); +} + +void _freeEvent(struct ::zts_callback_msg *msg) +{ + if (!msg) { + return; + } + if (msg->node) { delete msg->node; } + if (msg->network) { delete msg->network; } + if (msg->netif) { delete msg->netif; } + if (msg->route) { delete msg->route; } + if (msg->path) { delete msg->path; } + if (msg->peer) { delete msg->peer; } + if (msg->addr) { delete msg->addr; } +} + +void _passDequeuedEventToUser(struct ::zts_callback_msg *msg) +{ +#ifdef SDK_JNI + if(_userCallbackMethodRef) { + JNIEnv *env; +#if defined(__ANDROID__) + jint rs = jvm->AttachCurrentThread(&env, NULL); +#else + jint rs = jvm->AttachCurrentThread((void **)&env, NULL); +#endif + assert (rs == JNI_OK); + uint64_t arg = 0; + uint64_t id = 0; + if (NODE_EVENT_TYPE(msg->eventCode)) { + id = msg->node ? msg->node->address : 0; + } + if (NETWORK_EVENT_TYPE(msg->eventCode)) { + id = msg->network ? msg->network->nwid : 0; + } + if (PEER_EVENT_TYPE(msg->eventCode)) { + id = msg->peer ? msg->peer->address : 0; + } + env->CallVoidMethod(objRef, _userCallbackMethodRef, id, msg->eventCode); + _freeEvent(msg); + } +#else + if (_userEventCallbackFunc) { + _userEventCallbackFunc(msg); + _freeEvent(msg); + } +#endif +} + +bool _isCallbackRegistered() +{ + _callbackLock.lock(); + bool retval = false; +#ifdef SDK_JNI + retval = (jvm && objRef && _userCallbackMethodRef); +#else + retval = _userEventCallbackFunc; +#endif + _callbackLock.unlock(); + return retval; +} + +void _clearRegisteredCallback() +{ + _callbackLock.lock(); +#ifdef SDK_JNI + objRef = NULL; + _userCallbackMethodRef = NULL; +#else + _userEventCallbackFunc = NULL; +#endif + _callbackLock.unlock(); +} + +int _canPerformServiceOperation() +{ + return service + && service->isRunning() + && service->getNode() + && service->getNode()->online() + && !_getState(ZTS_STATE_FREE_CALLED); +} + +#define RESET_FLAGS( ) _serviceStateFlags = 0; +#define SET_FLAGS(f) _serviceStateFlags |= f; +#define CLR_FLAGS(f) _serviceStateFlags &= ~f; +#define GET_FLAGS(f) ((_serviceStateFlags & f) > 0) + +void _setState(uint8_t newFlags) +{ + if ((newFlags ^ _serviceStateFlags) & ZTS_STATE_NET_SERVICE_RUNNING) { + return; // No effect. Not allowed to set this flag manually + } + SET_FLAGS(newFlags); + if ( GET_FLAGS(ZTS_STATE_NODE_RUNNING) + && GET_FLAGS(ZTS_STATE_STACK_RUNNING) + && !(GET_FLAGS(ZTS_STATE_FREE_CALLED))) + { + SET_FLAGS(ZTS_STATE_NET_SERVICE_RUNNING); + } + else { + CLR_FLAGS(ZTS_STATE_NET_SERVICE_RUNNING); + } +} + +void _clrState(uint8_t newFlags) +{ + if (newFlags & ZTS_STATE_NET_SERVICE_RUNNING) { + return; // No effect. Not allowed to set this flag manually + } + CLR_FLAGS(newFlags); + if ( GET_FLAGS(ZTS_STATE_NODE_RUNNING) + && GET_FLAGS(ZTS_STATE_STACK_RUNNING) + && !(GET_FLAGS(ZTS_STATE_FREE_CALLED))) + { + SET_FLAGS(ZTS_STATE_NET_SERVICE_RUNNING); + } + else { + CLR_FLAGS(ZTS_STATE_NET_SERVICE_RUNNING); + } +} + +bool _getState(uint8_t testFlags) +{ + return testFlags & _serviceStateFlags; +} + +#if defined(__WINDOWS__) +DWORD WINAPI _runCallbacks(LPVOID thread_id) +#else +void *_runCallbacks(void *thread_id) +#endif +{ +#if defined(__APPLE__) + pthread_setname_np(ZTS_EVENT_CALLBACK_THREAD_NAME); +#endif + while (_getState(ZTS_STATE_CALLBACKS_RUNNING) || _callbackMsgQueue.size_approx() > 0) + { + struct ::zts_callback_msg *msg; + size_t sz = _callbackMsgQueue.size_approx(); + for (size_t j = 0; j < sz; j++) { + if (_callbackMsgQueue.try_dequeue(msg)) { + _callbackLock.lock(); + _passDequeuedEventToUser(msg); + _callbackLock.unlock(); + delete msg; + } + } + zts_delay_ms(ZTS_CALLBACK_PROCESSING_INTERVAL); + } +#if SDK_JNI + JNIEnv *env; + jint rs = jvm->DetachCurrentThread(); + pthread_exit(0); +#endif + return NULL; +} + +} // namespace ZeroTier diff --git a/src/Events.hpp b/src/Events.hpp new file mode 100644 index 0000000..58a3406 --- /dev/null +++ b/src/Events.hpp @@ -0,0 +1,106 @@ +/* + * Copyright (c)2013-2020 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2024-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +/** + * @file + * + * Header for callback event processing logic + */ + +#ifndef ZT_EVENTS_HPP +#define ZT_EVENTS_HPP + +#include <string> + +#include "ZeroTierSockets.h" + +#ifdef SDK_JNI + #include <jni.h> +#endif +namespace ZeroTier { + +#define ZTS_STATE_NODE_RUNNING 0x01 +#define ZTS_STATE_STACK_RUNNING 0x02 +#define ZTS_STATE_NET_SERVICE_RUNNING 0x04 +#define ZTS_STATE_CALLBACKS_RUNNING 0x08 +#define ZTS_STATE_FREE_CALLED 0x10 + +#ifdef SDK_JNI + // References to JNI objects and VM kept for future callbacks + extern JavaVM *jvm; + extern jobject objRef; + extern jmethodID _userCallbackMethodRef; +#endif + +/** + * How often callback messages are assembled and/or sent + */ +#define ZTS_CALLBACK_PROCESSING_INTERVAL 25 + +/** + * Enqueue an event to be sent to the user application + */ +void _enqueueEvent(int16_t eventCode, void *arg); + +/** + * Send callback message to user application + */ +void _passDequeuedEventToUser(struct ::zts_callback_msg *msg); + +/** + * Free memory occupied by callback structures + */ +void _freeEvent(struct ::zts_callback_msg *msg); + +/** + * Return whether a callback method has been set + */ +bool _isCallbackRegistered(); + +/** + * Clear pointer reference to user-provided callback function + */ +void _clearRegisteredCallback(); + +/** + * Return whether service operation can be performed at this time + */ +int _canPerformServiceOperation(); + +/** + * Set internal state flags + */ +void _setState(uint8_t newFlags); + +/** + * Clear internal state flags + */ +void _clrState(uint8_t newFlags); + +/** + * Get internal state flags + */ +bool _getState(uint8_t testFlags); + +#ifdef __WINDOWS__ +DWORD WINAPI _runCallbacks(LPVOID thread_id); +#else +/** + * Event callback thread + */ +void *_runCallbacks(void *thread_id); +#endif + +} // namespace ZeroTier + +#endif // _H
\ No newline at end of file diff --git a/src/Service.cpp b/src/NodeService.cpp index e9e587a..3a04d61 100644 --- a/src/Service.cpp +++ b/src/NodeService.cpp @@ -11,89 +11,57 @@ */ /****/ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <string> -#include <map> -#include <vector> -#include <algorithm> -#include <list> +/** + * @file + * + * ZeroTier Node Service (a distant relative of OneService) + */ + #include <thread> -#include <mutex> -#include <condition_variable> -#include "version.h" -#include "ZeroTierOne.h" +#include "Debug.hpp" +#include "Events.hpp" +#include "NodeService.hpp" +#include "ZeroTierSockets.h" +#include "VirtualTap.hpp" #include "Constants.hpp" -#include "Mutex.hpp" #include "Node.hpp" #include "Utils.hpp" -#include "InetAddress.hpp" #include "MAC.hpp" -#include "Identity.hpp" -#include "World.hpp" -#include "Salsa20.hpp" -#include "Poly1305.hpp" -#include "SHA512.hpp" - #include "Phy.hpp" #include "Thread.hpp" #include "OSUtils.hpp" #include "PortMapper.hpp" #include "Binder.hpp" #include "ManagedRoute.hpp" +#include "InetAddress.hpp" #include "BlockingQueue.hpp" -#include "Service.hpp" -#include "Debug.hpp" -#include "concurrentqueue.h" - -#include "ZeroTier.h" -#include "lwipDriver.hpp" - -#ifdef __WINDOWS__ +#if defined(__WINDOWS__) +WSADATA wsaData; #include <WinSock2.h> #include <Windows.h> #include <ShlObj.h> #include <netioapi.h> #include <iphlpapi.h> -//#include <unistd.h> #define stat _stat -#else -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/wait.h> -#include <unistd.h> -#include <ifaddrs.h> #endif -#include "Controls.hpp" - -// Use the virtual netcon endpoint instead of a tun/tap port driver -#include "VirtualTap.hpp" -namespace ZeroTier { typedef VirtualTap EthernetTap; } - -// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also -// bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi. -#define ZT_IF_METRIC 5000 - -// How often to check for new multicast subscriptions on a tap device -#define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000 +#ifdef SDK_JNI +#include <jni.h> +#endif -// How often to check for local interface addresses -#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000 +// Custom errno-like reporting variable +int zts_errno; namespace ZeroTier { -extern void postEvent(uint64_t id, int eventCode); -extern bool _network_caching_enabled; -extern bool _peer_caching_enabled; +uint8_t allowNetworkCaching; +uint8_t allowPeerCaching; +uint8_t allowLocalConf; -namespace { +typedef VirtualTap EthernetTap; static std::string _trimString(const std::string &s) { @@ -114,7 +82,7 @@ static std::string _trimString(const std::string &s) return s.substr(start,end - start); } -class OneServiceImpl; +class NodeServiceImpl; static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf); static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData); @@ -126,7 +94,7 @@ static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t z static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result); static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len); -struct OneServiceIncomingPacket +struct NodeServiceIncomingPacket { uint64_t now; int64_t sock; @@ -135,7 +103,7 @@ struct OneServiceIncomingPacket uint8_t data[ZT_MAX_MTU]; }; -class OneServiceImpl : public OneService +class NodeServiceImpl : public NodeService { public: // begin member variables -------------------------------------------------- @@ -145,7 +113,7 @@ public: const std::string _networksPath; const std::string _moonsPath; - Phy<OneServiceImpl *> _phy; + Phy<NodeServiceImpl *> _phy; Node *_node; bool _updateAutoApply; unsigned int _multipathMode = 0; @@ -159,8 +127,8 @@ public: // unsigned long _incomingPacketConcurrency; - std::vector<OneServiceIncomingPacket *> _incomingPacketMemoryPool; - BlockingQueue<OneServiceIncomingPacket *> _incomingPacketQueue; + std::vector<NodeServiceIncomingPacket *> _incomingPacketMemoryPool; + BlockingQueue<NodeServiceIncomingPacket *> _incomingPacketQueue; std::vector<std::thread> _incomingPacketThreads; Mutex _incomingPacketMemoryPoolLock,_incomingPacketThreadsLock; @@ -238,7 +206,7 @@ public: // end member variables ---------------------------------------------------- - OneServiceImpl(const char *hp,unsigned int port) : + NodeServiceImpl(const char *hp,unsigned int port) : _homePath((hp) ? hp : ".") ,_phy(this,false,true) ,_node((Node *)0) @@ -259,51 +227,16 @@ public: _ports[1] = 0; _ports[2] = 0; - /* Packet input concurrency is disabled intentially since it - would force the user-space network stack to constantly re-order - frames, resulting in lower RX performance */ - - /* - _incomingPacketConcurrency = 1; - // std::max((unsigned long)1,std::min((unsigned long)16,(unsigned long)std::thread::hardware_concurrency())); - char *envPool = std::getenv("INCOMING_PACKET_CONCURRENCY"); - if (envPool != NULL) { - int tmp = atoi(envPool); - if (tmp > 0) { - _incomingPacketConcurrency = tmp; - } - } - for(long t=0;t<_incomingPacketConcurrency;++t) { - _incomingPacketThreads.push_back(std::thread([this]() { - OneServiceIncomingPacket *pkt = nullptr; - for(;;) { - if (!_incomingPacketQueue.get(pkt)) - break; - if (!pkt) - break; - if (!_run) - break; - - const ZT_ResultCode rc = _node->processWirePacket(nullptr,pkt->now,pkt->sock,&(pkt->from),pkt->data,pkt->size,&_nextBackgroundTaskDeadline); - { - Mutex::Lock l(_incomingPacketMemoryPoolLock); - _incomingPacketMemoryPool.push_back(pkt); - } - if (ZT_ResultCode_isFatal(rc)) { - char tmp[256]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"fatal error code from processWirePacket: %d",(int)rc); - Mutex::Lock _l(_termReason_m); - _termReason = ONE_UNRECOVERABLE_ERROR; - _fatalErrorMessage = tmp; - this->terminate(); - break; - } - } - })); - }*/ + allowNetworkCaching = true; + allowPeerCaching = true; + allowLocalConf = false; +#ifdef __WINDOWS__ + // Initialize WinSock. Used in Phy for loopback pipe + WSAStartup(MAKEWORD(2, 2), &wsaData); +#endif } - virtual ~OneServiceImpl() + virtual ~NodeServiceImpl() { _incomingPacketQueue.stop(); _incomingPacketThreadsLock.lock(); @@ -425,7 +358,7 @@ public: } #endif // Join existing networks in networks.d - if (_network_caching_enabled) { + if (allowNetworkCaching) { std::vector<std::string> networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S "networks.d").c_str())); for(std::vector<std::string>::iterator f(networksDotD.begin());f!=networksDotD.end();++f) { std::size_t dot = f->find_last_of('.'); @@ -769,7 +702,7 @@ public: *nuptr = (void *)0; delete n.tap; _nets.erase(nwid); - if (_network_caching_enabled) { + if (allowNetworkCaching) { if (op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY) { char nlcpath[256]; OSUtils::ztsnprintf(nlcpath,sizeof(nlcpath),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.local.conf",_homePath.c_str(),nwid); @@ -787,17 +720,25 @@ public: inline void nodeEventCallback(enum ZT_Event event,const void *metaData) { // Feed node events into lock-free queue for later dequeuing by the callback thread - if (event <= ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION) { - if (event == ZTS_EVENT_NODE_ONLINE) { + switch(event) { + case ZT_EVENT_UP: { + _enqueueEvent(ZTS_EVENT_NODE_UP, NULL); + } break; + case ZT_EVENT_ONLINE: { struct zts_node_details *nd = new zts_node_details; nd->address = _node->address(); - postEvent(event, (void*)nd); - } - else { - postEvent(event, (void*)0); - } - } - switch(event) { + _enqueueEvent(ZTS_EVENT_NODE_ONLINE, (void*)nd); + } break; + case ZT_EVENT_OFFLINE: { + struct zts_node_details *nd = new zts_node_details; + nd->address = _node->address(); + _enqueueEvent(ZTS_EVENT_NODE_OFFLINE, (void*)nd); + } break; + case ZT_EVENT_DOWN: { + struct zts_node_details *nd = new zts_node_details; + nd->address = _node->address(); + _enqueueEvent(ZTS_EVENT_NODE_DOWN, (void*)nd); + } break; case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: { Mutex::Lock _l(_termReason_m); _termReason = ONE_IDENTITY_COLLISION; @@ -828,7 +769,7 @@ public: { // Force the ordering of callback messages, these messages are // only useful if the node and stack are both up and running - if (!_node->online() || !lwip_is_up()) { + if (!_node->online() || !_lwip_is_up()) { return; } // Generate messages to be dequeued by the callback message thread @@ -842,26 +783,26 @@ public: } switch (mostRecentStatus) { case ZT_NETWORK_STATUS_NOT_FOUND: - postEvent(ZTS_EVENT_NETWORK_NOT_FOUND, (void*)prepare_network_details_msg(nwid)); + _enqueueEvent(ZTS_EVENT_NETWORK_NOT_FOUND, (void*)prepare_network_details_msg(nwid)); break; case ZT_NETWORK_STATUS_CLIENT_TOO_OLD: - postEvent(ZTS_EVENT_NETWORK_CLIENT_TOO_OLD, (void*)prepare_network_details_msg(nwid)); + _enqueueEvent(ZTS_EVENT_NETWORK_CLIENT_TOO_OLD, (void*)prepare_network_details_msg(nwid)); break; case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION: - postEvent(ZTS_EVENT_NETWORK_REQUESTING_CONFIG, (void*)prepare_network_details_msg(nwid)); + _enqueueEvent(ZTS_EVENT_NETWORK_REQ_CONFIG, (void*)prepare_network_details_msg(nwid)); break; case ZT_NETWORK_STATUS_OK: - if (tap->hasIpv4Addr() && lwip_is_netif_up(tap->netif4)) { - postEvent(ZTS_EVENT_NETWORK_READY_IP4, (void*)prepare_network_details_msg(nwid)); + if (tap->hasIpv4Addr() && _lwip_is_netif_up(tap->netif4)) { + _enqueueEvent(ZTS_EVENT_NETWORK_READY_IP4, (void*)prepare_network_details_msg(nwid)); } - if (tap->hasIpv6Addr() && lwip_is_netif_up(tap->netif6)) { - postEvent(ZTS_EVENT_NETWORK_READY_IP6, (void*)prepare_network_details_msg(nwid)); + if (tap->hasIpv6Addr() && _lwip_is_netif_up(tap->netif6)) { + _enqueueEvent(ZTS_EVENT_NETWORK_READY_IP6, (void*)prepare_network_details_msg(nwid)); } // In addition to the READY messages, send one OK message - postEvent(ZTS_EVENT_NETWORK_OK, (void*)prepare_network_details_msg(nwid)); + _enqueueEvent(ZTS_EVENT_NETWORK_OK, (void*)prepare_network_details_msg(nwid)); break; case ZT_NETWORK_STATUS_ACCESS_DENIED: - postEvent(ZTS_EVENT_NETWORK_ACCESS_DENIED, (void*)prepare_network_details_msg(nwid)); + _enqueueEvent(ZTS_EVENT_NETWORK_ACCESS_DENIED, (void*)prepare_network_details_msg(nwid)); break; default: break; @@ -879,12 +820,12 @@ public: if (pl->peers[i].pathCount > 0) { pd = new zts_peer_details; memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details)); - postEvent(ZTS_EVENT_PEER_P2P, (void*)pd); + _enqueueEvent(ZTS_EVENT_PEER_DIRECT, (void*)pd); } if (pl->peers[i].pathCount == 0) { pd = new zts_peer_details; memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details)); - postEvent(ZTS_EVENT_PEER_RELAY, (void*)pd); + _enqueueEvent(ZTS_EVENT_PEER_RELAY, (void*)pd); } } // Previously known peer, update status @@ -892,12 +833,12 @@ public: if ((peerCache[pl->peers[i].address] == false) && pl->peers[i].pathCount > 0) { pd = new zts_peer_details; memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details)); - postEvent(ZTS_EVENT_PEER_P2P, (void*)pd); + _enqueueEvent(ZTS_EVENT_PEER_DIRECT, (void*)pd); } if ((peerCache[pl->peers[i].address] == true) && pl->peers[i].pathCount == 0) { pd = new zts_peer_details; memcpy(pd, &(pl->peers[i]), sizeof(struct zts_peer_details)); - postEvent(ZTS_EVENT_PEER_RELAY, (void*)pd); + _enqueueEvent(ZTS_EVENT_PEER_RELAY, (void*)pd); } } // Update our cache with most recently observed path count @@ -938,7 +879,7 @@ public: if (pl) { for(unsigned long i=0;i<pl->peerCount;++i) { if (pl->peers[i].address == id) { - status = pl->peers[i].pathCount > 0 ? ZTS_EVENT_PEER_P2P : ZTS_EVENT_PEER_RELAY; + status = pl->peers[i].pathCount > 0 ? ZTS_EVENT_PEER_DIRECT : ZTS_EVENT_PEER_RELAY; break; } } @@ -967,7 +908,7 @@ public: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - if (_network_caching_enabled) { + if (allowNetworkCaching) { OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str()); OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]); secure = true; @@ -977,7 +918,7 @@ public: } break; case ZT_STATE_OBJECT_PEER: - if (_peer_caching_enabled) { + if (allowPeerCaching) { OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); } @@ -1032,7 +973,7 @@ public: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - if (_network_caching_enabled) { + if (allowNetworkCaching) { OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); } else { @@ -1040,7 +981,7 @@ public: } break; case ZT_STATE_OBJECT_PEER: - if (_peer_caching_enabled) { + if (allowPeerCaching) { OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d" ZT_PATH_SEPARATOR_S "%.10llx.peer",_homePath.c_str(),(unsigned long long)id[0]); } break; @@ -1249,32 +1190,121 @@ public: }; static int SnodeVirtualNetworkConfigFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwconf) -{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } +{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodeVirtualNetworkConfigFunction(nwid,nuptr,op,nwconf); } static void SnodeEventCallback(ZT_Node *node,void *uptr,void *tptr,enum ZT_Event event,const void *metaData) -{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeEventCallback(event,metaData); } +{ reinterpret_cast<NodeServiceImpl *>(uptr)->nodeEventCallback(event,metaData); } static void SnodeStatePutFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],const void *data,int len) -{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeStatePutFunction(type,id,data,len); } +{ reinterpret_cast<NodeServiceImpl *>(uptr)->nodeStatePutFunction(type,id,data,len); } static int SnodeStateGetFunction(ZT_Node *node,void *uptr,void *tptr,enum ZT_StateObjectType type,const uint64_t id[2],void *data,unsigned int maxlen) -{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeStateGetFunction(type,id,data,maxlen); } +{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodeStateGetFunction(type,id,data,maxlen); } static int SnodeWirePacketSendFunction(ZT_Node *node,void *uptr,void *tptr,int64_t localSocket,const struct sockaddr_storage *addr,const void *data,unsigned int len,unsigned int ttl) -{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); } +{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodeWirePacketSendFunction(localSocket,addr,data,len,ttl); } static void SnodeVirtualNetworkFrameFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } +{ reinterpret_cast<NodeServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,nuptr,sourceMac,destMac,etherType,vlanId,data,len); } static int SnodePathCheckFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int64_t localSocket,const struct sockaddr_storage *remoteAddr) -{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); } +{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodePathCheckFunction(ztaddr,localSocket,remoteAddr); } static int SnodePathLookupFunction(ZT_Node *node,void *uptr,void *tptr,uint64_t ztaddr,int family,struct sockaddr_storage *result) -{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodePathLookupFunction(ztaddr,family,result); } +{ return reinterpret_cast<NodeServiceImpl *>(uptr)->nodePathLookupFunction(ztaddr,family,result); } static void StapFrameHandler(void *uptr,void *tptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) -{ reinterpret_cast<OneServiceImpl *>(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); } +{ reinterpret_cast<NodeServiceImpl *>(uptr)->tapFrameHandler(nwid,from,to,etherType,vlanId,data,len); } -} // anonymous namespace -std::string OneService::platformDefaultHomePath() +std::string NodeService::platformDefaultHomePath() { return OSUtils::platformDefaultHomePath(); } -OneService *OneService::newInstance(const char *hp,unsigned int port) { return new OneServiceImpl(hp,port); } -OneService::~OneService() {} +NodeService *NodeService::newInstance(const char *hp,unsigned int port) { return new NodeServiceImpl(hp,port); } +NodeService::~NodeService() {} + +////////////////////////////////////////////////////////////////////////////// +// Service // +////////////////////////////////////////////////////////////////////////////// + +NodeService *service; + +// Lock to guard access to ZeroTier core service +Mutex serviceLock; + +// Starts a ZeroTier NodeService background thread +#if defined(__WINDOWS__) +DWORD WINAPI _runNodeService(LPVOID arg) +#else +void *_runNodeService(void *arg) +#endif +{ +#if defined(__APPLE__) + pthread_setname_np(ZTS_SERVICE_THREAD_NAME); +#endif + struct serviceParameters *params = (struct serviceParameters *)arg; + int err; + try { + std::vector<std::string> hpsp(OSUtils::split(params->path.c_str(), ZT_PATH_SEPARATOR_S,"","")); + std::string ptmp; + if (params->path[0] == ZT_PATH_SEPARATOR) { + ptmp.push_back(ZT_PATH_SEPARATOR); + } + for (std::vector<std::string>::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) { + if (ptmp.length() > 0) { + ptmp.push_back(ZT_PATH_SEPARATOR); + } + ptmp.append(*pi); + if ((*pi != ".")&&(*pi != "..")) { + if (OSUtils::mkdir(ptmp) == false) { + DEBUG_ERROR("home path does not exist, and could not create"); + err = true; + perror("error\n"); + } + } + } + for(;;) { + serviceLock.lock(); + service = NodeService::newInstance(params->path.c_str(),params->port); + service->_userProvidedPort = params->port; + service->_userProvidedPath = params->path; + serviceLock.unlock(); + switch(service->run()) { + case NodeService::ONE_STILL_RUNNING: + case NodeService::ONE_NORMAL_TERMINATION: + _enqueueEvent(ZTS_EVENT_NODE_NORMAL_TERMINATION,NULL); + break; + case NodeService::ONE_UNRECOVERABLE_ERROR: + DEBUG_ERROR("fatal error: %s", service->fatalErrorMessage().c_str()); + err = true; + _enqueueEvent(ZTS_EVENT_NODE_UNRECOVERABLE_ERROR,NULL); + break; + case NodeService::ONE_IDENTITY_COLLISION: { + err = true; + delete service; + service = (NodeService *)0; + std::string oldid; + OSUtils::readFile((params->path + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid); + if (oldid.length()) { + OSUtils::writeFile((params->path + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid); + OSUtils::rm((params->path + ZT_PATH_SEPARATOR_S + "identity.secret").c_str()); + OSUtils::rm((params->path + ZT_PATH_SEPARATOR_S + "identity.public").c_str()); + } + _enqueueEvent(ZTS_EVENT_NODE_IDENTITY_COLLISION,NULL); + } continue; // restart! + } + break; // terminate loop -- normally we don't keep restarting + } + serviceLock.lock(); + _clrState(ZTS_STATE_NODE_RUNNING); + delete service; + service = (NodeService *)0; + serviceLock.unlock(); + _enqueueEvent(ZTS_EVENT_NODE_DOWN,NULL); + } catch ( ... ) { + DEBUG_ERROR("unexpected exception starting ZeroTier instance"); + } + delete params; + zts_delay_ms(ZTS_CALLBACK_PROCESSING_INTERVAL*2); + _clrState(ZTS_STATE_CALLBACKS_RUNNING); +#ifndef __WINDOWS__ + pthread_exit(0); +#endif + return NULL; +} } // namespace ZeroTier diff --git a/src/Service.hpp b/src/NodeService.hpp index b111d5f..43e4ce8 100644 --- a/src/Service.hpp +++ b/src/NodeService.hpp @@ -11,33 +11,49 @@ */ /****/ -#ifndef ZT_ONESERVICE_HPP -#define ZT_ONESERVICE_HPP +/** + * @file + * + * Header for ZeroTier Node Service (a distant relative of OneService) + */ + +#ifndef ZT_NODE_SERVICE_HPP +#define ZT_NODE_SERVICE_HPP #include <string> #include <vector> -#ifdef SDK_JNI -#include <jni.h> +#include "Node.hpp" +#include "InetAddress.hpp" +#include "Mutex.hpp" +#include "ZeroTierSockets.h" + +#define ZTS_SERVICE_THREAD_NAME "ZTServiceThread" +#define ZTS_EVENT_CALLBACK_THREAD_NAME "ZTEventCallbackThread" +// Interface metric for ZeroTier taps -- this ensures that if we are on WiFi and also +// bridged via ZeroTier to the same LAN traffic will (if the OS is sane) prefer WiFi. +#define ZT_IF_METRIC 5000 +// How often to check for new multicast subscriptions on a tap device +#define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000 +// How often to check for local interface addresses +#define ZT_LOCAL_INTERFACE_CHECK_INTERVAL 60000 + +#ifdef __WINDOWS__ +#include <Windows.h> #endif namespace ZeroTier { -class VirtualTap; -// Use the virtual libzt endpoint instead of a tun/tap port driver -namespace ZeroTier { typedef VirtualTap EthernetTap; } - -// Forward declaration so we can avoid dragging everything in -struct InetAddress; -class Node; - /** * Local service for ZeroTier One as system VPN/NFV provider */ -class OneService +class NodeService { public: + uint16_t _userProvidedPort; + std::string _userProvidedPath; + /** * Returned by node main if/when it terminates */ @@ -109,9 +125,9 @@ public: * @param hp Home path * @param port TCP and UDP port for packets and HTTP control (if 0, pick random port) */ - static OneService *newInstance(const char *hp,unsigned int port); + static NodeService *newInstance(const char *hp,unsigned int port); - virtual ~OneService(); + virtual ~NodeService(); /** * Execute the service main I/O loop until terminated @@ -178,13 +194,28 @@ public: inline bool isRunning() const { return (this->reasonForTermination() == ONE_STILL_RUNNING); } protected: - OneService() {} + NodeService() {} private: - OneService(const OneService &one) {} - inline OneService &operator=(const OneService &one) { return *this; } + NodeService(const NodeService &one) {} + inline NodeService &operator=(const NodeService &one) { return *this; } }; +struct serviceParameters +{ + int port; + std::string path; +}; + +#ifdef __WINDOWS__ +DWORD WINAPI _runNodeService(LPVOID arg); +#else +/** + * NodeService thread + */ +void *_runNodeService(void *arg); +#endif + } // namespace ZeroTier #endif diff --git a/src/Options.h b/src/Options.h deleted file mode 100644 index 74708dd..0000000 --- a/src/Options.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c)2013-2020 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2024-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#ifndef LIBZT_OPTIONS_H -#define LIBZT_OPTIONS_H - -////////////////////////////////////////////////////////////////////////////// -// Callbacks // -////////////////////////////////////////////////////////////////////////////// - -/** - * The maximum number of un-processed callback messages - */ -#define ZTS_CALLBACK_MSG_QUEUE_LEN 256 - -////////////////////////////////////////////////////////////////////////////// -// Timing // -////////////////////////////////////////////////////////////////////////////// - -/** - * How often callback messages are assembled and/or sent - */ -#define ZTS_CALLBACK_PROCESSING_INTERVAL 25 - -/** - * Polling interval (in ms) for fds wrapped in the Phy I/O loop - */ -#define ZTS_TAP_THREAD_POLLING_INTERVAL 50 - -#define ZTS_HOUSEKEEPING_INTERVAL 50 - -/** - * By how much thread I/O and callback loop delays are multiplied (unitless) - */ -#define ZTS_HIBERNATION_MULTIPLIER 50 - -////////////////////////////////////////////////////////////////////////////// -// Threading // -////////////////////////////////////////////////////////////////////////////// - -#define SERVICE_THREAD_NICENESS 0 // -10 -#define CALLBACK_THREAD_NICENESS 0 // 10 -#define LWIP_DRIVER_THREAD_NICENESS 0 // 10 -#define TCPIP_THREAD_NICENESS 0 // -10 -#define TAP_THREAD_NICENESS 0 // 10 - -#define ZTS_SERVICE_THREAD_NAME "ZeroTierServiceThread" -#define ZTS_EVENT_CALLBACK_THREAD_NAME "ZeroTierEventCallbackThread" -#define ZTS_LWIP_DRIVER_THREAD_NAME "lwipDriver" - -////////////////////////////////////////////////////////////////////////////// -// lwIP behaviour (tcpip driver) // -////////////////////////////////////////////////////////////////////////////// - -/** - * How many frames are handled per call from core - */ -#define LWIP_FRAMES_HANDLED_PER_CORE_CALL 16 - -/** - * How often the lwIP tcpip thread callback checks for incoming frames - */ -#define LWIP_DRIVER_LOOP_INTERVAL 250 - -/** - * Number of packets that can be queued for ingress into the lwIP core - */ -#define ZTS_LWIP_MAX_RX_QUEUE_LEN 1024 - -#endif
\ No newline at end of file diff --git a/src/Sockets.cpp b/src/Sockets.cpp index 9adc0c2..7844c51 100644 --- a/src/Sockets.cpp +++ b/src/Sockets.cpp @@ -17,42 +17,41 @@ * ZeroTier Socket API */ -#include <string.h> - #include "lwip/sockets.h" #include "lwip/def.h" +#include "lwip/inet.h" +#include "lwip/stats.h" -#include "ZeroTierConstants.h" -#include "Options.h" -#include "Debug.hpp" +#include "ZeroTierSockets.h" +#include "Events.hpp" #ifdef SDK_JNI #include <jni.h> #endif -namespace ZeroTier { +extern int zts_errno; -////////////////////////////////////////////////////////////////////////////// -// ZeroTier Socket API // -////////////////////////////////////////////////////////////////////////////// +namespace ZeroTier { -extern bool _run_service; -extern bool _run_lwip_tcpip; +extern uint8_t _serviceStateFlags; #ifdef __cplusplus extern "C" { #endif #ifdef SDK_JNI -void ss2zta(JNIEnv *env, struct sockaddr_storage *ss, jobject addr); -void zta2ss(JNIEnv *env, struct sockaddr_storage *ss, jobject addr); -void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, fd_set *dest_fd_set); -void fdset2ztfdset(JNIEnv *env, int nfds, fd_set *src_fd_set, jobject dest_ztfd_set); +void ss2zta(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr); +void zta2ss(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr); +void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, zts_fd_set *dest_fd_set); +void fdset2ztfdset(JNIEnv *env, int nfds, zts_fd_set *src_fd_set, jobject dest_ztfd_set); #endif -int zts_socket(int socket_family, int socket_type, int protocol) +int zts_socket(const int socket_family, const int socket_type, const int protocol) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_socket(socket_family, socket_type, protocol); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_socket(socket_family, socket_type, protocol); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_socket( @@ -63,53 +62,62 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_socket( } #endif -int zts_connect(int fd, const struct sockaddr *addr, socklen_t addrlen) +int zts_connect(int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen) { if (!addr) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; + } + if (addrlen > (int)sizeof(struct zts_sockaddr_storage) || addrlen < (int)sizeof(struct zts_sockaddr_in)) { + return ZTS_ERR_ARG; } - if (addrlen > (int)sizeof(struct sockaddr_storage) || addrlen < (int)sizeof(struct sockaddr_in)) { - return ZTS_ERR_INVALID_ARG; + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_connect(fd, addr, addrlen); + return lwip_connect(fd, (sockaddr*)addr, addrlen); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_connect( JNIEnv *env, jobject thisObj, jint fd, jobject addr) { - struct sockaddr_storage ss; + struct zts_sockaddr_storage ss; zta2ss(env, &ss, addr); - socklen_t addrlen = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - int retval = zts_connect(fd, (struct sockaddr *)&ss, addrlen); + socklen_t addrlen = ss.ss_family == ZTS_AF_INET ? sizeof(struct zts_sockaddr_in) : sizeof(struct zts_sockaddr_in6); + int retval = zts_connect(fd, (struct zts_sockaddr *)&ss, addrlen); return retval > -1 ? retval : -(zts_errno); } #endif -int zts_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) +int zts_bind(int fd, const struct zts_sockaddr *addr, zts_socklen_t addrlen) { if (!addr) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } - if (addrlen > (int)sizeof(struct sockaddr_storage) || addrlen < (int)sizeof(struct sockaddr_in)) { - return ZTS_ERR_INVALID_ARG; + if (addrlen > (int)sizeof(struct zts_sockaddr_storage) || addrlen < (int)sizeof(struct zts_sockaddr_in)) { + return ZTS_ERR_ARG; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_bind(fd, addr, addrlen); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_bind(fd, (sockaddr*)addr, addrlen); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_bind( JNIEnv *env, jobject thisObj, jint fd, jobject addr) { - struct sockaddr_storage ss; + struct zts_sockaddr_storage ss; zta2ss(env, &ss, addr); - socklen_t addrlen = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - int retval = zts_bind(fd, (struct sockaddr*)&ss, addrlen); + zts_socklen_t addrlen = ss.ss_family == ZTS_AF_INET ? sizeof(struct zts_sockaddr_in) : sizeof(struct zts_sockaddr_in6); + int retval = zts_bind(fd, (struct zts_sockaddr*)&ss, addrlen); return retval > -1 ? retval : -(zts_errno); } #endif int zts_listen(int fd, int backlog) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_listen(fd, backlog); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_listen(fd, backlog); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_listen( @@ -120,26 +128,32 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_listen( } #endif -int zts_accept(int fd, struct sockaddr *addr, socklen_t *addrlen) +int zts_accept(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_accept(fd, addr, addrlen); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_accept(fd, (sockaddr*)addr, (socklen_t*)addrlen); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_accept( JNIEnv *env, jobject thisObj, jint fd, jobject addr, jint port) { - struct sockaddr_storage ss; - socklen_t addrlen = sizeof(struct sockaddr_storage); - int retval = zts_accept(fd, (struct sockaddr *)&ss, &addrlen); + struct zts_sockaddr_storage ss; + zts_socklen_t addrlen = sizeof(struct zts_sockaddr_storage); + int retval = zts_accept(fd, (zts_sockaddr*)&ss, &addrlen); ss2zta(env, &ss, addr); return retval > -1 ? retval : -(zts_errno); } #endif #if defined(__linux__) -int zts_accept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags) +int zts_accept4(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen, int flags) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_INVALID_OP : ZTS_ERR_INVALID_OP; + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return ZTS_ERR_SERVICE; // TODO } #endif #ifdef SDK_JNI @@ -147,18 +161,21 @@ int zts_accept4(int fd, struct sockaddr *addr, socklen_t *addrlen, int flags) JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_accept4( JNIEnv *env, jobject thisObj, jint fd, jobject addr, jint port, jint flags) { - struct sockaddr_storage ss; - socklen_t addrlen = sizeof(struct sockaddr_storage); - int retval = zts_accept4(fd, (struct sockaddr *)&ss, &addrlen, flags); + struct zts_sockaddr_storage ss; + zts_socklen_t addrlen = sizeof(struct zts_sockaddr_storage); + int retval = zts_accept4(fd, (struct zts_sockaddr *)&ss, &addrlen, flags); ss2zta(env, &ss, addr); return retval > -1 ? retval : -(zts_errno); } #endif #endif -int zts_setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen) +int zts_setsockopt(int fd, int level, int optname, const void *optval,zts_socklen_t optlen) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_setsockopt(fd, level, optname, optval, optlen); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_setsockopt(fd, level, optname, optval, optlen); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_setsockopt( @@ -166,7 +183,7 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_setsockopt( { jclass c = env->GetObjectClass(optval); if (!c) { - return ZTS_ERR_INVALID_OP; + return ZTS_ERR_SERVICE; } int optval_int = -1; @@ -206,9 +223,12 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_setsockopt( } #endif -int zts_getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen) +int zts_getsockopt(int fd, int level, int optname, void *optval, zts_socklen_t *optlen) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_getsockopt(fd, level, optname, optval, optlen); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_getsockopt(fd, level, optname, optval, (socklen_t*)optlen); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getsockopt( @@ -216,15 +236,15 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getsockopt( { jclass c = env->GetObjectClass(optval); if (!c) { - return ZTS_ERR_INVALID_OP; + return ZTS_ERR_SERVICE; } int optval_int = 0; - socklen_t optlen; // Intentionally not used + zts_socklen_t optlen; // Intentionally not used int retval; if (optname == SO_RCVTIMEO) { - struct timeval tv; + struct zts_timeval tv; optlen = sizeof(tv); retval = zts_getsockopt(fd, level, optname, &tv, &optlen); // Convert seconds and microseconds back to milliseconds @@ -261,91 +281,61 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getsockopt( } #endif -int zts_getsockname(int fd, struct sockaddr *addr, socklen_t *addrlen) +int zts_getsockname(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen) { if (!addr) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; + } + if (*addrlen > (int)sizeof(struct zts_sockaddr_storage) || *addrlen < (int)sizeof(struct zts_sockaddr_in)) { + return ZTS_ERR_ARG; } - if (*addrlen > (int)sizeof(struct sockaddr_storage) || *addrlen < (int)sizeof(struct sockaddr_in)) { - return ZTS_ERR_INVALID_ARG; + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_getsockname(fd, addr, addrlen); + return lwip_getsockname(fd, (sockaddr*)addr, (socklen_t*)addrlen); } #ifdef SDK_JNI JNIEXPORT jboolean JNICALL Java_com_zerotier_libzt_ZeroTier_getsockname(JNIEnv *env, jobject thisObj, jint fd, jobject addr) { - struct sockaddr_storage ss; - socklen_t addrlen = sizeof(struct sockaddr_storage); - int retval =zts_getsockname(fd, (struct sockaddr *)&ss, &addrlen); + struct zts_sockaddr_storage ss; + zts_socklen_t addrlen = sizeof(struct zts_sockaddr_storage); + int retval = zts_getsockname(fd, (struct zts_sockaddr *)&ss, &addrlen); ss2zta(env, &ss, addr); return retval > -1 ? retval : -(zts_errno); } #endif -int zts_getpeername(int fd, struct sockaddr *addr, socklen_t *addrlen) +int zts_getpeername(int fd, struct zts_sockaddr *addr, zts_socklen_t *addrlen) { if (!addr) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } - if (*addrlen > (int)sizeof(struct sockaddr_storage) || *addrlen < (int)sizeof(struct sockaddr_in)) { - return ZTS_ERR_INVALID_ARG; + if (*addrlen > (int)sizeof(struct zts_sockaddr_storage) || *addrlen < (int)sizeof(struct zts_sockaddr_in)) { + return ZTS_ERR_ARG; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_getpeername(fd, addr, addrlen); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_getpeername(fd, (sockaddr*)addr, (socklen_t*)addrlen); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getpeername(JNIEnv *env, jobject thisObj, jint fd, jobject addr) { - struct sockaddr_storage ss; - int retval = zts_getpeername(fd, (struct sockaddr *)&ss, (socklen_t *)sizeof(struct sockaddr_storage)); + struct zts_sockaddr_storage ss; + int retval = zts_getpeername(fd, (struct zts_sockaddr *)&ss, (zts_socklen_t*)sizeof(struct zts_sockaddr_storage)); ss2zta(env, &ss, addr); return retval > -1 ? retval : -(zts_errno); } #endif -int zts_gethostname(char *name, size_t len) -{ - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_INVALID_OP : ZTS_ERR_INVALID_OP; // TODO -} -#ifdef SDK_JNI -#endif - -int zts_sethostname(const char *name, size_t len) -{ - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_INVALID_OP : ZTS_ERR_INVALID_OP; // TODO -} -#ifdef SDK_JNI -#endif - -/* -struct hostent *zts_gethostbyname(const char *name) -{ - return (struct hostent *)((!_run_service || !_run_lwip_tcpip) ? NULL : NULL); - // TODO: Test thread safety - char buf[256]; - int buflen = 256; - int h_err = 0; - struct hostent hret; - struct hostent **result = NULL; - int err = 0; - if ((err = lwip_gethostbyname_r(name, &hret, buf, buflen, result, &h_err)) != 0) { - DEBUG_ERROR("err = %d", err); - DEBUG_ERROR("h_err = %d", h_err); - errno = h_err; - return NULL; // failure - } - return *result; - - return lwip_gethostbyname(name); -} -#ifdef SDK_JNI -#endif -*/ - int zts_close(int fd) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_close(fd); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_close(fd); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_close( @@ -355,22 +345,25 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_close( } #endif -int zts_select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, - struct timeval *timeout) +int zts_select(int nfds, zts_fd_set *readfds, zts_fd_set *writefds, zts_fd_set *exceptfds, + struct zts_timeval *timeout) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_select(nfds, readfds, writefds, exceptfds, timeout); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_select(nfds, (fd_set*)readfds, (fd_set*)writefds, (fd_set*)exceptfds, (timeval*)timeout); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_select(JNIEnv *env, jobject thisObj, jint nfds, jobject readfds, jobject writefds, jobject exceptfds, jint timeout_sec, jint timeout_usec) { - struct timeval _timeout; + struct zts_timeval _timeout; _timeout.tv_sec = timeout_sec; _timeout.tv_usec = timeout_usec; - fd_set _readfds, _writefds, _exceptfds; - fd_set *r = NULL; - fd_set *w = NULL; - fd_set *e = NULL; + zts_fd_set _readfds, _writefds, _exceptfds; + zts_fd_set *r = NULL; + zts_fd_set *w = NULL; + zts_fd_set *e = NULL; if (readfds) { r = &_readfds; ztfdset2fdset(env, nfds, readfds, &_readfds); @@ -411,7 +404,10 @@ int zts_fcntl(int fd, int cmd, int flags) translated_flags = 1; } #endif - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_fcntl(fd, cmd, translated_flags); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_fcntl(fd, cmd, translated_flags); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_fcntl( @@ -422,12 +418,24 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_fcntl( } #endif +// TODO: JNI version +int zts_poll(struct zts_pollfd *fds, nfds_t nfds, int timeout) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_poll((pollfd*)fds, nfds, timeout); +} + int zts_ioctl(int fd, unsigned long request, void *argp) { if (!argp) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_ioctl(fd, request, argp); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_ioctl(fd, request, argp); } #ifdef SDK_JNI JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_ioctl( @@ -435,13 +443,12 @@ JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_ioctl( { int retval = ZTS_ERR_OK; if (request == FIONREAD) { - // DEBUG_ERROR("FIONREAD"); int bytesRemaining = 0; retval = zts_ioctl(fd, request, &bytesRemaining); // set value in general object jclass c = env->GetObjectClass(argp); if (!c) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } jfieldID fid = env->GetFieldID(c, "integer", "I"); env->SetIntField(argp, fid, bytesRemaining); @@ -449,7 +456,6 @@ JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_ioctl( if (request == FIONBIO) { // TODO: double check int meaninglessVariable = 0; - // DEBUG_ERROR("FIONBIO"); retval = zts_ioctl(fd, request, &meaninglessVariable); } return retval > -1 ? retval : -(zts_errno); @@ -459,9 +465,12 @@ JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_ioctl( ssize_t zts_send(int fd, const void *buf, size_t len, int flags) { if (!buf || len <= 0) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; + } + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_send(fd, buf, len, flags); + return lwip_send(fd, buf, len, flags); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_send( @@ -475,25 +484,28 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_send( #endif ssize_t zts_sendto(int fd, const void *buf, size_t len, int flags, - const struct sockaddr *addr, socklen_t addrlen) + const struct zts_sockaddr *addr,zts_socklen_t addrlen) { if (!addr || !buf || len <= 0) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; + } + if (addrlen > (int)sizeof(struct zts_sockaddr_storage) || addrlen < (int)sizeof(struct zts_sockaddr_in)) { + return ZTS_ERR_ARG; } - if (addrlen > (int)sizeof(struct sockaddr_storage) || addrlen < (int)sizeof(struct sockaddr_in)) { - return ZTS_ERR_INVALID_ARG; + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_sendto(fd, buf, len, flags, addr, addrlen); + return lwip_sendto(fd, buf, len, flags, (sockaddr*)addr, addrlen); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_sendto( JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint flags, jobject addr) { void *data = env->GetPrimitiveArrayCritical(buf, NULL); - struct sockaddr_storage ss; + struct zts_sockaddr_storage ss; zta2ss(env, &ss, addr); - socklen_t addrlen = ss.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); - int retval = zts_sendto(fd, data, env->GetArrayLength(buf), flags, (struct sockaddr *)&ss, addrlen); + zts_socklen_t addrlen = ss.ss_family == ZTS_AF_INET ? sizeof(struct zts_sockaddr_in) : sizeof(struct zts_sockaddr_in6); + int retval = zts_sendto(fd, data, env->GetArrayLength(buf), flags, (struct zts_sockaddr *)&ss, addrlen); env->ReleasePrimitiveArrayCritical(buf, data, 0); return retval > -1 ? retval : -(zts_errno); } @@ -501,7 +513,10 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_sendto( ssize_t zts_sendmsg(int fd, const struct msghdr *msg, int flags) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_sendmsg(fd, msg, flags); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_sendmsg(fd, msg, flags); } #ifdef SDK_JNI #endif @@ -509,9 +524,12 @@ ssize_t zts_sendmsg(int fd, const struct msghdr *msg, int flags) ssize_t zts_recv(int fd, void *buf, size_t len, int flags) { if (!buf) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; + } + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_recv(fd, buf, len, flags); + return lwip_recv(fd, buf, len, flags); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recv(JNIEnv *env, jobject thisObj, @@ -525,49 +543,64 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recv(JNIEnv *env, jobjec #endif ssize_t zts_recvfrom(int fd, void *buf, size_t len, int flags, - struct sockaddr *addr, socklen_t *addrlen) + struct zts_sockaddr *addr, zts_socklen_t *addrlen) { if (!buf) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; + } + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_recvfrom(fd, buf, len, flags, addr, addrlen); + return lwip_recvfrom(fd, buf, len, flags, (sockaddr*)addr, (socklen_t*)addrlen); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recvfrom( JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint flags, jobject addr) { - socklen_t addrlen = sizeof(struct sockaddr_storage); - struct sockaddr_storage ss; + zts_socklen_t addrlen = sizeof(struct zts_sockaddr_storage); + struct zts_sockaddr_storage ss; void *data = env->GetPrimitiveArrayCritical(buf, NULL); - int retval = zts_recvfrom(fd, data, env->GetArrayLength(buf), flags, (struct sockaddr *)&ss, &addrlen); + int retval = zts_recvfrom(fd, data, env->GetArrayLength(buf), flags, (struct zts_sockaddr *)&ss, &addrlen); env->ReleasePrimitiveArrayCritical(buf, data, 0); ss2zta(env, &ss, addr); return retval > -1 ? retval : -(zts_errno); } #endif +// TODO: JNI version ssize_t zts_recvmsg(int fd, struct msghdr *msg, int flags) { - // Not currently implemented by stack - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : ZTS_ERR_GENERAL; + if (!msg) { + return ZTS_ERR_ARG; + } + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_recvmsg(fd, msg, flags); } #ifdef SDK_JNI #endif -int zts_read(int fd, void *buf, size_t len) +ssize_t zts_read(int fd, void *buf, size_t len) { if (!buf) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; + } + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_read(fd, buf, len); + return lwip_read(fd, buf, len); } -int zts_read_offset(int fd, void *buf, size_t offset, size_t len) +ssize_t zts_read_offset(int fd, void *buf, size_t offset, size_t len) { if (!buf) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; + } + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; } char *cbuf = (char*)buf; - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_read(fd, &(cbuf[offset]), len); + return lwip_read(fd, &(cbuf[offset]), len); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read(JNIEnv *env, jobject thisObj, @@ -596,12 +629,24 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1length(JNIEnv *env } #endif -int zts_write(int fd, const void *buf, size_t len) +// TODO: JNI version +ssize_t zts_readv(int s, const struct zts_iovec *iov, int iovcnt) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_readv(s, (iovec*)iov, iovcnt); +} + +ssize_t zts_write(int fd, const void *buf, size_t len) { if (!buf || len <= 0) { - return ZTS_ERR_INVALID_ARG; + return ZTS_ERR_ARG; } - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_write(fd, buf, len); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_write(fd, buf, len); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write__IB(JNIEnv *env, jobject thisObj, @@ -628,9 +673,21 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write_1byte(JNIEnv *env, } #endif +// TODO: JNI version +ssize_t zts_writev(int fd, const struct zts_iovec *iov, int iovcnt) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_writev(fd, (iovec*)iov, iovcnt); +} + int zts_shutdown(int fd, int how) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_shutdown(fd, how); + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return lwip_shutdown(fd, how); } #ifdef SDK_JNI JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_shutdown( @@ -640,42 +697,213 @@ JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_shutdown( } #endif -int zts_add_dns_nameserver(struct sockaddr *addr) +int zts_add_dns_nameserver(struct zts_sockaddr *addr) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return ZTS_ERR_SERVICE; // TODO +} +#ifdef SDK_JNI +#endif + +int zts_del_dns_nameserver(struct zts_sockaddr *addr) +{ + if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) { + return ZTS_ERR_SERVICE; + } + return ZTS_ERR_SERVICE; // TODO +} +#ifdef SDK_JNI +#endif + +uint16_t zts_htons(uint16_t n) +{ + return lwip_htons(n); +} + +uint32_t zts_htonl(uint32_t n) +{ + return lwip_htonl(n); +} + +uint16_t zts_ntohs(uint16_t n) +{ + return lwip_htons(n); +} + +uint32_t zts_ntohl(uint32_t n) +{ + return lwip_htonl(n); +} + +const char *zts_inet_ntop(int af, const void *src, char *dst,zts_socklen_t size) +{ + return lwip_inet_ntop(af,src,dst,size); +} + +int zts_inet_pton(int af, const char *src, void *dst) +{ + return lwip_inet_pton(af,src,dst); +} + +uint32_t zts_inet_addr(const char *cp) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : -1; // TODO + return ipaddr_addr(cp); +} + +////////////////////////////////////////////////////////////////////////////// +// Statistics // +////////////////////////////////////////////////////////////////////////////// + +extern struct stats_ lwip_stats; + +int zts_get_all_stats(struct zts_stats *statsDest) +{ +#if LWIP_STATS + if (!statsDest) { + return ZTS_ERR_ARG; + } + memset(statsDest, 0, sizeof(struct zts_stats)); + // Copy lwIP stats + memcpy(&(statsDest->link), &(lwip_stats.link), sizeof(struct stats_proto)); + memcpy(&(statsDest->etharp), &(lwip_stats.etharp), sizeof(struct stats_proto)); + memcpy(&(statsDest->ip_frag), &(lwip_stats.ip_frag), sizeof(struct stats_proto)); + memcpy(&(statsDest->ip), &(lwip_stats.ip), sizeof(struct stats_proto)); + memcpy(&(statsDest->icmp), &(lwip_stats.icmp), sizeof(struct stats_proto)); + //memcpy(&(statsDest->igmp), &(lwip_stats.igmp), sizeof(struct stats_igmp)); + memcpy(&(statsDest->udp), &(lwip_stats.udp), sizeof(struct stats_proto)); + memcpy(&(statsDest->tcp), &(lwip_stats.tcp), sizeof(struct stats_proto)); + // mem omitted + // memp omitted + memcpy(&(statsDest->sys), &(lwip_stats.sys), sizeof(struct stats_sys)); + memcpy(&(statsDest->ip6), &(lwip_stats.ip6), sizeof(struct stats_proto)); + memcpy(&(statsDest->icmp6), &(lwip_stats.icmp6), sizeof(struct stats_proto)); + memcpy(&(statsDest->ip6_frag), &(lwip_stats.ip6_frag), sizeof(struct stats_proto)); + memcpy(&(statsDest->mld6), &(lwip_stats.mld6), sizeof(struct stats_igmp)); + memcpy(&(statsDest->nd6), &(lwip_stats.nd6), sizeof(struct stats_proto)); + memcpy(&(statsDest->ip_frag), &(lwip_stats.ip_frag), sizeof(struct stats_proto)); + // mib2 omitted + // Copy ZT stats + // ... + return ZTS_ERR_OK; +#else + return ZTS_ERR_NO_RESULT; +#endif } #ifdef SDK_JNI + // No implementation for JNI #endif -int zts_del_dns_nameserver(struct sockaddr *addr) +int zts_get_protocol_stats(int protocolType, void *protoStatsDest) { - return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : -1; // TODO +#if LWIP_STATS + if (!protoStatsDest) { + return ZTS_ERR_ARG; + } + memset(protoStatsDest, 0, sizeof(struct stats_proto)); + switch (protocolType) + { + case ZTS_STATS_PROTOCOL_LINK: + memcpy(protoStatsDest, &(lwip_stats.link), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_ETHARP: + memcpy(protoStatsDest, &(lwip_stats.etharp), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_IP: + memcpy(protoStatsDest, &(lwip_stats.ip), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_UDP: + memcpy(protoStatsDest, &(lwip_stats.udp), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_TCP: + memcpy(protoStatsDest, &(lwip_stats.tcp), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_ICMP: + memcpy(protoStatsDest, &(lwip_stats.icmp), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_IP_FRAG: + memcpy(protoStatsDest, &(lwip_stats.ip_frag), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_IP6: + memcpy(protoStatsDest, &(lwip_stats.ip6), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_ICMP6: + memcpy(protoStatsDest, &(lwip_stats.icmp6), sizeof(struct stats_proto)); + break; + case ZTS_STATS_PROTOCOL_IP6_FRAG: + memcpy(protoStatsDest, &(lwip_stats.ip6_frag), sizeof(struct stats_proto)); + break; + default: + return ZTS_ERR_ARG; + } + return ZTS_ERR_OK; +#else + return ZTS_ERR_NO_RESULT; +#endif } #ifdef SDK_JNI +JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1protocol_1stats( + JNIEnv *env, jobject thisObj, jint protocolType, jobject protoStatsObj) +{ + struct stats_proto stats; + int retval = zts_get_protocol_stats(protocolType, &stats); + // Copy stats into Java object + jclass c = env->GetObjectClass(protoStatsObj); + if (!c) { + return ZTS_ERR_ARG; + } + jfieldID fid; + fid = env->GetFieldID(c, "xmit", "I"); + env->SetIntField(protoStatsObj, fid, stats.xmit); + fid = env->GetFieldID(c, "recv", "I"); + env->SetIntField(protoStatsObj, fid, stats.recv); + fid = env->GetFieldID(c, "fw", "I"); + env->SetIntField(protoStatsObj, fid, stats.fw); + fid = env->GetFieldID(c, "drop", "I"); + env->SetIntField(protoStatsObj, fid, stats.drop); + fid = env->GetFieldID(c, "chkerr", "I"); + env->SetIntField(protoStatsObj, fid, stats.chkerr); + fid = env->GetFieldID(c, "lenerr", "I"); + env->SetIntField(protoStatsObj, fid, stats.lenerr); + fid = env->GetFieldID(c, "memerr", "I"); + env->SetIntField(protoStatsObj, fid, stats.memerr); + fid = env->GetFieldID(c, "rterr", "I"); + env->SetIntField(protoStatsObj, fid, stats.rterr); + fid = env->GetFieldID(c, "proterr", "I"); + env->SetIntField(protoStatsObj, fid, stats.proterr); + fid = env->GetFieldID(c, "opterr", "I"); + env->SetIntField(protoStatsObj, fid, stats.opterr); + fid = env->GetFieldID(c, "err", "I"); + env->SetIntField(protoStatsObj, fid, stats.err); + fid = env->GetFieldID(c, "cachehit", "I"); + env->SetIntField(protoStatsObj, fid, stats.cachehit); + return retval; +} #endif #ifdef SDK_JNI -void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, fd_set *dest_fd_set) +void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, zts_fd_set *dest_fd_set) { jclass c = env->GetObjectClass(src_ztfd_set); if (!c) { return; } - FD_ZERO(dest_fd_set); + ZTS_FD_ZERO(dest_fd_set); jfieldID fid = env->GetFieldID(c, "fds_bits", "[B"); jobject fdData = env->GetObjectField (src_ztfd_set, fid); jbyteArray * arr = reinterpret_cast<jbyteArray*>(&fdData); char *data = (char*)env->GetByteArrayElements(*arr, NULL); for (int i=0; i<nfds; i++) { if (data[i] == 0x01) { - FD_SET(i, dest_fd_set); + ZTS_FD_SET(i, dest_fd_set); } } env->ReleaseByteArrayElements(*arr, (jbyte*)data, 0); return; } -void fdset2ztfdset(JNIEnv *env, int nfds, fd_set *src_fd_set, jobject dest_ztfd_set) +void fdset2ztfdset(JNIEnv *env, int nfds, zts_fd_set *src_fd_set, jobject dest_ztfd_set) { jclass c = env->GetObjectClass(dest_ztfd_set); if (!c) { @@ -686,7 +914,7 @@ void fdset2ztfdset(JNIEnv *env, int nfds, fd_set *src_fd_set, jobject dest_ztfd_ jbyteArray * arr = reinterpret_cast<jbyteArray*>(&fdData); char *data = (char*)env->GetByteArrayElements(*arr, NULL); for (int i=0; i<nfds; i++) { - if (FD_ISSET(i, src_fd_set)) { + if (ZTS_FD_ISSET(i, src_fd_set)) { data[i] = 0x01; } } @@ -698,15 +926,15 @@ void fdset2ztfdset(JNIEnv *env, int nfds, fd_set *src_fd_set, jobject dest_ztfd_ // Helpers (for moving data across the JNI barrier) // ////////////////////////////////////////////////////////////////////////////// -void ss2zta(JNIEnv *env, struct sockaddr_storage *ss, jobject addr) +void ss2zta(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr) { jclass c = env->GetObjectClass(addr); if (!c) { return; } - if(ss->ss_family == AF_INET) + if(ss->ss_family == ZTS_AF_INET) { - struct sockaddr_in *in4 = (struct sockaddr_in*)ss; + struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)ss; jfieldID fid = env->GetFieldID(c, "_port", "I"); env->SetIntField(addr, fid, lwip_ntohs(in4->sin_port)); fid = env->GetFieldID(c,"_family", "I"); @@ -720,9 +948,9 @@ void ss2zta(JNIEnv *env, struct sockaddr_storage *ss, jobject addr) return; } - if(ss->ss_family == AF_INET6) + if(ss->ss_family == ZTS_AF_INET6) { - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)ss; + struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)ss; jfieldID fid = env->GetFieldID(c, "_port", "I"); env->SetIntField(addr, fid, lwip_ntohs(in6->sin6_port)); fid = env->GetFieldID(c,"_family", "I"); @@ -737,7 +965,7 @@ void ss2zta(JNIEnv *env, struct sockaddr_storage *ss, jobject addr) } } -void zta2ss(JNIEnv *env, struct sockaddr_storage *ss, jobject addr) +void zta2ss(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr) { jclass c = env->GetObjectClass(addr); if (!c) { @@ -745,12 +973,12 @@ void zta2ss(JNIEnv *env, struct sockaddr_storage *ss, jobject addr) } jfieldID fid = env->GetFieldID(c, "_family", "I"); int family = env->GetIntField(addr, fid); - if (family == AF_INET) + if (family == ZTS_AF_INET) { - struct sockaddr_in *in4 = (struct sockaddr_in*)ss; + struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)ss; fid = env->GetFieldID(c, "_port", "I"); in4->sin_port = lwip_htons(env->GetIntField(addr, fid)); - in4->sin_family = AF_INET; + in4->sin_family = ZTS_AF_INET; fid = env->GetFieldID(c, "_ip4", "[B"); jobject ipData = env->GetObjectField (addr, fid); jbyteArray * arr = reinterpret_cast<jbyteArray*>(&ipData); @@ -759,13 +987,13 @@ void zta2ss(JNIEnv *env, struct sockaddr_storage *ss, jobject addr) env->ReleaseByteArrayElements(*arr, (jbyte*)data, 0); return; } - if (family == AF_INET6) + if (family == ZTS_AF_INET6) { - struct sockaddr_in6 *in6 = (struct sockaddr_in6*)ss; + struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)ss; jfieldID fid = env->GetFieldID(c, "_port", "I"); in6->sin6_port = lwip_htons(env->GetIntField(addr, fid)); fid = env->GetFieldID(c,"_family", "I"); - in6->sin6_family = AF_INET6; + in6->sin6_family = ZTS_AF_INET6; fid = env->GetFieldID(c, "_ip6", "[B"); jobject ipData = env->GetObjectField (addr, fid); jbyteArray * arr = reinterpret_cast<jbyteArray*>(&ipData); diff --git a/src/VirtualTap.cpp b/src/VirtualTap.cpp index 88b6861..fd1b32a 100644 --- a/src/VirtualTap.cpp +++ b/src/VirtualTap.cpp @@ -14,28 +14,41 @@ /** * @file * - * Virtual Ethernet tap device + * Virtual ethernet tap device and combined network stack driver */ -#include "VirtualTap.hpp" -#include "Phy.hpp" -#include "Node.hpp" -//#include "OSUtils.hpp" - -#include "Service.hpp" +#include "MAC.hpp" #include "Mutex.hpp" -#include "lwipDriver.hpp" -#include "ZeroTier.h" +#include "InetAddress.hpp" +#include "MulticastGroup.hpp" + +#include "lwip/netif.h" +#include "lwip/etharp.h" +#include "lwip/sys.h" +#include "lwip/ethip6.h" +#include "lwip/tcpip.h" +#include "netif/ethernet.h" + +#ifdef LWIP_STATS +#include "lwip/stats.h" +#endif -#ifdef _MSC_VER +#include "VirtualTap.hpp" +#include "ZeroTierSockets.h" +#include "Events.hpp" +#include "Debug.hpp" + +#if defined(__WINDOWS__) +#include <time.h> #include "Synchapi.h" #endif +#define ZTS_TAP_THREAD_POLLING_INTERVAL 50 +#define LWIP_DRIVER_LOOP_INTERVAL 250 + namespace ZeroTier { -class VirtualTap; -extern OneService *service; -extern void postEvent(int eventCode, void *arg); +extern void _enqueueEvent(int16_t eventCode, void *arg = NULL); /** * A virtual tap device. The ZeroTier core service creates one of these for each @@ -66,7 +79,7 @@ VirtualTap::VirtualTap( memset(vtap_full_name, 0, sizeof(vtap_full_name)); snprintf(vtap_full_name, sizeof(vtap_full_name), "libzt%llx", (unsigned long long)_nwid); _dev = vtap_full_name; -#ifndef _WIN32 +#ifndef __WINDOWS__ ::pipe(_shutdownSignalPipe); #endif // Start virtual tap thread and stack I/O loops @@ -77,18 +90,18 @@ VirtualTap::~VirtualTap() { struct zts_network_details *nd = new zts_network_details; nd->nwid = _nwid; - postEvent(ZTS_EVENT_NETWORK_DOWN, (void*)nd); + _enqueueEvent(ZTS_EVENT_NETWORK_DOWN, (void*)nd); _run = false; -#ifndef _WIN32 +#ifndef __WINDOWS__ ::write(_shutdownSignalPipe[1],"\0",1); #endif _phy.whack(); - lwip_remove_netif(netif4); + _lwip_remove_netif(netif4); netif4 = NULL; - lwip_remove_netif(netif6); + _lwip_remove_netif(netif6); netif6 = NULL; Thread::join(_thread); -#ifndef _WIN32 +#ifndef __WINDOWS__ ::close(_shutdownSignalPipe[0]); ::close(_shutdownSignalPipe[1]); #endif @@ -156,7 +169,7 @@ bool VirtualTap::addIp(const InetAddress &ip) return false; } if (std::find(_ips.begin(),_ips.end(),ip) == _ips.end()) { - lwip_init_interface((void*)this, ip); + _lwip_init_interface((void*)this, ip); // TODO: Add ZTS_EVENT_ADDR_NEW ? _ips.push_back(ip); // Send callback message @@ -165,12 +178,12 @@ bool VirtualTap::addIp(const InetAddress &ip) if (ip.isV4()) { struct sockaddr_in *in4 = (struct sockaddr_in*)&(ad->addr); memcpy(&(in4->sin_addr.s_addr), ip.rawIpData(), 4); - postEvent(ZTS_EVENT_ADDR_ADDED_IP4, (void*)ad); + _enqueueEvent(ZTS_EVENT_ADDR_ADDED_IP4, (void*)ad); } if (ip.isV6()) { struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(ad->addr); memcpy(&(in6->sin6_addr.s6_addr), ip.rawIpData(), 16); - postEvent(ZTS_EVENT_ADDR_ADDED_IP6, (void*)ad); + _enqueueEvent(ZTS_EVENT_ADDR_ADDED_IP6, (void*)ad); } std::sort(_ips.begin(),_ips.end()); } @@ -187,14 +200,14 @@ bool VirtualTap::removeIp(const InetAddress &ip) if (ip.isV4()) { struct sockaddr_in *in4 = (struct sockaddr_in*)&(ad->addr); memcpy(&(in4->sin_addr.s_addr), ip.rawIpData(), 4); - postEvent(ZTS_EVENT_ADDR_REMOVED_IP4, (void*)ad); + _enqueueEvent(ZTS_EVENT_ADDR_REMOVED_IP4, (void*)ad); // FIXME: De-register from network stack } if (ip.isV6()) { // FIXME: De-register from network stack struct sockaddr_in6 *in6 = (struct sockaddr_in6*)&(ad->addr); memcpy(&(in6->sin6_addr.s6_addr), ip.rawIpData(), 16); - postEvent(ZTS_EVENT_ADDR_REMOVED_IP6, (void*)ad); + _enqueueEvent(ZTS_EVENT_ADDR_REMOVED_IP6, (void*)ad); } _ips.erase(i); } @@ -211,7 +224,7 @@ void VirtualTap::put(const MAC &from,const MAC &to,unsigned int etherType, const void *data,unsigned int len) { if (len <= _mtu && _enabled) { - lwip_eth_rx(this, from, to, etherType, data, len); + _lwip_eth_rx(this, from, to, etherType, data, len); } } @@ -220,19 +233,6 @@ std::string VirtualTap::deviceName() const return _dev; } -std::string VirtualTap::nodeId() const -{ - if (service) { - char id[16]; - memset(id, 0, sizeof(id)); - sprintf(id, "%llx", (unsigned long long)((OneService *)service)->getNode()->address()); - return std::string(id); - } - else { - return std::string("----------"); - } -} - void VirtualTap::setFriendlyName(const char *friendlyName) { DEBUG_INFO("%s", friendlyName); @@ -290,7 +290,7 @@ void VirtualTap::threadMain() if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) { break; } -#if defined(_WIN32) +#if defined(__WINDOWS__) Sleep(ZTS_TAP_THREAD_POLLING_INTERVAL); #else struct timespec sleepValue = {0}; @@ -300,11 +300,6 @@ void VirtualTap::threadMain() } } -void VirtualTap::Housekeeping() -{ - // -} - void VirtualTap::phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *local_address, const struct sockaddr *from,void *data,unsigned long len) {} void VirtualTap::phyOnTcpConnect(PhySocket *sock,void **uptr,bool success) {} @@ -313,5 +308,461 @@ void VirtualTap::phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,v void VirtualTap::phyOnTcpClose(PhySocket *sock,void **uptr) {} void VirtualTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {} void VirtualTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {} +void VirtualTap::phyOnUnixClose(PhySocket *sock,void **uptr) {} + +////////////////////////////////////////////////////////////////////////////// +// Netif driver code for lwIP network stack // +////////////////////////////////////////////////////////////////////////////// + +bool _has_exited = false; + +// Used to generate enumerated lwIP interface names +int netifCount = 0; + +// Lock to guard access to network stack state changes +Mutex stackLock; + +// Callback for when the TCPIP thread has been successfully started +static void _tcpip_init_done(void *arg) +{ + sys_sem_t *sem; + sem = (sys_sem_t *)arg; + _setState(ZTS_STATE_STACK_RUNNING); + _enqueueEvent(ZTS_EVENT_STACK_UP); + sys_sem_signal(sem); +} + +static void _main_lwip_driver_loop(void *arg) +{ +#if defined(__linux__) + pthread_setname_np(pthread_self(), ZTS_LWIP_DRIVER_THREAD_NAME); +#endif +#if defined(__APPLE__) + pthread_setname_np(ZTS_LWIP_DRIVER_THREAD_NAME); +#endif + sys_sem_t sem; + LWIP_UNUSED_ARG(arg); + if (sys_sem_new(&sem, 0) != ERR_OK) { + DEBUG_ERROR("failed to create semaphore"); + } + tcpip_init(_tcpip_init_done, &sem); + sys_sem_wait(&sem); + // Main loop + while(_getState(ZTS_STATE_STACK_RUNNING)) { + zts_delay_ms(LWIP_DRIVER_LOOP_INTERVAL); + } + _has_exited = true; + _enqueueEvent(ZTS_EVENT_STACK_DOWN); +} + +bool _lwip_is_up() +{ + Mutex::Lock _l(stackLock); + return _getState(ZTS_STATE_STACK_RUNNING); +} + +bool _lwip_has_previously_shutdown() +{ + Mutex::Lock _l(stackLock); + return _has_exited; +} + +void _lwip_driver_init() +{ + if (_lwip_is_up()) { + return; + } + if (_lwip_has_previously_shutdown()) { + return; + } + Mutex::Lock _l(stackLock); +#if defined(__WINDOWS__) + sys_init(); // Required for win32 init of critical sections +#endif + sys_thread_new(ZTS_LWIP_DRIVER_THREAD_NAME, _main_lwip_driver_loop, + NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); +} + +void _lwip_driver_shutdown() +{ + if (_lwip_has_previously_shutdown()) { + return; + } + Mutex::Lock _l(stackLock); + // Set flag to stop sending frames into the core + _clrState(ZTS_STATE_STACK_RUNNING); + // Wait until the main lwIP thread has exited + while (!_has_exited) { zts_delay_ms(LWIP_DRIVER_LOOP_INTERVAL); } + /* + if (tcpip_shutdown() == ERR_OK) { + sys_timeouts_free(); + } + */ +} + +void _lwip_remove_netif(void *netif) +{ + if (!netif) { + return; + } + struct netif *n = (struct netif*)netif; + LOCK_TCPIP_CORE(); + netif_remove(n); + netif_set_down(n); + netif_set_link_down(n); + UNLOCK_TCPIP_CORE(); +} + +err_t _lwip_eth_tx(struct netif *n, struct pbuf *p) +{ + if (!n) { + return ERR_IF; + } + struct pbuf *q; + char buf[ZT_MAX_MTU+32]; + char *bufptr; + int totalLength = 0; + + VirtualTap *tap = (VirtualTap*)n->state; + bufptr = buf; + for (q = p; q != NULL; q = q->next) { + memcpy(bufptr, q->payload, q->len); + bufptr += q->len; + totalLength += q->len; + } + struct eth_hdr *ethhdr; + ethhdr = (struct eth_hdr *)buf; + + MAC src_mac; + MAC dest_mac; + src_mac.setTo(ethhdr->src.addr, 6); + dest_mac.setTo(ethhdr->dest.addr, 6); + + char *data = buf + sizeof(struct eth_hdr); + int len = totalLength - sizeof(struct eth_hdr); + int proto = Utils::ntoh((uint16_t)ethhdr->type); + tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len); + if (ZT_MSG_TRANSFER == true) { + char flagbuf[32]; + memset(&flagbuf, 0, 32); + char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16]; + snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", + ethhdr->dest.addr[0], ethhdr->dest.addr[1], ethhdr->dest.addr[2], + ethhdr->dest.addr[3], ethhdr->dest.addr[4], ethhdr->dest.addr[5]); + MAC mac; + mac.setTo(ethhdr->dest.addr, 6); + mac.toAddress(tap->_nwid).toString(nodeBuf); + /* + DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] ethertype=0x%04x %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(), + Utils::ntoh(ethhdr->type), flagbuf); + */ + } + return ERR_OK; +} + +void _lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType, + const void *data, unsigned int len) +{ +#ifdef LWIP_STATS + stats_display(); +#endif + if (!_getState(ZTS_STATE_STACK_RUNNING)) { + return; + } + struct pbuf *p,*q; + struct eth_hdr ethhdr; + from.copyTo(ethhdr.src.addr, 6); + to.copyTo(ethhdr.dest.addr, 6); + ethhdr.type = Utils::hton((uint16_t)etherType); + + if (ZT_MSG_TRANSFER == true) { + char flagbuf[32]; + memset(&flagbuf, 0, 32); + char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16]; + snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", + ethhdr.dest.addr[0], ethhdr.dest.addr[1], ethhdr.dest.addr[2], + ethhdr.dest.addr[3], ethhdr.dest.addr[4], ethhdr.dest.addr[5]); + MAC mac; + mac.setTo(ethhdr.src.addr, 6); + mac.toAddress(tap->_nwid).toString(nodeBuf); + /* + DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] ethertype=0x%04x %s", len, macBuf, nodeBuf, tap->nodeId().c_str(), + Utils::ntoh(ethhdr.type), flagbuf); + */ + } + + p = pbuf_alloc(PBUF_RAW, (uint16_t)len+sizeof(struct eth_hdr), PBUF_RAM); + if (!p) { + DEBUG_ERROR("dropped packet: unable to allocate memory for pbuf"); + return; + } + // First pbuf gets ethernet header at start + q = p; + if (q->len < sizeof(ethhdr)) { + pbuf_free(p); + p = NULL; + DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header"); + return; + } + // Copy frame data into pbuf + const char *dataptr = reinterpret_cast<const char *>(data); + memcpy(q->payload,ðhdr,sizeof(ethhdr)); + int remainingPayloadSpace = q->len - sizeof(ethhdr); + memcpy((char*)q->payload + sizeof(ethhdr),dataptr,remainingPayloadSpace); + dataptr += remainingPayloadSpace; + // Remaining pbufs (if any) get rest of data + while ((q = q->next)) { + memcpy(q->payload,dataptr,q->len); + dataptr += q->len; + } + // Feed packet into stack + int err; + + if (Utils::ntoh(ethhdr.type) == 0x800 || Utils::ntoh(ethhdr.type) == 0x806) { + if ((err = ((struct netif *)tap->netif4)->input(p, (struct netif *)tap->netif4)) != ERR_OK) { + DEBUG_ERROR("packet input error (%d)", err); + pbuf_free(p); + } + } + if (Utils::ntoh(ethhdr.type) == 0x86DD) { + if ((err = ((struct netif *)tap->netif6)->input(p, (struct netif *)tap->netif6)) != ERR_OK) { + DEBUG_ERROR("packet input error (%d)", err); + pbuf_free(p); + } + } +} + +/* +static void print_netif_info(struct netif *n) { + DEBUG_INFO("n=%p, %c%c, %d, o=%p, o6=%p, mc=%x:%x:%x:%x:%x:%x, hwln=%d, st=%p, flgs=%d\n", + n, + n->name[0], + n->name[1], + n->mtu, + n->output, + n->output_ip6, + n->hwaddr[0], + n->hwaddr[1], + n->hwaddr[2], + n->hwaddr[3], + n->hwaddr[4], + n->hwaddr[5], + n->hwaddr_len, + n->state, + n->flags + ); +} +*/ + +bool _lwip_is_netif_up(void *n) +{ + if (!n) { + return false; + } + LOCK_TCPIP_CORE(); + bool result = netif_is_up((struct netif*)n); + UNLOCK_TCPIP_CORE(); + return result; +} + +/** + * Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED) + */ +#if LWIP_NETIF_REMOVE_CALLBACK +static void _netif_remove_callback(struct netif *n) +{ + // Called from core, no need to lock + if (!n || !n->state) { + return; + } + VirtualTap *tap = (VirtualTap *)n->state; + uint64_t mac = 0; + memcpy(&mac, n->hwaddr, n->hwaddr_len); + struct zts_netif_details *ifd = new zts_netif_details; + ifd->nwid = tap->_nwid; + memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len); + ifd->mac = lwip_htonl(ifd->mac) >> 16; + _enqueueEvent(ZTS_EVENT_NETIF_REMOVED, (void*)ifd); +} +#endif + +/** + * Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN) + */ +#if LWIP_NETIF_LINK_CALLBACK +static void _netif_link_callback(struct netif *n) +{ + // Called from core, no need to lock + if (!n || !n->state) { + return; + } + VirtualTap *tap = (VirtualTap *)n->state; + uint64_t mac = 0; + memcpy(&mac, n->hwaddr, n->hwaddr_len); + if (n->flags & NETIF_FLAG_LINK_UP) { + struct zts_netif_details *ifd = new zts_netif_details; + ifd->nwid = tap->_nwid; + memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len); + ifd->mac = lwip_htonl(ifd->mac) >> 16; + _enqueueEvent(ZTS_EVENT_NETIF_LINK_UP, (void*)ifd); + } + if (n->flags & NETIF_FLAG_LINK_UP) { + struct zts_netif_details *ifd = new zts_netif_details; + ifd->nwid = tap->_nwid; + memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len); + ifd->mac = lwip_htonl(ifd->mac) >> 16; + _enqueueEvent(ZTS_EVENT_NETIF_LINK_DOWN, (void*)ifd); + } +} +#endif + +void _lwip_set_callbacks(struct netif *n) +{ + if (!n) { + return; + } +#if LWIP_NETIF_STATUS_CALLBACK + // Not currently used + netif_set_status_callback(n, netif_status_callback); +#endif +#if LWIP_NETIF_REMOVE_CALLBACK + netif_set_remove_callback(n, netif_remove_callback); +#endif +#if LWIP_NETIF_LINK_CALLBACK + netif_set_link_callback(n, netif_link_callback); +#endif +} + +static struct zts_netif_details *_lwip_prepare_netif_status_msg(struct netif *n) +{ + if (!n || !n->state) { + return NULL; + } + VirtualTap *tap = (VirtualTap*)(n->state); + struct zts_netif_details *ifd = new zts_netif_details; + ifd->nwid = tap->_nwid; + ifd->mtu = n->mtu; + memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len); + ifd->mac = htonll(ifd->mac) >> 16; + return ifd; +} + +static err_t _netif_init4(struct netif *n) +{ + if (!n || !n->state) { + return ERR_IF; + } + // Called from netif code, no need to lock + n->hwaddr_len = 6; + n->name[0] = '4'; + n->name[1] = 'a'+netifCount; + n->linkoutput = _lwip_eth_tx; + n->output = etharp_output; + n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU; + n->flags = NETIF_FLAG_BROADCAST + | NETIF_FLAG_ETHARP + | NETIF_FLAG_ETHERNET + | NETIF_FLAG_IGMP + | NETIF_FLAG_MLD6 + | NETIF_FLAG_LINK_UP + | NETIF_FLAG_UP; + n->hwaddr_len = sizeof(n->hwaddr); + VirtualTap *tap = (VirtualTap*)(n->state); + tap->_mac.copyTo(n->hwaddr, n->hwaddr_len); + return ERR_OK; +} + +static err_t _netif_init6(struct netif *n) +{ + if (!n || !n->state) { + return ERR_IF; + } + n->hwaddr_len = sizeof(n->hwaddr); + VirtualTap *tap = (VirtualTap*)(n->state); + tap->_mac.copyTo(n->hwaddr, n->hwaddr_len); + // Called from netif code, no need to lock + n->hwaddr_len = 6; + n->name[0] = '6'; + n->name[1] = 'a'+netifCount; + n->linkoutput = _lwip_eth_tx; + n->output_ip6 = ethip6_output; + n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU; + n->flags = NETIF_FLAG_BROADCAST + | NETIF_FLAG_ETHARP + | NETIF_FLAG_ETHERNET + | NETIF_FLAG_IGMP + | NETIF_FLAG_MLD6 + | NETIF_FLAG_LINK_UP + | NETIF_FLAG_UP; + return ERR_OK; +} + +void _lwip_init_interface(void *tapref, const InetAddress &ip) +{ + char ipbuf[INET6_ADDRSTRLEN]; + char macbuf[ZTS_MAC_ADDRSTRLEN]; + + VirtualTap *vtap = (VirtualTap*)tapref; + struct netif *n = NULL; + bool isNewNetif = false; + + if (ip.isV4()) { + if (vtap->netif4) { + n = (struct netif*)vtap->netif4; + } + else { + n = new struct netif; + isNewNetif = true; + netifCount++; + } + char nmbuf[INET6_ADDRSTRLEN]; + static ip4_addr_t ip4, netmask, gw; + IP4_ADDR(&gw,127,0,0,1); + ip4.addr = *((u32_t *)ip.rawIpData()); + netmask.addr = *((u32_t *)ip.netmask().rawIpData()); + LOCK_TCPIP_CORE(); + netif_add(n, &ip4, &netmask, &gw, (void*)vtap, _netif_init4, tcpip_input); + vtap->netif4 = (void*)n; + _enqueueEvent(ZTS_EVENT_NETIF_UP, (void*)_lwip_prepare_netif_status_msg(n)); + UNLOCK_TCPIP_CORE(); + snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", + n->hwaddr[0], n->hwaddr[1], n->hwaddr[2], + n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]); + DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, nm=%s, tap=%p]",n, + macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf), vtap); + } + if (ip.isV6()) { + if (vtap->netif6) { + n = (struct netif*)vtap->netif6; + } + else { + n = new struct netif; + isNewNetif = true; + netifCount++; + } + static ip6_addr_t ip6; + memcpy(&(ip6.addr), ip.rawIpData(), sizeof(ip6.addr)); + LOCK_TCPIP_CORE(); + if (isNewNetif) { + vtap->netif6 = (void*)n; + netif_add(n, NULL, NULL, NULL, (void*)vtap, _netif_init6, ethernet_input); + n->ip6_autoconfig_enabled = 1; + vtap->_mac.copyTo(n->hwaddr, n->hwaddr_len); + netif_create_ip6_linklocal_address(n, 1); + netif_set_link_up(n); + netif_set_up(n); + netif_set_default(n); + } + netif_add_ip6_address(n,&ip6,NULL); + n->output_ip6 = ethip6_output; + UNLOCK_TCPIP_CORE(); + _enqueueEvent(ZTS_EVENT_NETIF_UP, (void*)_lwip_prepare_netif_status_msg(n)); + snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", + n->hwaddr[0], n->hwaddr[1], n->hwaddr[2], + n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]); + DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, tap=%p]", n, + macbuf, ip.toString(ipbuf), vtap); + } +} -} // namespace ZeroTier
\ No newline at end of file +} // namespace ZeroTier diff --git a/src/VirtualTap.hpp b/src/VirtualTap.hpp index 3703e96..486225c 100644 --- a/src/VirtualTap.hpp +++ b/src/VirtualTap.hpp @@ -14,38 +14,30 @@ /** * @file * - * Virtual Ethernet tap device + * Header for virtual ethernet tap device and combined network stack driver */ -#ifndef LIBZT_VIRTUALTAP_HPP -#define LIBZT_VIRTUALTAP_HPP +#ifndef ZT_VIRTUAL_TAP_HPP +#define ZT_VIRTUAL_TAP_HPP -#ifndef _MSC_VER -extern int errno; -#endif +#include "lwip/err.h" + +#define ZTS_LWIP_DRIVER_THREAD_NAME "NetworkStackThread" +#include "MAC.hpp" #include "Phy.hpp" #include "Thread.hpp" -#include "InetAddress.hpp" -#include "MulticastGroup.hpp" -#include "Mutex.hpp" - -#include "Options.h" - -#if defined(_WIN32) -#include <WinSock2.h> -#include <Windows.h> -#include <IPHlpApi.h> -#include <Ifdef.h> -#endif namespace ZeroTier { class Mutex; +class MAC; +class MulticastGroup; +struct InetAddress; /** - * A virtual tap device. The ZeroTier core service creates one of these for each - * virtual network joined. It will be destroyed upon leave(). + * A virtual tap device. The ZeroTier Node Service will create one per + * joined network. It will be destroyed upon leave(). */ class VirtualTap { @@ -84,18 +76,18 @@ public: bool hasIpv6Addr(); /** - * Adds an address to the userspace stack interface associated with this VirtualTap + * Adds an address to the user-space stack interface associated with this VirtualTap * - Starts VirtualTap main thread ONLY if successful */ bool addIp(const InetAddress &ip); /** - * Removes an address from the userspace stack interface associated with this VirtualTap + * Removes an address from the user-space stack interface associated with this VirtualTap */ bool removeIp(const InetAddress &ip); /** - * Presents data to the userspace stack + * Presents data to the user-space stack */ void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data, unsigned int len); @@ -106,11 +98,6 @@ public: std::string deviceName() const; /** - * Get Node ID (ZT address) - */ - std::string nodeId() const; - - /** * Set friendly name */ void setFriendlyName(const char *friendlyName); @@ -152,10 +139,6 @@ public: void (*_handler)(void *, void *, uint64_t, const MAC &, const MAC &, unsigned int, unsigned int, const void *, unsigned int); - ////////////////////////////////////////////////////////////////////////////// - // Lower-level lwIP netif handling and traffic handling readiness // - ////////////////////////////////////////////////////////////////////////////// - void *netif4 = NULL; void *netif6 = NULL; @@ -164,20 +147,10 @@ public: */ uint64_t _lastConfigUpdateTime = 0; - /** - * The last time that a callback notification was sent to the user application signalling - * that this interface is ready to process traffic. - */ - uint64_t _lastReadyReportTime = 0; - void lastConfigUpdate(uint64_t lastConfigUpdateTime); int _networkStatus = 0; - ////////////////////////////////////////////////////////////////////////////// - // Vars // - ////////////////////////////////////////////////////////////////////////////// - std::vector<std::pair<InetAddress, InetAddress> > routes; char vtap_full_name[64]; @@ -205,17 +178,6 @@ public: std::vector<MulticastGroup> _multicastGroups; Mutex _multicastGroups_m; - /* - * Timestamp of last run of housekeeping - * SEE: ZT_HOUSEKEEPING_INTERVAL in ZeroTier.h - */ - uint64_t last_housekeeping_ts = 0; - - /** - * Performs miscellaneous background tasks - */ - void Housekeeping(); - ////////////////////////////////////////////////////////////////////////////// // Not used in this implementation // ////////////////////////////////////////////////////////////////////////////// @@ -228,8 +190,135 @@ public: void phyOnTcpClose(PhySocket *sock,void **uptr); void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len); void phyOnTcpWritable(PhySocket *sock,void **uptr); + void phyOnUnixClose(PhySocket *sock,void **uptr); }; +/** + * @brief Return whether a given netif's NETIF_FLAG_UP flag is set + * + * @usage This is a convenience function to encapsulate a macro + */ +bool _lwip_is_netif_up(void *netif); + +/** + * @brief Increase the delay multiplier for the main driver loop + * + * @usage This should be called when we know the stack won't be used by any virtual taps + */ +void _lwip_hibernate_driver(); + +/** + * @brief Decrease the delay multiplier for the main driver loop + * + * @usage This should be called when at least one virtual tap is active + */ +void _lwip_wake_driver(); + +/** + * Returns whether the lwIP network stack is up and ready to process traffic + */ +bool _lwip_is_up(); + +/** + * @brief Initialize network stack semaphores, threads, and timers. + * + * @usage This is called during the initial setup of each VirtualTap but is only allowed to execute once + * @return + */ +void _lwip_driver_init(); + +/** + * @brief Shutdown the stack as completely as possible (not officially supported by lwIP) + * + * @usage This is to be called after it is determined that no further network activity will take place. + * The tcpip thread will be stopped, all interfaces will be brought down and all resources will + * be deallocated. A full application restart will be required to bring the stack back online. + * @return + */ +void _lwip_driver_shutdown(); + +/** + * @brief Requests that a netif be brought down and removed. + * + * @return + */ +void _lwip_remove_netif(void *netif); + +/** + * @brief Initialize and start the DNS client + * + * @usage Called after lwip_driver_init() + * @return + */ +void _lwip_dns_init(); + +/** + * @brief Starts DHCP timers + * + * @usage lwip_driver_init() + * @return + */ +void _lwip_start_dhcp(void *netif); + +/** + * @brief Called when the status of a netif changes: + * - Interface is up/down (ZTS_EVENT_NETIF_UP, ZTS_EVENT_NETIF_DOWN) + * - Address changes while up (ZTS_EVENT_NETIF_NEW_ADDRESS) + */ +#if LWIP_NETIF_STATUS_CALLBACK +static void _netif_status_callback(struct netif *netif); +#endif + +/** + * @brief Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED) + */ +#if LWIP_NETIF_REMOVE_CALLBACK +static void _netif_remove_callback(struct netif *netif); +#endif + +/** + * @brief Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN) + */ +#if LWIP_NETIF_LINK_CALLBACK +static void _netif_link_callback(struct netif *netif); +#endif + +/** + * @brief Set up an interface in the network stack for the VirtualTap. + * + * @param + * @param tapref Reference to VirtualTap that will be responsible for sending and receiving data + * @param ip Virtual IP address for this ZeroTier VirtualTap interface + * @return + */ +void _lwip_init_interface(void *tapref, const InetAddress &ip); + +/** + * @brief Called from the stack, outbound ethernet frames from the network stack enter the ZeroTier virtual wire here. + * + * @usage This shall only be called from the stack or the stack driver. Not the application thread. + * @param netif Transmits an outgoing Ethernet fram from the network stack onto the ZeroTier virtual wire + * @param p A pointer to the beginning of a chain pf struct pbufs + * @return + */ +err_t _lwip_eth_tx(struct netif *netif, struct pbuf *p); + +/** + * @brief Receives incoming Ethernet frames from the ZeroTier virtual wire + * + * @usage This shall be called from the VirtualTap's I/O thread (via VirtualTap::put()) + * @param tap Pointer to VirtualTap from which this data comes + * @param from Origin address (virtual ZeroTier hardware address) + * @param to Intended destination address (virtual ZeroTier hardware address) + * @param etherType Protocol type + * @param data Pointer to Ethernet frame + * @param len Length of Ethernet frame + * @return + */ +void _lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType, + const void *data, unsigned int len); + } // namespace ZeroTier #endif // _H + diff --git a/src/lwipDriver.cpp b/src/lwipDriver.cpp deleted file mode 100644 index b8fa9e2..0000000 --- a/src/lwipDriver.cpp +++ /dev/null @@ -1,535 +0,0 @@ -/* - * Copyright (c)2013-2020 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2024-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -/** - * @file - * - * lwIP network stack driver - */ - -#include <queue> - -#include "MAC.hpp" -#include "Mutex.hpp" - -#include "netif/ethernet.h" -#include "lwip/netif.h" -#include "lwip/etharp.h" -#include "lwip/tcpip.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/sys.h" -#include "lwip/tcp.h" -#include "lwip/timeouts.h" -#include "lwip/stats.h" -#include "lwip/ethip6.h" -#include "lwip/ip_addr.h" -#include "lwip/nd6.h" -#include "lwip/netifapi.h" - -#ifdef LWIP_STATS -#include "lwip/stats.h" -#endif - -#include "VirtualTap.hpp" -#include "lwipDriver.hpp" -#include "ZeroTier.h" -#include "Controls.hpp" - -extern void postEvent(uint64_t eventCode, void *arg); -extern void postEvent(uint64_t eventCode); - -#if defined(_WIN32) -#include <time.h> -#endif - -/** - * Length of human-readable MAC address string - */ -#define ZTS_MAC_ADDRSTRLEN 18 - -#ifndef htonll -#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) -#endif - -namespace ZeroTier { - -bool _has_exited = false; -int hibernationDelayMultiplier = 1; -int netifCount = 0; -extern bool _run_lwip_tcpip; -Mutex lwip_driver_m; - -void lwip_sleep(long ms) -{ -#if defined(_WIN32) - Sleep(ms*hibernationDelayMultiplier); -#else - usleep(ms*1000*hibernationDelayMultiplier); -#endif -} - -void lwip_hibernate_driver() -{ - hibernationDelayMultiplier = ZTS_HIBERNATION_MULTIPLIER; -} - -void lwip_wake_driver() -{ - hibernationDelayMultiplier = 1; -} - -// Callback for when the TCPIP thread has been successfully started -static void tcpip_init_done(void *arg) -{ - sys_sem_t *sem; - sem = (sys_sem_t *)arg; - _run_lwip_tcpip = true; - postEvent(ZTS_EVENT_STACK_UP); - sys_sem_signal(sem); -} - -static void main_lwip_driver_loop(void *arg) -{ -#if defined(__linux__) - pthread_setname_np(pthread_self(), ZTS_LWIP_DRIVER_THREAD_NAME); -#endif -#if defined(__APPLE__) - pthread_setname_np(ZTS_LWIP_DRIVER_THREAD_NAME); -#endif - sys_sem_t sem; - LWIP_UNUSED_ARG(arg); - if (sys_sem_new(&sem, 0) != ERR_OK) { - DEBUG_ERROR("failed to create semaphore"); - } - tcpip_init(tcpip_init_done, &sem); - sys_sem_wait(&sem); - // Main loop - while(_run_lwip_tcpip) { - lwip_sleep(LWIP_DRIVER_LOOP_INTERVAL); - } - _has_exited = true; - postEvent(ZTS_EVENT_STACK_DOWN); -} - -bool lwip_is_up() -{ - Mutex::Lock _l(lwip_driver_m); - return _run_lwip_tcpip; -} - -bool lwip_has_previously_shutdown() -{ - Mutex::Lock _l(lwip_driver_m); - return _has_exited; -} - -void lwip_driver_init() -{ - if (lwip_is_up()) { - return; - } - if (lwip_has_previously_shutdown()) { - return; - } - Mutex::Lock _l(lwip_driver_m); -#if defined(_WIN32) - sys_init(); // Required for win32 init of critical sections -#endif - sys_thread_new(ZTS_LWIP_DRIVER_THREAD_NAME, main_lwip_driver_loop, - NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO); -} - -void lwip_driver_shutdown() -{ - if (lwip_has_previously_shutdown()) { - return; - } - Mutex::Lock _l(lwip_driver_m); - // Set flag to stop sending frames into the core - _run_lwip_tcpip = false; - // Wait until the main lwIP thread has exited - while (!_has_exited) { lwip_sleep(LWIP_DRIVER_LOOP_INTERVAL); } - /* - if (tcpip_shutdown() == ERR_OK) { - sys_timeouts_free(); - } - */ -} - -void lwip_remove_netif(void *netif) -{ - if (!netif) { - return; - } - struct netif *n = (struct netif*)netif; - LOCK_TCPIP_CORE(); - netif_remove(n); - netif_set_down(n); - netif_set_link_down(n); - UNLOCK_TCPIP_CORE(); -} - -err_t lwip_eth_tx(struct netif *n, struct pbuf *p) -{ - if (!n) { - return ERR_IF; - } - struct pbuf *q; - char buf[ZT_MAX_MTU+32]; - char *bufptr; - int totalLength = 0; - - VirtualTap *tap = (VirtualTap*)n->state; - bufptr = buf; - for (q = p; q != NULL; q = q->next) { - memcpy(bufptr, q->payload, q->len); - bufptr += q->len; - totalLength += q->len; - } - struct eth_hdr *ethhdr; - ethhdr = (struct eth_hdr *)buf; - - MAC src_mac; - MAC dest_mac; - src_mac.setTo(ethhdr->src.addr, 6); - dest_mac.setTo(ethhdr->dest.addr, 6); - - char *data = buf + sizeof(struct eth_hdr); - int len = totalLength - sizeof(struct eth_hdr); - int proto = Utils::ntoh((uint16_t)ethhdr->type); - tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len); - if (ZT_MSG_TRANSFER == true) { - char flagbuf[32]; - memset(&flagbuf, 0, 32); - char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16]; - snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", - ethhdr->dest.addr[0], ethhdr->dest.addr[1], ethhdr->dest.addr[2], - ethhdr->dest.addr[3], ethhdr->dest.addr[4], ethhdr->dest.addr[5]); - MAC mac; - mac.setTo(ethhdr->dest.addr, 6); - mac.toAddress(tap->_nwid).toString(nodeBuf); - /* - DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] ethertype=0x%04x %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(), - Utils::ntoh(ethhdr->type), flagbuf); - */ - } - return ERR_OK; -} - -void lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType, - const void *data, unsigned int len) -{ -#ifdef LWIP_STATS - stats_display(); -#endif - if (!_run_lwip_tcpip) { - return; - } - struct pbuf *p,*q; - struct eth_hdr ethhdr; - from.copyTo(ethhdr.src.addr, 6); - to.copyTo(ethhdr.dest.addr, 6); - ethhdr.type = Utils::hton((uint16_t)etherType); - - if (ZT_MSG_TRANSFER == true) { - char flagbuf[32]; - memset(&flagbuf, 0, 32); - char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16]; - snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", - ethhdr.dest.addr[0], ethhdr.dest.addr[1], ethhdr.dest.addr[2], - ethhdr.dest.addr[3], ethhdr.dest.addr[4], ethhdr.dest.addr[5]); - MAC mac; - mac.setTo(ethhdr.src.addr, 6); - mac.toAddress(tap->_nwid).toString(nodeBuf); - /* - DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] ethertype=0x%04x %s", len, macBuf, nodeBuf, tap->nodeId().c_str(), - Utils::ntoh(ethhdr.type), flagbuf); - */ - } - - p = pbuf_alloc(PBUF_RAW, (uint16_t)len+sizeof(struct eth_hdr), PBUF_RAM); - if (!p) { - DEBUG_ERROR("dropped packet: unable to allocate memory for pbuf"); - return; - } - // First pbuf gets ethernet header at start - q = p; - if (q->len < sizeof(ethhdr)) { - pbuf_free(p); - p = NULL; - DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header"); - return; - } - // Copy frame data into pbuf - const char *dataptr = reinterpret_cast<const char *>(data); - memcpy(q->payload,ðhdr,sizeof(ethhdr)); - int remainingPayloadSpace = q->len - sizeof(ethhdr); - memcpy((char*)q->payload + sizeof(ethhdr),dataptr,remainingPayloadSpace); - dataptr += remainingPayloadSpace; - // Remaining pbufs (if any) get rest of data - while ((q = q->next)) { - memcpy(q->payload,dataptr,q->len); - dataptr += q->len; - } - // Feed packet into stack - int err; - - if (Utils::ntoh(ethhdr.type) == 0x800 || Utils::ntoh(ethhdr.type) == 0x806) { - if ((err = ((struct netif *)tap->netif4)->input(p, (struct netif *)tap->netif4)) != ERR_OK) { - DEBUG_ERROR("packet input error (%d)", err); - pbuf_free(p); - } - } - if (Utils::ntoh(ethhdr.type) == 0x86DD) { - if ((err = ((struct netif *)tap->netif6)->input(p, (struct netif *)tap->netif6)) != ERR_OK) { - DEBUG_ERROR("packet input error (%d)", err); - pbuf_free(p); - } - } -} - -/* -static void print_netif_info(struct netif *n) { - DEBUG_INFO("n=%p, %c%c, %d, o=%p, o6=%p, mc=%x:%x:%x:%x:%x:%x, hwln=%d, st=%p, flgs=%d\n", - n, - n->name[0], - n->name[1], - n->mtu, - n->output, - n->output_ip6, - n->hwaddr[0], - n->hwaddr[1], - n->hwaddr[2], - n->hwaddr[3], - n->hwaddr[4], - n->hwaddr[5], - n->hwaddr_len, - n->state, - n->flags - ); -} -*/ - -bool lwip_is_netif_up(void *n) -{ - if (!n) { - return false; - } - LOCK_TCPIP_CORE(); - bool result = netif_is_up((struct netif*)n); - UNLOCK_TCPIP_CORE(); - return result; -} - -/** - * Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED) - */ -#if LWIP_NETIF_REMOVE_CALLBACK -static void netif_remove_callback(struct netif *n) -{ - // Called from core, no need to lock - if (!n || !n->state) { - return; - } - VirtualTap *tap = (VirtualTap *)n->state; - uint64_t mac = 0; - memcpy(&mac, n->hwaddr, n->hwaddr_len); - struct zts_netif_details *ifd = new zts_netif_details; - ifd->nwid = tap->_nwid; - memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len); - ifd->mac = lwip_htonl(ifd->mac) >> 16; - postEvent(ZTS_EVENT_NETIF_REMOVED, (void*)ifd); -} -#endif - -/** - * Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN) - */ -#if LWIP_NETIF_LINK_CALLBACK -static void netif_link_callback(struct netif *n) -{ - // Called from core, no need to lock - if (!n || !n->state) { - return; - } - VirtualTap *tap = (VirtualTap *)n->state; - uint64_t mac = 0; - memcpy(&mac, n->hwaddr, n->hwaddr_len); - if (n->flags & NETIF_FLAG_LINK_UP) { - struct zts_netif_details *ifd = new zts_netif_details; - ifd->nwid = tap->_nwid; - memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len); - ifd->mac = lwip_htonl(ifd->mac) >> 16; - postEvent(ZTS_EVENT_NETIF_LINK_UP, (void*)ifd); - } - if (n->flags & NETIF_FLAG_LINK_UP) { - struct zts_netif_details *ifd = new zts_netif_details; - ifd->nwid = tap->_nwid; - memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len); - ifd->mac = lwip_htonl(ifd->mac) >> 16; - postEvent(ZTS_EVENT_NETIF_LINK_DOWN, (void*)ifd); - } -} -#endif - -void lwip_set_callbacks(struct netif *n) -{ - if (!n) { - return; - } -#if LWIP_NETIF_STATUS_CALLBACK - // Not currently used - netif_set_status_callback(n, netif_status_callback); -#endif -#if LWIP_NETIF_REMOVE_CALLBACK - netif_set_remove_callback(n, netif_remove_callback); -#endif -#if LWIP_NETIF_LINK_CALLBACK - netif_set_link_callback(n, netif_link_callback); -#endif -} - -static struct zts_netif_details *lwip_prepare_netif_status_msg(struct netif *n) -{ - if (!n || !n->state) { - return NULL; - } - VirtualTap *tap = (VirtualTap*)(n->state); - struct zts_netif_details *ifd = new zts_netif_details; - ifd->nwid = tap->_nwid; - ifd->mtu = n->mtu; - memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len); - ifd->mac = htonll(ifd->mac) >> 16; - return ifd; -} - -static err_t netif_init(struct netif *n) -{ - if (!n || !n->state) { - return ERR_IF; - } - // Called from netif code, no need to lock - n->hwaddr_len = 6; - n->name[0] = '4'; - n->name[1] = 'a'+netifCount; - n->linkoutput = lwip_eth_tx; - n->output = etharp_output; - n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU; - n->flags = NETIF_FLAG_BROADCAST - | NETIF_FLAG_ETHARP - | NETIF_FLAG_ETHERNET - | NETIF_FLAG_IGMP - | NETIF_FLAG_MLD6 - | NETIF_FLAG_LINK_UP - | NETIF_FLAG_UP; - n->hwaddr_len = sizeof(n->hwaddr); - VirtualTap *tap = (VirtualTap*)(n->state); - tap->_mac.copyTo(n->hwaddr, n->hwaddr_len); - return ERR_OK; -} - -static err_t netif_init6(struct netif *n) -{ - if (!n || !n->state) { - return ERR_IF; - } - n->hwaddr_len = sizeof(n->hwaddr); - VirtualTap *tap = (VirtualTap*)(n->state); - tap->_mac.copyTo(n->hwaddr, n->hwaddr_len); - // Called from netif code, no need to lock - n->hwaddr_len = 6; - n->name[0] = '6'; - n->name[1] = 'a'+netifCount; - n->linkoutput = lwip_eth_tx; - n->output_ip6 = ethip6_output; - n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU; - n->flags = NETIF_FLAG_BROADCAST - | NETIF_FLAG_ETHARP - | NETIF_FLAG_ETHERNET - | NETIF_FLAG_IGMP - | NETIF_FLAG_MLD6 - | NETIF_FLAG_LINK_UP - | NETIF_FLAG_UP; - return ERR_OK; -} - -void lwip_init_interface(void *tapref, const InetAddress &ip) -{ - char ipbuf[INET6_ADDRSTRLEN]; - char macbuf[ZTS_MAC_ADDRSTRLEN]; - - VirtualTap *vtap = (VirtualTap*)tapref; - struct netif *n = NULL; - bool isNewNetif = false; - - if (ip.isV4()) { - if (vtap->netif4) { - n = (struct netif*)vtap->netif4; - } - else { - n = new struct netif; - isNewNetif = true; - netifCount++; - } - char nmbuf[INET6_ADDRSTRLEN]; - static ip4_addr_t ip4, netmask, gw; - IP4_ADDR(&gw,127,0,0,1); - ip4.addr = *((u32_t *)ip.rawIpData()); - netmask.addr = *((u32_t *)ip.netmask().rawIpData()); - LOCK_TCPIP_CORE(); - netif_add(n, &ip4, &netmask, &gw, (void*)vtap, netif_init, tcpip_input); - vtap->netif4 = (void*)n; - postEvent(ZTS_EVENT_NETIF_UP, (void*)lwip_prepare_netif_status_msg(n)); - UNLOCK_TCPIP_CORE(); - snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", - n->hwaddr[0], n->hwaddr[1], n->hwaddr[2], - n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]); - DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, nm=%s, tap=%p]",n, - macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf), vtap); - } - if (ip.isV6()) { - if (vtap->netif6) { - n = (struct netif*)vtap->netif6; - } - else { - n = new struct netif; - isNewNetif = true; - netifCount++; - } - static ip6_addr_t ip6; - memcpy(&(ip6.addr), ip.rawIpData(), sizeof(ip6.addr)); - LOCK_TCPIP_CORE(); - if (isNewNetif) { - vtap->netif6 = (void*)n; - netif_add(n, NULL, NULL, NULL, (void*)vtap, netif_init6, ethernet_input); - n->ip6_autoconfig_enabled = 1; - vtap->_mac.copyTo(n->hwaddr, n->hwaddr_len); - netif_create_ip6_linklocal_address(n, 1); - netif_set_link_up(n); - netif_set_up(n); - netif_set_default(n); - } - netif_add_ip6_address(n,&ip6,NULL); - n->output_ip6 = ethip6_output; - UNLOCK_TCPIP_CORE(); - postEvent(ZTS_EVENT_NETIF_UP, (void*)lwip_prepare_netif_status_msg(n)); - snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x", - n->hwaddr[0], n->hwaddr[1], n->hwaddr[2], - n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]); - DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, tap=%p]", n, - macbuf, ip.toString(ipbuf), vtap); - } -} - -} // namespace ZeroTier
\ No newline at end of file diff --git a/src/lwipDriver.hpp b/src/lwipDriver.hpp deleted file mode 100644 index c2bcd9a..0000000 --- a/src/lwipDriver.hpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (c)2013-2020 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2024-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -/** - * @file - * - * lwIP network stack driver - */ - -#ifndef LIBZT_LWIP_DRIVER_HPP -#define LIBZT_LWIP_DRIVER_HPP - -#include "Debug.hpp" -#include "lwip/err.h" - -namespace ZeroTier { - -class MAC; -class Mutex; -class VirtualTap; -struct InetAddress; - -/** - * @brief Structure used to associate packets with interfaces. - */ -struct zts_sorted_packet -{ - // lwIP pbuf containing packet (originally encapsulated by ZT packet) - struct pbuf *p; - // ZT VirtualTap from which this packet originates - VirtualTap *vtap; - // lwIP netif we should accept this packet on - struct netif *n; -}; - -/** - * @brief Return whether a given netif's NETIF_FLAG_UP flag is set - * - * @usage This is a convenience function to encapsulate a macro - */ -bool lwip_is_netif_up(void *netif); - -/** - * @brief Increase the delay multiplier for the main driver loop - * - * @usage This should be called when we know the stack won't be used by any virtual taps - */ -void lwip_hibernate_driver(); - -/** - * @brief Decrease the delay multiplier for the main driver loop - * - * @usage This should be called when at least one virtual tap is active - */ -void lwip_wake_driver(); - -/** - * Returns whether the lwIP network stack is up and ready to process traffic - */ -bool lwip_is_up(); - -/** - * @brief Initialize network stack semaphores, threads, and timers. - * - * @usage This is called during the initial setup of each VirtualTap but is only allowed to execute once - * @return - */ -void lwip_driver_init(); - -/** - * @brief Shutdown the stack as completely as possible (not officially supported by lwIP) - * - * @usage This is to be called after it is determined that no further network activity will take place. - * The tcpip thread will be stopped, all interfaces will be brought down and all resources will - * be deallocated. A full application restart will be required to bring the stack back online. - * @return - */ -void lwip_driver_shutdown(); - -/** - * @brief Requests that a netif be brought down and removed. - * - * @return - */ -void lwip_remove_netif(void *netif); - -/** - * @brief Initialize and start the DNS client - * - * @usage Called after lwip_driver_init() - * @return - */ -void lwip_dns_init(); - -/** - * @brief Starts DHCP timers - * - * @usage lwip_driver_init() - * @return - */ -void lwip_start_dhcp(void *netif); - -/** - * @brief Called when the status of a netif changes: - * - Interface is up/down (ZTS_EVENT_NETIF_UP, ZTS_EVENT_NETIF_DOWN) - * - Address changes while up (ZTS_EVENT_NETIF_NEW_ADDRESS) - */ -#if LWIP_NETIF_STATUS_CALLBACK -static void netif_status_callback(struct netif *netif); -#endif - -/** - * @brief Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED) - */ -#if LWIP_NETIF_REMOVE_CALLBACK -static void netif_remove_callback(struct netif *netif); -#endif - -/** - * @brief Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN) - */ -#if LWIP_NETIF_LINK_CALLBACK -static void netif_link_callback(struct netif *netif); -#endif - -/** - * @brief Set up an interface in the network stack for the VirtualTap. - * - * @param - * @param tapref Reference to VirtualTap that will be responsible for sending and receiving data - * @param ip Virtual IP address for this ZeroTier VirtualTap interface - * @return - */ -void lwip_init_interface(void *tapref, const InetAddress &ip); - -/** - * @brief Called from the stack, outbound ethernet frames from the network stack enter the ZeroTier virtual wire here. - * - * @usage This shall only be called from the stack or the stack driver. Not the application thread. - * @param netif Transmits an outgoing Ethernet fram from the network stack onto the ZeroTier virtual wire - * @param p A pointer to the beginning of a chain pf struct pbufs - * @return - */ -err_t lwip_eth_tx(struct netif *netif, struct pbuf *p); - -/** - * @brief Receives incoming Ethernet frames from the ZeroTier virtual wire - * - * @usage This shall be called from the VirtualTap's I/O thread (via VirtualTap::put()) - * @param tap Pointer to VirtualTap from which this data comes - * @param from Origin address (virtual ZeroTier hardware address) - * @param to Intended destination address (virtual ZeroTier hardware address) - * @param etherType Protocol type - * @param data Pointer to Ethernet frame - * @param len Length of Ethernet frame - * @return - */ -void lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType, - const void *data, unsigned int len); - -} // namespace ZeroTier - -#endif // _H |
