Add portability and consistency fixes for C API, remove cruft, slight internal restructuring

This commit is contained in:
Joseph Henry
2020-05-01 19:15:38 -07:00
parent 2c709277b9
commit a0b50530d3
29 changed files with 4359 additions and 4110 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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

245
src/Events.cpp Normal file
View File

@@ -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

106
src/Events.hpp Normal file
View File

@@ -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

View File

@@ -11,89 +11,57 @@
*/
/****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/**
* @file
*
* ZeroTier Node Service (a distant relative of OneService)
*/
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <list>
#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"
#ifdef SDK_JNI
#include <jni.h>
#endif
// 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
// 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

View File

@@ -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

View File

@@ -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

View File

@@ -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
extern int zts_errno;
namespace ZeroTier {
//////////////////////////////////////////////////////////////////////////////
// ZeroTier Socket API //
//////////////////////////////////////////////////////////////////////////////
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 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_connect(fd, addr, addrlen);
if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
return ZTS_ERR_SERVICE;
}
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 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_getsockname(fd, addr, addrlen);
if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
return ZTS_ERR_SERVICE;
}
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;
}
return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_send(fd, buf, len, flags);
if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
return ZTS_ERR_SERVICE;
}
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 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_sendto(fd, buf, len, flags, addr, addrlen);
if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
return ZTS_ERR_SERVICE;
}
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;
}
return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_recv(fd, buf, len, flags);
if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
return ZTS_ERR_SERVICE;
}
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;
}
return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_recvfrom(fd, buf, len, flags, addr, addrlen);
if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
return ZTS_ERR_SERVICE;
}
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;
}
return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : lwip_read(fd, buf, len);
if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
return ZTS_ERR_SERVICE;
}
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)
{
return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : -1; // TODO
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 sockaddr *addr)
int zts_del_dns_nameserver(struct zts_sockaddr *addr)
{
return (!_run_service || !_run_lwip_tcpip) ? ZTS_ERR_SERVICE : -1; // TODO
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 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
void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, fd_set *dest_fd_set)
// No implementation for JNI
#endif
int zts_get_protocol_stats(int protocolType, void *protoStatsDest)
{
#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, 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);

View File

@@ -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"
#ifdef _MSC_VER
#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
#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) {}
} // namespace ZeroTier
//////////////////////////////////////////////////////////////////////////////
// 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

View File

@@ -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);
@@ -105,11 +97,6 @@ public:
*/
std::string deviceName() const;
/**
* Get Node ID (ZT address)
*/
std::string nodeId() const;
/**
* Set friendly name
*/
@@ -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

View File

@@ -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

View File

@@ -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