Add portability and consistency fixes for C API, remove cruft, slight internal restructuring
This commit is contained in:
1080
src/Controls.cpp
1080
src/Controls.cpp
File diff suppressed because it is too large
Load Diff
107
src/Controls.hpp
107
src/Controls.hpp
@@ -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
245
src/Events.cpp
Normal 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
106
src/Events.hpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
574
src/Sockets.cpp
574
src/Sockets.cpp
@@ -17,42 +17,41 @@
|
||||
* ZeroTier Socket API
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#include "ZeroTierConstants.h"
|
||||
#include "Options.h"
|
||||
#include "Debug.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
#include "Events.hpp"
|
||||
|
||||
#ifdef SDK_JNI
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
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);
|
||||
|
||||
@@ -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,ðhdr,sizeof(ethhdr));
|
||||
int remainingPayloadSpace = q->len - sizeof(ethhdr);
|
||||
memcpy((char*)q->payload + sizeof(ethhdr),dataptr,remainingPayloadSpace);
|
||||
dataptr += remainingPayloadSpace;
|
||||
// Remaining pbufs (if any) get rest of data
|
||||
while ((q = q->next)) {
|
||||
memcpy(q->payload,dataptr,q->len);
|
||||
dataptr += q->len;
|
||||
}
|
||||
// Feed packet into stack
|
||||
int err;
|
||||
|
||||
if (Utils::ntoh(ethhdr.type) == 0x800 || Utils::ntoh(ethhdr.type) == 0x806) {
|
||||
if ((err = ((struct netif *)tap->netif4)->input(p, (struct netif *)tap->netif4)) != ERR_OK) {
|
||||
DEBUG_ERROR("packet input error (%d)", err);
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
if (Utils::ntoh(ethhdr.type) == 0x86DD) {
|
||||
if ((err = ((struct netif *)tap->netif6)->input(p, (struct netif *)tap->netif6)) != ERR_OK) {
|
||||
DEBUG_ERROR("packet input error (%d)", err);
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static void print_netif_info(struct netif *n) {
|
||||
DEBUG_INFO("n=%p, %c%c, %d, o=%p, o6=%p, mc=%x:%x:%x:%x:%x:%x, hwln=%d, st=%p, flgs=%d\n",
|
||||
n,
|
||||
n->name[0],
|
||||
n->name[1],
|
||||
n->mtu,
|
||||
n->output,
|
||||
n->output_ip6,
|
||||
n->hwaddr[0],
|
||||
n->hwaddr[1],
|
||||
n->hwaddr[2],
|
||||
n->hwaddr[3],
|
||||
n->hwaddr[4],
|
||||
n->hwaddr[5],
|
||||
n->hwaddr_len,
|
||||
n->state,
|
||||
n->flags
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
bool _lwip_is_netif_up(void *n)
|
||||
{
|
||||
if (!n) {
|
||||
return false;
|
||||
}
|
||||
LOCK_TCPIP_CORE();
|
||||
bool result = netif_is_up((struct netif*)n);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED)
|
||||
*/
|
||||
#if LWIP_NETIF_REMOVE_CALLBACK
|
||||
static void _netif_remove_callback(struct netif *n)
|
||||
{
|
||||
// Called from core, no need to lock
|
||||
if (!n || !n->state) {
|
||||
return;
|
||||
}
|
||||
VirtualTap *tap = (VirtualTap *)n->state;
|
||||
uint64_t mac = 0;
|
||||
memcpy(&mac, n->hwaddr, n->hwaddr_len);
|
||||
struct zts_netif_details *ifd = new zts_netif_details;
|
||||
ifd->nwid = tap->_nwid;
|
||||
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
|
||||
ifd->mac = lwip_htonl(ifd->mac) >> 16;
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_REMOVED, (void*)ifd);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN)
|
||||
*/
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
static void _netif_link_callback(struct netif *n)
|
||||
{
|
||||
// Called from core, no need to lock
|
||||
if (!n || !n->state) {
|
||||
return;
|
||||
}
|
||||
VirtualTap *tap = (VirtualTap *)n->state;
|
||||
uint64_t mac = 0;
|
||||
memcpy(&mac, n->hwaddr, n->hwaddr_len);
|
||||
if (n->flags & NETIF_FLAG_LINK_UP) {
|
||||
struct zts_netif_details *ifd = new zts_netif_details;
|
||||
ifd->nwid = tap->_nwid;
|
||||
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
|
||||
ifd->mac = lwip_htonl(ifd->mac) >> 16;
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_LINK_UP, (void*)ifd);
|
||||
}
|
||||
if (n->flags & NETIF_FLAG_LINK_UP) {
|
||||
struct zts_netif_details *ifd = new zts_netif_details;
|
||||
ifd->nwid = tap->_nwid;
|
||||
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
|
||||
ifd->mac = lwip_htonl(ifd->mac) >> 16;
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_LINK_DOWN, (void*)ifd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void _lwip_set_callbacks(struct netif *n)
|
||||
{
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
// Not currently used
|
||||
netif_set_status_callback(n, netif_status_callback);
|
||||
#endif
|
||||
#if LWIP_NETIF_REMOVE_CALLBACK
|
||||
netif_set_remove_callback(n, netif_remove_callback);
|
||||
#endif
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
netif_set_link_callback(n, netif_link_callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct zts_netif_details *_lwip_prepare_netif_status_msg(struct netif *n)
|
||||
{
|
||||
if (!n || !n->state) {
|
||||
return NULL;
|
||||
}
|
||||
VirtualTap *tap = (VirtualTap*)(n->state);
|
||||
struct zts_netif_details *ifd = new zts_netif_details;
|
||||
ifd->nwid = tap->_nwid;
|
||||
ifd->mtu = n->mtu;
|
||||
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
|
||||
ifd->mac = htonll(ifd->mac) >> 16;
|
||||
return ifd;
|
||||
}
|
||||
|
||||
static err_t _netif_init4(struct netif *n)
|
||||
{
|
||||
if (!n || !n->state) {
|
||||
return ERR_IF;
|
||||
}
|
||||
// Called from netif code, no need to lock
|
||||
n->hwaddr_len = 6;
|
||||
n->name[0] = '4';
|
||||
n->name[1] = 'a'+netifCount;
|
||||
n->linkoutput = _lwip_eth_tx;
|
||||
n->output = etharp_output;
|
||||
n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU;
|
||||
n->flags = NETIF_FLAG_BROADCAST
|
||||
| NETIF_FLAG_ETHARP
|
||||
| NETIF_FLAG_ETHERNET
|
||||
| NETIF_FLAG_IGMP
|
||||
| NETIF_FLAG_MLD6
|
||||
| NETIF_FLAG_LINK_UP
|
||||
| NETIF_FLAG_UP;
|
||||
n->hwaddr_len = sizeof(n->hwaddr);
|
||||
VirtualTap *tap = (VirtualTap*)(n->state);
|
||||
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t _netif_init6(struct netif *n)
|
||||
{
|
||||
if (!n || !n->state) {
|
||||
return ERR_IF;
|
||||
}
|
||||
n->hwaddr_len = sizeof(n->hwaddr);
|
||||
VirtualTap *tap = (VirtualTap*)(n->state);
|
||||
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
|
||||
// Called from netif code, no need to lock
|
||||
n->hwaddr_len = 6;
|
||||
n->name[0] = '6';
|
||||
n->name[1] = 'a'+netifCount;
|
||||
n->linkoutput = _lwip_eth_tx;
|
||||
n->output_ip6 = ethip6_output;
|
||||
n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU;
|
||||
n->flags = NETIF_FLAG_BROADCAST
|
||||
| NETIF_FLAG_ETHARP
|
||||
| NETIF_FLAG_ETHERNET
|
||||
| NETIF_FLAG_IGMP
|
||||
| NETIF_FLAG_MLD6
|
||||
| NETIF_FLAG_LINK_UP
|
||||
| NETIF_FLAG_UP;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void _lwip_init_interface(void *tapref, const InetAddress &ip)
|
||||
{
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
char macbuf[ZTS_MAC_ADDRSTRLEN];
|
||||
|
||||
VirtualTap *vtap = (VirtualTap*)tapref;
|
||||
struct netif *n = NULL;
|
||||
bool isNewNetif = false;
|
||||
|
||||
if (ip.isV4()) {
|
||||
if (vtap->netif4) {
|
||||
n = (struct netif*)vtap->netif4;
|
||||
}
|
||||
else {
|
||||
n = new struct netif;
|
||||
isNewNetif = true;
|
||||
netifCount++;
|
||||
}
|
||||
char nmbuf[INET6_ADDRSTRLEN];
|
||||
static ip4_addr_t ip4, netmask, gw;
|
||||
IP4_ADDR(&gw,127,0,0,1);
|
||||
ip4.addr = *((u32_t *)ip.rawIpData());
|
||||
netmask.addr = *((u32_t *)ip.netmask().rawIpData());
|
||||
LOCK_TCPIP_CORE();
|
||||
netif_add(n, &ip4, &netmask, &gw, (void*)vtap, _netif_init4, tcpip_input);
|
||||
vtap->netif4 = (void*)n;
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_UP, (void*)_lwip_prepare_netif_status_msg(n));
|
||||
UNLOCK_TCPIP_CORE();
|
||||
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
|
||||
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
|
||||
DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, nm=%s, tap=%p]",n,
|
||||
macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf), vtap);
|
||||
}
|
||||
if (ip.isV6()) {
|
||||
if (vtap->netif6) {
|
||||
n = (struct netif*)vtap->netif6;
|
||||
}
|
||||
else {
|
||||
n = new struct netif;
|
||||
isNewNetif = true;
|
||||
netifCount++;
|
||||
}
|
||||
static ip6_addr_t ip6;
|
||||
memcpy(&(ip6.addr), ip.rawIpData(), sizeof(ip6.addr));
|
||||
LOCK_TCPIP_CORE();
|
||||
if (isNewNetif) {
|
||||
vtap->netif6 = (void*)n;
|
||||
netif_add(n, NULL, NULL, NULL, (void*)vtap, _netif_init6, ethernet_input);
|
||||
n->ip6_autoconfig_enabled = 1;
|
||||
vtap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
|
||||
netif_create_ip6_linklocal_address(n, 1);
|
||||
netif_set_link_up(n);
|
||||
netif_set_up(n);
|
||||
netif_set_default(n);
|
||||
}
|
||||
netif_add_ip6_address(n,&ip6,NULL);
|
||||
n->output_ip6 = ethip6_output;
|
||||
UNLOCK_TCPIP_CORE();
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_UP, (void*)_lwip_prepare_netif_status_msg(n));
|
||||
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
|
||||
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
|
||||
DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, tap=%p]", n,
|
||||
macbuf, ip.toString(ipbuf), vtap);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1,535 +0,0 @@
|
||||
/*
|
||||
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file in the project's root directory.
|
||||
*
|
||||
* Change Date: 2024-01-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2.0 of the Apache License.
|
||||
*/
|
||||
/****/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* lwIP network stack driver
|
||||
*/
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "MAC.hpp"
|
||||
#include "Mutex.hpp"
|
||||
|
||||
#include "netif/ethernet.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "lwip/etharp.h"
|
||||
#include "lwip/tcpip.h"
|
||||
#include "lwip/mem.h"
|
||||
#include "lwip/memp.h"
|
||||
#include "lwip/sys.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/timeouts.h"
|
||||
#include "lwip/stats.h"
|
||||
#include "lwip/ethip6.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/nd6.h"
|
||||
#include "lwip/netifapi.h"
|
||||
|
||||
#ifdef LWIP_STATS
|
||||
#include "lwip/stats.h"
|
||||
#endif
|
||||
|
||||
#include "VirtualTap.hpp"
|
||||
#include "lwipDriver.hpp"
|
||||
#include "ZeroTier.h"
|
||||
#include "Controls.hpp"
|
||||
|
||||
extern void postEvent(uint64_t eventCode, void *arg);
|
||||
extern void postEvent(uint64_t eventCode);
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Length of human-readable MAC address string
|
||||
*/
|
||||
#define ZTS_MAC_ADDRSTRLEN 18
|
||||
|
||||
#ifndef htonll
|
||||
#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32))
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
bool _has_exited = false;
|
||||
int hibernationDelayMultiplier = 1;
|
||||
int netifCount = 0;
|
||||
extern bool _run_lwip_tcpip;
|
||||
Mutex lwip_driver_m;
|
||||
|
||||
void lwip_sleep(long ms)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
Sleep(ms*hibernationDelayMultiplier);
|
||||
#else
|
||||
usleep(ms*1000*hibernationDelayMultiplier);
|
||||
#endif
|
||||
}
|
||||
|
||||
void lwip_hibernate_driver()
|
||||
{
|
||||
hibernationDelayMultiplier = ZTS_HIBERNATION_MULTIPLIER;
|
||||
}
|
||||
|
||||
void lwip_wake_driver()
|
||||
{
|
||||
hibernationDelayMultiplier = 1;
|
||||
}
|
||||
|
||||
// Callback for when the TCPIP thread has been successfully started
|
||||
static void tcpip_init_done(void *arg)
|
||||
{
|
||||
sys_sem_t *sem;
|
||||
sem = (sys_sem_t *)arg;
|
||||
_run_lwip_tcpip = true;
|
||||
postEvent(ZTS_EVENT_STACK_UP);
|
||||
sys_sem_signal(sem);
|
||||
}
|
||||
|
||||
static void main_lwip_driver_loop(void *arg)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
pthread_setname_np(pthread_self(), ZTS_LWIP_DRIVER_THREAD_NAME);
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
pthread_setname_np(ZTS_LWIP_DRIVER_THREAD_NAME);
|
||||
#endif
|
||||
sys_sem_t sem;
|
||||
LWIP_UNUSED_ARG(arg);
|
||||
if (sys_sem_new(&sem, 0) != ERR_OK) {
|
||||
DEBUG_ERROR("failed to create semaphore");
|
||||
}
|
||||
tcpip_init(tcpip_init_done, &sem);
|
||||
sys_sem_wait(&sem);
|
||||
// Main loop
|
||||
while(_run_lwip_tcpip) {
|
||||
lwip_sleep(LWIP_DRIVER_LOOP_INTERVAL);
|
||||
}
|
||||
_has_exited = true;
|
||||
postEvent(ZTS_EVENT_STACK_DOWN);
|
||||
}
|
||||
|
||||
bool lwip_is_up()
|
||||
{
|
||||
Mutex::Lock _l(lwip_driver_m);
|
||||
return _run_lwip_tcpip;
|
||||
}
|
||||
|
||||
bool lwip_has_previously_shutdown()
|
||||
{
|
||||
Mutex::Lock _l(lwip_driver_m);
|
||||
return _has_exited;
|
||||
}
|
||||
|
||||
void lwip_driver_init()
|
||||
{
|
||||
if (lwip_is_up()) {
|
||||
return;
|
||||
}
|
||||
if (lwip_has_previously_shutdown()) {
|
||||
return;
|
||||
}
|
||||
Mutex::Lock _l(lwip_driver_m);
|
||||
#if defined(_WIN32)
|
||||
sys_init(); // Required for win32 init of critical sections
|
||||
#endif
|
||||
sys_thread_new(ZTS_LWIP_DRIVER_THREAD_NAME, main_lwip_driver_loop,
|
||||
NULL, DEFAULT_THREAD_STACKSIZE, DEFAULT_THREAD_PRIO);
|
||||
}
|
||||
|
||||
void lwip_driver_shutdown()
|
||||
{
|
||||
if (lwip_has_previously_shutdown()) {
|
||||
return;
|
||||
}
|
||||
Mutex::Lock _l(lwip_driver_m);
|
||||
// Set flag to stop sending frames into the core
|
||||
_run_lwip_tcpip = false;
|
||||
// Wait until the main lwIP thread has exited
|
||||
while (!_has_exited) { lwip_sleep(LWIP_DRIVER_LOOP_INTERVAL); }
|
||||
/*
|
||||
if (tcpip_shutdown() == ERR_OK) {
|
||||
sys_timeouts_free();
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
void lwip_remove_netif(void *netif)
|
||||
{
|
||||
if (!netif) {
|
||||
return;
|
||||
}
|
||||
struct netif *n = (struct netif*)netif;
|
||||
LOCK_TCPIP_CORE();
|
||||
netif_remove(n);
|
||||
netif_set_down(n);
|
||||
netif_set_link_down(n);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
}
|
||||
|
||||
err_t lwip_eth_tx(struct netif *n, struct pbuf *p)
|
||||
{
|
||||
if (!n) {
|
||||
return ERR_IF;
|
||||
}
|
||||
struct pbuf *q;
|
||||
char buf[ZT_MAX_MTU+32];
|
||||
char *bufptr;
|
||||
int totalLength = 0;
|
||||
|
||||
VirtualTap *tap = (VirtualTap*)n->state;
|
||||
bufptr = buf;
|
||||
for (q = p; q != NULL; q = q->next) {
|
||||
memcpy(bufptr, q->payload, q->len);
|
||||
bufptr += q->len;
|
||||
totalLength += q->len;
|
||||
}
|
||||
struct eth_hdr *ethhdr;
|
||||
ethhdr = (struct eth_hdr *)buf;
|
||||
|
||||
MAC src_mac;
|
||||
MAC dest_mac;
|
||||
src_mac.setTo(ethhdr->src.addr, 6);
|
||||
dest_mac.setTo(ethhdr->dest.addr, 6);
|
||||
|
||||
char *data = buf + sizeof(struct eth_hdr);
|
||||
int len = totalLength - sizeof(struct eth_hdr);
|
||||
int proto = Utils::ntoh((uint16_t)ethhdr->type);
|
||||
tap->_handler(tap->_arg, NULL, tap->_nwid, src_mac, dest_mac, proto, 0, data, len);
|
||||
if (ZT_MSG_TRANSFER == true) {
|
||||
char flagbuf[32];
|
||||
memset(&flagbuf, 0, 32);
|
||||
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16];
|
||||
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ethhdr->dest.addr[0], ethhdr->dest.addr[1], ethhdr->dest.addr[2],
|
||||
ethhdr->dest.addr[3], ethhdr->dest.addr[4], ethhdr->dest.addr[5]);
|
||||
MAC mac;
|
||||
mac.setTo(ethhdr->dest.addr, 6);
|
||||
mac.toAddress(tap->_nwid).toString(nodeBuf);
|
||||
/*
|
||||
DEBUG_TRANS("len=%5d dst=%s [%s TX <-- %s] ethertype=0x%04x %s", totalLength, macBuf, nodeBuf, tap->nodeId().c_str(),
|
||||
Utils::ntoh(ethhdr->type), flagbuf);
|
||||
*/
|
||||
}
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void lwip_eth_rx(VirtualTap *tap, const MAC &from, const MAC &to, unsigned int etherType,
|
||||
const void *data, unsigned int len)
|
||||
{
|
||||
#ifdef LWIP_STATS
|
||||
stats_display();
|
||||
#endif
|
||||
if (!_run_lwip_tcpip) {
|
||||
return;
|
||||
}
|
||||
struct pbuf *p,*q;
|
||||
struct eth_hdr ethhdr;
|
||||
from.copyTo(ethhdr.src.addr, 6);
|
||||
to.copyTo(ethhdr.dest.addr, 6);
|
||||
ethhdr.type = Utils::hton((uint16_t)etherType);
|
||||
|
||||
if (ZT_MSG_TRANSFER == true) {
|
||||
char flagbuf[32];
|
||||
memset(&flagbuf, 0, 32);
|
||||
char macBuf[ZTS_MAC_ADDRSTRLEN], nodeBuf[16];
|
||||
snprintf(macBuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
ethhdr.dest.addr[0], ethhdr.dest.addr[1], ethhdr.dest.addr[2],
|
||||
ethhdr.dest.addr[3], ethhdr.dest.addr[4], ethhdr.dest.addr[5]);
|
||||
MAC mac;
|
||||
mac.setTo(ethhdr.src.addr, 6);
|
||||
mac.toAddress(tap->_nwid).toString(nodeBuf);
|
||||
/*
|
||||
DEBUG_TRANS("len=%5d dst=%s [%s RX --> %s] ethertype=0x%04x %s", len, macBuf, nodeBuf, tap->nodeId().c_str(),
|
||||
Utils::ntoh(ethhdr.type), flagbuf);
|
||||
*/
|
||||
}
|
||||
|
||||
p = pbuf_alloc(PBUF_RAW, (uint16_t)len+sizeof(struct eth_hdr), PBUF_RAM);
|
||||
if (!p) {
|
||||
DEBUG_ERROR("dropped packet: unable to allocate memory for pbuf");
|
||||
return;
|
||||
}
|
||||
// First pbuf gets ethernet header at start
|
||||
q = p;
|
||||
if (q->len < sizeof(ethhdr)) {
|
||||
pbuf_free(p);
|
||||
p = NULL;
|
||||
DEBUG_ERROR("dropped packet: first pbuf smaller than ethernet header");
|
||||
return;
|
||||
}
|
||||
// Copy frame data into pbuf
|
||||
const char *dataptr = reinterpret_cast<const char *>(data);
|
||||
memcpy(q->payload,ðhdr,sizeof(ethhdr));
|
||||
int remainingPayloadSpace = q->len - sizeof(ethhdr);
|
||||
memcpy((char*)q->payload + sizeof(ethhdr),dataptr,remainingPayloadSpace);
|
||||
dataptr += remainingPayloadSpace;
|
||||
// Remaining pbufs (if any) get rest of data
|
||||
while ((q = q->next)) {
|
||||
memcpy(q->payload,dataptr,q->len);
|
||||
dataptr += q->len;
|
||||
}
|
||||
// Feed packet into stack
|
||||
int err;
|
||||
|
||||
if (Utils::ntoh(ethhdr.type) == 0x800 || Utils::ntoh(ethhdr.type) == 0x806) {
|
||||
if ((err = ((struct netif *)tap->netif4)->input(p, (struct netif *)tap->netif4)) != ERR_OK) {
|
||||
DEBUG_ERROR("packet input error (%d)", err);
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
if (Utils::ntoh(ethhdr.type) == 0x86DD) {
|
||||
if ((err = ((struct netif *)tap->netif6)->input(p, (struct netif *)tap->netif6)) != ERR_OK) {
|
||||
DEBUG_ERROR("packet input error (%d)", err);
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
static void print_netif_info(struct netif *n) {
|
||||
DEBUG_INFO("n=%p, %c%c, %d, o=%p, o6=%p, mc=%x:%x:%x:%x:%x:%x, hwln=%d, st=%p, flgs=%d\n",
|
||||
n,
|
||||
n->name[0],
|
||||
n->name[1],
|
||||
n->mtu,
|
||||
n->output,
|
||||
n->output_ip6,
|
||||
n->hwaddr[0],
|
||||
n->hwaddr[1],
|
||||
n->hwaddr[2],
|
||||
n->hwaddr[3],
|
||||
n->hwaddr[4],
|
||||
n->hwaddr[5],
|
||||
n->hwaddr_len,
|
||||
n->state,
|
||||
n->flags
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
bool lwip_is_netif_up(void *n)
|
||||
{
|
||||
if (!n) {
|
||||
return false;
|
||||
}
|
||||
LOCK_TCPIP_CORE();
|
||||
bool result = netif_is_up((struct netif*)n);
|
||||
UNLOCK_TCPIP_CORE();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a netif is removed (ZTS_EVENT_NETIF_INTERFACE_REMOVED)
|
||||
*/
|
||||
#if LWIP_NETIF_REMOVE_CALLBACK
|
||||
static void netif_remove_callback(struct netif *n)
|
||||
{
|
||||
// Called from core, no need to lock
|
||||
if (!n || !n->state) {
|
||||
return;
|
||||
}
|
||||
VirtualTap *tap = (VirtualTap *)n->state;
|
||||
uint64_t mac = 0;
|
||||
memcpy(&mac, n->hwaddr, n->hwaddr_len);
|
||||
struct zts_netif_details *ifd = new zts_netif_details;
|
||||
ifd->nwid = tap->_nwid;
|
||||
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
|
||||
ifd->mac = lwip_htonl(ifd->mac) >> 16;
|
||||
postEvent(ZTS_EVENT_NETIF_REMOVED, (void*)ifd);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Called when a link is brought up or down (ZTS_EVENT_NETIF_LINK_UP, ZTS_EVENT_NETIF_LINK_DOWN)
|
||||
*/
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
static void netif_link_callback(struct netif *n)
|
||||
{
|
||||
// Called from core, no need to lock
|
||||
if (!n || !n->state) {
|
||||
return;
|
||||
}
|
||||
VirtualTap *tap = (VirtualTap *)n->state;
|
||||
uint64_t mac = 0;
|
||||
memcpy(&mac, n->hwaddr, n->hwaddr_len);
|
||||
if (n->flags & NETIF_FLAG_LINK_UP) {
|
||||
struct zts_netif_details *ifd = new zts_netif_details;
|
||||
ifd->nwid = tap->_nwid;
|
||||
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
|
||||
ifd->mac = lwip_htonl(ifd->mac) >> 16;
|
||||
postEvent(ZTS_EVENT_NETIF_LINK_UP, (void*)ifd);
|
||||
}
|
||||
if (n->flags & NETIF_FLAG_LINK_UP) {
|
||||
struct zts_netif_details *ifd = new zts_netif_details;
|
||||
ifd->nwid = tap->_nwid;
|
||||
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
|
||||
ifd->mac = lwip_htonl(ifd->mac) >> 16;
|
||||
postEvent(ZTS_EVENT_NETIF_LINK_DOWN, (void*)ifd);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void lwip_set_callbacks(struct netif *n)
|
||||
{
|
||||
if (!n) {
|
||||
return;
|
||||
}
|
||||
#if LWIP_NETIF_STATUS_CALLBACK
|
||||
// Not currently used
|
||||
netif_set_status_callback(n, netif_status_callback);
|
||||
#endif
|
||||
#if LWIP_NETIF_REMOVE_CALLBACK
|
||||
netif_set_remove_callback(n, netif_remove_callback);
|
||||
#endif
|
||||
#if LWIP_NETIF_LINK_CALLBACK
|
||||
netif_set_link_callback(n, netif_link_callback);
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct zts_netif_details *lwip_prepare_netif_status_msg(struct netif *n)
|
||||
{
|
||||
if (!n || !n->state) {
|
||||
return NULL;
|
||||
}
|
||||
VirtualTap *tap = (VirtualTap*)(n->state);
|
||||
struct zts_netif_details *ifd = new zts_netif_details;
|
||||
ifd->nwid = tap->_nwid;
|
||||
ifd->mtu = n->mtu;
|
||||
memcpy(&(ifd->mac), n->hwaddr, n->hwaddr_len);
|
||||
ifd->mac = htonll(ifd->mac) >> 16;
|
||||
return ifd;
|
||||
}
|
||||
|
||||
static err_t netif_init(struct netif *n)
|
||||
{
|
||||
if (!n || !n->state) {
|
||||
return ERR_IF;
|
||||
}
|
||||
// Called from netif code, no need to lock
|
||||
n->hwaddr_len = 6;
|
||||
n->name[0] = '4';
|
||||
n->name[1] = 'a'+netifCount;
|
||||
n->linkoutput = lwip_eth_tx;
|
||||
n->output = etharp_output;
|
||||
n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU;
|
||||
n->flags = NETIF_FLAG_BROADCAST
|
||||
| NETIF_FLAG_ETHARP
|
||||
| NETIF_FLAG_ETHERNET
|
||||
| NETIF_FLAG_IGMP
|
||||
| NETIF_FLAG_MLD6
|
||||
| NETIF_FLAG_LINK_UP
|
||||
| NETIF_FLAG_UP;
|
||||
n->hwaddr_len = sizeof(n->hwaddr);
|
||||
VirtualTap *tap = (VirtualTap*)(n->state);
|
||||
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
static err_t netif_init6(struct netif *n)
|
||||
{
|
||||
if (!n || !n->state) {
|
||||
return ERR_IF;
|
||||
}
|
||||
n->hwaddr_len = sizeof(n->hwaddr);
|
||||
VirtualTap *tap = (VirtualTap*)(n->state);
|
||||
tap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
|
||||
// Called from netif code, no need to lock
|
||||
n->hwaddr_len = 6;
|
||||
n->name[0] = '6';
|
||||
n->name[1] = 'a'+netifCount;
|
||||
n->linkoutput = lwip_eth_tx;
|
||||
n->output_ip6 = ethip6_output;
|
||||
n->mtu = LWIP_MTU < ZT_MAX_MTU ? LWIP_MTU : ZT_MAX_MTU;
|
||||
n->flags = NETIF_FLAG_BROADCAST
|
||||
| NETIF_FLAG_ETHARP
|
||||
| NETIF_FLAG_ETHERNET
|
||||
| NETIF_FLAG_IGMP
|
||||
| NETIF_FLAG_MLD6
|
||||
| NETIF_FLAG_LINK_UP
|
||||
| NETIF_FLAG_UP;
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
void lwip_init_interface(void *tapref, const InetAddress &ip)
|
||||
{
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
char macbuf[ZTS_MAC_ADDRSTRLEN];
|
||||
|
||||
VirtualTap *vtap = (VirtualTap*)tapref;
|
||||
struct netif *n = NULL;
|
||||
bool isNewNetif = false;
|
||||
|
||||
if (ip.isV4()) {
|
||||
if (vtap->netif4) {
|
||||
n = (struct netif*)vtap->netif4;
|
||||
}
|
||||
else {
|
||||
n = new struct netif;
|
||||
isNewNetif = true;
|
||||
netifCount++;
|
||||
}
|
||||
char nmbuf[INET6_ADDRSTRLEN];
|
||||
static ip4_addr_t ip4, netmask, gw;
|
||||
IP4_ADDR(&gw,127,0,0,1);
|
||||
ip4.addr = *((u32_t *)ip.rawIpData());
|
||||
netmask.addr = *((u32_t *)ip.netmask().rawIpData());
|
||||
LOCK_TCPIP_CORE();
|
||||
netif_add(n, &ip4, &netmask, &gw, (void*)vtap, netif_init, tcpip_input);
|
||||
vtap->netif4 = (void*)n;
|
||||
postEvent(ZTS_EVENT_NETIF_UP, (void*)lwip_prepare_netif_status_msg(n));
|
||||
UNLOCK_TCPIP_CORE();
|
||||
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
|
||||
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
|
||||
DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, nm=%s, tap=%p]",n,
|
||||
macbuf, ip.toString(ipbuf), ip.netmask().toString(nmbuf), vtap);
|
||||
}
|
||||
if (ip.isV6()) {
|
||||
if (vtap->netif6) {
|
||||
n = (struct netif*)vtap->netif6;
|
||||
}
|
||||
else {
|
||||
n = new struct netif;
|
||||
isNewNetif = true;
|
||||
netifCount++;
|
||||
}
|
||||
static ip6_addr_t ip6;
|
||||
memcpy(&(ip6.addr), ip.rawIpData(), sizeof(ip6.addr));
|
||||
LOCK_TCPIP_CORE();
|
||||
if (isNewNetif) {
|
||||
vtap->netif6 = (void*)n;
|
||||
netif_add(n, NULL, NULL, NULL, (void*)vtap, netif_init6, ethernet_input);
|
||||
n->ip6_autoconfig_enabled = 1;
|
||||
vtap->_mac.copyTo(n->hwaddr, n->hwaddr_len);
|
||||
netif_create_ip6_linklocal_address(n, 1);
|
||||
netif_set_link_up(n);
|
||||
netif_set_up(n);
|
||||
netif_set_default(n);
|
||||
}
|
||||
netif_add_ip6_address(n,&ip6,NULL);
|
||||
n->output_ip6 = ethip6_output;
|
||||
UNLOCK_TCPIP_CORE();
|
||||
postEvent(ZTS_EVENT_NETIF_UP, (void*)lwip_prepare_netif_status_msg(n));
|
||||
snprintf(macbuf, ZTS_MAC_ADDRSTRLEN, "%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
n->hwaddr[0], n->hwaddr[1], n->hwaddr[2],
|
||||
n->hwaddr[3], n->hwaddr[4], n->hwaddr[5]);
|
||||
DEBUG_INFO("initialized netif=%p as [mac=%s, addr=%s, tap=%p]", n,
|
||||
macbuf, ip.toString(ipbuf), vtap);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user