Merge refactored dev into master

This commit is contained in:
Joseph Henry
2021-03-12 20:32:08 -08:00
164 changed files with 3852 additions and 6273 deletions

31
.github/workflows/wheels.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Build New Wheels
on: [workflow_dispatch]
jobs:
build_wheels:
name: Build wheels on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macOS-latest]
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/setup-python@v2
- name: Install cibuildwheel
run: python -m pip install cibuildwheel==1.10.0
- name: Build wheels
env:
CIBW_ARCHS: auto
CIBW_BUILD: cp35-* cp36-* cp37-* cp38-* cp39-*
CIBW_BEFORE_BUILD: ln -s $(pwd) pkg/pypi/native; cp -f src/bindings/python/*.py pkg/pypi/libzt/; cd pkg/pypi; python setup.py build_clib
run: |
python -m cibuildwheel pkg/pypi --output-dir wheelhouse
- uses: actions/upload-artifact@v2
with:
path: wheelhouse/*.whl

View File

@@ -2,91 +2,212 @@ cmake_minimum_required(VERSION 3.0)
project(zt) project(zt)
find_package(Threads) find_package(Threads)
set(requiredlibs)
if(CENTRAL_API)
find_package(CURL)
if(CURL_FOUND)
include_directories(${CURL_INCLUDE_DIR})
set(requiredlibs ${requiredlibs} ${CURL_LIBRARIES})
else(CURL_FOUND)
message(
FATAL_ERROR "Could not find the CURL library and development files.")
endif(CURL_FOUND)
endif()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# | PLATFORM/FEATURE AND IDE DETECTION | # | PLATFORM DETECTION |
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if(${CMAKE_SYSTEM_NAME} MATCHES "Android") # Apple
set(BUILDING_ANDROID TRUE)
endif()
if(WIN32)
set(BUILDING_WIN32 TRUE)
endif()
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
set(BUILDING_WIN64 TRUE)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(BUILDING_DARWIN TRUE) set(BUILD_DARWIN TRUE)
endif() endif()
if(IOS_FRAMEWORK)
set(BUILDING_IOS TRUE) # macOS
endif() if(BUILD_DARWIN AND NOT BUILD_IOS_FRAMEWORK)
if(BUILDING_DARWIN AND NOT IOS_FRAMEWORK) set(BUILD_MACOS TRUE)
set(BUILDING_MACOS TRUE)
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
set(BUILDING_LINUX TRUE)
endif() endif()
if(${CMAKE_GENERATOR} STREQUAL "Xcode") if(${CMAKE_GENERATOR} STREQUAL "Xcode")
set(IN_XCODE TRUE) set(IN_XCODE TRUE)
set(XCODE_EMIT_EFFECTIVE_PLATFORM_NAME ON) set(XCODE_EMIT_EFFECTIVE_PLATFORM_NAME ON)
endif() endif()
if(BUILDING_WIN32
OR BUILDING_WIN64
OR MSVC)
set(BUILDING_WIN TRUE)
endif()
if(NOT BUILDING_ANDROID AND NOT IN_XCODE)
set(SHOULD_BUILD_TESTS TRUE)
endif()
if(BUILDING_WIN32
OR BUILDING_WIN64
OR MSVC)
set(BUILDING_WIN TRUE)
endif()
# -----------------------------------------------------------------------------
# | BUILD TYPES |
# -----------------------------------------------------------------------------
if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "debug")
set(DEBUG_BUILD ON)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib)
endif()
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "release")
set(RELEASE_BUILD ON)
set(CMAKE_VERBOSE_MAKEFILE OFF)
set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib)
endif()
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(INTERMEDIATE_LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib/intermediate)
# -----------------------------------------------------------------------------
# | LIBRARY NAMES |
# -----------------------------------------------------------------------------
# Target names
if(IN_XCODE) if(IN_XCODE)
set(XCODE_FRAMEWORK_NAME ${PROJECT_NAME}) set(XCODE_FRAMEWORK_NAME ${PROJECT_NAME})
endif() endif()
if(BUILDING_WIN) # Windows
if(WIN32)
set(BUILD_WIN32 TRUE)
endif()
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
set(BUILD_WIN64 TRUE)
endif()
if(BUILD_WIN32
OR BUILD_WIN64
OR MSVC)
set(BUILD_WIN TRUE)
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")
set(ZTO_SRC_DIR "${PROJ_DIR}/ext/ZeroTierOne")
set(LIBZT_SRC_DIR "${PROJ_DIR}/src")
set(CMAKE_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/bin)
set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/lib)
set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR})
set(INTERMEDIATE_LIBRARY_OUTPUT_PATH ${CMAKE_BINARY_DIR}/lib/intermediate)
if(UNIX)
set(LWIP_PORT_DIR ${PROJ_DIR}/ext/lwip-contrib/ports/unix/port)
endif()
if(BUILD_WIN)
set(LWIP_PORT_DIR ${PROJ_DIR}/ext/lwip-contrib/ports/win32)
endif()
# -----------------------------------------------------------------------------
# | INCLUDE DIRECTORIES |
# -----------------------------------------------------------------------------
# ZeroTier
include_directories(${ZTO_SRC_DIR})
include_directories(${ZTO_SRC_DIR}/include)
include_directories(${ZTO_SRC_DIR}/node)
include_directories(${ZTO_SRC_DIR}/osdep)
# ZeroTier (ext)
include_directories(${ZTO_SRC_DIR}/ext/miniupnpc)
include_directories(${ZTO_SRC_DIR}/ext/libnatpmp)
# libzt
include_directories(${PROJ_DIR}/src)
include_directories(${PROJ_DIR}/include)
# libzt (ext)
include_directories(${PROJ_DIR}/ext/concurrentqueue)
include_directories(${LWIP_SRC_DIR}/include)
include_directories(${LWIP_PORT_DIR}/include)
# -----------------------------------------------------------------------------
# | TARGET AND VARIANT SELECTION |
# -----------------------------------------------------------------------------
# C# language bindings (libzt.dll/dylib/so)
if (ZTS_ENABLE_PINVOKE)
# Features
set(BUILD_STATIC_LIB FALSE)
set(BUILD_SHARED_LIB TRUE)
set(BUILD_EXAMPLES FALSE)
set(BUILD_HOST_SELFTEST FALSE)
set(INSTALLABLE FALSE)
# Sources and libraries
set(ZTS_SWIG_WRAPPER_FILE ${LIBZT_SRC_DIR}/bindings/csharp/*.cpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZTS_ENABLE_PINVOKE=1")
endif()
# Python language bindings (_libzt.so)
if (ZTS_ENABLE_PYTHON)
# Features
set(ZTS_ENABLE_PYTHON TRUE)
#set(ZTS_ENABLE_STATS FALSE)
# Targets
set(BUILD_STATIC_LIB FALSE)
set(BUILD_SHARED_LIB TRUE)
set(BUILD_EXAMPLES FALSE)
set(BUILD_HOST_SELFTEST FALSE)
set(INSTALLABLE FALSE)
# Sources and libraries
find_package(PythonLibs REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
set(ZTS_SWIG_WRAPPER_FILE ${LIBZT_SRC_DIR}/bindings/python/*.cpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZTS_ENABLE_PYTHON=1")
endif()
# Java language bindings
if (ZTS_ENABLE_JAVA)
set(BUILD_STATIC_LIB FALSE)
set(BUILD_SHARED_LIB TRUE)
set(BUILD_HOST_EXAMPLES FALSE)
set(BUILD_HOST_SELFTEST FALSE)
set(ZTS_ENABLE_STATS FALSE)
set(INSTALLABLE FALSE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZTS_ENABLE_JAVA=1")
endif()
# All native targets for this host
if(BUILD_HOST)
set(BUILD_STATIC_LIB TRUE)
set(BUILD_SHARED_LIB TRUE)
set(BUILD_HOST_EXAMPLES TRUE)
set(BUILD_HOST_SELFTEST TRUE)
set(ZTS_ENABLE_STATS TRUE)
set(INSTALLABLE TRUE)
endif()
# CI
if(BUILD_HOST_SELFTEST_ONLY)
set(BUILD_STATIC_LIB TRUE)
set(BUILD_SHARED_LIB FALSE)
set(BUILD_HOST_EXAMPLES FALSE)
set(BUILD_HOST_SELFTEST TRUE)
set(ZTS_ENABLE_STATS FALSE)
set(INSTALLABLE FALSE)
endif()
# Android AAR containing libzt.so
if(${CMAKE_SYSTEM_NAME} MATCHES "Android")
set(BUILD_ANDROID TRUE)
set(BUILD_STATIC_LIB FALSE)
set(BUILD_SHARED_LIB TRUE)
set(BUILD_SELFTEST FALSE)
set(BUILD_EXAMPLES FALSE)
set(INSTALLABLE FALSE)
endif()
if(BUILD_MACOS_FRAMEWORK)
set(BUILD_STATIC_LIB TRUE)
set(BUILD_SHARED_LIB TRUE)
set(BUILD_SELFTEST FALSE)
set(BUILD_EXAMPLES FALSE)
set(INSTALLABLE 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)")
set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH NO)
include_directories(
"/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk/usr/include/")
endif()
if(BUILD_IOS_FRAMEWORK)
set(BUILD_STATIC_LIB TRUE)
set(BUILD_SHARED_LIB TRUE)
set(BUILD_SELFTEST FALSE)
set(BUILD_EXAMPLES FALSE)
set(INSTALLABLE 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
"/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer")
if(IOS_ARM64)
set(CMAKE_OSX_ARCHITECTURES arm64)
set(SDKVER "11.4")
endif()
if(IOS_ARMV7)
# armv7 armv7s
set(CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_BIT)")
set(SDKVER "10.0")
endif()
set(SDKROOT "${DEVROOT}/SDKs/iPhoneOS${SDKVER}.sdk")
if(EXISTS ${SDKROOT})
set(CMAKE_OSX_SYSROOT "${SDKROOT}")
else()
message("Warning, iOS Base SDK path not found: " ${SDKROOT})
endif()
endif()
if(ZTS_ENABLE_STATS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZTS_ENABLE_STATS=1")
endif()
# -----------------------------------------------------------------------------
# | HACKS TO GET THIS TO WORK ON WINDOWS |
# -----------------------------------------------------------------------------
if(BUILD_WIN)
# Possibly a CMake limitation? -- Can't share target output names # Possibly a CMake limitation? -- Can't share target output names
set(STATIC_LIB_NAME ${PROJECT_NAME}-static) set(STATIC_LIB_NAME ${PROJECT_NAME}-static)
set(STATIC_LIB_OUTPUT_NAME ${PROJECT_NAME}-static) set(STATIC_LIB_OUTPUT_NAME ${PROJECT_NAME}-static)
@@ -100,25 +221,75 @@ else()
endif() endif()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# | FLAGS | # | BUILD TYPES |
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
set(SILENCE "${SILENCE} -Wno-unused-parameter") if(CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "debug")
set(SILENCE "${SILENCE} -Wno-format") set(BUILD_DEBUG ON)
set(SILENCE "${SILENCE} -Wno-tautological-constant-out-of-range-compare ") set(CMAKE_VERBOSE_MAKEFILE ON)
set(SILENCE "${SILENCE} -Wno-macro-redefined") set(DEBUG_OPTIMIZATION "-O3")
set(SILENCE "${SILENCE} -Wno-parentheses-equality") endif()
set(SILENCE "${SILENCE} -Wno-sign-compare") if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "release")
set(SILENCE "${SILENCE} -Wno-unused-variable") set(BUILD_RELEASE ON)
set(SILENCE "${SILENCE} -Wno-missing-field-initializers") set(CMAKE_VERBOSE_MAKEFILE OFF)
set(SILENCE "${SILENCE} -Wno-unused-parameter") set(RELEASE_OPTIMIZATION "-O3")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wno-everything -w")
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(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(adhoc
${PROJ_DIR}/examples/cpp/adhoc.cpp)
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(client
${PROJ_DIR}/examples/cpp/client.cpp)
target_link_libraries(client ${STATIC_LIB_NAME})
add_executable(server
${PROJ_DIR}/examples/cpp/server.cpp)
target_link_libraries(server ${STATIC_LIB_NAME})
add_executable(keymanagement
${PROJ_DIR}/examples/cpp/keymanagement.cpp)
target_link_libraries(keymanagement ${STATIC_LIB_NAME})
if(CENTRAL_API)
add_executable(centralapi ${PROJ_DIR}/examples/cpp/centralapi.cpp)
target_link_libraries(centralapi ${STATIC_LIB_NAME})
endif()
endif()
# -----------------------------------------------------------------------------
# | FLAGS |
# -----------------------------------------------------------------------------
set(ZT_FLAGS "${ZT_FLAGS} -DZT_USE_MINIUPNPC=1") set(ZT_FLAGS "${ZT_FLAGS} -DZT_USE_MINIUPNPC=1")
set(ZT_FLAGS "${ZT_FLAGS} -DZT_SOFTWARE_UPDATE_DEFAULT=0") 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} -D_USING_LWIP_DEFINITIONS_=0")
set(ZT_FLAGS "${ZT_FLAGS} -DZT_SDK=1") set(ZT_FLAGS "${ZT_FLAGS} -DZT_SDK=1")
if(DEBUG_BUILD) if(BUILD_DEBUG)
set(LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_DBG_TYPES_ON=128") set(LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_DBG_TYPES_ON=128")
set(LWIP_FLAGS "${LWIP_FLAGS} -DSOCKETS_DEBUG=128") set(LWIP_FLAGS "${LWIP_FLAGS} -DSOCKETS_DEBUG=128")
# set (LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_STATS_LARGE=1") set (LWIP_FLAGS # set (LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_STATS_LARGE=1") set (LWIP_FLAGS
@@ -141,10 +312,7 @@ else()
set(LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_DBG_TYPES_ON=0") set(LWIP_FLAGS "${LWIP_FLAGS} -DLWIP_DBG_TYPES_ON=0")
endif() endif()
set(DEBUG_OPTIMIZATION "-O3") if(BUILD_WIN)
set(RELEASE_OPTIMIZATION "-O3")
if(BUILDING_WIN)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc -DNOMINMAX") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc -DNOMINMAX")
else() else()
@@ -159,8 +327,7 @@ else()
-DLWIP_DEBUG=1 -DLIBZT_DEBUG=1") -DLWIP_DEBUG=1 -DLIBZT_DEBUG=1")
set(CMAKE_C_FLAGS_RELEASE set(CMAKE_C_FLAGS_RELEASE
"${SILENCE} \ "${CMAKE_C_FLAGS_RELEASE} \
${CMAKE_C_FLAGS_RELEASE} \
${RELEASE_OPTIMIZATION} \ ${RELEASE_OPTIMIZATION} \
-fstack-protector") -fstack-protector")
@@ -174,19 +341,18 @@ else()
set(CMAKE_CXX_FLAGS_RELEASE set(CMAKE_CXX_FLAGS_RELEASE
"${CMAKE_CXX_FLAGS_RELEASE} \ "${CMAKE_CXX_FLAGS_RELEASE} \
${SILENCE} \
${RELEASE_OPTIMIZATION}") ${RELEASE_OPTIMIZATION}")
endif() endif()
# WINDOWS-specific MSVC flags and libraries # WINDOWS-specific MSVC flags and libraries
if(BUILDING_WIN) if(BUILD_WIN)
# 32-bit # 32-bit
if(NOT BUILDING_WIN64) if(NOT BUILD_WIN64)
set(WINLIBDIR, set(WINLIBDIR,
"C:/Program Files (x86)/Windows Kits/10/Lib/10.0.16299.0/um/x86") "C:/Program Files (x86)/Windows Kits/10/Lib/10.0.16299.0/um/x86")
endif() endif()
# 64-bit # 64-bit
if(BUILDING_WIN64) if(BUILD_WIN64)
set(WINLIBDIR, set(WINLIBDIR,
"C:/Program Files (x86)/Windows Kits/10/Lib/10.0.16299.0/um/x64") "C:/Program Files (x86)/Windows Kits/10/Lib/10.0.16299.0/um/x64")
endif() endif()
@@ -203,14 +369,30 @@ if(BUILDING_WIN)
add_definitions(-DADD_EXPORTS=1) add_definitions(-DADD_EXPORTS=1)
endif() endif()
# -----------------------------------------------------------------------------
# | OPTIONAL FEATURES |
# -----------------------------------------------------------------------------
if(CENTRAL_API)
set(requiredlibs)
find_package(CURL)
if(CURL_FOUND)
include_directories(${CURL_INCLUDE_DIR})
set(requiredlibs ${requiredlibs} ${CURL_LIBRARIES})
else(CURL_FOUND)
message(
FATAL_ERROR "Could not find the CURL library and development files.")
endif(CURL_FOUND)
endif()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# | JNI | # | JNI |
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if(SDK_JNI OR BUILDING_ANDROID) if(ZTS_ENABLE_JAVA OR BUILD_ANDROID)
message(STATUS "Looking for JNI") message(STATUS "Looking for JNI")
if(BUILDING_WIN) if(BUILD_WIN)
# We are only interested in finding jni.h: we do not care about extended JVM # We are only interested in finding jni.h: we do not care about extended JVM
# functionality or the AWT library. set(JAVA_AWT_LIBRARY NotNeeded) # functionality or the AWT library. set(JAVA_AWT_LIBRARY NotNeeded)
# set(JAVA_JVM_LIBRARY NotNeeded) set(JAVA_INCLUDE_PATH2 NotNeeded) # set(JAVA_JVM_LIBRARY NotNeeded) set(JAVA_INCLUDE_PATH2 NotNeeded)
@@ -231,32 +413,27 @@ if(SDK_JNI OR BUILDING_ANDROID)
message(STATUS "jni path=${JNI_INCLUDE_DIR}") message(STATUS "jni path=${JNI_INCLUDE_DIR}")
include_directories("${JNI_INCLUDE_DIR}") include_directories("${JNI_INCLUDE_DIR}")
# include_directories ("${JNI_INCLUDE_DIRS}") # include_directories ("${JNI_INCLUDE_DIRS}")
if(BUILDING_WIN) if(BUILD_WIN)
include_directories("${JNI_INCLUDE_DIR}\\win32") include_directories("${JNI_INCLUDE_DIR}\\win32")
endif() endif()
if(BUILDING_MACOS) if(BUILD_MACOS)
include_directories("${JNI_INCLUDE_DIR}/darwin") include_directories("${JNI_INCLUDE_DIR}/darwin")
endif() endif()
if(BUILDING_LINUX) if(BUILD_LINUX)
include_directories("${JNI_INCLUDE_DIR}/linux") include_directories("${JNI_INCLUDE_DIR}/linux")
endif() endif()
else() else()
message(STATUS "JNI not found") message(STATUS "JNI not found")
endif() endif()
if(JNI_FOUND) if(JNI_FOUND)
add_definitions(-DSDK_JNI=1) add_definitions(-DZTS_ENABLE_JAVA=1)
endif() endif()
endif() # SDK_JNI endif() # ZTS_ENABLE_JAVA
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# | SOURCES | # | SOURCES |
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
set(PROJ_DIR ${PROJECT_SOURCE_DIR})
set(LWIP_SRC_DIR "${PROJ_DIR}/ext/lwip/src")
set(ZTO_SRC_DIR "${PROJ_DIR}/ext/ZeroTierOne")
set(LIBZT_SRC_DIR "${PROJ_DIR}/src")
file(GLOB ztcoreSrcGlob ${ZTO_SRC_DIR}/node/*.cpp file(GLOB ztcoreSrcGlob ${ZTO_SRC_DIR}/node/*.cpp
${ZTO_SRC_DIR}/osdep/OSUtils.cpp ${ZTO_SRC_DIR}/osdep/PortMapper.cpp ${ZTO_SRC_DIR}/osdep/OSUtils.cpp ${ZTO_SRC_DIR}/osdep/PortMapper.cpp
${ZTO_SRC_DIR}/osdep/ManagedRoute.cpp) ${ZTO_SRC_DIR}/osdep/ManagedRoute.cpp)
@@ -264,6 +441,9 @@ file(GLOB ztcoreSrcGlob ${ZTO_SRC_DIR}/node/*.cpp
file(GLOB libnatpmpSrcGlob ${ZTO_SRC_DIR}/ext/libnatpmp/natpmp.c file(GLOB libnatpmpSrcGlob ${ZTO_SRC_DIR}/ext/libnatpmp/natpmp.c
${ZTO_SRC_DIR}/ext/libnatpmp/wingettimeofday.c ${ZTO_SRC_DIR}/ext/libnatpmp/wingettimeofday.c
${ZTO_SRC_DIR}/ext/libnatpmp/getgateway.c) ${ZTO_SRC_DIR}/ext/libnatpmp/getgateway.c)
if(NOT BUILD_WIN)
list(REMOVE_ITEM libnatpmpSrcGlob ${ZTO_SRC_DIR}/ext/libnatpmp/wingettimeofday.c)
endif()
file( file(
GLOB GLOB
@@ -282,21 +462,8 @@ file(
${ZTO_SRC_DIR}/ext/miniupnpc/upnperrors.c ${ZTO_SRC_DIR}/ext/miniupnpc/upnperrors.c
${ZTO_SRC_DIR}/ext/miniupnpc/upnpreplyparse.c) ${ZTO_SRC_DIR}/ext/miniupnpc/upnpreplyparse.c)
if(ZTS_PINVOKE)
set(ZTS_SWIG_WRAPPER_FILE ${LIBZT_SRC_DIR}/bindings/csharp/*.cxx)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DZTS_PINVOKE=1")
endif()
file(GLOB libztSrcGlob ${LIBZT_SRC_DIR}/*.cpp ${ZTS_SWIG_WRAPPER_FILE}) file(GLOB libztSrcGlob ${LIBZT_SRC_DIR}/*.cpp ${ZTS_SWIG_WRAPPER_FILE})
if(UNIX)
set(LWIP_PORT_DIR ${PROJ_DIR}/ext/lwip-contrib/ports/unix/port)
endif()
if(BUILDING_WIN)
set(LWIP_PORT_DIR ${PROJ_DIR}/ext/lwip-contrib/ports/win32)
endif()
file( file(
GLOB GLOB
lwipSrcGlob lwipSrcGlob
@@ -313,66 +480,15 @@ file(GLOB frameworkPublicHeaderGlob include/ZeroTierSockets.h)
file(GLOB frameworkHeaderGlob ${frameworkPublicHeaderGlob} file(GLOB frameworkHeaderGlob ${frameworkPublicHeaderGlob}
${frameworkPrivateHeaderGlob}) ${frameworkPrivateHeaderGlob})
# -----------------------------------------------------------------------------
# | INCLUDES |
# -----------------------------------------------------------------------------
include_directories(${ZTO_SRC_DIR})
include_directories(${ZTO_SRC_DIR}/node)
include_directories(${ZTO_SRC_DIR}/osdep)
include_directories(${ZTO_SRC_DIR}/include)
include_directories(${ZTO_SRC_DIR}/ext/miniupnpc)
include_directories(${ZTO_SRC_DIR}/ext/libnatpmp)
include_directories(${PROJ_DIR}/src)
include_directories(${PROJ_DIR}/include)
include_directories(${LWIP_SRC_DIR}/include)
include_directories(${LWIP_PORT_DIR}/include)
include_directories(${PROJ_DIR}/ext/concurrentqueue)
# TODO: Should separate this into its own ios.cmake file
if(IOS_FRAMEWORK)
# Controllers probably won't be run from iPhones, so we can omit JSON support
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
"/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer"
)
if(IOS_ARM64)
set(CMAKE_OSX_ARCHITECTURES arm64)
set(SDKVER "11.4")
endif()
if(IOS_ARMV7)
# armv7 armv7s
set(CMAKE_OSX_ARCHITECTURES "$(ARCHS_STANDARD_32_BIT)")
set(SDKVER "10.0")
endif()
set(SDKROOT "${DEVROOT}/SDKs/iPhoneOS${SDKVER}.sdk")
if(EXISTS ${SDKROOT})
set(CMAKE_OSX_SYSROOT "${SDKROOT}")
else()
message("Warning, iOS Base SDK path not found: " ${SDKROOT})
endif()
endif()
if(MACOS_FRAMEWORK)
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)")
set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH NO)
include_directories(
"/Library/Developer/CommandLineTools/SDKs/MacOSX11.0.sdk/usr/include/")
endif()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# | OBJECT LIBRARIES (INTERMEDIATE) | # | OBJECT LIBRARIES (INTERMEDIATE) |
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if(BUILD_STATIC_LIB)
# zto_obj # zto_obj
add_library(zto_obj OBJECT ${ztcoreSrcGlob}) add_library(zto_obj OBJECT ${ztcoreSrcGlob})
set_target_properties(zto_obj PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}") set_target_properties(zto_obj PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}")
if(BUILDING_WIN) if(BUILD_WIN)
target_link_libraries(zto_obj ws2_32) target_link_libraries(zto_obj ws2_32)
target_link_libraries(zto_obj ${shlwapi_LIBRARY_PATH}) target_link_libraries(zto_obj ${shlwapi_LIBRARY_PATH})
target_link_libraries(zto_obj ${iphlpapi_LIBRARY_PATH}) target_link_libraries(zto_obj ${iphlpapi_LIBRARY_PATH})
@@ -397,7 +513,7 @@ target_compile_definitions(
UPNP_VERSION_STRING=\"UPnP/1.1\" UPNP_VERSION_STRING=\"UPnP/1.1\"
ENABLE_STRNATPMPERR ENABLE_STRNATPMPERR
OS_STRING=\"Darwin/15.0.0\") OS_STRING=\"Darwin/15.0.0\")
if(BUILDING_DARWIN AND NOT IOS_FRAMEWORK) if(BUILD_DARWIN AND NOT BUILD_IOS_FRAMEWORK)
target_compile_definitions(miniupnpc_obj PRIVATE MACOSX) target_compile_definitions(miniupnpc_obj PRIVATE MACOSX)
endif() endif()
@@ -408,6 +524,7 @@ set_target_properties(lwip_obj PROPERTIES COMPILE_FLAGS "${LWIP_FLAGS}")
# libzt_obj # libzt_obj
add_library(libzt_obj OBJECT ${libztSrcGlob}) add_library(libzt_obj OBJECT ${libztSrcGlob})
set_target_properties(libzt_obj PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}") set_target_properties(libzt_obj PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}")
endif()
# PIC # PIC
@@ -449,16 +566,22 @@ add_library(zt_pic ${libztSrcGlob})
set_target_properties(zt_pic PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}" set_target_properties(zt_pic PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}"
POSITION_INDEPENDENT_CODE ON) POSITION_INDEPENDENT_CODE ON)
#set_property(
# TARGET lwip_pic
# APPEND
# PROPERTY STATIC_LIBRARY_FLAGS "-no_warning_for_no_symbols"
#)
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# | BUILD TARGETS (FINAL PRODUCT) | # | STATIC LIB |
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if(BUILD_STATIC_LIB)
# libztcore.a # libztcore.a
add_library(ztcore STATIC $<TARGET_OBJECTS:zto_obj>) add_library(ztcore STATIC $<TARGET_OBJECTS:zto_obj>)
set_target_properties( set_target_properties(
ztcore PROPERTIES OUTPUT_NAME ztcore LIBRARY_OUTPUT_DIRECTORY ztcore PROPERTIES OUTPUT_NAME ztcore LIBRARY_OUTPUT_DIRECTORY
${INTERMEDIATE_LIBRARY_OUTPUT_PATH}) ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
# libzt.a # libzt.a
add_library( add_library(
${STATIC_LIB_NAME} STATIC ${STATIC_LIB_NAME} STATIC
@@ -467,26 +590,37 @@ add_library(
$<TARGET_OBJECTS:lwip_pic> ${libztSrcGlob}) $<TARGET_OBJECTS:lwip_pic> ${libztSrcGlob})
set_target_properties( set_target_properties(
${STATIC_LIB_NAME} ${STATIC_LIB_NAME}
PROPERTIES OUTPUT_NAME zt PROPERTIES LINKER_LANGUAGE CXX
OUTPUT_NAME zt
POSITION_INDEPENDENT_CODE ON POSITION_INDEPENDENT_CODE ON
LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH}) LIBRARY_OUTPUT_DIRECTORY ${INTERMEDIATE_LIBRARY_OUTPUT_PATH})
set_target_properties(${STATIC_LIB_NAME} PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}") set_target_properties(${STATIC_LIB_NAME} PROPERTIES COMPILE_FLAGS "${ZT_FLAGS}")
target_link_libraries(${STATIC_LIB_NAME} ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(${STATIC_LIB_NAME} ${CMAKE_THREAD_LIBS_INIT})
if(CENTRAL_API) if(BUILD_WIN)
target_link_libraries(${STATIC_LIB_NAME} ${CURL_LIBRARIES})
endif()
if(BUILDING_WIN)
target_link_libraries(${STATIC_LIB_NAME} ${ws2_32_LIBRARY_PATH} target_link_libraries(${STATIC_LIB_NAME} ${ws2_32_LIBRARY_PATH}
${shlwapi_LIBRARY_PATH} ${iphlpapi_LIBRARY_PATH}) ${shlwapi_LIBRARY_PATH} ${iphlpapi_LIBRARY_PATH})
endif() # BUILD_STATIC_LIB
endif() endif()
if(CENTRAL_API)
# target_link_libraries(${STATIC_LIB_NAME} ${CURL_LIBRARIES})
endif()
# -----------------------------------------------------------------------------
# | SHARED LIB |
# -----------------------------------------------------------------------------
if(BUILD_SHARED_LIB)
# libzt.so/dylib/dll # libzt.so/dylib/dll
add_library(${DYNAMIC_LIB_NAME} SHARED ${libztSrcGlob}) add_library(${DYNAMIC_LIB_NAME} SHARED ${libztSrcGlob})
target_link_libraries(${DYNAMIC_LIB_NAME} ${PYTHON_LIBRARIES})
target_link_libraries(${DYNAMIC_LIB_NAME} zt_pic lwip_pic zto_pic natpmp_pic target_link_libraries(${DYNAMIC_LIB_NAME} zt_pic lwip_pic zto_pic natpmp_pic
miniupnpc_pic) miniupnpc_pic)
set_target_properties(${DYNAMIC_LIB_NAME} PROPERTIES COMPILE_FLAGS set_target_properties(${DYNAMIC_LIB_NAME}
PROPERTIES COMPILE_FLAGS
"${ZT_FLAGS}") "${ZT_FLAGS}")
set_target_properties( set_target_properties(
${DYNAMIC_LIB_NAME} PROPERTIES OUTPUT_NAME ${DYNAMIC_LIB_OUTPUT_NAME} ${DYNAMIC_LIB_NAME} PROPERTIES OUTPUT_NAME ${DYNAMIC_LIB_OUTPUT_NAME}
@@ -509,9 +643,10 @@ endif()
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
if(BUILDING_ANDROID) if(BUILD_ANDROID)
target_link_libraries(${DYNAMIC_LIB_NAME} android log) target_link_libraries(${DYNAMIC_LIB_NAME} android log)
endif() endif()
endif() # BUILD_SHARED_LIB
# xcode framework # xcode framework
if(IN_XCODE) if(IN_XCODE)
@@ -546,47 +681,30 @@ if(IN_XCODE)
FRAMEWORK_VERSION A FRAMEWORK_VERSION A
XCODE_ATTRIBUTE_DEFINES_MODULE YES XCODE_ATTRIBUTE_DEFINES_MODULE YES
MACOSX_FRAMEWORK_IDENTIFIER com.cmake.${XCODE_FRAMEWORK_NAME} MACOSX_FRAMEWORK_IDENTIFIER com.cmake.${XCODE_FRAMEWORK_NAME}
XCODE_ATTRIBUTE_MODULEMAP_FILE "${PROJ_DIR}/ports/module.modulemap" XCODE_ATTRIBUTE_MODULEMAP_FILE "${PROJ_DIR}/pkg/apple/module.modulemap"
PUBLIC_HEADER "${frameworkHeaderGlob}" PUBLIC_HEADER "${frameworkHeaderGlob}"
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer" XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "iPhone Developer"
XCODE_ATTRIBUTE_CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES YES) XCODE_ATTRIBUTE_CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES YES)
endif() endif()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# | EXECUTABLES | # | SELFTEST |
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if(SHOULD_BUILD_TESTS) if(BUILD_HOST_SELFTEST)
add_executable(earthtest ${PROJ_DIR}/examples/cpp/earthtest.cpp) add_executable(selftest ${PROJ_DIR}/test/selftest.cpp)
target_link_libraries(earthtest ${STATIC_LIB_NAME}) target_link_libraries(selftest ${STATIC_LIB_NAME})
add_executable(adhoc ${PROJ_DIR}/examples/cpp/adhoc.cpp) project(TEST)
target_link_libraries(adhoc ${STATIC_LIB_NAME}) enable_testing()
add_executable(comprehensive ${PROJ_DIR}/examples/cpp/comprehensive.cpp) add_test(NAME selftest COMMAND selftest)
target_link_libraries(comprehensive ${STATIC_LIB_NAME})
add_executable(client ${PROJ_DIR}/examples/cpp/client.cpp)
target_link_libraries(client ${STATIC_LIB_NAME})
add_executable(server ${PROJ_DIR}/examples/cpp/server.cpp)
target_link_libraries(server ${STATIC_LIB_NAME})
add_executable(nonblockingclient
${PROJ_DIR}/examples/cpp/nonblockingclient.cpp)
target_link_libraries(nonblockingclient ${STATIC_LIB_NAME})
add_executable(nonblockingserver
${PROJ_DIR}/examples/cpp/nonblockingserver.cpp)
target_link_libraries(nonblockingserver ${STATIC_LIB_NAME})
add_executable(keymanagement ${PROJ_DIR}/examples/cpp/keymanagement.cpp)
target_link_libraries(keymanagement ${STATIC_LIB_NAME})
if(CENTRAL_API)
add_executable(centralapi ${PROJ_DIR}/examples/cpp/centralapi.cpp)
target_link_libraries(centralapi ${STATIC_LIB_NAME})
endif()
endif() endif()
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# | INSTALL | # | INSTALL |
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
if(INSTALLABLE)
set(PUBLIC_ZT_HEADERS ${PROJECT_SOURCE_DIR}/include/ZeroTierSockets.h) set(PUBLIC_ZT_HEADERS ${PROJECT_SOURCE_DIR}/include/ZeroTierSockets.h)
set_target_properties(${STATIC_LIB_NAME} PROPERTIES PUBLIC_HEADER set_target_properties(${STATIC_LIB_NAME} PROPERTIES PUBLIC_HEADER
"${PUBLIC_ZT_HEADERS}") "${PUBLIC_ZT_HEADERS}")
install( install(
@@ -598,13 +716,4 @@ install(
TARGETS ${DYNAMIC_LIB_NAME} TARGETS ${DYNAMIC_LIB_NAME}
LIBRARY DESTINATION lib LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib) ARCHIVE DESTINATION lib)
endif()
# -----------------------------------------------------------------------------
# | CI TESTS |
# -----------------------------------------------------------------------------
add_executable(errortest ${PROJ_DIR}/test/error.cpp)
target_link_libraries(errortest ${STATIC_LIB_NAME})
project(TEST)
enable_testing()
add_test(NAME MyTest COMMAND errortest)

128
Makefile
View File

@@ -1,128 +0,0 @@
DIST_BUILD_SCRIPT := ./dist.sh
#EXECUTABLES = cmake
#build_reqs := $(foreach exec,$(EXECUTABLES),\
# $(if $(shell which $(exec)),some string,$(error "No $(exec) in PATH")))
.PHONY: list
list:
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= \
-F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") \
{print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
# Pull all submodules
update:
@git submodule update --init
@git submodule status
# Patch submodules (issue update first)
patch:
#-cd ext/lwip; git apply ../lwip.patch;
#-cd ext/lwip-contrib; git apply ../lwip-contrib.patch;
#-cd ext/ZeroTierOne; git apply ../ZeroTierOne.patch;
# Target-specific clean
clean_ios:
-rm -rf ports/xcode_ios
-rm -rf ports/xcode_ios_simulator
clean_macos:
-rm -rf ports/xcode_macos
clean_android:
-rm -rf ports/android/app/build
-find ports -name ".externalNativeBuild" -exec rm -r "{}" \;
clean_products:
-rm -rf products
.PHONY: clean
clean: clean_ios clean_macos clean_android
$(DIST_BUILD_SCRIPT) clean
# Use CMake generators to build projects from CMakeLists.txt
projects:
$(DIST_BUILD_SCRIPT) generate_projects
# Android
android_debug:
$(DIST_BUILD_SCRIPT) android "debug"
$(DIST_BUILD_SCRIPT) clean_android_project
$(DIST_BUILD_SCRIPT) prep_android_example "debug"
android_release:
$(DIST_BUILD_SCRIPT) android "release"
$(DIST_BUILD_SCRIPT) clean_android_project
$(DIST_BUILD_SCRIPT) prep_android_example "release"
android_clean:
$(DIST_BUILD_SCRIPT) android "clean"
android: android_debug android_release
prep_android_debug_example:
$(DIST_BUILD_SCRIPT) prep_android_example "debug"
prep_android_release_example:
$(DIST_BUILD_SCRIPT) prep_android_example "release"
# macOS
macos_debug:
$(DIST_BUILD_SCRIPT) macos "debug"
macos_release:
$(DIST_BUILD_SCRIPT) macos "release"
macos: macos_debug macos_release
# xcframework
xcframework:
xcodebuild -project ports/apple/zt.xcodeproj archive -scheme zt -sdk macosx -archivePath build/macosx
xcodebuild -project ports/apple/zt.xcodeproj archive -scheme zt -sdk iphoneos -archivePath build/iphoneos
xcodebuild -project ports/apple/zt.xcodeproj archive -scheme zt -sdk iphonesimulator -archivePath build/iphonesimulator
xcodebuild -create-xcframework \
-framework build/macosx.xcarchive/Products/Library/Frameworks/zt.framework \
-framework build/iphoneos.xcarchive/Products/Library/Frameworks/zt.framework \
-framework build/iphonesimulator.xcarchive/Products/Library/Frameworks/zt.framework \
-output lib/zt.xcframework
rm -rf build/macosx.xcarchive
rm -rf build/iphoneos.xcarchive
rm -rf build/iphonesimulator.xcarchive
# iOS
ios_debug:
$(DIST_BUILD_SCRIPT) ios "debug"
ios_release:
$(DIST_BUILD_SCRIPT) ios "release"
ios: ios_debug ios_release
# Host
host_release:
$(DIST_BUILD_SCRIPT) host "release"
host_debug:
$(DIST_BUILD_SCRIPT) host "debug"
host_clean:
$(DIST_BUILD_SCRIPT) host "clean"
host_jar_debug:
$(DIST_BUILD_SCRIPT) host_jar "debug"
host_jar_release:
$(DIST_BUILD_SCRIPT) host_jar "release"
host_jar: host_jar_debug host_jar_release
host_pinvoke_release:
$(DIST_BUILD_SCRIPT) host_pinvoke "release"
host_pinvoke_debug:
$(DIST_BUILD_SCRIPT) host_pinvoke "debug"
host_pinvoke: host_pinvoke_release host_pinvoke_debug
host: host_debug host_release
# Build every target available on this host
all: host host_pinvoke host_jar macos ios android
$(DIST_BUILD_SCRIPT) display
# [For distribution process only] Prepare remote builds
wrap:
$(DIST_BUILD_SCRIPT) wrap
# Binary distribution
bdist:
$(DIST_BUILD_SCRIPT) merge
$(DIST_BUILD_SCRIPT) bdist
# Source distribution
sdist: update patch
$(DIST_BUILD_SCRIPT) sdist
dist: bdist sdist

23
README Normal file
View File

@@ -0,0 +1,23 @@
--------------------------------------------------------------------------------
libzt --- Encrypted P2P SD-WAN library by ZeroTier
--------------------------------------------------------------------------------
This project uses cmake as a build system generator. The scripts build.sh and
build.ps1 are used to simplify building and packaging for various targets.
dist/ : Finished targets: libraries, binaries, packages, etc.
cache/ : Build system caches that can safely be deleted after build.
pkg/ : Project, script and spec files to generate packages.
1. git submodule update --init
2. (*)nix : ./build.sh host "release"
2. Windows : . .\build.ps1; Build-Host -BuildType "Release"
To see additional build targets:
./build.sh list
Help, bugs, and feature requests: https://github.com/zerotier/libzt/issues

424
README.md
View File

@@ -1,390 +1,110 @@
# ZeroTier SDK <div align="center">
Connect physical devices, virtual devices, and application instances as if everything is on a single LAN.
***
The ZeroTier SDK brings your network into user-space. We've paired our network hypervisor core with a network stack ([lwIP](https://savannah.nongnu.org/projects/lwip/)) to provide your application with an exclusive and private virtual network interface. All traffic on this interface is end-to-end encrypted between each peer and we provide an easy-to-use socket interface derived from [Berkeley Sockets](https://en.wikipedia.org/wiki/Berkeley_sockets). Since we aren't using the kernel's network stack that means, no drivers, no root, and no host configuration requirements. For a more in-depth discussion on the technical side of ZeroTier, check out our [Manual](https://www.zerotier.com/manual.shtml). For troubleshooting advice see our [Knowledgebase](https://zerotier.atlassian.net/wiki/spaces/SD/overview). If you need further assistance, create an account at [my.zerotier.com](https://my.zerotier.com) and join our community of users and professionals. <h1>ZeroTier SDK</h1>
<img alt="zts_socket()" src="https://i.imgur.com/BwSHwE3.png"> </img>
Downloads: [download.zerotier.com/dist/sdk](https://download.zerotier.com/dist/sdk) Peer-to-peer and cross-platform encrypted connections built right into your app or service. No drivers, no root, and no host configuration.
<div style="page-break-after: always;"></div> <br>
## Building on Linux, macOS <a href="./examples">Examples</a> |
*Requires [CMake](https://cmake.org/download/), [Clang](https://releases.llvm.org/download.html) is recommended* <a href="./include/README.md">API Documentation</a> |
``` <a href="https://discuss.zerotier.com/">Community</a> |
git submodule update --init <a href="https://github.com/zerotier/libzt/issues">Report a Bug</a>
make host_release CC=clang CXX=clang++
```
## Building on Windows
*Requires [CMake](https://cmake.org/download/) and [PowerShell](https://github.com/powershell/powershell)*
``` <a href="https://www.twitter.com/zerotier"><img alt="@zerotier" src="https://img.shields.io/twitter/follow/zerotier?style=social"/></a>
git submodule update --init <a href="https://old.reddit.com/r/zerotier"><img alt="r/zerotier" src="https://img.shields.io/reddit/subreddit-subscribers/zerotier?style=social"/></a>
. ./dist.ps1
Build-Library -BuildType "Release" -Arch "Win32|x64|ARM|ARM64" -LanguageBinding "none|csharp"
```
*Note: To build both `release` and `debug` libraries for only your host's architecture use `make host`. Or optionally `make host_release` for release only. To build everything including things like iOS frameworks, Android packages, etc, use `make all`. Possible build targets can be seen by using `make list`. Resultant libraries will be placed in `./lib`, test and example programs will be placed in `./bin`*
Typical build output: <img alt="latest libzt version" src="https://img.shields.io/github/v/tag/zerotier/libzt?label=latest version"/></a>
<a href="https://github.com/zerotier/libzt/commits/master"><img alt="Last Commit" src="https://img.shields.io/github/last-commit/zerotier/libzt"/></a>
<a href="https://github.com/zerotier/libzt/actions"><img alt="Build Status (master branch)" src="https://img.shields.io/github/workflow/status/zerotier/libzt/CMake/master"/></a>
</div>
``` | Language/Platform | Installation | Version | Example |
lib |:----------|:---------|:---|:---|
├── release | C/C++ | [Build from source](#build-from-source) | <img alt="version" src="https://img.shields.io/github/v/tag/zerotier/libzt?label="/>|[C/C++](./examples/cpp) |
| └── linux-x86_64 | Objective-C | See [examples/objective-c](./examples/objective-c) | <img alt="version" src="https://img.shields.io/github/v/tag/zerotier/libzt?label="/> |[Objective-C](./examples/objective-c) |
| ├── libzt.a | C# | `Install-Package ZeroTier.Sockets` |<a href="https://www.nuget.org/packages/ZeroTier.Sockets/"><img src="https://img.shields.io/github/v/tag/zerotier/libzt?label=NuGet"/></a> |[C#](./examples/csharp) |
| └── libzt.so | Python | `pip install libzt`|<a href="https://pypi.org/project/libzt/"><img src="https://img.shields.io/pypi/v/libzt?label=PyPI"/></a> |[Python](./examples/python) |
└── debug | Rust | Coming *very* soon | <img alt="version" src="https://img.shields.io/github/v/tag/zerotier/libzt?label="/>|[Rust](./examples/rust) |
└── ... | Swift | See [examples/swift](./examples/swift) |<img alt="version" src="https://img.shields.io/github/v/tag/zerotier/libzt?label="/> |[Swift](./examples/swift) |
bin | Java | `./build.sh host-jar` |<img src="https://img.shields.io/github/v/tag/zerotier/libzt?label="/> |[Java](./examples/java) |
└── release | Node.js | See [examples/nodejs](./examples/nodejs) |<img src="https://img.shields.io/badge/-help--wanted-green"/>|[Node.js](./examples/nodejs) |
└── linux-x86_64 | Linux | [Build from source](#build-from-source) | <img alt="version" src="https://img.shields.io/github/v/tag/zerotier/libzt?label="/></a>| [C/C++](./examples/cpp) |
├── client | macOS | `brew install libzt`|<a href="https://formulae.brew.sh/formula/libzt#default"><img src="https://img.shields.io/homebrew/v/libzt?label=Homebrew"/></a> | [C/C++](./examples/cpp), [Objective-C](./examples/objective-c) |
└── server | iOS / iPadOS | `./build.sh ios-framework` | <img src="https://img.shields.io/github/v/tag/zerotier/libzt?label="/>| [Objective-C](./examples/objective-c), [Swift](./examples/swift) |
``` | Android |`./build.sh android-aar` | <img src="https://img.shields.io/github/v/tag/zerotier/libzt?label="/> | [Java](./examples/java) |
Example linking step: <br>
``` <div align="left">
clang++ -o yourApp yourApp.cpp -L./lib/release/linux-x86_64/ -lzt; ./yourApp
```
<div style="page-break-after: always;"></div>
## 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:
`zts_start(char *path, void (*userCallbackFunc)(struct 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:
``` ```
#include "ZeroTierSockets.h" #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() int main()
{ {
zts_start("configPath", &on_zts_event, 9994); zts_start(...)
uint64_t nwid = 0x0123456789abcdef; zts_join(networkId);
while (!networkReady) { sleep(1); } zts_socket(ZTS_AF_INET, ZTS_SOCK_STREAM, 0);
zts_join(nwid); zts_connect(...);
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
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.
<div style="page-break-after: always;"></div>
## Connecting and communicating with peers
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
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`:
```
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:
```
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. # Build from source
<div style="page-break-after: always;"></div>
A typical ordering of messages may look like the following:
``` ```
... git submodule update --init
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 This project uses [CMake](https://cmake.org/download/) as a build system generator. The scripts `build.*` simplify building and packaging for various targets. There are many targets and configurations not mentioned here.
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`:* |Platform| Build instructions | Notes |
|:---|:---|:---|
|Linux | `./build.sh host "release"`| [build.sh](./build.sh) |
|macOS | `./build.sh host "release"`| [build.sh](./build.sh) |
|Windows | `. .\build.ps1; Build-Host -BuildType "Release"`| [build.ps1](./build.ps1), *Requires [PowerShell](https://github.com/powershell/powershell)*|
Using the `host` keyword will automatically detect the current machine type and build standard libzt for use in C/C++ (no additional language bindings.) See `./build.sh list` for additional target options.
Example output:
``` ```
ZTS_EVENT_NODE_OFFLINE // Your node is offline. ~/libzt/dist/macos-x64-host-release
ZTS_EVENT_NODE_ONLINE // Your node is online and ready to communicate! ├── bin
ZTS_EVENT_NODE_DOWN // The node is down (for any reason.) │   ├── client
ZTS_EVENT_NODE_IDENTITY_COLLISION // There is another node with the same identity causing a conflict. │   ├── server
ZTS_EVENT_NODE_UNRECOVERABLE_ERROR // Something went wrong internally. │   └── ...
ZTS_EVENT_NODE_NORMAL_TERMINATION // Your node has terminated. └── lib
├── libzt.a
└── libzt.dylib
``` ```
*Example contents of `msg->node`:* Important directories:
``` |Directory| Purpose|
id : f746d550dd |:---|:---|
version : 1.4.6 |`dist`| Contains finished targets (libraries, binaries, packages, etc.)|
primaryPort : 9995 |`cache`| Contains build system caches that can safely be deleted after use.|
secondaryPort : 0 |`pkg`| Contains project, script and spec files to generate packages.|
```
## Network Events # Self-hosting (Optional)
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`:* We provide ways for your app or enterprise to function indepenently from any of our services if desired.
``` While we do operate a global network of redundant root servers, network controllers and an admin API/UI called [Central](https://my.zerotier.com), some use-cases require full control over the infrastructure and we try to make it as easy as possible to set up your own controllers and root servers: See [here](https://github.com/zerotier/ZeroTierOne/tree/master/controller) to learn more about how to set up your own network controller, and [here](https://www.zerotier.com/manual/#4_4) to learn more about setting up your own roots.
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`:* # Help
``` - Reference: [C API](./include/README.md)
nwid : 8bd712bf36bdae5f - Examples: [examples/](./examples)
mac : ae53fa031fcf - Bug reports: [Open a github issue](https://github.com/zerotier/libzt/issues).
name : cranky_hayes - General ZeroTier troubleshooting: [Knowledgebase](https://zerotier.atlassian.net/wiki/spaces/SD/overview).
type : 0 - Chat with us: [discuss.zerotier.com](https://discuss.zerotier.com)
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> # Licensing
## Peer Events
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`:*
```
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
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`:*
```
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
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`.
```
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
- 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
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:
```
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:
```
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!):
```
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:
```
struct zts_sockaddr_in6 in6;
...
inet_ntop(AF_INET6, &(in6->sin6_addr), dstStr, INET6_ADDRSTRLEN);
```
<div style="page-break-after: always;"></div>
## Thread model (advanced)
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
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`.
```
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>
## Licensing
ZeroTier is licensed under the BSL version 1.1. See [LICENSE.txt](./LICENSE.txt) and the ZeroTier pricing page for details. ZeroTier is free to use internally in businesses and academic institutions and for non-commercial purposes. Certain types of commercial use such as building closed-source apps and devices based on ZeroTier or offering ZeroTier network controllers and network management as a SaaS service require a commercial license.
A small amount of third party code is also included in ZeroTier and is not subject to our BSL license. See [AUTHORS.md](ext/ZeroTierOne/AUTHORS.md) for a list of third party code, where it is included, and the licenses that apply to it. All of the third party code in ZeroTier is liberally licensed (MIT, BSD, Apache, public domain, etc.). If you want a commercial license to use the ZeroTier SDK in your product contact us directly via [contact@zerotier.com](mailto:contact@zerotier.com)
ZeroTier and the ZeroTier SDK (libzt and libztcore) are licensed under the [BSL version 1.1](./LICENSE.txt). ZeroTier is free to use internally in businesses and academic institutions and for non-commercial purposes. Certain types of commercial use such as building closed-source apps and devices based on ZeroTier or offering ZeroTier network controllers and network management as a SaaS service require a commercial license. A small amount of third party code is also included in ZeroTier and is not subject to our BSL license. See [AUTHORS.md](ext/ZeroTierOne/AUTHORS.md) for a list of third party code, where it is included, and the licenses that apply to it. All of the third party code in ZeroTier is liberally licensed (MIT, BSD, Apache, public domain, etc.). If you want a commercial license to use the ZeroTier SDK in your product contact us directly via [contact@zerotier.com](mailto:contact@zerotier.com)

206
build.ps1 Normal file
View File

@@ -0,0 +1,206 @@
function Build-Host
{
$Arch="x64"
$Artifact="host"
$BuildType="Debug"
$Variant="-DBUILD_HOST=1"
# Directory for CMake to build and store intermediate files
$env:BuildDir="cache\win-$Arch-$Artifact-"+$BuildType.ToLower()
md $env:BuildDir -ErrorAction:'silentlycontinue'
# Directory where we plan to store the resultant libraries
$env:OutputDir="dist\win-$Arch-$Artifact-"+$BuildType.ToLower()
md $env:OutputDir -ErrorAction:'silentlycontinue'
pushd -Path $env:BuildDir
cmake $Variant -G "Visual Studio 16 2019" -A $Arch ../../
cmake --build . --config $BuildType
ctest -C debug
popd
#
md $env:OutputDir\lib\ -ErrorAction:'silentlycontinue'
md $env:OutputDir\bin\ -ErrorAction:'silentlycontinue'
cp $env:BuildDir\lib\$BuildType\zt.lib $env:OutputDir\lib\libzt.lib
cp $env:BuildDir\bin\$BuildType\*.exe $env:OutputDir\bin
cp $env:BuildDir\lib\$BuildType\zt-shared.dll $env:OutputDir\lib\libzt.dll
cp $env:BuildDir\lib\$BuildType\zt-shared.pdb $env:OutputDir\lib\libzt.pdb -ErrorAction:'silentlycontinue'
tree /F $env:OutputDir
}
function Build-Library([string]$BuildType, [string]$Arch, [string]$LangBinding)
{
$OptLangBinding=""
if ($LangBinding -eq "csharp") {
$OptLangBinding="-DZTS_ENABLE_PINVOKE=1"
$LangBindingPostfix="pinvoke"
}
if ($LangBinding -eq "java") {
$OptLangBinding="-DZTS_ENABLE_JAVA=1"
$LangBindingPostfix="jni"
}
$archAlias = ""
$bitCount = ""
if ($Arch -eq "Win32") {
$bitCount="32"
$archAlias="win-x86"
}
if ($Arch -eq "x64") {
$bitCount="64"
$archAlias="win-x64"
}
#if ($Arch -eq "ARM32") {
# $bitCount="32"
# $archAlias="win-arm"
#}
if ($Arch -eq "ARM") {
$bitCount="64"
$archAlias="win-arm64"
}
if ($archAlias -eq "" -or $bitCount -eq "") {
echo "No valid architecture specified. Breaking."
break
}
# Directory for CMake to build and store intermediate files
$env:BuildDir="cache\win-$Arch-$LangBindingPostfix-"+$BuildType.ToLower()
md $env:BuildDir -ErrorAction:'silentlycontinue'
# Directory where we plan to store the resultant libraries
$env:OutputDir="dist\win-$Arch-$LangBindingPostfix-"+$BuildType.ToLower()
md $env:OutputDir -ErrorAction:'silentlycontinue'
pushd -Path $env:BuildDir
cmake ${OptLangBinding} -G "Visual Studio 16 2019" -A $Arch ../../
cmake --build . --config $BuildType
popd
md $env:OutputDir\lib\ -ErrorAction:'silentlycontinue'
#cp $env:BuildDir\$BuildType\zt.lib $env:OutputDir\lib\libzt.lib
cp $env:BuildDir\$BuildType\zt-shared.dll $env:OutputDir\lib\libzt.dll
cp $env:BuildDir\$BuildType\zt-shared.pdb $env:OutputDir\lib\libzt.pdb -ErrorAction:'silentlycontinue'
}
function Build-All
{
# Win32
Build-Library -BuildType "Release" -Arch "Win32" -LangBinding ""
Build-Library -BuildType "Release" -Arch "Win32" -LangBinding "csharp"
Build-Library -BuildType "Debug" -Arch "Win32" -LangBinding ""
Build-Library -BuildType "Debug" -Arch "Win32" -LangBinding "csharp"
# x64
Build-Library -BuildType "Release" -Arch "x64" -LangBinding ""
Build-Library -BuildType "Release" -Arch "x64" -LangBinding "csharp"
Build-Library -BuildType "Debug" -Arch "x64" -LangBinding ""
Build-Library -BuildType "Debug" -Arch "x64" -LangBinding "csharp"
}
function BuildNuGetPackages([string]$Version)
{
BuildNuGetPackage-Sockets -BuildType "Release" -Arch "x64" -Version $Version
BuildNuGetPackage-Sockets -BuildType "Debug" -Arch "x64" -Version $Version
BuildNuGetPackage-Sockets -BuildType "Release" -Arch "Win32" -Version $Version
BuildNuGetPackage-Sockets -BuildType "Debug" -Arch "Win32" -Version $Version
}
function BuildNuGetPackage-Sockets([string]$BuildType, [string]$Arch, [string]$Version)
{
$archAlias = $Arch
if ($Arch -eq "Win32") {
$archAlias="x86"
}
$TargetTuple = "win-"+$archAlias+"-nuget-"+$($BuildType.ToLower())
# Where we plan to output *.nupkg(s)
md pkg\nuget\ZeroTier.Sockets\bin\ -Force
md dist\$TargetTuple -Force
del dist\$TargetTuple\*.nupkg -ErrorAction:'silentlycontinue'
# licenses
md pkg\nuget\ZeroTier.Sockets\licenses -Force
cp LICENSE.txt pkg\nuget\ZeroTier.Sockets\licenses
# contentFiles (sources)
md pkg\nuget\ZeroTier.Sockets\contentFiles -Force
cp src\bindings\csharp\*.cs pkg\nuget\ZeroTier.Sockets\contentFiles
cp examples\csharp\*.cs pkg\nuget\ZeroTier.Sockets\contentFiles
# runtimes
md pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\native -Force
md pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\lib\uap10.0 -Force
#md pkg\nuget\ZeroTier.Sockets\runtimes\win10-arm\native -Force
# Build wrapper library for C# ZeroTier.Sockets abstraction
csc -target:library -debug:pdbonly `
-pdb:pkg\nuget\ZeroTier.Sockets\bin\ZeroTier.Sockets.pdb `
-out:pkg\nuget\ZeroTier.Sockets\bin\ZeroTier.Sockets.dll `
.\src\bindings\csharp\*.cs
# Build unmanaged native libzt.dll with exported P/INVOKE symbols
Build-Library -BuildType $BuildType -Arch $Arch -LangBinding "csharp"
# Copy native libzt.dll into package tree
cp .\dist\win-$archAlias-pinvoke-$($BuildType.ToLower())\lib\*.dll `
pkg\nuget\ZeroTier.Sockets\bin\libzt.dll
# .NET Framework
md pkg\nuget\ZeroTier.Sockets\lib\net40 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net403 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net45 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net451 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net452 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net46 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net461 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net462 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net47 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net471 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net472 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net48 -Force
# .NET "Core" 5.0 (moniker missing from microsoft documentation?)
md pkg\nuget\ZeroTier.Sockets\lib\net5.0 -Force
# Copy assemblies into framework-specific directories.
$folders = Get-ChildItem pkg\nuget\ZeroTier.Sockets\lib\
foreach ($folder in $folders.name){
cp -Path "pkg\nuget\ZeroTier.Sockets\bin\*.*" `
-Destination "pkg\nuget\ZeroTier.Sockets\lib\$folder" -Recurse
}
# Native DLL placement
cp .\dist\win-$archAlias-pinvoke-$($BuildType.ToLower())\lib\*.dll `
pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\lib\uap10.0\libzt.dll
cp .\dist\win-$archAlias-pinvoke-$($BuildType.ToLower())\lib\*.dll `
pkg\nuget\ZeroTier.Sockets\lib\net40\libzt.dll
cp .\dist\win-$archAlias-pinvoke-$($BuildType.ToLower())\lib\*.dll `
pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\native\libzt.dll
cp .\dist\win-$archAlias-pinvoke-$($BuildType.ToLower())\lib\*.pdb `
pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\lib\uap10.0\libzt.pdb
# Package
pushd -Path pkg\nuget\ZeroTier.Sockets
nuget pack ZeroTier.Sockets.$archAlias.nuspec `
-Version $Version -OutputDirectory ..\..\..\dist\$TargetTuple\
popd
}
function Clean-PackageDirectory
{
rm pkg\nuget\ZeroTier.Sockets\lib `
-Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
rm pkg\nuget\ZeroTier.Sockets\contentFiles `
-Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
rm pkg\nuget\ZeroTier.Sockets\licenses `
-Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
rm pkg\nuget\ZeroTier.Sockets\runtimes `
-Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
rm pkg\nuget\ZeroTier.Sockets\bin `
-Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
}
function Clean
{
rm cache -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
rm dist -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
}

543
build.sh Executable file
View File

@@ -0,0 +1,543 @@
#!/bin/bash
# -----------------------------------------------------------------------------
# | SYSTEM DISCOVERY AND CONFIGURATION |
# -----------------------------------------------------------------------------
# Find and set cmake
CMAKE=cmake3
if [[ $(which $CMAKE) = "" ]];
then
CMAKE=cmake # try this next
fi
if [[ $(which $CMAKE) = "" ]];
then
echo "CMake (cmake) not found. Please install before continuing."
exit
fi
#
if [[ ! $(which tree) = "" ]];
then
TREE=tree
else
TREE="du -a "
fi
# Determine operating system
OSNAME=$(uname | tr '[A-Z]' '[a-z]')
if [[ $OSNAME = *"darwin"* ]]; then
SHARED_LIB_NAME="libzt.dylib"
STATIC_LIB_NAME="libzt.a"
HOST_PLATFORM="macos"
fi
if [[ $OSNAME = *"linux"* ]]; then
SHARED_LIB_NAME="libzt.so"
STATIC_LIB_NAME="libzt.a"
HOST_PLATFORM="linux"
fi
# Determine and normalize machine type
HOST_MACHINE_TYPE=$(uname -m)
if [[ $HOST_MACHINE_TYPE = *"x86_64"* ]]; then
HOST_MACHINE_TYPE="x64"
fi
# Determine number of cores. We'll tell CMake to use them all
if [[ $OSNAME = *"darwin"* ]]; then
N_PROCESSORS=$(sysctl -n hw.ncpu)
fi
if [[ $OSNAME = *"linux"* ]]; then
N_PROCESSORS=$(nproc --all)
fi
# How many processor cores CMake should use during builds,
# comment out the below line out if you don't want parallelism:
BUILD_CONCURRENCY="-j $N_PROCESSORS"
# -----------------------------------------------------------------------------
# | PATHS |
# -----------------------------------------------------------------------------
# Where we place all finished artifacts
BUILD_OUTPUT_DIR=$(pwd)/dist
# Where we tell CMake to place its build systems and their caches
BUILD_CACHE_DIR=$(pwd)/cache
# Where package projects, scripts, spec files, etc live
PKG_DIR=$(pwd)/pkg
# Default location for (host) libraries
DEFAULT_HOST_LIB_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE
# Default location for (host) binaries
DEFAULT_HOST_BIN_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE
# Default location for (host) packages
DEFAULT_HOST_PKG_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE
# Defaultlocation for CMake's caches (when building for host)
DEFAULT_HOST_BUILD_CACHE_DIR=$BUILD_CACHE_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE
gethosttype()
{
echo $HOST_PLATFORM-$HOST_MACHINE_TYPE
}
# -----------------------------------------------------------------------------
# | TARGETS |
# -----------------------------------------------------------------------------
# Build xcframework
#
# ./build.sh xcframework "debug"
#
# Example output:
#
# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/apple-xcframework-debug
# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist
#
# apple-xcframework-debug
# └── pkg
# └── zt.xcframework
# ├── Info.plist
# ├── ios-arm64
# │   └── zt.framework
# │   └── ...
# ├── ios-arm64_x86_64-simulator
# │   └── zt.framework
# │   └── ...
# └── macos-arm64_x86_64
# └── zt.framework
# └── ...
#
xcframework()
{
if [[ ! $OSNAME = *"darwin"* ]]; then
echo "Can only build this on a Mac"
exit 0
fi
BUILD_TYPE=${1:-release}
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
# Build all frameworks
macos-framework $BUILD_TYPE
iphoneos-framework $BUILD_TYPE
iphonesimulator-framework $BUILD_TYPE
ARTIFACT="xcframework"
TARGET_PLATFORM="apple"
TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR
MACOS_FRAMEWORK_DIR=macos-x64-framework-$BUILD_TYPE
IOS_FRAMEWORK_DIR=iphoneos-arm64-framework-$BUILD_TYPE
IOS_SIM_FRAMEWORK_DIR=iphonesimulator-x64-framework-$BUILD_TYPE
# Pack everything
rm -rf $PKG_OUTPUT_DIR/zt.xcframework # Remove prior to move to prevent error
xcodebuild -create-xcframework \
-framework $BUILD_CACHE_DIR/$MACOS_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \
-framework $BUILD_CACHE_DIR/$IOS_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \
-framework $BUILD_CACHE_DIR/$IOS_SIM_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \
-output $PKG_OUTPUT_DIR/zt.xcframework
}
# Build iOS framework
#
# ./build.sh iphonesimulator-framework "debug"
#
# Example output:
#
# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/iphonesimulator-x64-framework-debug
# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist
#
# /Volumes/$USER/zt/libzt/libzt-dev/dist/iphonesimulator-x64-framework-debug
# └── pkg
# └── zt.framework
# ├── Headers
# │   └── ZeroTierSockets.h
# ├── Info.plist
# ├── Modules
# │   └── module.modulemap
# └── zt
#
iphonesimulator-framework()
{
if [[ ! $OSNAME = *"darwin"* ]]; then
echo "Can only build this on a Mac"
exit 0
fi
ARTIFACT="framework"
BUILD_TYPE=${1:-Release}
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
VARIANT="-DBUILD_IOS_FRAMEWORK=True"
TARGET_PLATFORM="iphonesimulator"
TARGET_MACHINE_TYPE="x64" # presumably
CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR
# Generate project
mkdir -p $CACHE_DIR
cd $CACHE_DIR
# iOS (SDK 11+, 64-bit only, arm64)
$CMAKE -G Xcode ../../ $VARIANT
# Build framework
xcodebuild -target zt -configuration "$UPPERCASE_BUILD_TYPE" -sdk "iphonesimulator"
cd -
cp -rf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
}
# Build macOS framework
#
# ./build.sh macos-framework "debug"
#
# Example output:
#
# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/macos-x64-framework-debug
# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist
#
# /Volumes/$USER/zt/libzt/libzt-dev/dist/macos-x64-framework-debug
# └── pkg
# └── zt.framework
# ├── Headers
# │   └── ZeroTierSockets.h
# ├── Info.plist
# ├── Modules
# │   └── module.modulemap
# └── zt
#
macos-framework()
{
if [[ ! $OSNAME = *"darwin"* ]]; then
echo "Can only build this on a Mac"
exit 0
fi
ARTIFACT="framework"
BUILD_TYPE=${1:-Release}
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
VARIANT="-DBUILD_MACOS_FRAMEWORK=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR
# Generate project
mkdir -p $CACHE_DIR
cd $CACHE_DIR
$CMAKE -G Xcode ../../ $VARIANT
# Build framework
xcodebuild -target zt -configuration $UPPERCASE_BUILD_TYPE -sdk "macosx"
cd -
cp -rf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
}
# Build iOS framework
#
# ./build.sh iphoneos-framework "debug"
#
# Example output:
#
# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/iphoneos-arm64-framework-debug
# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist
#
# /Volumes/$USER/zt/libzt/libzt-dev/dist/iphoneos-arm64-framework-debug
# └── pkg
# └── zt.framework
# ├── Headers
# │   └── ZeroTierSockets.h
# ├── Info.plist
# ├── Modules
# │   └── module.modulemap
# └── zt
#
iphoneos-framework()
{
if [[ ! $OSNAME = *"darwin"* ]]; then
echo "Can only build this on a Mac"
exit 0
fi
ARTIFACT="framework"
BUILD_TYPE=${1:-Release}
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
VARIANT="-DBUILD_IOS_FRAMEWORK=True -DIOS_ARM64=True"
TARGET_PLATFORM="iphoneos"
TARGET_MACHINE_TYPE=arm64
CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR
# Generate project
mkdir -p $CACHE_DIR
cd $CACHE_DIR
# iOS (SDK 11+, 64-bit only, arm64)
$CMAKE -G Xcode ../../ $VARIANT
sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj
# Build framework
xcodebuild -arch $TARGET_MACHINE_TYPE -target zt -configuration "$UPPERCASE_BUILD_TYPE" -sdk "iphoneos"
cd -
cp -rvf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
}
# Build standard libraries, examples, and selftest
#
# ./build.sh host "release"
#
# Example output:
#
# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/linux-x64-host-release
# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist
#
# linux-x64-host-release
# ├── bin
# │   ├── client
# │   └── server
# └── lib
#  ├── libzt.a
#  └── libzt.so # .dylib, .dll
#
host()
{
ARTIFACT="host"
# Default to release
BUILD_TYPE=${1:-release}
VARIANT="-DBUILD_HOST=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
mkdir -p $LIB_OUTPUT_DIR
mkdir -p $BIN_OUTPUT_DIR
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR
cp -f $CACHE_DIR/bin/* $BIN_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
}
host-install()
{
cd cache/$HOST_PLATFORM-$HOST_MACHINE_TYPE-host-$1/
make install
cd -
}
host-uninstall()
{
cd cache/$HOST_PLATFORM-$HOST_MACHINE_TYPE-host-$1/
xargs rm < install_manifest.txt
cd -
}
# Build shared library with python wrapper symbols exported
host-python()
{
ARTIFACT="python"
# Default to release
BUILD_TYPE=${1:-release}
VARIANT="-DZTS_ENABLE_PYTHON=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
mkdir -p $LIB_OUTPUT_DIR
# Optional step to generate new SWIG wrapper
swig -c++ -python -o src/bindings/python/zt_wrap.cpp -Iinclude src/bindings/python/zt.i
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
cp -f $CACHE_DIR/lib/$SHARED_LIB_NAME $LIB_OUTPUT_DIR/_libzt.so
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
}
# Build shared library with P/INVOKE wrapper symbols exported
host-pinvoke()
{
ARTIFACT="pinvoke"
# Default to release
BUILD_TYPE=${1:-release}
VARIANT="-DZTS_ENABLE_PINVOKE=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
mkdir -p $LIB_OUTPUT_DIR
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
}
# Build shared library with Java JNI wrapper symbols exported (.jar)
host-jar()
{
ARTIFACT="jar"
# Default to release
BUILD_TYPE=${1:-release}
VARIANT="-DZTS_ENABLE_JAVA=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR
# Share same cache dir with CMake
JAVA_JAR_DIR=$CACHE_DIR/pkg/jar
JAVA_JAR_SOURCE_TREE_DIR=$JAVA_JAR_DIR/com/zerotier/libzt/
mkdir -p $JAVA_JAR_SOURCE_TREE_DIR
cp -f src/bindings/java/*.java $JAVA_JAR_SOURCE_TREE_DIR
# Build
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
# Package everything
cp -f $CACHE_DIR/lib/libzt.* $JAVA_JAR_DIR
cd $JAVA_JAR_DIR
export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
javac com/zerotier/libzt/*.java
jar cf libzt-"$(git describe --abbrev=0)".jar $SHARED_LIB_NAME com/zerotier/libzt/*.class
rm -rf com $SHARED_LIB_NAME
cd -
# Copy JAR to dist/
echo -e "\nContents of JAR:\n"
jar tf $JAVA_JAR_DIR/*.jar
echo -e
mv $JAVA_JAR_DIR/*.jar $PKG_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
}
# -----------------------------------------------------------------------------
# | ANDROID CONFIG |
# -----------------------------------------------------------------------------
ANDROID_PKG_PROJ_DIR=$(pwd)/pkg/android
# Set ANDROID_HOME because setting sdk.dir in local.properties isn't always reliable
#export PATH=/Library/Java/JavaVirtualMachines/$JDK/Contents/Home/bin/:${PATH}
#export PATH=/Users/$USER/Library/Android/sdk/platform-tools/:${PATH}
GRADLE_ARGS=--stacktrace
#ANDROID_APP_NAME=com.example.mynewestapplication
# for our purposes we limit this to execution on macOS
if [[ $OSNAME = *"linux"* ]]; then
export ANDROID_HOME=/usr/lib/android-sdk/
fi
if [[ $OSNAME = *"darwin"* ]]; then
export ANDROID_HOME=/Users/$USER/Library/Android/sdk
fi
# Build shared library with Java JNI wrapper symbols exported (.aar)
#
# ./build.sh android-aar "release"
#
# Example output:
#
# - Cache : /Volumes/$USER/zt/libzt/libzt-dev/cache/android-any-android-release
# - Build output : /Volumes/$USER/zt/libzt/libzt-dev/dist
#
# android-any-android-release
# └── libzt-release.aar
#
android-aar()
{
ARTIFACT="android"
BUILD_TYPE=${1:-release} # Default to release
CMAKE_SWITCH="ZTS_ENABLE_JAVA"
TARGET_PLATFORM="android"
TARGET_MACHINE_TYPE=any
CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
PKG_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
mkdir -p $CACHE_DIR
mkdir -p $PKG_OUTPUT_DIR
# Unsure why, but Gradle's build script chokes on this non-source file now
rm -rf ext/ZeroTierOne/ext/miniupnpc/VERSION
export PATH=$ANDROID_HOME/cmdline-tools/tools/bin:$PATH
# Copy source files into project
cp -f src/bindings/java/*.java ${ANDROID_PKG_PROJ_DIR}/app/src/main/java/com/zerotier/libzt
# Build
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
CMAKE_FLAGS="-D${CMAKE_SWITCH}=1 -D${CMAKE_SWITCH}=ON"
cd $ANDROID_PKG_PROJ_DIR
./gradlew $GRADLE_ARGS assemble$UPPERCASE_BUILD_TYPE # assembleRelease / assembleDebug
mv $ANDROID_PKG_PROJ_DIR/app/build/outputs/aar/*.aar \
$PKG_OUTPUT_DIR/libzt-$BUILD_TYPE.aar
cd -
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $PKG_OUTPUT_DIR
}
# Build static library and selftest. Currently this only tests
# the core C API, not any of the language bindings.
test()
{
ARTIFACT="test"
# Default to release
BUILD_TYPE=${1:-release}
VARIANT="-DBUILD_HOST_SELFTEST_ONLY=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
mkdir -p $BIN_OUTPUT_DIR
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
cp -f $CACHE_DIR/bin/* $BIN_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR
# Test
cd $CACHE_DIR
ctest -C release
cd -
}
# Recursive deep clean
clean()
{
# Finished artifacts
rm -rf $BUILD_OUTPUT_DIR
# CMake's build system cache
rm -rf $BUILD_CACHE_DIR
# CMake test output
rm -rf Testing
# Android AAR project binaries and sources (copied from src/bindings/java)
rm -rf $ANDROID_PKG_PROJ_DIR/app/build
rm -rf $ANDROID_PKG_PROJ_DIR/app/src/main/java/com/zerotier/libzt/*.java
rm -rf $ANDROID_PKG_PROJ_DIR/app/.externalNativeBuild
# Remove whatever remains
find . \
\( -name '*.dylib' \
-o -name '*.dll' \
-o -name '*.aar' \
-o -name '*.jar' \
-o -name '*.so' \
-o -name '*.a' \
-o -name '*.o' \
-o -name '*.exe' \
-o -name '*.o.d' \
-o -name '*.out' \
-o -name '*.log' \
-o -name '*.dSYM' \
-o -name '*.class' \
\) -exec rm -rf {} +
find . -type d -name "__pycache__" -exec rm -rf {} +
}
list()
{
IFS=$'\n'
for f in $(declare -F); do
echo "${f:11}"
done
}
"$@"

175
dist.ps1
View File

@@ -1,175 +0,0 @@
function Clean
{
Remove-Item builds -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
Remove-Item tmp -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
Remove-Item lib -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
Remove-Item bin -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
# pkg
Clean-PackageDirectory
Get-ChildItem pkg -recurse -include *.dll | remove-item
Get-ChildItem pkg -recurse -include *.lib | remove-item
Get-ChildItem pkg -recurse -include *.pdb | remove-item
Get-ChildItem pkg -recurse -include *.nupkg | remove-item
# src
Get-ChildItem src -recurse -include *.dll | remove-item
Get-ChildItem src -recurse -include *.lib | remove-item
Get-ChildItem src -recurse -include *.pdb | remove-item
Get-ChildItem src -recurse -include *.dylib | remove-item
Get-ChildItem src -recurse -include *.so | remove-item
Get-ChildItem src -recurse -include *.exe | remove-item
Get-ChildItem src -recurse -include *.out | remove-item
Get-ChildItem src -recurse -include *.a | remove-item
}
function Build-Library([string]$BuildType, [string]$Arch, [string]$LanguageBinding)
{
$OptionalLanguageBinding=""
if ($LanguageBinding -eq "csharp") {
$OptionalLanguageBinding="-DZTS_PINVOKE:BOOL=ON"
$LanguageBindingPostfix="-pinvoke"
}
if ($LanguageBinding -eq "java") {
#$OptionalLanguageBinding="-DSDK_JNI=ON -DSDK_JNI=1"
#$LanguageBindingPostfix="-jni"
}
$archAlias = ""
$bitCount = ""
if ($Arch -eq "Win32") {
$bitCount="32"
$archAlias="win-x86"
}
if ($Arch -eq "x64") {
$bitCount="64"
$archAlias="win-x64"
}
#if ($Arch -eq "ARM32") {
# $bitCount="32"
# $archAlias="win-arm"
#}
if ($Arch -eq "ARM") {
$bitCount="64"
$archAlias="win-arm64"
}
if ($archAlias -eq "" -or $bitCount -eq "") {
echo "No valid architecture specified. Breaking."
break
}
# Directory for CMake to build and store intermediate files
$env:BuildDir="tmp\$BuildType\"+$Arch+$LanguageBindingPostfix
md $env:BuildDir -ErrorAction:'silentlycontinue'
# Directory where we plan to store the resultant libraries
$env:OutputDir="lib\"+$BuildType.ToLower()
md $env:OutputDir\$archAlias$LanguageBindingPostfix -ErrorAction:'silentlycontinue'
Push-Location -Path $env:BuildDir
cmake ${OptionalLanguageBinding} -G "Visual Studio 16 2019" -A $Arch ../../../
cmake --build . --config $BuildType
Pop-Location
Copy-Item $env:BuildDir\$BuildType\zt.lib $env:OutputDir\$archAlias$LanguageBindingPostfix\libzt$bitCount.lib
Copy-Item $env:BuildDir\$BuildType\zt-shared.dll $env:OutputDir\$archAlias$LanguageBindingPostfix\libzt$bitCount.dll
Copy-Item $env:BuildDir\$BuildType\zt-shared.pdb $env:OutputDir\$archAlias$LanguageBindingPostfix\libzt$bitCount.pdb -ErrorAction:'silentlycontinue'
}
function Build-All
{
# Win32
Build-Library -BuildType "Release" -Arch "Win32" -LanguageBinding ""
Build-Library -BuildType "Release" -Arch "Win32" -LanguageBinding "pinvoke"
Build-Library -BuildType "Debug" -Arch "Win32" -LanguageBinding ""
Build-Library -BuildType "Debug" -Arch "Win32" -LanguageBinding "pinvoke"
# x64
Build-Library -BuildType "Release" -Arch "x64" -LanguageBinding ""
Build-Library -BuildType "Release" -Arch "x64" -LanguageBinding "pinvoke"
Build-Library -BuildType "Debug" -Arch "x64" -LanguageBinding ""
Build-Library -BuildType "Debug" -Arch "x64" -LanguageBinding "pinvoke"
}
function BuildNuGetPackages([string]$Version)
{
BuildNuGetPackage-Sockets -BuildType "Release" -Arch "x64" -Version $Version
BuildNuGetPackage-Sockets -BuildType "Debug" -Arch "x64" -Version $Version
BuildNuGetPackage-Sockets -BuildType "Release" -Arch "Win32" -Version $Version
BuildNuGetPackage-Sockets -BuildType "Debug" -Arch "Win32" -Version $Version
}
function BuildNuGetPackage-Sockets([string]$BuildType, [string]$Arch, [string]$Version)
{
$archAlias = $Arch
if ($Arch -eq "Win32") {
$archAlias="x86"
}
md pkg\nuget\ZeroTier.Sockets\bin\ -Force
md builds\pkg\nuget\$($BuildType.ToLower())\$archAlias -Force
del builds\pkg\nuget\$($BuildType.ToLower())\$archAlias\*.nupkg -ErrorAction:'silentlycontinue'
# licenses
md pkg\nuget\ZeroTier.Sockets\licenses -Force
Copy-Item LICENSE.txt pkg\nuget\ZeroTier.Sockets\licenses
# contentFiles (sources)
md pkg\nuget\ZeroTier.Sockets\contentFiles -Force
Copy-Item src\bindings\csharp\*.cs pkg\nuget\ZeroTier.Sockets\contentFiles
# Where we plan to output *.nupkg(s)
md builds\pkg\nuget\$($BuildType.ToLower()) -Force
# runtimes
md pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\native -Force
md pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\lib\uap10.0 -Force
#md pkg\nuget\ZeroTier.Sockets\runtimes\win10-arm\native -Force
# Build wrapper library for C# ZeroTier.Sockets abstraction
csc -target:library -debug:pdbonly -pdb:pkg\nuget\ZeroTier.Sockets\bin\ZeroTier.Sockets.pdb -out:pkg\nuget\ZeroTier.Sockets\bin\ZeroTier.Sockets.dll .\src\bindings\csharp\*.cs
# Build unmanaged native libzt.dll with exported P/INVOKE symbols
Build-Library -BuildType $BuildType -Arch $Arch -LanguageBinding "csharp"
Copy-Item .\lib\$($BuildType.ToLower())\win-$archAlias-pinvoke\*.dll pkg\nuget\ZeroTier.Sockets\bin\libzt.dll
# .NET Framework
md pkg\nuget\ZeroTier.Sockets\lib\net40 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net403 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net45 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net451 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net452 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net46 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net461 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net462 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net47 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net471 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net472 -Force
md pkg\nuget\ZeroTier.Sockets\lib\net48 -Force
# .NET "Core" 5.0 (moniker missing from microsoft documentation?)
md pkg\nuget\ZeroTier.Sockets\lib\net5.0 -Force
# Copy assemblies into framework-specific directories.
$folders = Get-ChildItem pkg\nuget\ZeroTier.Sockets\lib\
foreach ($folder in $folders.name){
Copy-Item -Path "pkg\nuget\ZeroTier.Sockets\bin\*.*" -Destination "pkg\nuget\ZeroTier.Sockets\lib\$folder" -Recurse
}
# Native DLL placement
Copy-Item .\lib\$($BuildType.ToLower())\win-$archAlias-pinvoke\*.dll pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\lib\uap10.0\libzt.dll
Copy-Item .\lib\$($BuildType.ToLower())\win-$archAlias-pinvoke\*.dll pkg\nuget\ZeroTier.Sockets\lib\net40\libzt.dll
Copy-Item .\lib\$($BuildType.ToLower())\win-$archAlias-pinvoke\*.dll pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\native\libzt.dll
Copy-Item .\lib\$($BuildType.ToLower())\win-$archAlias-pinvoke\*.pdb pkg\nuget\ZeroTier.Sockets\runtimes\win10-$archAlias\lib\uap10.0\libzt.pdb
# Package
Push-Location -Path pkg\nuget\ZeroTier.Sockets
nuget pack ZeroTier.Sockets.$archAlias.nuspec -Version $Version -OutputDirectory ..\..\..\builds\pkg\nuget\$($BuildType.ToLower())\$archAlias
Pop-Location
}
function Clean-PackageDirectory
{
Remove-Item pkg\nuget\ZeroTier.Sockets\lib -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
Remove-Item pkg\nuget\ZeroTier.Sockets\contentFiles -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
Remove-Item pkg\nuget\ZeroTier.Sockets\licenses -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
Remove-Item pkg\nuget\ZeroTier.Sockets\runtimes -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
Remove-Item pkg\nuget\ZeroTier.Sockets\bin -Recurse -Force -Confirm:$false -ErrorAction:'silentlycontinue'
}

734
dist.sh
View File

@@ -1,734 +0,0 @@
#!/bin/bash
# This script works in conjunction with the Makefile and CMakeLists.txt. It is
# intended to be called from the Makefile, it generates projects and builds
# targets as specified in CMakeLists.txt. In addition, this script is
# responsible for packaging all of the resultant builds, licenses, and
# documentation as well as controlling the installation and remote execution of
# tests on mobile devices.
# Example workflow for producing a full release package:
#
# (1) On packaging platform, build most targets (including android and ios):
# (1a) make all
# (1b) make wrap
# (2) On other supported platforms, build remaining supported targets
# and copy them into a directory structure that is expected by a later stage:
# (2a) make all
# (2b) make wrap
# (3) Copy all resultant $(ARCH)_product directories to root project directory
# of packaging platform. For instance:
#
# libzt
# ├── README.md
# ├── products
# ├── linux-x86_64_products
# ├── linux-armv7l_products
# ├── linux-armv6l_products
# ├── products
# ├── win_products
# └── ...
#
# (4) Merge all builds into single `products` directory and package:
# (4a) make clean
# (4a) make dist
CMAKE=cmake
BUILD_CONCURRENCY=
#"-j 2"
OSNAME=$(uname | tr '[A-Z]' '[a-z]')
BUILD_TMP=$(pwd)/tmp
ANDROID_PROJ_DIR=$(pwd)/ports/android
XCODE_IOS_PROJ_DIR=$(pwd)/ports/xcode_ios
XCODE_IOS_SIMULATOR_PROJ_DIR=$(pwd)/ports/xcode_ios_simulator
XCODE_MACOS_PROJ_DIR=$(pwd)/ports/xcode_macos
# Generates wrapper source files for various target languages
generate_swig_wrappers()
{
SRC=../src
cd ports/;
# C#
mkdir -p ${SRC}/csharp
swig -csharp -c++ zt.i
# Prepend our callback garb to libzt.cs, copy new source files into src/csharp
cat csharp/csharp_callback.cs libzt.cs > libzt_concat.cs
rm libzt.cs
mv libzt_concat.cs libzt.cs
mv -f *.cs zt_wrap.cxx ${SRC}/csharp/
# Javascript
# Build for all three engines. Why not?
ENGINE=jsc
mkdir -p ${SRC}/js/${ENGINE}
swig -javascript -${ENGINE} -c++ zt.i
mv zt_wrap.cxx ${SRC}/js/${ENGINE}
ENGINE=v8
mkdir -p ${SRC}/js/${ENGINE}
swig -javascript -${ENGINE} -c++ zt.i
mv zt_wrap.cxx ${SRC}/js/${ENGINE}
ENGINE=node
mkdir -p ${SRC}/js/${ENGINE}
swig -javascript -${ENGINE} -c++ zt.i
mv -f zt_wrap.cxx ${SRC}/js/${ENGINE}
# Python
mkdir -p ${SRC}/python
swig -python -c++ zt.i
mv -f zt_wrap.cxx *.py ${SRC}/python
# Lua
mkdir -p ${SRC}/lua
swig -lua -c++ zt.i
mv -f zt_wrap.cxx ${SRC}/lua
# Go 64
mkdir -p ${SRC}/go64
swig -intgosize 64 -go -c++ zt.i
mv -f zt_wrap.cxx *.go *.c ${SRC}/go64
# Go 32
mkdir -p ${SRC}/go32
swig -intgosize 32 -go -c++ zt.i
mv -f zt_wrap.cxx *.go *.c ${SRC}/go32
cd -
}
# Generates projects if needed
generate_projects()
{
if [[ ! $OSNAME = *"darwin"* ]]; then
exit 0
fi
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
if [[ $OSNAME = *"darwin"* ]]; then
# iOS (SDK 11+, 64-bit only, arm64)
if [ ! -d "$XCODE_IOS_PROJ_DIR" ]; then
mkdir -p $XCODE_IOS_PROJ_DIR
cd $XCODE_IOS_PROJ_DIR
$CMAKE -G Xcode ../../ -DIOS_FRAMEWORK=1 -DIOS_ARM64=1
# Manually replace arch strings in project file
sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj
cd -
fi
if [ ! -d "$XCODE_IOS_SIMULATOR_PROJ_DIR" ]; then
mkdir -p $XCODE_IOS_SIMULATOR_PROJ_DIR
cd $XCODE_IOS_SIMULATOR_PROJ_DIR
$CMAKE -G Xcode ../../ -DIOS_FRAMEWORK=1
# Manually replace arch strings in project file
#sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj
cd -
fi
# macOS
if [ ! -d "$XCODE_MACOS_PROJ_DIR" ]; then
mkdir -p $XCODE_MACOS_PROJ_DIR
cd $XCODE_MACOS_PROJ_DIR
$CMAKE -G Xcode ../../ -DMACOS_FRAMEWORK=1
cd -
fi
fi
}
# Build framework for iOS (with embedded static library)
ios()
{
if [[ ! $OSNAME = *"darwin"* ]]; then
exit 0
fi
generate_projects # if needed
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
cd $XCODE_IOS_PROJ_DIR
# Framework
xcodebuild -arch arm64 -target zt -configuration "$UPPERCASE_CONFIG" -sdk "iphoneos"
cd -
IOS_OUTPUT_DIR=$(pwd)/lib/$1/ios
mkdir -p $IOS_OUTPUT_DIR
rm -rf $IOS_OUTPUT_DIR/zt.framework # Remove prior to move to prevent error
mv $XCODE_IOS_PROJ_DIR/$UPPERCASE_CONFIG-iphoneos/* $IOS_OUTPUT_DIR
cd $XCODE_IOS_SIMULATOR_PROJ_DIR
# Framework
xcodebuild -target zt -configuration "$UPPERCASE_CONFIG" -sdk "iphonesimulator"
cd -
SIMULATOR_OUTPUT_DIR=$(pwd)/lib/$1/ios-simulator
mkdir -p $SIMULATOR_OUTPUT_DIR
rm -rf $SIMULATOR_OUTPUT_DIR/zt.framework # Remove prior to move to prevent error
mv $XCODE_IOS_SIMULATOR_PROJ_DIR/$UPPERCASE_CONFIG-iphonesimulator/* $SIMULATOR_OUTPUT_DIR
# Combine the two archs
lipo -create $IOS_OUTPUT_DIR/zt.framework/zt $SIMULATOR_OUTPUT_DIR/zt.framework/zt -output $IOS_OUTPUT_DIR/zt.framework/zt
# Clean up
rm -rf $SIMULATOR_OUTPUT_DIR
}
# Build framework for current host (macOS only)
macos()
{
if [[ ! $OSNAME = *"darwin"* ]]; then
exit 0
fi
generate_projects # if needed
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
cd $XCODE_MACOS_PROJ_DIR
# Framework
xcodebuild -target zt -configuration "$UPPERCASE_CONFIG" -sdk "macosx"
cd -
OUTPUT_DIR=$(pwd)/lib/$1/macos-universal
mkdir -p $OUTPUT_DIR
rm -rf $OUTPUT_DIR/zt.framework # Remove prior to move to prevent error
mv $XCODE_MACOS_PROJ_DIR/$UPPERCASE_CONFIG/* $OUTPUT_DIR
}
# Build xcframework
xcframework()
{
if [[ ! $OSNAME = *"darwin"* ]]; then
exit 0
fi
generate_projects # if needed
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
OUTPUT_DIR=$(pwd)/lib/$1
cd $XCODE_MACOS_PROJ_DIR
xcodebuild -target zt -configuration "$UPPERCASE_CONFIG" -sdk "macosx"
cd $XCODE_IOS_PROJ_DIR
xcodebuild -arch arm64 -target zt -configuration "$UPPERCASE_CONFIG" -sdk "iphoneos"
cd $XCODE_IOS_SIMULATOR_PROJ_DIR
xcodebuild -target zt -configuration "$UPPERCASE_CONFIG" -sdk "iphonesimulator"
mkdir -p $OUTPUT_DIR
rm -rf $OUTPUT_DIR/zt.xcframework # Remove prior to move to prevent error
xcodebuild -create-xcframework \
-framework $XCODE_MACOS_PROJ_DIR/$UPPERCASE_CONFIG/zt.framework \
-framework $XCODE_IOS_PROJ_DIR/$UPPERCASE_CONFIG-iphoneos/zt.framework \
-framework $XCODE_IOS_SIMULATOR_PROJ_DIR/$UPPERCASE_CONFIG-iphonesimulator/zt.framework \
-output $OUTPUT_DIR/zt.xcframework
}
# Build Java JAR for current host (uses JNI)
host_jar()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
copy_root_java_sources_to_projects
NORMALIZED_OSNAME=$OSNAME
if [[ $OSNAME = *"darwin"* ]]; then
DYNAMIC_LIB_NAME="libzt.dylib"
NORMALIZED_OSNAME="macos"
fi
if [[ $OSNAME = *"linux"* ]]; then
DYNAMIC_LIB_NAME="libzt.so"
fi
LIB_OUTPUT_DIR=$(pwd)/lib/$1/${NORMALIZED_OSNAME}-$(uname -m)
mkdir -p $LIB_OUTPUT_DIR
rm -rf $LIB_OUTPUT_DIR/zt.jar
# Build dynamic library
BUILD_DIR=$(pwd)/tmp/${NORMALIZED_OSNAME}-$(uname -m)-jni-$1
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
$CMAKE -H. -B$BUILD_DIR -DCMAKE_BUILD_TYPE=$UPPERCASE_CONFIG -DSDK_JNI=ON "-DSDK_JNI=1"
$CMAKE --build $BUILD_DIR $BUILD_CONCURRENCY
# Copy dynamic library from previous build step
# And, remove any lib that may exist prior. We don't want accidental successes
cd $(pwd)/ports/java
rm $DYNAMIC_LIB_NAME
mv $BUILD_DIR/lib/$DYNAMIC_LIB_NAME .
# Begin constructing JAR
export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
javac com/zerotier/libzt/*.java
jar cf zt.jar $DYNAMIC_LIB_NAME com/zerotier/libzt/*.class
rm $DYNAMIC_LIB_NAME
cd -
# Move completed JAR
LIB_OUTPUT_DIR=$(pwd)/lib/$1/${NORMALIZED_OSNAME}-$(uname -m)
mkdir -p $LIB_OUTPUT_DIR
mv $(pwd)/ports/java/zt.jar $LIB_OUTPUT_DIR
# Build sample app classes
# Remove old dynamic library if it exists
rm -rf $(pwd)/examples/java/$DYNAMIC_LIB_NAME
javac -cp ".:"$LIB_OUTPUT_DIR/zt.jar $(pwd)/examples/java/src/com/zerotier/libzt/javasimpleexample/*.java
# To run:
# jar xf $LIB_OUTPUT_DIR/zt.jar libzt.dylib
# cp libzt.dylib examples/java/
# java -cp "lib/debug/macos-x86_64/zt.jar:examples/java/src/main/java" ExampleApp
}
# Build all ordinary library types for current host
host_pinvoke()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
NORMALIZED_OSNAME=$OSNAME
if [[ $OSNAME = *"darwin"* ]]; then
DYNAMIC_LIB_NAME="libzt.dylib"
NORMALIZED_OSNAME="macos"
fi
if [[ $OSNAME = *"linux"* ]]; then
DYNAMIC_LIB_NAME="libzt.so"
fi
# CMake build files
BUILD_DIR=$(pwd)/tmp/${NORMALIZED_OSNAME}-$(uname -m)-$1
mkdir -p $BUILD_DIR
# Where to place results
BIN_OUTPUT_DIR=$(pwd)/bin/$1/${NORMALIZED_OSNAME}-$(uname -m)
mkdir -p $BIN_OUTPUT_DIR
rm -rf $BIN_OUTPUT_DIR/*
LIB_OUTPUT_DIR=$(pwd)/lib/$1/${NORMALIZED_OSNAME}-$(uname -m)-pinvoke
mkdir -p $LIB_OUTPUT_DIR
rm -rf $LIB_OUTPUT_DIR/libzt.a $LIB_OUTPUT_DIR/$DYNAMIC_LIB_NAME $LIB_OUTPUT_DIR/libztcore.a
# Build
cmake -DZTS_PINVOKE=True -H. -B$BUILD_DIR -DCMAKE_BUILD_TYPE=$1
$CMAKE --build $BUILD_DIR $BUILD_CONCURRENCY
# Move and clean up
cp -f $BUILD_DIR/bin/* $BIN_OUTPUT_DIR
cp -f $BUILD_DIR/lib/* $LIB_OUTPUT_DIR
clean_post_build
}
# Build all ordinary library types for current host
host()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
NORMALIZED_OSNAME=$OSNAME
if [[ $OSNAME = *"darwin"* ]]; then
DYNAMIC_LIB_NAME="libzt.dylib"
NORMALIZED_OSNAME="macos"
fi
if [[ $OSNAME = *"linux"* ]]; then
DYNAMIC_LIB_NAME="libzt.so"
fi
# CMake build files
BUILD_DIR=$(pwd)/tmp/${NORMALIZED_OSNAME}-$(uname -m)-$1
mkdir -p $BUILD_DIR
# Where to place results
BIN_OUTPUT_DIR=$(pwd)/bin/$1/${NORMALIZED_OSNAME}-$(uname -m)
mkdir -p $BIN_OUTPUT_DIR
rm -rf $BIN_OUTPUT_DIR/*
LIB_OUTPUT_DIR=$(pwd)/lib/$1/${NORMALIZED_OSNAME}-$(uname -m)
mkdir -p $LIB_OUTPUT_DIR
rm -rf $LIB_OUTPUT_DIR/libzt.a $LIB_OUTPUT_DIR/$DYNAMIC_LIB_NAME $LIB_OUTPUT_DIR/libztcore.a
# Build
$CMAKE -H. -B$BUILD_DIR -DCMAKE_BUILD_TYPE=$1
$CMAKE --build $BUILD_DIR $BUILD_CONCURRENCY
# Move and clean up
cp -f $BUILD_DIR/bin/* $BIN_OUTPUT_DIR
cp -f $BUILD_DIR/lib/* $LIB_OUTPUT_DIR
clean_post_build
}
# Set important variables for Android builds
set_android_env()
{
#JDK=jdk1.8.0_202.jdk
# Set ANDROID_HOME because setting sdk.dir in local.properties isn't always reliable
export ANDROID_HOME=/Users/$USER/Library/Android/sdk
export PATH=/Library/Java/JavaVirtualMachines/$JDK/Contents/Home/bin/:${PATH}
export PATH=/Users/$USER/Library/Android/sdk/platform-tools/:${PATH}
GRADLE_ARGS=--stacktrace
ANDROID_APP_NAME=com.example.mynewestapplication
}
# Build android AAR from ports/android
android()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
set_android_env
copy_root_java_sources_to_projects
# NOTE: There's no reason this won't build on linux, it's just that
# for our purposes we limit this to execution on macOS
if [[ ! $OSNAME = *"darwin"* ]]; then
exit 0
fi
# CMake build files
BUILD_DIR=$(pwd)/tmp/android-$1
mkdir -p $BUILD_DIR
# If clean requested, remove temp build dir
if [[ $1 = *"clean"* ]]; then
rm -rf $BUILD_DIR
exit 0
fi
# Where to place results
LIB_OUTPUT_DIR=$(pwd)/lib/$1/android
mkdir -p $LIB_OUTPUT_DIR
# Build
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
CMAKE_FLAGS="-DSDK_JNI=1 -DSDK_JNI=ON"
cd $ANDROID_PROJ_DIR
./gradlew $GRADLE_ARGS assemble$UPPERCASE_CONFIG # assembleRelease / assembleDebug
mv $ANDROID_PROJ_DIR/app/build/outputs/aar/app-$1.aar \
$LIB_OUTPUT_DIR/libzt-$1.aar
cd -
}
# Remove intermediate object files and/or libraries
clean_post_build()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
find $(pwd)/lib -type f -name 'liblwip_pic.a' -exec rm {} +
find $(pwd)/lib -type f -name 'liblwip.a' -exec rm {} +
find $(pwd)/lib -type f -name 'libminiupnpc.a' -exec rm {} +
find $(pwd)/lib -type f -name 'libminiupnpc_pic.a' -exec rm {} +
find $(pwd)/lib -type f -name 'libnatpmp.a' -exec rm {} +
find $(pwd)/lib -type f -name 'libnatpmp_pic.a' -exec rm {} +
find $(pwd)/lib -type f -name 'libzto_pic.a' -exec rm {} +
find $(pwd)/lib -type f -name 'libzt_pic.a' -exec rm {} +
}
# General clean
clean()
{
# Remove all temporary build files, products, etc
rm -rf builds tmp lib bin products
rm -f *.o *.s *.exp *.lib *.core core
# Generally search for and remove object files, libraries, etc
find . -path './*_products' -prune -type f \( -name '*.dylib' -o -name '*.dll' -o -name '*.so' -o -name \
'*.a' -o -name '*.o' -o -name '*.exe' -o -name '*.o.d' -o -name \
'*.out' -o -name '*.log' -o -name '*.dSYM' -o -name '*.class' \) -delete
# Remove any sources copied to project directories
rm -rf ports/android/app/src/main/java/com/zerotier/libzt/*.java
rm -rf ports/java/com/zerotier/libzt/*.java
}
# Copy and rename Android AAR from lib to example app directory
prep_android_example()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
mkdir -p examples/android/ExampleAndroidApp/app/libs/
cp -f lib/$1/android/libzt-$1.aar \
examples/android/ExampleAndroidApp/app/libs/libzt.aar
}
# Clean Android project
clean_android_project()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
set_android_env
ANDROID_EXAMPLE_PROJ_DIR="examples/android/ExampleAndroidApp"
cd $ANDROID_EXAMPLE_PROJ_DIR
./gradlew $GRADLE_ARGS clean
./gradlew $GRADLE_ARGS cleanBuildCache
cd -
}
# Build APK from AAR and sources
build_android_app()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
set_android_env
ANDROID_EXAMPLE_PROJ_DIR="examples/android/ExampleAndroidApp"
UPPERCASE_CONFIG="$(tr '[:lower:]' '[:upper:]' <<< ${1:0:1})${1:1}"
cd $ANDROID_EXAMPLE_PROJ_DIR
./gradlew assemble$UPPERCASE_CONFIG
cd -
}
# Stops an Android app that is already installed on device
stop_android_app()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
set_android_env
adb shell am force-stop $ANDROID_APP_NAME
}
# Starts an Android app that is already installed on device
start_android_app()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
set_android_env
adb shell monkey -p $ANDROID_APP_NAME 1
}
# Copy and install example Android app on device
install_android_app()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
set_android_env
if [[ $1 = "release" ]]; then
APKNAME=app-$1-"unsigned"
else
APKNAME=app-$1
fi
APK=examples/android/ExampleAndroidApp/app/build/outputs/apk/$1/$APKNAME.apk
echo "Installing $APK ..."
adb install -r $APK
}
# Perform all steps necessary to run a new instance of the app on device
run_android_app()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
stop_android_app
prep_android_example $1
clean_android_project
# The following two functions take 'debug' as an argument regardless
# of the build type since the native code is built with the proper
# configuration anyway.
build_android_app "debug"
install_android_app "debug"
start_android_app
}
# View ADB logs of running Android app
android_app_log()
{
set_android_env
if [[ $OSNAME = *"darwin"* ]]; then
adb logcat
fi
}
# View ADB logs of running Android app (filtered, must restart for each app re-launch)
android_app_log_filtered()
{
set_android_env
if [[ $OSNAME = *"darwin"* ]]; then
adb logcat | grep -F "`adb shell ps | grep $ANDROID_APP_NAME | cut -c10-15`"
fi
}
# Copy java sources to projects before build process. This is so
# that we only have to maintain one set of sources for multiple java-
# based projects.
copy_root_java_sources_to_projects()
{
cp -f src/java/*.java ports/android/app/src/main/java/com/zerotier/libzt
cp -f src/java/*.java ports/java/com/zerotier/libzt/
}
# At the end of build stage, print contents and trees for inspection
display()
{
find $(pwd)/lib -type f -name 'zt.jar' -exec echo -e "\n" \; -exec ls {} \; -exec jar tf {} +
echo -e "\n"
tree $(pwd)/lib
}
# Merge all remotely-built targets. This is used before dist()
merge()
{
if [ -d "darwin-x86_64_products" ]; then
rsync -a darwin-x86_64_products/ products/
else
echo "Warning: darwin-x86_64_products is missing"
fi
# x86_64 64-bit linux
REMOTE_PRODUCTS_DIR=linux-x86_64_products
if [ -d "$REMOTE_PRODUCTS_DIR" ]; then
rsync -a $REMOTE_PRODUCTS_DIR/ products/
echo "Merged products from " $REMOTE_PRODUCTS_DIR " to " products
else
echo "Warning: $REMOTE_PRODUCTS_DIR is missing"
fi
# armv7l linux
REMOTE_PRODUCTS_DIR=linux-armv7l_products
if [ -d "$REMOTE_PRODUCTS_DIR" ]; then
rsync -a $REMOTE_PRODUCTS_DIR/ products/
echo "Merged products from " $REMOTE_PRODUCTS_DIR " to " products
else
echo "Warning: $REMOTE_PRODUCTS_DIR is missing"
fi
# armv6l linux
REMOTE_PRODUCTS_DIR=linux-armv6l_products
if [ -d "$REMOTE_PRODUCTS_DIR" ]; then
rsync -a $REMOTE_PRODUCTS_DIR/ products/
echo "Merged products from " $REMOTE_PRODUCTS_DIR " to " products
else
echo "Warning: $REMOTE_PRODUCTS_DIR is missing"
fi
# 32/64-bit windows
REMOTE_PRODUCTS_DIR=win_products
if [ -d "$REMOTE_PRODUCTS_DIR" ]; then
rsync -a $REMOTE_PRODUCTS_DIR/ products/
echo "Merged products from " $REMOTE_PRODUCTS_DIR " to " products
else
echo "Warning: $REMOTE_PRODUCTS_DIR is missing"
fi
}
# On hosts which are not the final packaging platform (e.g. armv7, armv6l, etc)
# we will rename the products directory so that we can merge() it at a later
# stage on the packaging platform
wrap()
{
ARCH_WRAP_DIR=$OSNAME"-"$(uname -m)_products
cp -rf lib $ARCH_WRAP_DIR
echo "Copied products to:" $ARCH_WRAP_DIR
PROD_FILENAME=$ARCH_WRAP_DIR.tar.gz
tar --exclude=$PROD_FILENAME -zcvf $PROD_FILENAME -C $ARCH_WRAP_DIR .
}
# Renames and copies licenses for libzt and each of its dependencies
package_licenses()
{
CURR_DIR=$1
DEST_DIR=$2
mkdir -p $DEST_DIR
cp $CURR_DIR/ext/lwip/COPYING $DEST_DIR/LWIP-LICENSE.BSD
cp $CURR_DIR/ext/concurrentqueue/LICENSE.md $DEST_DIR/CONCURRENTQUEUE-LICENSE.BSD
cp $CURR_DIR/LICENSE.txt $DEST_DIR/ZEROTIER-LICENSE.BSL-1.1
cp $CURR_DIR/include/net/ROUTE_H-LICENSE.APSL $DEST_DIR/ROUTE_H-LICENSE.APSL
cp $CURR_DIR/include/net/ROUTE_H-LICENSE $DEST_DIR/ROUTE_H-LICENSE
}
# Copies binaries, documentation, licenses, source, etc into a products
# directory and then tarballs everything together
package_everything()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
LIBZT_VERSION=$(git describe)
PROD_NAME=$LIBZT_VERSION-$(date '+%Y%m%d_%H-%M')-$1
PROD_DIR=$(pwd)/products/$PROD_NAME/
# Make products directory
# Licenses
package_licenses $(pwd) $PROD_DIR/licenses
# Examples
mkdir -p $PROD_DIR/examples
cp examples/cpp/* $PROD_DIR/examples
# Source
mkdir -p $PROD_DIR/src
cp src/*.cpp src/*.hpp src/*.c src/*.h $PROD_DIR/src
cp $(pwd)/README.pdf $PROD_DIR/README.pdf
# Header(s)
mkdir -p $PROD_DIR/include
cp $(pwd)/include/*.h $PROD_DIR/include
# Libraries
mkdir -p $PROD_DIR/lib
cp -r $(pwd)/products/$1/* $PROD_DIR/lib
rm -rf $(pwd)/products/$1
# Clean
find $PROD_DIR -type f \( -name '*.DS_Store' -o -name 'thumbs.db' \) -delete
# Record the version (and each submodule's version)
echo "$(git describe)" > $PROD_DIR/VERSION
echo -e "$(git submodule status | awk '{$1=$1};1')" >> $PROD_DIR/VERSION
echo -e "$(cat ext/ZeroTierOne/version.h | grep ZEROTIER_ONE_VERSION | sed 's/\#define//g' | awk '{$1=$1};1')" >> $PROD_DIR/VERSION
echo "$(date)" >> $PROD_DIR/VERSION
# Tar everything
PROD_FILENAME=$(pwd)/products/$PROD_NAME.tar.gz
tar --exclude=$PROD_FILENAME -zcvf $PROD_FILENAME -C $PROD_DIR .
if [[ $OSNAME = *"darwin"* ]]; then
md5 $PROD_FILENAME
fi
if [[ $OSNAME = *"linux"* ]]; then
md5sum $PROD_FILENAME
fi
# Print results for post-build inspection
echo -e "\n"
tree $PROD_DIR
cat $PROD_DIR/VERSION
# Final check. Display warnings if anything is missing
FILES="VERSION
README.md
README.pdf
reference/errno.h
licenses/LWIP-LICENSE.BSD
licenses/CONCURRENTQUEUE-LICENSE.BSD
licenses/ZEROTIER-LICENSE.BSL-1.1
licenses/ROUTE_H-LICENSE.APSL
licenses/ROUTE_H-LICENSE
licenses/LWIP-LICENSE.BSD"
for f in $FILES
do
if [ ! -f "$PROD_DIR$f" ]; then
echo "Warning: $PROD_DIR$f is missing"
fi
done
}
# Generates a source-only tarball
sdist()
{
VERSION=$(git describe --abbrev=0)
TARBALL_DIR="libzt-${VERSION}"
TARBALL_NAME=libzt-${VERSION}-source.tar.gz
PROD_DIR=$(pwd)/products/
mkdir -p $PROD_DIR
#
mkdir ${TARBALL_DIR}
# primary sources
cp -rf src ${TARBALL_DIR}/src
cp -rf include ${TARBALL_DIR}/include
# important build scripts
cp Makefile ${TARBALL_DIR}
cp CMakeLists.txt ${TARBALL_DIR}
cp *.md ${TARBALL_DIR}
cp *.sh ${TARBALL_DIR}
cp *.bat ${TARBALL_DIR}
# submodules/dependencies
# lwIP
mkdir ${TARBALL_DIR}/ext
mkdir -p ${TARBALL_DIR}/ext/lwip/src
cp -rf ext/lwip/src/api ${TARBALL_DIR}/ext/lwip/src
cp -rf ext/lwip/src/core ${TARBALL_DIR}/ext/lwip/src
cp -rf ext/lwip/src/include ${TARBALL_DIR}/ext/lwip/src
cp -rf ext/lwip/src/netif ${TARBALL_DIR}/ext/lwip/src
# lwIP ports
mkdir -p ${TARBALL_DIR}/ext/lwip-contrib/ports
cp -rf ext/lwip-contrib/ports/unix ${TARBALL_DIR}/ext/lwip-contrib/ports
cp -rf ext/lwip-contrib/ports/win32 ${TARBALL_DIR}/ext/lwip-contrib/ports
# ZeroTierOne
mkdir ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/*.h ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/controller ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/ext ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/include ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/node ${TARBALL_DIR}/ext/ZeroTierOne
cp -rf ext/ZeroTierOne/osdep ${TARBALL_DIR}/ext/ZeroTierOne
#
# Perform selective removal
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/bin
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/tap-mac
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/librethinkdbxx
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/installfiles
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/curl-*
rm -rf ${TARBALL_DIR}/ext/ZeroTierOne/ext/http-parser
#
mkdir ${TARBALL_DIR}/ext/concurrentqueue
cp -rf ext/concurrentqueue/*.h ${TARBALL_DIR}/ext/concurrentqueue
# Licenses
package_licenses $(pwd) $TARBALL_DIR/licenses
# Tarball everything and display the results
tar -cvf ${TARBALL_NAME} ${TARBALL_DIR}
tree ${TARBALL_DIR}
rm -rf ${TARBALL_DIR}
mv ${TARBALL_NAME} ${PROD_DIR}
}
# Package both debug and release
bdist()
{
echo "Executing task: " ${FUNCNAME[ 0 ]} "(" $1 ")"
package_everything "debug"
package_everything "release"
}
# Generate a markdown CHANGELOG from git-log
update_changelog()
{
first_commit=$(git rev-list --max-parents=0 HEAD)
git for-each-ref --sort=-refname --format="## [%(refname:short)] - %(taggerdate:short) &(newline)*** &(newline)- %(subject) %(body)" refs/tags > CHANGELOG.md
gsed -i '''s/\&(newline)/\n/' CHANGELOG.md # replace first instance
gsed -i '''s/\&(newline)/\n/' CHANGELOG.md # replace second instance
echo -e "\n" >> CHANGELOG.md
for curr_tag in $(git tag -l --sort=-v:refname)
do
prev_tag=$(git describe --abbrev=0 ${curr_tag}^)
if [ -z "${prev_tag}" ]
then
prev_tag=${first_commit}
fi
echo "[${curr_tag}]: https://github.com/zerotier/libzt/compare/${prev_tag}..${curr_tag}" >> CHANGELOG.md
done
}
# List all functions in this script (just for convenience)
list()
{
IFS=$'\n'
for f in $(declare -F); do
echo "${f:11}"
done
}
"$@"

View File

@@ -1,57 +1 @@
Useful things to know Please read the [Common pitfalls](../include/README.md#common-pitfalls) section in the C API reference documentation.
=====
### IDENTITIES and AUTHORIZATION:
Upon the first execution of this code, a new identity will be generated and placed in the location given in the first argument to zts_start(path, ...). If you accidentally duplicate the identity files and use them simultaneously in a different node instance **you will experience undefined behavior** and it is likely that nothing will work.
You must authorize the node ID provided by the `ZTS_EVENT_NODE_ONLINE` callback to join your network, otherwise nothing will happen. This can be done manually or via our web API: https://my.zerotier.com/help/api
An exception to the above rule is if you are using an Ad-hoc network, it has no controller and therefore requires no authorization.
### ESTABLISHING A CONNECTION:
Creating a standard socket connection generally works the same as it would using an ordinary socket interface, however with libzt there is a subtle difference in how connections are established which may cause confusion:
The underlying virtual ZT layer creates what are called "transport-triggered links" between nodes. That is, links are not established until an attempt to communicate with a peer has taken place. The side effect is that the first few packets sent from a libzt instance are usually relayed via our free infrastructure and it isn't until a root server has passed contact information to both peers that a direct connection will be established. Therefore, it is required that multiple connection attempts be undertaken when initially communicating with a peer. After a transport-triggered link is established libzt will inform you via `ZTS_EVENT_PEER_DIRECT` for a specific peer ID. No action is required on your part for this callback event.
*Note: In these initial moments before `ZTS_EVENT_PEER_DIRECT` has been received for a specific peer, traffic may be slow, jittery and there may be high packet loss. This will subside within a couple of seconds.*
### ERROR HANDLING:
libzt's API is actually composed of two categories of functions with slightly different error reporting mechanisms.
- Category 1: Control functions (`zts_start`, `zts_join`, `zts_get_peer_status`, etc). Errors returned by these functions can be any of the following:
```
ZTS_ERR_OK // No error
ZTS_ERR_SOCKET // Socket error, see zts_errno
ZTS_ERR_SERVICE // You probably did something at the wrong time
ZTS_ERR_ARG // Invalid argument
ZTS_ERR_NO_RESULT // No result (not necessarily an error)
ZTS_ERR_GENERAL // Consider filing a bug report
```
- Category 2: Sockets (`zts_socket`, `zts_bind`, `zts_connect`, `zts_listen`, etc). Errors returned by these functions can be the same as the above. With the added possibility of `zts_errno` being set. Much like standard errno this will provide a more specific reason for an error's occurrence. See `ZeroTierSockets.h` for values.
### API COMPATIBILITY WITH HOST OS:
While the ZeroTier socket interface can coexist with your host OS's own interface in the same file with no type and naming conflicts, try not to mix and match host OS/libzt structures, functions, or constants. It may look similar and may even work some of the time but there enough differences that it will cause headaches:
If you are calling a `zts_*` function, use the appropriate `ZTS_*` constants:
```
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:
```
struct zts_sockaddr_in in4; <------ Note the zts_* prefix
...
zts_bind(fd, (struct zts_sockaddr *)&in4, sizeof(struct zts_sockaddr_in)) < 0)
```

View File

@@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>ExampleAndroidApp</name>
<comment>Project ExampleAndroidApp created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-9/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>app</name>
<comment>Project app created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@@ -1,2 +0,0 @@
connection.project.dir=..
eclipse.preferences.version=1

View File

@@ -1,43 +0,0 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.mynewestapplication"
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
externalNativeBuild {
cmake {
cppFlags ""
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
debuggable true
jniDebuggable true
minifyEnabled false
}
}
}
dependencies {
implementation files('libs/libzt.aar')
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0-alpha3'
implementation("com.squareup.okhttp3:okhttp:3.12.0")
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.github.bumptech.glide:glide:4.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.6.1'
}

View File

@@ -1,26 +0,0 @@
package com.example.exampleandroidapp;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("com.example.exampleandroidapp", appContext.getPackageName());
}
}

View File

@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.exampleandroidapp">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -1,77 +0,0 @@
package com.example.exampleandroidapp;
import com.zerotier.libzt.ZeroTierSocketFactory;
import com.zerotier.libzt.ZeroTier;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.concurrent.ThreadLocalRandom;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class HTTPWorker extends Thread {
@Override
public void run() {
long tid = Thread.currentThread().getId();
// Test: Perform randomly-delayed HTTP GET requests
if (true) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.socketFactory(new ZeroTierSocketFactory());
OkHttpClient client = builder.build();
Request request1 = new Request.Builder()
.url("http://11.7.7.223:80/warandpeace.txt")
.build();
Request request2 = new Request.Builder()
.url("http://11.7.7.223:8082/pumpkin.jpg")
.build();
RequestBody formBody = new FormBody.Builder()
.add("message", "Your message")
.build();
Request request3 = new Request.Builder()
.url("http://11.7.7.223:8082/")
.post(formBody)
.build();
long i = 0;
for (;;) {
try {
int randomNum = ThreadLocalRandom.current().nextInt(0, 2 + 1);
i++;
Response response = null;
if (randomNum == 0) {
response = client.newCall(request1).execute();
}
if (randomNum == 1) {
//response = client.newCall(request2).execute();
response = client.newCall(request1).execute();
}
if (randomNum == 2) {
//response = client.newCall(request3).execute();
response = client.newCall(request1).execute();
//System.out.println(tid+"::POST");
//continue;
}
InputStream in = response.body().byteStream();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = in.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
System.out.println(tid+"::GET: i="+i+", len="+buffer.toByteArray().length);
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
}
}
}

View File

@@ -1,96 +0,0 @@
package com.example.exampleandroidapp;
// OS imports
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Environment;
import android.Manifest;
// Misc imports
import java.util.ArrayList;
import java.util.List;
// ZeroTier imports
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierSocket;
import com.zerotier.libzt.ZeroTierSocketFactory;
import com.zerotier.libzt.ZeroTierSSLSocketFactory;
import com.zerotier.libzt.ZeroTierSocketAddress;
import com.zerotier.libzt.ZeroTierSocketOptionValue;
import com.zerotier.libzt.ZeroTierSocketImplFactory;
import com.zerotier.libzt.ZeroTierProtoStats;
// Custom ZeroTierEventListener
import com.example.exampleandroidapp.MyZeroTierEventListener;
public class MainActivity extends AppCompatActivity {
static void sleep(int ms)
{
try { Thread.sleep(ms); }
catch (InterruptedException e) { e.printStackTrace(); }
}
void tests()
{
// Start ZeroTier service and wait for it to come online
System.out.println("Starting ZeroTier...");
MyZeroTierEventListener listener = new MyZeroTierEventListener();
ZeroTier.start(getApplicationContext().getFilesDir() + "/zerotier3", listener, 9994);
while (listener.isOnline == false) { sleep (50); }
System.out.println("joining network...");
ZeroTier.join(0xa09acf0233e4b070L);
System.out.println("waiting for callback");
while (listener.isNetworkReady == false) { sleep (50); }
boolean testBackgroundWorkerGET = true;
boolean testRestart = true;
boolean testProtocolStats = true;
if (testRestart) {
for (int i=0; i<10; i++) {
System.out.println("restarting...");
ZeroTier.restart();
sleep(10000);
}
}
if (testProtocolStats) {
ZeroTierProtoStats protocolSpecificStats = new ZeroTierProtoStats();
int numPings = 0;
System.out.println("recording stats...");
while (true) {
sleep(50);
ZeroTier.get_protocol_stats(ZeroTier.STATS_PROTOCOL_ICMP, protocolSpecificStats);
if (protocolSpecificStats.recv > numPings) {
numPings = protocolSpecificStats.recv;
System.out.println("icmp.recv="+numPings);
}
}
}
if (testBackgroundWorkerGET) {
// Start worker threads (staggered by)
List<Thread> threads = new ArrayList<>();
for (int i = 0; i < 5; i++) {
sleep(500);
HTTPWorker thread = new HTTPWorker();
thread.start();
threads.add(thread);
}
try {
Thread.sleep(60000000);
} catch (Exception e) {
}
System.exit(0);
}
}
// Entry point
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tests();
}
}

View File

@@ -1,83 +0,0 @@
package com.example.exampleandroidapp;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierEventListener;
public class MyZeroTierEventListener implements ZeroTierEventListener {
public boolean isNetworkReady = false;
public boolean isOnline = false;
public void onZeroTierEvent(long id, int eventCode)
{
if (eventCode == ZeroTier.EVENT_NODE_UP) {
// Safe to ignore this callback
//System.out.println("EVENT_NODE_UP");
}
if (eventCode == ZeroTier.EVENT_NODE_ONLINE) {
// The core service is running properly and can join networks now
System.out.println("EVENT_NODE_ONLINE: nodeId=" + Long.toHexString(id));
isOnline = true;
}
if (eventCode == ZeroTier.EVENT_NODE_OFFLINE) {
// Network does not seem to be reachable by any available strategy
System.out.println("EVENT_NODE_OFFLINE");
}
if (eventCode == ZeroTier.EVENT_NODE_DOWN) {
// Called when the node is shutting down
System.out.println("EVENT_NODE_DOWN");
}
if (eventCode == ZeroTier.EVENT_NODE_IDENTITY_COLLISION) {
// Another node with this identity already exists
System.out.println("EVENT_NODE_IDENTITY_COLLISION");
}
if (eventCode == ZeroTier.EVENT_NODE_UNRECOVERABLE_ERROR) {
// Try again
System.out.println("EVENT_NODE_UNRECOVERABLE_ERROR");
}
if (eventCode == ZeroTier.EVENT_NODE_NORMAL_TERMINATION) {
// Normal closure
System.out.println("EVENT_NODE_NORMAL_TERMINATION");
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP4) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP4: nwid=" + Long.toHexString(id));
isNetworkReady = true;
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP6) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP6: nwid=" + Long.toHexString(id));
isNetworkReady = true;
}
if (eventCode == ZeroTier.EVENT_NETWORK_DOWN) {
// Someone called leave(), we have no assigned addresses, or otherwise cannot use this interface
System.out.println("EVENT_NETWORK_DOWN: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_REQUESTING_CONFIG) {
// Waiting for network configuration
System.out.println("EVENT_NETWORK_REQUESTING_CONFIG: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_OK) {
// Config received and this node is authorized for this network
System.out.println("EVENT_NETWORK_OK: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_ACCESS_DENIED) {
// You are not authorized to join this network
System.out.println("EVENT_NETWORK_ACCESS_DENIED: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_NOT_FOUND) {
// The virtual network does not exist
System.out.println("EVENT_NETWORK_NOT_FOUND: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_CLIENT_TOO_OLD) {
// The core version is too old
System.out.println("EVENT_NETWORK_CLIENT_TOO_OLD: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_PEER_P2P) {
System.out.println("EVENT_PEER_P2P: id=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_PEER_RELAY) {
System.out.println("EVENT_PEER_RELAY: id=" + Long.toHexString(id));
}
}
}

View File

@@ -1,34 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillType="evenOdd"
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
android:strokeColor="#00000000"
android:strokeWidth="1">
<aapt:attr name="android:fillColor">
<gradient
android:endX="78.5885"
android:endY="90.9159"
android:startX="48.7653"
android:startY="61.0927"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
android:strokeColor="#00000000"
android:strokeWidth="1" />
</vector>

View File

@@ -1,170 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportHeight="108"
android:viewportWidth="108">
<path
android:fillColor="#26A69A"
android:pathData="M0,0h108v108h-108z" />
<path
android:fillColor="#00000000"
android:pathData="M9,0L9,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,0L19,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,0L29,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,0L39,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,0L49,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,0L59,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,0L69,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,0L79,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M89,0L89,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M99,0L99,108"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,9L108,9"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,19L108,19"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,29L108,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,39L108,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,49L108,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,59L108,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,69L108,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,79L108,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,89L108,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M0,99L108,99"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,29L89,29"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,39L89,39"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,49L89,49"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,59L89,59"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,69L89,69"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M19,79L89,79"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M29,19L29,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M39,19L39,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M49,19L49,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M59,19L59,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M69,19L69,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
<path
android:fillColor="#00000000"
android:pathData="M79,19L79,89"
android:strokeColor="#33FFFFFF"
android:strokeWidth="0.8" />
</vector>

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView"
android:layout_width="136dp"
android:layout_height="213dp"
app:srcCompat="@android:color/transparent"
tools:layout_editor_absoluteX="25dp"
tools:layout_editor_absoluteY="16dp" />
</android.support.constraint.ConstraintLayout>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">ExampleAndroidApp</string>
</resources>

View File

@@ -1,11 +0,0 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

View File

@@ -1,17 +0,0 @@
package com.example.exampleandroidapp;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}

View File

@@ -1,13 +0,0 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

View File

@@ -1,6 +0,0 @@
#Tue Jul 31 12:01:02 PDT 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip

View File

@@ -5,24 +5,39 @@ using System.Net;
using System.Net.Sockets; // For SocketType, etc using System.Net.Sockets; // For SocketType, etc
using System.Text; // For Encoding using System.Text; // For Encoding
using ZeroTier; // For ZeroTier.Node, ZeroTier.Event, and ZeroTier.Socket /**
*
* Namespaces explained:
*
* ZeroTier.Core (API to control a ZeroTier Node)
* -> class ZeroTier.Core.Node
* -> class ZeroTier.Core.Event
*
* ZeroTier.Sockets (Socket API similar to System.Net.Sockets)
* -> class ZeroTier.Sockets.Socket
* -> class ZeroTier.Sockets.SocketException
*
* ZeroTier.Central (upcoming)
*
*/
using ZeroTier;
public class ExampleApp { public class ExampleApp {
ZeroTier.Node node; ZeroTier.Core.Node node;
/** /**
* Initialize and start ZeroTier * Initialize and start ZeroTier
*/ */
public void StartZeroTier(string configFilePath, ushort servicePort, ulong networkId) public void StartZeroTier(string configFilePath, ushort servicePort, ulong networkId)
{ {
node = new ZeroTier.Node(configFilePath, OnZeroTierEvent, servicePort); node = new ZeroTier.Core.Node(configFilePath, OnZeroTierEvent, servicePort);
node.Start(); // Network activity only begins after calling Start() node.Start(); // Network activity only begins after calling Start()
/* How you do this next part is up to you, but essentially we're waiting for the node /* How you do this next part is up to you, but essentially we're waiting for the node
to signal to us (via a ZeroTier.Event) that it has access to the internet and is to signal to us via OnZeroTierEvent(ZeroTier.Core.Event) that it has access to the
able to talk to one of our root servers. As a convenience you can just periodically check internet and is able to talk to one of our root servers. As a convenience you can just
IsOnline() instead of looking for the event via the callback. */ periodically check Node.IsOnline() instead of looking for the event via the callback. */
while (!node.IsOnline()) { Thread.Sleep(100); } while (!node.IsOnline()) { Thread.Sleep(100); }
/* After the node comes online you may now join/leave networks. You will receive /* After the node comes online you may now join/leave networks. You will receive
@@ -31,7 +46,7 @@ public class ExampleApp {
or removed routes, etc. */ or removed routes, etc. */
node.Join(networkId); node.Join(networkId);
/* Note that ZeroTier.Socket calls will fail if there are no routes available, for this /* Note that ZeroTier.Sockets.Socket calls will fail if there are no routes available, for this
reason we should wait to make those calls until the node has indicated to us that at reason we should wait to make those calls until the node has indicated to us that at
least one network has been joined successfully. */ least one network has been joined successfully. */
while (!node.HasRoutes()) { Thread.Sleep(100); } while (!node.HasRoutes()) { Thread.Sleep(100); }
@@ -49,7 +64,7 @@ public class ExampleApp {
* Your application should process event messages and return control as soon as possible. Blocking * Your application should process event messages and return control as soon as possible. Blocking
* or otherwise time-consuming operations are not reccomended here. * or otherwise time-consuming operations are not reccomended here.
*/ */
public void OnZeroTierEvent(ZeroTier.Event e) public void OnZeroTierEvent(ZeroTier.Core.Event e)
{ {
Console.WriteLine("Event.eventCode = {0} ({1})", e.EventCode, e.EventName); Console.WriteLine("Event.eventCode = {0} ({1})", e.EventCode, e.EventName);
@@ -73,7 +88,7 @@ public class ExampleApp {
byte[] bytes = new Byte[1024]; byte[] bytes = new Byte[1024];
Console.WriteLine(localEndPoint.ToString()); Console.WriteLine(localEndPoint.ToString());
ZeroTier.Socket listener = new ZeroTier.Socket(AddressFamily.InterNetwork, ZeroTier.Sockets.Socket listener = new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp ); SocketType.Stream, ProtocolType.Tcp );
// Bind the socket to the local endpoint and // Bind the socket to the local endpoint and
@@ -89,13 +104,13 @@ public class ExampleApp {
// Program is suspended while waiting for an incoming connection. // Program is suspended while waiting for an incoming connection.
bool nonblocking = true; bool nonblocking = true;
ZeroTier.Socket handler; ZeroTier.Sockets.Socket handler;
if (nonblocking) { // Non-blocking style Accept() loop using Poll() if (nonblocking) { // Non-blocking style Accept() loop using Poll()
Console.WriteLine("Starting non-blocking Accept() loop..."); Console.WriteLine("Starting non-blocking Accept() loop...");
listener.Blocking = false; listener.Blocking = false;
// loop // loop
int timeout = 1000000; // microseconds (1 second) int timeout = 100000; // microseconds (1 second)
while (true) { while (true) {
Console.WriteLine("Polling... (for data or incoming connections)"); Console.WriteLine("Polling... (for data or incoming connections)");
if (listener.Poll(timeout, SelectMode.SelectRead)) { if (listener.Poll(timeout, SelectMode.SelectRead)) {
@@ -103,7 +118,7 @@ public class ExampleApp {
handler = listener.Accept(); handler = listener.Accept();
break; break;
} }
Thread.Sleep(1000); //Thread.Sleep(5);
} }
} }
else { // Blocking style else { // Blocking style
@@ -113,26 +128,40 @@ public class ExampleApp {
data = null; data = null;
Console.WriteLine("Accepted connection from: " + handler.RemoteEndPoint.ToString()); Console.WriteLine("Accepted connection from: " + handler.RemoteEndPoint.ToString());
// handler.ReceiveTimeout = 1000;
// An incoming connection needs to be processed. // An incoming connection needs to be processed.
while (true) { while (true) {
int bytesRec = handler.Receive(bytes); int bytesRec = 0;
Console.WriteLine("Bytes received: {0}", bytesRec); try {
data += Encoding.ASCII.GetString(bytes,0,bytesRec); Console.WriteLine("Receiving...");
bytesRec = handler.Receive(bytes);
}
catch (ZeroTier.Sockets.SocketException e)
{
Console.WriteLine("ServiveErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
}
if (bytesRec > 0) { if (bytesRec > 0) {
Console.WriteLine("Bytes received: {0}", bytesRec);
data = Encoding.ASCII.GetString(bytes,0,bytesRec);
Console.WriteLine( "Text received : {0}", data); Console.WriteLine( "Text received : {0}", data);
break; //break;
}
}
// Echo the data back to the client. // Echo the data back to the client.
byte[] msg = Encoding.ASCII.GetBytes(data); byte[] msg = Encoding.ASCII.GetBytes(data);
handler.Send(msg); handler.Send(msg);
}
else
{
System.GC.Collect();
Console.WriteLine("No data...");
}
}
handler.Shutdown(SocketShutdown.Both); handler.Shutdown(SocketShutdown.Both);
handler.Close(); handler.Close();
} }
} catch (ZeroTier.SocketException e) { } catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(e); Console.WriteLine(e);
Console.WriteLine("ServiveErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode); Console.WriteLine("ServiveErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
} }
@@ -151,7 +180,7 @@ public class ExampleApp {
// Connect to a remote device. // Connect to a remote device.
try { try {
// Create a TCP/IP socket. // Create a TCP/IP socket.
ZeroTier.Socket sender = new ZeroTier.Socket(AddressFamily.InterNetwork, ZeroTier.Sockets.Socket sender = new ZeroTier.Sockets.Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp ); SocketType.Stream, ProtocolType.Tcp );
// Connect the socket to the remote endpoint. Catch any errors. // Connect the socket to the remote endpoint. Catch any errors.
@@ -181,7 +210,7 @@ public class ExampleApp {
} catch (ArgumentNullException ane) { } catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}",ane.ToString()); Console.WriteLine("ArgumentNullException : {0}",ane.ToString());
} catch (ZeroTier.SocketException e) { } catch (ZeroTier.Sockets.SocketException e) {
Console.WriteLine(e); Console.WriteLine(e);
Console.WriteLine("ServiveErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode); Console.WriteLine("ServiveErrorCode={0} SocketErrorCode={1}", e.ServiceErrorCode, e.SocketErrorCode);
} }

161
examples/java/Example.java Normal file
View File

@@ -0,0 +1,161 @@
//package com.zerotier.libzt.javasimpleexample;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierEventListener;
import java.math.BigInteger;
public class Example {
static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
String keyPath="."; // Default to current directory
BigInteger networkId;
Integer servicePort=0;
if (args.length != 3) {
System.err.println(" Invalid arguments");
System.err.println(" Usage: example <path_to_write_keys> <nwid> <ztServicePort>");
System.exit(1);
}
keyPath = args[0];
networkId = new BigInteger(args[1], 16);
servicePort = Integer.parseInt(args[2]);
System.out.println("networkId = " + Long.toHexString(networkId.longValue()));
System.out.println("keyPath = " + keyPath);
System.out.println("servicePort = " + servicePort);
//
// BEGIN SETUP
//
// Set up event listener and start service
MyZeroTierEventListener listener = new MyZeroTierEventListener();
ZeroTier.start(keyPath, (ZeroTierEventListener)listener, servicePort);
// Wait for EVENT_NODE_ONLINE
System.out.println("waiting for node to come online...");
while (listener.isOnline == false) { sleep(50); }
System.out.println("joining network");
ZeroTier.join(networkId.longValue());
// Wait for EVENT_NETWORK_READY_IP4/6
System.out.println("waiting for network config...");
while (listener.isNetworkReady == false) { sleep(50); }
System.out.println("joined");
//
// END SETUP
//
sleep(120000);
/**
*
* Begin using socket API after this point:
*
* ZeroTier.ZeroTierSocket, ZeroTier.ZeroTierSocketFactory, etc
*
* (or)
*
* ZeroTier.socket(), ZeroTier.connect(), etc
*/
}
}
/**
* Example event handling
*/
class MyZeroTierEventListener implements ZeroTierEventListener {
public boolean isNetworkReady = false;
public boolean isOnline = false;
public void onZeroTierEvent(long id, int eventCode) {
if (eventCode == ZeroTier.EVENT_NODE_UP) {
System.out.println("EVENT_NODE_UP: nodeId=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NODE_ONLINE) {
// The core service is running properly and can join networks now
System.out.println("EVENT_NODE_ONLINE: nodeId=" + Long.toHexString(id));
isOnline = true;
}
if (eventCode == ZeroTier.EVENT_NODE_OFFLINE) {
// Network does not seem to be reachable by any available strategy
System.out.println("EVENT_NODE_OFFLINE");
}
if (eventCode == ZeroTier.EVENT_NODE_DOWN) {
// Called when the node is shutting down
System.out.println("EVENT_NODE_DOWN");
}
if (eventCode == ZeroTier.EVENT_NODE_IDENTITY_COLLISION) {
// Another node with this identity already exists
System.out.println("EVENT_NODE_IDENTITY_COLLISION");
}
if (eventCode == ZeroTier.EVENT_NODE_UNRECOVERABLE_ERROR) {
// Try again
System.out.println("EVENT_NODE_UNRECOVERABLE_ERROR");
}
if (eventCode == ZeroTier.EVENT_NODE_NORMAL_TERMINATION) {
// Normal closure
System.out.println("EVENT_NODE_NORMAL_TERMINATION");
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP4) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP4: nwid=" + Long.toHexString(id));
isNetworkReady = true;
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP6) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP6: nwid=" + Long.toHexString(id));
//isNetworkReady = true;
}
if (eventCode == ZeroTier.EVENT_NETWORK_DOWN) {
// Someone called leave(), we have no assigned addresses, or otherwise cannot use this interface
System.out.println("EVENT_NETWORK_DOWN: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_REQ_CONFIG) {
// Waiting for network configuration
System.out.println("EVENT_NETWORK_REQ_CONFIG: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_OK) {
// Config received and this node is authorized for this network
System.out.println("EVENT_NETWORK_OK: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_ACCESS_DENIED) {
// You are not authorized to join this network
System.out.println("EVENT_NETWORK_ACCESS_DENIED: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_NOT_FOUND) {
// The virtual network does not exist
System.out.println("EVENT_NETWORK_NOT_FOUND: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_CLIENT_TOO_OLD) {
// The core version is too old
System.out.println("EVENT_NETWORK_CLIENT_TOO_OLD: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_PEER_DIRECT) {
System.out.println("EVENT_PEER_DIRECT: id=" + Long.toHexString(id));
/*
ZeroTierPeerDetails details = new ZeroTierPeerDetails();
ZeroTier.get_peer(id, details);
System.out.println("address="+Long.toHexString(details.address));
System.out.println("pathCount="+details.pathCount);
System.out.println("version="+details.versionMajor+"."+details.versionMinor+"."+details.versionRev);
System.out.println("latency="+details.latency); // Not relevant
System.out.println("role="+details.role); // Not relevent
// Print all known paths
for (int i=0; i<details.pathCount; i++) {
System.out.println("addr="+details.paths[i].toString());
}
*/
}
if (eventCode == ZeroTier.EVENT_PEER_RELAY) {
System.out.println("EVENT_PEER_RELAY: id=" + Long.toHexString(id));
}
}
}

9
examples/java/Makefile Normal file
View File

@@ -0,0 +1,9 @@
all:
jar xf *.jar libzt.dylib
javac -cp *.jar Example.java
clean:
rm -rf *.class
superclean: clean
rm -rf *.dylib *.so *.jar

View File

@@ -1,25 +1,9 @@
### How to compile/use this example: # Java example
1. Follow "Building from source" section from README.md in the root of this git repository 1). Build or download the `zt-1.3.3.jar`, copy it to this directory
(the linking step/example from that section does not apply to this example)
2. Create the java library .jar file: 2). Run `make`
``` 3). `java -cp ".:zt-1.3.3.jar" Example id_path 0123456789abcdef 9997`
make host_jar_release
```
for other `host_jar` variants see Makefile in the root of this git repository See [src/bindings/java](../../src/bindings/java) for wrapper implementation code.
2. Copy the output .jar to this directory:
```
cp lib/lib/release/linux-x86_64/zt.jar examples/java/simpleExample/
```
3. Now you can compile this example:
```
cd src
javac -cp ../zt.jar ./com/zerotier/libzt/javasimpleexample/*.java
```

View File

@@ -1,64 +0,0 @@
/*
* ZeroTier SDK - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
* You can be released from the requirements of the license by purchasing
* a commercial license. Buying such a license is mandatory as soon as you
* develop commercial closed-source software that incorporates or links
* directly against ZeroTier software without disclosing the source code
* of your own application.
*/
package com.zerotier.libzt.javasimpleexample;
import com.zerotier.libzt.ZeroTier;
public class Main {
static void sleep(int ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
// Set up event listener and start service
MyZeroTierEventListener listener = new MyZeroTierEventListener();
int servicePort = 9994;
ZeroTier.start("test/path", listener, servicePort);
// Wait for EVENT_NODE_ONLINE
System.out.println("waiting for node to come online...");
while (listener.isOnline == false) { sleep(50); }
System.out.println("joining network");
ZeroTier.join(0x0123456789abcdefL);
// Wait for EVENT_NETWORK_READY_IP4/6
System.out.println("waiting for network config...");
while (listener.isNetworkReady == false) { sleep(50); }
System.out.println("joined");
/*
Begin using socket API after this point
Use ZeroTier.ZeroTierSocket, ZeroTier.ZeroTierSocketFactory, etc
(or)
ZeroTier.socket(), ZeroTier.connect(), etc
*/
}
}

View File

@@ -1,96 +0,0 @@
package com.zerotier.libzt.javasimpleexample;
import com.zerotier.libzt.ZeroTier;
import com.zerotier.libzt.ZeroTierEventListener;
public class MyZeroTierEventListener implements ZeroTierEventListener {
public boolean isNetworkReady = false;
public boolean isOnline = false;
public void onZeroTierEvent(long id, int eventCode) {
if (eventCode == ZeroTier.EVENT_NODE_UP) {
System.out.println("EVENT_NODE_UP: nodeId=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NODE_ONLINE) {
// The core service is running properly and can join networks now
System.out.println("EVENT_NODE_ONLINE: nodeId=" + Long.toHexString(ZeroTier.get_node_id()));
isOnline = true;
}
if (eventCode == ZeroTier.EVENT_NODE_OFFLINE) {
// Network does not seem to be reachable by any available strategy
System.out.println("EVENT_NODE_OFFLINE");
}
if (eventCode == ZeroTier.EVENT_NODE_DOWN) {
// Called when the node is shutting down
System.out.println("EVENT_NODE_DOWN");
}
if (eventCode == ZeroTier.EVENT_NODE_IDENTITY_COLLISION) {
// Another node with this identity already exists
System.out.println("EVENT_NODE_IDENTITY_COLLISION");
}
if (eventCode == ZeroTier.EVENT_NODE_UNRECOVERABLE_ERROR) {
// Try again
System.out.println("EVENT_NODE_UNRECOVERABLE_ERROR");
}
if (eventCode == ZeroTier.EVENT_NODE_NORMAL_TERMINATION) {
// Normal closure
System.out.println("EVENT_NODE_NORMAL_TERMINATION");
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP4) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP4: nwid=" + Long.toHexString(id));
if (id == 0xa09acf0233e4b070L) {
isNetworkReady = true;
}
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP6) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP6: nwid=" + Long.toHexString(id));
//isNetworkReady = true;
}
if (eventCode == ZeroTier.EVENT_NETWORK_DOWN) {
// Someone called leave(), we have no assigned addresses, or otherwise cannot use this interface
System.out.println("EVENT_NETWORK_DOWN: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_REQUESTING_CONFIG) {
// Waiting for network configuration
System.out.println("EVENT_NETWORK_REQUESTING_CONFIG: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_OK) {
// Config received and this node is authorized for this network
System.out.println("EVENT_NETWORK_OK: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_ACCESS_DENIED) {
// You are not authorized to join this network
System.out.println("EVENT_NETWORK_ACCESS_DENIED: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_NOT_FOUND) {
// The virtual network does not exist
System.out.println("EVENT_NETWORK_NOT_FOUND: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_CLIENT_TOO_OLD) {
// The core version is too old
System.out.println("EVENT_NETWORK_CLIENT_TOO_OLD: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_PEER_P2P) {
System.out.println("EVENT_PEER_P2P: id=" + Long.toHexString(id));
/*
ZeroTierPeerDetails details = new ZeroTierPeerDetails();
ZeroTier.get_peer(id, details);
System.out.println("address="+Long.toHexString(details.address));
System.out.println("pathCount="+details.pathCount);
System.out.println("version="+details.versionMajor+"."+details.versionMinor+"."+details.versionRev);
System.out.println("latency="+details.latency); // Not relevant
System.out.println("role="+details.role); // Not relevent
// Print all known paths
for (int i=0; i<details.pathCount; i++) {
System.out.println("addr="+details.paths[i].toString());
}
*/
}
if (eventCode == ZeroTier.EVENT_PEER_RELAY) {
System.out.println("EVENT_PEER_RELAY: id=" + Long.toHexString(id));
}
}
}

15
examples/python/Makefile Normal file
View File

@@ -0,0 +1,15 @@
LIB_OUTPUT_DIR = $(shell cd ../../ && ./build.sh gethosttype)
copy_wrapper_sources:
cp -f ../../src/bindings/python/*.py .
debug: copy_wrapper_sources
cd ../../ && ./build.sh host-python "debug"
cp -f ../../dist/$(LIB_OUTPUT_DIR)-python-debug/lib/*.so .
release: copy_wrapper_sources
cd ../../ && ./build.sh host-python "release"
cp -f ../../dist/$(LIB_OUTPUT_DIR)-python-release/lib/*.so .
clean:
rm -rf *.so libzt.py prototype.py

23
examples/python/README.md Normal file
View File

@@ -0,0 +1,23 @@
# Python example
This example demonstrates how to use the ZeroTier socket interface provided by libzt in a Python application. The API is designed to be a drop-in replacement for the Python [Low-level networking interface](https://docs.python.org/3/library/socket.html).
Note: Only `AF_INET` and `AF_INET6` address families are supported.
### Install
```
pip install libzt
```
### Run
```
python3 example.py server id-path/bob 0123456789abcdef 9997 8080
python3 example.py client id-path/alice 0123456789abcdef 9996 11.22.33.44 8080
```
*Where `9996` and `9997` are arbitrary ports that you allow ZeroTier to use for encrypted UDP traffic, port `8080` is an arbitrary port used by the client/server socket code, and `11.22.33.44` should be whatever IP address the network assigns your node.*
### Implementation Details
- See [src/bindings/python](../../src/bindings/python)

157
examples/python/example.py Normal file
View File

@@ -0,0 +1,157 @@
'''Example low-level socket usage'''
import time
import sys
import libzt
def print_usage():
'''print help'''
print(
"\nUsage: <server|client> <id_path> <nwid> <zt_service_port> <remote_ip> <remote_port>\n"
)
print("Ex: python3 demo.py server . 0123456789abcdef 9994 8080")
print("Ex: python3 demo.py client . 0123456789abcdef 9994 192.168.22.1 8080\n")
if len(sys.argv) < 6:
print("Too few arguments")
if len(sys.argv) > 7:
print("Too many arguments")
sys.exit(0)
is_joined = False # Flags to keep state
is_online = False # Flags to keep state
#
# Event handler
#
class MyEventCallbackClass(libzt.EventCallbackClass):
def on_zerotier_event(self, msg):
global is_online
global is_joined
print("eventCode=", msg.eventCode)
if msg.eventCode == libzt.ZTS_EVENT_NODE_ONLINE:
print("ZTS_EVENT_NODE_ONLINE")
print("nodeId=" + hex(msg.node.address))
# The node is now online, you can join/leave networks
is_online = True
if msg.eventCode == libzt.ZTS_EVENT_NODE_OFFLINE:
print("ZTS_EVENT_NODE_OFFLINE")
if msg.eventCode == libzt.ZTS_EVENT_NETWORK_READY_IP4:
print("ZTS_EVENT_NETWORK_READY_IP4")
is_joined = True
# The node has successfully joined a network and has an address
# you can perform network calls now
if msg.eventCode == libzt.ZTS_EVENT_PEER_DIRECT:
print("ZTS_EVENT_PEER_DIRECT")
if msg.eventCode == libzt.ZTS_EVENT_PEER_RELAY:
print("ZTS_EVENT_PEER_RELAY")
#
# Main
#
def main():
global is_online
global is_joined
key_file_path = "." # Where identity files are stored
network_id = 0 # Network to join
# Port used by ZeroTier to send encpryted UDP traffic
# NOTE: Should be different from other instances of ZeroTier
# running on the same machine
zt_service_port = 9997
remote_ip = None # ZeroTier IP of remote node
remote_port = 8080 # ZeroTier port your app logic may use
mode = None # client|server
if len(sys.argv) < 6 or len(sys.argv) > 7:
print_usage()
if sys.argv[1] == "server" and len(sys.argv) == 6:
mode = sys.argv[1]
key_file_path = sys.argv[2]
network_id = int(sys.argv[3], 16)
zt_service_port = int(sys.argv[4])
remote_port = int(sys.argv[5])
if sys.argv[1] == "client" and len(sys.argv) == 7:
mode = sys.argv[1]
key_file_path = sys.argv[2]
network_id = int(sys.argv[3], 16)
zt_service_port = int(sys.argv[4])
remote_ip = sys.argv[5]
remote_port = int(sys.argv[6])
if mode is None:
print_usage()
print("mode = ", mode)
print("path = ", key_file_path)
print("network_id = ", network_id)
print("zt_service_port = ", zt_service_port)
print("remote_ip = ", remote_ip)
print("remote_port = ", remote_port)
#
# Example start and join logic
#
print("Starting ZeroTier...")
event_callback = MyEventCallbackClass()
libzt.start(key_file_path, event_callback, zt_service_port)
print("Waiting for node to come online...")
while not is_online:
time.sleep(1)
print("Joining network:", hex(network_id))
libzt.join(network_id)
while not is_joined:
time.sleep(1) # You can ping this app at this point
print("Joined network")
#
# Example server
#
if mode == "server":
print("Starting server...")
serv = libzt.socket(libzt.ZTS_AF_INET, libzt.ZTS_SOCK_STREAM, 0)
try:
# serv.setblocking(True)
serv.bind(("0.0.0.0", remote_port))
serv.listen(5)
while True:
conn, addr = serv.accept()
print("Accepted connection from: ", addr)
while True:
print("recv:")
data = conn.recv(4096)
if data:
print("data = ", data)
# print(type(b'what'))
# exit(0)
if not data:
break
print("send:")
# bytes(data, 'ascii') + b'\x00'
n_bytes = conn.send(data) # echo back to the server
print("sent " + str(n_bytes) + " byte(s)")
conn.close()
print("client disconnected")
except Exception as ex:
print(ex)
print("errno=", libzt.errno()) # See include/ZeroTierSockets.h for codes
#
# Example client
#
if mode == "client":
print("Starting client...")
client = libzt.socket(libzt.ZTS_AF_INET, libzt.ZTS_SOCK_STREAM, 0)
try:
print("connecting...")
client.connect((remote_ip, remote_port))
print("send:")
data = "Hello, world!"
client.send(data)
data = client.recv(1024)
print("Received", repr(data))
except Exception as ex:
print(ex)
print("errno=", libzt.errno())
if __name__ == "__main__":
main()

219
ext/THIRDPARTY.txt Normal file
View File

@@ -0,0 +1,219 @@
Third-Party Code
ZeroTier and the ZeroTier SDK (including libzt) includes the following third
party code, either in ext/ or incorporated into the ZeroTier core. This third
party code remains licensed under its original license and is not subject to
ZeroTier's BSL license.
LZ4 compression algorithm by Yann Collet - http://code.google.com/p/lz4/
-----------------------------------------------------------------------------
LZ4 - Fast LZ compression algorithm
Header File
Copyright (C) 2011-2016, Yann Collet.
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
You can contact the author at :
- LZ4 homepage : http://www.lz4.org
- LZ4 source repository : https://github.com/lz4/lz4
C++11 json (nlohmann/json) by Niels Lohmann
https://github.com/nlohmann/json
-----------------------------------------------------------------------------
MIT License
Copyright (c) 2013-2021 Niels Lohmann
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MiniUPNPC and libnatpmp by Thomas Bernard - http://miniupnp.free.fr/
-----------------------------------------------------------------------------
MiniUPnPc
Copyright (c) 2005-2016, Thomas BERNARD
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
lwIP - https://www.nongnu.org/lwip/2_1_x/index.html
-----------------------------------------------------------------------------
Copyright (c) 2001-2003 Swedish Institute of Computer Science.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
This file is part of the lwIP TCP/IP stack.
Author: Adam Dunkels <adam@sics.se>
concurrentqueue - https://github.com/cameron314/concurrentqueue
-----------------------------------------------------------------------------
Simplified BSD License:
Copyright (c) 2013-2016, Cameron Desrochers.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of
conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials
provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
curl - https://curl.se/
-----------------------------------------------------------------------------
COPYRIGHT AND PERMISSION NOTICE
Copyright (c) 1996 - 2021, Daniel Stenberg, <daniel@haxx.se>, and many
contributors, see the THANKS file.
All rights reserved.
Permission to use, copy, modify, and distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright
notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
OR OTHER DEALINGS IN THE SOFTWARE.
Except as contained in this notice, the name of a copyright holder shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization of the copyright holder.

172
gradlew vendored
View File

@@ -1,172 +0,0 @@
#!/usr/bin/env sh
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

84
gradlew.bat vendored
View File

@@ -1,84 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -1,4 +1,427 @@
ZeroTier Socket API 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>
This is the externally facing plain C API. It provides a platform-agnostic ZeroTier-based socket interface.

View File

@@ -20,6 +20,23 @@
#ifndef ZT_SOCKETS_H #ifndef ZT_SOCKETS_H
#define ZT_SOCKETS_H #define ZT_SOCKETS_H
//////////////////////////////////////////////////////////////////////////////
// Configuration Options //
//////////////////////////////////////////////////////////////////////////////
#ifdef ZTS_ENABLE_PYTHON
/**
* In some situations (Python comes to mind) a signal may not make its
* way to libzt, for this reason we make sure to define a custom signal
* handler that can at least process SIGTERMs
*/
#define ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS 1
#endif
#if !defined(ZTS_ENABLE_PYTHON) && !defined(ZTS_ENABLE_PINVOKE)
#define ZTS_C_API_ONLY 1
#endif
#if !ZTS_NO_STDINT_H #if !ZTS_NO_STDINT_H
#include <stdint.h> #include <stdint.h>
#endif #endif
@@ -39,7 +56,7 @@
extern "C" { extern "C" {
#endif #endif
#ifdef ZTS_PINVOKE #ifdef ZTS_ENABLE_PINVOKE
// Used by P/INVOKE wrappers // Used by P/INVOKE wrappers
typedef void (*CppCallback)(void *msg); typedef void (*CppCallback)(void *msg);
#endif #endif
@@ -735,9 +752,6 @@ struct zts_network_details
} multicastSubscriptions[ZTS_MAX_MULTICAST_SUBSCRIPTIONS]; } multicastSubscriptions[ZTS_MAX_MULTICAST_SUBSCRIPTIONS];
}; };
/** /**
* Physical network path to a peer * Physical network path to a peer
*/ */
@@ -829,6 +843,44 @@ struct zts_peer_list
unsigned long peerCount; unsigned long peerCount;
}; };
//////////////////////////////////////////////////////////////////////////////
// Python Bindings (Subset of regular socket API) //
//////////////////////////////////////////////////////////////////////////////
#ifdef ZTS_ENABLE_PYTHON
#include "Python.h"
/**
* Abstract class used as a director. Pointer to an instance of this class
* is provided to the Python layer.
*
* See: https://rawgit.com/swig/swig/master/Doc/Manual/SWIGPlus.html#SWIGPlus_target_language_callbacks
*/
class PythonDirectorCallbackClass
{
public:
/**
* Called by native code on event. Implemented in Python
*/
virtual void on_zerotier_event(struct zts_callback_msg *msg);
virtual ~PythonDirectorCallbackClass() {};
};
extern PythonDirectorCallbackClass *_userEventCallback;
int zts_py_bind(int fd, int family, int type, PyObject *addro);
int zts_py_connect(int fd, int family, int type, PyObject *addro);
PyObject * zts_py_accept(int fd);
int zts_py_listen(int fd, int backlog);
PyObject * zts_py_recv(int fd, int len, int flags);
int zts_py_send(int fd, PyObject *buf, int len, int flags);
int zts_py_close(int fd);
int zts_py_setblocking(int fd, int flag);
int zts_py_getblocking(int fd);
#endif // ZTS_ENABLE_PYTHON
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// ZeroTier Service Controls // // ZeroTier Service Controls //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -849,7 +901,7 @@ struct zts_peer_list
// Central API // // Central API //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#ifndef NO_CENTRAL_API #ifdef ZTS_ENABLE_CENTRAL_API
#define CENTRAL_API_DEFAULT_URL "https://my.zerotier.com" #define CENTRAL_API_DEFAULT_URL "https://my.zerotier.com"
#define CENRTAL_API_MAX_URL_LEN 128 #define CENRTAL_API_MAX_URL_LEN 128
@@ -1032,11 +1084,16 @@ ZTS_API int ZTCALL zts_get_node_identity(char *key_pair_str, uint16_t *key_buf_l
* @param port Port that the library should use for talking to other ZeroTier nodes * @param port Port that the library should use for talking to other ZeroTier nodes
* @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure
*/ */
#ifdef ZTS_PINVOKE #ifdef ZTS_ENABLE_PYTHON
ZTS_API int ZTCALL zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len, int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len,
PythonDirectorCallbackClass *callback, uint16_t port);
#endif
#ifdef ZTS_ENABLE_PINVOKE
int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len,
CppCallback callback, uint16_t port); CppCallback callback, uint16_t port);
#else #endif
ZTS_API int ZTCALL zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len, #ifdef ZTS_C_API_ONLY
int zts_start_with_identity(const char *key_pair_str, uint16_t key_buf_len,
void (*callback)(void *), uint16_t port); void (*callback)(void *), uint16_t port);
#endif #endif
@@ -1100,9 +1157,13 @@ ZTS_API int ZTCALL zts_disable_local_storage(uint8_t disabled);
* @param port Port that the library should use for talking to other ZeroTier nodes * @param port Port that the library should use for talking to other ZeroTier nodes
* @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure * @return ZTS_ERR_OK on success. ZTS_ERR_SERVICE or ZTS_ERR_ARG on failure
*/ */
#ifdef ZTS_PINVOKE #ifdef ZTS_ENABLE_PYTHON
ZTS_API int ZTCALL zts_start(const char *path, PythonDirectorCallbackClass *callback, uint16_t port);
#endif
#ifdef ZTS_ENABLE_PINVOKE
ZTS_API int ZTCALL zts_start(const char *path, CppCallback callback, uint16_t port); ZTS_API int ZTCALL zts_start(const char *path, CppCallback callback, uint16_t port);
#else #endif
#ifdef ZTS_C_API_ONLY
ZTS_API int ZTCALL zts_start(const char *path, void (*callback)(void *), uint16_t port); ZTS_API int ZTCALL zts_start(const char *path, void (*callback)(void *), uint16_t port);
#endif #endif
@@ -1234,6 +1295,8 @@ ZTS_API void ZTCALL zts_delay_ms(long interval_ms);
// Statistics // // Statistics //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
#ifdef ZTS_ENABLE_STATS
#define ZTS_STATS_PROTOCOL_LINK 0 #define ZTS_STATS_PROTOCOL_LINK 0
#define ZTS_STATS_PROTOCOL_ETHARP 1 #define ZTS_STATS_PROTOCOL_ETHARP 1
#define ZTS_STATS_PROTOCOL_IP 2 #define ZTS_STATS_PROTOCOL_IP 2
@@ -1342,6 +1405,8 @@ ZTS_API int ZTCALL zts_get_all_stats(struct zts_stats *statsDest);
*/ */
ZTS_API int ZTCALL zts_get_protocol_stats(int protocolType, void *protoStatsDest); ZTS_API int ZTCALL zts_get_protocol_stats(int protocolType, void *protoStatsDest);
#endif // ZTS_ENABLE_STATS
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Socket API // // Socket API //
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

11
pkg/README.md Normal file
View File

@@ -0,0 +1,11 @@
# Packages
This is where package spec files, source trees, project configs, etc live.
## Example usage
- See [examples/](../../examples/)
## Implementation Details
- See [src/bindings/](../../src/bindings/)

View File

@@ -0,0 +1 @@
Before build, Java wrapper sources will be copied here

View File

@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip

0
examples/android/ExampleAndroidApp/gradlew → pkg/android/gradlew vendored Normal file → Executable file
View File

View File

View File

@@ -9,7 +9,7 @@
<license type="file">LICENSE.txt</license> <license type="file">LICENSE.txt</license>
<icon>icon.png</icon> <icon>icon.png</icon>
<requireLicenseAcceptance>false</requireLicenseAcceptance> <requireLicenseAcceptance>false</requireLicenseAcceptance>
<releaseNotes>Initial release</releaseNotes> <releaseNotes>Namespace adjustments, additions to Socket API, memory leak fixes.</releaseNotes>
<description>Encrypted P2P SD-WAN networking layer (Managed C# API) [x64]</description> <description>Encrypted P2P SD-WAN networking layer (Managed C# API) [x64]</description>
<title>Encrypted P2P SD-WAN networking layer (Managed C# API) [x64]</title> <title>Encrypted P2P SD-WAN networking layer (Managed C# API) [x64]</title>
<copyright>Copyright 2021 ZeroTier, Inc.</copyright> <copyright>Copyright 2021 ZeroTier, Inc.</copyright>

View File

@@ -0,0 +1,29 @@
[ZeroTier](https://www.zerotier.com) SDK
=====
Connect physical devices, virtual devices, and application instances as if everything is on a single LAN.
ZeroTier brings your network into user-space. We've paired our network hypervisor core with a TCP/UDP/IP stack [(lwIP)](https://en.wikipedia.org/wiki/LwIP) to provide your application with an exclusive and private virtual network interface. All traffic on this interface is end-to-end encrypted between each peer and we provide an easy-to-use socket interface similar to [Berkeley Sockets](https://en.wikipedia.org/wiki/Berkeley_sockets). Since we aren't using the kernel's IP stack that means no drivers, no root, and no host configuration requirements.
- Website: https://www.zerotier.com/
- ZeroTier Manual: https://www.zerotier.com/manual/
- ZeroTier Repo: https://github.com/zerotier/zerotierone
- SDK Repo: https://github.com/zerotier/libzt
- Forum: https://discuss.zerotier.com
## 1.3.3-alpha.2 Release Notes
### New namespace structure:
- `ZeroTier.Core` (API to control a ZeroTier Node)
- `class ZeroTier.Core.Node`
- `class ZeroTier.Core.Event`
- `ZeroTier.Sockets`
- `class ZeroTier.Sockets.Socket`
- `class ZeroTier.Sockets.SocketException`
- `ZeroTier.Central` (upcoming)
### Added to Socket API
- `Socket.ReceiveTimeout`, `Socket.SendTimeout`, etc.
### Bugs
- Fixed memory leak caused by unmanaged resources not being released.

149
pkg/pypi/LICENSE Normal file
View File

@@ -0,0 +1,149 @@
-----------------------------------------------------------------------------
Business Source License 1.1
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.
-----------------------------------------------------------------------------
Parameters
Licensor: ZeroTier, Inc.
Licensed Work: ZeroTier Network Virtualization Engine 1.4.4
The Licensed Work is (c)2019 ZeroTier, Inc.
Additional Use Grant: You may make use of the Licensed Work, provided you
do not use it in any of the following ways:
* Sell hosted ZeroTier services as a "SaaS" Product
(1) Operate or sell access to ZeroTier root servers,
network controllers, or authorization key or certificate
generation components of the Licensed Work as a
for-profit service, regardless of whether the use of
these components is sold alone or is bundled with other
services. Note that this does not apply to the use of
ZeroTier behind the scenes to operate a service not
related to ZeroTier network administration.
* Create Non-Open-Source Commercial Derviative Works
(2) Link or directly include the Licensed Work in a
commercial or for-profit application or other product
not distributed under an Open Source Initiative (OSI)
compliant license. See: https://opensource.org/licenses
(3) Remove the name, logo, copyright, or other branding
material from the Licensed Work to create a "rebranded"
or "white labeled" version to distribute as part of
any commercial or for-profit product or service.
* Certain Government Uses
(4) Use or deploy the Licensed Work in a government
setting in support of any active government function
or operation with the exception of the following:
physical or mental health care, family and social
services, social welfare, senior care, child care, and
the care of persons with disabilities.
Change Date: 2023-01-01
Change License: Apache License version 2.0 as published by the Apache
Software Foundation
https://www.apache.org/licenses/
Alternative Licensing
If you would like to use the Licensed Work in any way that conflicts with
the stipulations of the Additional Use Grant, contact ZeroTier, Inc. to
obtain an alternative commercial license.
Visit us on the web at: https://www.zerotier.com/
Notice
The Business Source License (this document, or the "License") is not an Open
Source license. However, the Licensed Work will eventually be made available
under an Open Source License, as stated in this License.
For more information on the use of the Business Source License for ZeroTier
products, please visit our pricing page which contains license details and
and license FAQ: https://zerotier.com/pricing
For more information on the use of the Business Source License generally,
please visit the Adopting and Developing Business Source License FAQ at
https://mariadb.com/bsl-faq-adopting.
-----------------------------------------------------------------------------
Business Source License 1.1
Terms
The Licensor hereby grants you the right to copy, modify, create derivative
works, redistribute, and make non-production use of the Licensed Work. The
Licensor may make an Additional Use Grant, above, permitting limited
production use.
Effective on the Change Date, or the fourth anniversary of the first publicly
available distribution of a specific version of the Licensed Work under this
License, whichever comes first, the Licensor hereby grants you rights under
the terms of the Change License, and the rights granted in the paragraph
above terminate.
If your use of the Licensed Work does not comply with the requirements
currently in effect as described in this License, you must purchase a
commercial license from the Licensor, its affiliated entities, or authorized
resellers, or you must refrain from using the Licensed Work.
All copies of the original and modified Licensed Work, and derivative works
of the Licensed Work, are subject to this License. This License applies
separately for each version of the Licensed Work and the Change Date may vary
for each version of the Licensed Work released by Licensor.
You must conspicuously display this License on each original or modified copy
of the Licensed Work. If you receive the Licensed Work in original or
modified form from a third party, the terms and conditions set forth in this
License apply to your use of that work.
Any use of the Licensed Work in violation of this License will automatically
terminate your rights under this License for the current and all other
versions of the Licensed Work.
This License does not grant you any right in any trademark or logo of
Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.
-----------------------------------------------------------------------------
MariaDB hereby grants you permission to use this Licenses text to license
your works, and to refer to it using the trademark "Business Source License",
as long as you comply with the Covenants of Licensor below.
Covenants of Licensor
In consideration of the right to use this Licenses text and the "Business
Source License" name and trademark, Licensor covenants to MariaDB, and to all
other recipients of the licensed work to be provided by Licensor:
1. To specify as the Change License the GPL Version 2.0 or any later version,
or a license that is compatible with GPL Version 2.0 or a later version,
where "compatible" means that software provided under the Change License can
be included in a program with software provided under GPL Version 2.0 or a
later version. Licensor may specify additional Change Licenses without
limitation.
2. To either: (a) specify an additional grant of rights to use that does not
impose any additional restriction on the right granted in this License, as
the Additional Use Grant; or (b) insert the text "None".
3. To specify a Change Date.
4. Not to modify this License in any other way.

3
pkg/pypi/MANIFEST.in Normal file
View File

@@ -0,0 +1,3 @@
README.md
setup.cfg
setup.py

17
pkg/pypi/README.md Normal file
View File

@@ -0,0 +1,17 @@
<div align="center">
<img width=120px src=https://github.com/zerotier/ZeroTierOne/raw/master/artwork/ZeroTierIcon512x512.png></img>
<h1>libzt (ZeroTier)</h1>
Peer-to-peer and cross-platform encrypted connections built right into your app or service. No drivers, no root, and no host configuration.
<a href="https://github.com/zerotier/libzt/"><img alt="latest libzt version" src="https://img.shields.io/github/v/tag/zerotier/libzt?label=latest version"/></a>
<a href="https://github.com/zerotier/libzt/commits/master"><img alt="Last Commit" src="https://img.shields.io/github/last-commit/zerotier/libzt"/></a>
<a href="https://github.com/zerotier/libzt/actions"><img alt="Build Status (master branch)" src="https://img.shields.io/github/workflow/status/zerotier/libzt/CMake/master"/></a>
</div>
<div align="center">
Examples, tutorials and API docs for Python and other languages: [github.com/zerotier/libzt](https://www.github.com/zerotier/libzt)
*NOTE: The implementation of this language binding attempts to be as Pythonic as possible. If something is not as it should be, please make a pull request or issue. Thanks.*

61
pkg/pypi/build.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
PYBIN=python3.9
#PYBIN=/opt/python/cp39-cp39/bin/python3
# Build the extension module
ext()
{
# Symbolic link to source tree so that sdist structure makes sense
ln -s ../../ native
# Copy language bindings into module directory
cp -f native/src/bindings/python/*.py libzt/
cp -f native/LICENSE.txt LICENSE
#mkdir -p build/temp.macosx-11-x86_64-3.9
#mkdir -p build/temp.linux-x86_64-3.8
# Build C libraries (and then) C++ extension
$PYBIN setup.py build_clib --verbose build_ext -i --verbose
}
# Build a wheel
wheel()
{
ext
$PYBIN setup.py bdist_wheel
}
clean()
{
find . -name '*.so' -type f -delete
find . -name '*.pyc' -type f -delete
find . -name '__pycache__' -type d -delete
rm -rf libzt/sockets.py
rm -rf libzt/libzt.py
rm -rf src ext build dist native
rm -rf libzt.egg-info
rm -rf LICENSE
}
manylinux()
{
CONTAINER="quay.io/pypa/manylinux_2_24_x86_64"
docker pull ${CONTAINER}
docker run --rm -it --entrypoint bash -v $(pwd)/../../:/media/libzt ${CONTAINER}
}
cycle()
{
#clean
#swig -c++ -python -o ../../src/bindings/python/zt_wrap.cpp -I../../include ../../src/bindings/python/zt.i
#wheel
#pip3 uninstall -y libzt
#pip3 install dist/libzt-1.3.3-cp39-cp39-macosx_11_0_x86_64.whl
}
update-version()
{
echo "__version__ = \"$(git describe)\"" > libzt/version.py
}
"$@"

View File

@@ -0,0 +1,3 @@
from .libzt import *
from .sockets import *
from .version import __version__

View File

@@ -0,0 +1 @@
__version__ = "1.3.4b0"

Some files were not shown because too many files have changed in this diff Show More