Expand C API and simplify NodeService
This commit is contained in:
158
CMakeLists.txt
158
CMakeLists.txt
@@ -2,9 +2,9 @@ cmake_minimum_required(VERSION 3.0)
|
||||
project(zt)
|
||||
find_package(Threads)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | PLATFORM DETECTION |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Apple
|
||||
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
@@ -42,9 +42,9 @@ endif()
|
||||
# Linux
|
||||
# if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | SOURCE DIRECTORIES |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
set(PROJ_DIR ${PROJECT_SOURCE_DIR})
|
||||
set(LWIP_SRC_DIR "${PROJ_DIR}/ext/lwip/src")
|
||||
@@ -62,9 +62,9 @@ if(BUILD_WIN)
|
||||
set(LWIP_PORT_DIR ${PROJ_DIR}/ext/lwip-contrib/ports/win32)
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | INCLUDE DIRECTORIES |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ZeroTier
|
||||
include_directories(${ZTO_SRC_DIR})
|
||||
@@ -82,9 +82,9 @@ include_directories(${PROJ_DIR}/ext/concurrentqueue)
|
||||
include_directories(${LWIP_SRC_DIR}/include)
|
||||
include_directories(${LWIP_PORT_DIR}/include)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | TARGET AND VARIANT SELECTION |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# Defaults
|
||||
set(ALLOW_INSTALL_TARGET TRUE)
|
||||
@@ -143,7 +143,6 @@ if(BUILD_HOST)
|
||||
set(ALLOW_INSTALL_TARGET TRUE)
|
||||
set(BUILD_HOST_SELFTEST FALSE)
|
||||
set(ZTS_ENABLE_STATS TRUE)
|
||||
set(ZTS_ENABLE_CENTRAL_API FALSE)
|
||||
endif()
|
||||
|
||||
# CI
|
||||
@@ -172,7 +171,6 @@ if(BUILD_MACOS_FRAMEWORK)
|
||||
set(BUILD_HOST_SELFTEST FALSE)
|
||||
set(BUILD_EXAMPLES FALSE)
|
||||
set(ALLOW_INSTALL_TARGET FALSE)
|
||||
set(ZTS_ENABLE_CENTRAL_API FALSE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOMIT_JSON_SUPPORT=1")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DOMIT_JSON_SUPPORT=1")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_ARCHS "$(ARCHS_STANDARD)")
|
||||
@@ -187,7 +185,6 @@ if(BUILD_IOS_FRAMEWORK)
|
||||
set(BUILD_HOST_SELFTEST FALSE)
|
||||
set(BUILD_EXAMPLES FALSE)
|
||||
set(ALLOW_INSTALL_TARGET FALSE)
|
||||
set(ZTS_ENABLE_CENTRAL_API FALSE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOMIT_JSON_SUPPORT=1")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DOMIT_JSON_SUPPORT=1")
|
||||
set(DEVROOT
|
||||
@@ -209,13 +206,12 @@ if(BUILD_IOS_FRAMEWORK)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | TESTING (and) FEATURE FLAGS |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(BUILD_HOST_SELFTEST)
|
||||
set(ZTS_ENABLE_STATS TRUE)
|
||||
set(ZTS_ENABLE_CENTRAL_API TRUE)
|
||||
endif()
|
||||
|
||||
# Enable specific features (eventually these will be enabled by default)
|
||||
@@ -223,13 +219,13 @@ if(ZTS_ENABLE_STATS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZTS_ENABLE_STATS=1")
|
||||
endif()
|
||||
|
||||
if(ZTS_ENABLE_CENTRAL_API)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZTS_ENABLE_CENTRAL_API=1")
|
||||
if(ZTS_DISABLE_CENTRAL_API)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZTS_DISABLE_CENTRAL_API=1")
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | HACKS TO GET THIS TO WORK ON WINDOWS |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(BUILD_WIN)
|
||||
# Possibly a CMake limitation? -- Can't share target output names
|
||||
@@ -244,9 +240,9 @@ else()
|
||||
set(DYNAMIC_LIB_OUTPUT_NAME ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | BUILD TYPES |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "debug")
|
||||
set(BUILD_DEBUG ON)
|
||||
@@ -261,57 +257,67 @@ if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "release")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wno-everything -w")
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------------------
|
||||
# | EXAMPLES |
|
||||
# -----------------------------------------------------------------------------
|
||||
# -------------------------------------------------------------------------------
|
||||
|
||||
if(BUILD_HOST_EXAMPLES)
|
||||
add_executable(nonblockingclient
|
||||
${PROJ_DIR}/examples/cpp/nonblockingclient.cpp)
|
||||
target_link_libraries(nonblockingclient ${STATIC_LIB_NAME})
|
||||
add_executable(pingable-node
|
||||
${PROJ_DIR}/examples/c/pingable-node.c)
|
||||
target_link_libraries(pingable-node ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(nonblockingserver
|
||||
${PROJ_DIR}/examples/cpp/nonblockingserver.cpp)
|
||||
target_link_libraries(nonblockingserver ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(earthtest
|
||||
${PROJ_DIR}/examples/cpp/earthtest.cpp)
|
||||
target_link_libraries(earthtest ${STATIC_LIB_NAME})
|
||||
add_executable(statistics
|
||||
${PROJ_DIR}/examples/c/statistics.c)
|
||||
target_link_libraries(statistics ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(adhoc
|
||||
${PROJ_DIR}/examples/cpp/adhoc.cpp)
|
||||
${PROJ_DIR}/examples/c/adhoc.c)
|
||||
target_link_libraries(adhoc ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(comprehensive
|
||||
${PROJ_DIR}/examples/cpp/comprehensive.cpp)
|
||||
target_link_libraries(comprehensive ${STATIC_LIB_NAME})
|
||||
add_executable(centralapi
|
||||
${PROJ_DIR}/examples/c/centralapi.cpp)
|
||||
target_link_libraries(centralapi ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(callbackapi
|
||||
${PROJ_DIR}/examples/c/callbackapi.c)
|
||||
target_link_libraries(callbackapi ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(nostorage
|
||||
${PROJ_DIR}/examples/c/nostorage.c)
|
||||
target_link_libraries(nostorage ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(client
|
||||
${PROJ_DIR}/examples/cpp/client.cpp)
|
||||
${PROJ_DIR}/examples/c/client.c)
|
||||
target_link_libraries(client ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(server
|
||||
${PROJ_DIR}/examples/cpp/server.cpp)
|
||||
${PROJ_DIR}/examples/c/server.c)
|
||||
target_link_libraries(server ${STATIC_LIB_NAME})
|
||||
|
||||
add_executable(keymanagement
|
||||
${PROJ_DIR}/examples/cpp/keymanagement.cpp)
|
||||
target_link_libraries(keymanagement ${STATIC_LIB_NAME})
|
||||
add_executable(nonblockingclient
|
||||
${PROJ_DIR}/examples/c/nonblockingclient.c)
|
||||
target_link_libraries(nonblockingclient ${STATIC_LIB_NAME})
|
||||
|
||||
if(ZTS_ENABLE_CENTRAL_API)
|
||||
add_executable(centralapi ${PROJ_DIR}/examples/cpp/centralapi.cpp)
|
||||
target_link_libraries(centralapi ${STATIC_LIB_NAME})
|
||||
endif()
|
||||
add_executable(nonblockingserver
|
||||
${PROJ_DIR}/examples/c/nonblockingserver.c)
|
||||
target_link_libraries(nonblockingserver ${STATIC_LIB_NAME})
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | FLAGS |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
set(SILENCE "-Wno-missing-field-initializers \
|
||||
-Wno-macro-redefined \
|
||||
-Wno-tautological-overlap-compare \
|
||||
-Wno-unused-function \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-macro-redefined \
|
||||
-Wno-tautological-constant-out-of-range-compare \
|
||||
-Wno-parentheses-equality")
|
||||
|
||||
set(ZT_FLAGS "${ZT_FLAGS} -DZT_USE_MINIUPNPC=1")
|
||||
set(ZT_FLAGS "${ZT_FLAGS} -DZT_SOFTWARE_UPDATE_DEFAULT=0")
|
||||
set(ZT_FLAGS "${ZT_FLAGS} -D_USING_LWIP_DEFINITIONS_=0")
|
||||
set(ZT_FLAGS "${ZT_FLAGS} -DZT_SDK=1")
|
||||
|
||||
if(BUILD_DEBUG)
|
||||
set(LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_DBG_TYPES_ON=128")
|
||||
@@ -389,15 +395,14 @@ if(BUILD_WIN)
|
||||
message(STATUS "WS2_32=${ws2_32_LIBRARY_PATH}")
|
||||
message(STATUS "ShLwApi=${shlwapi_LIBRARY_PATH}")
|
||||
message(STATUS "liphlpapi=${iphlpapi_LIBRARY_PATH}")
|
||||
add_definitions(-DZT_SDK=1)
|
||||
add_definitions(-DADD_EXPORTS=1)
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | OPTIONAL FEATURES |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(ZTS_ENABLE_CENTRAL_API)
|
||||
if(NOT ZTS_DISABLE_CENTRAL_API)
|
||||
set(requiredlibs)
|
||||
find_package(CURL)
|
||||
if(CURL_FOUND)
|
||||
@@ -409,9 +414,9 @@ if(ZTS_ENABLE_CENTRAL_API)
|
||||
endif(CURL_FOUND)
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | JNI |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(ZTS_ENABLE_JAVA OR BUILD_ANDROID)
|
||||
message(STATUS "Looking for JNI")
|
||||
@@ -454,13 +459,12 @@ if(ZTS_ENABLE_JAVA OR BUILD_ANDROID)
|
||||
endif()
|
||||
endif() # ZTS_ENABLE_JAVA
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | SOURCES |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
file(GLOB ztcoreSrcGlob ${ZTO_SRC_DIR}/node/*.cpp
|
||||
${ZTO_SRC_DIR}/osdep/OSUtils.cpp ${ZTO_SRC_DIR}/osdep/PortMapper.cpp
|
||||
${ZTO_SRC_DIR}/osdep/ManagedRoute.cpp)
|
||||
${ZTO_SRC_DIR}/osdep/OSUtils.cpp ${ZTO_SRC_DIR}/osdep/PortMapper.cpp)
|
||||
|
||||
file(GLOB libnatpmpSrcGlob ${ZTO_SRC_DIR}/ext/libnatpmp/natpmp.c
|
||||
${ZTO_SRC_DIR}/ext/libnatpmp/wingettimeofday.c
|
||||
@@ -504,9 +508,9 @@ file(GLOB frameworkPublicHeaderGlob include/ZeroTierSockets.h)
|
||||
file(GLOB frameworkHeaderGlob ${frameworkPublicHeaderGlob}
|
||||
${frameworkPrivateHeaderGlob})
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | OBJECT LIBRARIES (INTERMEDIATE) |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(BUILD_STATIC_LIB)
|
||||
# zto_obj
|
||||
@@ -596,9 +600,9 @@ set_target_properties(zt_pic PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}"
|
||||
# PROPERTY STATIC_LIBRARY_FLAGS "-no_warning_for_no_symbols"
|
||||
#)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | STATIC LIB |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(BUILD_STATIC_LIB)
|
||||
# libztcore.a
|
||||
@@ -625,7 +629,7 @@ if(BUILD_STATIC_LIB)
|
||||
target_link_libraries(${STATIC_LIB_NAME} ${ws2_32_LIBRARY_PATH}
|
||||
${shlwapi_LIBRARY_PATH} ${iphlpapi_LIBRARY_PATH})
|
||||
endif()
|
||||
if(ZTS_ENABLE_CENTRAL_API)
|
||||
if(NOT ZTS_DISABLE_CENTRAL_API)
|
||||
target_link_libraries(${STATIC_LIB_NAME} ${CURL_LIBRARIES})
|
||||
endif()
|
||||
endif() # BUILD_STATIC_LIB
|
||||
@@ -634,9 +638,9 @@ endif() # BUILD_STATIC_LIB
|
||||
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | SHARED LIB |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(BUILD_SHARED_LIB)
|
||||
# libzt.so/dylib/dll
|
||||
@@ -661,17 +665,12 @@ if(BUILD_SHARED_LIB)
|
||||
zto_pic
|
||||
natpmp_pic
|
||||
miniupnpc_pic)
|
||||
|
||||
if(ZTS_ENABLE_CENTRAL_API)
|
||||
target_link_libraries(${DYNAMIC_LIB_NAME} ${CURL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
if(BUILD_ANDROID)
|
||||
target_link_libraries(${DYNAMIC_LIB_NAME} android log)
|
||||
endif()
|
||||
if(ZTS_ENABLE_CENTRAL_API)
|
||||
if(NOT ZTS_DISABLE_CENTRAL_API)
|
||||
target_link_libraries(${DYNAMIC_LIB_NAME} ${CURL_LIBRARIES})
|
||||
endif()
|
||||
endif() # BUILD_SHARED_LIB
|
||||
@@ -715,21 +714,22 @@ if(IN_XCODE)
|
||||
XCODE_ATTRIBUTE_CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES YES)
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | SELFTEST |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if(BUILD_HOST_SELFTEST)
|
||||
add_executable(selftest-c-api ${PROJ_DIR}/test/selftest-c-api.c)
|
||||
target_link_libraries(selftest-c-api ${STATIC_LIB_NAME})
|
||||
add_executable(selftest-c
|
||||
${PROJ_DIR}/test/selftest.c)
|
||||
target_link_libraries(selftest-c ${STATIC_LIB_NAME})
|
||||
project(TEST)
|
||||
enable_testing()
|
||||
add_test(NAME selftest-c-api COMMAND selftest-c-api)
|
||||
add_test(NAME selftest-c COMMAND selftest-c)
|
||||
endif()
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
# | INSTALL |
|
||||
# -----------------------------------------------------------------------------
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
if (ALLOW_INSTALL_TARGET)
|
||||
set(PUBLIC_ZT_HEADERS ${PROJECT_SOURCE_DIR}/include/ZeroTierSockets.h)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div align="center">
|
||||
|
||||
<h1>ZeroTier SDK</h1>
|
||||
<img alt="zts_socket()" src="https://i.imgur.com/BwSHwE3.png"> </img>
|
||||
<img alt="zts_socket()" src="https://i.imgur.com/BwSHwE3.png" class="doxyhidden"> </img>
|
||||
|
||||
Peer-to-peer and cross-platform encrypted connections built right into your app or service. No drivers, no root, and no host configuration.
|
||||
|
||||
|
||||
97
examples/c/adhoc.c
Normal file
97
examples/c/adhoc.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Pingable node joined to controller-less adhoc network with a 6PLANE addressing scheme
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
|
||||
Ad-hoc Network:
|
||||
|
||||
ffSSSSEEEE000000
|
||||
| | | |
|
||||
| | | Reserved for future use, must be 0
|
||||
| | End of port range (hex)
|
||||
| Start of port range (hex)
|
||||
Reserved ZeroTier address prefix indicating a controller-less network.
|
||||
|
||||
Ad-hoc networks are public (no access control) networks that have no network controller. Instead
|
||||
their configuration and other credentials are generated locally. Ad-hoc networks permit only IPv6
|
||||
UDP and TCP unicast traffic (no multicast or broadcast) using 6plane format NDP-emulated IPv6
|
||||
addresses. In addition an ad-hoc network ID encodes an IP port range. UDP packets and TCP SYN
|
||||
(connection open) packets are only allowed to destination ports within the encoded range.
|
||||
|
||||
For example ff00160016000000 is an ad-hoc network allowing only SSH, while ff0000ffff000000 is an
|
||||
ad-hoc network allowing any UDP or TCP port.
|
||||
|
||||
Keep in mind that these networks are public and anyone in the entire world can join them. Care must
|
||||
be taken to avoid exposing vulnerable services or sharing unwanted files or other resources.
|
||||
|
||||
*/
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 3) {
|
||||
printf("\nUsage:\n");
|
||||
printf("adhoc <adhocStartPort> <adhocEndPort>\n");
|
||||
exit(0);
|
||||
}
|
||||
int err = ZTS_ERR_OK;
|
||||
|
||||
uint16_t adhocStartPort = atoi(argv[1]); // Start of port range your application will use
|
||||
uint16_t adhocEndPort = atoi(argv[2]); // End of port range your application will use
|
||||
uint64_t net_id = zts_net_compute_adhoc_id(adhocStartPort, adhocEndPort);
|
||||
|
||||
// Start node and get identity
|
||||
|
||||
printf("Starting node...\n");
|
||||
zts_node_start();
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
uint64_t node_id = zts_node_get_id();
|
||||
printf("My public identity (node ID) is %llx\n", node_id);
|
||||
char keypair[ZTS_ID_STR_BUF_LEN] = { 0 };
|
||||
uint16_t len = ZTS_ID_STR_BUF_LEN;
|
||||
if (zts_node_get_id_pair(keypair, &len) != ZTS_ERR_OK) {
|
||||
printf("Error getting identity keypair. Exiting.\n");
|
||||
}
|
||||
printf("Identity [public/secret pair] = %s\n", keypair);
|
||||
|
||||
// Join the adhoc network
|
||||
|
||||
printf("Joining network %llx\n", net_id);
|
||||
if (zts_net_join(net_id) != ZTS_ERR_OK) {
|
||||
printf("Unable to join network. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("Waiting for join to complete\n");
|
||||
while (zts_net_count() < 1) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
// Get address
|
||||
|
||||
char ipstr[ZTS_IP_MAX_STR_LEN] = { 0 };
|
||||
if ((err = zts_addr_compute_rfc4193_str(net_id, node_id, ipstr, ZTS_IP_MAX_STR_LEN))
|
||||
!= ZTS_ERR_OK) {
|
||||
printf("Unable to compute address (error = %d). Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
printf("Join %llx from another machine and ping6 me at %s\n", net_id, ipstr);
|
||||
|
||||
// Do network stuff!
|
||||
// zts_socket, zts_connect, etc
|
||||
|
||||
while (1) {
|
||||
zts_util_delay(500); // Idle indefinitely
|
||||
}
|
||||
|
||||
printf("Stopping node\n");
|
||||
return zts_node_stop();
|
||||
}
|
||||
113
examples/c/callbackapi.c
Normal file
113
examples/c/callbackapi.c
Normal file
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Pingable node that demonstrates basic usage of the callback API. To see
|
||||
* more exhaustive examples look at test/selftest.c
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void on_zts_event(void* msgPtr)
|
||||
{
|
||||
zts_event_msg_t* msg = (zts_event_msg_t*)msgPtr;
|
||||
// Node events
|
||||
if (msg->event_code == ZTS_EVENT_NODE_ONLINE) {
|
||||
printf("ZTS_EVENT_NODE_ONLINE --- This node's ID is %llx\n", msg->node->node_id);
|
||||
}
|
||||
if (msg->event_code == ZTS_EVENT_NODE_OFFLINE) {
|
||||
printf("ZTS_EVENT_NODE_OFFLINE --- Check your physical Internet connection, router, "
|
||||
"firewall, etc. What ports are you blocking?\n");
|
||||
}
|
||||
// Virtual network events
|
||||
if (msg->event_code == ZTS_EVENT_NETWORK_NOT_FOUND) {
|
||||
printf(
|
||||
"ZTS_EVENT_NETWORK_NOT_FOUND --- Are you sure %llx is a valid network?\n",
|
||||
msg->network->net_id);
|
||||
}
|
||||
if (msg->event_code == ZTS_EVENT_NETWORK_ACCESS_DENIED) {
|
||||
printf(
|
||||
"ZTS_EVENT_NETWORK_ACCESS_DENIED --- Access to virtual network %llx has been denied. "
|
||||
"Did you authorize the node yet?\n",
|
||||
msg->network->net_id);
|
||||
}
|
||||
if (msg->event_code == ZTS_EVENT_NETWORK_READY_IP6) {
|
||||
printf(
|
||||
"ZTS_EVENT_NETWORK_READY_IP6 --- Network config received. IPv6 traffic can now be sent "
|
||||
"over network %llx\n",
|
||||
msg->network->net_id);
|
||||
}
|
||||
// Address events
|
||||
if (msg->event_code == ZTS_EVENT_ADDR_ADDED_IP6) {
|
||||
char ipstr[ZTS_INET6_ADDRSTRLEN] = { 0 };
|
||||
struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)&(msg->addr->addr);
|
||||
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ipstr, ZTS_INET6_ADDRSTRLEN);
|
||||
printf(
|
||||
"ZTS_EVENT_ADDR_NEW_IP6 --- Join %llx and ping me at %s\n",
|
||||
msg->addr->net_id,
|
||||
ipstr);
|
||||
}
|
||||
|
||||
// To see more exhaustive examples look at test/selftest.c
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
printf("\nUsage:\n");
|
||||
printf("pingable-node <net_id>\n");
|
||||
exit(0);
|
||||
}
|
||||
uint64_t net_id = strtoull(argv[1], NULL, 16);
|
||||
|
||||
zts_init_set_event_handler(&on_zts_event);
|
||||
|
||||
printf("Starting node...\n");
|
||||
zts_node_start();
|
||||
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("My public identity (node ID) is %llx\n", zts_node_get_id());
|
||||
char keypair[ZTS_ID_STR_BUF_LEN] = { 0 };
|
||||
uint16_t len = ZTS_ID_STR_BUF_LEN;
|
||||
if (zts_node_get_id_pair(keypair, &len) != ZTS_ERR_OK) {
|
||||
printf("Error getting identity keypair. Exiting.\n");
|
||||
}
|
||||
printf("Identity [public/secret pair] = %s\n", keypair);
|
||||
|
||||
printf("Joining network %llx\n", net_id);
|
||||
if (zts_net_join(net_id) != ZTS_ERR_OK) {
|
||||
printf("Unable to join network. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Waiting for join to complete\n");
|
||||
while (zts_net_count() < 1) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("Waiting for address assignment from network\n");
|
||||
int err = 0;
|
||||
while (! (err = zts_addr_is_assigned(net_id, ZTS_AF_INET))) {
|
||||
zts_util_delay(500);
|
||||
}
|
||||
|
||||
char ipstr[ZTS_IP_MAX_STR_LEN] = { 0 };
|
||||
zts_addr_get_str(net_id, ZTS_AF_INET, ipstr, ZTS_IP_MAX_STR_LEN);
|
||||
printf("Join %llx from another machine and ping me at %s\n", net_id, ipstr);
|
||||
|
||||
// Do network stuff!
|
||||
// zts_socket, zts_connect, etc
|
||||
|
||||
while (1) {
|
||||
zts_util_delay(500); // Idle indefinitely
|
||||
}
|
||||
|
||||
printf("Stopping node\n");
|
||||
return zts_node_stop();
|
||||
}
|
||||
109
examples/c/centralapi.cpp
Normal file
109
examples/c/centralapi.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
// For optional JSON parsing
|
||||
#include "../ext/ZeroTierOne/ext/json/json.hpp"
|
||||
|
||||
void process_response(char* response, int http_resp_code)
|
||||
{
|
||||
if (http_resp_code == 0) {
|
||||
// Request failed at library level, do nothing. There would be no HTTP code at this point.
|
||||
return;
|
||||
}
|
||||
printf("Raw response string (%d) = %s\n", http_resp_code, response);
|
||||
// Parse into navigable JSON object
|
||||
if (http_resp_code < 200 || http_resp_code >= 300) {
|
||||
return;
|
||||
}
|
||||
nlohmann::json res = nlohmann::json::parse(response);
|
||||
if (! res.is_object()) {
|
||||
fprintf(stderr, "Unable to parse (root element is not a JSON object)");
|
||||
}
|
||||
// Pretty print JSON blob
|
||||
std::cout << std::setw(4) << res << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 3) {
|
||||
printf("\nlibzt example central API client\n");
|
||||
printf("centralapi <central_url> <api_token>\n");
|
||||
exit(0);
|
||||
}
|
||||
char* central_url = argv[1]; // API endpoint
|
||||
char* api_token = argv[2]; // User token (generate at my.zerotier.com)
|
||||
|
||||
/**
|
||||
* This example demonstrates how to use the ZeroTier Central API to:
|
||||
*
|
||||
* - Get the status of our hosted service (or your own)
|
||||
* - Create a network
|
||||
* - Get the full configuration of a network
|
||||
* - Authorize/Deauthorize nodes on a network
|
||||
*
|
||||
* This example does not start a node (though you can if you wish.) This portion of the
|
||||
* libzt API is merely a wrapper around our web API endpoint (https://my.zerotier.com/help/api).
|
||||
* The HTTP requests are done via libcurl. This API is thread-safe but not multi-threaded.
|
||||
*
|
||||
* Error Codes:
|
||||
* -2 : [ZTS_ERR_SERVICE] The API may not have been initialized properly
|
||||
* -3 : [ZTS_ERR_ARG] Invalid argument
|
||||
* [100-500] : Standard HTTP error codes
|
||||
*
|
||||
* Usage example: centralapi https://my.zerotier.com e7no7nVRFItge7no7cVR5Ibge7no8nV1
|
||||
*
|
||||
*/
|
||||
|
||||
int err = ZTS_ERR_OK;
|
||||
// Buffer to store server response as JSON string blobs
|
||||
char rbuf[ZTS_CENTRAL_RESP_BUF_DEFAULT_SZ] = { 0 };
|
||||
|
||||
// Provide URL to Central API server and user API token generated at https://my.zerotier.com
|
||||
printf("Initializing Central API client...\n");
|
||||
if ((err = zts_central_init(central_url, api_token, rbuf, ZTS_CENTRAL_RESP_BUF_DEFAULT_SZ))
|
||||
!= ZTS_ERR_OK) {
|
||||
fprintf(stderr, "Error while initializing client's Central API parameters\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
zts_central_set_verbose(false); // (optional) Turn on reporting from libcurl
|
||||
zts_central_set_access_mode(ZTS_CENTRAL_READ /*| ZTS_CENTRAL_WRITE*/);
|
||||
|
||||
int http_res_code = 0;
|
||||
|
||||
// Get hosted service status
|
||||
printf("Requesting Central API server status (/api/status):\n");
|
||||
if ((err = zts_central_status_get(&http_res_code)) != ZTS_ERR_OK) {
|
||||
fprintf(stderr, "Error (%d) making the request.\n", err);
|
||||
}
|
||||
else {
|
||||
process_response(rbuf, http_res_code);
|
||||
}
|
||||
// Get network config
|
||||
int64_t nwid = 0x1234567890abcdef;
|
||||
printf("Requesting network config: /api/network/%llx\n", nwid);
|
||||
if ((err = zts_central_net_get(&http_res_code, nwid)) != ZTS_ERR_OK) {
|
||||
fprintf(stderr, "Error (%d) making the request.\n", err);
|
||||
}
|
||||
else {
|
||||
process_response(rbuf, http_res_code);
|
||||
}
|
||||
// Authorize a node on a network
|
||||
int64_t nodeid = 0x9934343434;
|
||||
printf("Authorizing: /api/network/%llx/member/%llx\n", nwid, nodeid);
|
||||
if ((err = zts_central_node_auth(&http_res_code, nwid, nodeid, ZTS_CENTRAL_NODE_AUTH_TRUE))
|
||||
!= ZTS_ERR_OK) {
|
||||
fprintf(stderr, "Error (%d) making the request.\n", err);
|
||||
}
|
||||
else {
|
||||
process_response(rbuf, http_res_code);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
105
examples/c/client.c
Normal file
105
examples/c/client.c
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Simple socket-based client application
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 5) {
|
||||
printf("\nlibzt example client\n");
|
||||
printf("client <id_storage_path> <net_id> <remote_addr> <remote_port>\n");
|
||||
exit(0);
|
||||
}
|
||||
char* storage_path = argv[1];
|
||||
uint64_t net_id = strtoull(argv[2], NULL, 16);
|
||||
char* remote_addr = argv[3];
|
||||
int remote_port = atoi(argv[4]);
|
||||
int err = ZTS_ERR_OK;
|
||||
|
||||
// Initialize node
|
||||
|
||||
if ((err = zts_init_from_storage(storage_path)) != ZTS_ERR_OK) {
|
||||
printf("Unable to start service, error = %d. Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Start node
|
||||
|
||||
if ((err = zts_node_start()) != ZTS_ERR_OK) {
|
||||
printf("Unable to start service, error = %d. Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
printf("Public identity (node ID) is %llx\n", zts_node_get_id());
|
||||
|
||||
// Join network
|
||||
|
||||
printf("Joining network %llx\n", net_id);
|
||||
if (zts_net_join(net_id) != ZTS_ERR_OK) {
|
||||
printf("Unable to join network. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
|
||||
printf("Waiting for join to complete\n");
|
||||
while (zts_net_count() < 1) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
// Get assigned address (of the family type we care about)
|
||||
|
||||
int family = zts_util_get_ip_family(remote_addr);
|
||||
|
||||
printf("Waiting for address assignment from network\n");
|
||||
while (! (err = zts_addr_is_assigned(net_id, family))) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
char ipstr[ZTS_IP_MAX_STR_LEN] = { 0 };
|
||||
zts_addr_get_str(net_id, family, ipstr, ZTS_IP_MAX_STR_LEN);
|
||||
printf("IP address on network %llx is %s\n", net_id, ipstr);
|
||||
|
||||
// BEGIN Socket Stuff
|
||||
|
||||
char* msgStr = (char*)"Welcome to the machine";
|
||||
int bytes = 0, fd;
|
||||
char recvBuf[128] = { 0 };
|
||||
memset(recvBuf, 0, sizeof(recvBuf));
|
||||
|
||||
// Connect to remote host
|
||||
|
||||
// Can also use traditional: zts_socket(), zts_connect(), etc
|
||||
|
||||
printf("Attempting to connect...\n");
|
||||
while ((fd = zts_simple_tcp_client(remote_addr, remote_port)) < 0) {
|
||||
printf("Re-attempting to connect...\n");
|
||||
}
|
||||
|
||||
// Data I/O
|
||||
|
||||
printf("Sending message string to server...\n");
|
||||
if ((bytes = zts_write(fd, msgStr, strlen(msgStr))) < 0) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
printf("Sent %d bytes: %s\n", bytes, msgStr);
|
||||
printf("Reading message string from server...\n");
|
||||
if ((bytes = zts_read(fd, recvBuf, sizeof(recvBuf))) < 0) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
printf("Read %d bytes: %s\n", bytes, recvBuf);
|
||||
|
||||
// Close
|
||||
|
||||
zts_close(fd);
|
||||
return zts_node_stop();
|
||||
}
|
||||
96
examples/c/nonblockingclient.c
Normal file
96
examples/c/nonblockingclient.c
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Simple socket-based client application
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 5) {
|
||||
printf("\nlibzt example client\n");
|
||||
printf("client <id_storage_path> <net_id> <remote_addr> <remote_port>\n");
|
||||
exit(0);
|
||||
}
|
||||
char* storage_path = argv[1];
|
||||
uint64_t net_id = strtoull(argv[2], NULL, 16);
|
||||
char* remote_addr = argv[3];
|
||||
int remote_port = atoi(argv[4]);
|
||||
int err = ZTS_ERR_OK;
|
||||
|
||||
// Initialize node
|
||||
|
||||
if ((err = zts_init_from_storage(storage_path)) != ZTS_ERR_OK) {
|
||||
printf("Unable to start service, error = %d. Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Start node
|
||||
|
||||
if ((err = zts_node_start()) != ZTS_ERR_OK) {
|
||||
printf("Unable to start service, error = %d. Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("Public identity (node ID) is %llx\n", zts_node_get_id());
|
||||
|
||||
printf("Joining network %llx\n", net_id);
|
||||
if (zts_net_join(net_id) != ZTS_ERR_OK) {
|
||||
printf("Unable to join network. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
|
||||
printf("Waiting for join to complete\n");
|
||||
while (zts_net_count() < 1) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
// Sockets
|
||||
|
||||
char* msgStr = (char*)"Welcome to the machine";
|
||||
int bytes = 0, fd;
|
||||
char recvBuf[128] = { 0 };
|
||||
memset(recvBuf, 0, sizeof(recvBuf));
|
||||
|
||||
// Create socket
|
||||
|
||||
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
|
||||
printf("Error (fd=%d, zts_errno=%d). Exiting.\n", fd, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Connect
|
||||
|
||||
// Can also use:
|
||||
// zts_connect(int fd, const struct zts_sockaddr* addr, zts_socklen_t addrlen);
|
||||
while (zts_simple_connect(fd, remote_addr, remote_port, 0) != ZTS_ERR_OK) {
|
||||
printf("Attempting to connect...\n");
|
||||
}
|
||||
|
||||
// Data I/O
|
||||
|
||||
// Wait random intervals to send a message to the server
|
||||
// The non-blocking aspect of this example is server-side
|
||||
while (1) {
|
||||
if ((bytes = zts_send(fd, msgStr, strlen(msgStr), 0)) < 0) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
printf("zts_send()=%d\n", bytes);
|
||||
zts_util_delay((rand() % 100) * 50);
|
||||
}
|
||||
|
||||
zts_close(fd);
|
||||
return zts_node_stop();
|
||||
}
|
||||
169
examples/c/nonblockingserver.c
Normal file
169
examples/c/nonblockingserver.c
Normal file
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Simple socket-based server application
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 5) {
|
||||
printf("\nlibzt example server\n");
|
||||
printf("server <id_storage_path> <net_id> <local_addr> <local_port>\n");
|
||||
exit(0);
|
||||
}
|
||||
char* storage_path = argv[1];
|
||||
uint64_t net_id = strtoull(argv[2], NULL, 16);
|
||||
char* local_addr = argv[3];
|
||||
int local_port = atoi(argv[4]);
|
||||
int fd, accfd;
|
||||
int err = ZTS_ERR_OK;
|
||||
|
||||
// Initialize node
|
||||
|
||||
if ((err = zts_init_from_storage(storage_path)) != ZTS_ERR_OK) {
|
||||
printf("Unable to start service, error = %d. Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Start node
|
||||
|
||||
if ((err = zts_node_start()) != ZTS_ERR_OK) {
|
||||
printf("Unable to start service, error = %d. Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("Public identity (node ID) is %llx\n", zts_node_get_id());
|
||||
|
||||
printf("Joining network %llx\n", net_id);
|
||||
if (zts_net_join(net_id) != ZTS_ERR_OK) {
|
||||
printf("Unable to join network. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
|
||||
printf("Waiting for join to complete\n");
|
||||
while (zts_net_count() < 1) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("Waiting for address assignment from network\n");
|
||||
while (! (err = zts_addr_is_assigned(net_id, ZTS_AF_INET))) {
|
||||
zts_util_delay(500);
|
||||
}
|
||||
|
||||
char ipstr[ZTS_IP_MAX_STR_LEN] = { 0 };
|
||||
zts_addr_get_str(net_id, ZTS_AF_INET, ipstr, ZTS_IP_MAX_STR_LEN);
|
||||
printf("Assigned IP address: %s\n", ipstr);
|
||||
|
||||
// Sockets
|
||||
|
||||
printf("Creating socket...\n");
|
||||
if ((fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0)) < 0) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
printf("Binding...\n");
|
||||
// Can also use:
|
||||
// zts_bind(int fd, const struct zts_sockaddr* addr, zts_socklen_t addrlen)
|
||||
if ((err = zts_simple_bind(fd, local_addr, local_port) < 0)) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
printf("Listening...\n");
|
||||
int backlog = 100;
|
||||
if ((err = zts_listen(fd, backlog)) < 0) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int bytes = 0;
|
||||
char recvBuf[128] = { 0 };
|
||||
|
||||
while (1) {
|
||||
// Accept
|
||||
// Can also use
|
||||
// zts_accept(int fd, struct zts_sockaddr* addr, zts_socklen_t* addrlen)
|
||||
|
||||
char ipstr[ZTS_INET6_ADDRSTRLEN] = { 0 };
|
||||
int port = 0;
|
||||
printf("Accepting on listening socket...\n");
|
||||
if ((accfd = zts_simple_accept(fd, ipstr, ZTS_INET6_ADDRSTRLEN, &port)) < 0) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, err, zts_errno);
|
||||
}
|
||||
printf("Accepted connection from %s:%d\n", ipstr, port);
|
||||
}
|
||||
|
||||
// Data I/O
|
||||
|
||||
// Technique 1: ZTS_O_NONBLOCK
|
||||
if (0) {
|
||||
zts_fcntl(fd, ZTS_F_SETFL, ZTS_O_NONBLOCK);
|
||||
zts_fcntl(accfd, ZTS_F_SETFL, ZTS_O_NONBLOCK);
|
||||
while (1) {
|
||||
bytes = zts_recv(accfd, recvBuf, sizeof(recvBuf), 0);
|
||||
printf("zts_recv(%d, ...)=%d\n", accfd, bytes);
|
||||
zts_util_delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
// Technique 2: zts_select
|
||||
if (0) {
|
||||
struct zts_timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 50000;
|
||||
int result = 0;
|
||||
zts_fd_set active_fd_set, read_fd_set;
|
||||
ZTS_FD_ZERO(&active_fd_set);
|
||||
ZTS_FD_SET(accfd, &active_fd_set);
|
||||
while (1) {
|
||||
read_fd_set = active_fd_set;
|
||||
if ((result = zts_select(ZTS_FD_SETSIZE, &read_fd_set, NULL, NULL, &tv) < 0)) {
|
||||
// perror ("select");
|
||||
exit(1);
|
||||
}
|
||||
for (int i = 0; i < ZTS_FD_SETSIZE; i++) {
|
||||
if (ZTS_FD_ISSET(i, &read_fd_set)) {
|
||||
bytes = zts_recv(accfd, recvBuf, sizeof(recvBuf), 0);
|
||||
printf("zts_recv(%d, ...)=%d\n", i, bytes);
|
||||
}
|
||||
// ZTS_FD_CLR(i, &active_fd_set);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Technique 3: zts_poll
|
||||
if (1) {
|
||||
int numfds = 0;
|
||||
struct zts_pollfd poll_set[16];
|
||||
memset(poll_set, '\0', sizeof(poll_set));
|
||||
poll_set[0].fd = accfd;
|
||||
poll_set[0].events = ZTS_POLLIN;
|
||||
numfds++;
|
||||
int result = 0;
|
||||
int timeout_ms = 50;
|
||||
while (1) {
|
||||
result = zts_poll(poll_set, numfds, timeout_ms);
|
||||
printf("zts_poll()=%d\n", result);
|
||||
for (int i = 0; i < numfds; i++) {
|
||||
if (poll_set[i].revents & ZTS_POLLIN) {
|
||||
bytes = zts_recv(poll_set[i].fd, recvBuf, sizeof(recvBuf), 0);
|
||||
printf("zts_recv(%d, ...)=%d\n", i, bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
err = zts_close(fd);
|
||||
return zts_node_stop();
|
||||
}
|
||||
109
examples/c/nostorage.c
Normal file
109
examples/c/nostorage.c
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Demonstrates how to manage ZeroTier node identities (public/secret keypairs) without
|
||||
* local storage (e.g. zts_init_from_storage().)
|
||||
*
|
||||
* WARNING: This prints secret keys to your terminal.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char cache_data[ZTS_STORE_DATA_LEN];
|
||||
|
||||
void on_zts_event(void* msgPtr)
|
||||
{
|
||||
zts_event_msg_t* msg = (zts_event_msg_t*)msgPtr;
|
||||
int len = msg->len; // Length of message (or structure)
|
||||
|
||||
if (msg->event_code == ZTS_EVENT_NODE_ONLINE) {
|
||||
printf("ZTS_EVENT_NODE_ONLINE\n");
|
||||
}
|
||||
|
||||
// Copy data to a buffer that you have allocated or write it to storage.
|
||||
// The data pointed to by msg->cache will be invalid after this function
|
||||
// returns.
|
||||
|
||||
memset(cache_data, 0, ZTS_STORE_DATA_LEN);
|
||||
|
||||
if (msg->event_code == ZTS_EVENT_STORE_IDENTITY_PUBLIC) {
|
||||
printf("ZTS_EVENT_STORE_IDENTITY_PUBLIC (len=%d)\n", msg->len);
|
||||
printf("identity.public = [ %.*s ]\n", len, msg->cache);
|
||||
memcpy(cache_data, msg->cache, len);
|
||||
}
|
||||
if (msg->event_code == ZTS_EVENT_STORE_IDENTITY_SECRET) {
|
||||
printf("ZTS_EVENT_STORE_IDENTITY_SECRET (len=%d)\n", msg->len);
|
||||
printf("identity.secret = [ %.*s ]\n", len, msg->cache);
|
||||
memcpy(cache_data, msg->cache, len);
|
||||
// Same data can be retrieved via: zts_node_get_id_pair()
|
||||
}
|
||||
if (msg->event_code == ZTS_EVENT_STORE_PLANET) {
|
||||
printf("ZTS_EVENT_STORE_PLANET (len=%d)\n", msg->len);
|
||||
// Binary data
|
||||
memcpy(cache_data, msg->cache, len);
|
||||
}
|
||||
if (msg->event_code == ZTS_EVENT_STORE_PEER) {
|
||||
printf("ZTS_EVENT_STORE_PEER (len=%d)\n", msg->len);
|
||||
// Binary data
|
||||
memcpy(cache_data, msg->cache, len);
|
||||
}
|
||||
if (msg->event_code == ZTS_EVENT_STORE_NETWORK) {
|
||||
printf("ZTS_EVENT_STORE_NETWORK (len=%d)\n", msg->len);
|
||||
// Binary data
|
||||
memcpy(cache_data, msg->cache, len);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
int err = ZTS_ERR_OK;
|
||||
|
||||
// Initialize node
|
||||
|
||||
zts_init_set_event_handler(&on_zts_event);
|
||||
|
||||
// Start node
|
||||
|
||||
printf("Starting node...\n");
|
||||
int generate_new_id = 1;
|
||||
if (generate_new_id) {
|
||||
// OPTION A
|
||||
// Generate new automatically ID if no prior init called
|
||||
zts_node_start();
|
||||
}
|
||||
else {
|
||||
// OPTION B
|
||||
// Copy your key here
|
||||
char identity[ZTS_ID_STR_BUF_LEN] = { 0 };
|
||||
int len = ZTS_ID_STR_BUF_LEN;
|
||||
|
||||
// Generate key (optional):
|
||||
// int key_len;
|
||||
// zts_id_new(identity, &key_len);
|
||||
|
||||
// Load pre-existing identity from buffer
|
||||
zts_init_from_memory(identity, len);
|
||||
zts_node_start();
|
||||
}
|
||||
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
// Do network stuff!
|
||||
// zts_socket, zts_connect, etc
|
||||
|
||||
printf("Node %llx is now online. Idling.\n", zts_node_get_id());
|
||||
while (1) {
|
||||
zts_util_delay(500); // Idle indefinitely
|
||||
}
|
||||
|
||||
printf("Stopping node\n");
|
||||
return zts_node_stop();
|
||||
}
|
||||
67
examples/c/pingable-node.c
Normal file
67
examples/c/pingable-node.c
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Pingable node
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
printf("\nUsage:\n");
|
||||
printf("pingable-node <net_id>\n");
|
||||
exit(0);
|
||||
}
|
||||
uint64_t net_id = strtoull(argv[1], NULL, 16);
|
||||
|
||||
printf("Starting node...\n");
|
||||
zts_node_start();
|
||||
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("My public identity (node ID) is %llx\n", zts_node_get_id());
|
||||
char keypair[ZTS_ID_STR_BUF_LEN] = { 0 };
|
||||
uint16_t len = ZTS_ID_STR_BUF_LEN;
|
||||
if (zts_node_get_id_pair(keypair, &len) != ZTS_ERR_OK) {
|
||||
printf("Error getting identity keypair. Exiting.\n");
|
||||
}
|
||||
printf("Identity [public/secret pair] = %s\n", keypair);
|
||||
|
||||
printf("Joining network %llx\n", net_id);
|
||||
if (zts_net_join(net_id) != ZTS_ERR_OK) {
|
||||
printf("Unable to join network. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Waiting for join to complete\n");
|
||||
while (zts_net_count() < 1) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("Waiting for address assignment from network\n");
|
||||
int err = 0;
|
||||
while (! (err = zts_addr_is_assigned(net_id, ZTS_AF_INET))) {
|
||||
zts_util_delay(500);
|
||||
}
|
||||
|
||||
char ipstr[ZTS_IP_MAX_STR_LEN] = { 0 };
|
||||
zts_addr_get_str(net_id, ZTS_AF_INET, ipstr, ZTS_IP_MAX_STR_LEN);
|
||||
printf("Join %llx from another machine and ping me at %s\n", net_id, ipstr);
|
||||
|
||||
// Do network stuff!
|
||||
// zts_socket, zts_connect, etc
|
||||
|
||||
while (1) {
|
||||
zts_util_delay(500); // Idle indefinitely
|
||||
}
|
||||
|
||||
printf("Stopping node\n");
|
||||
return zts_node_stop();
|
||||
}
|
||||
111
examples/c/server.c
Normal file
111
examples/c/server.c
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Simple socket-based server application
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 5) {
|
||||
printf("\nlibzt example server\n");
|
||||
printf("server <id_storage_path> <net_id> <local_addr> <local_port>\n");
|
||||
exit(0);
|
||||
}
|
||||
char* storage_path = argv[1];
|
||||
uint64_t net_id = strtoull(argv[2], NULL, 16);
|
||||
char* local_addr = argv[3];
|
||||
int local_port = atoi(argv[4]);
|
||||
int fd, accfd;
|
||||
int err = ZTS_ERR_OK;
|
||||
|
||||
// Initialize node
|
||||
|
||||
if ((err = zts_init_from_storage(storage_path)) != ZTS_ERR_OK) {
|
||||
printf("Unable to start service, error = %d. Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Start node
|
||||
|
||||
if ((err = zts_node_start()) != ZTS_ERR_OK) {
|
||||
printf("Unable to start service, error = %d. Exiting.\n", err);
|
||||
exit(1);
|
||||
}
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
printf("Public identity (node ID) is %llx\n", zts_node_get_id());
|
||||
|
||||
// Join network
|
||||
|
||||
printf("Joining network %llx\n", net_id);
|
||||
if (zts_net_join(net_id) != ZTS_ERR_OK) {
|
||||
printf("Unable to join network. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
printf("Don't forget to authorize this device in my.zerotier.com or the web API!\n");
|
||||
printf("Waiting for join to complete\n");
|
||||
while (zts_net_count() < 1) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
// Get assigned address (of the family type we care about)
|
||||
|
||||
int family = zts_util_get_ip_family(local_addr);
|
||||
|
||||
printf("Waiting for address assignment from network\n");
|
||||
while (! (err = zts_addr_is_assigned(net_id, family))) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
char ipstr[ZTS_IP_MAX_STR_LEN] = { 0 };
|
||||
zts_addr_get_str(net_id, family, ipstr, ZTS_IP_MAX_STR_LEN);
|
||||
printf("IP address on network %llx is %s\n", net_id, ipstr);
|
||||
|
||||
// BEGIN Socket Stuff
|
||||
|
||||
// Accept incoming connection
|
||||
|
||||
// Can also use traditional: zts_socket(), zts_bind(), zts_listen(), zts_accept(), etc.
|
||||
|
||||
char remote_addr[ZTS_INET6_ADDRSTRLEN] = { 0 };
|
||||
int remote_port = 0;
|
||||
int len = ZTS_INET6_ADDRSTRLEN;
|
||||
if ((accfd = zts_simple_tcp_server(local_addr, local_port, remote_addr, len, &remote_port))
|
||||
< 0) {
|
||||
printf("Error (fd=%d, zts_errno=%d). Exiting.\n", accfd, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
printf("Accepted connection from %s:%d\n", remote_addr, remote_port);
|
||||
|
||||
// Data I/O
|
||||
|
||||
int bytes = 0;
|
||||
char recvBuf[128] = { 0 };
|
||||
|
||||
printf("Reading message string from client...\n");
|
||||
if ((bytes = zts_read(accfd, recvBuf, sizeof(recvBuf))) < 0) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
printf("Read %d bytes: %s\n", bytes, recvBuf);
|
||||
printf("Sending message string to client...\n");
|
||||
if ((bytes = zts_write(accfd, recvBuf, bytes)) < 0) {
|
||||
printf("Error (fd=%d, ret=%d, zts_errno=%d). Exiting.\n", fd, bytes, zts_errno);
|
||||
exit(1);
|
||||
}
|
||||
printf("Sent %d bytes: %s\n", bytes, recvBuf);
|
||||
|
||||
// Close
|
||||
|
||||
printf("Closing connection socket\n");
|
||||
err = zts_close(accfd);
|
||||
err = zts_close(fd);
|
||||
return zts_node_stop();
|
||||
}
|
||||
130
examples/c/statistics.c
Normal file
130
examples/c/statistics.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* libzt C API example
|
||||
*
|
||||
* Pingable node that also displays protocol statistics that are
|
||||
* useful for debugging.
|
||||
*/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
if (argc != 2) {
|
||||
printf("\nUsage:\n");
|
||||
printf("pingable-node <net_id>\n");
|
||||
exit(0);
|
||||
}
|
||||
uint64_t net_id = strtoull(argv[1], NULL, 16);
|
||||
|
||||
printf("Starting node...\n");
|
||||
zts_node_start();
|
||||
|
||||
printf("Waiting for node to come online\n");
|
||||
while (! zts_node_is_online()) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("My public identity (node ID) is %llx\n", zts_node_get_id());
|
||||
char keypair[ZTS_ID_STR_BUF_LEN] = { 0 };
|
||||
uint16_t len = ZTS_ID_STR_BUF_LEN;
|
||||
if (zts_node_get_id_pair(keypair, &len) != ZTS_ERR_OK) {
|
||||
printf("Error getting identity keypair. Exiting.\n");
|
||||
}
|
||||
printf("Identity [public/secret pair] = %s\n", keypair);
|
||||
|
||||
printf("Joining network %llx\n", net_id);
|
||||
if (zts_net_join(net_id) != ZTS_ERR_OK) {
|
||||
printf("Unable to join network. Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Waiting for join to complete\n");
|
||||
while (zts_net_count() < 1) {
|
||||
zts_util_delay(50);
|
||||
}
|
||||
|
||||
printf("Waiting for address assignment from network\n");
|
||||
int err = 0;
|
||||
while (! (err = zts_addr_is_assigned(net_id, ZTS_AF_INET))) {
|
||||
zts_util_delay(500);
|
||||
}
|
||||
|
||||
char ipstr[ZTS_IP_MAX_STR_LEN] = { 0 };
|
||||
zts_addr_get_str(net_id, ZTS_AF_INET, ipstr, ZTS_IP_MAX_STR_LEN);
|
||||
printf("Join %llx from another machine and ping me at %s\n", net_id, ipstr);
|
||||
|
||||
// Do network stuff!
|
||||
// zts_socket, zts_connect, etc
|
||||
|
||||
// Show protocol statistics
|
||||
|
||||
zts_stats_counter_t s = { 0 };
|
||||
|
||||
while (1) {
|
||||
zts_util_delay(1000);
|
||||
if ((err = zts_stats_get_all(&s)) == ZTS_ERR_NO_RESULT) {
|
||||
printf("no results\n");
|
||||
continue;
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
printf(
|
||||
" link_tx=%9d, link_rx=%9d, link_drop=%9d, link_err=%9d\n",
|
||||
s.link_tx,
|
||||
s.link_rx,
|
||||
s.link_drop,
|
||||
s.link_err);
|
||||
printf(
|
||||
"etharp_tx=%9d, etharp_rx=%9d, etharp_drop=%9d, etharp_err=%9d\n",
|
||||
s.etharp_tx,
|
||||
s.etharp_rx,
|
||||
s.etharp_drop,
|
||||
s.etharp_err);
|
||||
printf(
|
||||
" ip4_tx=%9d, ip4_rx=%9d, ip4_drop=%9d, ip4_err=%9d\n",
|
||||
s.ip4_tx,
|
||||
s.ip4_rx,
|
||||
s.ip4_drop,
|
||||
s.ip4_err);
|
||||
printf(
|
||||
" ip6_tx=%9d, ip6_rx=%9d, ip6_drop=%9d, ip6_err=%9d\n",
|
||||
s.ip6_tx,
|
||||
s.ip6_rx,
|
||||
s.ip6_drop,
|
||||
s.ip6_err);
|
||||
printf(
|
||||
" icmp4_tx=%9d, icmp4_rx=%9d, icmp4_drop=%9d, icmp4_err=%9d\n",
|
||||
s.icmp4_tx,
|
||||
s.icmp4_rx,
|
||||
s.icmp4_drop,
|
||||
s.icmp4_err);
|
||||
printf(
|
||||
" icmp6_tx=%9d, icmp6_rx=%9d, icmp6_drop=%9d, icmp6_err=%9d\n",
|
||||
s.icmp6_tx,
|
||||
s.icmp6_rx,
|
||||
s.icmp6_drop,
|
||||
s.icmp6_err);
|
||||
printf(
|
||||
" udp_tx=%9d, udp_rx=%9d, udp_drop=%9d, udp_err=%9d\n",
|
||||
s.udp_tx,
|
||||
s.udp_rx,
|
||||
s.udp_drop,
|
||||
s.udp_err);
|
||||
printf(
|
||||
" tcp_tx=%9d, tcp_rx=%9d, tcp_drop=%9d, tcp_err=%9d\n",
|
||||
s.tcp_tx,
|
||||
s.tcp_rx,
|
||||
s.tcp_drop,
|
||||
s.tcp_err);
|
||||
printf(
|
||||
" nd6_tx=%9d, nd6_rx=%9d, nd6_drop=%9d, nd6_err=%9d\n",
|
||||
s.nd6_tx,
|
||||
s.nd6_rx,
|
||||
s.nd6_drop,
|
||||
s.nd6_err);
|
||||
}
|
||||
return zts_node_stop();
|
||||
}
|
||||
@@ -1,427 +0,0 @@
|
||||
C API Documentation
|
||||
=====
|
||||
This is the externally facing plain C API. All language bindings interface with this. It provides a uniform socket interface across all supported platforms.
|
||||
|
||||
---
|
||||
|
||||
### Table of Contents ###
|
||||
|
||||
- [Starting ZeroTier](#starting-zerotier)
|
||||
- [Joining a Network](#joining-a-network)
|
||||
- [Connecting to peers](#connecting-to-peers)
|
||||
- [Event Handling](#event-handling)
|
||||
- [Node Events](#node-events)
|
||||
- [Network Events](#network-events)
|
||||
- [Peer Events](#peer-events)
|
||||
- [Address Events](#address-events)
|
||||
- [Error Handling](#error-handling)
|
||||
- [Common pitfalls](#common-pitfalls)
|
||||
- [API compatibility with host OS](#api-compatibility-with-host-os)
|
||||
- [Thread Model](#thread-model)
|
||||
- [Debugging](#debugging)
|
||||
|
||||
# Starting ZeroTier
|
||||
|
||||
The next few sections explain how to use the network control interface portion of the API. These functions are non-blocking and will return an error code specified in the [Error Handling](#error-handling) section and will result in the generation of callback events detailed in the [Event Handling](#event-handling) section. It is your responsibility to handle these events.
|
||||
|
||||
To start the service, simply call:
|
||||
|
||||
```c
|
||||
zts_start(const char *path, void (*callback)(void *), uint16_t port);
|
||||
zts_callback_msg*), int port)`
|
||||
```
|
||||
|
||||
At this stage, if a cryptographic identity for this node does not already exist on your local storage medium, it will generate a new one and store it, the node's address (commonly referred to as `nodeId`) will be derived from this identity and will be presented to you upon receiving the `ZTS_EVENT_NODE_ONLINE` shown below. The first argument `path` is a path where you will direct ZeroTier to store its automatically-generated cryptographic identity files (`identity.public` and `identity.secret`), these files are your keys to communicating on the network. Keep them safe and keep them unique. If any two nodes are online using the same identities you will have a bad time. The second argument `userCallbackFunc` is a function that you specify to handle all generated events for the life of your program, see below:
|
||||
|
||||
```c
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
...
|
||||
|
||||
bool networkReady = false;
|
||||
|
||||
void on_zts_event(struct zts_callback_msg *msg)
|
||||
{
|
||||
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
|
||||
printf("ZTS_EVENT_NODE_ONLINE, nodeId=%llx\n", msg->node->address);
|
||||
networkReady = true;
|
||||
}
|
||||
...
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
zts_start("configPath", &on_zts_event, 9994);
|
||||
uint64_t nwid = 0x0123456789abcdef;
|
||||
while (!networkReady) { sleep(1); }
|
||||
zts_join(nwid);
|
||||
int fd = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
|
||||
...
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
For more complete examples see `./examples/`
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
After calling `zts_start()` you will receive one or more events specified in the [Node Events](#node-events) section. After receiving `ZTS_EVENT_NODE_ONLINE` you will be allowed to join or leave networks. You must authorize the node ID provided by the this callback event to join your network. This can be done manually or via our [Web API](https://my.zerotier.com/help/api). Note however that if you are using an Ad-hoc network, it has no controller and therefore requires no authorization.
|
||||
|
||||
At the end of your program or when no more network activity is anticipated, the user application can shut down the service with `zts_stop()`. However, it is safe to leave the service running in the background indefinitely as it doesn't consume much memory or CPU while at idle. `zts_stop()` is a non-blocking call and will itself issue a series of events indicating that various aspects of the ZeroTier service have successfully shut down.
|
||||
|
||||
It is worth noting that while `zts_stop()` will stop the service, the user-space network stack will continue operating in a headless hibernation mode. This is intended behavior due to the fact that the network stack we've chosen doesn't currently support the notion of shutdown since it was initially designed for embedded applications that are simply switched off. If you do need a way to shut everything down and free all resources you can call `zts_free()`, but please note that calling this function will prevent all subsequent `zts_start()` calls from succeeding and will require a full application restart if you want to run the service again. The events `ZTS_EVENT_NODE_ONLINE` and `ZTS_EVENT_NODE_OFFLINE` can be seen periodically throughout the lifetime of your application depending on the reliability of your underlying network link, these events are lagging indicators and are typically only triggered every thirty (30) seconds.
|
||||
|
||||
Lastly, the function `zts_restart()` is provided as a way to restart the ZeroTier service along with all of its virtual interfaces. The network stack will remain online and undisturbed during this call. Note that this call will temporarily block until the service has fully shut down, then will return and you may then watch for the appropriate startup callbacks mentioned above.
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# Joining a network
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Joining a ZeroTier virtual network is as easy as calling `zts_join(uint64_t networkId)`. Similarly there is a `zts_leave(uint64_t networkId)`. Note that `zts_start()` must be called and a `ZTS_EVENT_NODE_ONLINE` event must have been received before these calls will succeed. After calling `zts_join()` any one of the events detailed in the [Network Events](#network-events) section may be generated.
|
||||
|
||||
# Connecting to peers
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Creating a standard socket connection generally works the same as it would using an ordinary socket interface, however with ZeroTier there is a subtle difference in how connections are established which may cause confusion. Since ZeroTier employs transport-triggered link provisioning a direct connection between peers will not exist until contact has been attempted by at least one peer. During this time before a direct link is available traffic will be handled via our free relay service. The provisioning of this direct link usually only takes a couple of seconds but it is important to understand that if you attempt something like s `zts_connect(...)` call during this time it may fail due to packet loss. Therefore it is advised to repeatedly call `zts_connect(...)` until it succeeds and to wait to send additional traffic until `ZTS_EVENT_PEER_DIRECT` has been received for the peer you are attempting to communicate with. All of the above is optional, but it will improve your experience.
|
||||
|
||||
`tl;dr: Try a few times and wait a few seconds`
|
||||
|
||||
As a mitigation for the above behavior, ZeroTier will by default cache details about how to contact a peer in the `peers.d` subdirectory of the config path you passed to `zts_start(...)`. In scenarios where paths do not often change, this can almost completely eliminate the issue and will make connections nearly instantaneous. If however you do not wish to cache these details you can disable it via `zts_set_peer_caching(false)`.
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# Event handling
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
As mentioned in previous sections, the control API works by use of non-blocking calls and the generation of a few dozen different event types. Depending on the type of event there may be additional contextual information attached to the `zts_callback_msg` object that you can use. This contextual information will be housed in one of the following structures which are defined in `include/ZeroTierSockets.h`:
|
||||
|
||||
```c
|
||||
struct zts_callback_msg
|
||||
{
|
||||
int eventCode;
|
||||
struct zts_node_details *node;
|
||||
struct zts_network_details *network;
|
||||
struct zts_netif_details *netif;
|
||||
struct zts_virtual_network_route *route;
|
||||
struct zts_peer_details *peer;
|
||||
struct zts_addr_details *addr;
|
||||
};
|
||||
```
|
||||
|
||||
Here's an example of a callback function:
|
||||
|
||||
```c
|
||||
void on_zts_event(struct zts_callback_msg *msg)
|
||||
{
|
||||
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
|
||||
printf("ZTS_EVENT_NODE_ONLINE, node=%llx\n", msg->node->address);
|
||||
// You can join networks now!
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this callback function you can perform additional non-blocking API calls or other work. While not returning control to the service isn't forbidden (the event messages are generated by a separate thread) it is recommended that you return control as soon as possible as not returning will prevent the user application from receiving additional callback event messages which may be time-sensitive.
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
A typical ordering of messages may look like the following:
|
||||
|
||||
```c
|
||||
...
|
||||
ZTS_EVENT_NODE_ONLINE // Your node is ready to be used.
|
||||
ZTS_EVENT_ADDR_ADDED_IP4 // Your node received an IP address assignment on a given network.
|
||||
ZTS_EVENT_NETWORK_UPDATE // Something about a network changed.
|
||||
ZTS_EVENT_NETWORK_READY_IP4 // Your node has joined a network, has an address, and can send/receive traffic.
|
||||
ZTS_EVENT_PEER_RELAY // A peer was discovered but no direct path exists (yet.)
|
||||
...
|
||||
ZTS_EVENT_PEER_DIRECT // One or more direct paths to a peer were discovered.
|
||||
```
|
||||
|
||||
## Node Events
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Accessible via `msg->node` as a `zts_node_details` object, this message type will contain information about the status of your node. *Possible values of `msg->eventCode`:*
|
||||
|
||||
```c
|
||||
ZTS_EVENT_NODE_OFFLINE // Your node is offline.
|
||||
ZTS_EVENT_NODE_ONLINE // Your node is online and ready to communicate!
|
||||
ZTS_EVENT_NODE_DOWN // The node is down (for any reason.)
|
||||
ZTS_EVENT_NODE_IDENTITY_COLLISION // There is another node with the same identity causing a conflict.
|
||||
ZTS_EVENT_NODE_UNRECOVERABLE_ERROR // Something went wrong internally.
|
||||
ZTS_EVENT_NODE_NORMAL_TERMINATION // Your node has terminated.
|
||||
```
|
||||
|
||||
*Example contents of `msg->node`:*
|
||||
|
||||
```
|
||||
id : f746d550dd
|
||||
version : 1.4.6
|
||||
primaryPort : 9995
|
||||
secondaryPort : 0
|
||||
```
|
||||
|
||||
## Network Events
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Accessible via `msg->network` as a `zts_network_details` object, this message type will contain information about the status of a particular network your node has joined. *Possible values of `msg->eventCode`:*
|
||||
|
||||
```c
|
||||
ZTS_EVENT_NETWORK_NOT_FOUND // The network does not exist. The provided networkID may be incorrect.
|
||||
ZTS_EVENT_NETWORK_CLIENT_TOO_OLD // This client is too old.
|
||||
ZTS_EVENT_NETWORK_REQ_CONFIG // Waiting for network config, this might take a few seconds.
|
||||
ZTS_EVENT_NETWORK_OK // Node successfully joined.
|
||||
ZTS_EVENT_NETWORK_ACCESS_DENIED // The network is private. Your node requires authorization.
|
||||
ZTS_EVENT_NETWORK_READY_IP4 // Your node successfully received an IPv4 address.
|
||||
ZTS_EVENT_NETWORK_READY_IP6 // Your node successfully received an IPv6 address.
|
||||
ZTS_EVENT_NETWORK_DOWN // For some reason the network is no longer available.
|
||||
ZTS_EVENT_NETWORK_UPDATE // The network's config has changed: mtu, name, managed route, etc.
|
||||
```
|
||||
|
||||
*Example contents of `msg->network`:*
|
||||
|
||||
```
|
||||
nwid : 8bd712bf36bdae5f
|
||||
mac : ae53fa031fcf
|
||||
name : cranky_hayes
|
||||
type : 0
|
||||
mtu : 2800
|
||||
dhcp : 0
|
||||
bridge : 0
|
||||
broadcastEnabled : 1
|
||||
portError : 0
|
||||
netconfRevision : 34
|
||||
routeCount : 1
|
||||
multicastSubscriptionCount : 1
|
||||
- mac=ffffffffffff, adi=ac1b2561
|
||||
addresses:
|
||||
- FC5D:69B6:E0F7:46D5:50DD::1
|
||||
- 172.27.37.97
|
||||
routes:
|
||||
- target : 172.27.0.0
|
||||
- via : 0.0.0.0
|
||||
- flags : 0
|
||||
- metric : 0
|
||||
```
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
## Peer Events
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Accessible via `msg->peer` as a `zts_peer_details` object, this message type will contain information about a peer that was discovered by your node. These events are triggered when the reachability status of a peer has changed. *Possible values of `msg->eventCode`:*
|
||||
|
||||
```c
|
||||
ZTS_EVENT_PEER_DIRECT // At least one direct path to this peer is known.
|
||||
ZTS_EVENT_PEER_RELAY // No direct path to this peer is known. It will be relayed, (high packet loss and jitter.)
|
||||
ZTS_EVENT_PEER_UNREACHABLE // Peer is not reachable by any means.
|
||||
ZTS_EVENT_PEER_PATH_DISCOVERED // A new direct path to this peer has been discovered.
|
||||
ZTS_EVENT_PEER_PATH_DEAD // A direct path to this peer has expired.
|
||||
```
|
||||
|
||||
*Example contents of `msg->peer`:*
|
||||
|
||||
```
|
||||
peer : a747d5502d
|
||||
role : 0
|
||||
latency : 4
|
||||
version : 1.4.6
|
||||
pathCount : 2
|
||||
- 172.27.37.97
|
||||
- F75D:69B6:E0C7:47D5:51DB::1
|
||||
```
|
||||
|
||||
## Address Events
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Accessible via `msg->addr` as a `zts_addr_details` object, this message type will contain information about addresses assign to your node on a particular network. The information contained in these events is also available via `ZTS_EVENT_NETWORK_UPDATE` events. *Possible values of `msg->eventCode`:*
|
||||
|
||||
```c
|
||||
ZTS_EVENT_ADDR_ADDED_IP4 // A new IPv4 address was assigned to your node on the indicated network.
|
||||
ZTS_EVENT_ADDR_REMOVED_IP4 // An IPv4 address assignment to your node was removed on the indicated network.
|
||||
ZTS_EVENT_ADDR_ADDED_IP6 // A new IPv6 address was assigned to your node on the indicated network.
|
||||
ZTS_EVENT_ADDR_REMOVED_IP6 // An IPv6 address assignment to your node was removed on the indicated network.
|
||||
```
|
||||
|
||||
*Example contents of `msg->addr`:*
|
||||
|
||||
```
|
||||
nwid : a747d5502d
|
||||
addr : 172.27.37.97
|
||||
```
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# Error handling
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Calling a `zts_*` function will result in one of the following return codes. Only when `ZTS_ERR` is returned will `zts_errno` be set. Its values closely mirror those used in standard socket interfaces and are defined in `include/ZeroTierSockets.h`.
|
||||
|
||||
```c
|
||||
ZTS_ERR_OK // No error
|
||||
ZTS_ERR_SOCKET // Socket error (see zts_errno for more information)
|
||||
ZTS_ERR_SERVICE // General ZeroTier internal error. Maybe you called something out of order?
|
||||
ZTS_ERR_ARG // An argument provided is invalid.
|
||||
ZTS_ERR_NO_RESULT // Call succeeded but no result was available. Not necessarily an error.
|
||||
ZTS_ERR_GENERAL // General internal failure. Consider filing a bug report.
|
||||
```
|
||||
|
||||
*NOTE: For Android/Java (or similar) which use JNI, the socket API's error codes are negative values encoded in the return values of function calls*
|
||||
*NOTE: For protocol-level errors (such as dropped packets) or internal network stack errors, see the section `Statistics`*
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# Common pitfalls
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
- If you have started a node but have not received a `ZTS_EVENT_NODE_ONLINE`:
|
||||
- You may need to view our [Router Config Tips](https://zerotier.atlassian.net/wiki/spaces/SD/pages/6815768/Router+Configuration+Tips) knowledgebase article. Sometimes this is due to firewall/NAT settings.
|
||||
|
||||
- If you have received a `ZTS_EVENT_NODE_ONLINE` event and attempted to join a network but do not see your node ID in the network panel on [my.zerotier.com](my.zerotier.com) after some time:
|
||||
- You may have typed in your network ID incorrectly.
|
||||
- Used an improper integer representation for your network ID (e.g. `int` instead of `uint64_t`).
|
||||
|
||||
- If you are unable to reliably connect to peers:
|
||||
- You should first read the section on [Connecting and communicating with peers](#connecting-and-communicating-with-peers).
|
||||
- If the previous step doesn't help move onto our knowledgebase article [Router Config Tips](https://zerotier.atlassian.net/wiki/spaces/SD/pages/6815768/Router+Configuration+Tips). Sometimes this can be a transport-triggered link issue, and sometimes it can be a firewall/NAT issue.
|
||||
|
||||
- API calls seem to fail in nonsensical ways and you're tearing your hair out:
|
||||
- Be sure to read and understand the [API compatibility with host OS](#api-compatibility-with-host-os) section.
|
||||
- See the [Debugging](#debugging) section for more advice.
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# API compatibility with host OS
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Since libzt re-implements a socket interface likely very similar to your host OS's own interface it may be tempting to mix and match host OS structures and functions with those of libzt. This may work on occasion, but you are tempting fate. Here are a few important guidelines:
|
||||
|
||||
If you are calling a `zts_*` function, use the appropriate `ZTS_*` constants:
|
||||
```c
|
||||
zts_socket(ZTS_AF_INET6, ZTS_SOCK_DGRAM, 0); (CORRECT)
|
||||
zts_socket(AF_INET6, SOCK_DGRAM, 0); (INCORRECT)
|
||||
```
|
||||
|
||||
If you are calling a `zts_*` function, use the appropriate `zts_*` structure:
|
||||
```c
|
||||
struct zts_sockaddr_in in4; <------ Note the zts_ prefix
|
||||
...
|
||||
zts_bind(fd, (struct sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
|
||||
```
|
||||
|
||||
If you are calling a host OS function, use your host OS's constants (and structures!):
|
||||
|
||||
```c
|
||||
inet_ntop(AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
|
||||
inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (INCORRECT)
|
||||
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), ...); (CORRECT)
|
||||
```
|
||||
|
||||
If you are calling a host OS function but passing a `zts_*` structure, this can work sometimes but you should take care to pass the correct host OS constants:
|
||||
```c
|
||||
struct zts_sockaddr_in6 in6;
|
||||
...
|
||||
inet_ntop(AF_INET6, &(in6->sin6_addr), dstStr, INET6_ADDRSTRLEN);
|
||||
```
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# Thread model
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
Both the **socket** and **control** interfaces are thread-safe but are implemented differently. The socket interface is implemented using a relatively performant core locking mechanism in lwIP. This can be disabled if you know what you're doing. The control interface is implemented by a single coarse-grained lock. This lock is not a performance bottleneck since it only applies to functions that manipulate the ZeroTier service and are called seldomly. Callback events are generated by a separate thread and are independent from the rest of the API's internal locking mechanism. Not returning from a callback event won't impact the rest of the API but it will prevent your application from receiving future events so it is in your application's best interest to perform as little work as possible in the callback function and promptly return control back to ZeroTier.
|
||||
|
||||
*Note: Internally, `libzt` will spawn a number of threads for various purposes: a thread for the core service, a thread for the network stack, a low priority thread to process callback events, and a thread for each network joined. The vast majority of work is performed by the core service and stack threads.*
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
# Debugging
|
||||
- #### [Back to Table of Contents](#table-of-contents)
|
||||
|
||||
If you're experiencing odd behavior or something that looks like a bug I would suggest first reading and understanding the following sections:
|
||||
|
||||
* [Common pitfalls](#common-pitfalls)
|
||||
* [API compatibility with host OS](#api-compatibility-with-host-os)
|
||||
* [Thread model](#thread-model)
|
||||
|
||||
If the information in those sections hasn't helped, there are a couple of ways to get debug traces out of various parts of the library.
|
||||
|
||||
1) Build the library in debug mode with `make host_debug`. This will prevent the stripping of debug symbols from the library and will enable basic output traces from libzt.
|
||||
|
||||
2) If you believe your problem is in the network stack you can manually enable debug traces for individual modules in `src/lwipopts.h`. Toggle the `*_DEBUG` types from `LWIP_DBG_OFF` to `LWIP_DBG_ON`. And then rebuild. This will come with a significant performance cost.
|
||||
|
||||
3) Enabling network stack statistics. This is useful if you want to monitor the stack's receipt and handling of traffic as well as internal things like memory allocations and cache hits. Protocol and service statistics are available in debug builds of `libzt`. These statistics are detailed fully in the section of `include/ZeroTierSockets.h` that is guarded by `LWIP_STATS`.
|
||||
|
||||
```c
|
||||
struct zts_stats_proto stats;
|
||||
if (zts_get_protocol_stats(ZTS_STATS_PROTOCOL_ICMP, &stats) == ZTS_ERR_OK) {
|
||||
printf("icmp.recv=%d\n", stats.recv); // Count of received pings
|
||||
}
|
||||
if (zts_get_protocol_stats(ZTS_STATS_PROTOCOL_TCP, &stats) == ZTS_ERR_OK) {
|
||||
printf("tcp.drop=%d\n", stats.drop); // Count of dropped TCP packets
|
||||
}
|
||||
```
|
||||
|
||||
4) There are a series of additional events which can signal whether the network stack or its virtual network interfaces have been set up properly. See `ZTS_EVENT_STACK_*` and `ZTS_EVENT_NETIF_*`.
|
||||
|
||||
<div style="page-break-after: always;"></div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
140
src/Central.cpp
140
src/Central.cpp
@@ -4,20 +4,18 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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 ZT_CENTRAL_H
|
||||
#define ZT_CENTRAL_H
|
||||
|
||||
#ifdef ZTS_ENABLE_CENTRAL_API
|
||||
#ifndef ZTS_DISABLE_CENTRAL_API
|
||||
|
||||
#include "Debug.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <curl/curl.h>
|
||||
@@ -26,6 +24,8 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define REQ_LEN 64
|
||||
|
||||
char api_url[ZTS_CENRTAL_MAX_URL_LEN];
|
||||
char api_token[ZTS_CENTRAL_TOKEN_LEN + 1];
|
||||
|
||||
@@ -50,22 +50,31 @@ size_t on_data(void* buffer, size_t size, size_t nmemb, void* userp)
|
||||
DEBUG_INFO("buf=%p,size=%zu,nmemb=%zu,userp=%p", buffer, size, nmemb, userp);
|
||||
int byte_count = (size * nmemb);
|
||||
if (_resp_buf_offset + byte_count >= _resp_buf_len) {
|
||||
DEBUG_ERROR("Out of buffer space. Cannot store response from server");
|
||||
return 0; // Signal to libcurl that our buffer is full (triggers a write error.)
|
||||
DEBUG_INFO("Out of buffer space. Cannot store response from server");
|
||||
return 0; // Signal to libcurl that our buffer is full (triggers a
|
||||
// write error.)
|
||||
}
|
||||
memcpy(_resp_buf + _resp_buf_offset, buffer, byte_count);
|
||||
_resp_buf_offset += byte_count;
|
||||
return byte_count;
|
||||
}
|
||||
|
||||
void zts_central_set_access_mode(int8_t modes)
|
||||
int zts_central_set_access_mode(int8_t modes)
|
||||
{
|
||||
if (! (modes & ZTS_CENTRAL_READ) && ! (modes & ZTS_CENTRAL_WRITE)) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
_access_modes = modes;
|
||||
return ZTS_ERR_OK;
|
||||
}
|
||||
|
||||
void zts_central_set_verbose(int8_t is_verbose)
|
||||
int zts_central_set_verbose(int8_t is_verbose)
|
||||
{
|
||||
if (is_verbose != 1 && is_verbose != 0) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
_bIsVerbose = is_verbose;
|
||||
return ZTS_ERR_OK;
|
||||
}
|
||||
|
||||
void zts_central_clear_resp_buf()
|
||||
@@ -81,7 +90,7 @@ int zts_central_init(
|
||||
char* resp_buf,
|
||||
uint32_t resp_buf_len)
|
||||
{
|
||||
_access_modes = ZTS_CENTRAL_READ; // Defauly read-only
|
||||
_access_modes = ZTS_CENTRAL_READ; // Default read-only
|
||||
_bIsVerbose = 0; // Default disable libcurl verbose output
|
||||
Mutex::Lock _l(_responseBuffer_m);
|
||||
if (resp_buf_len == 0) {
|
||||
@@ -99,7 +108,7 @@ int zts_central_init(
|
||||
}
|
||||
else {
|
||||
memset(api_url, 0, ZTS_CENRTAL_MAX_URL_LEN);
|
||||
memcpy(api_url, url_str, url_len);
|
||||
strncpy(api_url, url_str, url_len);
|
||||
}
|
||||
int token_len = strlen(token_str);
|
||||
if (token_len != ZTS_CENTRAL_TOKEN_LEN) {
|
||||
@@ -107,7 +116,7 @@ int zts_central_init(
|
||||
}
|
||||
else {
|
||||
memset(api_token, 0, ZTS_CENTRAL_TOKEN_LEN);
|
||||
memcpy(api_token, token_str, token_len);
|
||||
strncpy(api_token, token_str, token_len);
|
||||
}
|
||||
_bInit = true;
|
||||
return ZTS_ERR_OK;
|
||||
@@ -118,7 +127,7 @@ void zts_central_cleanup()
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
int _central_req(
|
||||
int central_req(
|
||||
int request_type,
|
||||
char* central_str,
|
||||
char* api_route_str,
|
||||
@@ -128,15 +137,17 @@ int _central_req(
|
||||
{
|
||||
int err = ZTS_ERR_OK;
|
||||
if (! _bInit) {
|
||||
DEBUG_ERROR("Error: Central API must be initialized first. Call zts_central_init()");
|
||||
DEBUG_INFO("Error: Central API must be initialized first. Call "
|
||||
"zts_central_init()");
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (request_type == ZTS_HTTP_GET && ! (_access_modes & ZTS_CENTRAL_READ)) {
|
||||
DEBUG_ERROR("Error: Incorrect access mode. Need (ZTS_CENTRAL_READ) permission");
|
||||
DEBUG_INFO("Error: Incorrect access mode. Need (ZTS_CENTRAL_READ) permission");
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (request_type == ZTS_HTTP_POST && ! (_access_modes & ZTS_CENTRAL_WRITE)) {
|
||||
DEBUG_ERROR("Error: Incorrect access mode. Need (ZTS_CENTRAL_WRITE) permission");
|
||||
DEBUG_INFO("Error: Incorrect access mode. Need (ZTS_CENTRAL_WRITE) "
|
||||
"permission");
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
zts_central_clear_resp_buf();
|
||||
@@ -150,9 +161,9 @@ int _central_req(
|
||||
if (url_len > ZTS_CENRTAL_MAX_URL_LEN) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
char req_url[ZTS_CENRTAL_MAX_URL_LEN];
|
||||
strcpy(req_url, central_str);
|
||||
strcat(req_url, api_route_str);
|
||||
char req_url[ZTS_CENRTAL_MAX_URL_LEN] = { 0 };
|
||||
strncpy(req_url, central_str, ZTS_CENRTAL_MAX_URL_LEN);
|
||||
strncat(req_url, api_route_str, ZTS_CENRTAL_MAX_URL_LEN);
|
||||
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
@@ -162,10 +173,13 @@ int _central_req(
|
||||
}
|
||||
|
||||
struct curl_slist* hs = NULL;
|
||||
char auth_str[ZTS_CENTRAL_TOKEN_LEN + 32];
|
||||
char auth_str[ZTS_CENTRAL_TOKEN_LEN + 32] = { 0 }; // + Authorization: Bearer
|
||||
if (token_strlen == ZTS_CENTRAL_TOKEN_LEN) {
|
||||
memset(auth_str, 0, ZTS_CENTRAL_TOKEN_LEN + 32);
|
||||
sprintf(auth_str, "Authorization: Bearer %s", token_str);
|
||||
OSUtils::ztsnprintf(
|
||||
auth_str,
|
||||
ZTS_CENTRAL_TOKEN_LEN + 32,
|
||||
"Authorization: Bearer %s",
|
||||
token_str);
|
||||
}
|
||||
|
||||
hs = curl_slist_append(hs, auth_str);
|
||||
@@ -194,7 +208,8 @@ int _central_req(
|
||||
if (request_type == ZTS_HTTP_DELETE) {
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
}
|
||||
// curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); // Consider 400-500 series code as failures
|
||||
// curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); // Consider 400-500
|
||||
// series code as failures
|
||||
// Perform request
|
||||
res = curl_easy_perform(curl);
|
||||
if (res == CURLE_OK) {
|
||||
@@ -208,7 +223,7 @@ int _central_req(
|
||||
// curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||
}
|
||||
else {
|
||||
DEBUG_ERROR("%s", curl_easy_strerror(res));
|
||||
DEBUG_INFO("%s", curl_easy_strerror(res));
|
||||
err = ZTS_ERR_SERVICE;
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
@@ -225,87 +240,86 @@ int zts_get_last_resp_buf(char* dest_buffer, int dest_buf_len)
|
||||
return ZTS_ERR_OK;
|
||||
}
|
||||
|
||||
int zts_central_get_status(int* resp_code)
|
||||
int zts_central_status_get(int* resp_code)
|
||||
{
|
||||
return _central_req(ZTS_HTTP_GET, api_url, (char*)"/api/status", api_token, resp_code, NULL);
|
||||
return central_req(ZTS_HTTP_GET, api_url, (char*)"/api/status", api_token, resp_code, NULL);
|
||||
}
|
||||
|
||||
int zts_central_get_self(int* resp_code)
|
||||
int zts_central_self_get(int* resp_code)
|
||||
{
|
||||
return _central_req(ZTS_HTTP_GET, api_url, (char*)"/api/self", api_token, resp_code, NULL);
|
||||
return central_req(ZTS_HTTP_GET, api_url, (char*)"/api/self", api_token, resp_code, NULL);
|
||||
}
|
||||
|
||||
int zts_central_get_network(int* resp_code, uint64_t nwid)
|
||||
int zts_central_net_get(int* resp_code, uint64_t net_id)
|
||||
{
|
||||
char req[64];
|
||||
sprintf(req, "/api/network/%llx", nwid);
|
||||
return _central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
|
||||
char req[REQ_LEN] = { 0 };
|
||||
OSUtils::ztsnprintf(req, REQ_LEN, "/api/network/%llx", net_id);
|
||||
return central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
|
||||
}
|
||||
|
||||
int zts_central_update_network(int* resp_code, uint64_t nwid)
|
||||
int zts_central_net_update(int* resp_code, uint64_t net_id)
|
||||
{
|
||||
char req[64];
|
||||
sprintf(req, "/api/network/%llx", nwid);
|
||||
return _central_req(ZTS_HTTP_POST, api_url, req, api_token, resp_code, NULL);
|
||||
char req[REQ_LEN] = { 0 };
|
||||
OSUtils::ztsnprintf(req, REQ_LEN, "/api/network/%llx", net_id);
|
||||
return central_req(ZTS_HTTP_POST, api_url, req, api_token, resp_code, NULL);
|
||||
}
|
||||
|
||||
int zts_central_delete_network(int* resp_code, uint64_t nwid)
|
||||
int zts_central_net_delete(int* resp_code, uint64_t net_id)
|
||||
{
|
||||
char req[64];
|
||||
sprintf(req, "/api/network/%llx", nwid);
|
||||
return _central_req(ZTS_HTTP_DELETE, api_url, req, api_token, resp_code, NULL);
|
||||
char req[REQ_LEN] = { 0 };
|
||||
OSUtils::ztsnprintf(req, REQ_LEN, "/api/network/%llx", net_id);
|
||||
return central_req(ZTS_HTTP_DELETE, api_url, req, api_token, resp_code, NULL);
|
||||
}
|
||||
|
||||
int zts_central_get_networks(int* resp_code)
|
||||
int zts_central_net_get_all(int* resp_code)
|
||||
{
|
||||
return _central_req(ZTS_HTTP_GET, api_url, (char*)"/api/network", api_token, resp_code, NULL);
|
||||
return central_req(ZTS_HTTP_GET, api_url, (char*)"/api/network", api_token, resp_code, NULL);
|
||||
}
|
||||
|
||||
int zts_central_get_member(int* resp_code, uint64_t nwid, uint64_t nodeid)
|
||||
int zts_central_member_get(int* resp_code, uint64_t net_id, uint64_t node_id)
|
||||
{
|
||||
if (nwid == 0 || nodeid == 0) {
|
||||
if (net_id == 0 || node_id == 0) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
char req[64];
|
||||
sprintf(req, "/api/network/%llx/member/%llx", nwid, nodeid);
|
||||
return _central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
|
||||
char req[REQ_LEN] = { 0 };
|
||||
OSUtils::ztsnprintf(req, REQ_LEN, "/api/network/%llx/member/%llx", net_id, node_id);
|
||||
return central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
|
||||
}
|
||||
|
||||
int zts_central_update_member(int* resp_code, uint64_t nwid, uint64_t nodeid, char* post_data)
|
||||
int zts_central_member_update(int* resp_code, uint64_t net_id, uint64_t node_id, char* post_data)
|
||||
{
|
||||
if (nwid == 0 || nodeid == 0 || post_data == NULL) {
|
||||
if (net_id == 0 || node_id == 0 || post_data == NULL) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
char req[64];
|
||||
sprintf(req, "/api/network/%llx/member/%llx", nwid, nodeid);
|
||||
return _central_req(ZTS_HTTP_POST, api_url, req, api_token, resp_code, post_data);
|
||||
char req[REQ_LEN] = { 0 };
|
||||
OSUtils::ztsnprintf(req, REQ_LEN, "/api/network/%llx/member/%llx", net_id, node_id);
|
||||
return central_req(ZTS_HTTP_POST, api_url, req, api_token, resp_code, post_data);
|
||||
}
|
||||
|
||||
int zts_central_set_node_auth(int* resp_code, uint64_t nwid, uint64_t nodeid, uint8_t is_authed)
|
||||
int zts_central_node_auth(int* resp_code, uint64_t net_id, uint64_t node_id, uint8_t is_authed)
|
||||
{
|
||||
if (is_authed != 0 && is_authed != 1) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
char config_data[64];
|
||||
char config_data[REQ_LEN] = { 0 };
|
||||
if (is_authed == ZTS_CENTRAL_NODE_AUTH_TRUE) {
|
||||
sprintf(config_data, "{\"config\": {\"authorized\": true} }");
|
||||
OSUtils::ztsnprintf(config_data, REQ_LEN, "{\"config\": {\"authorized\": true} }");
|
||||
}
|
||||
if (is_authed == ZTS_CENTRAL_NODE_AUTH_FALSE) {
|
||||
sprintf(config_data, "{\"config\": {\"authorized\": false} }");
|
||||
OSUtils::ztsnprintf(config_data, REQ_LEN, "{\"config\": {\"authorized\": false} }");
|
||||
}
|
||||
return zts_central_update_member(resp_code, nwid, nodeid, config_data);
|
||||
return zts_central_member_update(resp_code, net_id, node_id, config_data);
|
||||
}
|
||||
|
||||
int zts_central_get_members_of_network(int* resp_code, uint64_t nwid)
|
||||
int zts_central_net_get_members(int* resp_code, uint64_t net_id)
|
||||
{
|
||||
char req[64];
|
||||
sprintf(req, "/api/network/%llx/member", nwid);
|
||||
return _central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
|
||||
char req[REQ_LEN] = { 0 };
|
||||
OSUtils::ztsnprintf(req, REQ_LEN, "/api/network/%llx/member", net_id);
|
||||
return central_req(ZTS_HTTP_GET, api_url, req, api_token, resp_code, NULL);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif // ZTS_ENABLE_CENTRAL_API
|
||||
#endif // _H
|
||||
#endif // ZTS_DISABLE_CENTRAL_API
|
||||
|
||||
1022
src/Controls.cpp
1022
src/Controls.cpp
File diff suppressed because it is too large
Load Diff
140
src/Debug.hpp
140
src/Debug.hpp
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
@@ -17,25 +17,14 @@
|
||||
* Debug macros
|
||||
*/
|
||||
|
||||
#ifndef LIBZT_DEBUG_HPP
|
||||
#define LIBZT_DEBUG_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Debugging Macros //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef ZTS_DEBUG_HPP
|
||||
#define ZTS_DEBUG_HPP
|
||||
|
||||
#if defined(__linux__) || defined(__APPLE__)
|
||||
#include <pthread.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
|
||||
#define ZT_MSG_ERROR true // Errors
|
||||
#define ZT_MSG_INFO true // Information which is generally useful to any developer
|
||||
#define ZT_MSG_TEST true // For use in selftest
|
||||
#define ZT_MSG_TRANSFER true // RX/TX specific statements
|
||||
|
||||
#define ZT_COLOR true
|
||||
|
||||
// Debug output colors
|
||||
@@ -66,87 +55,12 @@
|
||||
|
||||
#define ZT_FILENAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__) // short
|
||||
|
||||
#if defined(__JNI_LIB__)
|
||||
#include <jni.h>
|
||||
#endif
|
||||
#if defined(__ANDROID__)
|
||||
#include <android/log.h>
|
||||
#define ZT_LOG_TAG "ZTSDK"
|
||||
#endif
|
||||
|
||||
#if defined(LIBZT_DEBUG) || defined(LIBZT_TRACE) || defined(__NATIVETEST__)
|
||||
//
|
||||
#if ZT_MSG_ERROR == true
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_ERROR(fmt, args...) \
|
||||
((void)__android_log_print( \
|
||||
ANDROID_LOG_VERBOSE, \
|
||||
ZT_LOG_TAG, \
|
||||
"%17s:%5d:%20s: " fmt "\n", \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
##args))
|
||||
#elif defined(_WIN32)
|
||||
#define DEBUG_ERROR(fmt, ...) \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
ZT_RED "%17s:%5d:%25s: " fmt "\n" ZT_RESET, \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_ERROR(fmt, args...) \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
ZT_RED "%17s:%5d:%25s: " fmt "\n" ZT_RESET, \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_ERROR(fmt, args...)
|
||||
#endif
|
||||
|
||||
//
|
||||
#if ZT_MSG_TEST == true
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_TEST(fmt, args...) \
|
||||
((void)__android_log_print( \
|
||||
ANDROID_LOG_VERBOSE, \
|
||||
ZT_LOG_TAG, \
|
||||
"%17s:%5d:%25s: " fmt "\n", \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
##args))
|
||||
#elif defined(_WIN32)
|
||||
#define DEBUG_TEST(fmt, ...) \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
ZT_CYN "%17s:%5d:%25s: " fmt "\n" ZT_RESET, \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_TEST(fmt, args...) \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
ZT_CYN "%17s:%5d:%25s: " fmt "\n" ZT_RESET, \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_TEST(fmt, args...)
|
||||
#endif
|
||||
|
||||
//
|
||||
#if ZT_MSG_INFO == true
|
||||
#if defined(LIBZT_DEBUG)
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_INFO(fmt, args...) \
|
||||
((void)__android_log_print( \
|
||||
@@ -176,55 +90,11 @@
|
||||
__FUNCTION__, \
|
||||
##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_INFO(fmt, args...)
|
||||
#endif
|
||||
|
||||
//
|
||||
#if ZT_MSG_TRANSFER == true
|
||||
#if defined(__ANDROID__)
|
||||
#define DEBUG_TRANS(fmt, args...) \
|
||||
((void)__android_log_print( \
|
||||
ANDROID_LOG_VERBOSE, \
|
||||
ZT_LOG_TAG, \
|
||||
"%17s:%5d:%25s: " fmt "\n", \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
##args))
|
||||
#elif defined(_WIN32)
|
||||
#define DEBUG_TRANS(fmt, ...) \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
ZT_GRN "%17s:%5d:%25s: " fmt "\n" ZT_RESET, \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
__VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_TRANS(fmt, args...) \
|
||||
fprintf( \
|
||||
stderr, \
|
||||
ZT_GRN "%17s:%5d:%25s: " fmt "\n" ZT_RESET, \
|
||||
ZT_FILENAME, \
|
||||
__LINE__, \
|
||||
__FUNCTION__, \
|
||||
##args)
|
||||
#endif
|
||||
#else
|
||||
#define DEBUG_TRANS(fmt, args...)
|
||||
#endif
|
||||
#else // !LIBZT_DEBUG || !__NATIVE_TEST__
|
||||
#else // !LIBZT_DEBUG
|
||||
#if defined(_WIN32)
|
||||
#define DEBUG_ERROR(...)
|
||||
#define DEBUG_TEST(...)
|
||||
#define DEBUG_INFO(...)
|
||||
#define DEBUG_TRANS(...)
|
||||
#else
|
||||
#define DEBUG_ERROR(fmt, args...)
|
||||
#define DEBUG_TEST(fmt, args...)
|
||||
#define DEBUG_INFO(fmt, args...)
|
||||
#define DEBUG_TRANS(fmt, args...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
205
src/Events.cpp
205
src/Events.cpp
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
@@ -14,49 +14,57 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Callback event processing logic
|
||||
* Callback event creation and distribution to user application
|
||||
*/
|
||||
|
||||
#include "Events.hpp"
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "NodeService.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
#include "concurrentqueue.h"
|
||||
|
||||
#ifdef ZTS_ENABLE_JAVA
|
||||
#include <jni.h>
|
||||
#endif
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Debug.hpp"
|
||||
#include "Events.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "NodeService.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#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
|
||||
|
||||
#ifdef ZTS_ENABLE_PYTHON
|
||||
#include "Python.h"
|
||||
PythonDirectorCallbackClass* _userEventCallback = NULL;
|
||||
void PythonDirectorCallbackClass::on_zerotier_event(struct zts_callback_msg* msg)
|
||||
void PythonDirectorCallbackClass::on_zerotier_event(zts_event_msg_t* msg)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ZTS_NODE_EVENT(code) code >= ZTS_EVENT_NODE_UP&& code <= ZTS_EVENT_NODE_FATAL_ERROR
|
||||
#define ZTS_NETWORK_EVENT(code) \
|
||||
code >= ZTS_EVENT_NETWORK_NOT_FOUND&& code <= ZTS_EVENT_NETWORK_UPDATE
|
||||
#define ZTS_STACK_EVENT(code) code >= ZTS_EVENT_STACK_UP&& code <= ZTS_EVENT_STACK_DOWN
|
||||
#define ZTS_NETIF_EVENT(code) code >= ZTS_EVENT_NETIF_UP&& code <= ZTS_EVENT_NETIF_LINK_DOWN
|
||||
#define ZTS_PEER_EVENT(code) code >= ZTS_EVENT_PEER_DIRECT&& code <= ZTS_EVENT_PEER_PATH_DEAD
|
||||
#define ZTS_ROUTE_EVENT(code) code >= ZTS_EVENT_ROUTE_ADDED&& code <= ZTS_EVENT_ROUTE_REMOVED
|
||||
#define ZTS_ADDR_EVENT(code) code >= ZTS_EVENT_ADDR_ADDED_IP4&& code <= ZTS_EVENT_ADDR_REMOVED_IP6
|
||||
#define ZTS_STORE_EVENT(code) \
|
||||
code >= ZTS_EVENT_STORE_IDENTITY_SECRET&& code <= ZTS_EVENT_STORE_NETWORK
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
extern NodeService* service;
|
||||
extern NodeService* zts_service;
|
||||
|
||||
// Global state variable shared between Socket, Control, Event and NodeService logic.
|
||||
uint8_t _serviceStateFlags;
|
||||
// Global state variable shared between Socket, Control, Event and
|
||||
// NodeService logic.
|
||||
volatile uint8_t service_state = 0;
|
||||
int last_state_check;
|
||||
|
||||
#define RESET_FLAGS() service_state = 0;
|
||||
#define SET_FLAGS(f) service_state |= f;
|
||||
#define CLR_FLAGS(f) service_state &= ~f;
|
||||
#define GET_FLAGS(f) ((service_state & f) > 0)
|
||||
|
||||
// Lock to guard access to callback function pointers.
|
||||
Mutex _callbackLock;
|
||||
Mutex events_m;
|
||||
|
||||
#ifdef ZTS_ENABLE_PINVOKE
|
||||
void (*_userEventCallback)(void*);
|
||||
@@ -65,45 +73,74 @@ void (*_userEventCallback)(void*);
|
||||
void (*_userEventCallback)(void*);
|
||||
#endif
|
||||
|
||||
moodycamel::ConcurrentQueue<struct zts_callback_msg*> _callbackMsgQueue;
|
||||
moodycamel::ConcurrentQueue<zts_event_msg_t*> _callbackMsgQueue;
|
||||
|
||||
void _enqueueEvent(int16_t eventCode, void* arg)
|
||||
void Events::run()
|
||||
{
|
||||
struct zts_callback_msg* msg = new zts_callback_msg();
|
||||
msg->eventCode = eventCode;
|
||||
while (getState(ZTS_STATE_CALLBACKS_RUNNING) || _callbackMsgQueue.size_approx() > 0) {
|
||||
zts_event_msg_t* msg;
|
||||
size_t sz = _callbackMsgQueue.size_approx();
|
||||
for (size_t j = 0; j < sz; j++) {
|
||||
if (_callbackMsgQueue.try_dequeue(msg)) {
|
||||
events_m.lock();
|
||||
sendToUser(msg);
|
||||
events_m.unlock();
|
||||
delete msg;
|
||||
}
|
||||
}
|
||||
zts_util_delay(ZTS_CALLBACK_PROCESSING_INTERVAL);
|
||||
}
|
||||
}
|
||||
|
||||
if (NODE_EVENT_TYPE(eventCode)) {
|
||||
msg->node = (struct zts_node_details*)arg;
|
||||
void Events::enqueue(int16_t event_code, const void* arg, int len)
|
||||
{
|
||||
if (! _enabled) {
|
||||
return;
|
||||
}
|
||||
if (NETWORK_EVENT_TYPE(eventCode)) {
|
||||
msg->network = (struct zts_network_details*)arg;
|
||||
zts_event_msg_t* msg = new zts_event_msg_t();
|
||||
msg->event_code = event_code;
|
||||
|
||||
if (ZTS_NODE_EVENT(event_code)) {
|
||||
msg->node = (zts_node_info_t*)arg;
|
||||
msg->len = sizeof(zts_node_info_t);
|
||||
}
|
||||
if (STACK_EVENT_TYPE(eventCode)) {
|
||||
if (ZTS_NETWORK_EVENT(event_code)) {
|
||||
msg->network = (zts_net_info_t*)arg;
|
||||
msg->len = sizeof(zts_net_info_t);
|
||||
}
|
||||
if (ZTS_STACK_EVENT(event_code)) {
|
||||
/* nothing to convey to user */
|
||||
}
|
||||
if (NETIF_EVENT_TYPE(eventCode)) {
|
||||
msg->netif = (struct zts_netif_details*)arg;
|
||||
if (ZTS_NETIF_EVENT(event_code)) {
|
||||
msg->netif = (zts_netif_info_t*)arg;
|
||||
msg->len = sizeof(zts_netif_info_t);
|
||||
}
|
||||
if (ROUTE_EVENT_TYPE(eventCode)) {
|
||||
msg->route = (struct zts_virtual_network_route*)arg;
|
||||
if (ZTS_ROUTE_EVENT(event_code)) {
|
||||
msg->route = (zts_route_info_t*)arg;
|
||||
msg->len = sizeof(zts_route_info_t);
|
||||
}
|
||||
if (PEER_EVENT_TYPE(eventCode)) {
|
||||
msg->peer = (struct zts_peer_details*)arg;
|
||||
if (ZTS_PEER_EVENT(event_code)) {
|
||||
msg->peer = (zts_peer_info_t*)arg;
|
||||
msg->len = sizeof(zts_peer_info_t);
|
||||
}
|
||||
if (ADDR_EVENT_TYPE(eventCode)) {
|
||||
msg->addr = (struct zts_addr_details*)arg;
|
||||
if (ZTS_ADDR_EVENT(event_code)) {
|
||||
msg->addr = (zts_addr_info_t*)arg;
|
||||
msg->len = sizeof(zts_addr_info_t);
|
||||
}
|
||||
if (ZTS_STORE_EVENT(event_code)) {
|
||||
msg->cache = (void*)arg;
|
||||
msg->len = len;
|
||||
}
|
||||
|
||||
if (msg && _callbackMsgQueue.size_approx() > 1024) {
|
||||
// Rate-limit number of events
|
||||
_freeEvent(msg);
|
||||
destroy(msg);
|
||||
}
|
||||
else {
|
||||
_callbackMsgQueue.enqueue(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void _freeEvent(struct zts_callback_msg* msg)
|
||||
void Events::destroy(zts_event_msg_t* msg)
|
||||
{
|
||||
if (! msg) {
|
||||
return;
|
||||
@@ -128,9 +165,9 @@ void _freeEvent(struct zts_callback_msg* msg)
|
||||
}
|
||||
}
|
||||
|
||||
void _passDequeuedEventToUser(struct zts_callback_msg* msg)
|
||||
void Events::sendToUser(zts_event_msg_t* msg)
|
||||
{
|
||||
bool bShouldStopCallbackThread = (msg->eventCode == ZTS_EVENT_STACK_DOWN);
|
||||
bool bShouldStopCallbackThread = (msg->event_code == ZTS_EVENT_STACK_DOWN);
|
||||
#ifdef ZTS_ENABLE_PYTHON
|
||||
PyGILState_STATE state = PyGILState_Ensure();
|
||||
_userEventCallback->on_zerotier_event(msg);
|
||||
@@ -147,16 +184,16 @@ void _passDequeuedEventToUser(struct zts_callback_msg* msg)
|
||||
assert(rs == JNI_OK);
|
||||
uint64_t arg = 0;
|
||||
uint64_t id = 0;
|
||||
if (NODE_EVENT_TYPE(msg->eventCode)) {
|
||||
if (ZTS_NODE_EVENT(msg->event_code)) {
|
||||
id = msg->node ? msg->node->address : 0;
|
||||
}
|
||||
if (NETWORK_EVENT_TYPE(msg->eventCode)) {
|
||||
if (ZTS_NETWORK_EVENT(msg->event_code)) {
|
||||
id = msg->network ? msg->network->nwid : 0;
|
||||
}
|
||||
if (PEER_EVENT_TYPE(msg->eventCode)) {
|
||||
if (ZTS_PEER_EVENT(msg->event_code)) {
|
||||
id = msg->peer ? msg->peer->address : 0;
|
||||
}
|
||||
env->CallVoidMethod(objRef, _userCallbackMethodRef, id, msg->eventCode);
|
||||
env->CallVoidMethod(objRef, _userCallbackMethodRef, id, msg->event_code);
|
||||
}
|
||||
#endif // ZTS_ENABLE_JAVA
|
||||
#ifdef ZTS_ENABLE_PINVOKE
|
||||
@@ -169,53 +206,47 @@ void _passDequeuedEventToUser(struct zts_callback_msg* msg)
|
||||
_userEventCallback(msg);
|
||||
}
|
||||
#endif
|
||||
_freeEvent(msg);
|
||||
destroy(msg);
|
||||
if (bShouldStopCallbackThread) {
|
||||
/* Ensure last possible callback ZTS_EVENT_STACK_DOWN is
|
||||
delivered before callback thread is finally stopped. */
|
||||
_clrState(ZTS_STATE_CALLBACKS_RUNNING);
|
||||
clrState(ZTS_STATE_CALLBACKS_RUNNING);
|
||||
}
|
||||
}
|
||||
|
||||
bool _isCallbackRegistered()
|
||||
bool Events::hasCallback()
|
||||
{
|
||||
_callbackLock.lock();
|
||||
events_m.lock();
|
||||
bool retval = false;
|
||||
#ifdef ZTS_ENABLE_JAVA
|
||||
retval = (jvm && objRef && _userCallbackMethodRef);
|
||||
#else
|
||||
retval = _userEventCallback;
|
||||
#endif
|
||||
_callbackLock.unlock();
|
||||
events_m.unlock();
|
||||
return retval;
|
||||
}
|
||||
|
||||
void _clearRegisteredCallback()
|
||||
void Events::clrCallback()
|
||||
{
|
||||
_callbackLock.lock();
|
||||
events_m.lock();
|
||||
#ifdef ZTS_ENABLE_JAVA
|
||||
objRef = NULL;
|
||||
_userCallbackMethodRef = NULL;
|
||||
#else
|
||||
_userEventCallback = NULL;
|
||||
#endif
|
||||
_callbackLock.unlock();
|
||||
events_m.unlock();
|
||||
}
|
||||
|
||||
int _canPerformServiceOperation()
|
||||
int Events::canPerformServiceOperation()
|
||||
{
|
||||
return service && service->isRunning() && service->getNode() && service->getNode()->online()
|
||||
&& ! _getState(ZTS_STATE_FREE_CALLED);
|
||||
return zts_service && zts_service->isRunning() && ! 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)
|
||||
void Events::setState(uint8_t newFlags)
|
||||
{
|
||||
if ((newFlags ^ _serviceStateFlags) & ZTS_STATE_NET_SERVICE_RUNNING) {
|
||||
if ((newFlags ^ service_state) & ZTS_STATE_NET_SERVICE_RUNNING) {
|
||||
return; // No effect. Not allowed to set this flag manually
|
||||
}
|
||||
SET_FLAGS(newFlags);
|
||||
@@ -228,7 +259,7 @@ void _setState(uint8_t newFlags)
|
||||
}
|
||||
}
|
||||
|
||||
void _clrState(uint8_t newFlags)
|
||||
void Events::clrState(uint8_t newFlags)
|
||||
{
|
||||
if (newFlags & ZTS_STATE_NET_SERVICE_RUNNING) {
|
||||
return; // No effect. Not allowed to set this flag manually
|
||||
@@ -243,39 +274,19 @@ void _clrState(uint8_t newFlags)
|
||||
}
|
||||
}
|
||||
|
||||
bool _getState(uint8_t testFlags)
|
||||
bool Events::getState(uint8_t testFlags)
|
||||
{
|
||||
return testFlags & _serviceStateFlags;
|
||||
return testFlags & service_state;
|
||||
}
|
||||
|
||||
#if defined(__WINDOWS__)
|
||||
DWORD WINAPI _runCallbacks(LPVOID thread_id)
|
||||
#else
|
||||
void* _runCallbacks(void* thread_id)
|
||||
#endif
|
||||
void Events::enable()
|
||||
{
|
||||
#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;
|
||||
_enabled = true;
|
||||
}
|
||||
}
|
||||
zts_delay_ms(ZTS_CALLBACK_PROCESSING_INTERVAL);
|
||||
}
|
||||
#if ZTS_ENABLE_JAVA
|
||||
JNIEnv* env;
|
||||
jint rs = jvm->DetachCurrentThread();
|
||||
pthread_exit(0);
|
||||
#endif
|
||||
return NULL;
|
||||
|
||||
void Events::disable()
|
||||
{
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
115
src/Events.hpp
115
src/Events.hpp
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
@@ -14,13 +14,12 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Header for callback event processing logic
|
||||
* Callback event creation and distribution to user application
|
||||
*/
|
||||
|
||||
#ifndef ZT_EVENTS_HPP
|
||||
#define ZT_EVENTS_HPP
|
||||
#ifndef ZTS_USER_EVENTS_HPP
|
||||
#define ZTS_USER_EVENTS_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <string>
|
||||
@@ -29,10 +28,49 @@
|
||||
#include <BaseTsd.h>
|
||||
#endif
|
||||
|
||||
/* Macro substitutions to standardize state checking of service, node, callbacks, and TCP/IP
|
||||
* stack. These are used only for control functions that are called at a low frequency. All higher
|
||||
* frequency socket calls use a unguarded state flags */
|
||||
|
||||
// Lock service and check that it is running
|
||||
#define ACQUIRE_SERVICE(x) \
|
||||
Mutex::Lock _ls(service_m); \
|
||||
if (! zts_service || ! zts_service->isRunning()) { \
|
||||
return x; \
|
||||
}
|
||||
// Lock service and check that it is not currently running
|
||||
#define ACQUIRE_SERVICE_OFFLINE() \
|
||||
Mutex::Lock _ls(service_m); \
|
||||
if (zts_service && zts_service->isRunning()) { \
|
||||
return ZTS_ERR_SERVICE; \
|
||||
} \
|
||||
if (! zts_service) { \
|
||||
init_subsystems(); \
|
||||
}
|
||||
// Unlock service
|
||||
#define RELEASE_SERVICE() service_m.unlock();
|
||||
// Lock service, ensure node is online
|
||||
#define ACQUIRE_ONLINE_NODE() \
|
||||
ACQUIRE_SERVICE() if (! zts_service->nodeIsOnline()) \
|
||||
{ \
|
||||
return ZTS_ERR_SERVICE; \
|
||||
}
|
||||
// Lock event callback
|
||||
#define ACQUIRE_EVENTS() \
|
||||
Mutex::Lock _lc(events_m); \
|
||||
if (! zts_events) { \
|
||||
return ZTS_ERR_SERVICE; \
|
||||
}
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
#ifdef ZTS_ENABLE_JAVA
|
||||
#include <jni.h>
|
||||
// References to JNI objects and VM kept for future callbacks
|
||||
extern JavaVM* jvm;
|
||||
extern jobject objRef;
|
||||
extern jmethodID _userCallbackMethodRef;
|
||||
#endif
|
||||
namespace ZeroTier {
|
||||
|
||||
#define ZTS_STATE_NODE_RUNNING 0x01
|
||||
#define ZTS_STATE_STACK_RUNNING 0x02
|
||||
@@ -40,71 +78,88 @@ namespace ZeroTier {
|
||||
#define ZTS_STATE_CALLBACKS_RUNNING 0x08
|
||||
#define ZTS_STATE_FREE_CALLED 0x10
|
||||
|
||||
#ifdef ZTS_ENABLE_JAVA
|
||||
// References to JNI objects and VM kept for future callbacks
|
||||
extern JavaVM* jvm;
|
||||
extern jobject objRef;
|
||||
extern jmethodID _userCallbackMethodRef;
|
||||
#endif
|
||||
extern volatile uint8_t service_state;
|
||||
extern int last_state_check;
|
||||
|
||||
inline int transport_ok()
|
||||
{
|
||||
last_state_check = service_state & ZTS_STATE_NET_SERVICE_RUNNING;
|
||||
return last_state_check;
|
||||
}
|
||||
|
||||
/**
|
||||
* How often callback messages are assembled and/or sent
|
||||
*/
|
||||
#define ZTS_CALLBACK_PROCESSING_INTERVAL 25
|
||||
|
||||
class Events {
|
||||
bool _enabled;
|
||||
|
||||
public:
|
||||
Events() : _enabled(true)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform one iteration of callback processing
|
||||
*/
|
||||
void run();
|
||||
|
||||
/**
|
||||
* Enable callback event processing
|
||||
*/
|
||||
void enable();
|
||||
|
||||
/**
|
||||
* Disable callback event processing
|
||||
*/
|
||||
void disable();
|
||||
|
||||
/**
|
||||
* Enqueue an event to be sent to the user application
|
||||
*/
|
||||
void _enqueueEvent(int16_t eventCode, void* arg);
|
||||
void enqueue(int16_t event_code, const void* arg, int len = 0);
|
||||
|
||||
/**
|
||||
* Send callback message to user application
|
||||
*/
|
||||
void _passDequeuedEventToUser(struct ::zts_callback_msg* msg);
|
||||
void sendToUser(zts_event_msg_t* msg);
|
||||
|
||||
/**
|
||||
* Free memory occupied by callback structures
|
||||
*/
|
||||
void _freeEvent(struct ::zts_callback_msg* msg);
|
||||
void destroy(zts_event_msg_t* msg);
|
||||
|
||||
/**
|
||||
* Return whether a callback method has been set
|
||||
*/
|
||||
bool _isCallbackRegistered();
|
||||
bool hasCallback();
|
||||
|
||||
/**
|
||||
* Clear pointer reference to user-provided callback function
|
||||
*/
|
||||
void _clearRegisteredCallback();
|
||||
void clrCallback();
|
||||
|
||||
/**
|
||||
* Return whether service operation can be performed at this time
|
||||
*/
|
||||
int _canPerformServiceOperation();
|
||||
int canPerformServiceOperation();
|
||||
|
||||
/**
|
||||
* Set internal state flags
|
||||
*/
|
||||
void _setState(uint8_t newFlags);
|
||||
void setState(uint8_t newFlags);
|
||||
|
||||
/**
|
||||
* Clear internal state flags
|
||||
*/
|
||||
void _clrState(uint8_t newFlags);
|
||||
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
|
||||
bool getState(uint8_t testFlags);
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
|
||||
1514
src/NodeService.cpp
1514
src/NodeService.cpp
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
@@ -14,16 +14,20 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Header for ZeroTier Node Service (a distant relative of OneService)
|
||||
* ZeroTier Node Service
|
||||
*/
|
||||
|
||||
#ifndef ZT_NODE_SERVICE_HPP
|
||||
#define ZT_NODE_SERVICE_HPP
|
||||
#ifndef ZTS_NODE_SERVICE_HPP
|
||||
#define ZTS_NODE_SERVICE_HPP
|
||||
|
||||
#include "Binder.hpp"
|
||||
#include "Constants.hpp"
|
||||
#include "Events.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "PortMapper.hpp"
|
||||
#include "VirtualTap.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <string>
|
||||
@@ -31,8 +35,9 @@
|
||||
|
||||
#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.
|
||||
// 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
|
||||
@@ -46,15 +51,10 @@
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Local service for ZeroTier One as system VPN/NFV provider
|
||||
* ZeroTier node service
|
||||
*/
|
||||
class NodeService {
|
||||
public:
|
||||
uint16_t _userProvidedPort;
|
||||
std::string _userProvidedPath;
|
||||
char _userProvidedPublicIdentity[ZT_IDENTITY_STRING_BUFFER_LENGTH];
|
||||
char _userProvidedSecretIdentity[ZT_IDENTITY_STRING_BUFFER_LENGTH];
|
||||
|
||||
/**
|
||||
* Returned by node main if/when it terminates
|
||||
*/
|
||||
@@ -91,140 +91,455 @@ class NodeService {
|
||||
|
||||
/**
|
||||
* Whitelist of addresses that can be configured by this network.
|
||||
* If empty and allowManaged is true, allow all private/pseudoprivate addresses.
|
||||
* If empty and allowManaged is true, allow all
|
||||
* private/pseudoprivate addresses.
|
||||
*/
|
||||
std::vector<InetAddress> allowManagedWhitelist;
|
||||
|
||||
/**
|
||||
* Allow configuration of IPs and routes within global (Internet) IP space?
|
||||
* Allow configuration of IPs and routes within global (Internet) IP
|
||||
* space?
|
||||
*/
|
||||
bool allowGlobal;
|
||||
|
||||
/**
|
||||
* Allow overriding of system default routes for "full tunnel" operation?
|
||||
* Allow overriding of system default routes for "full tunnel"
|
||||
* operation?
|
||||
*/
|
||||
bool allowDefault;
|
||||
};
|
||||
|
||||
/**
|
||||
* @return Platform default home path or empty string if this platform doesn't have one
|
||||
*/
|
||||
static std::string platformDefaultHomePath();
|
||||
Phy<NodeService*> _phy;
|
||||
Node* _node;
|
||||
unsigned int _primaryPort = 0;
|
||||
unsigned int _secondaryPort = 0;
|
||||
unsigned int _tertiaryPort = 0;
|
||||
volatile unsigned int _udpPortPickerCounter;
|
||||
|
||||
/**
|
||||
* Create a new instance of the service
|
||||
std::map<uint64_t, unsigned int> peerCache;
|
||||
|
||||
// Local configuration and memo-ized information from it
|
||||
Hashtable<uint64_t, std::vector<InetAddress> > _v4Hints;
|
||||
Hashtable<uint64_t, std::vector<InetAddress> > _v6Hints;
|
||||
Hashtable<uint64_t, std::vector<InetAddress> > _v4Blacklists;
|
||||
Hashtable<uint64_t, std::vector<InetAddress> > _v6Blacklists;
|
||||
std::vector<InetAddress> _globalV4Blacklist;
|
||||
std::vector<InetAddress> _globalV6Blacklist;
|
||||
std::vector<InetAddress> _allowManagementFrom;
|
||||
std::vector<std::string> _interfacePrefixBlacklist;
|
||||
Mutex _localConfig_m;
|
||||
|
||||
std::vector<InetAddress> explicitBind;
|
||||
|
||||
/*
|
||||
* To attempt to handle NAT/gateway craziness we use three local UDP
|
||||
* ports:
|
||||
*
|
||||
* Once created, you must call the run() method to actually start
|
||||
* processing.
|
||||
* [0] is the normal/default port, usually 9993
|
||||
* [1] is a port derived from our ZeroTier address
|
||||
* [2] is a port computed from the normal/default for use with
|
||||
* uPnP/NAT-PMP mappings
|
||||
*
|
||||
* The port is saved to a file in the home path called zerotier-one.port,
|
||||
* which is used by the CLI and can be used to see which port was chosen if
|
||||
* 0 (random port) is picked.
|
||||
*
|
||||
* @param hp Home path
|
||||
* @param port TCP and UDP port for packets and HTTP control (if 0, pick random port)
|
||||
* [2] exists because on some gateways trying to do regular NAT-t
|
||||
* interferes destructively with uPnP port mapping behavior in very
|
||||
* weird buggy ways. It's only used if uPnP/NAT-PMP is enabled in this
|
||||
* build.
|
||||
*/
|
||||
static NodeService* newInstance(const char* hp, unsigned int port);
|
||||
unsigned int _ports[3] = { 0 };
|
||||
Binder _binder;
|
||||
|
||||
virtual ~NodeService();
|
||||
// Time we last received a packet from a global address
|
||||
uint64_t _lastDirectReceiveFromGlobal;
|
||||
|
||||
/**
|
||||
* Execute the service main I/O loop until terminated
|
||||
*
|
||||
* The terminate() method may be called from a signal handler or another
|
||||
* thread to terminate execution. Otherwise this will not return unless
|
||||
* another condition terminates execution such as a fatal error.
|
||||
*/
|
||||
virtual ReasonForTermination run() = 0;
|
||||
// Last potential sleep/wake event
|
||||
uint64_t _lastRestart;
|
||||
|
||||
/**
|
||||
* @return Reason for terminating or ONE_STILL_RUNNING if running
|
||||
*/
|
||||
virtual ReasonForTermination reasonForTermination() const = 0;
|
||||
// Deadline for the next background task service function
|
||||
volatile int64_t _nextBackgroundTaskDeadline;
|
||||
|
||||
/**
|
||||
* @return Fatal error message or empty string if none
|
||||
*/
|
||||
virtual std::string fatalErrorMessage() const = 0;
|
||||
|
||||
/**
|
||||
* @return System device name corresponding with a given ZeroTier network ID or empty string if
|
||||
* not opened yet or network ID not found
|
||||
*/
|
||||
virtual std::string portDeviceName(uint64_t nwid) const = 0;
|
||||
|
||||
/**
|
||||
* Whether we allow access to the service via local HTTP requests (disabled by default in libzt)
|
||||
*/
|
||||
bool allowHttpBackplaneManagement = false;
|
||||
|
||||
/**
|
||||
* @return Reference to the Node
|
||||
*/
|
||||
virtual Node* getNode() = 0;
|
||||
|
||||
/**
|
||||
* Fills out a structure with network-specific route information
|
||||
*/
|
||||
virtual void getRoutes(uint64_t nwid, void* routeArray, unsigned int* numRoutes) = 0;
|
||||
|
||||
virtual void join(uint64_t nwid) = 0;
|
||||
virtual void leave(uint64_t nwid) = 0;
|
||||
virtual void getIdentity(char* key_pair_str, uint16_t* key_buf_len) = 0;
|
||||
|
||||
/**
|
||||
* Terminate background service (can be called from other threads)
|
||||
*/
|
||||
virtual void terminate() = 0;
|
||||
|
||||
/**
|
||||
* Get local settings for a network
|
||||
*
|
||||
* @param nwid Network ID
|
||||
* @param settings Buffer to fill with local network settings
|
||||
* @return True if network was found and settings is filled
|
||||
*/
|
||||
virtual bool getNetworkSettings(const uint64_t nwid, NetworkSettings& settings) const = 0;
|
||||
|
||||
/**
|
||||
* @return True if service is still running
|
||||
*/
|
||||
inline bool isRunning() const
|
||||
// Configured networks
|
||||
struct NetworkState {
|
||||
NetworkState() : tap((VirtualTap*)0)
|
||||
{
|
||||
return (this->reasonForTermination() == ONE_STILL_RUNNING);
|
||||
// Real defaults are in network 'up' code in network event
|
||||
// handler
|
||||
settings.allowManaged = true;
|
||||
settings.allowGlobal = false;
|
||||
settings.allowDefault = false;
|
||||
}
|
||||
|
||||
protected:
|
||||
NodeService()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
NodeService(const NodeService& one)
|
||||
{
|
||||
}
|
||||
inline NodeService& operator=(const NodeService& one)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
VirtualTap* tap;
|
||||
ZT_VirtualNetworkConfig config; // memcpy() of raw config from core
|
||||
std::vector<InetAddress> managedIps;
|
||||
NetworkSettings settings;
|
||||
};
|
||||
std::map<uint64_t, NetworkState> _nets;
|
||||
|
||||
struct serviceParameters {
|
||||
int port;
|
||||
std::string path;
|
||||
char publicIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH];
|
||||
char secretIdentityStr[ZT_IDENTITY_STRING_BUFFER_LENGTH];
|
||||
};
|
||||
/** Lock to control access to network configuration data */
|
||||
Mutex _nets_m;
|
||||
/** Lock to control access to storage data */
|
||||
Mutex _store_m;
|
||||
/** Lock to control access to service run state */
|
||||
Mutex _run_m;
|
||||
// Set to false to force service to stop
|
||||
volatile bool _run;
|
||||
/** Lock to control access to termination reason */
|
||||
Mutex _termReason_m;
|
||||
// Termination status information
|
||||
ReasonForTermination _termReason;
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
DWORD WINAPI _runNodeService(LPVOID arg);
|
||||
#else
|
||||
/**
|
||||
* NodeService thread
|
||||
*/
|
||||
void* _runNodeService(void* arg);
|
||||
std::string _fatalErrorMessage;
|
||||
|
||||
// uPnP/NAT-PMP port mapper if enabled
|
||||
bool _portMappingEnabled; // local.conf settings
|
||||
#ifdef ZT_USE_MINIUPNPC
|
||||
PortMapper* _portMapper;
|
||||
#endif
|
||||
|
||||
/** Whether we allow caching network configs to storage */
|
||||
uint8_t _allowNetworkCaching;
|
||||
|
||||
/** Whether we allow caching peer hints to storage */
|
||||
uint8_t _allowPeerCaching;
|
||||
|
||||
char _publicIdStr[ZT_IDENTITY_STRING_BUFFER_LENGTH] = { 0 };
|
||||
char _secretIdStr[ZT_IDENTITY_STRING_BUFFER_LENGTH] = { 0 };
|
||||
char _planetData[ZTS_STORE_DATA_LEN] = { 0 };
|
||||
|
||||
/** Whether the node has successfully come online */
|
||||
bool _nodeIsOnline;
|
||||
|
||||
/** Whether we allow the NodeService to generate events for the user */
|
||||
bool _eventsEnabled;
|
||||
|
||||
/** Primary port defined by the user */
|
||||
uint16_t _userProvidedPort;
|
||||
|
||||
/** Storage path defined by the user */
|
||||
std::string _homePath;
|
||||
|
||||
/** System to ingest events from this class and emit them to the user */
|
||||
Events* _events;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
NodeService();
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~NodeService();
|
||||
|
||||
ReasonForTermination run();
|
||||
|
||||
ReasonForTermination reasonForTermination() const;
|
||||
|
||||
std::string fatalErrorMessage() const;
|
||||
|
||||
void getRoutes(uint64_t net_id, void* routeArray, unsigned int* numRoutes);
|
||||
|
||||
void terminate();
|
||||
|
||||
void uninitialize();
|
||||
|
||||
int getNetworkSettings(const uint64_t net_id, NetworkSettings& settings) const;
|
||||
|
||||
int checkIfManagedIsAllowed(const NetworkState& n, const InetAddress& target);
|
||||
|
||||
void syncManagedStuff(NetworkState& n);
|
||||
|
||||
void phyOnDatagram(
|
||||
PhySocket* sock,
|
||||
void** uptr,
|
||||
const struct sockaddr* localAddr,
|
||||
const struct sockaddr* from,
|
||||
void* data,
|
||||
unsigned long len);
|
||||
|
||||
int nodeVirtualNetworkConfigFunction(
|
||||
uint64_t net_id,
|
||||
void** nuptr,
|
||||
enum ZT_VirtualNetworkConfigOperation op,
|
||||
const ZT_VirtualNetworkConfig* nwc);
|
||||
|
||||
void nodeEventCallback(enum ZT_Event event, const void* metaData);
|
||||
zts_net_info_t* prepare_network_details_msg(const NetworkState& n);
|
||||
|
||||
void generateEventMsgs();
|
||||
|
||||
/** Join a network */
|
||||
int join(uint64_t net_id);
|
||||
|
||||
/** Leave a network */
|
||||
int leave(uint64_t net_id);
|
||||
|
||||
/** Return number of networks joined */
|
||||
int networkCount();
|
||||
|
||||
/** Orbit a moon */
|
||||
int orbit(void* tptr, uint64_t moonWorldId, uint64_t moonSeed);
|
||||
|
||||
/** De-orbit a moon */
|
||||
int deorbit(void* tptr, uint64_t moonWorldId);
|
||||
|
||||
uint64_t getNodeId();
|
||||
|
||||
int getIdentity(char* keypair, uint16_t* len);
|
||||
|
||||
int setIdentity(const char* keypair, uint16_t len);
|
||||
|
||||
void nodeStatePutFunction(
|
||||
enum ZT_StateObjectType type,
|
||||
const uint64_t id[2],
|
||||
const void* data,
|
||||
int len);
|
||||
|
||||
int nodeStateGetFunction(
|
||||
enum ZT_StateObjectType type,
|
||||
const uint64_t id[2],
|
||||
void* data,
|
||||
unsigned int maxlen);
|
||||
|
||||
int nodeWirePacketSendFunction(
|
||||
const int64_t localSocket,
|
||||
const struct sockaddr_storage* addr,
|
||||
const void* data,
|
||||
unsigned int len,
|
||||
unsigned int ttl);
|
||||
|
||||
void nodeVirtualNetworkFrameFunction(
|
||||
uint64_t net_id,
|
||||
void** nuptr,
|
||||
uint64_t sourceMac,
|
||||
uint64_t destMac,
|
||||
unsigned int etherType,
|
||||
unsigned int vlanId,
|
||||
const void* data,
|
||||
unsigned int len);
|
||||
|
||||
int nodePathCheckFunction(
|
||||
uint64_t ztaddr,
|
||||
const int64_t localSocket,
|
||||
const struct sockaddr_storage* remoteAddr);
|
||||
|
||||
int nodePathLookupFunction(uint64_t ztaddr, int family, struct sockaddr_storage* result);
|
||||
|
||||
void tapFrameHandler(
|
||||
uint64_t net_id,
|
||||
const MAC& from,
|
||||
const MAC& to,
|
||||
unsigned int etherType,
|
||||
unsigned int vlanId,
|
||||
const void* data,
|
||||
unsigned int len);
|
||||
|
||||
int shouldBindInterface(const char* ifname, const InetAddress& ifaddr);
|
||||
|
||||
int _trialBind(unsigned int port);
|
||||
|
||||
/** Return whether the NodeService is running */
|
||||
int isRunning();
|
||||
|
||||
/** Return whether the node is online */
|
||||
int nodeIsOnline();
|
||||
|
||||
/** Instruct the NodeService on where to look for identity files and caches */
|
||||
int setHomePath(const char* homePath);
|
||||
|
||||
/** Set the NodeService's primary port */
|
||||
int setPrimaryPort(unsigned short primaryPort);
|
||||
|
||||
/** Get the NodeService's primary port */
|
||||
unsigned short getPrimaryPort();
|
||||
|
||||
/** Set the event system instance used to convey messages to the user */
|
||||
int setUserEventSystem(Events* events);
|
||||
|
||||
/** Set the planet definition */
|
||||
int setPlanet(const char* data, int len);
|
||||
|
||||
/** Add Interface prefix to blacklist (prevents ZeroTier from using that interface) */
|
||||
int addInterfacePrefixToBlacklist(const char* prefix, int len);
|
||||
|
||||
/** Return the MAC Address of the node in the given network */
|
||||
uint64_t getMACAddress(uint64_t net_id);
|
||||
|
||||
int getNetworkName(uint64_t net_id, char* dst, int len);
|
||||
|
||||
int allowPeerCaching(int allowed);
|
||||
int allowNetworkCaching(int allowed);
|
||||
int getNetworkBroadcast(uint64_t net_id);
|
||||
int getNetworkMTU(uint64_t net_id);
|
||||
int getNetworkType(uint64_t net_id);
|
||||
int getNetworkStatus(uint64_t net_id);
|
||||
|
||||
int getFirstAssignedAddr(uint64_t net_id, int family, struct zts_sockaddr_storage* addr);
|
||||
|
||||
int getAllAssignedAddr(uint64_t net_id, struct zts_sockaddr_storage* addr, int* count);
|
||||
|
||||
int networkHasRoute(uint64_t net_id, int family);
|
||||
|
||||
int addrIsAssigned(uint64_t net_id, int family);
|
||||
|
||||
void phyOnTcpConnect(PhySocket* sock, void** uptr, bool success)
|
||||
{
|
||||
}
|
||||
void phyOnTcpAccept(
|
||||
PhySocket* sockL,
|
||||
PhySocket* sockN,
|
||||
void** uptrL,
|
||||
void** uptrN,
|
||||
const struct sockaddr* from)
|
||||
{
|
||||
}
|
||||
void phyOnTcpClose(PhySocket* sock, void** uptr)
|
||||
{
|
||||
}
|
||||
void phyOnTcpData(PhySocket* sock, void** uptr, void* data, unsigned long len)
|
||||
{
|
||||
}
|
||||
void phyOnTcpWritable(PhySocket* sock, void** uptr)
|
||||
{
|
||||
}
|
||||
void phyOnFileDescriptorActivity(PhySocket* sock, void** uptr, bool readable, bool writable)
|
||||
{
|
||||
}
|
||||
void phyOnUnixAccept(PhySocket* sockL, PhySocket* sockN, void** uptrL, void** uptrN)
|
||||
{
|
||||
}
|
||||
void phyOnUnixClose(PhySocket* sock, void** uptr)
|
||||
{
|
||||
}
|
||||
void phyOnUnixData(PhySocket* sock, void** uptr, void* data, unsigned long len)
|
||||
{
|
||||
}
|
||||
void phyOnUnixWritable(PhySocket* sock, void** uptr)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
static int SnodeVirtualNetworkConfigFunction(
|
||||
ZT_Node* node,
|
||||
void* uptr,
|
||||
void* tptr,
|
||||
uint64_t net_id,
|
||||
void** nuptr,
|
||||
enum ZT_VirtualNetworkConfigOperation op,
|
||||
const ZT_VirtualNetworkConfig* nwconf)
|
||||
{
|
||||
return reinterpret_cast<NodeService*>(uptr)
|
||||
->nodeVirtualNetworkConfigFunction(net_id, nuptr, op, nwconf);
|
||||
}
|
||||
|
||||
static void
|
||||
SnodeEventCallback(ZT_Node* node, void* uptr, void* tptr, enum ZT_Event event, const void* metaData)
|
||||
{
|
||||
reinterpret_cast<NodeService*>(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<NodeService*>(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<NodeService*>(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<NodeService*>(uptr)
|
||||
->nodeWirePacketSendFunction(localSocket, addr, data, len, ttl);
|
||||
}
|
||||
|
||||
static void SnodeVirtualNetworkFrameFunction(
|
||||
ZT_Node* node,
|
||||
void* uptr,
|
||||
void* tptr,
|
||||
uint64_t net_id,
|
||||
void** nuptr,
|
||||
uint64_t sourceMac,
|
||||
uint64_t destMac,
|
||||
unsigned int etherType,
|
||||
unsigned int vlanId,
|
||||
const void* data,
|
||||
unsigned int len)
|
||||
{
|
||||
reinterpret_cast<NodeService*>(uptr)->nodeVirtualNetworkFrameFunction(
|
||||
net_id,
|
||||
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<NodeService*>(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<NodeService*>(uptr)->nodePathLookupFunction(ztaddr, family, result);
|
||||
}
|
||||
|
||||
static void StapFrameHandler(
|
||||
void* uptr,
|
||||
void* tptr,
|
||||
uint64_t net_id,
|
||||
const MAC& from,
|
||||
const MAC& to,
|
||||
unsigned int etherType,
|
||||
unsigned int vlanId,
|
||||
const void* data,
|
||||
unsigned int len)
|
||||
{
|
||||
reinterpret_cast<NodeService*>(uptr)
|
||||
->tapFrameHandler(net_id, from, to, etherType, vlanId, data, len);
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
@@ -17,8 +17,8 @@
|
||||
* Custom signal handler
|
||||
*/
|
||||
|
||||
#ifndef SIGNALS_HPP
|
||||
#define SIGNALS_HPP
|
||||
#ifndef ZTS_SIGNALS_HPP
|
||||
#define ZTS_SIGNALS_HPP
|
||||
|
||||
#ifdef ZTS_ENABLE_PYTHON
|
||||
#define ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS 1
|
||||
|
||||
407
src/Sockets.cpp
407
src/Sockets.cpp
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
@@ -19,33 +19,28 @@
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#include "Events.hpp"
|
||||
#include "Utilities.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
#include "lwip/def.h"
|
||||
#include "lwip/dns.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/ip_addr.h"
|
||||
#include "lwip/netdb.h"
|
||||
#include "lwip/stats.h"
|
||||
|
||||
#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
|
||||
|
||||
extern int zts_errno;
|
||||
// errno-like reporting variable
|
||||
int zts_errno;
|
||||
extern int last_state_check;
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
extern uint8_t _serviceStateFlags;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int zts_socket(const int socket_family, const int socket_type, const int protocol)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_socket(socket_family, socket_type, protocol);
|
||||
@@ -53,21 +48,24 @@ int zts_socket(const int socket_family, const int socket_type, const int protoco
|
||||
|
||||
int zts_connect(int fd, const struct zts_sockaddr* addr, zts_socklen_t addrlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! addr) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
if (addrlen > (int)sizeof(struct zts_sockaddr_storage)
|
||||
|| addrlen < (int)sizeof(struct zts_sockaddr_in)) {
|
||||
if (addrlen > (zts_socklen_t)sizeof(struct zts_sockaddr_storage)
|
||||
|| addrlen < (zts_socklen_t)sizeof(struct zts_sockaddr_in)) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
return lwip_connect(fd, (sockaddr*)addr, addrlen);
|
||||
}
|
||||
|
||||
int zts_connect_easy(int fd, int family, char* ipstr, int port, int timeout_ms)
|
||||
int zts_simple_connect(int fd, const char* ipstr, int port, int timeout_ms)
|
||||
{
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (timeout_ms < 0) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
@@ -83,21 +81,17 @@ int zts_connect_easy(int fd, int family, char* ipstr, int port, int timeout_ms)
|
||||
struct zts_sockaddr_storage ss;
|
||||
struct zts_sockaddr* sa = NULL;
|
||||
|
||||
if (family == ZTS_AF_INET) {
|
||||
// Convert to standard address structure
|
||||
|
||||
addrlen = sizeof(ss);
|
||||
ipstr2sockaddr(family, ipstr, port, (struct zts_sockaddr*)&ss, &addrlen);
|
||||
zts_util_ipstr_to_saddr(ipstr, port, (struct zts_sockaddr*)&ss, &addrlen);
|
||||
sa = (struct zts_sockaddr*)&ss;
|
||||
}
|
||||
if (family == ZTS_AF_INET6) {
|
||||
addrlen = sizeof(ss);
|
||||
ipstr2sockaddr(family, ipstr, port, (struct zts_sockaddr*)&ss, &addrlen);
|
||||
sa = (struct zts_sockaddr*)&ss;
|
||||
}
|
||||
|
||||
if (addrlen > 0 && sa != NULL) {
|
||||
if (zts_get_blocking(fd)) {
|
||||
if (zts_simple_get_blocking(fd)) {
|
||||
do {
|
||||
err = zts_connect(fd, sa, addrlen);
|
||||
zts_delay_ms(connect_delay);
|
||||
zts_util_delay(connect_delay);
|
||||
n_tries--;
|
||||
} while ((err < 0) && (zts_errno != 0) && (n_tries > 0));
|
||||
}
|
||||
@@ -108,7 +102,7 @@ int zts_connect_easy(int fd, int family, char* ipstr, int port, int timeout_ms)
|
||||
|
||||
int zts_bind(int fd, const struct zts_sockaddr* addr, zts_socklen_t addrlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! addr) {
|
||||
@@ -121,28 +115,26 @@ int zts_bind(int fd, const struct zts_sockaddr* addr, zts_socklen_t addrlen)
|
||||
return lwip_bind(fd, (sockaddr*)addr, addrlen);
|
||||
}
|
||||
|
||||
int zts_bind_easy(int fd, int family, char* ipstr, int port)
|
||||
int zts_simple_bind(int fd, const char* ipstr, int port)
|
||||
{
|
||||
if (family == ZTS_AF_INET) {
|
||||
struct zts_sockaddr_in in4;
|
||||
zts_socklen_t addrlen = sizeof(in4);
|
||||
ipstr2sockaddr(family, ipstr, port, (struct zts_sockaddr*)&in4, &addrlen);
|
||||
struct zts_sockaddr* sa = (struct zts_sockaddr*)&in4;
|
||||
return zts_bind(fd, sa, addrlen);
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (family == ZTS_AF_INET6) {
|
||||
struct zts_sockaddr_in6 in6;
|
||||
zts_socklen_t addrlen = sizeof(in6);
|
||||
ipstr2sockaddr(family, ipstr, port, (struct zts_sockaddr*)&in6, &addrlen);
|
||||
struct zts_sockaddr* sa = (struct zts_sockaddr*)&in6;
|
||||
|
||||
zts_socklen_t addrlen = 0;
|
||||
struct zts_sockaddr_storage ss;
|
||||
struct zts_sockaddr* sa = NULL;
|
||||
|
||||
addrlen = sizeof(ss);
|
||||
zts_util_ipstr_to_saddr(ipstr, port, (struct zts_sockaddr*)&ss, &addrlen);
|
||||
sa = (struct zts_sockaddr*)&ss;
|
||||
|
||||
return zts_bind(fd, sa, addrlen);
|
||||
}
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
|
||||
int zts_listen(int fd, int backlog)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_listen(fd, backlog);
|
||||
@@ -150,20 +142,20 @@ int zts_listen(int fd, int backlog)
|
||||
|
||||
int zts_accept(int fd, struct zts_sockaddr* addr, zts_socklen_t* addrlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_accept(fd, (sockaddr*)addr, (socklen_t*)addrlen);
|
||||
}
|
||||
|
||||
int zts_accept_easy(int fd, char* remoteIpStr, int len, int* port)
|
||||
int zts_simple_accept(int fd, char* remote_addr, int len, int* port)
|
||||
{
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (len != ZTS_INET6_ADDRSTRLEN) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
char ipstr[ZTS_INET6_ADDRSTRLEN];
|
||||
memset(ipstr, 0, ZTS_INET6_ADDRSTRLEN);
|
||||
|
||||
zts_sockaddr_storage ss;
|
||||
zts_socklen_t addrlen = sizeof(ss);
|
||||
|
||||
@@ -171,20 +163,82 @@ int zts_accept_easy(int fd, char* remoteIpStr, int len, int* port)
|
||||
struct zts_sockaddr* sa = (struct zts_sockaddr*)&ss;
|
||||
if (sa->sa_family == ZTS_AF_INET) {
|
||||
struct zts_sockaddr_in* in4 = (struct zts_sockaddr_in*)sa;
|
||||
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), remoteIpStr, ZTS_INET_ADDRSTRLEN);
|
||||
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr), remote_addr, ZTS_INET_ADDRSTRLEN);
|
||||
*port = ntohs(in4->sin_port);
|
||||
}
|
||||
if (sa->sa_family == ZTS_AF_INET6) {
|
||||
struct zts_sockaddr_in6* in6 = (struct zts_sockaddr_in6*)sa;
|
||||
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), remoteIpStr, ZTS_INET6_ADDRSTRLEN);
|
||||
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr), remote_addr, ZTS_INET6_ADDRSTRLEN);
|
||||
*port = ntohs(in6->sin6_port);
|
||||
}
|
||||
return acc_fd;
|
||||
}
|
||||
|
||||
int zts_simple_tcp_client(const char* remote_ipstr, int remote_port)
|
||||
{
|
||||
int fd, family = zts_util_get_ip_family(remote_ipstr);
|
||||
if ((fd = zts_socket(family, ZTS_SOCK_STREAM, 0)) < 0) {
|
||||
return fd; // Failed to create socket
|
||||
}
|
||||
int timeout = 0;
|
||||
if ((fd = zts_simple_connect(fd, remote_ipstr, remote_port, timeout)) < 0) {
|
||||
zts_close(fd);
|
||||
return fd; // Failed to connect
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int zts_simple_tcp_server(
|
||||
const char* local_ipstr,
|
||||
int local_port,
|
||||
char* remote_ipstr,
|
||||
int len,
|
||||
int* remote_port)
|
||||
{
|
||||
int listen_fd, family = zts_util_get_ip_family(local_ipstr);
|
||||
if ((listen_fd = zts_socket(family, ZTS_SOCK_STREAM, 0)) < 0) {
|
||||
return listen_fd; // Failed to create socket
|
||||
}
|
||||
if ((listen_fd = zts_simple_bind(listen_fd, local_ipstr, local_port)) < 0) {
|
||||
return listen_fd; // Failed to bind
|
||||
}
|
||||
int backlog = 0;
|
||||
if ((listen_fd = zts_listen(listen_fd, backlog)) < 0) {
|
||||
return listen_fd; // Failed to listen
|
||||
}
|
||||
int acc_fd = 0;
|
||||
if ((acc_fd = zts_simple_accept(listen_fd, remote_ipstr, len, remote_port)) < 0) {
|
||||
return acc_fd; // Failed to accept
|
||||
}
|
||||
zts_close(listen_fd);
|
||||
return acc_fd;
|
||||
}
|
||||
|
||||
int zts_simple_udp_server(const char* local_ipstr, int local_port)
|
||||
{
|
||||
int fd, family = zts_util_get_ip_family(local_ipstr);
|
||||
if ((fd = zts_socket(family, ZTS_SOCK_DGRAM, 0)) < 0) {
|
||||
return fd; // Failed to create socket
|
||||
}
|
||||
if ((fd = zts_simple_bind(fd, local_ipstr, local_port)) < 0) {
|
||||
zts_close(fd);
|
||||
return fd; // Failed to connect
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int zts_simple_udp_client(const char* remote_ipstr)
|
||||
{
|
||||
int fd, family = zts_util_get_ip_family(remote_ipstr);
|
||||
if ((fd = zts_socket(family, ZTS_SOCK_DGRAM, 0)) < 0) {
|
||||
return fd; // Failed to create socket
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
int zts_setsockopt(int fd, int level, int optname, const void* optval, zts_socklen_t optlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_setsockopt(fd, level, optname, optval, optlen);
|
||||
@@ -192,7 +246,7 @@ int zts_setsockopt(int fd, int level, int optname, const void* optval, zts_sockl
|
||||
|
||||
int zts_getsockopt(int fd, int level, int optname, void* optval, zts_socklen_t* optlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_getsockopt(fd, level, optname, optval, (socklen_t*)optlen);
|
||||
@@ -200,7 +254,7 @@ int zts_getsockopt(int fd, int level, int optname, void* optval, zts_socklen_t*
|
||||
|
||||
int zts_getsockname(int fd, struct zts_sockaddr* addr, zts_socklen_t* addrlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! addr) {
|
||||
@@ -215,7 +269,7 @@ int zts_getsockname(int fd, struct zts_sockaddr* addr, zts_socklen_t* addrlen)
|
||||
|
||||
int zts_getpeername(int fd, struct zts_sockaddr* addr, zts_socklen_t* addrlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! addr) {
|
||||
@@ -230,7 +284,7 @@ int zts_getpeername(int fd, struct zts_sockaddr* addr, zts_socklen_t* addrlen)
|
||||
|
||||
int zts_close(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_close(fd);
|
||||
@@ -243,7 +297,7 @@ int zts_select(
|
||||
zts_fd_set* exceptfds,
|
||||
struct zts_timeval* timeout)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_select(
|
||||
@@ -256,7 +310,7 @@ int zts_select(
|
||||
|
||||
int zts_fcntl(int fd, int cmd, int flags)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_fcntl(fd, cmd, flags);
|
||||
@@ -264,7 +318,7 @@ int zts_fcntl(int fd, int cmd, int flags)
|
||||
|
||||
int zts_poll(struct zts_pollfd* fds, nfds_t nfds, int timeout)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_poll((pollfd*)fds, nfds, timeout);
|
||||
@@ -272,7 +326,7 @@ int zts_poll(struct zts_pollfd* fds, nfds_t nfds, int timeout)
|
||||
|
||||
int zts_ioctl(int fd, unsigned long request, void* argp)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! argp) {
|
||||
@@ -283,7 +337,7 @@ int zts_ioctl(int fd, unsigned long request, void* argp)
|
||||
|
||||
ssize_t zts_send(int fd, const void* buf, size_t len, int flags)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! buf) {
|
||||
@@ -300,7 +354,7 @@ ssize_t zts_sendto(
|
||||
const struct zts_sockaddr* addr,
|
||||
zts_socklen_t addrlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! addr || ! buf) {
|
||||
@@ -315,16 +369,15 @@ ssize_t zts_sendto(
|
||||
|
||||
ssize_t zts_sendmsg(int fd, const struct zts_msghdr* msg, int flags)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
|
||||
return lwip_sendmsg(fd, (const struct msghdr*)msg, flags);
|
||||
}
|
||||
|
||||
ssize_t zts_recv(int fd, void* buf, size_t len, int flags)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! buf) {
|
||||
@@ -341,7 +394,7 @@ ssize_t zts_recvfrom(
|
||||
struct zts_sockaddr* addr,
|
||||
zts_socklen_t* addrlen)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! buf) {
|
||||
@@ -352,7 +405,7 @@ ssize_t zts_recvfrom(
|
||||
|
||||
ssize_t zts_recvmsg(int fd, struct zts_msghdr* msg, int flags)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! msg) {
|
||||
@@ -363,7 +416,7 @@ ssize_t zts_recvmsg(int fd, struct zts_msghdr* msg, int flags)
|
||||
|
||||
ssize_t zts_read(int fd, void* buf, size_t len)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (! buf) {
|
||||
@@ -374,19 +427,17 @@ ssize_t zts_read(int fd, void* buf, size_t len)
|
||||
|
||||
ssize_t zts_readv(int fd, const struct zts_iovec* iov, int iovcnt)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
|
||||
return lwip_readv(fd, (iovec*)iov, iovcnt);
|
||||
}
|
||||
|
||||
ssize_t zts_write(int fd, const void* buf, size_t len)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
|
||||
if (! buf) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
@@ -395,16 +446,15 @@ ssize_t zts_write(int fd, const void* buf, size_t len)
|
||||
|
||||
ssize_t zts_writev(int fd, const struct zts_iovec* iov, int iovcnt)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
|
||||
return lwip_writev(fd, (iovec*)iov, iovcnt);
|
||||
}
|
||||
|
||||
int zts_shutdown(int fd, int how)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
return lwip_shutdown(fd, how);
|
||||
@@ -412,7 +462,7 @@ int zts_shutdown(int fd, int how)
|
||||
|
||||
struct zts_hostent* zts_gethostbyname(const char* name)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return NULL;
|
||||
}
|
||||
if (! name) {
|
||||
@@ -423,7 +473,7 @@ struct zts_hostent* zts_gethostbyname(const char* name)
|
||||
|
||||
int zts_dns_set_server(uint8_t index, const zts_ip_addr* addr)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
@@ -438,7 +488,7 @@ int zts_dns_set_server(uint8_t index, const zts_ip_addr* addr)
|
||||
|
||||
const zts_ip_addr* zts_dns_get_server(uint8_t index)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return NULL;
|
||||
}
|
||||
if (index >= DNS_MAX_SERVERS) {
|
||||
@@ -467,13 +517,14 @@ int zts_inet_pton(int family, const char* src, void* dst)
|
||||
return lwip_inet_pton(family, src, dst);
|
||||
}
|
||||
|
||||
int ipstr2sockaddr(
|
||||
int family,
|
||||
char* src_ipstr,
|
||||
int zts_util_ipstr_to_saddr(
|
||||
const char* src_ipstr,
|
||||
int port,
|
||||
struct zts_sockaddr* dest_addr,
|
||||
zts_socklen_t* addrlen)
|
||||
{
|
||||
int family = zts_util_get_ip_family(src_ipstr);
|
||||
|
||||
if (family == ZTS_AF_INET) {
|
||||
struct zts_sockaddr_in in4;
|
||||
in4.sin_port = htons(port);
|
||||
@@ -509,14 +560,15 @@ int ipstr2sockaddr(
|
||||
|
||||
/**
|
||||
* Helper functions that simplify API wrapper generation and usage in other
|
||||
* non-C-like languages. Use simple integer types instead of bit flags, limit
|
||||
* the number of operations each function performs, prevent the user from
|
||||
* needing to manipulate the content of structures in a non-native language.
|
||||
* non-C-like languages. Use simple integer types instead of bit flags,
|
||||
* limit the number of operations each function performs, prevent the user
|
||||
* from needing to manipulate the content of structures in a non-native
|
||||
* language.
|
||||
*/
|
||||
|
||||
int zts_set_no_delay(int fd, int enabled)
|
||||
int zts_simple_set_no_delay(int fd, int enabled)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (enabled != 0 && enabled != 1) {
|
||||
@@ -525,9 +577,9 @@ int zts_set_no_delay(int fd, int enabled)
|
||||
return zts_setsockopt(fd, ZTS_IPPROTO_TCP, ZTS_TCP_NODELAY, (void*)&enabled, sizeof(int));
|
||||
}
|
||||
|
||||
int zts_get_no_delay(int fd)
|
||||
int zts_simple_get_no_delay(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int err, optval = 0;
|
||||
@@ -538,9 +590,9 @@ int zts_get_no_delay(int fd)
|
||||
return optval != 0;
|
||||
}
|
||||
|
||||
int zts_set_linger(int fd, int enabled, int value)
|
||||
int zts_simple_set_linger(int fd, int enabled, int value)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (enabled != 0 && enabled != 1) {
|
||||
@@ -555,37 +607,37 @@ int zts_set_linger(int fd, int enabled, int value)
|
||||
return zts_setsockopt(fd, ZTS_SOL_SOCKET, ZTS_SO_LINGER, (void*)&linger, sizeof(linger));
|
||||
}
|
||||
|
||||
int zts_get_linger_enabled(int fd)
|
||||
int zts_simple_get_linger_enabled(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int err;
|
||||
struct zts_linger linger;
|
||||
zts_socklen_t len = sizeof(linger);
|
||||
int err;
|
||||
if ((err = zts_getsockopt(fd, ZTS_SOL_SOCKET, ZTS_SO_LINGER, (void*)&linger, &len)) < 0) {
|
||||
return err;
|
||||
}
|
||||
return linger.l_onoff;
|
||||
}
|
||||
|
||||
int zts_get_linger_value(int fd)
|
||||
int zts_simple_get_linger_value(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int err;
|
||||
struct zts_linger linger;
|
||||
zts_socklen_t len = sizeof(linger);
|
||||
int err;
|
||||
if ((err = zts_getsockopt(fd, ZTS_SOL_SOCKET, ZTS_SO_LINGER, (void*)&linger, &len)) < 0) {
|
||||
return err;
|
||||
}
|
||||
return linger.l_linger;
|
||||
}
|
||||
|
||||
int zts_set_reuse_addr(int fd, int enabled)
|
||||
int zts_simple_set_reuse_addr(int fd, int enabled)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (enabled != 0 && enabled != 1) {
|
||||
@@ -594,13 +646,12 @@ int zts_set_reuse_addr(int fd, int enabled)
|
||||
return zts_setsockopt(fd, ZTS_SOL_SOCKET, ZTS_SO_REUSEADDR, (void*)&enabled, sizeof(enabled));
|
||||
}
|
||||
|
||||
int zts_get_reuse_addr(int fd)
|
||||
int zts_simple_get_reuse_addr(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int err;
|
||||
int optval = 0;
|
||||
int err, optval = 0;
|
||||
zts_socklen_t optlen = sizeof(optval);
|
||||
if ((err = zts_getsockopt(fd, ZTS_SOL_SOCKET, ZTS_SO_REUSEADDR, (void*)&optval, &optlen)) < 0) {
|
||||
return err;
|
||||
@@ -608,9 +659,9 @@ int zts_get_reuse_addr(int fd)
|
||||
return optval != 0;
|
||||
}
|
||||
|
||||
int zts_set_recv_timeout(int fd, int seconds, int microseconds)
|
||||
int zts_simple_set_recv_timeout(int fd, int seconds, int microseconds)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (seconds < 0 || microseconds < 0) {
|
||||
@@ -622,9 +673,9 @@ int zts_set_recv_timeout(int fd, int seconds, int microseconds)
|
||||
return zts_setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void*)&tv, sizeof(tv));
|
||||
}
|
||||
|
||||
int zts_get_recv_timeout(int fd)
|
||||
int zts_simple_get_recv_timeout(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
struct timeval tv;
|
||||
@@ -636,9 +687,9 @@ int zts_get_recv_timeout(int fd)
|
||||
return tv.tv_sec; // TODO microseconds
|
||||
}
|
||||
|
||||
int zts_set_send_timeout(int fd, int seconds, int microseconds)
|
||||
int zts_simple_set_send_timeout(int fd, int seconds, int microseconds)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (seconds < 0 || microseconds < 0) {
|
||||
@@ -650,9 +701,9 @@ int zts_set_send_timeout(int fd, int seconds, int microseconds)
|
||||
return zts_setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (void*)&tv, sizeof(tv));
|
||||
}
|
||||
|
||||
int zts_get_send_timeout(int fd)
|
||||
int zts_simple_get_send_timeout(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
struct zts_timeval tv;
|
||||
@@ -664,9 +715,9 @@ int zts_get_send_timeout(int fd)
|
||||
return tv.tv_sec; // TODO microseconds
|
||||
}
|
||||
|
||||
int zts_set_send_buf_size(int fd, int size)
|
||||
int zts_simple_set_send_buf_size(int fd, int size)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (size < 0) {
|
||||
@@ -675,9 +726,9 @@ int zts_set_send_buf_size(int fd, int size)
|
||||
return zts_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (void*)&size, sizeof(int));
|
||||
}
|
||||
|
||||
int zts_get_send_buf_size(int fd)
|
||||
int zts_simple_get_send_buf_size(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int err, optval = 0;
|
||||
@@ -688,9 +739,9 @@ int zts_get_send_buf_size(int fd)
|
||||
return optval;
|
||||
}
|
||||
|
||||
int zts_set_recv_buf_size(int fd, int size)
|
||||
int zts_simple_set_recv_buf_size(int fd, int size)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (size < 0) {
|
||||
@@ -699,9 +750,9 @@ int zts_set_recv_buf_size(int fd, int size)
|
||||
return zts_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, (void*)&size, sizeof(int));
|
||||
}
|
||||
|
||||
int zts_get_recv_buf_size(int fd)
|
||||
int zts_simple_get_recv_buf_size(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int err, optval = 0;
|
||||
@@ -712,9 +763,9 @@ int zts_get_recv_buf_size(int fd)
|
||||
return optval;
|
||||
}
|
||||
|
||||
int zts_set_ttl(int fd, int ttl)
|
||||
int zts_simple_set_ttl(int fd, int ttl)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (ttl < 0 || ttl > 255) {
|
||||
@@ -723,9 +774,9 @@ int zts_set_ttl(int fd, int ttl)
|
||||
return zts_setsockopt(fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
|
||||
}
|
||||
|
||||
int zts_get_ttl(int fd)
|
||||
int zts_simple_get_ttl(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int err, ttl = 0;
|
||||
@@ -736,9 +787,9 @@ int zts_get_ttl(int fd)
|
||||
return ttl;
|
||||
}
|
||||
|
||||
int zts_set_blocking(int fd, int enabled)
|
||||
int zts_simple_set_blocking(int fd, int enabled)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (enabled != 0 && enabled != 1) {
|
||||
@@ -754,9 +805,9 @@ int zts_set_blocking(int fd, int enabled)
|
||||
}
|
||||
}
|
||||
|
||||
int zts_get_blocking(int fd)
|
||||
int zts_simple_get_blocking(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int flags = zts_fcntl(fd, ZTS_F_GETFL, 0);
|
||||
@@ -766,10 +817,9 @@ int zts_get_blocking(int fd)
|
||||
return ! (flags & ZTS_O_NONBLOCK);
|
||||
}
|
||||
|
||||
int zts_set_keepalive(int fd, int enabled)
|
||||
int zts_simple_set_keepalive(int fd, int enabled)
|
||||
{
|
||||
//
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
if (enabled != 0 && enabled != 1) {
|
||||
@@ -779,13 +829,12 @@ int zts_set_keepalive(int fd, int enabled)
|
||||
return zts_setsockopt(fd, ZTS_SOL_SOCKET, ZTS_SO_KEEPALIVE, &keepalive, sizeof(keepalive));
|
||||
}
|
||||
|
||||
int zts_get_keepalive(int fd)
|
||||
int zts_simple_get_keepalive(int fd)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
if (! transport_ok()) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
int err;
|
||||
int optval = 0;
|
||||
int err, optval = 0;
|
||||
zts_socklen_t optlen = sizeof(optval);
|
||||
if ((err = zts_getsockopt(fd, ZTS_SOL_SOCKET, ZTS_SO_KEEPALIVE, (void*)&optval, &optlen)) < 0) {
|
||||
return err;
|
||||
@@ -793,102 +842,6 @@ int zts_get_keepalive(int fd)
|
||||
return optval != 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Statistics //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifdef ZTS_ENABLE_STATS
|
||||
|
||||
extern struct stats_ lwip_stats;
|
||||
|
||||
int zts_get_all_stats(struct zts_stats* statsDest)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
#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
|
||||
}
|
||||
|
||||
int zts_get_protocol_stats(int protocolType, void* protoStatsDest)
|
||||
{
|
||||
if (! (_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
#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
|
||||
}
|
||||
|
||||
#endif // ZTS_ENABLE_STATS
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
92
src/Utilities.cpp
Normal file
92
src/Utilities.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c)2013-2021 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: 2026-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.
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include "Utilities.hpp"
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <windows.h>
|
||||
#elif _POSIX_C_SOURCE >= 199309L
|
||||
#include <time.h> // for nanosleep
|
||||
#else
|
||||
#include <unistd.h> // for usleep
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int zts_util_get_ip_family(const char* ipstr)
|
||||
{
|
||||
if (! ipstr) {
|
||||
return ZTS_ERR_ARG;
|
||||
}
|
||||
int family = -1;
|
||||
struct zts_sockaddr_in sa4;
|
||||
if (zts_inet_pton(ZTS_AF_INET, ipstr, &(sa4.sin_addr)) == 1) {
|
||||
family = ZTS_AF_INET;
|
||||
}
|
||||
struct zts_sockaddr_in6 sa6;
|
||||
if (zts_inet_pton(ZTS_AF_INET6, ipstr, &(sa6.sin6_addr)) == 1) {
|
||||
family = ZTS_AF_INET6;
|
||||
}
|
||||
return family;
|
||||
}
|
||||
|
||||
void zts_util_delay(long milliseconds)
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
Sleep(milliseconds);
|
||||
#elif _POSIX_C_SOURCE >= 199309L
|
||||
struct timespec ts;
|
||||
ts.tv_sec = milliseconds / 1000;
|
||||
ts.tv_nsec = (milliseconds % 1000) * 1000000;
|
||||
nanosleep(&ts, NULL);
|
||||
#else
|
||||
usleep(milliseconds * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
void native_ss_to_zts_ss(struct zts_sockaddr_storage* ss_out, const struct sockaddr_storage* ss_in)
|
||||
{
|
||||
if (ss_in->ss_family == AF_INET) {
|
||||
struct sockaddr_in* s_in4 = (struct sockaddr_in*)ss_in;
|
||||
struct zts_sockaddr_in* d_in4 = (struct zts_sockaddr_in*)ss_out;
|
||||
#ifndef __WINDOWS__
|
||||
d_in4->sin_len = 0; // s_in4->sin_len;
|
||||
#endif
|
||||
d_in4->sin_family = ZTS_AF_INET;
|
||||
d_in4->sin_port = s_in4->sin_port;
|
||||
memcpy(&(d_in4->sin_addr), &(s_in4->sin_addr), sizeof(s_in4->sin_addr));
|
||||
}
|
||||
if (ss_in->ss_family == AF_INET6) {
|
||||
struct sockaddr_in6* s_in6 = (struct sockaddr_in6*)ss_in;
|
||||
struct zts_sockaddr_in6* d_in6 = (struct zts_sockaddr_in6*)ss_out;
|
||||
#ifndef __WINDOWS__
|
||||
d_in6->sin6_len = 0; // s_in6->sin6_len;
|
||||
#endif
|
||||
d_in6->sin6_family = ZTS_AF_INET6;
|
||||
d_in6->sin6_port = s_in6->sin6_port;
|
||||
d_in6->sin6_flowinfo = s_in6->sin6_flowinfo;
|
||||
memcpy(&(d_in6->sin6_addr), &(s_in6->sin6_addr), sizeof(s_in6->sin6_addr));
|
||||
d_in6->sin6_scope_id = s_in6->sin6_scope_id;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
29
src/Utilities.hpp
Normal file
29
src/Utilities.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c)2013-2021 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: 2026-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 ZTS_UTILITIES_HPP
|
||||
#define ZTS_UTILITIES_HPP
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void native_ss_to_zts_ss(struct zts_sockaddr_storage* ss_out, const struct sockaddr_storage* ss_in);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // ZTS_UTILITIES_HPP
|
||||
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
@@ -14,7 +14,7 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Virtual ethernet tap device and combined network stack driver
|
||||
* Virtual Ethernet tap device and combined network stack driver
|
||||
*/
|
||||
|
||||
#include "Constants.hpp"
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "MAC.hpp"
|
||||
#include "MulticastGroup.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "lwip/etharp.h"
|
||||
#include "lwip/ethip6.h"
|
||||
#include "lwip/netif.h"
|
||||
@@ -33,7 +34,6 @@
|
||||
#include "lwip/stats.h"
|
||||
#endif
|
||||
|
||||
#include "Debug.hpp"
|
||||
#include "Events.hpp"
|
||||
#include "VirtualTap.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
@@ -49,18 +49,18 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
extern void _enqueueEvent(int16_t eventCode, void* arg = NULL);
|
||||
extern Events* zts_events;
|
||||
|
||||
/**
|
||||
* A virtual tap device. The ZeroTier core service creates one of these for each
|
||||
* virtual network joined. It will be destroyed upon leave().
|
||||
* Virtual tap device. ZeroTier will create one per joined network. It will
|
||||
* then be destroyed upon leaving the network.
|
||||
*/
|
||||
VirtualTap::VirtualTap(
|
||||
const char* homePath,
|
||||
const MAC& mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
uint64_t net_id,
|
||||
const char* friendlyName,
|
||||
void (*handler)(
|
||||
void*,
|
||||
@@ -81,13 +81,11 @@ VirtualTap::VirtualTap(
|
||||
, _run(true)
|
||||
, _mac(mac)
|
||||
, _mtu(mtu)
|
||||
, _nwid(nwid)
|
||||
, _net_id(net_id)
|
||||
, _unixListenSocket((PhySocket*)0)
|
||||
, _phy(this, false, true)
|
||||
{
|
||||
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;
|
||||
OSUtils::ztsnprintf(vtap_full_name, VTAP_NAME_LEN, "libzt-vtap-%llx", _net_id);
|
||||
#ifndef __WINDOWS__
|
||||
::pipe(_shutdownSignalPipe);
|
||||
#endif
|
||||
@@ -97,8 +95,8 @@ VirtualTap::VirtualTap(
|
||||
|
||||
VirtualTap::~VirtualTap()
|
||||
{
|
||||
struct zts_network_details* nd = new zts_network_details;
|
||||
nd->nwid = _nwid;
|
||||
zts_net_info_t* nd = new zts_net_info_t;
|
||||
nd->net_id = _net_id;
|
||||
_run = false;
|
||||
#ifndef __WINDOWS__
|
||||
::write(_shutdownSignalPipe[1], "\0", 1);
|
||||
@@ -108,7 +106,7 @@ VirtualTap::~VirtualTap()
|
||||
netif4 = NULL;
|
||||
_lwip_remove_netif(netif6);
|
||||
netif6 = NULL;
|
||||
_enqueueEvent(ZTS_EVENT_NETWORK_DOWN, (void*)nd);
|
||||
_events->enqueue(ZTS_EVENT_NETWORK_DOWN, (void*)nd);
|
||||
Thread::join(_thread);
|
||||
#ifndef __WINDOWS__
|
||||
::close(_shutdownSignalPipe[0]);
|
||||
@@ -131,6 +129,11 @@ bool VirtualTap::enabled() const
|
||||
return _enabled;
|
||||
}
|
||||
|
||||
void VirtualTap::setUserEventSystem(Events* events)
|
||||
{
|
||||
_events = events;
|
||||
}
|
||||
|
||||
bool VirtualTap::hasIpv4Addr()
|
||||
{
|
||||
Mutex::Lock _l(_ips_m);
|
||||
@@ -159,21 +162,21 @@ bool VirtualTap::hasIpv6Addr()
|
||||
|
||||
bool VirtualTap::addIp(const InetAddress& ip)
|
||||
{
|
||||
char ipbuf[128];
|
||||
// ip.toString(ipbuf);
|
||||
// DEBUG_INFO("addr=%s", ipbuf);
|
||||
|
||||
// TODO: Rewrite to allow for more addresses
|
||||
char ipbuf[128] = { 0 };
|
||||
/* Limit address assignments to one per type.
|
||||
This limitation can be removed if some changes
|
||||
are made in the netif driver. */
|
||||
if (ip.isV4() && hasIpv4Addr()) {
|
||||
ip.toString(ipbuf);
|
||||
DEBUG_INFO("failed to add IP (%s), only one per type per netif allowed\n", ipbuf);
|
||||
// DEBUG_INFO("failed to add IP (%s), only one per type per netif
|
||||
// allowed\n", ipbuf);
|
||||
return false;
|
||||
}
|
||||
if (ip.isV6() && hasIpv6Addr()) {
|
||||
ip.toString(ipbuf);
|
||||
DEBUG_INFO("failed to add IP (%s), only one per type per netif allowed\n", ipbuf);
|
||||
// DEBUG_INFO("failed to add IP (%s), only one per type per netif
|
||||
// allowed\n", ipbuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,16 +221,6 @@ void VirtualTap::put(
|
||||
}
|
||||
}
|
||||
|
||||
std::string VirtualTap::deviceName() const
|
||||
{
|
||||
return _dev;
|
||||
}
|
||||
|
||||
void VirtualTap::setFriendlyName(const char* friendlyName)
|
||||
{
|
||||
DEBUG_INFO("%s", friendlyName);
|
||||
}
|
||||
|
||||
void VirtualTap::scanMulticastGroups(
|
||||
std::vector<MulticastGroup>& added,
|
||||
std::vector<MulticastGroup>& removed)
|
||||
@@ -299,10 +292,13 @@ void VirtualTap::phyOnDatagram(
|
||||
void* data,
|
||||
unsigned long len)
|
||||
{
|
||||
// Intentionally empty
|
||||
}
|
||||
|
||||
void VirtualTap::phyOnTcpConnect(PhySocket* sock, void** uptr, bool success)
|
||||
{
|
||||
}
|
||||
|
||||
void VirtualTap::phyOnTcpAccept(
|
||||
PhySocket* sockL,
|
||||
PhySocket* sockN,
|
||||
@@ -311,22 +307,26 @@ void VirtualTap::phyOnTcpAccept(
|
||||
const struct sockaddr* from)
|
||||
{
|
||||
}
|
||||
|
||||
void VirtualTap::phyOnTcpClose(PhySocket* sock, void** uptr)
|
||||
{
|
||||
}
|
||||
|
||||
void VirtualTap::phyOnTcpData(PhySocket* sock, void** uptr, void* data, unsigned long len)
|
||||
{
|
||||
}
|
||||
|
||||
void VirtualTap::phyOnTcpWritable(PhySocket* sock, void** uptr)
|
||||
{
|
||||
}
|
||||
|
||||
void VirtualTap::phyOnUnixClose(PhySocket* sock, void** uptr)
|
||||
{
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//----------------------------------------------------------------------------//
|
||||
// Netif driver code for lwIP network stack //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
bool _has_exited = false;
|
||||
bool _has_started = false;
|
||||
@@ -342,39 +342,39 @@ static void _tcpip_init_done(void* arg)
|
||||
{
|
||||
sys_sem_t* sem;
|
||||
sem = (sys_sem_t*)arg;
|
||||
_setState(ZTS_STATE_STACK_RUNNING);
|
||||
zts_events->setState(ZTS_STATE_STACK_RUNNING);
|
||||
_has_started = true;
|
||||
_enqueueEvent(ZTS_EVENT_STACK_UP);
|
||||
zts_events->enqueue(ZTS_EVENT_STACK_UP, NULL);
|
||||
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);
|
||||
pthread_setname_np(pthread_self(), ZTS_LWIP_THREAD_NAME);
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
pthread_setname_np(ZTS_LWIP_DRIVER_THREAD_NAME);
|
||||
pthread_setname_np(ZTS_LWIP_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");
|
||||
// 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);
|
||||
while (zts_events->getState(ZTS_STATE_STACK_RUNNING)) {
|
||||
zts_util_delay(LWIP_DRIVER_LOOP_INTERVAL);
|
||||
}
|
||||
_has_exited = true;
|
||||
_enqueueEvent(ZTS_EVENT_STACK_DOWN);
|
||||
zts_events->enqueue(ZTS_EVENT_STACK_DOWN, NULL);
|
||||
}
|
||||
|
||||
bool _lwip_is_up()
|
||||
{
|
||||
Mutex::Lock _l(stackLock);
|
||||
return _getState(ZTS_STATE_STACK_RUNNING);
|
||||
return zts_events->getState(ZTS_STATE_STACK_RUNNING);
|
||||
}
|
||||
|
||||
void _lwip_driver_init()
|
||||
@@ -390,7 +390,7 @@ void _lwip_driver_init()
|
||||
sys_init(); // Required for win32 init of critical sections
|
||||
#endif
|
||||
sys_thread_new(
|
||||
ZTS_LWIP_DRIVER_THREAD_NAME,
|
||||
ZTS_LWIP_THREAD_NAME,
|
||||
_main_lwip_driver_loop,
|
||||
NULL,
|
||||
DEFAULT_THREAD_STACKSIZE,
|
||||
@@ -404,11 +404,11 @@ void _lwip_driver_shutdown()
|
||||
}
|
||||
Mutex::Lock _l(stackLock);
|
||||
// Set flag to stop sending frames into the core
|
||||
_clrState(ZTS_STATE_STACK_RUNNING);
|
||||
zts_events->clrState(ZTS_STATE_STACK_RUNNING);
|
||||
// Wait until the main lwIP thread has exited
|
||||
if (_has_started) {
|
||||
while (! _has_exited) {
|
||||
zts_delay_ms(LWIP_DRIVER_LOOP_INTERVAL);
|
||||
zts_util_delay(LWIP_DRIVER_LOOP_INTERVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -432,7 +432,7 @@ err_t _lwip_eth_tx(struct netif* n, struct pbuf* p)
|
||||
return ERR_IF;
|
||||
}
|
||||
struct pbuf* q;
|
||||
char buf[ZT_MAX_MTU + 32];
|
||||
char buf[ZT_MAX_MTU + 32] = { 0 };
|
||||
char* bufptr;
|
||||
int totalLength = 0;
|
||||
|
||||
@@ -454,29 +454,8 @@ err_t _lwip_eth_tx(struct netif* n, struct pbuf* p)
|
||||
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);
|
||||
*/
|
||||
}
|
||||
tap->_handler(tap->_arg, NULL, tap->_net_id, src_mac, dest_mac, proto, 0, data, len);
|
||||
|
||||
return ERR_OK;
|
||||
}
|
||||
|
||||
@@ -491,7 +470,7 @@ void _lwip_eth_rx(
|
||||
#ifdef LWIP_STATS
|
||||
stats_display();
|
||||
#endif
|
||||
if (! _getState(ZTS_STATE_STACK_RUNNING)) {
|
||||
if (! zts_events->getState(ZTS_STATE_STACK_RUNNING)) {
|
||||
return;
|
||||
}
|
||||
struct pbuf *p, *q;
|
||||
@@ -500,40 +479,19 @@ void _lwip_eth_rx(
|
||||
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");
|
||||
// DEBUG_ERROR("dropped packet: unable to allocate memory for
|
||||
// pbuf");
|
||||
return;
|
||||
}
|
||||
// First pbuf gets ethernet header at start
|
||||
// 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");
|
||||
// DEBUG_ERROR("dropped packet: first pbuf smaller than Ethernet
|
||||
// header");
|
||||
return;
|
||||
}
|
||||
// Copy frame data into pbuf
|
||||
@@ -554,7 +512,7 @@ void _lwip_eth_rx(
|
||||
if (tap->netif4) {
|
||||
if ((err = ((struct netif*)tap->netif4)->input(p, (struct netif*)tap->netif4))
|
||||
!= ERR_OK) {
|
||||
DEBUG_ERROR("packet input error (%d)", err);
|
||||
// DEBUG_ERROR("packet input error (%d)", err);
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
@@ -563,7 +521,7 @@ void _lwip_eth_rx(
|
||||
if (tap->netif6) {
|
||||
if ((err = ((struct netif*)tap->netif6)->input(p, (struct netif*)tap->netif6))
|
||||
!= ERR_OK) {
|
||||
DEBUG_ERROR("packet input error (%d)", err);
|
||||
// DEBUG_ERROR("packet input error (%d)", err);
|
||||
pbuf_free(p);
|
||||
}
|
||||
}
|
||||
@@ -581,59 +539,6 @@ bool _lwip_is_netif_up(void* n)
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
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 *details = new zts_netif_details();
|
||||
details->nwid = tap->_nwid;
|
||||
memcpy(&(details->mac), n->hwaddr, n->hwaddr_len);
|
||||
details->mtu = n->mtu;
|
||||
return details;
|
||||
}
|
||||
|
||||
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;
|
||||
struct zts_netif_details *details = new zts_netif_details();
|
||||
details->nwid = tap->_nwid;
|
||||
details->mac = 0;
|
||||
details->mtu = 0;
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_REMOVED, (void*)details);
|
||||
}
|
||||
|
||||
static void _netif_status_callback(struct netif *n)
|
||||
{
|
||||
// Called from core, no need to lock
|
||||
if (!n) {
|
||||
return;
|
||||
} if (netif_is_up(n)) {
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_UP, (void*)_lwip_prepare_netif_status_msg(n));
|
||||
} else {
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_DOWN, (void*)_lwip_prepare_netif_status_msg(n));
|
||||
}
|
||||
}
|
||||
|
||||
static void _netif_link_callback(struct netif *n)
|
||||
{
|
||||
// Called from core, no need to lock
|
||||
if (!n) {
|
||||
return;
|
||||
} if (netif_is_link_up(n)) {
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_LINK_UP, (void*)_lwip_prepare_netif_status_msg(n));
|
||||
} else {
|
||||
_enqueueEvent(ZTS_EVENT_NETIF_LINK_DOWN, (void*)_lwip_prepare_netif_status_msg(n));
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
static err_t _netif_init4(struct netif* n)
|
||||
{
|
||||
if (! n || ! n->state) {
|
||||
@@ -676,7 +581,7 @@ static err_t _netif_init6(struct netif* n)
|
||||
|
||||
void _lwip_init_interface(void* tapref, const InetAddress& ip)
|
||||
{
|
||||
char macbuf[ZTS_MAC_ADDRSTRLEN];
|
||||
char macbuf[ZTS_MAC_ADDRSTRLEN] = { 0 };
|
||||
|
||||
VirtualTap* vtap = (VirtualTap*)tapref;
|
||||
struct netif* n = NULL;
|
||||
@@ -691,11 +596,7 @@ void _lwip_init_interface(void* tapref, const InetAddress& ip)
|
||||
isNewNetif = true;
|
||||
netifCount++;
|
||||
}
|
||||
/*
|
||||
netif_set_status_callback(n, _netif_status_callback);
|
||||
netif_set_remove_callback(n, _netif_remove_callback);
|
||||
netif_set_link_callback(n, _netif_link_callback);
|
||||
*/
|
||||
|
||||
static ip4_addr_t ip4, netmask, gw;
|
||||
IP4_ADDR(&gw, 127, 0, 0, 1);
|
||||
ip4.addr = *((u32_t*)ip.rawIpData());
|
||||
@@ -714,12 +615,6 @@ void _lwip_init_interface(void* tapref, const InetAddress& ip)
|
||||
n->hwaddr[3],
|
||||
n->hwaddr[4],
|
||||
n->hwaddr[5]);
|
||||
/*
|
||||
char nmbuf[INET6_ADDRSTRLEN];
|
||||
char ipbuf[INET6_ADDRSTRLEN];
|
||||
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) {
|
||||
@@ -729,11 +624,7 @@ void _lwip_init_interface(void* tapref, const InetAddress& ip)
|
||||
n = new struct netif;
|
||||
isNewNetif = true;
|
||||
netifCount++;
|
||||
} /*
|
||||
netif_set_status_callback(n, _netif_status_callback);
|
||||
netif_set_remove_callback(n, _netif_remove_callback);
|
||||
netif_set_link_callback(n, _netif_link_callback);
|
||||
*/
|
||||
}
|
||||
static ip6_addr_t ip6;
|
||||
memcpy(&(ip6.addr), ip.rawIpData(), sizeof(ip6.addr));
|
||||
LOCK_TCPIP_CORE();
|
||||
@@ -760,10 +651,6 @@ void _lwip_init_interface(void* tapref, const InetAddress& ip)
|
||||
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);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 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: 2025-01-01
|
||||
* Change Date: 2026-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.
|
||||
@@ -14,16 +14,18 @@
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Header for virtual ethernet tap device and combined network stack driver
|
||||
* Header for virtual Ethernet tap device and combined network stack driver
|
||||
*/
|
||||
|
||||
#ifndef ZT_VIRTUAL_TAP_HPP
|
||||
#define ZT_VIRTUAL_TAP_HPP
|
||||
#ifndef ZTS_VIRTUAL_TAP_HPP
|
||||
#define ZTS_VIRTUAL_TAP_HPP
|
||||
|
||||
#include "lwip/err.h"
|
||||
|
||||
#define ZTS_LWIP_DRIVER_THREAD_NAME "ZTNetworkStackThread"
|
||||
#define ZTS_LWIP_THREAD_NAME "ZTNetworkStackThread"
|
||||
#define VTAP_NAME_LEN 64
|
||||
|
||||
#include "Events.hpp"
|
||||
#include "MAC.hpp"
|
||||
#include "Phy.hpp"
|
||||
#include "Thread.hpp"
|
||||
@@ -36,8 +38,8 @@ class MulticastGroup;
|
||||
struct InetAddress;
|
||||
|
||||
/**
|
||||
* A virtual tap device. The ZeroTier Node Service will create one per
|
||||
* joined network. It will be destroyed upon leave().
|
||||
* Virtual tap device. ZeroTier will create one per joined network. It will
|
||||
* then be destroyed upon leaving the network.
|
||||
*/
|
||||
class VirtualTap {
|
||||
friend class Phy<VirtualTap*>;
|
||||
@@ -48,7 +50,7 @@ class VirtualTap {
|
||||
const MAC& mac,
|
||||
unsigned int mtu,
|
||||
unsigned int metric,
|
||||
uint64_t nwid,
|
||||
uint64_t net_id,
|
||||
const char* friendlyName,
|
||||
void (*handler)(
|
||||
void*,
|
||||
@@ -67,10 +69,18 @@ class VirtualTap {
|
||||
void setEnabled(bool en);
|
||||
bool enabled() const;
|
||||
|
||||
/**
|
||||
* System to ingest events from this class and emit them to the user
|
||||
*/
|
||||
Events* _events;
|
||||
|
||||
/**
|
||||
* Mutex for protecting IP address container for this tap.
|
||||
*/
|
||||
Mutex _ips_m; // Public because we want it accessible by the driver layer
|
||||
Mutex _ips_m; // Public because we want it accessible by the driver
|
||||
// layer
|
||||
|
||||
void setUserEventSystem(Events* events);
|
||||
|
||||
/**
|
||||
* Return whether this tap has been assigned an IPv4 address.
|
||||
@@ -83,13 +93,15 @@ class VirtualTap {
|
||||
bool hasIpv6Addr();
|
||||
|
||||
/**
|
||||
* Adds an address to the user-space 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 user-space stack interface associated with this VirtualTap
|
||||
* Removes an address from the user-space stack interface associated
|
||||
* with this VirtualTap
|
||||
*/
|
||||
bool removeIp(const InetAddress& ip);
|
||||
|
||||
@@ -99,16 +111,6 @@ class VirtualTap {
|
||||
void
|
||||
put(const MAC& from, const MAC& to, unsigned int etherType, const void* data, unsigned int len);
|
||||
|
||||
/**
|
||||
* Get VirtualTap device name (e.g. 'libzt17d72843bc2c5760')
|
||||
*/
|
||||
std::string deviceName() const;
|
||||
|
||||
/**
|
||||
* Set friendly name
|
||||
*/
|
||||
void setFriendlyName(const char* friendlyName);
|
||||
|
||||
/**
|
||||
* Scan multicast groups
|
||||
*/
|
||||
@@ -142,16 +144,15 @@ class VirtualTap {
|
||||
void* netif4 = NULL;
|
||||
void* netif6 = NULL;
|
||||
|
||||
/**
|
||||
* The last time that this virtual tap received a network config update from the core
|
||||
*/
|
||||
// The last time that this virtual tap received a network config update
|
||||
// from the core
|
||||
uint64_t _lastConfigUpdateTime = 0;
|
||||
|
||||
void lastConfigUpdate(uint64_t lastConfigUpdateTime);
|
||||
|
||||
int _networkStatus = 0;
|
||||
|
||||
char vtap_full_name[64];
|
||||
char vtap_full_name[VTAP_NAME_LEN] = { 0 };
|
||||
|
||||
std::vector<InetAddress> ips() const;
|
||||
std::vector<InetAddress> _ips;
|
||||
@@ -163,22 +164,20 @@ class VirtualTap {
|
||||
volatile bool _run;
|
||||
MAC _mac;
|
||||
unsigned int _mtu;
|
||||
uint64_t _nwid;
|
||||
uint64_t _net_id;
|
||||
PhySocket* _unixListenSocket;
|
||||
Phy<VirtualTap*> _phy;
|
||||
|
||||
Thread _thread;
|
||||
|
||||
int _shutdownSignalPipe[2];
|
||||
|
||||
std::string _dev; // path to Unix domain socket
|
||||
int _shutdownSignalPipe[2] = { 0 };
|
||||
|
||||
std::vector<MulticastGroup> _multicastGroups;
|
||||
Mutex _multicastGroups_m;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//----------------------------------------------------------------------------//
|
||||
// Not used in this implementation //
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
void phyOnDatagram(
|
||||
PhySocket* sock,
|
||||
@@ -210,7 +209,8 @@ 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
|
||||
* @usage This should be called when we know the stack won't be used by any
|
||||
* virtual taps
|
||||
*/
|
||||
void _lwip_hibernate_driver();
|
||||
|
||||
@@ -229,17 +229,19 @@ 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
|
||||
* @usage This is called during the initial setup of each VirtualTap but is
|
||||
* only allowed to execute once
|
||||
*/
|
||||
void _lwip_driver_init();
|
||||
|
||||
/**
|
||||
* @brief Shutdown the stack as completely as possible (not officially supported by lwIP)
|
||||
* @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.
|
||||
* @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.
|
||||
*/
|
||||
void _lwip_driver_shutdown();
|
||||
|
||||
@@ -280,7 +282,8 @@ static void _netif_link_callback(struct netif* netif);
|
||||
/**
|
||||
* @brief Set up an interface in the network stack for the VirtualTap.
|
||||
*
|
||||
* @param tapref Reference to VirtualTap that will be responsible for sending and receiving data
|
||||
* @param tapref Reference to VirtualTap that will be responsible for
|
||||
* sending and receiving data
|
||||
* @param ip Virtual IP address for this ZeroTier VirtualTap interface
|
||||
*/
|
||||
void _lwip_init_interface(void* tapref, const InetAddress& ip);
|
||||
@@ -294,12 +297,13 @@ void _lwip_init_interface(void* tapref, const InetAddress& ip);
|
||||
void _lwip_remove_address_from_netif(void* tapref, const InetAddress& ip);
|
||||
|
||||
/**
|
||||
* @brief Called from the stack, outbound ethernet frames from the network stack enter the ZeroTier
|
||||
* virtual wire here.
|
||||
* @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
|
||||
* @usage This shall only be called from the stack or the stack driver. Not
|
||||
* the application thread.
|
||||
* @param netif Transmits an outgoing Ethernet frame from the network stack
|
||||
* onto the ZeroTier virtual wire
|
||||
* @param p A pointer to the beginning of a chain pf struct pbufs
|
||||
* @return
|
||||
*/
|
||||
@@ -308,10 +312,12 @@ 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())
|
||||
* @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 to Intended destination address (virtual ZeroTier hardware
|
||||
* address)
|
||||
* @param etherType Protocol type
|
||||
* @param data Pointer to Ethernet frame
|
||||
* @param len Length of Ethernet frame
|
||||
|
||||
@@ -1,835 +0,0 @@
|
||||
/**
|
||||
* Selftest. To be run for every commit.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <ZeroTierSockets.h>
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wunused-value"
|
||||
|
||||
int random32() {
|
||||
const int BITS_PER_RAND = (int)(log2(RAND_MAX/2 + 1) + 1.0);
|
||||
int ret = 0;
|
||||
for (int i = 0; i < sizeof(int) * CHAR_BIT; i += BITS_PER_RAND) {
|
||||
ret <<= BITS_PER_RAND;
|
||||
ret |= rand();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint64_t random64() {
|
||||
return ((uint64_t)random32() << 32) | random32();
|
||||
}
|
||||
|
||||
int is_online = 0;
|
||||
int has_ip4 = 0;
|
||||
int has_ip6 = 0;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Event Handler //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
void on_zts_event(void *msgPtr)
|
||||
{
|
||||
struct zts_callback_msg *msg = (struct zts_callback_msg *)msgPtr;
|
||||
fprintf(stderr, "event=%d\n", msg->eventCode);
|
||||
if (msg->eventCode == ZTS_EVENT_NODE_ONLINE) {
|
||||
fprintf(stderr, "ZTS_EVENT_NODE_ONLINE\n");
|
||||
is_online = 1;
|
||||
}
|
||||
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP4) {
|
||||
fprintf(stderr, "ZTS_EVENT_NETWORK_READY_IP4\n");
|
||||
has_ip4 = 1;
|
||||
}
|
||||
if (msg->eventCode == ZTS_EVENT_NETWORK_READY_IP6) {
|
||||
fprintf(stderr, "ZTS_EVENT_NETWORK_READY_IP6\n");
|
||||
has_ip6 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void api_value_arg_test(
|
||||
int8_t i8, int16_t i16, int32_t i32, int64_t i64, void* nullable)
|
||||
{
|
||||
//fprintf(stderr, "%d, %d, %d, %lld, %p\n", i8, i16, i32, i64, nullable);
|
||||
int res = ZTS_ERR_OK;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test uninitialized Network Stack API usage //
|
||||
//----------------------------------------------------------------------------//
|
||||
/*
|
||||
res = zts_get_all_stats((struct zts_stats *)nullable);
|
||||
assert(("pre-init call to zts_get_all_stats(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_get_protocol_stats(i32, nullable);
|
||||
assert(("pre-init call to zts_get_protocol_stats(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
*/
|
||||
res = zts_dns_set_server(i8, (const zts_ip_addr *)nullable);
|
||||
assert(("pre-init call to zts_add_dns_nameserver(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
const zts_ip_addr *res_ptr = zts_dns_get_server(i8);
|
||||
assert(("pre-init call to zts_del_dns_nameserver(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test uninitialized Node API usage //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
res = zts_stop();
|
||||
assert(("pre-init call to zts_stop(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_restart();
|
||||
assert(("pre-init call to zts_restart(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_free();
|
||||
assert(("pre-init call to zts_free(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_join(i64);
|
||||
assert(("pre-init call to zts_join(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_leave(i64);
|
||||
assert(("pre-init call to zts_leave(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_orbit(i64,i64);
|
||||
assert(("pre-init call to zts_orbit(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_deorbit(i64);
|
||||
assert(("pre-init call to zts_deorbit(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test uninitialized Socket API usage //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
res = zts_socket(i32,i32,i32);
|
||||
assert(("pre-init call to zts_socket(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_connect(i32, (const struct zts_sockaddr *)nullable, i32);
|
||||
assert(("pre-init call to zts_connect(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_bind(i32, (const struct zts_sockaddr *)nullable, i32);
|
||||
assert(("pre-init call to zts_bind(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_listen(i32, i32);
|
||||
assert(("pre-init call to zts_listen(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_accept(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable);
|
||||
assert(("pre-init call to zts_accept(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_setsockopt(i32, i32, i32, nullable, i32);
|
||||
assert(("pre-init call to zts_setsockopt(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_getsockopt(i32, i32, i32, nullable, (zts_socklen_t *)nullable);
|
||||
assert(("pre-init call to zts_getsockopt(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_getsockname(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable);
|
||||
assert(("pre-init call to zts_getsockname(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_getpeername(i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable);
|
||||
assert(("pre-init call to zts_getpeername(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_close(i32);
|
||||
assert(("pre-init call to zts_close(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_select(i32, (zts_fd_set *)nullable, (zts_fd_set *)nullable, (zts_fd_set *)nullable, (struct zts_timeval *)nullable);
|
||||
assert(("pre-init call to zts_select(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_fcntl(i32, i32, i32);
|
||||
assert(("pre-init call to zts_fcntl(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_poll((struct zts_pollfd *)nullable, i32, i32);
|
||||
assert(("pre-init call to zts_poll(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_ioctl(i32, i64, nullable);
|
||||
assert(("pre-init call to zts_ioctl(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_send(i32, nullable, i32, i32);
|
||||
assert(("pre-init call to zts_send(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_sendto(i32, nullable, i32, i32, (const struct zts_sockaddr *)nullable, i32);
|
||||
assert(("pre-init call to zts_sendto(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_sendmsg(i32, (const struct zts_msghdr *)nullable, i32);
|
||||
assert(("pre-init call to zts_sendmsg(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_recv(i32, nullable, i32, i32);
|
||||
assert(("pre-init call to zts_recv(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_recvfrom(i32, nullable, i32, i32, (struct zts_sockaddr *)nullable, (zts_socklen_t *)nullable);
|
||||
assert(("pre-init call to zts_recvfrom(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_recvmsg(i32, (struct zts_msghdr *)nullable, i32);
|
||||
assert(("pre-init call to zts_recvmsg(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_read(i32, nullable, i32);
|
||||
assert(("pre-init call to zts_read(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_readv(i32, (const struct zts_iovec *)nullable, i32);
|
||||
assert(("pre-init call to zts_readv(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_write(i32, nullable, i32);
|
||||
assert(("pre-init call to zts_write(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_writev(i32, (const struct zts_iovec *)nullable, i32);
|
||||
assert(("pre-init call to zts_writev(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
res = zts_shutdown(i32, i32);
|
||||
assert(("pre-init call to zts_shutdown(): res != ZTS_ERR_SERVICE",
|
||||
res == ZTS_ERR_SERVICE));
|
||||
}
|
||||
|
||||
void test_pre_service()
|
||||
{
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test service-related API functions before initializing service //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// Test null values
|
||||
api_value_arg_test(0,0,0,0,NULL);
|
||||
|
||||
// Test wild values
|
||||
for (int i=0; i<4096; i++) {
|
||||
int8_t i8 = (uint8_t)random64();
|
||||
int16_t i16 = (uint16_t)random64();
|
||||
int32_t i32 = (uint32_t)random64();
|
||||
int64_t i64 = (uint64_t)random64();
|
||||
int x;
|
||||
void* nullable = &x;
|
||||
api_value_arg_test(i8,i16,i32,i64,nullable);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test non-service helper functions //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// (B) Test zts_inet_ntop
|
||||
|
||||
char ipstr[ZTS_INET6_ADDRSTRLEN];
|
||||
int16_t port = 0;
|
||||
struct zts_sockaddr_in in4;
|
||||
|
||||
in4.sin_port = htons(8080);
|
||||
#if defined(_WIN32)
|
||||
zts_inet_pton(ZTS_AF_INET, "192.168.22.1", &(in4.sin_addr.S_addr));
|
||||
#else
|
||||
zts_inet_pton(ZTS_AF_INET, "192.168.22.1", &(in4.sin_addr.s_addr));
|
||||
#endif
|
||||
|
||||
in4.sin_family = ZTS_AF_INET;
|
||||
|
||||
struct zts_sockaddr *sa = (struct zts_sockaddr *)&in4;
|
||||
if (sa->sa_family == ZTS_AF_INET) {
|
||||
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)sa;
|
||||
zts_inet_ntop(ZTS_AF_INET, &(in4->sin_addr),
|
||||
ipstr, ZTS_INET_ADDRSTRLEN);
|
||||
port = ntohs(in4->sin_port);
|
||||
}
|
||||
if (sa->sa_family == ZTS_AF_INET6) {
|
||||
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)sa;
|
||||
zts_inet_ntop(ZTS_AF_INET6, &(in6->sin6_addr),
|
||||
ipstr, ZTS_INET6_ADDRSTRLEN);
|
||||
}
|
||||
|
||||
assert(("zts_inet_ntop(): port != 8080", port == 8080));
|
||||
assert(("zts_inet_ntop(): strcmp(ipstr, \"192.168.22.1\") != 0",
|
||||
!strcmp(ipstr, "192.168.22.1")));
|
||||
|
||||
// (C) Test zts_inet_pton
|
||||
|
||||
uint8_t buf[sizeof(struct zts_in6_addr)];
|
||||
char str[ZTS_INET6_ADDRSTRLEN];
|
||||
|
||||
zts_inet_pton(ZTS_AF_INET, "192.168.22.2", buf);
|
||||
zts_inet_ntop(ZTS_AF_INET, buf, str, ZTS_INET6_ADDRSTRLEN);
|
||||
assert(("zts_inet_pton(): strcmp(ipstr, \"192.168.22.2\") != 0",
|
||||
!strcmp(str, "192.168.22.2")));
|
||||
}
|
||||
|
||||
void test_service()
|
||||
{
|
||||
int res = ZTS_ERR_OK;
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test simplified API, proxy for setsockopt/getsockopt/ioctl etc //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
int s4 = zts_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0);
|
||||
assert(s4 >= 0);
|
||||
|
||||
// TCP_NODELAY
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_no_delay(s4);
|
||||
assert(res == 0);
|
||||
// Turn on
|
||||
res = zts_set_no_delay(s4, 1);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
res = zts_get_no_delay(s4);
|
||||
// Should return value instead of error code
|
||||
assert(res == 1);
|
||||
// Turn off
|
||||
res = zts_set_no_delay(s4, 0);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
res = zts_get_no_delay(s4);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
assert(res == 0);
|
||||
|
||||
// SO_LINGER
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_linger_enabled(s4);
|
||||
assert(res == 0);
|
||||
res = zts_get_linger_value(s4);
|
||||
assert(res == 0);
|
||||
// Turn on, set to 7 seconds
|
||||
res = zts_set_linger(s4, 1, 7);
|
||||
res = zts_get_linger_enabled(s4);
|
||||
assert(res == 1);
|
||||
res = zts_get_linger_value(s4);
|
||||
assert(res == 7);
|
||||
res = zts_set_linger(s4, 0, 0);
|
||||
// Turn off
|
||||
res = zts_get_linger_enabled(s4);
|
||||
assert(res == 0);
|
||||
res = zts_get_linger_value(s4);
|
||||
assert(res == 0);
|
||||
|
||||
// SO_REUSEADDR
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_reuse_addr(s4);
|
||||
assert(res == 0);
|
||||
// Turn on
|
||||
res = zts_set_reuse_addr(s4, 1);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
res = zts_get_reuse_addr(s4);
|
||||
// Should return value instead of error code
|
||||
assert(res == 1);
|
||||
// Turn off
|
||||
res = zts_set_reuse_addr(s4, 0);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
res = zts_get_reuse_addr(s4);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
assert(res == 0);
|
||||
|
||||
// SO_RCVTIMEO
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_recv_timeout(s4);
|
||||
assert(res == 0);
|
||||
// Set to value
|
||||
res = zts_set_recv_timeout(s4, 3, 0);
|
||||
res = zts_get_recv_timeout(s4);
|
||||
assert(res == 3);
|
||||
res = zts_set_recv_timeout(s4, 0, 0);
|
||||
// Set to zero
|
||||
res = zts_get_recv_timeout(s4);
|
||||
assert(res == 0);
|
||||
|
||||
// SO_SNDTIMEO
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_send_timeout(s4);
|
||||
assert(res == 0);
|
||||
// Set to value
|
||||
res = zts_set_send_timeout(s4, 4, 0);
|
||||
res = zts_get_send_timeout(s4);
|
||||
assert(res == 4);
|
||||
res = zts_set_send_timeout(s4, 0, 0);
|
||||
// Set to zero
|
||||
res = zts_get_send_timeout(s4);
|
||||
assert(res == 0);
|
||||
|
||||
// SO_SNDBUF
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_send_buf_size(s4);
|
||||
assert(res == -1); // Unimplemented as of writing of test
|
||||
// Set to 7 seconds
|
||||
res = zts_set_send_buf_size(s4, 1024);
|
||||
res = zts_get_send_buf_size(s4);
|
||||
assert(res == -1); // Unimplemented as of writing of test
|
||||
res = zts_set_send_buf_size(s4, 0);
|
||||
// Set to zero
|
||||
res = zts_get_send_buf_size(s4);
|
||||
assert(res == -1); // Unimplemented as of writing of test
|
||||
|
||||
// SO_RCVBUF
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_recv_buf_size(s4);
|
||||
assert(res > 0);
|
||||
// Set to value
|
||||
res = zts_set_recv_buf_size(s4, 1024);
|
||||
res = zts_get_recv_buf_size(s4);
|
||||
assert(res == 1024);
|
||||
res = zts_set_recv_buf_size(s4, 0);
|
||||
// Set to zero
|
||||
res = zts_get_recv_buf_size(s4);
|
||||
assert(res == 0);
|
||||
|
||||
// IP_TTL
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_ttl(s4);
|
||||
assert(res == 255); // Defaults to max
|
||||
// Set to value
|
||||
res = zts_set_ttl(s4, 128);
|
||||
res = zts_get_ttl(s4);
|
||||
assert(res == 128);
|
||||
res = zts_set_ttl(s4, 0);
|
||||
// Set to zero
|
||||
res = zts_get_ttl(s4);
|
||||
assert(res == 0);
|
||||
|
||||
// O_NONBLOCK
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_blocking(s4);
|
||||
assert(res == 1);
|
||||
// Turn off (non-blocking)
|
||||
res = zts_set_blocking(s4, 0);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
res = zts_get_blocking(s4);
|
||||
// Should return value instead of error code
|
||||
assert(res == 0);
|
||||
// Turn off
|
||||
res = zts_set_blocking(s4, 1);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
res = zts_get_blocking(s4);
|
||||
assert(res == 1);
|
||||
|
||||
// SO_KEEPALIVE
|
||||
|
||||
// Check value before doing anything
|
||||
res = zts_get_keepalive(s4);
|
||||
assert(res == 0);
|
||||
// Turn on
|
||||
res = zts_set_keepalive(s4, 1);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
res = zts_get_keepalive(s4);
|
||||
// Should return value instead of error code
|
||||
assert(res == 1);
|
||||
// Turn off
|
||||
res = zts_set_keepalive(s4, 0);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
res = zts_get_keepalive(s4);
|
||||
assert(res == ZTS_ERR_OK);
|
||||
assert(res == 0);
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test DNS client functionality //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
/*
|
||||
// Set first nameserver
|
||||
|
||||
char *ns1_addr_str = "FCC5:205E:4FF5:5311:DFF0::1";
|
||||
zts_ip_addr ns1;
|
||||
zts_ipaddr_aton(ns1_addr_str, &ns1);
|
||||
zts_dns_set_server(0, &ns1);
|
||||
|
||||
// Get first nameserver
|
||||
|
||||
const zts_ip_addr *ns1_result;
|
||||
ns1_result = zts_dns_get_server(0);
|
||||
printf("dns1 = %s\n", zts_ipaddr_ntoa(ns1_result));
|
||||
|
||||
// Set second nameserver
|
||||
|
||||
char *ns2_addr_str = "192.168.22.1";
|
||||
zts_ip_addr ns2;
|
||||
zts_ipaddr_aton(ns2_addr_str, &ns2);
|
||||
zts_dns_set_server(1, &ns2);
|
||||
|
||||
// Get second nameserver
|
||||
|
||||
const zts_ip_addr *ns2_result;
|
||||
ns2_result = zts_dns_get_server(1);
|
||||
printf("dns1 = %s\n", zts_ipaddr_ntoa(ns2_result));
|
||||
|
||||
// Check that each nameserver address was properly set and get
|
||||
|
||||
assert(("zts_dns_get_server(): Address mismatch", !strcmp(ns1_addr_str, zts_ipaddr_ntoa(ns1_result))));
|
||||
assert(("zts_dns_get_server(): Address mismatch", !strcmp(ns2_addr_str, zts_ipaddr_ntoa(ns2_result))));
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Test shutting down the service //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
zts_stop();
|
||||
s4 = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
|
||||
assert(("s4 != ZTS_ERR_SERVICE, not shut down", s4 == ZTS_ERR_SERVICE));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Server //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#define MAX_CONNECT_TIME 60 // outer re-attempt loop
|
||||
#define CONNECT_TIMEOUT 30 // zts_connect_easy, ms
|
||||
#define BUFLEN 128
|
||||
char *msg = "welcome to the machine";
|
||||
|
||||
void start_server_app(uint16_t port4, uint16_t port6)
|
||||
{
|
||||
int err = ZTS_ERR_OK;
|
||||
int bytes_read = 0;
|
||||
int bytes_sent = 0;
|
||||
|
||||
int msglen = strlen(msg);
|
||||
char dstbuf[BUFLEN];
|
||||
int buflen = BUFLEN;
|
||||
|
||||
struct timespec start, now;
|
||||
int time_diff = 0;
|
||||
|
||||
//
|
||||
// IPv4 test
|
||||
//
|
||||
|
||||
fprintf(stderr, "server4: will listen on: 0.0.0.0:%d\n", port4);
|
||||
int s4 = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
|
||||
assert(s4 == 0 && zts_errno == 0);
|
||||
|
||||
err = zts_bind_easy(s4, ZTS_AF_INET, "0.0.0.0", port4);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
err = zts_listen(s4, 1);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
struct zts_sockaddr_in in4;
|
||||
zts_socklen_t addrlen4 = sizeof(in4);
|
||||
|
||||
int acc4 = -1;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
do {
|
||||
fprintf(stderr, "server4: accepting...\n");
|
||||
acc4 = zts_accept(s4, &in4, &addrlen4);
|
||||
zts_delay_ms(250);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
time_diff = (now.tv_sec - start.tv_sec);
|
||||
} while (err < 0 && time_diff < MAX_CONNECT_TIME);
|
||||
|
||||
assert(acc4 == 1 && zts_errno == 0);
|
||||
|
||||
// Read message
|
||||
memset(dstbuf, 0, buflen);
|
||||
bytes_read = zts_read(acc4, dstbuf, buflen);
|
||||
fprintf(stderr, "server4: read (%d) bytes\n", bytes_read);
|
||||
assert(bytes_read == msglen && zts_errno == 0);
|
||||
|
||||
// Send message
|
||||
bytes_sent = zts_write(acc4, msg, msglen);
|
||||
fprintf(stderr, "server4: wrote (%d) bytes\n", bytes_sent);
|
||||
assert(bytes_sent == msglen && zts_errno == 0);
|
||||
|
||||
zts_close(s4);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
zts_close(acc4);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
assert(bytes_sent == bytes_read);
|
||||
if (bytes_sent == bytes_read) {
|
||||
fprintf(stderr, "server4: Test OK\n");
|
||||
} else {
|
||||
fprintf(stderr, "server4: Test FAIL\n");
|
||||
}
|
||||
|
||||
//
|
||||
// IPv6 test
|
||||
//
|
||||
|
||||
fprintf(stderr, "server: will listen on: [::]:%d\n", port6);
|
||||
int s6 = zts_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0);
|
||||
assert(s6 == 0 && zts_errno == 0);
|
||||
|
||||
err = zts_bind_easy(s6, ZTS_AF_INET6, "::", port6);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
err = zts_listen(s6, 1);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
struct zts_sockaddr_in6 in6;
|
||||
zts_socklen_t addrlen6 = sizeof(in6);
|
||||
|
||||
int acc6 = -1;
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
do {
|
||||
fprintf(stderr, "server6: accepting...\n");
|
||||
acc6 = zts_accept(s6, &in6, &addrlen6);
|
||||
zts_delay_ms(250);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
time_diff = (now.tv_sec - start.tv_sec);
|
||||
} while (err < 0 && time_diff < MAX_CONNECT_TIME);
|
||||
|
||||
fprintf(stderr, "server6: accepted connection (fd=%d)\n", acc6);
|
||||
assert(acc6 == 1 && zts_errno == 0);
|
||||
|
||||
// Read message
|
||||
memset(dstbuf, 0, buflen);
|
||||
bytes_read = zts_read(acc6, dstbuf, buflen);
|
||||
fprintf(stderr, "server6: read (%d) bytes\n", bytes_read);
|
||||
assert(bytes_read == msglen && zts_errno == 0);
|
||||
|
||||
// Send message
|
||||
bytes_sent = zts_write(acc6, msg, msglen);
|
||||
fprintf(stderr, "server6: wrote (%d) bytes\n", bytes_sent);
|
||||
assert(bytes_sent == msglen && zts_errno == 0);
|
||||
|
||||
zts_close(s6);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
zts_close(acc6);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
zts_stop();
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
int s = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
|
||||
assert(("s != ZTS_ERR_SERVICE, not shut down", s == ZTS_ERR_SERVICE));
|
||||
|
||||
assert(bytes_sent == bytes_read);
|
||||
if (bytes_sent == bytes_read) {
|
||||
fprintf(stderr, "server6: Test OK\n");
|
||||
} else {
|
||||
fprintf(stderr, "server6: Test FAIL\n");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Client //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
void start_client_app(char *ip4, uint16_t port4, char *ip6, uint16_t port6)
|
||||
{
|
||||
int err = ZTS_ERR_OK;
|
||||
int bytes_read = 0;
|
||||
int bytes_sent = 0;
|
||||
|
||||
int msglen = strlen(msg);
|
||||
char dstbuf[BUFLEN];
|
||||
int buflen = BUFLEN;
|
||||
|
||||
struct timespec start, now;
|
||||
int time_diff = 0;
|
||||
|
||||
//
|
||||
// IPv4 test
|
||||
//
|
||||
|
||||
err = ZTS_ERR_OK;
|
||||
int s4 = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
zts_set_blocking(s4, 1);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
do {
|
||||
fprintf(stderr, "client4: connecting to: %s:%d\n", ip4, port4);
|
||||
err = zts_connect_easy(s4, ZTS_AF_INET, ip4, port4, CONNECT_TIMEOUT);
|
||||
zts_delay_ms(500);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
time_diff = (now.tv_sec - start.tv_sec);
|
||||
} while (err < 0 && time_diff < MAX_CONNECT_TIME);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
fprintf(stderr, "client4: connected\n");
|
||||
// Send message
|
||||
bytes_sent = zts_write(s4, msg, msglen);
|
||||
fprintf(stderr, "client4: wrote (%d) bytes\n", bytes_sent);
|
||||
assert(bytes_sent == msglen && zts_errno == 0);
|
||||
|
||||
// Read message
|
||||
memset(dstbuf, 0, buflen);
|
||||
bytes_read = zts_read(s4, dstbuf, buflen);
|
||||
assert(bytes_read == msglen && zts_errno == 0);
|
||||
|
||||
fprintf(stderr, "client4: read (%d) bytes\n", bytes_read);
|
||||
assert(bytes_sent == bytes_read && zts_errno == 0);
|
||||
|
||||
zts_close(s4);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
assert(bytes_sent == bytes_read);
|
||||
if (bytes_sent == bytes_read) {
|
||||
fprintf(stderr, "client4: Test OK\n");
|
||||
} else {
|
||||
fprintf(stderr, "client4: Test FAIL\n");
|
||||
}
|
||||
|
||||
//
|
||||
// IPv6 test
|
||||
//
|
||||
|
||||
err = ZTS_ERR_OK;
|
||||
int s6 = zts_socket(ZTS_AF_INET6, ZTS_SOCK_STREAM, 0);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
zts_set_blocking(s6, 1);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
do {
|
||||
fprintf(stderr, "client6: connecting to: %s:%d\n", ip6, port6);
|
||||
err = zts_connect_easy(s6, ZTS_AF_INET6, ip6, port6, CONNECT_TIMEOUT);
|
||||
zts_delay_ms(500);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
time_diff = (now.tv_sec - start.tv_sec);
|
||||
} while (err < 0 && time_diff < MAX_CONNECT_TIME);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
fprintf(stderr, "client6: connected\n");
|
||||
// Send message
|
||||
bytes_sent = zts_write(s6, msg, msglen);
|
||||
fprintf(stderr, "client6: wrote (%d) bytes\n", bytes_sent);
|
||||
assert(bytes_sent == msglen && zts_errno == 0);
|
||||
|
||||
// Read message
|
||||
memset(dstbuf, 0, buflen);
|
||||
bytes_read = zts_read(s6, dstbuf, buflen);
|
||||
assert(bytes_read == msglen && zts_errno == 0);
|
||||
|
||||
fprintf(stderr, "client6: read (%d) bytes\n", bytes_read);
|
||||
assert(bytes_sent == bytes_read && zts_errno == 0);
|
||||
|
||||
zts_close(s6);
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
|
||||
zts_stop();
|
||||
assert(err == ZTS_ERR_OK && zts_errno == 0);
|
||||
int s = zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
|
||||
assert(("s != ZTS_ERR_SERVICE, not shut down", s == ZTS_ERR_SERVICE));
|
||||
|
||||
assert(bytes_sent == bytes_read);
|
||||
if (bytes_sent == bytes_read) {
|
||||
fprintf(stderr, "client6: Test OK\n");
|
||||
} else {
|
||||
fprintf(stderr, "client6: Test FAIL\n");
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Start node //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
void start_node(char *path, uint64_t nwid)
|
||||
{
|
||||
struct timespec start, now;
|
||||
int time_diff = 0;
|
||||
|
||||
fprintf(stderr, "starting node...\n");
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
int res = zts_start(path, &on_zts_event, 0);
|
||||
assert(("error starting service: res != ZTS_ERR_OK", res == ZTS_ERR_OK));
|
||||
do {
|
||||
zts_delay_ms(25);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
time_diff = (now.tv_sec - start.tv_sec);
|
||||
} while (!is_online && (time_diff < MAX_CONNECT_TIME));
|
||||
if (!is_online) {
|
||||
fprintf(stderr, "node failed to come online\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "joining: %llx\n", nwid);
|
||||
clock_gettime(CLOCK_MONOTONIC, &start);
|
||||
if (nwid) {
|
||||
zts_join(nwid);
|
||||
do {
|
||||
zts_delay_ms(25);
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
time_diff = (now.tv_sec - start.tv_sec);
|
||||
} while ((!has_ip4 || !has_ip6) && (time_diff < MAX_CONNECT_TIME));
|
||||
if (!has_ip4 || !has_ip6) {
|
||||
fprintf(stderr, "node failed to receive assigned addresses\n");
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
// Main //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc != 1 && argc != 5 && argc != 7) {
|
||||
fprintf(stderr, "Invalid number of arguments.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
//
|
||||
// API fuzz test
|
||||
//
|
||||
|
||||
test_pre_service();
|
||||
|
||||
//
|
||||
// Default test
|
||||
//
|
||||
|
||||
// selftest
|
||||
if (argc == 1) {
|
||||
srand(time(NULL));
|
||||
// Store identities in cwd, join 0x0
|
||||
start_node(".",0x0);
|
||||
test_service();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Default test (single node)
|
||||
// selftest <id-path>
|
||||
/*
|
||||
if (argc == 2) {
|
||||
srand(time(NULL));
|
||||
start_node(argv[1],0x0);
|
||||
test_service();
|
||||
exit(0);
|
||||
}*/
|
||||
|
||||
//
|
||||
// Client/Server communication test
|
||||
//
|
||||
|
||||
// Server test
|
||||
if (argc == 5) {
|
||||
//fprintf(stderr, "server.path = %s\n", argv[1]);
|
||||
//fprintf(stderr, "server.nwid = %s\n", argv[2]);
|
||||
//fprintf(stderr, "server.port4 = %s\n", argv[3]);
|
||||
//fprintf(stderr, "server.port6 = %s\n", argv[4]);
|
||||
uint64_t nwid = strtoull(argv[2],NULL,16);
|
||||
int port4 = atoi(argv[3]);
|
||||
int port6 = atoi(argv[4]);
|
||||
start_node(argv[1],nwid);
|
||||
start_server_app(port4, port6);
|
||||
exit(0);
|
||||
}
|
||||
// Client test
|
||||
if (argc == 7) {
|
||||
//fprintf(stderr, "client.path = %s\n", argv[1]);
|
||||
//fprintf(stderr, "client.nwid = %s\n", argv[2]);
|
||||
//fprintf(stderr, "client.port4 = %s\n", argv[3]);
|
||||
//fprintf(stderr, "client.ip4 = %s\n", argv[4]);
|
||||
//fprintf(stderr, "client.port6 = %s\n", argv[5]);
|
||||
//fprintf(stderr, "client.ip6 = %s\n", argv[6]);
|
||||
uint64_t nwid = strtoull(argv[2],NULL,16);
|
||||
int port4 = atoi(argv[3]);
|
||||
int port6 = atoi(argv[5]);
|
||||
start_node(argv[1],nwid);
|
||||
start_client_app(argv[4], port4, argv[6], port6);
|
||||
exit(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
1887
test/selftest.c
Normal file
1887
test/selftest.c
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user