You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
248 lines
6.4 KiB
248 lines
6.4 KiB
/* |
|
* 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 "Constants.hpp" |
|
#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_UPDATE |
|
#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_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->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 (STACK_EVENT_TYPE(eventCode)) { |
|
/* nothing to convey to user */ |
|
} 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 (PEER_EVENT_TYPE(eventCode)) { |
|
msg->peer = (struct zts_peer_details*)arg; |
|
} if (ADDR_EVENT_TYPE(eventCode)) { |
|
msg->addr = (struct zts_addr_details*)arg; |
|
} |
|
|
|
if (msg && _callbackMsgQueue.size_approx() > 1024) { |
|
// Rate-limit number of events |
|
_freeEvent(msg); |
|
} |
|
else { |
|
_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->peer) { delete msg->peer; } |
|
if (msg->addr) { delete msg->addr; } |
|
} |
|
|
|
void _passDequeuedEventToUser(struct zts_callback_msg *msg) |
|
{ |
|
bool bShouldStopCallbackThread = (msg->eventCode == ZTS_EVENT_STACK_DOWN); |
|
#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 |
|
if (bShouldStopCallbackThread) { |
|
/* Ensure last possible callback ZTS_EVENT_STACK_DOWN is |
|
delivered before callback thread is finally stopped. */ |
|
_clrState(ZTS_STATE_CALLBACKS_RUNNING); |
|
} |
|
} |
|
|
|
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
|
|
|