summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoseph Henry <[email protected]>2020-05-01 19:15:38 -0700
committerJoseph Henry <[email protected]>2020-05-01 19:15:38 -0700
commita0b50530d37d9c13d30a68bf1d4686485be36327 (patch)
tree50251ec3ef7f18468ec3eb2d379d835ea8c64d1f /src
parent2c709277b9632bd8e3af8b66f51d3f5a53f84e8e (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.cpp1062
-rw-r--r--src/Controls.hpp107
-rw-r--r--src/Events.cpp245
-rw-r--r--src/Events.hpp106
-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.h80
-rw-r--r--src/Sockets.cpp574
-rw-r--r--src/VirtualTap.cpp541
-rw-r--r--src/VirtualTap.hpp195
-rw-r--r--src/lwipDriver.cpp535
-rw-r--r--src/lwipDriver.hpp173
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,&ethhdr,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,&ethhdr,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