diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 735677d42..000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,236 +0,0 @@ -cmake_minimum_required (VERSION 3.8) - -cmake_policy(SET CMP0048 NEW) - -if(${CMAKE_VERSION} VERSION_LESS 3.15) - cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -else() - cmake_policy(VERSION 3.15) -endif() - -set(ZEROTIER_VERSION_MAJOR 1 CACHE INTERNAL "") -set(ZEROTIER_VERSION_MINOR 9 CACHE INTERNAL "") -set(ZEROTIER_VERSION_REVISION 0 CACHE INTERNAL "") -set(ZEROTIER_VERSION_BUILD 0 CACHE INTERNAL "") - -project(zerotier - VERSION ${ZEROTIER_VERSION_MAJOR}.${ZEROTIER_VERSION_MINOR}.${ZEROTIER_VERSION_REVISION}.${ZEROTIER_VERSION_BUILD} - DESCRIPTION "ZeroTier Network Hypervisor" - LANGUAGES CXX C) - -if(NOT PACKAGE_STATIC) - - set(default_build_type "Release") - - if(WIN32) - set(CMAKE_CXX_STANDARD 17) - set(CMAKE_SYSTEM_VERSION "7" CACHE STRING INTERNAL FORCE) - else(WIN32) - if(APPLE) - set(CMAKE_CXX_STANDARD 17) - else(APPLE) - set(CMAKE_CXX_STANDARD 11) - endif(APPLE) - endif(WIN32) - - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to '${default_build_type}' as none was specified.") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") - endif() - - option(BUILD_CENTRAL_CONTROLLER "Build ZeroTier Central Controller" OFF) - if(BUILD_CENTRAL_CONTROLLER) - find_package(PkgConfig REQUIRED) - if(APPLE) - set(CMAKE_PREFIX_PATH - ${CMAKE_PREFIX_PATH} - /usr/local/opt/libpq - /usr/local/lib - ) - endif(APPLE) - find_package(PostgreSQL REQUIRED) - - pkg_check_modules(hiredis REQUIRED IMPORTED_TARGET hiredis) - - add_subdirectory(controller/thirdparty/redis-plus-plus-1.1.1) - set(redispp_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/controller/thirdparty/redis-plus-plus-1.1.1/src/sw) - set(redispp_STATIC_LIB redispp_static) - endif(BUILD_CENTRAL_CONTROLLER) - - if(CMAKE_BUILD_TYPE STREQUAL "Debug") - add_definitions(-DZT_DEBUG) - endif(CMAKE_BUILD_TYPE STREQUAL "Debug") - - if(WIN32) - - message("++ Setting Windows Compiler Flags ${CMAKE_BUILD_TYPE}") - - add_definitions(-DNOMINMAX) - add_compile_options( - -Wall - -Wno-deprecated - -Wno-unused-function - -Wno-format - -Wno-attributes - $<$:-g> - $<$:-O0> - $<$:-O3> - $<$:-ffast-math> - $<$:-O3> - $<$:-g> - ) - - #set(GOFLAGS - # -a - # -trimpath - #) - - if(BUILD_32BIT) - set(CMAKE_SYSTEM_PROCESSOR "x86" CACHE STRING "system processor") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32" CACHE STRING "c++ flags") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32" CACHE STRING "c flags") - set(GOARCH "GOARCH=386" CACHE STRING "go architecture") - add_compile_options( - -m32 - ) - add_link_options( - -m32 - ) - endif(BUILD_32BIT) - - else(WIN32) - - if(APPLE) - - message("++ Setting MacOS Compiler Flags ${CMAKE_BUILD_TYPE}") - - set(MACOS_VERSION_MIN "10.14") - - add_compile_options( - -Wall - -Wno-deprecated - -Wno-unused-function - -Wno-attributes - -mmacosx-version-min=${MACOS_VERSION_MIN} - $<$:-g> - $<$:-O0> - $<$:-Ofast> - $<$:-ffast-math> - $<$:-fPIE> - $<$:-flto> - $<$:-O1> - $<$:-fPIE> - $<$:-g> - ) - - add_link_options( - -mmacosx-version-min=${MACOS_VERSION_MIN} - $<$:-flto> - ) - - else(APPLE) - - message("++ Setting Linux/BSD/Posix Compiler Flags (${CMAKE_BUILD_TYPE})") - - add_compile_options( - -Wall - -Wno-deprecated - -Wno-unused-function - -Wno-format - -Wno-attributes - $<$:-g> - $<$:-O0> - $<$:-O3> - $<$:-ffast-math> - $<$:-fPIE> - $<$:-O3> - $<$:-fPIE> - $<$:-g> - ) - - option(BUILD_32BIT "Force building as 32-bit binary" OFF) - option(BUILD_STATIC "Build statically linked executable" OFF) - - if(BUILD_32BIT) - set(CMAKE_SYSTEM_PROCESSOR "x86" CACHE STRING "system processor") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32" CACHE STRING "c++ flags") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32" CACHE STRING "c flags") - add_compile_options( - -m32 - ) - endif(BUILD_32BIT) - - if(BUILD_STATIC) - add_link_options( - -static - ) - set(CMAKE_EXE_LINKER_FLAGS "-static ${CMAKE_EXE_LINKER_FLAGS}") - endif(BUILD_STATIC) - - endif(APPLE) - endif(WIN32) - - if ( - CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64" OR - CMAKE_SYSTEM_PROCESSOR MATCHES "arm64" OR - CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64" OR - CMAKE_SYSTEM_PROCESSOR MATCHES "AARCH64" - ) - message("++ Adding flags for processor ${CMAKE_SYSTEM_PROCESSOR}") - add_compile_options(-march=armv8-a+aes+crypto -mtune=generic -mstrict-align) - endif() - - if(BUILD_CENTRAL_CONTROLLER) - add_definitions(-DZT_CONTROLLER_USE_LIBPQ=1) - endif(BUILD_CENTRAL_CONTROLLER) - - add_subdirectory(core) -# add_subdirectory(controller) - add_subdirectory(osdep) - -else(NOT PACKAGE_STATIC) - - if(BUILD_32BIT) - set(CMAKE_SYSTEM_PROCESSOR "x86" CACHE STRING "system processor") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32" CACHE STRING "c++ flags") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32" CACHE STRING "c flags") - add_compile_options( - -m32 - ) - endif(BUILD_32BIT) - - set(STATIC_BINARY ${CMAKE_BINARY_DIR}/zerotier) - set(IMPORTED_LOCATION ${CMAKE_BINARY_DIR}) - add_executable(zerotier IMPORTED GLOBAL) - install(PROGRAMS ${STATIC_BINARY} DESTINATION bin) - -endif(NOT PACKAGE_STATIC) - -# Linux packaging - -if("${CMAKE_SYSTEM_NAME}" EQUAL "Linux") - if(IS_DIRECTORY /lib/systemd/system) - install( - FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/debian/zerotier.service - DESTINATION /lib/systemd/system - ) - elseif(IS_DIRECTORY /usr/lib/systemd/system) - install( - FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/debian/zerotier.service - DESTINATION /usr/lib/systemd/system - ) - else() - install( - FILES ${CMAKE_CURRENT_SOURCE_DIR}/packaging/debian/zerotier.init - DESTINATION /etc/init.d - ) - endif() -endif() - -if("${ZT_PACKAGE_FORMAT}" MATCHES "DEB") - include(packaging/debian.cmake) -elseif("${ZT_PACKAGE_FORMAT}" MATCHES "RPM") - include(packaging/rpm.cmake) -else() -endif() diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 8a34c58e5..000000000 --- a/Jenkinsfile +++ /dev/null @@ -1,502 +0,0 @@ -pipeline { - options { - disableConcurrentBuilds() - preserveStashes(buildCount: 10) - timestamps() - } - parameters { - booleanParam(name: "BUILD_ALL", defaultValue: false, description: "Build all supported platform/architecture combos. Defaults to x86/x64 only") - } - environment { - PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - } - - agent none - - stages { - stage ("Build") { - steps { - script { - def tasks = [:] - tasks << buildStaticBinaries() - tasks << buildDebianNative() - tasks << buildCentosNative() - tasks << buildMacOS() - tasks << buildWindows() - tasks << buildFreeBSD() - - parallel tasks - } - } - } - stage ("Package Static") { - steps { - script { - parallel packageStatic() - } - } - } - } -} - -def buildMacOS() { - def tasks = [:] - tasks << getTasks(['mac'],['amd64'], {unused1, unused2 -> - def myNode = { - env.PATH = env.PATH + ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - node ('mac') { - dir("build") { - checkout scm - sh 'make' - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - return myNode - }) - return tasks -} - -def buildWindows() { - def tasks = [:] - tasks << getTasks(['windows'], ['amd64', 'i386'], { unused1, platform -> - def myNode = { - node ('windows') { - env.SHELL = 'C:/Windows/System32/cmd.exe' - dir ("build") { - checkout scm - - dir ("build") { - withEnv(["PATH=C:\\TDM-GCC-64\\bin;C:\\WINDOWS;C:\\Windows\\system32;C:\\CMake\\bin;C:\\Go\\bin"]) { - def cmakeFlags = "" - if (platform == "i386") { - cmakeFlags = '-DBUILD_32BIT=1' - } - bat """ - cmake -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release ${cmakeFlags} .. - mingw32-make -j8 - """ - } - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - } - return myNode - }) - - return tasks -} - -def buildFreeBSD() { - def tasks = [:] - tasks << getTasks(['freebsd12'], ['amd64'], { unused1, unused2 -> - def myNode = { - node ('freebsd12') { - dir('build') { - checkout scm - sh 'make setup' - dir('build') { - sh 'make -j4' - } - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - return myNode - }) - return tasks -} - -def buildStaticBinaries() { - def tasks = [:] - def dist = ["alpine"] - def archs = [] - if (params.BUILD_ALL == true) { - archs = ["arm64", "amd64", "i386", "armhf", "ppc64le", "s390x"] - } else { - archs = ["amd64", "i386"] - } - - tasks << getTasks(dist, archs, { distro, platform -> - def myNode = { - node ('linux-build') { - env.PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - dir ("build") { - checkout scm - } - def runtime = docker.image("ztbuild/${distro}-${platform}:latest") - runtime.inside { - dir("build") { - - def cmakeFlags = 'CMAKE_ARGS="-DBUILD_STATIC=1"' - if (platform == "i386") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_STATIC=1"' - } else if (platform == "armhf") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_STATIC=1 -DBUILD_ARM_V6=1"' - } - - sh "${cmakeFlags} make" - dir("build") { - sh "mv zerotier zerotier-static-${platform}" - stash includes: 'zerotier-static-*', name: "static-${platform}" - } - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - } - return myNode - }) - - return tasks -} - -def getTasks(axisDistro, axisPlatform, task) { - def tasks = [:] - for(int i=0; i< axisDistro.size(); i++) { - def axisDistroValue = axisDistro[i] - for(int j=0; j< axisPlatform.size(); j++) { - def axisPlatformValue = axisPlatform[j] - tasks["${axisDistroValue}/${axisPlatformValue}"] = task(axisDistroValue, axisPlatformValue) - } - } - return tasks -} - -def packageStatic() { - def tasks = [:] - - def centos7 = ["centos7"] - def centos7Arch = ["i386"] - tasks << getTasks(centos7, centos7Arch, { distro, arch -> - def myNode = { - node ('linux-build') { - env.PATH = env.PATH + ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - dir ("build") { - checkout scm - } - def runtime = docker.image("ztbuild/${distro}-${arch}:latest") - runtime.inside { - dir("build") { - unstash "static-${arch}" - sh "mkdir -p build" - sh "mv zerotier-static-${arch} build/zerotier && chmod +x build/zerotier" - sh 'CMAKE_ARGS="-DBUILD_32BIT=1 -DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=RPM" make setup' - dir("build") { - sh 'make package -j4 VERBOSE=1' - } - sh "mkdir -p ${distro}" - sh "cp -av build/*.rpm ${distro}/" - archiveArtifacts artifacts: "${distro}/*.rpm", onlyIfSuccessful: true - } - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - return myNode - }) - - if (params.BUILD_ALL == true) { - def s390xStatics = ["clefos", "debian-buster", "debian-sid", "debian-bullseye", "debian-stretch", "ubuntu-bionic", "ubuntu-eoan", "ubuntu-focal"] - def s390x = ["s390x"] - tasks << getTasks(s390xStatics, s390x , { distro, arch -> - def myNode = { - node ('linux-build') { - env.PATH = env.PATH + ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - dir ("build") { - checkout scm - } - def runtime = docker.image("ztbuild/${distro}-${arch}:latest") - def pkgFormat = "DEB" - if (distro == "clefos") { - pkgFormat = "RPM" - } - runtime.inside { - dir("build/") { - unstash "static-${arch}" - sh "mkdir -p build" - sh "mv zerotier-static-${arch} build/zerotier && chmod +x build/zerotier" - sh "CMAKE_ARGS=\"-DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=${pkgFormat}\" make setup" - dir("build") { - sh 'make package -j4 VERBOSE=1' - } - sh "mkdir -p ${distro}" - sh "cp -av build/*.rpm ${distro}/" - archiveArtifacts artifacts: "${distro}/*.rpm", onlyIfSuccessful: true - } - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - return myNode - }) - } - - def debianJessie = ["debian-jessie"] - def debianJessieArchs = [] - if (params.BUILD_ALL == true) { - debianJessieArch = ["armhf", "amd64", "i386"] - } else { - debianJessieArch = ["amd64", "i386"] - } - tasks << getTasks(debianJessie, debianJessieArch, { distro, arch -> - def myNode = { - node ('linux-build') { - env.PATH = env.PATH + ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - dir ("build") { - checkout scm - } - def runtime = docker.image("ztbuild/${distro}-${arch}:latest") - runtime.inside { - dir('build/') { - def cmakeFlags = 'CMAKE_ARGS="-DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB"' - if (arch == "i386") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_32BIT=1 -DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB"' - } else if (arch == "armel") { - cmakeFlags = 'CMAKE_ARGS="-DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB -DBUILD_ARM_V5=1"' - } else if (arch == "armhf") { - cmakeFlags = 'CMAKE_ARGS="-DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB -DBUILD_ARM_V6=1"' - } - - unstash "static-${arch}" - sh "mkdir -p build" - sh "mv zerotier-static-${arch} build/zerotier && chmod +x build/zerotier" - sh "${cmakeFlags} make setup" - dir("build") { - sh 'make package -j4 VERBOSE=1' - } - sh "mkdir -p ${distro}" - sh "cp -av build/*.deb ${distro}/" - archiveArtifacts artifacts: "${distro}/*.deb", onlyIfSuccessful: true - } - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - return myNode - }) - - def ubuntuTrusty = ["ubuntu-trusty"] - def ubuntuTrustyArch = [] - if (params.BUILD_ALL == true) { - ubuntuTrustyArch = ["i386", "amd64", "arm64", "ppc64le"] - } else { - ubuntuTrustyArch = ["i386", "amd64"] - } - tasks << getTasks(ubuntuTrusty, ubuntuTrustyArch, { distro, arch -> - def myNode = { - node ('linux-build') { - env.PATH = env.PATH + ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - dir ("build") { - checkout scm - } - def runtime = docker.image("ztbuild/${distro}-${arch}:latest") - runtime.inside { - dir('build/') { - def cmakeFlags = 'CMAKE_ARGS="-DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB"' - if (arch == "i386") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_32BIT=1 -DBUILD_STATIC=1 -DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB"' - } else if (arch == "armel") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_STATIC=1 -DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB -DBUILD_ARM_V5=1"' - } else if (arch == "armhf") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_STATIC=1 -DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB -DBUILD_ARM_V6=1"' - } - - unstash "static-${arch}" - sh "mkdir -p build" - sh "mv zerotier-static-${arch} build/zerotier && chmod +x build/zerotier" - sh "${cmakeFlags} make setup" - dir("build") { - sh 'make package -j4 VERBOSE=1' - } - sh "mkdir -p ${distro}" - sh "cp -av build/*.deb ${distro}/" - archiveArtifacts artifacts: "${distro}/*.deb", onlyIfSuccessful: true - } - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - return myNode - }) - - def debianWheezy = ["debian-wheezy"] - def debianWheezyArchs = [] - if (params.BUILD_ALL == true) { - debianWheezyArchs = ["armhf", "amd64", "i386"] - } else { - debianWheezyArchs = ["amd64", "i386"] - } - tasks << getTasks(debianJessie, debianJessieArch, { distro, arch -> - def myNode = { - node ('linux-build') { - env.PATH = env.PATH + ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - dir ("build") { - checkout scm - } - def runtime = docker.image("ztbuild/${distro}-${arch}:latest") - runtime.inside { - dir('build/') { - def cmakeFlags = 'CMAKE_ARGS="-DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB"' - if (arch == "i386") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_32BIT=1 -DBUILD_STATIC=1 -DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB"' - } else if (arch == "armel") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_STATIC=1 -DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB -DBUILD_ARM_V5=1"' - } else if (arch == "armhf") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_STATIC=1 -DPACKAGE_STATIC=1 -DZT_PACKAGE_FORMAT=DEB -DBUILD_ARM_V6=1"' - } - unstash "static-${arch}" - sh "mkdir -p build" - sh "mv zerotier-static-${arch} build/zerotier && chmod +x build/zerotier" - sh "${cmakeFlags} make setup" - dir("build") { - sh 'make package -j4 VERBOSE=1' - } - sh "mkdir -p ${distro}" - sh "cp -av build/*.deb ${distro}/" - archiveArtifacts artifacts: "${distro}/*.deb", onlyIfSuccessful: true - } - } - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - return myNode - }) - - return tasks -} - -def buildDebianNative() { - def tasks = [:] - def debian = ["debian-buster" , "debian-stretch", "debian-sid", "debian-bullseye"] - def debianArchs = [] - if (params.BUILD_ALL) { - debianArchs = ["ppc64le", "i386", "armhf", "armel", "arm64", "amd64"] - } else { - debianArchs = ["amd64", "i386"] - } - - def build = { distro, arch -> - def myNode = { - node ('linux-build') { - env.PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - dir ("build") { - checkout scm - } - def runtime = docker.image("ztbuild/${distro}-${arch}:latest") - runtime.inside { - def cmakeFlags = 'CMAKE_ARGS="-DZT_PACKAGE_FORMAT=DEB"' - if (arch == "i386") { - cmakeFlags = 'CMAKE_ARGS="-DBUILD_32BIT=1 -DZT_PACKAGE_FORMAT=DEB"' - } else if (arch == "armel") { - cmakeFlags = 'CMAKE_ARGS="-DZT_PACKAGE_FORMAT=DEB -DBUILD_ARM_V5=1"' - } else if (arch == "armhf") { - cmakeFlags = 'CMAKE_ARGS="-DZT_PACKAGE_FORMAT=DEB -DBUILD_ARM_V6=1"' - } - - dir("build") { - sh "${cmakeFlags} make setup" - dir("build") { - sh "make package -j4 VERBOSE=1" - } - } - sh "mkdir -p ${distro}" - sh "mv build/build/*.deb ${distro}" - archiveArtifacts artifacts: "${distro}/*.deb", onlyIfSuccessful: true - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - } - return myNode - } - - tasks << getTasks(debian, debianArchs, build) - - // bash is broken when running under QEMU-s390x on Xenial - def xenial = ["ubuntu-xenial"] - def xenialArchs = [] - if (params.BUILD_ALL == true) { - xenialArchs = ["i386", "amd64", "armhf", "arm64", "ppc64le"] - } else { - xenialArchs = ["i386", "amd64"] - } - tasks << getTasks(xenial, xenialArchs, build) - - def ubuntu = ["ubuntu-bionic", "ubuntu-eoan"] - def ubuntuArchs = [] - if (params.BUILD_ALL == true) { - ubuntuArchs = ["i386", "amd64", "armhf", "arm64", "ppc64le"] - } else { - ubuntuArchs = ["i386", "amd64"] - } - tasks << getTasks(ubuntu, ubuntuArchs, build) - - def ubuntuFocal = ["ubuntu-focal"] - def ubuntuFocalArchs = [] - if (params.BUILD_ALL == true) { - ubuntuFocalArchs = ["amd64", "arm64", "ppc64le"] - } else { - ubuntuFocalArchs = ["amd64"] - } - tasks << getTasks(ubuntuFocal, ubuntuFocalArchs, build) - - def kali = ["kali-rolling"] - def kaliArchs = ["amd64"] - tasks << getTasks(kali, kaliArchs, build) - - return tasks -} - -def buildCentosNative() { - def tasks = [:] - - def build = { distro, arch -> - def myNode = { - node ('linux-build') { - env.PATH = env.PATH + ":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/go/bin:/home/jenkins-build/go/bin" - dir ("build") { - checkout scm - } - def runtime = docker.image("ztbuild/${distro}-${arch}:latest") - runtime.inside { - dir("build") { - if (distro == 'centos7' && arch == 'amd64') { - sh 'source scl_source enable devtoolset-8 llvm-toolset-7 && CMAKE_ARGS="-DZT_PACKAGE_FORMAT=RPM" make setup' - } else { - sh 'CMAKE_ARGS="-DZT_PACKAGE_FORMAT=RPM" make setup' - } - dir ("build") { - if (distro == 'centos7' && arch == 'amd64') { - sh 'source scl_source enable devtoolset-8 llvm-toolset-7 && make package -j4 VERBOSE=1' - } else { - sh 'make package -j4 VERBOSE=1' - } - } - } - sh "mkdir -p ${distro}" - sh "cp -av build/build/*.rpm ${distro}/" - archiveArtifacts artifacts: "${distro}/*.rpm", onlyIfSuccessful: true - - cleanWs deleteDirs: true, disableDeferredWipeout: true, notFailBuild: true - } - } - } - return myNode - } - - def centos8 = ["centos8"] - def centos8Archs = [] - if (params.BUILD_ALL == true) { - centos8Archs = ["amd64", "arm64", "ppc64le"] - } else { - centos8Archs = ["amd64"] - } - tasks << getTasks(centos8, centos8Archs, build) - - def centos7 = ["centos7"] - def centos7Archs = ["amd64"] - tasks << getTasks(centos7, centos7Archs, build) - - return tasks -} diff --git a/Makefile b/Makefile deleted file mode 100644 index 3dfd97f4e..000000000 --- a/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -BUILDDIR := build -TIMESTAMP=$(shell date +"%Y%m%d%H%M") - -.PHONY: all - -all: setup - cd ${BUILDDIR} && $(MAKE) -j4 VERBOSE=1 - -setup: FORCE - mkdir -p ${BUILDDIR} && cd ${BUILDDIR} && cmake .. -DCMAKE_BUILD_TYPE=Release ${CMAKE_ARGS} - -setup-debug: FORCE - mkdir -p ${BUILDDIR} && cd ${BUILDDIR} && cmake .. -DCMAKE_BUILD_TYPE=Debug ${CMAKE_ARGS} - -debug: FORCE - mkdir -p ${BUILDDIR} && cd ${BUILDDIR} && cmake .. -DCMAKE_BUILD_TYPE=Debug ${CMAKE_ARGS} && $(MAKE) - -central-controller: FORCE - mkdir -p ${BUILDDIR} && cd ${BUILDDIR} && cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_CENTRAL_CONTROLLER=1 ${CMAKE_ARGS} && $(MAKE) -j4 - -central-controller-debug: FORCE - mkdir -p ${BUILDDIR} && cd ${BUILDDIR} && cmake .. -DCMAKE_BUILD_TYPE=Debug -DBUILD_CENTRAL_CONTROLLER=1 ${CMAKE_ARGS} && $(MAKE) -j4 - -central-controller-docker: FORCE - docker build -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f controller/central-docker/Dockerfile . - -clean: FORCE - rm -rf ${BUILDDIR} rust-zerotier-core/target service/target rust-zerotier-core/src/capi.rs service/src/osdep.rs - -distclean: FORCE - rm -rf ${BUILDDIR} - -rust-bindgen: FORCE - cargo install bindgen - rm -f rust-zerotier-core/src/capi.rs service/src/osdep.rs - bindgen --no-doc-comments --no-layout-tests --no-derive-debug core/zerotier.h >rust-zerotier-core/src/capi.rs - bindgen --no-doc-comments --no-layout-tests --no-derive-debug osdep/rust-osdep.h >service/src/osdep.rs - -FORCE: diff --git a/attic/Arp.cpp b/attic/Arp.cpp deleted file mode 100644 index 8bf69f9ee..000000000 --- a/attic/Arp.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#include -#include - -#include "Arp.hpp" -#include "OSUtils.hpp" - -namespace ZeroTier { - -static const uint8_t ARP_REQUEST_HEADER[8] = {0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x01}; -static const uint8_t ARP_RESPONSE_HEADER[8] = {0x00, 0x01, 0x08, 0x00, 0x06, 0x04, 0x00, 0x02}; - -Arp::Arp() : - _cache(), - _lastCleaned(OSUtils::now()) -{ -} - -void Arp::addLocal(uint32_t ip, const MAC &mac) -{ - _ArpEntry &e = _cache[ip]; - e.lastQuerySent = 0; // local IP - e.lastResponseReceived = 0; // local IP - e.mac = mac; - e.local = true; -} - -void Arp::remove(uint32_t ip) -{ - _cache.erase(ip); -} - -uint32_t Arp::processIncomingArp(const void *arp, unsigned int len, void *response, unsigned int &responseLen, MAC &responseDest) -{ - const uint64_t now = OSUtils::now(); - uint32_t ip = 0; - - responseLen = 0; - responseDest.zero(); - - if (len >= 28) { - if (!memcmp(arp, ARP_REQUEST_HEADER, 8)) { - // Respond to ARP requests for locally-known IPs - Map< uint32_t, Arp::_ArpEntry >::const_iterator targetEntry(_cache.find(reinterpret_cast(arp)[6])); - if ((targetEntry != _cache.end()) && (targetEntry->second.local)) { - memcpy(response, ARP_RESPONSE_HEADER, 8); - targetEntry->second.mac.copyTo(reinterpret_cast(response) + 8); - memcpy(reinterpret_cast(response) + 14, reinterpret_cast(arp) + 24, 4); - memcpy(reinterpret_cast(response) + 18, reinterpret_cast(arp) + 8, 10); - responseLen = 28; - responseDest.setTo(reinterpret_cast(arp) + 8); - } - } else if (!memcmp(arp, ARP_RESPONSE_HEADER, 8)) { - // Learn cache entries for remote IPs from relevant ARP replies - uint32_t responseIp = 0; - memcpy(&responseIp, reinterpret_cast(arp) + 14, 4); - Map< uint32_t, Arp::_ArpEntry >::iterator queryEntry(_cache.find(responseIp)); - if ((queryEntry != _cache.end()) && (!queryEntry->second.local) && ((now - queryEntry->second.lastQuerySent) <= ZT_ARP_QUERY_MAX_TTL)) { - queryEntry->second.lastResponseReceived = now; - queryEntry->second.mac.setTo(reinterpret_cast(arp) + 8); - ip = responseIp; - } - } - } - - if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) { - _lastCleaned = now; - for (Map< uint32_t, _ArpEntry >::iterator i(_cache.begin()); i != _cache.end();) { - if ((!i->second.local) && ((now - i->second.lastResponseReceived) >= ZT_ARP_EXPIRE)) - _cache.erase(i++); - else ++i; - } - } - - return ip; -} - -MAC Arp::query(const MAC &localMac, uint32_t localIp, uint32_t targetIp, void *query, unsigned int &queryLen, MAC &queryDest) -{ - const uint64_t now = OSUtils::now(); - - _ArpEntry &e = _cache[targetIp]; - - if (((e.mac) && ((now - e.lastResponseReceived) >= (ZT_ARP_EXPIRE / 3))) || - ((!e.mac) && ((now - e.lastQuerySent) >= ZT_ARP_QUERY_INTERVAL))) { - e.lastQuerySent = now; - - uint8_t *q = reinterpret_cast(query); - memcpy(q, ARP_REQUEST_HEADER, 8); - q += 8; // ARP request header information, always the same - localMac.copyTo(q); - q += 6; // sending host MAC address - memcpy(q, &localIp, 4); - q += 4; // sending host IP (IP already in big-endian byte order) - memset(q, 0, 6); - q += 6; // sending zeros for target MAC address as thats what we want to find - memcpy(q, &targetIp, 4); // target IP address for resolution (IP already in big-endian byte order) - queryLen = 28; - if (e.mac) - queryDest = e.mac; // confirmation query, send directly to address holder - else queryDest = (uint64_t)0xffffffffffffULL; // broadcast query - } else { - queryLen = 0; - queryDest.zero(); - } - - return e.mac; -} - -} // namespace ZeroTier diff --git a/attic/Arp.hpp b/attic/Arp.hpp deleted file mode 100644 index 5c6fe1ae3..000000000 --- a/attic/Arp.hpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#ifndef ZT_ARP_HPP -#define ZT_ARP_HPP - -#include "../core/Constants.hpp" -#include "../core/Containers.hpp" -#include "../core/MAC.hpp" - -#include -#include - -/** - * Maximum possible ARP length - * - * ARPs are 28 bytes in length, but specify a 128 byte buffer since - * some weird extensions we may support in the future can pad them - * out to as long as 72 bytes. - */ -#define ZT_ARP_BUF_LENGTH 128 - -/** - * Minimum permitted interval between sending ARP queries for a given IP - */ -#define ZT_ARP_QUERY_INTERVAL 2000 - -/** - * Maximum time between query and response, otherwise responses are discarded to prevent poisoning - */ -#define ZT_ARP_QUERY_MAX_TTL 5000 - -/** - * ARP expiration time - */ -#define ZT_ARP_EXPIRE 600000 - -namespace ZeroTier { - -/** - * ARP cache and resolver - * - * To implement ARP: - * - * (1) Call processIncomingArp() on all ARP packets received and then always - * check responseLen after calling. If it is non-zero, send the contents - * of response to responseDest. - * - * (2) Call query() to look up IP addresses, and then check queryLen. If it - * is non-zero, send the contents of query to queryDest (usually broadcast). - * - * Note that either of these functions can technically generate a response or - * a query at any time, so their result parameters for sending ARPs should - * always be checked. - * - * This class is not thread-safe and must be guarded if used in multi-threaded - * code. - */ -class Arp -{ -public: - Arp(); - - /** - * Set a local IP entry that we should respond to ARPs for - * - * @param mac Our local MAC address - * @param ip IP in big-endian byte order (sin_addr.s_addr) - */ - void addLocal(uint32_t ip,const MAC &mac); - - /** - * Delete a local IP entry or a cached ARP entry - * - * @param ip IP in big-endian byte order (sin_addr.s_addr) - */ - void remove(uint32_t ip); - - /** - * Process ARP packets - * - * For ARP queries, a response is generated and responseLen is set to its - * frame payload length in bytes. - * - * For ARP responses, the cache is populated and the IP address entry that - * was learned is returned. - * - * @param arp ARP frame data - * @param len Length of ARP frame (usually 28) - * @param response Response buffer -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size - * @param responseLen Response length, or set to 0 if no response - * @param responseDest Destination of response, or set to null if no response - * @return IP address learned or 0 if no new IPs in cache - */ - uint32_t processIncomingArp(const void *arp,unsigned int len,void *response,unsigned int &responseLen,MAC &responseDest); - - /** - * Get the MAC corresponding to an IP, generating a query if needed - * - * This returns a MAC for a remote IP. The local MAC is returned for local - * IPs as well. It may also generate a query if the IP is not known or the - * entry needs to be refreshed. In this case queryLen will be set to a - * non-zero value, so this should always be checked on return even if the - * MAC returned is non-null. - * - * @param localMac Local MAC address of host interface - * @param localIp Local IP address of host interface - * @param targetIp IP to look up - * @param query Buffer for generated query -- MUST be a minimum of ZT_ARP_BUF_LENGTH in size - * @param queryLen Length of generated query, or set to 0 if no query generated - * @param queryDest Destination of query, or set to null if no query generated - * @return MAC or 0 if no cached entry for this IP - */ - MAC query(const MAC &localMac,uint32_t localIp,uint32_t targetIp,void *query,unsigned int &queryLen,MAC &queryDest); - -private: - struct _ArpEntry - { - _ArpEntry() : lastQuerySent(0),lastResponseReceived(0),mac(),local(false) {} - uint64_t lastQuerySent; // Time last query was sent or 0 for local IP - uint64_t lastResponseReceived; // Time of last ARP response or 0 for local IP - MAC mac; // MAC address of device responsible for IP or null if not known yet - bool local; // True if this is a local ARP entry - }; - - Map< uint32_t,_ArpEntry > _cache; - uint64_t _lastCleaned; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/MacEthernetTap.cpp b/attic/MacEthernetTap.cpp deleted file mode 100644 index 0dae5cd97..000000000 --- a/attic/MacEthernetTap.cpp +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Copyright (c)2019 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#include "../node/Constants.hpp" - -#ifdef __APPLE__ - -#include "../node/Utils.hpp" -#include "../node/Mutex.hpp" -#include "../node/Dictionary.hpp" -#include "OSUtils.hpp" -#include "MacEthernetTap.hpp" -#include "MacEthernetTapAgent.h" -#include "MacDNSHelper.hpp" - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); - -namespace ZeroTier { - -static Mutex globalTapCreateLock; -static bool globalTapInitialized = false; - -MacEthernetTap::MacEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _homePath(homePath), - _mtu(mtu), - _metric(metric), - _devNo(0), - _agentStdin(-1), - _agentStdout(-1), - _agentStderr(-1), - _agentStdin2(-1), - _agentStdout2(-1), - _agentStderr2(-1), - _agentPid(-1), - _enabled(true) -{ - char ethaddr[64],mtustr[16],devnostr[16],devstr[16],metricstr[16]; - OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",mtu); - OSUtils::ztsnprintf(metricstr,sizeof(metricstr),"%u",metric); - - std::string agentPath(homePath); - agentPath.push_back(ZT_PATH_SEPARATOR); - agentPath.append("MacEthernetTapAgent"); - if (!OSUtils::fileExists(agentPath.c_str())) - throw std::runtime_error("MacEthernetTapAgent not present in ZeroTier home"); - - Mutex::Lock _gl(globalTapCreateLock); // only make one at a time - - // Destroy all feth devices on first tap start in case ZeroTier did not exit cleanly last time. - // We leave interfaces less than feth100 alone in case something else is messing with feth devices. - if (!globalTapInitialized) { - globalTapInitialized = true; - struct ifaddrs *ifa = (struct ifaddrs *)0; - std::set deleted; - if (!getifaddrs(&ifa)) { - struct ifaddrs *p = ifa; - while (p) { - int nameLen = (int)strlen(p->ifa_name); - // Delete feth# from feth0 to feth9999, but don't touch >10000. - if ((!strncmp(p->ifa_name,"feth",4))&&(nameLen >= 5)&&(nameLen <= 8)&&(deleted.count(std::string(p->ifa_name)) == 0)) { - deleted.insert(std::string(p->ifa_name)); - const char *args[4]; - args[0] = "/sbin/ifconfig"; - args[1] = p->ifa_name; - args[2] = "destroy"; - args[3] = (char *)0; - const pid_t pid = vfork(); - if (pid == 0) { - execv(args[0],const_cast(args)); - _exit(-1); - } else if (pid > 0) { - int rv = 0; - waitpid(pid,&rv,0); - } - } - p = p->ifa_next; - } - freeifaddrs(ifa); - } - } - - unsigned int devNo = 100 + ((nwid ^ (nwid >> 32) ^ (nwid >> 48)) % 4900); - for(;;) { - OSUtils::ztsnprintf(devnostr,sizeof(devnostr),"%u",devNo); - OSUtils::ztsnprintf(devstr,sizeof(devstr),"feth%u",devNo); - bool duplicate = false; - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (!getifaddrs(&ifa)) { - struct ifaddrs *p = ifa; - while (p) { - if (!strcmp(p->ifa_name,devstr)) { - duplicate = true; - break; - } - p = p->ifa_next; - } - freeifaddrs(ifa); - } - if (duplicate) { - devNo = (devNo + 1) % 5000; - if (devNo < 100) - devNo = 100; - } else { - _dev = devstr; - _devNo = devNo; - break; - } - } - - if (::pipe(_shutdownSignalPipe)) - throw std::runtime_error("pipe creation failed"); - - int agentStdin[2]; - int agentStdout[2]; - int agentStderr[2]; - if (::pipe(agentStdin)) - throw std::runtime_error("pipe creation failed"); - if (::pipe(agentStdout)) - throw std::runtime_error("pipe creation failed"); - if (::pipe(agentStderr)) - throw std::runtime_error("pipe creation failed"); - _agentStdin = agentStdin[1]; - _agentStdout = agentStdout[0]; - _agentStderr = agentStderr[0]; - _agentStdin2 = agentStdin[0]; - _agentStdout2 = agentStdout[1]; - _agentStderr2 = agentStderr[1]; - long apid = (long)fork(); - if (apid < 0) { - throw std::runtime_error("fork failed"); - } else if (apid == 0) { - ::dup2(agentStdin[0],STDIN_FILENO); - ::dup2(agentStdout[1],STDOUT_FILENO); - ::dup2(agentStderr[1],STDERR_FILENO); - ::close(agentStdin[0]); - ::close(agentStdin[1]); - ::close(agentStdout[0]); - ::close(agentStdout[1]); - ::close(agentStderr[0]); - ::close(agentStderr[1]); - ::execl(agentPath.c_str(),agentPath.c_str(),devnostr,ethaddr,mtustr,metricstr,(char *)0); - ::_exit(-1); - } else { - _agentPid = apid; - } - Thread::sleep(100); // this causes them to come up in a more user-friendly order on launch - - _thread = Thread::start(this); -} - -MacEthernetTap::~MacEthernetTap() -{ - char tmp[64]; - const char *args[4]; - pid_t pid0,pid1; - - MacDNSHelper::removeDNS(_nwid); - - Mutex::Lock _gl(globalTapCreateLock); - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - - int ec = 0; - ::kill(_agentPid,SIGKILL); - ::waitpid(_agentPid,&ec,0); - - args[0] = "/sbin/ifconfig"; - args[1] = _dev.c_str(); - args[2] = "destroy"; - args[3] = (char *)0; - pid0 = vfork(); - if (pid0 == 0) { - execv(args[0],const_cast(args)); - _exit(-1); - } - - snprintf(tmp,sizeof(tmp),"feth%u",_devNo + 5000); - //args[0] = "/sbin/ifconfig"; - args[1] = tmp; - //args[2] = "destroy"; - //args[3] = (char *)0; - pid1 = vfork(); - if (pid1 == 0) { - execv(args[0],const_cast(args)); - _exit(-1); - } - - if (pid0 > 0) { - int rv = 0; - waitpid(pid0,&rv,0); - } - if (pid1 > 0) { - int rv = 0; - waitpid(pid1,&rv,0); - } - - Thread::join(_thread); -} - -void MacEthernetTap::setEnabled(bool en) { _enabled = en; } -bool MacEthernetTap::enabled() const { return _enabled; } - -bool MacEthernetTap::addIp(const InetAddress &ip) -{ - char tmp[128]; - - if (!ip) - return false; - - std::string cmd; - cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); - cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet"); - cmd.push_back(0); - cmd.append(ip.toString(tmp)); - cmd.push_back(0); - cmd.append("alias"); - cmd.push_back(0); - - uint16_t l = (uint16_t)cmd.length(); - _putLock.lock(); - write(_agentStdin,&l,2); - write(_agentStdin,cmd.data(),cmd.length()); - _putLock.unlock(); - - return true; -} - -bool MacEthernetTap::removeIp(const InetAddress &ip) -{ - char tmp[128]; - - if (!ip) - return false; - - std::string cmd; - cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); - cmd.append((ip.ss_family == AF_INET6) ? "inet6" : "inet"); - cmd.push_back(0); - cmd.append(ip.toString(tmp)); - cmd.push_back(0); - cmd.append("-alias"); - cmd.push_back(0); - - uint16_t l = (uint16_t)cmd.length(); - _putLock.lock(); - write(_agentStdin,&l,2); - write(_agentStdin,cmd.data(),cmd.length()); - _putLock.unlock(); - - return true; -} - -std::vector MacEthernetTap::ips() const -{ - struct ifaddrs *ifa = (struct ifaddrs *)0; - std::vector r; - if (!getifaddrs(&ifa)) { - struct ifaddrs *p = ifa; - while (p) { - if ((p->ifa_name)&&(!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } - freeifaddrs(ifa); - } - std::sort(r.begin(),r.end()); - r.erase(std::unique(r.begin(),r.end()),r.end()); - return r; -} - -void MacEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - struct iovec iov[3]; - unsigned char hdr[15]; - uint16_t l; - if ((_agentStdin > 0)&&(len <= _mtu)&&(_enabled)) { - hdr[0] = ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET; - to.copyTo(hdr + 1,6); - from.copyTo(hdr + 7,6); - hdr[13] = (unsigned char)((etherType >> 8) & 0xff); - hdr[14] = (unsigned char)(etherType & 0xff); - l = (uint16_t)(len + 15); - iov[0].iov_base = &l; - iov[0].iov_len = 2; - iov[1].iov_base = hdr; - iov[1].iov_len = 15; - iov[2].iov_base = const_cast(data); - iov[2].iov_len = len; - _putLock.lock(); - writev(_agentStdin,iov,3); - _putLock.unlock(); - } -} - -std::string MacEthernetTap::deviceName() const { return _dev; } -void MacEthernetTap::setFriendlyName(const char *friendlyName) {} - -void MacEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - std::vector newGroups; - - struct ifmaddrs *ifmap = (struct ifmaddrs *)0; - if (!getifmaddrs(&ifmap)) { - struct ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); - } - p = p->ifma_next; - } - freeifmaddrs(ifmap); - } - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - newGroups.erase(std::unique(newGroups.begin(),newGroups.end()),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); -} - -void MacEthernetTap::setMtu(unsigned int mtu) -{ - if (_mtu != mtu) { - char tmp[16]; - std::string cmd; - cmd.push_back((char)ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG); - cmd.append("mtu"); - cmd.push_back(0); - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); - cmd.append(tmp); - cmd.push_back(0); - uint16_t l = (uint16_t)cmd.length(); - _putLock.lock(); - write(_agentStdin,&l,2); - write(_agentStdin,cmd.data(),cmd.length()); - _putLock.unlock(); - _mtu = mtu; - } -} - -#define ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE 131072 - -void MacEthernetTap::threadMain() - throw() -{ - char agentReadBuf[ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE]; - char agentStderrBuf[256]; - fd_set readfds,nullfds; - MAC to,from; - - Thread::sleep(250); - - const int nfds = std::max(std::max(_shutdownSignalPipe[0],_agentStdout),_agentStderr) + 1; - long agentReadPtr = 0; - fcntl(_agentStdout,F_SETFL,fcntl(_agentStdout,F_GETFL)|O_NONBLOCK); - fcntl(_agentStderr,F_SETFL,fcntl(_agentStderr,F_GETFL)|O_NONBLOCK); - - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_agentStdout,&readfds); - FD_SET(_agentStderr,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); - - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) - break; - - if (FD_ISSET(_agentStdout,&readfds)) { - long n = (long)read(_agentStdout,agentReadBuf + agentReadPtr,ZT_MACETHERNETTAP_AGENT_READ_BUF_SIZE - agentReadPtr); - if (n > 0) { - agentReadPtr += n; - while (agentReadPtr >= 2) { - long len = *((uint16_t *)agentReadBuf); - if (agentReadPtr >= (len + 2)) { - char *msg = agentReadBuf + 2; - - if ((len > 14)&&(_enabled)) { - to.setTo(msg,6); - from.setTo(msg + 6,6); - _handler(_arg,(void *)0,_nwid,from,to,ntohs(((const uint16_t *)msg)[6]),0,(const void *)(msg + 14),(unsigned int)len - 14); - } - - if (agentReadPtr > (len + 2)) { - memmove(agentReadBuf,agentReadBuf + len + 2,agentReadPtr -= (len + 2)); - } else { - agentReadPtr = 0; - } - } else { - break; - } - } - } - } - - if (FD_ISSET(_agentStderr,&readfds)) { - read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf)); - /* - const ssize_t n = read(_agentStderr,agentStderrBuf,sizeof(agentStderrBuf)); - if (n > 0) - write(STDERR_FILENO,agentStderrBuf,(size_t)n); - */ - } - } - - ::close(_agentStdin); - ::close(_agentStdout); - ::close(_agentStderr); - ::close(_agentStdin2); - ::close(_agentStdout2); - ::close(_agentStderr2); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); -} - -void MacEthernetTap::setDns(const char *domain, const std::vector &servers) -{ - MacDNSHelper::setDNS(this->_nwid, domain, servers); -} - -} // namespace ZeroTier - -#endif // __APPLE__ diff --git a/attic/MacEthernetTap.hpp b/attic/MacEthernetTap.hpp deleted file mode 100644 index 095fda0c1..000000000 --- a/attic/MacEthernetTap.hpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c)2019 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#ifndef ZT_OSXETHERNETTAP_HPP -#define ZT_OSXETHERNETTAP_HPP - -#include "../node/Constants.hpp" -#include "../node/MAC.hpp" -#include "../node/InetAddress.hpp" -#include "../node/MulticastGroup.hpp" -#include "../node/Mutex.hpp" -#include "Thread.hpp" -#include "EthernetTap.hpp" - -#include -#include - -#include -#include -#include - -namespace ZeroTier { - -class MacEthernetTap : public EthernetTap -{ -public: - MacEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); - - virtual ~MacEthernetTap(); - - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); - virtual bool removeIp(const InetAddress &ip); - virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); - virtual void setMtu(unsigned int mtu); - virtual void setDns(const char *domain, const std::vector &servers); - - void threadMain() - throw(); - -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - Thread _thread; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - Mutex _putLock; - unsigned int _mtu; - unsigned int _metric; - unsigned int _devNo; - int _shutdownSignalPipe[2]; - int _agentStdin,_agentStdout,_agentStderr,_agentStdin2,_agentStdout2,_agentStderr2; - long _agentPid; - volatile bool _enabled; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/MacEthernetTapAgent.c b/attic/MacEthernetTapAgent.c deleted file mode 100644 index 90da4777c..000000000 --- a/attic/MacEthernetTapAgent.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Copyright (c)2019 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -/* - * This creates a pair of feth devices with the lower numbered device - * being the ZeroTier virtual interface and the other being the device - * used to actually read and write packets. The latter gets no IP config - * and is only used for I/O. The behavior of feth is similar to the - * veth pairs that exist on Linux. - * - * The feth device has only existed since MacOS Sierra, but that's fairly - * long ago in Mac terms. - * - * I/O with feth must be done using two different sockets. The BPF socket - * is used to receive packets, while an AF_NDRV (low-level network driver - * access) socket must be used to inject. AF_NDRV can't read IP frames - * since BSD doesn't forward packets out the NDRV tap if they've already - * been handled, and while BPF can inject its MTU for injected packets - * is limited to 2048. AF_NDRV packet injection is required to inject - * ZeroTier's large MTU frames. - * - * All this stuff is basically undocumented. A lot of tracing through - * the Darwin/XNU kernel source was required to figure out how to make - * this actually work. - * - * We hope to develop a DriverKit-based driver in the near-mid future to - * replace this weird hack, but it works for now through Big Sur in our - * testing. - * - * See also: - * - * https://apple.stackexchange.com/questions/337715/fake-ethernet-interfaces-feth-if-fake-anyone-ever-seen-this - * https://opensource.apple.com/source/xnu/xnu-4570.41.2/bsd/net/if_fake.c.auto.html - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "../version.h" -#include "MacEthernetTapAgent.h" - -#ifndef SIOCAUTOCONF_START -#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ -#endif -#ifndef SIOCAUTOCONF_STOP -#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ -#endif - -#define P_IFCONFIG "/sbin/ifconfig" - -static unsigned char s_pktReadBuf[131072] __attribute__ ((__aligned__(16))); -static unsigned char s_stdinReadBuf[131072] __attribute__ ((__aligned__(16))); -static char s_deviceName[IFNAMSIZ]; -static char s_peerDeviceName[IFNAMSIZ]; -static int s_bpffd = -1; -static int s_ndrvfd = -1; -static pid_t s_parentPid; - -static void configureIpv6Parameters(const char *ifname,int performNUD,int acceptRouterAdverts) -{ - struct in6_ndireq nd; - struct in6_ifreq ifr; - - int s = socket(AF_INET6,SOCK_DGRAM,0); - if (s <= 0) - return; - - memset(&nd,0,sizeof(nd)); - strncpy(nd.ifname,ifname,sizeof(nd.ifname)); - - if (ioctl(s,SIOCGIFINFO_IN6,&nd)) { - close(s); - return; - } - - unsigned long oldFlags = (unsigned long)nd.ndi.flags; - - if (performNUD) - nd.ndi.flags |= ND6_IFF_PERFORMNUD; - else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; - - if (oldFlags != (unsigned long)nd.ndi.flags) { - if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) { - close(s); - return; - } - } - - memset(&ifr,0,sizeof(ifr)); - strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name)); - if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) { - close(s); - return; - } - - close(s); -} - -static int run(const char *path,...) -{ - va_list ap; - char *args[16]; - int argNo = 1; - - va_start(ap,path); - args[0] = (char *)path; - for(;argNo<15;++argNo) { - args[argNo] = va_arg(ap,char *); - if (!args[argNo]) { - break; - } - } - args[argNo++] = (char *)0; - va_end(ap); - - pid_t pid = vfork(); - if (pid < 0) { - return -1; - } else if (pid == 0) { - dup2(STDERR_FILENO,STDOUT_FILENO); - execv(args[0],args); - _exit(-1); - } - int rv = 0; - waitpid(pid,&rv,0); - return rv; -} - -static void die() -{ - if (s_ndrvfd >= 0) - close(s_ndrvfd); - if (s_bpffd >= 0) - close(s_bpffd); - if (s_deviceName[0]) - run("/sbin/ifconfig",s_deviceName,"destroy",(char *)0); - if (s_peerDeviceName[0]) - run("/sbin/ifconfig",s_peerDeviceName,"destroy",(char *)0); -} - -int main(int argc,char **argv) -{ - char buf[128]; - struct ifreq ifr; - u_int fl; - fd_set rfds,wfds,efds; - struct iovec iov[2]; - - s_deviceName[0] = 0; - s_peerDeviceName[0] = 0; - s_parentPid = getppid(); - - atexit(&die); - signal(SIGIO,SIG_IGN); - signal(SIGCHLD,SIG_IGN); - signal(SIGPIPE,SIG_IGN); - signal(SIGUSR1,SIG_IGN); - signal(SIGUSR2,SIG_IGN); - signal(SIGALRM,SIG_IGN); - signal(SIGQUIT,&exit); - signal(SIGTERM,&exit); - signal(SIGKILL,&exit); - signal(SIGINT,&exit); - signal(SIGPIPE,&exit); - - if (getuid() != 0) { - if (setuid(0) != 0) { - fprintf(stderr,"E must be run as root or with root setuid bit on executable\n"); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST; - } - } - - if (argc < 5) { - fprintf(stderr,"E invalid or missing argument(s) (usage: MacEthernetTapAgent <0-4999> )\n"); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST; - } - const int deviceNo = atoi(argv[1]); - if ((deviceNo < 0)||(deviceNo > 4999)) { - fprintf(stderr,"E invalid or missing argument(s) (usage: MacEthernetTapAgent <0-4999> )\n"); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST; - } - const char *mac = argv[2]; - const char *mtu = argv[3]; - const char *metric = argv[4]; - - s_ndrvfd = socket(AF_NDRV,SOCK_RAW,0); - if (s_ndrvfd < 0) { - fprintf(stderr,"E unable to open AF_NDRV socket\n"); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - - snprintf(s_deviceName,sizeof(s_deviceName),"feth%d",deviceNo); - snprintf(s_peerDeviceName,sizeof(s_peerDeviceName),"feth%d",deviceNo+5000); - if (run(P_IFCONFIG,s_peerDeviceName,"create",(char *)0) != 0) { - fprintf(stderr,"E unable to create %s\n",s_deviceName); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - usleep(10); - if (run(P_IFCONFIG,s_deviceName,"create",(char *)0) != 0) { - fprintf(stderr,"E unable to create %s\n",s_deviceName); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - run(P_IFCONFIG,s_deviceName,"lladdr",mac,(char *)0); - usleep(10); - run(P_IFCONFIG,s_peerDeviceName,"peer",s_deviceName,(char *)0); - usleep(10); - run(P_IFCONFIG,s_peerDeviceName,"mtu","16370","up",(char *)0); /* 16370 is the largest MTU MacOS/Darwin seems to allow */ - usleep(10); - run(P_IFCONFIG,s_deviceName,"mtu",mtu,"metric",metric,"up",(char *)0); - usleep(10); - configureIpv6Parameters(s_deviceName,1,0); - usleep(10); - - struct sockaddr_ndrv nd; - nd.snd_len = sizeof(struct sockaddr_ndrv); - nd.snd_family = AF_NDRV; - memcpy(nd.snd_name,s_peerDeviceName,sizeof(nd.snd_name)); - if (bind(s_ndrvfd,(struct sockaddr *)&nd,sizeof(nd)) != 0) { - fprintf(stderr,"E unable to bind AF_NDRV socket\n"); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - if (connect(s_ndrvfd,(struct sockaddr *)&nd,sizeof(nd)) != 0) { - fprintf(stderr,"E unable to connect AF_NDRV socket\n"); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - - /* Start at /dev/bpf1 since some simple bpf-using net utilities hard-code /dev/bpf0. - * Things like libpcap are smart enough to search. */ - for(int bpfno=1;bpfno<5000;++bpfno) { - char tmp[32]; - snprintf(tmp,sizeof(tmp),"/dev/bpf%d",bpfno); - s_bpffd = open(tmp,O_RDWR); - if (s_bpffd >= 0) { - break; - } - } - if (s_bpffd < 0) { - fprintf(stderr,"E unable to open bpf device\n"); - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - - fl = sizeof(s_pktReadBuf); - if (ioctl(s_bpffd,BIOCSBLEN,&fl) != 0) { - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - const size_t readPktSize = (size_t)fl; - fl = 1; - if (ioctl(s_bpffd,BIOCIMMEDIATE,&fl) != 0) { - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - fl = 0; - if (ioctl(s_bpffd,BIOCSSEESENT,&fl) != 0) { - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - memset(&ifr,0,sizeof(ifr)); - memcpy(ifr.ifr_name,s_peerDeviceName,IFNAMSIZ); - if (ioctl(s_bpffd,BIOCSETIF,&ifr) != 0) { - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - fl = 1; - if (ioctl(s_bpffd,BIOCSHDRCMPLT,&fl) != 0) { - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - fl = 1; - if (ioctl(s_bpffd,BIOCPROMISC,&fl) != 0) { - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE; - } - - fprintf(stderr,"I %s %s %d.%d.%d.%d\n",s_deviceName,s_peerDeviceName,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION,ZEROTIER_ONE_VERSION_BUILD); - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&efds); - long stdinReadPtr = 0; - for(;;) { - FD_SET(STDIN_FILENO,&rfds); - FD_SET(s_bpffd,&rfds); - if (select(s_bpffd+1,&rfds,&wfds,&efds,(struct timeval *)0) < 0) { - if ((errno == EAGAIN)||(errno == EINTR)) { - usleep(10); - continue; - } - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR; - } - - if (FD_ISSET(s_bpffd,&rfds)) { - long n = (long)read(s_bpffd,s_pktReadBuf,readPktSize); - if (n > 0) { - for(unsigned char *p=s_pktReadBuf,*eof=p+n;pbh_caplen > 0)&&((p + h->bh_hdrlen + h->bh_caplen) <= eof)) { - uint16_t len = (uint16_t)h->bh_caplen; - iov[0].iov_base = &len; - iov[0].iov_len = 2; - iov[1].iov_base = p + h->bh_hdrlen; - iov[1].iov_len = h->bh_caplen; - writev(STDOUT_FILENO,iov,2); - } - p += BPF_WORDALIGN(h->bh_hdrlen + h->bh_caplen); - } - } - } - - if (FD_ISSET(STDIN_FILENO,&rfds)) { - long n = (long)read(STDIN_FILENO,s_stdinReadBuf + stdinReadPtr,sizeof(s_stdinReadBuf) - stdinReadPtr); - if (n > 0) { - stdinReadPtr += n; - while (stdinReadPtr >= 2) { - long len = *((uint16_t *)s_stdinReadBuf); - if (stdinReadPtr >= (len + 2)) { - if (len > 0) { - unsigned char *msg = s_stdinReadBuf + 2; - - switch(msg[0]) { - case ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET: - if (len > 1) { - if (write(s_ndrvfd,msg+1,len-1) < 0) { - fprintf(stderr,"E inject failed size==%ld errno==%d\n",len-1,errno); - } - } - break; - - case ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG: { - char *args[16]; - args[0] = P_IFCONFIG; - args[1] = s_deviceName; - int argNo = 2; - for(int argPtr=0,k=1,l=(int)len;k 0) { - argPtr = 0; - ++argNo; - if (argNo >= 15) { - break; - } - } - } else { - if (argPtr == 0) { - args[argNo] = (char *)(msg + k); - } - argPtr++; - } - } - args[argNo] = (char *)0; - if (argNo > 2) { - pid_t pid = fork(); - if (pid < 0) { - return -1; - } else if (pid == 0) { - dup2(STDERR_FILENO,STDOUT_FILENO); - execv(args[0],args); - _exit(-1); - } - int rv = 0; - waitpid(pid,&rv,0); - } - } break; - - case ZT_MACETHERNETTAPAGENT_STDIN_CMD_EXIT: - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS; - - default: - fprintf(stderr,"E unrecognized message type over pipe from host process: %d (length: %d)\n",(int)msg[0],(int)len); - break; - } - } - - if (stdinReadPtr > (len + 2)) { - memmove(s_stdinReadBuf,s_stdinReadBuf + len + 2,stdinReadPtr -= (len + 2)); - } else { - stdinReadPtr = 0; - } - } else { - break; - } - } - } - } - } - - return ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS; -} diff --git a/attic/MacEthernetTapAgent.h b/attic/MacEthernetTapAgent.h deleted file mode 100644 index da6e34195..000000000 --- a/attic/MacEthernetTapAgent.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c)2019 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#ifndef ZT_MACETHERNETTAPAGENT_H -#define ZT_MACETHERNETTAPAGENT_H - -#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_SUCCESS 0 -#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_INVALID_REQUEST -1 -#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_UNABLE_TO_CREATE -2 -#define ZT_MACETHERNETTAPAGENT_EXIT_CODE_READ_ERROR -3 - -#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_PACKET 0 -#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_IFCONFIG 1 -#define ZT_MACETHERNETTAPAGENT_STDIN_CMD_EXIT 2 - -#define ZT_MACETHERNETTAPAGENT_DEFAULT_SYSTEM_PATH "/Library/Application Support/ZeroTier/One/MacEthernetTapAgent" - -#endif diff --git a/attic/MacKextEthernetTap.cpp b/attic/MacKextEthernetTap.cpp deleted file mode 100644 index 208ac00da..000000000 --- a/attic/MacKextEthernetTap.cpp +++ /dev/null @@ -1,690 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// OSX compile fix... in6_var defines this in a struct which namespaces it for C++ ... why?!? -struct prf_ra { - u_char onlink : 1; - u_char autonomous : 1; - u_char reserved : 6; -} prf_ra; - -#include -#include - -// These are KERNEL_PRIVATE... why? -#ifndef SIOCAUTOCONF_START -#define SIOCAUTOCONF_START _IOWR('i', 132, struct in6_ifreq) /* accept rtadvd on this interface */ -#endif -#ifndef SIOCAUTOCONF_STOP -#define SIOCAUTOCONF_STOP _IOWR('i', 133, struct in6_ifreq) /* stop accepting rtadv for this interface */ -#endif - -// -------------------------------------------------------------------------- -// -------------------------------------------------------------------------- -// This source is from: -// http://www.opensource.apple.com/source/Libinfo/Libinfo-406.17/gen.subproj/getifmaddrs.c?txt -// It's here because OSX 10.6 does not have this convenience function. - -#define SALIGN (sizeof(uint32_t) - 1) -#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \ -(SALIGN + 1)) -#define MAX_SYSCTL_TRY 5 -#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA) - -/* FreeBSD uses NET_RT_IFMALIST and RTM_NEWMADDR from */ -/* We can use NET_RT_IFLIST2 and RTM_NEWMADDR2 on Darwin */ -//#define DARWIN_COMPAT - -//#ifdef DARWIN_COMPAT -#define GIM_SYSCTL_MIB NET_RT_IFLIST2 -#define GIM_RTM_ADDR RTM_NEWMADDR2 -//#else -//#define GIM_SYSCTL_MIB NET_RT_IFMALIST -//#define GIM_RTM_ADDR RTM_NEWMADDR -//#endif - -// Not in 10.6 includes so use our own -struct _intl_ifmaddrs { - struct _intl_ifmaddrs *ifma_next; - struct sockaddr *ifma_name; - struct sockaddr *ifma_addr; - struct sockaddr *ifma_lladdr; -}; - -static inline int _intl_getifmaddrs(struct _intl_ifmaddrs **pif) -{ - int icnt = 1; - int dcnt = 0; - int ntry = 0; - size_t len; - size_t needed; - int mib[6]; - int i; - char *buf; - char *data; - char *next; - char *p; - struct ifma_msghdr2 *ifmam; - struct _intl_ifmaddrs *ifa, *ift; - struct rt_msghdr *rtm; - struct sockaddr *sa; - - mib[0] = CTL_NET; - mib[1] = PF_ROUTE; - mib[2] = 0; /* protocol */ - mib[3] = 0; /* wildcard address family */ - mib[4] = GIM_SYSCTL_MIB; - mib[5] = 0; /* no flags */ - do { - if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) - return (-1); - if ((buf = (char *)malloc(needed)) == NULL) - return (-1); - if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { - if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { - free(buf); - return (-1); - } - free(buf); - buf = NULL; - } - } while (buf == NULL); - - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - icnt++; - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - dcnt += len; - p += len; - } - break; - } - } - - data = (char *)malloc(sizeof(struct _intl_ifmaddrs) * icnt + dcnt); - if (data == NULL) { - free(buf); - return (-1); - } - - ifa = (struct _intl_ifmaddrs *)(void *)data; - data += sizeof(struct _intl_ifmaddrs) * icnt; - - memset(ifa, 0, sizeof(struct _intl_ifmaddrs) * icnt); - ift = ifa; - - for (next = buf; next < buf + needed; next += rtm->rtm_msglen) { - rtm = (struct rt_msghdr *)(void *)next; - if (rtm->rtm_version != RTM_VERSION) - continue; - - switch (rtm->rtm_type) { - case GIM_RTM_ADDR: - ifmam = (struct ifma_msghdr2 *)(void *)rtm; - if ((ifmam->ifmam_addrs & RTA_IFA) == 0) - break; - - p = (char *)(ifmam + 1); - for (i = 0; i < RTAX_MAX; i++) { - if ((RTA_MASKS & ifmam->ifmam_addrs & - (1 << i)) == 0) - continue; - sa = (struct sockaddr *)(void *)p; - len = SA_RLEN(sa); - switch (i) { - case RTAX_GATEWAY: - ift->ifma_lladdr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - case RTAX_IFP: - ift->ifma_name = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - case RTAX_IFA: - ift->ifma_addr = - (struct sockaddr *)(void *)data; - memcpy(data, p, len); - data += len; - break; - - default: - data += len; - break; - } - p += len; - } - ift->ifma_next = ift + 1; - ift = ift->ifma_next; - break; - } - } - - free(buf); - - if (ift > ifa) { - ift--; - ift->ifma_next = NULL; - *pif = ifa; - } else { - *pif = NULL; - free(ifa); - } - return (0); -} - -static inline void _intl_freeifmaddrs(struct _intl_ifmaddrs *ifmp) -{ - free(ifmp); -} - -// -------------------------------------------------------------------------- -// -------------------------------------------------------------------------- - -#include -#include -#include -#include - -#include "../core/Constants.hpp" -#include "../core/Utils.hpp" -#include "../core/Mutex.hpp" -#include "../core/Dictionary.hpp" -#include "OSUtils.hpp" -#include "MacKextEthernetTap.hpp" - -// ff:ff:ff:ff:ff:ff with no ADI -static const ZeroTier::MulticastGroup _blindWildcardMulticastGroup(ZeroTier::MAC(0xff),0); - -static inline bool _setIpv6Stuff(const char *ifname,bool performNUD,bool acceptRouterAdverts) -{ - struct in6_ndireq nd; - struct in6_ifreq ifr; - - int s = socket(AF_INET6,SOCK_DGRAM,0); - if (s <= 0) - return false; - - memset(&nd,0,sizeof(nd)); - strncpy(nd.ifname,ifname,sizeof(nd.ifname)); - - if (ioctl(s,SIOCGIFINFO_IN6,&nd)) { - close(s); - return false; - } - - unsigned long oldFlags = (unsigned long)nd.ndi.flags; - - if (performNUD) - nd.ndi.flags |= ND6_IFF_PERFORMNUD; - else nd.ndi.flags &= ~ND6_IFF_PERFORMNUD; - - if (oldFlags != (unsigned long)nd.ndi.flags) { - if (ioctl(s,SIOCSIFINFO_FLAGS,&nd)) { - close(s); - return false; - } - } - - memset(&ifr,0,sizeof(ifr)); - strncpy(ifr.ifr_name,ifname,sizeof(ifr.ifr_name)); - if (ioctl(s,acceptRouterAdverts ? SIOCAUTOCONF_START : SIOCAUTOCONF_STOP,&ifr)) { - close(s); - return false; - } - - close(s); - return true; -} - -namespace ZeroTier { - -static long globalTapsRunning = 0; -static Mutex globalTapCreateLock; - -MacKextEthernetTap::MacKextEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *data,unsigned int len), - void *arg) : - _handler(handler), - _arg(arg), - _nwid(nwid), - _homePath(homePath), - _mtu(mtu), - _metric(metric), - _fd(0), - _enabled(true) -{ - char devpath[64],ethaddr[64],mtustr[32],metstr[32],nwids[32]; - struct stat stattmp; - - OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",nwid); - - Mutex::Lock _gl(globalTapCreateLock); - - if (::stat("/dev/zt0",&stattmp)) { - long kextpid = (long)vfork(); - if (kextpid == 0) { - ::chdir(homePath); - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - ::execl("/sbin/kextload","/sbin/kextload","-q","-repository",homePath,"tap.kext",(const char *)0); - ::_exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - ::waitpid(kextpid,&exitcode,0); - } - ::usleep(500); // give tap device driver time to start up and try again - if (::stat("/dev/zt0",&stattmp)) - throw std::runtime_error("/dev/zt# tap devices do not exist and cannot load tap.kext"); - } - - // Try to reopen the last device we had, if we had one and it's still unused. - std::map globalDeviceMap; - FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r"); - if (devmapf) { - char buf[256]; - while (fgets(buf,sizeof(buf),devmapf)) { - char *x = (char *)0; - char *y = (char *)0; - char *saveptr = (char *)0; - for(char *f=Utils::stok(buf,"\r\n=",&saveptr);(f);f=Utils::stok((char *)0,"\r\n=",&saveptr)) { - if (!x) x = f; - else if (!y) y = f; - else break; - } - if ((x)&&(y)&&(x[0])&&(y[0])) - globalDeviceMap[x] = y; - } - fclose(devmapf); - } - bool recalledDevice = false; - std::map::const_iterator gdmEntry = globalDeviceMap.find(nwids); - if (gdmEntry != globalDeviceMap.end()) { - std::string devpath("/dev/"); devpath.append(gdmEntry->second); - if (stat(devpath.c_str(),&stattmp) == 0) { - _fd = ::open(devpath.c_str(),O_RDWR); - if (_fd > 0) { - _dev = gdmEntry->second; - recalledDevice = true; - } - } - } - - // Open the first unused tap device if we didn't recall a previous one. - if (!recalledDevice) { - for(int i=0;i<64;++i) { - OSUtils::ztsnprintf(devpath,sizeof(devpath),"/dev/zt%d",i); - if (stat(devpath,&stattmp)) - throw std::runtime_error("no more TAP devices available"); - _fd = ::open(devpath,O_RDWR); - if (_fd > 0) { - char foo[16]; - OSUtils::ztsnprintf(foo,sizeof(foo),"zt%d",i); - _dev = foo; - break; - } - } - } - - if (_fd <= 0) - throw std::runtime_error("unable to open TAP device or no more devices available"); - - if (fcntl(_fd,F_SETFL,fcntl(_fd,F_GETFL) & ~O_NONBLOCK) == -1) { - ::close(_fd); - throw std::runtime_error("unable to set flags on file descriptor for TAP device"); - } - - // Configure MAC address and MTU, bring interface up - OSUtils::ztsnprintf(ethaddr,sizeof(ethaddr),"%.2x:%.2x:%.2x:%.2x:%.2x:%.2x",(int)mac[0],(int)mac[1],(int)mac[2],(int)mac[3],(int)mac[4],(int)mac[5]); - OSUtils::ztsnprintf(mtustr,sizeof(mtustr),"%u",_mtu); - OSUtils::ztsnprintf(metstr,sizeof(metstr),"%u",_metric); - long cpid = (long)vfork(); - if (cpid == 0) { - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"lladdr",ethaddr,"mtu",mtustr,"metric",metstr,"up",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - if (exitcode) { - ::close(_fd); - throw std::runtime_error("ifconfig failure setting link-layer address and activating tap interface"); - } - } - - _setIpv6Stuff(_dev.c_str(),true,false); - - // Set close-on-exec so that devices cannot persist if we fork/exec for update - fcntl(_fd,F_SETFD,fcntl(_fd,F_GETFD) | FD_CLOEXEC); - - ::pipe(_shutdownSignalPipe); - - ++globalTapsRunning; - - globalDeviceMap[nwids] = _dev; - devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"w"); - if (devmapf) { - gdmEntry = globalDeviceMap.begin(); - while (gdmEntry != globalDeviceMap.end()) { - fprintf(devmapf,"%s=%s\n",gdmEntry->first.c_str(),gdmEntry->second.c_str()); - ++gdmEntry; - } - fclose(devmapf); - } - - _thread = Thread::start(this); -} - -MacKextEthernetTap::~MacKextEthernetTap() -{ - ::write(_shutdownSignalPipe[1],"\0",1); // causes thread to exit - Thread::join(_thread); - - ::close(_fd); - ::close(_shutdownSignalPipe[0]); - ::close(_shutdownSignalPipe[1]); - - { - Mutex::Lock _gl(globalTapCreateLock); - if (--globalTapsRunning <= 0) { - globalTapsRunning = 0; // sanity check -- should not be possible - - char tmp[16384]; - sprintf(tmp,"%s/%s",_homePath.c_str(),"tap.kext"); - long kextpid = (long)vfork(); - if (kextpid == 0) { - OSUtils::redirectUnixOutputs("/dev/null",(const char *)0); - ::execl("/sbin/kextunload","/sbin/kextunload",tmp,(const char *)0); - ::_exit(-1); - } else if (kextpid > 0) { - int exitcode = -1; - ::waitpid(kextpid,&exitcode,0); - } - } - } -} - -void MacKextEthernetTap::setEnabled(bool en) -{ - _enabled = en; - // TODO: interface status change -} - -bool MacKextEthernetTap::enabled() const -{ - return _enabled; -} - -bool MacKextEthernetTap::addIp(const InetAddress &ip) -{ - if (!ip) - return false; - - long cpid = (long)vfork(); - if (cpid == 0) { - char tmp[128]; - ::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.family() == AF_INET6) ? "inet6" : "inet",ip.toString(tmp),"alias",(const char *)0); - ::_exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - ::waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } // else return false... - - return false; -} - -bool MacKextEthernetTap::removeIp(const InetAddress &ip) -{ - if (!ip) - return true; - std::vector allIps(ips()); - for(std::vector::iterator i(allIps.begin());i!=allIps.end();++i) { - if (*i == ip) { - long cpid = (long)vfork(); - if (cpid == 0) { - char tmp[128]; - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.family() == AF_INET6) ? "inet6" : "inet",ip.toIpString(tmp),"-alias",(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - return (exitcode == 0); - } - } - } - return false; -} - -std::vector MacKextEthernetTap::ips() const -{ - struct ifaddrs *ifa = (struct ifaddrs *)0; - if (getifaddrs(&ifa)) - return std::vector(); - - std::vector r; - - struct ifaddrs *p = ifa; - while (p) { - if ((!strcmp(p->ifa_name,_dev.c_str()))&&(p->ifa_addr)&&(p->ifa_netmask)&&(p->ifa_addr->sa_family == p->ifa_netmask->sa_family)) { - switch(p->ifa_addr->sa_family) { - case AF_INET: { - struct sockaddr_in *sin = (struct sockaddr_in *)p->ifa_addr; - struct sockaddr_in *nm = (struct sockaddr_in *)p->ifa_netmask; - r.push_back(InetAddress(&(sin->sin_addr.s_addr),4,Utils::countBits((uint32_t)nm->sin_addr.s_addr))); - } break; - case AF_INET6: { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)p->ifa_addr; - struct sockaddr_in6 *nm = (struct sockaddr_in6 *)p->ifa_netmask; - uint32_t b[4]; - memcpy(b,nm->sin6_addr.s6_addr,sizeof(b)); - r.push_back(InetAddress(sin->sin6_addr.s6_addr,16,Utils::countBits(b[0]) + Utils::countBits(b[1]) + Utils::countBits(b[2]) + Utils::countBits(b[3]))); - } break; - } - } - p = p->ifa_next; - } - - if (ifa) - freeifaddrs(ifa); - - std::sort(r.begin(),r.end()); - r.erase(std::unique(r.begin(),r.end()),r.end()); - - return r; -} - -void MacKextEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) -{ - char putBuf[ZT_MAX_MTU + 64]; - if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { - to.copyTo((uint8_t *)putBuf); - from.copyTo((uint8_t *)(putBuf + 6)); - *((uint16_t *)(putBuf + 12)) = htons((uint16_t)etherType); - memcpy(putBuf + 14,data,len); - len += 14; - ::write(_fd,putBuf,len); - } -} - -std::string MacKextEthernetTap::deviceName() const -{ - return _dev; -} - -void MacKextEthernetTap::setFriendlyName(const char *friendlyName) -{ -} - -void MacKextEthernetTap::scanMulticastGroups(std::vector &added,std::vector &removed) -{ - std::vector newGroups; - - struct _intl_ifmaddrs *ifmap = (struct _intl_ifmaddrs *)0; - if (!_intl_getifmaddrs(&ifmap)) { - struct _intl_ifmaddrs *p = ifmap; - while (p) { - if (p->ifma_addr->sa_family == AF_LINK) { - struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; - struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; - if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) - newGroups.push_back(MulticastGroup(MAC((uint8_t *)(la->sdl_data + la->sdl_nlen)),0)); - } - p = p->ifma_next; - } - _intl_freeifmaddrs(ifmap); - } - - std::vector allIps(ips()); - for(std::vector::iterator ip(allIps.begin());ip!=allIps.end();++ip) - newGroups.push_back(MulticastGroup::deriveMulticastGroupForAddressResolution(*ip)); - - std::sort(newGroups.begin(),newGroups.end()); - std::unique(newGroups.begin(),newGroups.end()); - - for(std::vector::iterator m(newGroups.begin());m!=newGroups.end();++m) { - if (!std::binary_search(_multicastGroups.begin(),_multicastGroups.end(),*m)) - added.push_back(*m); - } - for(std::vector::iterator m(_multicastGroups.begin());m!=_multicastGroups.end();++m) { - if (!std::binary_search(newGroups.begin(),newGroups.end(),*m)) - removed.push_back(*m); - } - - _multicastGroups.swap(newGroups); -} - -void MacKextEthernetTap::setMtu(unsigned int mtu) -{ - if (mtu != _mtu) { - _mtu = mtu; - long cpid = (long)vfork(); - if (cpid == 0) { - char tmp[64]; - OSUtils::ztsnprintf(tmp,sizeof(tmp),"%u",mtu); - execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0); - _exit(-1); - } else if (cpid > 0) { - int exitcode = -1; - waitpid(cpid,&exitcode,0); - } - } -} - -void MacKextEthernetTap::threadMain() - throw() -{ - fd_set readfds,nullfds; - MAC to,from; - int n,nfds,r; - char getBuf[ZT_MAX_MTU + 64]; - - Thread::sleep(500); - - FD_ZERO(&readfds); - FD_ZERO(&nullfds); - nfds = (int)std::max(_shutdownSignalPipe[0],_fd) + 1; - - r = 0; - for(;;) { - FD_SET(_shutdownSignalPipe[0],&readfds); - FD_SET(_fd,&readfds); - select(nfds,&readfds,&nullfds,&nullfds,(struct timeval *)0); - - if (FD_ISSET(_shutdownSignalPipe[0],&readfds)) // writes to shutdown pipe terminate thread - break; - - if (FD_ISSET(_fd,&readfds)) { - n = (int)::read(_fd,getBuf + r,sizeof(getBuf) - r); - if (n < 0) { - if ((errno != EINTR)&&(errno != ETIMEDOUT)) - break; - } else { - // Some tap drivers like to send the ethernet frame and the - // payload in two chunks, so handle that by accumulating - // data until we have at least a frame. - r += n; - if (r > 14) { - if (r > ((int)_mtu + 14)) // sanity check for weird TAP behavior on some platforms - r = _mtu + 14; - - if (_enabled) { - to.setTo((uint8_t *)getBuf); - from.setTo((uint8_t *)(getBuf + 6)); - unsigned int etherType = ntohs(((const uint16_t *)getBuf)[6]); - // TODO: VLAN support - _handler(_arg,(void *)0,_nwid,from,to,etherType,0,(const void *)(getBuf + 14),r - 14); - } - - r = 0; - } - } - } - } -} - -} // namespace ZeroTier diff --git a/attic/MacKextEthernetTap.hpp b/attic/MacKextEthernetTap.hpp deleted file mode 100644 index 7434cc6c3..000000000 --- a/attic/MacKextEthernetTap.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#ifndef ZT_MacKextEthernetTap_HPP -#define ZT_MacKextEthernetTap_HPP - -#include -#include - -#include -#include -#include - -#include "../core/Constants.hpp" -#include "../core/MAC.hpp" -#include "../core/InetAddress.hpp" -#include "../core/MulticastGroup.hpp" - -#include "Thread.hpp" -#include "EthernetTap.hpp" - -namespace ZeroTier { - -class MacKextEthernetTap : public EthernetTap -{ -public: - MacKextEthernetTap( - const char *homePath, - const MAC &mac, - unsigned int mtu, - unsigned int metric, - uint64_t nwid, - const char *friendlyName, - void (*handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int), - void *arg); - - virtual ~MacKextEthernetTap(); - - virtual void setEnabled(bool en); - virtual bool enabled() const; - virtual bool addIp(const InetAddress &ip); - virtual bool removeIp(const InetAddress &ip); - virtual std::vector ips() const; - virtual void put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len); - virtual std::string deviceName() const; - virtual void setFriendlyName(const char *friendlyName); - virtual void scanMulticastGroups(std::vector &added,std::vector &removed); - virtual void setMtu(unsigned int mtu); - - void threadMain() - throw(); - -private: - void (*_handler)(void *,void *,uint64_t,const MAC &,const MAC &,unsigned int,unsigned int,const void *,unsigned int); - void *_arg; - uint64_t _nwid; - Thread _thread; - std::string _homePath; - std::string _dev; - std::vector _multicastGroups; - unsigned int _mtu; - unsigned int _metric; - int _fd; - int _shutdownSignalPipe[2]; - volatile bool _enabled; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/NeighborDiscovery.cpp b/attic/NeighborDiscovery.cpp deleted file mode 100644 index 45452ea15..000000000 --- a/attic/NeighborDiscovery.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#include "../core/Constants.hpp" -#include "NeighborDiscovery.hpp" -#include "OSUtils.hpp" - -#include -#include - -namespace ZeroTier { - -uint16_t calc_checksum(uint16_t *addr, int len) -{ - int count = len; - uint32_t sum = 0; - uint16_t answer = 0; - - // Sum up 2-byte values until none or only one byte left. - while (count > 1) { - sum += *(addr++); - count -= 2; - } - - // Add left-over byte, if any. - if (count > 0) { - sum += *(uint8_t *)addr; - } - - // Fold 32-bit sum into 16 bits; we lose information by doing this, - // increasing the chances of a collision. - // sum = (lower 16 bits) + (upper 16 bits shifted right 16 bits) - while (sum >> 16) { - sum = (sum & 0xffff) + (sum >> 16); - } - - // Checksum is one's compliment of sum. - answer = ~sum; - - return (answer); -} - -struct _pseudo_header -{ - uint8_t sourceAddr[16]; - uint8_t targetAddr[16]; - uint32_t length; - uint8_t zeros[3]; - uint8_t next; // 58 -}; - -struct _option -{ - _option(int optionType) - : type(optionType), length(8) - { - memset(mac, 0, sizeof(mac)); - } - - uint8_t type; - uint8_t length; - uint8_t mac[6]; -}; - -struct _neighbor_solicitation -{ - _neighbor_solicitation() - : type(135), code(0), checksum(0), option(1) - { - memset(&reserved, 0, sizeof(reserved)); - memset(target, 0, sizeof(target)); - } - - void calculateChecksum(const sockaddr_storage &sourceIp, const sockaddr_storage &destIp) - { - _pseudo_header ph; - memset(&ph, 0, sizeof(_pseudo_header)); - const sockaddr_in6 *src = (const sockaddr_in6 *)&sourceIp; - const sockaddr_in6 *dest = (const sockaddr_in6 *)&destIp; - - memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr)); - memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr)); - ph.next = 58; - ph.length = htonl(sizeof(_neighbor_solicitation)); - - size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_solicitation); - uint8_t *tmp = (uint8_t *)malloc(len); - memcpy(tmp, &ph, sizeof(_pseudo_header)); - memcpy(tmp + sizeof(_pseudo_header), this, sizeof(_neighbor_solicitation)); - - checksum = calc_checksum((uint16_t *)tmp, (int)len); - - free(tmp); - tmp = NULL; - } - - uint8_t type; // 135 - uint8_t code; // 0 - uint16_t checksum; - uint32_t reserved; - uint8_t target[16]; - _option option; -}; - -struct _neighbor_advertisement -{ - _neighbor_advertisement() - : type(136), code(0), checksum(0), rso(0x40), option(2) - { - memset(padding, 0, sizeof(padding)); - memset(target, 0, sizeof(target)); - } - - void calculateChecksum(const sockaddr_storage &sourceIp, const InetAddress &destIp) - { - _pseudo_header ph; - memset(&ph, 0, sizeof(_pseudo_header)); - const sockaddr_in6 *src = (const sockaddr_in6 *)&sourceIp; - const sockaddr_in6 *dest = (const sockaddr_in6 *)&destIp; - - memcpy(ph.sourceAddr, &src->sin6_addr, sizeof(struct in6_addr)); - memcpy(ph.targetAddr, &dest->sin6_addr, sizeof(struct in6_addr)); - ph.next = 58; - ph.length = htonl(sizeof(_neighbor_advertisement)); - - size_t len = sizeof(_pseudo_header) + sizeof(_neighbor_advertisement); - uint8_t *tmp = (uint8_t *)malloc(len); - memcpy(tmp, &ph, sizeof(_pseudo_header)); - memcpy(tmp + sizeof(_pseudo_header), this, sizeof(_neighbor_advertisement)); - - checksum = calc_checksum((uint16_t *)tmp, (int)len); - - free(tmp); - tmp = NULL; - } - - uint8_t type; // 136 - uint8_t code; // 0 - uint16_t checksum; - uint8_t rso; - uint8_t padding[3]; - uint8_t target[16]; - _option option; -}; - -NeighborDiscovery::NeighborDiscovery() - : _cache(), _lastCleaned(OSUtils::now()) -{} - -void NeighborDiscovery::addLocal(const sockaddr_storage &address, const MAC &mac) -{ - _NDEntry &e = _cache[InetAddress(address)]; - e.lastQuerySent = 0; - e.lastResponseReceived = 0; - e.mac = mac; - e.local = true; -} - -void NeighborDiscovery::remove(const sockaddr_storage &address) -{ - _cache.erase(InetAddress(address)); -} - -sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest) -{ - // assert(sizeof(_neighbor_solicitation) == 28); - // assert(sizeof(_neighbor_advertisement) == 32); - - const uint64_t now = OSUtils::now(); - InetAddress ip; - - if (len >= sizeof(_neighbor_solicitation) && nd[0] == 0x87) { - // respond to Neighbor Solicitation request for local address - _neighbor_solicitation solicitation; - memcpy(&solicitation, nd, len); - InetAddress targetAddress(solicitation.target, 16, 0); - Map::const_iterator targetEntry(_cache.find(targetAddress)); - if ((targetEntry != _cache.end()) && targetEntry->second.local) { - _neighbor_advertisement adv; - targetEntry->second.mac.copyTo(adv.option.mac); - memcpy(adv.target, solicitation.target, 16); - adv.calculateChecksum(localIp, targetAddress); - memcpy(response, &adv, sizeof(_neighbor_advertisement)); - responseLen = sizeof(_neighbor_advertisement); - responseDest.setTo(solicitation.option.mac); - } - } else if (len >= sizeof(_neighbor_advertisement) && nd[0] == 0x88) { - _neighbor_advertisement adv; - memcpy(&adv, nd, len); - InetAddress responseAddress(adv.target, 16, 0); - Map::iterator queryEntry(_cache.find(responseAddress)); - if ((queryEntry != _cache.end()) && !queryEntry->second.local && (now - queryEntry->second.lastQuerySent <= ZT_ND_QUERY_MAX_TTL)) { - queryEntry->second.lastResponseReceived = now; - queryEntry->second.mac.setTo(adv.option.mac); - ip = responseAddress; - } - } - - if ((now - _lastCleaned) >= ZT_ND_EXPIRE) { - _lastCleaned = now; - for (Map< InetAddress, _NDEntry >::iterator i(_cache.begin()); i != _cache.end();) { - if (!i->second.local && (now - i->second.lastResponseReceived) >= ZT_ND_EXPIRE) { - _cache.erase(i++); - } else { - ++i; - } - } - } - - return *reinterpret_cast(&ip); -} - -MAC NeighborDiscovery::query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest) -{ - const uint64_t now = OSUtils::now(); - - InetAddress localAddress(localIp); - localAddress.setPort(0); - InetAddress targetAddress(targetIp); - targetAddress.setPort(0); - - _NDEntry &e = _cache[targetAddress]; - - if ((e.mac && ((now - e.lastResponseReceived) >= (ZT_ND_EXPIRE / 3))) || - (!e.mac && ((now - e.lastQuerySent) >= ZT_ND_QUERY_INTERVAL))) { - e.lastQuerySent = now; - - _neighbor_solicitation ns; - memcpy(ns.target, targetAddress.rawIpData(), 16); - localMac.copyTo(ns.option.mac); - ns.calculateChecksum(localIp, targetIp); - if (e.mac) { - queryDest = e.mac; - } else { - queryDest = (uint64_t)0xffffffffffffULL; - } - } else { - queryLen = 0; - queryDest.zero(); - } - - return e.mac; -} - -} diff --git a/attic/NeighborDiscovery.hpp b/attic/NeighborDiscovery.hpp deleted file mode 100644 index 423710b8f..000000000 --- a/attic/NeighborDiscovery.hpp +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#ifndef ZT_NEIGHBORDISCOVERY_HPP -#define ZT_NEIGHBORDISCOVERY_HPP - -#include "../core/Containers.hpp" -#include "../core/MAC.hpp" -#include "../core/InetAddress.hpp" - -#define ZT_ND_QUERY_INTERVAL 2000 -#define ZT_ND_QUERY_MAX_TTL 5000 -#define ZT_ND_EXPIRE 600000 - -namespace ZeroTier { - -class NeighborDiscovery -{ -public: - NeighborDiscovery(); - - /** - * Set a local IP entry that we should respond to Neighbor Requests withPrefix64k - * - * @param mac Our local MAC address - * @param ip Our IPv6 address - */ - void addLocal(const sockaddr_storage &address, const MAC &mac); - - /** - * Delete a local IP entry or cached Neighbor entry - * - * @param address IPv6 address to remove - */ - void remove(const sockaddr_storage &address); - - sockaddr_storage processIncomingND(const uint8_t *nd, unsigned int len, const sockaddr_storage &localIp, uint8_t *response, unsigned int &responseLen, MAC &responseDest); - - MAC query(const MAC &localMac, const sockaddr_storage &localIp, const sockaddr_storage &targetIp, uint8_t *query, unsigned int &queryLen, MAC &queryDest); - -private: - struct _NDEntry - { - _NDEntry() : lastQuerySent(0), lastResponseReceived(0), mac(), local(false) - {} - - uint64_t lastQuerySent; - uint64_t lastResponseReceived; - MAC mac; - bool local; - }; - - Map< InetAddress, _NDEntry > _cache; - uint64_t _lastCleaned; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/OFFICIAL-RELEASE-STEPS.md b/attic/OFFICIAL-RELEASE-STEPS.md deleted file mode 100644 index 6de3526cf..000000000 --- a/attic/OFFICIAL-RELEASE-STEPS.md +++ /dev/null @@ -1,33 +0,0 @@ -ZeroTier Official Release Steps -====== - -This is mostly for ZeroTier internal use, but others who want to do builds might find it helpful. - -Note: Many of these steps will require GPG and other signing keys that are kept in cold storage and must be mounted. - -# Bumping the Version and Preparing Installers - -The version must be incremented in all of the following files: - - /version.h - /zerotier-one.spec - /debian/changelog - /ext/installfiles/mac/ZeroTier One.pkgproj - /ext/installfiles/windows/ZeroTier One.aip - /windows/WinUI/AboutView.xaml - -The final .AIP file can only be edited on Windows with [Advanced Installer Enterprise](http://www.advancedinstaller.com/). In addition to incrementing the version be sure that a new product code is generated. (The "upgrade code" GUID on the other hand must never change.) - -# Building for Supported Platforms - -## Macintosh - -Mac's easy. Just type: - - make official - -You will need [Packages](http://s.sudre.free.fr/Software/Packages/about.html) and our release signing key in the keychain. - -## Windows - -First load the Visual Studio solution and rebuild the UI and ZeroTier One in both x64 and i386 `Release` mode. Then load [Advanced Installer Enterprise](http://www.advancedinstaller.com/), check that the version is correct, and build. The build will fail if any build artifacts are missing, and Windows must have our product singing key (from DigiCert) available to sign the resulting MSI file. The MSI must then be tested on at least a few different CLEAN Windows VMs to ensure that the installer is valid and properly signed. diff --git a/attic/PeerList.hpp b/attic/PeerList.hpp deleted file mode 100644 index 7bf539ae2..000000000 --- a/attic/PeerList.hpp +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#ifndef ZT_PEERLIST_HPP -#define ZT_PEERLIST_HPP - -#include "Constants.hpp" -#include "SharedPtr.hpp" -#include "Peer.hpp" - -namespace ZeroTier { - -/** - * A list of peers - * - * This is a simple vector optimized for the case where there will almost always - * be zero or one element. In that case it doesn't allocate. If there's more than - * one element, it will grow to include all elements. - * - * It's used to return lookups in Topology where there will almost always be zero - * or one peers returned but where there technically (but very rarely) can be more. - */ -class PeerList -{ -public: - ZT_INLINE PeerList() noexcept: - m_onePeer(), - m_peers(&m_onePeer), - m_peerCount(0) - {} - - ZT_INLINE PeerList(const PeerList &pl) - { - const unsigned int pc = pl.m_peerCount; - if (likely(pc <= 1)) { - m_onePeer = pl.m_onePeer; - m_peers = &m_onePeer; - } else { - m_peers = new SharedPtr[pc]; - for (unsigned int i = 0;i < pc;++i) - m_peers[i] = pl.m_peers[i]; - } - m_peerCount = pc; - } - - ZT_INLINE ~PeerList() - { - if (unlikely(m_peers != &m_onePeer)) - delete[] m_peers; - } - - ZT_INLINE PeerList &operator=(const PeerList &pl) - { - if (&pl != this) { - if (unlikely(m_peers != &m_onePeer)) - delete[] m_peers; - if (likely(pl.m_peerCount <= 1)) { - m_onePeer = pl.m_onePeer; - m_peers = &m_onePeer; - } else { - m_onePeer.zero(); - m_peers = new SharedPtr[pl.m_peerCount]; - for (unsigned int i = 0;i < pl.m_peerCount;++i) - m_peers[i] = pl.m_peers[i]; - } - m_peerCount = pl.m_peerCount; - } - return *this; - } - - /** - * Resize the peer list to store a given number of members - * - * To populate the list, this must be called first followed by each member - * being set with the [] operator. List content after this call is undefined - * and may contain old data if the object is being re-used. - * - * @param s New size of list - */ - ZT_INLINE void resize(const unsigned int s) - { - if (unlikely(m_peers != &m_onePeer)) - delete[] m_peers; - m_peerCount = s; - if (likely(s <= 1)) { - m_peers = &m_onePeer; - } else { - m_peers = new SharedPtr[s]; - } - } - - ZT_INLINE SharedPtr &operator[](const unsigned int i) noexcept - { return m_peers[i]; } - - ZT_INLINE const SharedPtr &operator[](const unsigned int i) const noexcept - { return m_peers[i]; } - - ZT_INLINE unsigned int size() const noexcept - { return m_peerCount; } - -private: - SharedPtr m_onePeer; - SharedPtr *m_peers; - unsigned int m_peerCount; -}; - -} // namespace ZeroTier - -#endif diff --git a/attic/central-controller-docker/Dockerfile b/attic/central-controller-docker/Dockerfile deleted file mode 100644 index 716390f82..000000000 --- a/attic/central-controller-docker/Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -# Dockerfile for ZeroTier Central Controllers -FROM centos:7 as builder -MAINTAINER Adam Ierymekno , Grant Limberg - -ARG git_branch=master - -RUN yum update -y -RUN yum install -y https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm -RUN yum -y install epel-release && yum -y update && yum clean all -RUN yum groupinstall -y "Development Tools" -RUN yum install -y bash postgresql10 postgresql10-devel libpqxx-devel glibc-static libstdc++-static clang jemalloc jemalloc-devel - -RUN git clone http://git.int.zerotier.com/zerotier/ZeroTierOne.git -RUN if [ "$git_branch" != "master" ]; then cd ZeroTierOne && git checkout -b $git_branch origin/$git_branch; fi -RUN ldconfig -RUN cd ZeroTierOne && make central-controller - -FROM centos:7 - -COPY --from=builder /ZeroTierOne/zerotier-one /usr/local/bin/zerotier-one -RUN chmod a+x /usr/local/bin/zerotier-one - -ADD ext/central-controller-docker/main.sh / -RUN chmod a+x /main.sh - -ENTRYPOINT /main.sh diff --git a/attic/central-controller-docker/README.md b/attic/central-controller-docker/README.md deleted file mode 100644 index a954b1c37..000000000 --- a/attic/central-controller-docker/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# ZeroTier Central Controller Docker Image - -Dockerfile & startup script for use with [ZeroTier Central](https://my.zerotier.com). Not intended for public use. diff --git a/attic/central-controller-docker/main.sh b/attic/central-controller-docker/main.sh deleted file mode 100755 index b8d3b142c..000000000 --- a/attic/central-controller-docker/main.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash - -if [ -z "$ZT_IDENTITY_PATH" ]; then - echo '*** FAILED: ZT_IDENTITY_PATH environment variable is not defined' - exit 1 -fi -if [ -z "$ZT_DB_HOST" ]; then - echo '*** FAILED: ZT_DB_HOST environment variable not defined' - exit 1 -fi -if [ -z "$ZT_DB_PORT" ]; then - echo '*** FAILED: ZT_DB_PORT environment variable not defined' - exit 1 -fi -if [ -z "$ZT_DB_NAME" ]; then - echo '*** FAILED: ZT_DB_NAME environment variable not defined' - exit 1 -fi -if [ -z "$ZT_DB_USER" ]; then - echo '*** FAILED: ZT_DB_USER environment variable not defined' - exit 1 -fi -if [ -z "$ZT_DB_PASSWORD" ]; then - echo '*** FAILED: ZT_DB_PASSWORD environment variable not defined' - exit 1 -fi - -RMQ="" -if [ "$ZT_USE_RABBITMQ" == "true" ]; then - if [ -z "$RABBITMQ_HOST" ]; then - echo '*** FAILED: RABBITMQ_HOST environment variable not defined' - exit 1 - fi - if [ -z "$RABBITMQ_PORT" ]; then - echo '*** FAILED: RABBITMQ_PORT environment variable not defined' - exit 1 - fi - if [ -z "$RABBITMQ_USERNAME" ]; then - echo '*** FAILED: RABBITMQ_USERNAME environment variable not defined' - exit 1 - fi - if [ -z "$RABBITMQ_PASSWORD" ]; then - echo '*** FAILED: RABBITMQ_PASSWORD environment variable not defined' - exit 1 - fi - RMQ=", \"rabbitmq\": { - \"host\": \"${RABBITMQ_HOST}\", - \"port\": ${RABBITMQ_PORT}, - \"username\": \"${RABBITMQ_USERNAME}\", - \"password\": \"${RABBITMQ_PASSWORD}\" - }" -fi - -mkdir -p /var/lib/zerotier-one - -pushd /var/lib/zerotier-one -ln -s $ZT_IDENTITY_PATH/identity.public identity.public -ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret -popd - -DEFAULT_PORT=9993 - -echo "{ - \"settings\": { - \"portMappingEnabled\": true, - \"softwareUpdate\": \"disable\", - \"interfacePrefixBlacklist\": [ - \"inot\", - \"nat64\" - ], - \"controllerDbPath\": \"postgres:host=${ZT_DB_HOST} port=${ZT_DB_PORT} dbname=${ZT_DB_NAME} user=${ZT_DB_USER} password=${ZT_DB_PASSWORD} sslmode=prefer sslcert=${DB_CLIENT_CERT} sslkey=${DB_CLIENT_KEY} sslrootcert=${DB_SERVER_CA}\" - ${RMQ} - } -} -" > /var/lib/zerotier-one/local.conf - -export GLIBCXX_FORCE_NEW=1 -export GLIBCPP_FORCE_NEW=1 -export LD_PRELOAD="/usr/lib64/libjemalloc.so" -exec /usr/local/bin/zerotier-one -p${ZT_CONTROLLER_PORT:-$DEFAULT_PORT} /var/lib/zerotier-one diff --git a/core/AES.cpp b/attic/core/AES.cpp similarity index 100% rename from core/AES.cpp rename to attic/core/AES.cpp diff --git a/core/AES.hpp b/attic/core/AES.hpp similarity index 100% rename from core/AES.hpp rename to attic/core/AES.hpp diff --git a/core/AES_aesni.cpp b/attic/core/AES_aesni.cpp similarity index 100% rename from core/AES_aesni.cpp rename to attic/core/AES_aesni.cpp diff --git a/core/AES_armcrypto.cpp b/attic/core/AES_armcrypto.cpp similarity index 100% rename from core/AES_armcrypto.cpp rename to attic/core/AES_armcrypto.cpp diff --git a/core/Address.hpp b/attic/core/Address.hpp similarity index 100% rename from core/Address.hpp rename to attic/core/Address.hpp diff --git a/core/Buf.cpp b/attic/core/Buf.cpp similarity index 100% rename from core/Buf.cpp rename to attic/core/Buf.cpp diff --git a/core/Buf.hpp b/attic/core/Buf.hpp similarity index 100% rename from core/Buf.hpp rename to attic/core/Buf.hpp diff --git a/core/C25519.cpp b/attic/core/C25519.cpp similarity index 100% rename from core/C25519.cpp rename to attic/core/C25519.cpp diff --git a/core/C25519.hpp b/attic/core/C25519.hpp similarity index 100% rename from core/C25519.hpp rename to attic/core/C25519.hpp diff --git a/core/CAPI.cpp b/attic/core/CAPI.cpp similarity index 100% rename from core/CAPI.cpp rename to attic/core/CAPI.cpp diff --git a/core/CMakeLists.txt b/attic/core/CMakeLists.txt similarity index 100% rename from core/CMakeLists.txt rename to attic/core/CMakeLists.txt diff --git a/core/CallContext.hpp b/attic/core/CallContext.hpp similarity index 100% rename from core/CallContext.hpp rename to attic/core/CallContext.hpp diff --git a/core/CapabilityCredential.cpp b/attic/core/CapabilityCredential.cpp similarity index 100% rename from core/CapabilityCredential.cpp rename to attic/core/CapabilityCredential.cpp diff --git a/core/CapabilityCredential.hpp b/attic/core/CapabilityCredential.hpp similarity index 100% rename from core/CapabilityCredential.hpp rename to attic/core/CapabilityCredential.hpp diff --git a/core/Certificate.cpp b/attic/core/Certificate.cpp similarity index 100% rename from core/Certificate.cpp rename to attic/core/Certificate.cpp diff --git a/core/Certificate.hpp b/attic/core/Certificate.hpp similarity index 100% rename from core/Certificate.hpp rename to attic/core/Certificate.hpp diff --git a/core/Constants.hpp b/attic/core/Constants.hpp similarity index 100% rename from core/Constants.hpp rename to attic/core/Constants.hpp diff --git a/core/Containers.hpp b/attic/core/Containers.hpp similarity index 100% rename from core/Containers.hpp rename to attic/core/Containers.hpp diff --git a/core/Context.hpp b/attic/core/Context.hpp similarity index 100% rename from core/Context.hpp rename to attic/core/Context.hpp diff --git a/core/Credential.cpp b/attic/core/Credential.cpp similarity index 100% rename from core/Credential.cpp rename to attic/core/Credential.cpp diff --git a/core/Credential.hpp b/attic/core/Credential.hpp similarity index 100% rename from core/Credential.hpp rename to attic/core/Credential.hpp diff --git a/core/Defaults.cpp b/attic/core/Defaults.cpp similarity index 100% rename from core/Defaults.cpp rename to attic/core/Defaults.cpp diff --git a/core/Defaults.hpp b/attic/core/Defaults.hpp similarity index 100% rename from core/Defaults.hpp rename to attic/core/Defaults.hpp diff --git a/core/Defragmenter.hpp b/attic/core/Defragmenter.hpp similarity index 100% rename from core/Defragmenter.hpp rename to attic/core/Defragmenter.hpp diff --git a/core/Dictionary.cpp b/attic/core/Dictionary.cpp similarity index 100% rename from core/Dictionary.cpp rename to attic/core/Dictionary.cpp diff --git a/core/Dictionary.hpp b/attic/core/Dictionary.hpp similarity index 100% rename from core/Dictionary.hpp rename to attic/core/Dictionary.hpp diff --git a/core/ECC384.cpp b/attic/core/ECC384.cpp similarity index 100% rename from core/ECC384.cpp rename to attic/core/ECC384.cpp diff --git a/core/ECC384.hpp b/attic/core/ECC384.hpp similarity index 100% rename from core/ECC384.hpp rename to attic/core/ECC384.hpp diff --git a/core/Endpoint.cpp b/attic/core/Endpoint.cpp similarity index 100% rename from core/Endpoint.cpp rename to attic/core/Endpoint.cpp diff --git a/core/Endpoint.hpp b/attic/core/Endpoint.hpp similarity index 100% rename from core/Endpoint.hpp rename to attic/core/Endpoint.hpp diff --git a/core/Expect.hpp b/attic/core/Expect.hpp similarity index 100% rename from core/Expect.hpp rename to attic/core/Expect.hpp diff --git a/core/FCV.hpp b/attic/core/FCV.hpp similarity index 100% rename from core/FCV.hpp rename to attic/core/FCV.hpp diff --git a/core/Fingerprint.hpp b/attic/core/Fingerprint.hpp similarity index 100% rename from core/Fingerprint.hpp rename to attic/core/Fingerprint.hpp diff --git a/core/Identity.cpp b/attic/core/Identity.cpp similarity index 100% rename from core/Identity.cpp rename to attic/core/Identity.cpp diff --git a/core/Identity.hpp b/attic/core/Identity.hpp similarity index 100% rename from core/Identity.hpp rename to attic/core/Identity.hpp diff --git a/core/InetAddress.cpp b/attic/core/InetAddress.cpp similarity index 100% rename from core/InetAddress.cpp rename to attic/core/InetAddress.cpp diff --git a/core/InetAddress.hpp b/attic/core/InetAddress.hpp similarity index 100% rename from core/InetAddress.hpp rename to attic/core/InetAddress.hpp diff --git a/core/LZ4.cpp b/attic/core/LZ4.cpp similarity index 100% rename from core/LZ4.cpp rename to attic/core/LZ4.cpp diff --git a/core/LZ4.hpp b/attic/core/LZ4.hpp similarity index 100% rename from core/LZ4.hpp rename to attic/core/LZ4.hpp diff --git a/core/Locator.cpp b/attic/core/Locator.cpp similarity index 100% rename from core/Locator.cpp rename to attic/core/Locator.cpp diff --git a/core/Locator.hpp b/attic/core/Locator.hpp similarity index 100% rename from core/Locator.hpp rename to attic/core/Locator.hpp diff --git a/core/MAC.hpp b/attic/core/MAC.hpp similarity index 100% rename from core/MAC.hpp rename to attic/core/MAC.hpp diff --git a/core/MIMC52.cpp b/attic/core/MIMC52.cpp similarity index 100% rename from core/MIMC52.cpp rename to attic/core/MIMC52.cpp diff --git a/core/MIMC52.hpp b/attic/core/MIMC52.hpp similarity index 100% rename from core/MIMC52.hpp rename to attic/core/MIMC52.hpp diff --git a/core/Member.cpp b/attic/core/Member.cpp similarity index 100% rename from core/Member.cpp rename to attic/core/Member.cpp diff --git a/core/Member.hpp b/attic/core/Member.hpp similarity index 100% rename from core/Member.hpp rename to attic/core/Member.hpp diff --git a/core/MembershipCredential.cpp b/attic/core/MembershipCredential.cpp similarity index 100% rename from core/MembershipCredential.cpp rename to attic/core/MembershipCredential.cpp diff --git a/core/MembershipCredential.hpp b/attic/core/MembershipCredential.hpp similarity index 100% rename from core/MembershipCredential.hpp rename to attic/core/MembershipCredential.hpp diff --git a/core/Meter.hpp b/attic/core/Meter.hpp similarity index 100% rename from core/Meter.hpp rename to attic/core/Meter.hpp diff --git a/core/MulticastGroup.hpp b/attic/core/MulticastGroup.hpp similarity index 100% rename from core/MulticastGroup.hpp rename to attic/core/MulticastGroup.hpp diff --git a/core/Mutex.hpp b/attic/core/Mutex.hpp similarity index 100% rename from core/Mutex.hpp rename to attic/core/Mutex.hpp diff --git a/core/Network.cpp b/attic/core/Network.cpp similarity index 100% rename from core/Network.cpp rename to attic/core/Network.cpp diff --git a/core/Network.hpp b/attic/core/Network.hpp similarity index 100% rename from core/Network.hpp rename to attic/core/Network.hpp diff --git a/core/NetworkConfig.cpp b/attic/core/NetworkConfig.cpp similarity index 100% rename from core/NetworkConfig.cpp rename to attic/core/NetworkConfig.cpp diff --git a/core/NetworkConfig.hpp b/attic/core/NetworkConfig.hpp similarity index 100% rename from core/NetworkConfig.hpp rename to attic/core/NetworkConfig.hpp diff --git a/core/NetworkController.hpp b/attic/core/NetworkController.hpp similarity index 100% rename from core/NetworkController.hpp rename to attic/core/NetworkController.hpp diff --git a/core/Node.cpp b/attic/core/Node.cpp similarity index 100% rename from core/Node.cpp rename to attic/core/Node.cpp diff --git a/core/Node.hpp b/attic/core/Node.hpp similarity index 100% rename from core/Node.hpp rename to attic/core/Node.hpp diff --git a/core/OS.hpp b/attic/core/OS.hpp similarity index 100% rename from core/OS.hpp rename to attic/core/OS.hpp diff --git a/core/OwnershipCredential.cpp b/attic/core/OwnershipCredential.cpp similarity index 100% rename from core/OwnershipCredential.cpp rename to attic/core/OwnershipCredential.cpp diff --git a/core/OwnershipCredential.hpp b/attic/core/OwnershipCredential.hpp similarity index 100% rename from core/OwnershipCredential.hpp rename to attic/core/OwnershipCredential.hpp diff --git a/core/Path.cpp b/attic/core/Path.cpp similarity index 100% rename from core/Path.cpp rename to attic/core/Path.cpp diff --git a/core/Path.hpp b/attic/core/Path.hpp similarity index 100% rename from core/Path.hpp rename to attic/core/Path.hpp diff --git a/core/Peer.cpp b/attic/core/Peer.cpp similarity index 100% rename from core/Peer.cpp rename to attic/core/Peer.cpp diff --git a/core/Peer.hpp b/attic/core/Peer.hpp similarity index 100% rename from core/Peer.hpp rename to attic/core/Peer.hpp diff --git a/core/Poly1305.cpp b/attic/core/Poly1305.cpp similarity index 100% rename from core/Poly1305.cpp rename to attic/core/Poly1305.cpp diff --git a/core/Poly1305.hpp b/attic/core/Poly1305.hpp similarity index 100% rename from core/Poly1305.hpp rename to attic/core/Poly1305.hpp diff --git a/core/Protocol.hpp b/attic/core/Protocol.hpp similarity index 100% rename from core/Protocol.hpp rename to attic/core/Protocol.hpp diff --git a/core/README.md b/attic/core/README.md similarity index 100% rename from core/README.md rename to attic/core/README.md diff --git a/core/RevocationCredential.cpp b/attic/core/RevocationCredential.cpp similarity index 100% rename from core/RevocationCredential.cpp rename to attic/core/RevocationCredential.cpp diff --git a/core/RevocationCredential.hpp b/attic/core/RevocationCredential.hpp similarity index 100% rename from core/RevocationCredential.hpp rename to attic/core/RevocationCredential.hpp diff --git a/core/SHA512.cpp b/attic/core/SHA512.cpp similarity index 100% rename from core/SHA512.cpp rename to attic/core/SHA512.cpp diff --git a/core/SHA512.hpp b/attic/core/SHA512.hpp similarity index 100% rename from core/SHA512.hpp rename to attic/core/SHA512.hpp diff --git a/core/Salsa20.cpp b/attic/core/Salsa20.cpp similarity index 100% rename from core/Salsa20.cpp rename to attic/core/Salsa20.cpp diff --git a/core/Salsa20.hpp b/attic/core/Salsa20.hpp similarity index 100% rename from core/Salsa20.hpp rename to attic/core/Salsa20.hpp diff --git a/core/ScopedPtr.hpp b/attic/core/ScopedPtr.hpp similarity index 100% rename from core/ScopedPtr.hpp rename to attic/core/ScopedPtr.hpp diff --git a/core/SelfAwareness.cpp b/attic/core/SelfAwareness.cpp similarity index 100% rename from core/SelfAwareness.cpp rename to attic/core/SelfAwareness.cpp diff --git a/core/SelfAwareness.hpp b/attic/core/SelfAwareness.hpp similarity index 100% rename from core/SelfAwareness.hpp rename to attic/core/SelfAwareness.hpp diff --git a/core/SharedPtr.hpp b/attic/core/SharedPtr.hpp similarity index 100% rename from core/SharedPtr.hpp rename to attic/core/SharedPtr.hpp diff --git a/core/Spinlock.hpp b/attic/core/Spinlock.hpp similarity index 100% rename from core/Spinlock.hpp rename to attic/core/Spinlock.hpp diff --git a/core/Store.hpp b/attic/core/Store.hpp similarity index 100% rename from core/Store.hpp rename to attic/core/Store.hpp diff --git a/core/SymmetricKey.hpp b/attic/core/SymmetricKey.hpp similarity index 100% rename from core/SymmetricKey.hpp rename to attic/core/SymmetricKey.hpp diff --git a/core/TagCredential.cpp b/attic/core/TagCredential.cpp similarity index 100% rename from core/TagCredential.cpp rename to attic/core/TagCredential.cpp diff --git a/core/TagCredential.hpp b/attic/core/TagCredential.hpp similarity index 100% rename from core/TagCredential.hpp rename to attic/core/TagCredential.hpp diff --git a/core/Tests.cpp b/attic/core/Tests.cpp similarity index 100% rename from core/Tests.cpp rename to attic/core/Tests.cpp diff --git a/core/Tests.h b/attic/core/Tests.h similarity index 100% rename from core/Tests.h rename to attic/core/Tests.h diff --git a/core/TinyMap.hpp b/attic/core/TinyMap.hpp similarity index 100% rename from core/TinyMap.hpp rename to attic/core/TinyMap.hpp diff --git a/core/Topology.cpp b/attic/core/Topology.cpp similarity index 100% rename from core/Topology.cpp rename to attic/core/Topology.cpp diff --git a/core/Topology.hpp b/attic/core/Topology.hpp similarity index 100% rename from core/Topology.hpp rename to attic/core/Topology.hpp diff --git a/core/Trace.cpp b/attic/core/Trace.cpp similarity index 100% rename from core/Trace.cpp rename to attic/core/Trace.cpp diff --git a/core/Trace.hpp b/attic/core/Trace.hpp similarity index 100% rename from core/Trace.hpp rename to attic/core/Trace.hpp diff --git a/core/TriviallyCopyable.hpp b/attic/core/TriviallyCopyable.hpp similarity index 100% rename from core/TriviallyCopyable.hpp rename to attic/core/TriviallyCopyable.hpp diff --git a/core/TrustStore.cpp b/attic/core/TrustStore.cpp similarity index 100% rename from core/TrustStore.cpp rename to attic/core/TrustStore.cpp diff --git a/core/TrustStore.hpp b/attic/core/TrustStore.hpp similarity index 100% rename from core/TrustStore.hpp rename to attic/core/TrustStore.hpp diff --git a/core/Utils.cpp b/attic/core/Utils.cpp similarity index 100% rename from core/Utils.cpp rename to attic/core/Utils.cpp diff --git a/core/Utils.hpp b/attic/core/Utils.hpp similarity index 100% rename from core/Utils.hpp rename to attic/core/Utils.hpp diff --git a/core/VL1.cpp b/attic/core/VL1.cpp similarity index 100% rename from core/VL1.cpp rename to attic/core/VL1.cpp diff --git a/core/VL1.hpp b/attic/core/VL1.hpp similarity index 100% rename from core/VL1.hpp rename to attic/core/VL1.hpp diff --git a/core/VL2.cpp b/attic/core/VL2.cpp similarity index 100% rename from core/VL2.cpp rename to attic/core/VL2.cpp diff --git a/core/VL2.hpp b/attic/core/VL2.hpp similarity index 100% rename from core/VL2.hpp rename to attic/core/VL2.hpp diff --git a/core/version.h.in b/attic/core/version.h.in similarity index 100% rename from core/version.h.in rename to attic/core/version.h.in diff --git a/core/zerotier.h b/attic/core/zerotier.h similarity index 100% rename from core/zerotier.h rename to attic/core/zerotier.h diff --git a/attic/cycle_controllers.sh b/attic/cycle_controllers.sh deleted file mode 100755 index 34acacf4e..000000000 --- a/attic/cycle_controllers.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash - -CONTROLLERS=`kubectl get pods -o=name | grep controller | sed "s/^.\{4\}//"` - -for c in ${CONTROLLERS[@]} -do - kubectl delete pod ${c} - sleep 30 -done diff --git a/attic/debian/changelog b/attic/debian/changelog deleted file mode 100644 index dc8363396..000000000 --- a/attic/debian/changelog +++ /dev/null @@ -1,116 +0,0 @@ -zerotier-one (1.4.6) unstable; urgency=medium - - * Update default root server list - * Fix build flags on "armhf" (32-bit ARM) platforms for better - compatibility with Pi Zero and other devices. - * Fix license text in one.cpp. - * Add a clarification to LICENSE.txt. - - -- Adam Ierymenko Fri, 30 Aug 2019 01:00:00 -0700 - -zerotier-one (1.4.4) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - * License changed to BSL 1.1 - - -- Adam Ierymenko Fri, 23 Aug 2019 01:00:00 -0700 - -zerotier-one (1.4.2-2) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - * This is a new build that fixes a binary build issue with containers and SELinux - - -- Adam Ierymenko Thu, 04 Aug 2019 01:00:00 -0700 - -zerotier-one (1.4.2) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Thu, 04 Aug 2019 01:00:00 -0700 - -zerotier-one (1.4.0) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Thu, 29 Jul 2019 01:00:00 -0700 - -zerotier-one (1.2.12) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Tue, 25 Jul 2018 01:00:00 -0700 - -zerotier-one (1.2.10) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Tue, 08 May 2018 01:00:00 -0700 - -zerotier-one (1.2.8) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Tue, 27 Apr 2018 01:00:00 -0700 - -zerotier-one (1.2.6) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Tue, 17 Apr 2018 01:00:00 -0700 - -zerotier-one (1.2.4) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Mon, 24 Mar 2017 01:00:00 -0700 - -zerotier-one (1.2.2) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Fri, 17 Mar 2017 01:00:00 -0700 - -zerotier-one (1.2.0) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Tue, 14 Mar 2017 09:08:00 -0700 - -zerotier-one (1.1.14) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Tue, 21 Jul 2016 07:14:12 -0700 - -zerotier-one (1.1.12) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Tue, 12 Jul 2016 03:02:22 -0700 - -zerotier-one (1.1.10) unstable; urgency=medium - - * See https://github.com/zerotier/ZeroTierOne for release notes. - * ZeroTier Debian packages no longer depend on http-parser since its ABI is too unstable. - - -- Adam Ierymenko Tue, 12 Jul 2016 12:29:00 -0700 - -zerotier-one (1.1.8) unstable; urgency=low - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Fri, 08 Jul 2016 01:56:00 -0700 - -zerotier-one (1.1.6) unstable; urgency=medium - - * First Debian release on ZeroTier, Inc. private apt repository. - - * See https://github.com/zerotier/ZeroTierOne for release notes. - - -- Adam Ierymenko Fri, 24 Jun 2016 10:00:00 -0700 - -zerotier-one (1.1.5) UNRELEASED; urgency=medium - - * Development package -- first clean Debian packaging test. - - -- Adam Ierymenko Wed, 08 Jun 2016 10:05:01 -0700 diff --git a/attic/debian/compat b/attic/debian/compat deleted file mode 100644 index 301160a93..000000000 --- a/attic/debian/compat +++ /dev/null @@ -1 +0,0 @@ -8 \ No newline at end of file diff --git a/attic/debian/control b/attic/debian/control deleted file mode 100644 index 1eb147e09..000000000 --- a/attic/debian/control +++ /dev/null @@ -1,19 +0,0 @@ -Source: zerotier-one -Maintainer: Adam Ierymenko -Section: net -Priority: optional -Standards-Version: 3.9.6 -Build-Depends: debhelper (>= 9) -Vcs-Git: git://github.com/zerotier/ZeroTierOne -Vcs-Browser: https://github.com/zerotier/ZeroTierOne -Homepage: https://www.zerotier.com/ - -Package: zerotier-one -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, iproute2, adduser, libstdc++6 -Homepage: https://www.zerotier.com/ -Description: ZeroTier network virtualization service - ZeroTier One lets you join ZeroTier virtual networks and - have them appear as tun/tap ports on your system. See - https://www.zerotier.com/ for instructions and - documentation. diff --git a/attic/debian/control.wheezy b/attic/debian/control.wheezy deleted file mode 100644 index a8e240847..000000000 --- a/attic/debian/control.wheezy +++ /dev/null @@ -1,19 +0,0 @@ -Source: zerotier-one -Maintainer: Adam Ierymenko -Section: net -Priority: optional -Standards-Version: 3.9.4 -Build-Depends: debhelper -Vcs-Git: git://github.com/zerotier/ZeroTierOne -Vcs-Browser: https://github.com/zerotier/ZeroTierOne -Homepage: https://www.zerotier.com/ - -Package: zerotier-one -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, iproute, libstdc++6 -Homepage: https://www.zerotier.com/ -Description: ZeroTier network virtualization service - ZeroTier One lets you join ZeroTier virtual networks and - have them appear as tun/tap ports on your system. See - https://www.zerotier.com/ for instructions and - documentation. diff --git a/attic/debian/copyright b/attic/debian/copyright deleted file mode 100644 index da3678d52..000000000 --- a/attic/debian/copyright +++ /dev/null @@ -1,18 +0,0 @@ -Format: http://dep.debian.net/deps/dep5 -Upstream-Name: zerotier-one -Source: https://github.com/zerotier/ZeroTierOne - -Files: * -Copyright: 2011-2016 ZeroTier, Inc. -License: ZeroTier BSL 1.1 - -License: ZeroTier BSL 1.1 - Copyright (c)2019 ZeroTier, Inc. - - Use of this software is governed by the Business Source License included - in the LICENSE.TXT file in the project's root directory. - - Change Date: 2026-01-01 - - On the date above, in accordance with the Business Source License, use - of this software will be governed by version 2.0 of the Apache License. diff --git a/attic/debian/postinst b/attic/debian/postinst deleted file mode 100644 index 2e673aef9..000000000 --- a/attic/debian/postinst +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh -e - -case "$1" in - configure) - if ! id zerotier-one >>/dev/null 2>&1; then - useradd --system --user-group --home-dir /var/lib/zerotier-one --no-create-home zerotier-one - fi - ;; -esac - -#DEBHELPER# diff --git a/attic/debian/rules b/attic/debian/rules deleted file mode 100755 index e6644d8ef..000000000 --- a/attic/debian/rules +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/make -f - -CFLAGS=-O3 -fstack-protector-strong -CXXFLAGS=-O3 -fstack-protector-strong - -%: - dh $@ --with systemd - -override_dh_auto_build: - make -j 4 - -override_dh_systemd_start: - dh_systemd_start --restart-after-upgrade - -override_dh_installinit: - dh_installinit --name=zerotier-one -- defaults diff --git a/attic/debian/rules.static b/attic/debian/rules.static deleted file mode 100644 index 72c529552..000000000 --- a/attic/debian/rules.static +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/make -f - -CFLAGS=-O3 -fstack-protector-strong -CXXFLAGS=-O3 -fstack-protector-strong - -%: - dh $@ --with systemd - -override_dh_auto_build: -# make -j 2 - -override_dh_systemd_start: - dh_systemd_start --restart-after-upgrade - -override_dh_installinit: - dh_installinit --name=zerotier-one -- defaults diff --git a/attic/debian/rules.wheezy b/attic/debian/rules.wheezy deleted file mode 100755 index 55e2647a2..000000000 --- a/attic/debian/rules.wheezy +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/make -f - -CFLAGS=-O3 -fstack-protector -CXXFLAGS=-O3 -fstack-protector - -%: - dh $@ - -override_dh_auto_build: - make -j 2 - diff --git a/attic/debian/rules.wheezy.static b/attic/debian/rules.wheezy.static deleted file mode 100644 index 0165be37e..000000000 --- a/attic/debian/rules.wheezy.static +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/make -f - -CFLAGS=-O3 -fstack-protector -CXXFLAGS=-O3 -fstack-protector - -%: - dh $@ - -override_dh_auto_build: -# make -j 2 - diff --git a/attic/debian/source/format b/attic/debian/source/format deleted file mode 100644 index 46ebe0266..000000000 --- a/attic/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) \ No newline at end of file diff --git a/attic/debian/ufw-zerotier-one b/attic/debian/ufw-zerotier-one deleted file mode 100644 index 7c2908941..000000000 --- a/attic/debian/ufw-zerotier-one +++ /dev/null @@ -1,4 +0,0 @@ -[zerotier-one] -title=ZeroTier One -description=A planetary Ethernet switch -ports=9993/udp diff --git a/attic/debian/zerotier-one.init b/attic/debian/zerotier-one.init deleted file mode 100644 index 41a22a50d..000000000 --- a/attic/debian/zerotier-one.init +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/sh - -### BEGIN INIT INFO -# Provides: zerotier-one -# Required-Start: $remote_fs $syslog -# Required-Stop: $remote_fs $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: -# Short-Description: ZeroTier One network virtualization service -### END INIT INFO - -PATH=/bin:/usr/bin:/sbin:/usr/sbin -DESC="zerotier-one daemon" -NAME=zerotier-one -DAEMON=/usr/sbin/zerotier-one -PIDFILE=/var/lib/zerotier-one/zerotier-one.pid -SCRIPTNAME=/etc/init.d/"$NAME" -EXTRA_OPTS=-d - -test -f $DAEMON || exit 0 - -. /lib/lsb/init-functions - -case "$1" in -start) log_daemon_msg "Starting ZeroTier One" "zerotier-one" - start_daemon -p $PIDFILE $DAEMON $EXTRA_OPTS - log_end_msg $? - ;; -stop) log_daemon_msg "Stopping ZeroTier One" "zerotier-one" - killproc -p $PIDFILE $DAEMON - RETVAL=$? - [ $RETVAL -eq 0 ] && [ -e "$PIDFILE" ] && rm -f $PIDFILE - log_end_msg $RETVAL - ;; -restart) log_daemon_msg "Restarting ZeroTier One" "zerotier-one" - $0 stop - $0 start - ;; -reload|force-reload) log_daemon_msg "Reloading ZeroTier One" "zerotier-one" - log_end_msg 0 - ;; -status) - status_of_proc -p $PIDFILE $DAEMON $NAME && exit 0 || exit $? - ;; -*) log_action_msg "Usage: /etc/init.d/cron {start|stop|status|restart|reload|force-reload}" - exit 2 - ;; -esac -exit 0 diff --git a/attic/debian/zerotier-one.service b/attic/debian/zerotier-one.service deleted file mode 100644 index 133d4490c..000000000 --- a/attic/debian/zerotier-one.service +++ /dev/null @@ -1,12 +0,0 @@ -[Unit] -Description=ZeroTier One -After=network-online.target -Wants=network-online.target - -[Service] -ExecStart=/usr/sbin/zerotier-one -Restart=always -KillMode=process - -[Install] -WantedBy=multi-user.target diff --git a/attic/debian/zerotier-one.upstart b/attic/debian/zerotier-one.upstart deleted file mode 100644 index 7753580a8..000000000 --- a/attic/debian/zerotier-one.upstart +++ /dev/null @@ -1,14 +0,0 @@ -description "ZeroTier One upstart startup script" - -author "Adam Ierymenko " - -start on (local-filesystems and net-device-up IFACE!=lo) -stop on runlevel [!2345] - -respawn -respawn limit 2 300 - -#pre-start script -#end script - -exec /usr/sbin/zerotier-one diff --git a/attic/doc/2015-GCM-SIV.pdf b/attic/doc/2015-GCM-SIV.pdf deleted file mode 100644 index 78522f7f3..000000000 Binary files a/attic/doc/2015-GCM-SIV.pdf and /dev/null differ diff --git a/attic/doc/AES-GMAC-SIV.png b/attic/doc/AES-GMAC-SIV.png deleted file mode 100644 index 8da2d1a6f..000000000 Binary files a/attic/doc/AES-GMAC-SIV.png and /dev/null differ diff --git a/attic/doc/README.md b/attic/doc/README.md deleted file mode 100644 index 707c64a9a..000000000 --- a/attic/doc/README.md +++ /dev/null @@ -1,6 +0,0 @@ -Manual Pages and Other Documentation -===== - -Use "./build.sh" to build the manual pages. - -You'll need either NodeJS/npm installed (script will then automatically install the npm *marked-man* package) or */usr/bin/ronn*. The latter is a Ruby program packaged on some distributions as *rubygem-ronn* or *ruby-ronn* or installable as *gem install ronn*. The Node *marked-man* package and *ronn* from rubygems are two roughly equivalent alternatives for compiling MarkDown into roff/man format. diff --git a/attic/doc/SECURITY.md b/attic/doc/SECURITY.md deleted file mode 100644 index b81d0830f..000000000 --- a/attic/doc/SECURITY.md +++ /dev/null @@ -1,149 +0,0 @@ -ZeroTier security and cryptographic design -======= - -(c)2020 ZeroTier, Inc. -Author(s): Adam Ierymenko - -# Introduction - -This document describes the core components of ZeroTier's cryptographic and security architecture. It focuses primarily on version 2.0 and only briefly touches on v1.x constructions that are being phased out. - -The intended audience for this document is developers, auditors, and security professionals wishing to understand ZeroTier's design from a security posture point of view. It's also written to serve as the basis for professional security audits of the ZeroTier protocol and code base. - -## High-Level Protocol Design - -ZeroTier's protocol is split into two conceptual layers that we term **VL1** and **VL2**. - -VL1 stands for *virtual layer 1* and is a cryptographically addressed secure global peer-to-peer network responsible for moving packets between ZeroTier nodes. It's a virtual analogue of the physical wire or radio transciever in an Ethernet or WiFi network respectively. Think of it as a gigantic wire closet for planet Earth. - -VL2 stands for *virtual layer 2* and is a full Ethernet emulation layer incorporating cryptographic certificate and token based access control. It is similar (but not identical) to other Ethernet virtualization protocols like VXLAN. VL2 is conceptually separate from VL1 but for the sake of simplicity and ease of use leverages VL1's cryptographic infrastructure for its own authentication needs. - -## VL1 Asymmetric Cryptography: Identities, and Addressing - -VL1 peers are cryptographically addressed, meaning addresses are strongly bound to public keys. Cryptographic addressing is extremely convenient in peer-to-peer networks as it leverages authenticated (AEAD) encryption to implicity authenticate endpoint addresses. - -A ZeroTier identity is comprised of one or more cryptographic public keys and a short **ZeroTier address** derived from a hash of those keys. In addition to this short address there also exists a longer fingerprint in the form of a SHA-384 hash of identity public key(s). - -#### Identity Types and Corresponding Algorithms - -* **Type 0** (v1.x and v2.x): one Curve25519 key for elliptic curve Diffie-Hellman and one Ed25519 key for Ed25519 signatures, with the address and fingerprint computed from a hash of both. -* **Type 1** (v2.x only): Curve25519, Ed25519, and NIST P-384 public keys, with the latter being used for signatures (the Ed25519 key is still there but is presently unused) and with *both* Curve25519 and NIST P-384 being used for elliptic curve Diffie-Hellman key agreement. In key agreement the resulting raw secret keys are hashed together using SHA-384 to combine them and yield a single session key. - -Session keys resulting from identity key exchange and agreement are *long-lived keys* that remain static for the lifetime of a particular pair of identities. A different mechanism is used for ephemeral key negotiation. - -#### ZeroTier Addresses and Identity Fingerprints - -In the simplest form of cryptographic addressing, keys are used directly as addresses throughout the system. Unfortunately even public key cryptosystems with short keys like Curve25519 still result in string representations that are prohibitively long for human beings to type. ZeroTier mitigates this usability problem by using a short hash of the public key termed a **ZeroTier address** to refer to a peer's full identity. This short address is also used at the wire level to reduce the size of the packet header. Peers may request full identities based on addresses from from root servers. - -ZeroTier addresses are very short: only 40 bits or 10 hexadecimal digits, e.g. `89e92ceee5.` This makes them convenient to type, but such a short hash would in a naive implementation introduce a significant risk that an attacker could create a duplicate identity with a different key pair but the same address. With 40 bits an intentional collision would require only an average of about 549,755,813,888 attempts for a 50% chance of colliding. If an attempt requires 0.5ms of CPU time on a typical contemporary desktop or server CPU, this would require about 3,000 CPU-days. Since this type of search is easy to parallelize, it would take only a few days for someone with access to a few thousand CPU cores. - -To provide this short hash with a larger security margin, an intentionally slow one-way "hashcash" or "proof of work" function is required during identity generation. This work function is slow to compute but fast to verify, and an address is not valid unless its work checks out. This gives identity address derivation the following costs: - -* Type 1 identities: an average of about 500ms per key pair per typical 2.4ghz CPU core, requiring around 3 million CPU-days to reach a 50% collision probability. -* Type 2 identities: an average of about one second per key pair per typical 2.4ghz CPU core, requiring around 6.3 million CPU-days to reach a 50% collision probability. - -While too costly for the vast majority of attackers, this cost may not be prohibitive to a nation-state level attacker or to a criminal with significant funds and/or access to a very large "botnet." It's also possible that FPGA, GPU, or ASIC acceleration could be leveraged to decrease this time in a manner similar to what's been accomplished in the area of cryptocurrency mining. - -Fingerprints are full SHA-384 hashes of identity public keys. In base32-encoding they look like this: - -``` -bzg7fc3sn46fzyxcxw2ev4c4m2u5fyisb3o4wz5hfmvexbzwk6et3fsglkdcn6nnjobxi3bq7hgxqox3n4u4k -``` - -These are too large to type but not to copy/paste, store in databases, or use in scripts and APIs. - -Once a device has joined a network, network controllers will remember and check its full identity or identity fingerprint (depending on implementation) rather than just the device's ZeroTier address. - -## VL1 Wire Protocol - -ZeroTier's wire protocol is packet based with packets having the following format: - -``` -[0:8] 64-bit packet ID and cryptographic nonce -[8:13] 40-bit destination ZeroTier address -[13:18] 40-bit source ZeroTier address -[18:19] 8-bit cleartext flags, cipher, and hop count (bits: FFCCCHHH) -[19:27] 64-bit message authentication code (MAC) --- BEGIN ENCRYPTED SECTION -- -[27:28] 8-bit inner flags and 5-bit protocol verb (bits: FFFVVVVV) -[28:...] Verb-specific packet payload -``` - -All fields (both those that remain cleartext and those that are encrypted) in a packet are authenticated except for the last three "hops" bits of the combined flags/cipher/hops field. These are masked to zero during MAC computation and verification. This is because the hops field is the only field that can be modified by third party peers in transit. It's incremented whenever a packet is forwarded by a root server or connectivity-assisting peer and is checked against a limit to prevent infinite forwarding loops. - -Packets can be up to 16,384 bytes in size. Since the most common transport is UDP and this transport does not reliably support fragmentation, ZeroTier implements its own packet fragmentation and re-assembly scheme using fragments with the following wire format: - -``` -[0:8] 64-bit packet ID of packet of which this is a fragment -[8:13] 40-bit destination ZeroTier address -[13:14] 0xff here indicates a fragment since addresses cannot start with this byte -[14:15] 4-bit total fragments and 4-bit fragment number (bits: TTTTNNNN) -[15:16] 5 reserved bits, 3-bit hop count (bits: rrrrrHHH) -[16:...] Fragment data -``` - -A fragmented packet is indicated by the presence of the flag 0x40 in its cleartext flags field. If this flag is present the receiver must expect the receipt of one or more fragments in addition to the packet's header and first fragment. The total number of fragments expected is not contained in the header but will be contained within each subsequent fragment. If a fragment is received prior to its head, it's held in the event that its head arrives as the protocol does support out of order receipt of fragments. - -Fragmentation can be effectively ignored from a security point of view (with the exception of denial of service concerns, which are mitigated by way of limits and heuristics in the code) since packet message authentication codes are checked at the packet level. Any improperly fragmented packet will fail cryptographic MAC check and be discarded. - -*Legacy: In v1.x the packet ID and nonce field was assigned from a counter maintained to avoid duplicate nonce assignment and the MAC field was the first 64 bits of a Poly1305 MAC of the packet. The overall construction was identical in form to the NaCl Salsa20/Poly1305 "secret box" construction in which the first 32 bytes of Salsa20 output are used as a one-time Poly1305 key for each packet.* - -In v2.x the packet ID and MAC field are in reality a single split 128-bit encrypted nonce and MAC field. See AES-GMAC-SIV below. - -## Symmetric Encryption: AES-GMAC-SIV - -**This is a draft and may change based on peer review and feedback.** - -In v1.x there is a risk of nonce re-use due in part to the small size of the MAC and in part to the way ZeroTier is used. More specifically the risk arises when ZeroTier VMs are cloned or ZeroTier is used on small devices that have the potential to lack both accurate timekeeping and native strong random sources. - -Salsa20 was used in v1.x since at the time the protocol was initially designed AES acceleration was not available on most mobile phones, embedded chips, and small ARM processors such as those use on Raspberry Pi and similar devices. This is no longer the case. - -For v2.x our design has three objectives: - -- Make use of FIPS140-compliant cryptographic primitives that would be available in a FIPS140-ceritified library (e.g. a FIPS build of crypto++ or openssl libcrypto), and use them in a way that could pass FIPS/NIST/NSA review. -- Use AES with hardware acceleration for extremely high performance processors with AES hardware acceleration, which is most non-trivial CPUs today. -- Incorporate some form of nonce-reuse-resistance to reduce the risk of duplicate nonces when virtual machines are cloned or on small devices, and to mitigate the short MAC. - -The proposed AES-GMAC-SIV construction attempts to achieve all these objectives by using GMAC combined with AES-CTR (both FIPS140 primitives) in a way that achieves the security bounds and characteristics of AES-GCM-SIV but could be certified as FIPS compliant. The design is almost identical to another proposed mode called AES-GCM-SIV except that GMAC is used "as-is" for FIPS-certifiability reasons. - -#### AES-GMAC-SIV Session Setup - -For each new session key, derive two sub-keys **K0** and **K1** using a key derivation function such as KBKDF-HMAC-SHA384. - -#### AES-GMAC-SIV Encryption - - - -As with all other SIV (synthetic IV) modes of operation, encryption requires two passes. Since messages are small in our system it's very likely that the second pass would be operating on data already in CPU L0 cache, reducing the additional overhead of this two-pass requirement. - -1. Generate a new unique 64-bit packet ID in the same manner as v1.x. -2. Expand this 64-bit ID to a 96-bit AES-GMAC nonce by padding the remainder with the size of the packet in bytes and the direction of communication (sender > recipient or recipient > sender). This adds a small amount of additional entropy taken from characteristics of the packet. -3. Using session sub-key **K0** compute AES-GMAC(K0, plaintext) to yield a 128-bit GMAC tag. -4. Take the first 64 bits of this 128-bit GMAC tag and append it to the 64-bit packet ID generated in step 1 to yield a 128-bit combined nonce+MAC field. -5. Obtain a 128-bit AES-CTR nonce by encrypting this 128-bit combined nonce+MAC field as a single AES block using **K1**. This is done because GMAC alone is not a cryptographic PRF (pseudo-random function) and we want to ensure that we destroy any algebraic structure before using it with AES-CTR. -6. Using the encrypted nonce+MAC field as a 128-bit nonce, encrypt the encrypted section of the packet with AES-CTR. This is also done using **K1**, meaning that the first block of CTR padding data is actually AES(K1,AES(K1,nonce+MAC)). -7. Encrypt the 128-bit AES-CTR nonce again as a single AES block using **K0** to yield a final encrypted 128-bit combined nonce and MAC. *(Question for peer review: does this step have any attack-mitigating value? AES-CTR does not require that its nonce/IV be a secret.)* -8. Split this final encrypted nonce+IV into two 64-bit chunks, replacing the packet ID with one and placing the other in the packet MAC field. - -#### AES-GMAC-SIV Decryption - -Unlike encryption, SIV decryption can be performed in a single pass if there is a performance benefit to doing so. - -1. Re-combine the packet ID and MAC fields into a single 128-bit block. -2. Decrypt this block with AES using **K0** to yield the AES-CTR nonce. -3. Decrypt the packet using AES-CTR with **K1**. -4. Decrypt the 128-bit AES-CTR nonce field *again* as a single AES block using **K1** to obtain the original packet nonce and 64-bit truncated GMAC tag. -5. Expand the 64-bit packet ID / nonce into a 96-bit GMAC nonce as in encryption step 2. -6. Compute AES-GMAC(K0,plaintext) as in encryption step 3. -7. Verify that the first 64 bytes of the resulting GMAC tag equals the tag (last 64 bits) obtained in decryption step 4 and discard the packet if they do not match. - -#### Discussion - -Most standard stream cipher modes such as AES-GCM or Salsa20/Poly1305 require that message nonce/IV values are never duplicated for the same session key. Since these stream modes generate key streams that are simply XORed with message plaintext, nonce duplication reveals the plaintext of both messages for which the nonce is duplicated due to the commutativity of the XOR operation. It may also allow the MAC (GMAC or Poly1305) itself to be attacked in such a way as to enable message forgery. - -SIV modes mitigate these attacks by making the actual cryptographic nonce used for stream encryption dependent on the content of the message. If a nonce is repeated when two messages differ, ciphertext will still be unique unless a MAC collision also occurs. The chance of this is quite small, only 1/2^64 in our system for any given pair of repeated nonce values. If a repeated nonce occurs and both messages are the same, the protocol will leak only the fact that a message was repeated. The actual plaintext and MAC are not compromised. - -Our AES-GMAC-SIV mode is almost identical to a proposed mode called [AES-GCM-SIV](https://cyber.biu.ac.il/aes-gcm-siv/). The proposed AES-GCM-SIV mode uses a variant of GMAC called POLYVAL with very minor performance improvements while ours retains standard GMAC for compatibility with existing standards and libraries. We call our mode AES-GMAC-SIV to distinguish it. - -*Question for peer review: both GMAC and AES-CTR are FIPS140 approved primitives, and the use of AES-CTR with an approved MAC is permitted. Is it actually feasible that this could be FIPS certified if it were documented in a correct and "strategic" way? It would be described as GMAC authenticated AES-CTR with the CTR IV being constructed via keyed hash (AES) from an initial plaintext IV and a "salt" taken from the MAC, or some similar description.* - diff --git a/attic/doc/build.sh b/attic/doc/build.sh deleted file mode 100755 index 9df72a333..000000000 --- a/attic/doc/build.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/bash - -export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin - -if [ ! -f zerotier-cli.1.md ]; then - echo 'This script must be run from the doc/ subfolder of the ZeroTier tree.' -fi - -rm -f *.1 *.2 *.8 - -if [ -e /usr/bin/ronn -o -e /usr/local/bin/ronn ]; then - # Use 'ronn' which is available as a package on many distros including Debian - ronn -r zerotier-cli.1.md - ronn -r zerotier-idtool.1.md - ronn -r zerotier-one.8.md -else - # Use 'marked-man' from npm - NODE=/usr/bin/node - if [ ! -e $NODE ]; then - if [ -e /usr/bin/nodejs ]; then - NODE=/usr/bin/nodejs - elif [ -e /usr/local/bin/node ]; then - NODE=/usr/local/bin/node - elif [ -e /usr/local/bin/nodejs ]; then - NODE=/usr/local/bin/nodejs - else - echo 'Unable to find ronn or node/npm -- cannot build man pages!' - exit 1 - fi - fi - - if [ ! -f node_modules/marked-man/bin/marked-man ]; then - echo 'Installing npm package "marked-man" -- MarkDown to ROFF converter...' - npm install marked-man - fi - - $NODE node_modules/marked-man/bin/marked-man zerotier-cli.1.md >zerotier-cli.1 - $NODE node_modules/marked-man/bin/marked-man zerotier-idtool.1.md >zerotier-idtool.1 - $NODE node_modules/marked-man/bin/marked-man zerotier-one.8.md >zerotier-one.8 -fi - -exit 0 diff --git a/attic/doc/contact@zerotier.com.gpg b/attic/doc/contact@zerotier.com.gpg deleted file mode 100644 index dc7d6455c..000000000 --- a/attic/doc/contact@zerotier.com.gpg +++ /dev/null @@ -1,52 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Comment: GPGTools - https://gpgtools.org - -mQINBFdQq7oBEADEVhyRiaL8dEjMPlI/idO8tA7adjhfvejxrJ3Axxi9YIuIKhWU -5hNjDjZAiV9iSCMfJN3TjC3EDA+7nFyU6nDKeAMkXPbaPk7ti+Tb1nA4TJsBfBlm -CC14aGWLItpp8sI00FUzorxLWRmU4kOkrRUJCq2kAMzbYWmHs0hHkWmvj8gGu6mJ -WU3sDIjvdsm3hlgtqr9grPEnj+gA7xetGs3oIfp6YDKymGAV49HZmVAvSeoqfL1p -pEKlNQ1aO9uNfHLdx6+4pS1miyo7D1s7ru2IcqhTDhg40cHTL/VldC3d8vXRFLIi -Uo2tFZ6J1jyQP5c1K4rTpw3UNVne3ob7uCME+T1+ePeuM5Y/cpcCvAhJhO0rrlr0 -dP3lOKrVdZg4qhtFAspC85ivcuxWNWnfTOBrgnvxCA1fmBX+MLNUEDsuu55LBNQT -5+WyrSchSlsczq+9EdomILhixUflDCShHs+Efvh7li6Pg56fwjEfj9DJYFhRvEvQ -7GZ7xtysFzx4AYD4/g5kCDsMTbc9W4Jv+JrMt3JsXt2zqwI0P4R1cIAu0J6OZ4Xa -dJ7Ci1WisQuJRcCUtBTUxcYAClNGeors5Nhl4zDrNIM7zIJp+GfPYdWKVSuW10mC -r3OS9QctMSeVPX/KE85TexeRtmyd4zUdio49+WKgoBhM8Z9MpTaafn2OPQARAQAB -tFBaZXJvVGllciwgSW5jLiAoWmVyb1RpZXIgU3VwcG9ydCBhbmQgUmVsZWFzZSBT -aWduaW5nIEtleSkgPGNvbnRhY3RAemVyb3RpZXIuY29tPokCNwQTAQoAIQUCV1Cr -ugIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRAWVxmII+UqYViGEACnC3+3 -lRzfv7f7JLWo23FSHjlF3IiWfYd+47BLDx706SDih1H6Qt8CqRy706bWbtictEJ/ -xTaWgTEDzY/lRalYO5NAFTgK9h2zBP1t8zdEA/rmtVPOWOzd6jr0q3l3pKQTeMF0 -6g+uaMDG1OkBz6MCwdg9counz6oa8OHK76tXNIBEnGOPBW375z1O+ExyddQOHDcS -IIsUlFmtIL1yBa7Q5NSfLofPLfS0/o2FItn0riSaAh866nXHynQemjTrqkUxf5On -65RLM+AJQaEkX17vDlsSljHrtYLKrhEueqeq50e89c2Ya4ucmSVeC9lrSqfyvGOO -P3aT/hrmeE9XBf7a9vozq7XhtViEC/ZSd1/z/oeypv4QYenfw8CtXP5bW1mKNK/M -8xnrnYwo9BUMclX2ZAvu1rTyiUvGre9fEGfhlS0rjmCgYfMgBZ+R/bFGiNdn6gAd -PSY/8fP8KFZl0xUzh2EnWe/bptoZ67CKkDbVZnfWtuKA0Ui7anitkjZiv+6wanv4 -+5A3k/H3D4JofIjRNgx/gdVPhJfWjAoutIgGeIWrkfcAP9EpsR5swyc4KuE6kJ/Y -wXXVDQiju0xE1EdNx/S1UOeq0EHhOFqazuu00ojATekUPWenNjPWIjBYQ0Ag4ycL -KU558PFLzqYaHphdWYgxfGR+XSgzVTN1r7lW87kCDQRXUKu6ARAA2wWOywNMzEiP -ZK6CqLYGZqrpfx+drOxSowwfwjP3odcK8shR/3sxOmYVqZi0XVZtb9aJVz578rNb -e4Vfugql1Yt6w3V84z/mtfj6ZbTOOU5yAGZQixm6fkXAnpG5Eer/C8Aw8dH1EreP -Na1gIVcUzlpg2Ql23qjr5LqvGtUB4BqJSF4X8efNi/y0hj/GaivUMqCF6+Vvh3GG -fhvzhgBPku/5wK2XwBL9BELqaQ/tWOXuztMw0xFH/De75IH3LIvQYCuv1pnM4hJL -XYnpAGAWfmFtmXNnPVon6g542Z6c0G/qi657xA5vr6OSSbazDJXNiHXhgBYEzRrH -napcohTQwFKEA3Q4iftrsTDX/eZVTrO9x6qKxwoBVTGwSE52InWAxkkcnZM6tkfV -n7Ukc0oixZ6E70Svls27zFgaWbUFJQ6JFoC6h+5AYbaga6DwKCYOP3AR+q0ZkcH/ -oJIdvKuhF9zDZbQhd76b4gK3YXnMpVsj9sQ9P23gh61RkAQ1HIlGOBrHS/XYcvpk -DcfIlJXKC3V1ggrG+BpKu46kiiYmRR1/yM0EXH2n99XhLNSxxFxxWhjyw8RcR6iG -ovDxWAULW+bJHjaNJdgb8Kab7j2nT2odUjUHMP42uLJgvS5LgRn39IvtzjoScAqg -8I817m8yLU/91D2f5qmJIwFI6ELwImkAEQEAAYkCHwQYAQoACQUCV1CrugIbDAAK -CRAWVxmII+UqYWSSEACxaR/hhr8xUIXkIV52BeD+2BOS8FNOi0aM67L4fEVplrsV -Op9fvAnUNmoiQo+RFdUdaD2Rpq+yUjQHHbj92mlk6Cmaon46wU+5bAWGYpV1Uf+o -wbKw1Xv83Uj9uHo7zv9WDtOUXUiTe/S792icTfRYrKbwkfI8iCltgNhTQNX0lFX/ -Sr2y1/dGCTCMEuA/ClqGKCm9lIYdu+4z32V9VXTSX85DsUjLOCO/hl9SHaelJgmi -IJzRY1XLbNDK4IH5eWtbaprkTNIGt00QhsnM5w+rn1tO80giSxXFpKBE+/pAx8PQ -RdVFzxHtTUGMCkZcgOJolk8y+DJWtX8fP+3a4Vq11a3qKJ19VXk3qnuC1aeW7OQF -j6ISyHsNNsnBw5BRaS5tdrpLXw6Z7TKr1eq+FylmoOK0pIw5xOdRmSVoFm4lVcI5 -e5EwB7IIRF00IFqrXe8dCT0oDT9RXc6CNh6GIs9D9YKwDPRD/NKQlYoegfa13Jz7 -S3RIXtOXudT1+A1kaBpGKnpXOYD3w7jW2l0zAd6a53AAGy4SnL1ac4cml76NIWiF -m2KYzvMJZBk5dAtFa0SgLK4fg8X6Ygoo9E0JsXxSrW9I1JVfo6Ia//YOBMtt4XuN -Awqahjkq87yxOYYTnJmr2OZtQuFboymfMhNqj3G2DYmZ/ZIXXPgwHx0fnd3R0Q== -=JgAv ------END PGP PUBLIC KEY BLOCK----- diff --git a/attic/doc/manpage_encoding_declaration.UTF-8 b/attic/doc/manpage_encoding_declaration.UTF-8 deleted file mode 100644 index 991db0a6a..000000000 --- a/attic/doc/manpage_encoding_declaration.UTF-8 +++ /dev/null @@ -1 +0,0 @@ -'\" -*- coding: utf-8 -*- diff --git a/attic/doc/zerotier-cli.1 b/attic/doc/zerotier-cli.1 deleted file mode 100644 index 167109ec9..000000000 --- a/attic/doc/zerotier-cli.1 +++ /dev/null @@ -1,83 +0,0 @@ -.TH "ZEROTIER\-CLI" "1" "December 2016" "" "" -.SH "NAME" -\fBzerotier-cli\fR \- control local ZeroTier virtual network service -.SH SYNOPSIS -.P -\fBzerotier\-cli\fP [\-switches] [arguments] -.SH DESCRIPTION -.P -\fBzerotier\-cli\fR provides a simple command line interface to the local JSON API of the ZeroTier virtual network endpoint service zerotier\-one(8)\. -.P -By default \fBzerotier\-cli\fR must be run as root or with \fBsudo\fP\|\. If you want to allow an unprivileged user to use \fBzerotier\-cli\fR to control the system ZeroTier service, you can create a local copy of the ZeroTier service authorization token in the user's home directory: -.P -.RS 2 -.nf -sudo cp /var/lib/zerotier\-one/authtoken\.secret /home/user/\.zeroTierOneAuthToken -chown user /home/user/\.zeroTierOneAuthToken -chmod 0600 /home/user/\.zeroTierOneAuthToken -.fi -.RE -.P -(The location of ZeroTier's service home may differ by platform\. See zerotier\-one(8)\.) -.P -Note that this gives the user the power to connect or disconnect the system to or from any virtual network, which is a significant permission\. -.P -\fBzerotier\-cli\fR has several command line arguments that are visible in \fBhelp\fP output\. The two most commonly used are \fB\-j\fP for raw JSON output and \fB\-D\fP to specify an alternative ZeroTier service working directory\. Raw JSON output is easier to parse in scripts and also contains verbose details not present in the tabular output\. The \fB\-D\fP option specifies where the service's zerotier\-one\.port and authtoken\.secret files are located if the service is not running at the default location for your system\. -.SH COMMANDS -.RS 0 -.IP \(bu 2 -\fBhelp\fP: -Displays \fBzerotier\-cli\fR help\. -.IP \(bu 2 -\fBinfo\fP: -Shows information about this device including its 10\-digit ZeroTier address and apparent connection status\. Use \fB\-j\fP for more verbose output\. -.IP \(bu 2 -\fBlistpeers\fP: -This command lists the ZeroTier VL1 (virtual layer 1, the peer to peer network) peers this service knows about and has recently (within the past 30 minutes or so) communicated with\. These are not necessarily all the devices on your virtual network(s), and may also include a few devices not on any virtual network you've joined\. These are typically either root servers or network controllers\. -.IP \(bu 2 -\fBlistnetworks\fP: -This lists the networks your system belongs to and some information about them, such as any ZeroTier\-managed IP addresses you have been assigned\. (IP addresses assigned manually to ZeroTier interfaces will not be listed here\. Use the standard network interface commands to see these\.) -.IP \(bu 2 -\fBjoin\fP: -To join a network just use \fBjoin\fP and its 16\-digit hex network ID\. That's it\. Then use \fBlistnetworks\fP to see the status\. You'll either get a reply from the network controller with a certificate and other info such as IP assignments, or you'll get "access denied\." In this case you'll need the administrator of this network to authorize your device by its 10\-digit device ID (visible with \fBinfo\fP) on the network's controller\. -.IP \(bu 2 -\fBleave\fP: -Leaving a network is as easy as joining it\. This disconnects from the network and deletes its interface from the system\. Note that peers on the network may hang around in \fBlistpeers\fP for up to 30 minutes until they time out due to lack of traffic\. But if they no longer share a network with you, they can't actually communicate with you in any meaningful way\. - -.RE -.SH EXAMPLES -.P -Join "Earth," ZeroTier's big public party line network: -.P -.RS 2 -.nf -$ sudo zerotier\-cli join 8056c2e21c000001 -$ sudo zerotier\-cli listnetworks -( wait until you get an Earth IP ) -$ ping earth\.zerotier\.net -( you should now be able to ping our Earth test IP ) -.fi -.RE -.P -Leave "Earth": -.P -.RS 2 -.nf -$ sudo zerotier\-cli leave 8056c2e21c000001 -.fi -.RE -.P -List VL1 peers: -.P -.RS 2 -.nf -$ sudo zerotier\-cli listpeers -.fi -.RE -.SH COPYRIGHT -.P -(c)2011\-2016 ZeroTier, Inc\. \-\- https://www\.zerotier\.com/ \-\- https://github\.com/zerotier -.SH SEE ALSO -.P -zerotier\-one(8), zerotier\-idtool(1) - diff --git a/attic/doc/zerotier-cli.1.md b/attic/doc/zerotier-cli.1.md deleted file mode 100644 index 6252d452f..000000000 --- a/attic/doc/zerotier-cli.1.md +++ /dev/null @@ -1,68 +0,0 @@ -zerotier-cli(1) -- control local ZeroTier virtual network service -================================================================= - -## SYNOPSIS - -`zerotier-cli` [-switches] [arguments] - -## DESCRIPTION - -**zerotier-cli** provides a simple command line interface to the local JSON API of the ZeroTier virtual network endpoint service zerotier-one(8). - -By default **zerotier-cli** must be run as root or with `sudo`. If you want to allow an unprivileged user to use **zerotier-cli** to control the system ZeroTier service, you can create a local copy of the ZeroTier service authorization token in the user's home directory: - - sudo cp /var/lib/zerotier-one/authtoken.secret /home/user/.zeroTierOneAuthToken - chown user /home/user/.zeroTierOneAuthToken - chmod 0600 /home/user/.zeroTierOneAuthToken - -(The location of ZeroTier's service home may differ by platform. See zerotier-one(8).) - -Note that this gives the user the power to connect or disconnect the system to or from any virtual network, which is a significant permission. - -**zerotier-cli** has several command line arguments that are visible in `help` output. The two most commonly used are `-j` for raw JSON output and `-D` to specify an alternative ZeroTier service working directory. Raw JSON output is easier to parse in scripts and also contains verbose details not present in the tabular output. The `-D` option specifies where the service's zerotier-one.port and authtoken.secret files are located if the service is not running at the default location for your system. - -## COMMANDS - - * `help`: - Displays **zerotier-cli** help. - - * `info`: - Shows information about this device including its 10-digit ZeroTier address and apparent connection status. Use `-j` for more verbose output. - - * `listpeers`: - This command lists the ZeroTier VL1 (virtual layer 1, the peer to peer network) peers this service knows about and has recently (within the past 30 minutes or so) communicated with. These are not necessarily all the devices on your virtual network(s), and may also include a few devices not on any virtual network you've joined. These are typically either root servers or network controllers. - - * `listnetworks`: - This lists the networks your system belongs to and some information about them, such as any ZeroTier-managed IP addresses you have been assigned. (IP addresses assigned manually to ZeroTier interfaces will not be listed here. Use the standard network interface commands to see these.) - - * `join`: - To join a network just use `join` and its 16-digit hex network ID. That's it. Then use `listnetworks` to see the status. You'll either get a reply from the network controller with a certificate and other info such as IP assignments, or you'll get "access denied." In this case you'll need the administrator of this network to authorize your device by its 10-digit device ID (visible with `info`) on the network's controller. - - * `leave`: - Leaving a network is as easy as joining it. This disconnects from the network and deletes its interface from the system. Note that peers on the network may hang around in `listpeers` for up to 30 minutes until they time out due to lack of traffic. But if they no longer share a network with you, they can't actually communicate with you in any meaningful way. - -## EXAMPLES - -Join "Earth," ZeroTier's big public party line network: - - $ sudo zerotier-cli join 8056c2e21c000001 - $ sudo zerotier-cli listnetworks - ( wait until you get an Earth IP ) - $ ping earth.zerotier.net - ( you should now be able to ping our Earth test IP ) - -Leave "Earth": - - $ sudo zerotier-cli leave 8056c2e21c000001 - -List VL1 peers: - - $ sudo zerotier-cli listpeers - -## COPYRIGHT - -(c)2011-2016 ZeroTier, Inc. -- https://www.zerotier.com/ -- https://github.com/zerotier - -## SEE ALSO - -zerotier-one(8), zerotier-idtool(1) diff --git a/attic/doc/zerotier-idtool.1 b/attic/doc/zerotier-idtool.1 deleted file mode 100644 index fbc367a6a..000000000 --- a/attic/doc/zerotier-idtool.1 +++ /dev/null @@ -1,84 +0,0 @@ -.TH "ZEROTIER\-IDTOOL" "1" "December 2016" "" "" -.SH "NAME" -\fBzerotier-idtool\fR \- tool for creating and manipulating ZeroTier identities -.SH SYNOPSIS -.P -\fBzerotier\-idtool\fP [args] -.SH DESCRIPTION -.P -\fBzerotier\-idtool\fR is a command line utility for doing things with ZeroTier identities\. A ZeroTier identity consists of a public/private key pair (or just the public if it's only an identity\.public) and a 10\-digit hexadecimal ZeroTier address derived from the public key by way of a proof of work based hash function\. -.SH COMMANDS -.P -When command arguments call for a public or secret (full) identity, the identity can be specified as a path to a file or directly on the command line\. -.RS 0 -.IP \(bu 2 -\fBhelp\fP: -Display help\. (Also running with no command does this\.) -.IP \(bu 2 -\fBgenerate\fP [secret file] [public file] [vanity]: -Generate a new ZeroTier identity\. If a secret file is specified, the full identity including the private key will be written to this file\. If the public file is specified, the public portion will be written there\. If no file paths are specified the full secret identity is output to STDOUT\. The vanity prefix is a series of hexadecimal digits that the generated identity's address should start with\. Typically this isn't used, and if it's specified generation can take a very long time due to the intrinsic cost of generating identities with their proof of work function\. Generating an identity with a known 16\-bit (4 digit) prefix on a 2\.8ghz Core i5 (using one core) takes an average of two hours\. -.IP \(bu 2 -\fBvalidate\fP : -Locally validate an identity's key and proof of work function correspondence\. -.IP \(bu 2 -\fBgetpublic\fP : -Extract the public portion of an identity\.secret and print to STDOUT\. -.IP \(bu 2 -\fBsign\fP : -Sign a file's contents with SHA512+ECC\-256 (ed25519)\. The signature is output in hex to STDOUT\. -.IP \(bu 2 -\fBverify\fP : -Verify a signature created with \fBsign\fP\|\. -.IP \(bu 2 -\fBmkcom\fP [id,value,maxdelta] [\|\.\.\.]: -Create and sign a network membership certificate\. This is not generally useful since network controllers do this automatically and is included mostly for testing purposes\. - -.RE -.SH EXAMPLES -.P -Generate and dump a new identity: -.P -.RS 2 -.nf -$ zerotier\-idtool generate -.fi -.RE -.P -Generate and write a new identity, both secret and public parts: -.P -.RS 2 -.nf -$ zerotier\-idtool generate identity\.secret identity\.public -.fi -.RE -.P -Generate a vanity address that begins with the hex digits "beef" (this will take a while!): -.P -.RS 2 -.nf -$ zerotier\-idtool generate beef\.secret beef\.public beef -.fi -.RE -.P -Sign a file with an identity's secret key: -.P -.RS 2 -.nf -$ zerotier\-idtool sign identity\.secret last_will_and_testament\.txt -.fi -.RE -.P -Verify a file's signature with a public key: -.P -.RS 2 -.nf -$ zerotier\-idtool verify identity\.public last_will_and_testament\.txt -.fi -.RE -.SH COPYRIGHT -.P -(c)2011\-2016 ZeroTier, Inc\. \-\- https://www\.zerotier\.com/ \-\- https://github\.com/zerotier -.SH SEE ALSO -.P -zerotier\-one(8), zerotier\-cli(1) - diff --git a/attic/doc/zerotier-idtool.1.md b/attic/doc/zerotier-idtool.1.md deleted file mode 100644 index 52a586c11..000000000 --- a/attic/doc/zerotier-idtool.1.md +++ /dev/null @@ -1,65 +0,0 @@ -zerotier-idtool(1) -- tool for creating and manipulating ZeroTier identities -============================================================================ - -## SYNOPSIS - -`zerotier-idtool` [args] - -## DESCRIPTION - -**zerotier-idtool** is a command line utility for doing things with ZeroTier identities. A ZeroTier identity consists of a public/private key pair (or just the public if it's only an identity.public) and a 10-digit hexadecimal ZeroTier address derived from the public key by way of a proof of work based hash function. - -## COMMANDS - -When command arguments call for a public or secret (full) identity, the identity can be specified as a path to a file or directly on the command line. - - * `help`: - Display help. (Also running with no command does this.) - - * `generate` [secret file] [public file] [vanity]: - Generate a new ZeroTier identity. If a secret file is specified, the full identity including the private key will be written to this file. If the public file is specified, the public portion will be written there. If no file paths are specified the full secret identity is output to STDOUT. The vanity prefix is a series of hexadecimal digits that the generated identity's address should start with. Typically this isn't used, and if it's specified generation can take a very long time due to the intrinsic cost of generating identities with their proof of work function. Generating an identity with a known 16-bit (4 digit) prefix on a 2.8ghz Core i5 (using one core) takes an average of two hours. - - * `validate` : - Locally validate an identity's key and proof of work function correspondence. - - * `getpublic` : - Extract the public portion of an identity.secret and print to STDOUT. - - * `sign` : - Sign a file's contents with SHA512+ECC-256 (ed25519). The signature is output in hex to STDOUT. - - * `verify` : - Verify a signature created with `sign`. - - * `mkcom` [id,value,maxdelta] [...]: - Create and sign a network membership certificate. This is not generally useful since network controllers do this automatically and is included mostly for testing purposes. - -## EXAMPLES - -Generate and dump a new identity: - - $ zerotier-idtool generate - -Generate and write a new identity, both secret and public parts: - - $ zerotier-idtool generate identity.secret identity.public - -Generate a vanity address that begins with the hex digits "beef" (this will take a while!): - - $ zerotier-idtool generate beef.secret beef.public beef - -Sign a file with an identity's secret key: - - $ zerotier-idtool sign identity.secret last_will_and_testament.txt - -Verify a file's signature with a public key: - - $ zerotier-idtool verify identity.public last_will_and_testament.txt - -## COPYRIGHT - -(c)2011-2016 ZeroTier, Inc. -- https://www.zerotier.com/ -- https://github.com/zerotier - -## SEE ALSO - -zerotier-one(8), zerotier-cli(1) diff --git a/attic/doc/zerotier-one.8 b/attic/doc/zerotier-one.8 deleted file mode 100644 index 4ad7a15d0..000000000 --- a/attic/doc/zerotier-one.8 +++ /dev/null @@ -1,104 +0,0 @@ -.TH "ZEROTIER\-ONE" "8" "December 2016" "" "" -.SH "NAME" -\fBzerotier-one\fR \- ZeroTier virtual network endpoint service -.SH SYNOPSIS -.P -\fBzerotier\-one\fP [\-switches] [working directory] -.SH DESCRIPTION -.P -\fBzerotier\-one\fR is the service/daemon responsible for connecting a Unix (Linux/BSD/OSX) system to one or more ZeroTier virtual networks and presenting those networks to the system as virtual network ports\. You can think of it as a peer to peer VPN client\. -.P -It's typically run by init systems like systemd (Linux) or launchd (Mac) rather than directly by the user, and it must be run as root unless you give it the \fB\-U\fP switch and don't plan on actually joining networks (e\.g\. to run a network controller microservice only)\. -.P -The \fBzerotier\-one\fR service keeps its state and other files in a working directory\. If this directory is not specified at launch it defaults to "/var/lib/zerotier\-one" on Linux, "/Library/Application Support/ZeroTier/One" on Mac, and "/var/db/zerotier\-one" on FreeBSD and other similar BSDs\. The working directory should persist\. It shouldn't be automatically cleaned by system cleanup daemons or stored in a volatile location\. Loss of its identity\.secret file results in loss of this system's unique 10\-digit ZeroTier address and key\. -.P -Multiple instances of \fBzerotier\-one\fR can be run on the same system as long as they are run with different primary ports (see switches) and a different working directory\. But since a single service can join any number of networks, typically there's no point in doing this\. -.P -The \fBzerotier\-one\fR service is controlled via a JSON API available at 127\.0\.0\.1: with the default primary port being 9993\. Access to this API requires an authorization token normally found in the authtoken\.secret file in the service's working directory\. On some platforms access may be guarded by other measures such as socket peer UID/GID lookup if additional security options are enabled (this is not the default)\. -.P -The first time the service is started in a fresh working directory, it generates a ZeroTier identity\. On slow systems this process can take ten seconds or more due to an anti\-DDOS/anti\-counterfeit proof of work function used by ZeroTier in address generation\. This only happens once, and once generated the result is saved in identity\.secret in the working directory\. This file represents and defines/claims your ZeroTier address and associated ECC\-256 key pair\. -.SH SWITCHES -.RS 0 -.IP \(bu 2 -\fB\-h\fP: -Display help\. -.IP \(bu 2 -\fB\-v\fP: -Display ZeroTier One version\. -.IP \(bu 2 -\fB\-U\fP: -Skip privilege check and allow to be run by non\-privileged user\. This is typically used when \fBzerotier\-one\fR is built with the network controller option included\. In this case the ZeroTier service might only be acting as a network controller and might never actually join networks, in which case it does not require elevated system permissions\. -.IP \(bu 2 -\fB\-p\fP: -Specify a different primary port\. If this is not given the default is 9993\. If zero is given a random port is chosen each time\. -.IP \(bu 2 -\fB\-d\fP: -Fork and run as a daemon\. -.IP \(bu 2 -\fB\-i\fP: -Invoke the \fBzerotier\-idtool\fR personality, in which case the binary behaves like zerotier\-idtool(1)\. This happens automatically if the name of the binary (or a symlink to it) is zerotier\-idtool\. -.IP \(bu 2 -\fB\-q\fP: -Invoke the \fBzerotier\-cli\fR personality, in which case the binary behaves like zerotier\-cli(1)\. This happens automatically if the name of the binary (or a symlink to it) is zerotier\-cli\. - -.RE -.SH EXAMPLES -.P -Run as daemon with OS default working directory and default port: -.P -.RS 2 -.nf -$ sudo zerotier\-one \-d -.fi -.RE -.P -Run as daemon with a different working directory and port: -.P -.RS 2 -.nf -$ sudo zerotier\-one \-d \-p12345 /tmp/zerotier\-working\-directory\-test -.fi -.RE -.SH FILES -.P -These are found in the service's working directory\. -.RS 0 -.IP \(bu 2 -\fBidentity\.public\fP: -The public portion of your ZeroTier identity, which is your 10\-digit hex address and the associated public key\. -.IP \(bu 2 -\fBidentity\.secret\fP: -Your full ZeroTier identity including its private key\. This file identifies the system on the network, which means you can move a ZeroTier address around by copying this file and you should back up this file if you want to save your system's static ZeroTier address\. This file must be protected, since theft of its secret key will allow anyone to impersonate your device on any network and decrypt traffic\. For network controllers this file is particularly sensitive since it constitutes the private key for a certificate authority for the controller's networks\. -.IP \(bu 2 -\fBauthtoken\.secret\fP: -The secret token used to authenticate requests to the service's local JSON API\. If it does not exist it is generated from a secure random source on service start\. To use, send it in the "X\-ZT1\-Auth" header with HTTP requests to 127\.0\.0\.1:\|\. -.IP \(bu 2 -\fBdevicemap\fP: -Remembers mappings of zt# interface numbers to ZeroTier networks so they'll persist across restarts\. On some systems that support longer interface names that can encode the network ID (such as FreeBSD) this file may not be present\. -.IP \(bu 2 -\fBzerotier\-one\.pid\fP: -ZeroTier's PID\. This file is deleted on normal shutdown\. -.IP \(bu 2 -\fBzerotier\-one\.port\fP: -ZeroTier's primary port, which is also where its JSON API is found at 127\.0\.0\.1:\|\. This file is created on startup and is read by zerotier\-cli(1) to determine where it should find the control API\. -.IP \(bu 2 -\fBcontroller\.db\fP: -If the ZeroTier One service is built with the network controller enabled, this file contains the controller's SQLite3 database\. -.IP \(bu 2 -\fBcontroller\.db\.backup\fP: -If the ZeroTier One service is built with the network controller enabled, it periodically backs up its controller\.db database in this file (currently every 5 minutes if there have been changes)\. Since this file is not a currently in use SQLite3 database it's safer to back up without corruption\. On new backups the file is rotated out rather than being rewritten in place\. -.IP \(bu 2 -\fBiddb\.d/\fP (directory): -Caches the public identity of every peer ZeroTier has spoken with in the last 60 days\. This directory and its contents can be deleted, but this may result in slower connection initations since it will require that we go out and re\-fetch full identities for peers we're speaking to\. -.IP \(bu 2 -\fBnetworks\.d\fP (directory): -This caches network configurations and certificate information for networks you belong to\. ZeroTier scans this directory for \|\.conf files on startup to recall its networks, so "touch"ing an empty \|\.conf file in this directory is a way of pre\-configuring ZeroTier to join a specific network on startup without using the API\. If the config file is empty ZeroTIer will just fetch it from the network's controller\. - -.RE -.SH COPYRIGHT -.P -(c)2011\-2016 ZeroTier, Inc\. \-\- https://www\.zerotier\.com/ \-\- https://github\.com/zerotier -.SH SEE ALSO -.P -zerotier\-cli(1), zerotier\-idtool(1) - diff --git a/attic/doc/zerotier-one.8.md b/attic/doc/zerotier-one.8.md deleted file mode 100644 index bd31d5c80..000000000 --- a/attic/doc/zerotier-one.8.md +++ /dev/null @@ -1,95 +0,0 @@ -zerotier-one(8) -- ZeroTier virtual network endpoint service -============================================================ - -## SYNOPSIS - -`zerotier-one` [-switches] [working directory] - -## DESCRIPTION - -**zerotier-one** is the service/daemon responsible for connecting a Unix (Linux/BSD/OSX) system to one or more ZeroTier virtual networks and presenting those networks to the system as virtual network ports. You can think of it as a peer to peer VPN client. - -It's typically run by init systems like systemd (Linux) or launchd (Mac) rather than directly by the user, and it must be run as root unless you give it the `-U` switch and don't plan on actually joining networks (e.g. to run a network controller microservice only). - -The **zerotier-one** service keeps its state and other files in a working directory. If this directory is not specified at launch it defaults to "/var/lib/zerotier-one" on Linux, "/Library/Application Support/ZeroTier/One" on Mac, and "/var/db/zerotier-one" on FreeBSD and other similar BSDs. The working directory should persist. It shouldn't be automatically cleaned by system cleanup daemons or stored in a volatile location. Loss of its identity.secret file results in loss of this system's unique 10-digit ZeroTier address and key. - -Multiple instances of **zerotier-one** can be run on the same system as long as they are run with different primary ports (see switches) and a different working directory. But since a single service can join any number of networks, typically there's no point in doing this. - -The **zerotier-one** service is controlled via a JSON API available at 127.0.0.1: with the default primary port being 9993. Access to this API requires an authorization token normally found in the authtoken.secret file in the service's working directory. On some platforms access may be guarded by other measures such as socket peer UID/GID lookup if additional security options are enabled (this is not the default). - -The first time the service is started in a fresh working directory, it generates a ZeroTier identity. On slow systems this process can take ten seconds or more due to an anti-DDOS/anti-counterfeit proof of work function used by ZeroTier in address generation. This only happens once, and once generated the result is saved in identity.secret in the working directory. This file represents and defines/claims your ZeroTier address and associated ECC-256 key pair. - -## SWITCHES - - * `-h`: - Display help. - - * `-v`: - Display ZeroTier One version. - - * `-U`: - Skip privilege check and allow to be run by non-privileged user. This is typically used when **zerotier-one** is built with the network controller option included. In this case the ZeroTier service might only be acting as a network controller and might never actually join networks, in which case it does not require elevated system permissions. - - * `-p`: - Specify a different primary port. If this is not given the default is 9993. If zero is given a random port is chosen each time. - - * `-d`: - Fork and run as a daemon. - - * `-i`: - Invoke the **zerotier-idtool** personality, in which case the binary behaves like zerotier-idtool(1). This happens automatically if the name of the binary (or a symlink to it) is zerotier-idtool. - - * `-q`: - Invoke the **zerotier-cli** personality, in which case the binary behaves like zerotier-cli(1). This happens automatically if the name of the binary (or a symlink to it) is zerotier-cli. - -## EXAMPLES - -Run as daemon with OS default working directory and default port: - - $ sudo zerotier-one -d - -Run as daemon with a different working directory and port: - - $ sudo zerotier-one -d -p12345 /tmp/zerotier-working-directory-test - -## FILES - -These are found in the service's working directory. - - * `identity.public`: - The public portion of your ZeroTier identity, which is your 10-digit hex address and the associated public key. - - * `identity.secret`: - Your full ZeroTier identity including its private key. This file identifies the system on the network, which means you can move a ZeroTier address around by copying this file and you should back up this file if you want to save your system's static ZeroTier address. This file must be protected, since theft of its secret key will allow anyone to impersonate your device on any network and decrypt traffic. For network controllers this file is particularly sensitive since it constitutes the private key for a certificate authority for the controller's networks. - - * `authtoken.secret`: - The secret token used to authenticate requests to the service's local JSON API. If it does not exist it is generated from a secure random source on service start. To use, send it in the "X-ZT1-Auth" header with HTTP requests to 127.0.0.1:. - - * `devicemap`: - Remembers mappings of zt# interface numbers to ZeroTier networks so they'll persist across restarts. On some systems that support longer interface names that can encode the network ID (such as FreeBSD) this file may not be present. - - * `zerotier-one.pid`: - ZeroTier's PID. This file is deleted on normal shutdown. - - * `zerotier-one.port`: - ZeroTier's primary port, which is also where its JSON API is found at 127.0.0.1:. This file is created on startup and is read by zerotier-cli(1) to determine where it should find the control API. - - * `controller.db`: - If the ZeroTier One service is built with the network controller enabled, this file contains the controller's SQLite3 database. - - * `controller.db.backup`: - If the ZeroTier One service is built with the network controller enabled, it periodically backs up its controller.db database in this file (currently every 5 minutes if there have been changes). Since this file is not a currently in use SQLite3 database it's safer to back up without corruption. On new backups the file is rotated out rather than being rewritten in place. - - * `iddb.d/` (directory): - Caches the public identity of every peer ZeroTier has spoken with in the last 60 days. This directory and its contents can be deleted, but this may result in slower connection initations since it will require that we go out and re-fetch full identities for peers we're speaking to. - - * `networks.d` (directory): - This caches network configurations and certificate information for networks you belong to. ZeroTier scans this directory for .conf files on startup to recall its networks, so "touch"ing an empty .conf file in this directory is a way of pre-configuring ZeroTier to join a specific network on startup without using the API. If the config file is empty ZeroTIer will just fetch it from the network's controller. - -## COPYRIGHT - -(c)2011-2016 ZeroTier, Inc. -- https://www.zerotier.com/ -- https://github.com/zerotier - -## SEE ALSO - -zerotier-cli(1), zerotier-idtool(1) diff --git a/attic/dockerbuild/Dockerfile.alpine b/attic/dockerbuild/Dockerfile.alpine deleted file mode 100644 index 1610ce52e..000000000 --- a/attic/dockerbuild/Dockerfile.alpine +++ /dev/null @@ -1,23 +0,0 @@ -FROM alpine:3.11.3 - -ARG go_pkg_url - -RUN apk add --update alpine-sdk linux-headers cmake openssh curl - - -RUN adduser -D -s /bin/ash jenkins && \ - passwd -u jenkins && \ - ssh-keygen -A && \ - mkdir /home/jenkins/.ssh && \ - chown -R jenkins:jenkins /home/jenkins - -RUN curl -s $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz - -COPY authorized_keys /home/jenkins/.ssh/authorized_keys -RUN chown -R jenkins:jenkins /home/jenkins/.ssh && \ - chmod 600 /home/jenkins/.ssh/authorized_keys - -EXPOSE 22 -CMD ["/usr/sbin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.centos6 b/attic/dockerbuild/Dockerfile.centos6 deleted file mode 100644 index 6b8f023ed..000000000 --- a/attic/dockerbuild/Dockerfile.centos6 +++ /dev/null @@ -1,20 +0,0 @@ -FROM centos:6 - -ARG go_pkg_url - -RUN yum update -y -RUN yum install -y curl git wget openssh-server sudo make rpmdevtools && yum clean all - -RUN curl -s $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build - -RUN echo $'\n\ - export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n'\ - >> ~/.bash_profile - -RUN mkdir /rpmbuild && chmod 777 /rpmbuild - -CMD ["/usr/sbin/sshd", "-D"] diff --git a/attic/dockerbuild/Dockerfile.centos6-i386 b/attic/dockerbuild/Dockerfile.centos6-i386 deleted file mode 100644 index c6a47072b..000000000 --- a/attic/dockerbuild/Dockerfile.centos6-i386 +++ /dev/null @@ -1,21 +0,0 @@ -FROM i386/centos:6 - -ARG go_pkg_url - -RUN echo i386 > /etc/yum/vars/basearch && echo i686 > /etc/yum/vars/arch - -RUN yum install -y curl git wget openssh-server sudo make rpmdevtools && yum clean all - -RUN curl -s $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build - -RUN echo $'\n\ - export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n'\ - >> ~/.bash_profile - -RUN mkdir /rpmbuild && chmod 777 /rpmbuild - -CMD ["/usr/sbin/sshd", "-D"] diff --git a/attic/dockerbuild/Dockerfile.centos7 b/attic/dockerbuild/Dockerfile.centos7 deleted file mode 100644 index 71bc492a3..000000000 --- a/attic/dockerbuild/Dockerfile.centos7 +++ /dev/null @@ -1,32 +0,0 @@ -FROM centos:7 - -ARG go_pkg_url - -RUN yum install -y epel-release -RUN yum install -y curl git wget openssh-server sudo make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel centos-release-scl devtoolset-8 llvm-toolset-7 openssl-devel && yum clean all - -RUN curl -sL https://github.com/Kitware/CMake/releases/download/v3.16.3/cmake-3.16.3.tar.gz -o cmake.tar.gz && \ - tar -xzf cmake.tar.gz && \ - cd cmake-3.16.3 && \ - ./bootstrap && \ - make -j4 && \ - make install - -RUN curl -s $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN wget -qO- "https://cmake.org/files/v3.15/cmake-3.15.1-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C /usr/local - -RUN /usr/bin/ssh-keygen -A -RUN useradd jenkins-build - -RUN echo $'\n\ - export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n\ - source scl_source enable devtoolset-8 llvm-toolset-7\n'\ - >> ~/.bash_profile - -RUN mkdir /rpmbuild && chmod 777 /rpmbuild - -CMD ["/usr/sbin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.centos7-i386 b/attic/dockerbuild/Dockerfile.centos7-i386 deleted file mode 100644 index 763615972..000000000 --- a/attic/dockerbuild/Dockerfile.centos7-i386 +++ /dev/null @@ -1,29 +0,0 @@ -FROM centos:7 - -ARG go_pkg_url - -RUN yum install -y curl git wget openssh-server sudo make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel openssl-devel && yum clean all - -RUN curl -sL https://github.com/Kitware/CMake/releases/download/v3.16.3/cmake-3.16.3.tar.gz -o cmake.tar.gz && \ - tar -xzf cmake.tar.gz && \ - cd cmake-3.16.3 && \ - ./bootstrap && \ - make -j4 && \ - make install - -RUN curl -s $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN /usr/bin/ssh-keygen -A - -RUN useradd jenkins-build - -RUN echo $'\n\ - export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n'\ - >> ~/.bash_profile - -RUN mkdir /rpmbuild && chmod 777 /rpmbuild - -CMD ["/usr/sbin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.centos8 b/attic/dockerbuild/Dockerfile.centos8 deleted file mode 100644 index c4f0ee9d7..000000000 --- a/attic/dockerbuild/Dockerfile.centos8 +++ /dev/null @@ -1,25 +0,0 @@ -FROM centos:8 - -ARG go_pkg_url - -RUN yum install -y epel-release -RUN yum install -y curl git wget openssh-server sudo make rpmdevtools clang gcc-c++ ruby ruby-devel cmake && yum clean all - -RUN curl -s $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN wget -qO- "https://cmake.org/files/v3.15/cmake-3.15.1-Linux-x86_64.tar.gz" | tar --strip-components=1 -xz -C /usr/local - -RUN /usr/bin/ssh-keygen -A -RUN useradd jenkins-build - -RUN echo $'\n\ - export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n\ - source scl_source enable devtoolset-8 llvm-toolset-7\n'\ - >> ~/.bash_profile - -RUN mkdir /rpmbuild && chmod 777 /rpmbuild - -CMD ["/usr/sbin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.clefos-s390x b/attic/dockerbuild/Dockerfile.clefos-s390x deleted file mode 100644 index f473a89c9..000000000 --- a/attic/dockerbuild/Dockerfile.clefos-s390x +++ /dev/null @@ -1,26 +0,0 @@ -FROM s390x/clefos:7 - -ARG go_pkg_url - -RUN yum install -y curl git wget openssh-server sudo make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel openssl-devel && yum clean all -RUN curl -sL https://github.com/Kitware/CMake/releases/download/v3.16.3/cmake-3.16.3.tar.gz -o cmake.tar.gz && \ - tar -xzf cmake.tar.gz && \ - cd cmake-3.16.3 && \ - ./bootstrap && \ - make -j4 && \ - make install - -RUN curl -s $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN /usr/bin/ssh-keygen -A - -RUN echo $'\n\ - export PATH=$PATH:/usr/local/go/bin:$HOME/go/bin\n'\ - >> ~/.bash_profile - -RUN mkdir /rpmbuild && chmod 777 /rpmbuild - -CMD ["/usr/sbin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.debian-bullseye b/attic/dockerbuild/Dockerfile.debian-bullseye deleted file mode 100644 index 9fc07b015..000000000 --- a/attic/dockerbuild/Dockerfile.debian-bullseye +++ /dev/null @@ -1,15 +0,0 @@ -FROM debian:bullseye-20191224 - -ARG go_pkg_url - -RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd cmake - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.debian-buster b/attic/dockerbuild/Dockerfile.debian-buster deleted file mode 100644 index 42d0b21d9..000000000 --- a/attic/dockerbuild/Dockerfile.debian-buster +++ /dev/null @@ -1,15 +0,0 @@ -FROM debian:buster-20191224 - -ARG go_pkg_url - -RUN apt-get update && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd cmake - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.debian-jessie b/attic/dockerbuild/Dockerfile.debian-jessie deleted file mode 100644 index d034bbf6d..000000000 --- a/attic/dockerbuild/Dockerfile.debian-jessie +++ /dev/null @@ -1,22 +0,0 @@ -FROM debian:jessie-20191224 - -ARG go_pkg_url - -RUN apt-get update && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd libssl-dev - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN curl -sL https://github.com/Kitware/CMake/releases/download/v3.16.3/cmake-3.16.3.tar.gz -o cmake.tar.gz && \ - tar -xzf cmake.tar.gz && \ - cd cmake-3.16.3 && \ - ./bootstrap && \ - make -j4 && \ - make install - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.debian-sid b/attic/dockerbuild/Dockerfile.debian-sid deleted file mode 100644 index 0d5b9b15a..000000000 --- a/attic/dockerbuild/Dockerfile.debian-sid +++ /dev/null @@ -1,15 +0,0 @@ -FROM debian:sid-20191224 - -ARG go_pkg_url - -RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd cmake - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.debian-stretch b/attic/dockerbuild/Dockerfile.debian-stretch deleted file mode 100644 index 75ca1f4ff..000000000 --- a/attic/dockerbuild/Dockerfile.debian-stretch +++ /dev/null @@ -1,22 +0,0 @@ -FROM debian:stretch-20191224 - -ARG go_pkg_url - -RUN apt-get update && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd libssl-dev - -RUN curl -sL https://github.com/Kitware/CMake/releases/download/v3.16.3/cmake-3.16.3.tar.gz -o cmake.tar.gz && \ - tar -xzf cmake.tar.gz && \ - cd cmake-3.16.3 && \ - ./bootstrap && \ - make -j4 && \ - make install - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.debian-wheezy b/attic/dockerbuild/Dockerfile.debian-wheezy deleted file mode 100644 index 7322959e6..000000000 --- a/attic/dockerbuild/Dockerfile.debian-wheezy +++ /dev/null @@ -1,23 +0,0 @@ -FROM debian:wheezy-20190228 - -ARG go_pkg_url - -RUN echo "deb http://archive.debian.org/debian/ wheezy contrib main non-free" > /etc/apt/sources.list && \ - echo "deb-src http://archive.debian.org/debian/ wheezy contrib main non-free" >> /etc/apt/sources.list && \ - apt-get update && apt-get install -y apt-utils && \ - apt-get install -y --force-yes \ - curl gcc make sudo expect gnupg fakeroot perl-base=5.14.2-21+deb7u3 perl \ - libc-bin=2.13-38+deb7u10 libc6=2.13-38+deb7u10 libc6-dev build-essential \ - cdbs devscripts equivs automake autoconf libtool libaudit-dev selinux-basics \ - libdb5.1=5.1.29-5 libdb5.1-dev libssl1.0.0=1.0.1e-2+deb7u20 procps gawk libsigsegv2 \ - curl ca-certificates devscripts - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.kali-rolling b/attic/dockerbuild/Dockerfile.kali-rolling deleted file mode 100644 index 2825dffe4..000000000 --- a/attic/dockerbuild/Dockerfile.kali-rolling +++ /dev/null @@ -1,15 +0,0 @@ -FROM kalilinux/kali-rolling:latest - -ARG go_pkg_url - -RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd cmake - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.ubuntu-bionic b/attic/dockerbuild/Dockerfile.ubuntu-bionic deleted file mode 100644 index bfb640dfe..000000000 --- a/attic/dockerbuild/Dockerfile.ubuntu-bionic +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:bionic-20200112 - -ARG go_pkg_url - -RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd cmake - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.ubuntu-eoan b/attic/dockerbuild/Dockerfile.ubuntu-eoan deleted file mode 100644 index d30c0c0de..000000000 --- a/attic/dockerbuild/Dockerfile.ubuntu-eoan +++ /dev/null @@ -1,15 +0,0 @@ -FROM ubuntu:eoan-20200114 - -ARG go_pkg_url - -RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd cmake - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.ubuntu-trusty b/attic/dockerbuild/Dockerfile.ubuntu-trusty deleted file mode 100644 index 038332353..000000000 --- a/attic/dockerbuild/Dockerfile.ubuntu-trusty +++ /dev/null @@ -1,22 +0,0 @@ -FROM ubuntu:trusty-20191217 - -ARG go_pkg_url - -RUN apt-get update && apt-get upgrade -y && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd libssl-dev - -RUN curl -sL https://github.com/Kitware/CMake/releases/download/v3.16.3/cmake-3.16.3.tar.gz -o cmake.tar.gz && \ - tar -xzf cmake.tar.gz && \ - cd cmake-3.16.3 && \ - ./bootstrap && \ - make -j4 && \ - make install - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Dockerfile.ubuntu-xenial b/attic/dockerbuild/Dockerfile.ubuntu-xenial deleted file mode 100644 index 58191d8a4..000000000 --- a/attic/dockerbuild/Dockerfile.ubuntu-xenial +++ /dev/null @@ -1,22 +0,0 @@ -FROM ubuntu:xenial-20200114 - -ARG go_pkg_url - -RUN apt-get update && apt-get -y install build-essential curl ca-certificates devscripts dh-systemd - -RUN curl -sL https://github.com/Kitware/CMake/releases/download/v3.16.3/cmake-3.16.3.tar.gz -o cmake.tar.gz && \ - tar -xzf cmake.tar.gz && \ - cd cmake-3.16.3 && \ - ./bootstrap && \ - make -j4 && \ - make install - -RUN curl -s -k $go_pkg_url -o go.tar.gz && \ - tar -C /usr/local -xzf go.tar.gz && \ - rm go.tar.gz - -RUN groupadd -g 1000 jenkins-build && useradd -u 1000 -g 1000 jenkins-build -RUN chmod 777 /home - -CMD ["/usr/bin/sshd", "-D"] - diff --git a/attic/dockerbuild/Makefile b/attic/dockerbuild/Makefile deleted file mode 100644 index 1d6939f36..000000000 --- a/attic/dockerbuild/Makefile +++ /dev/null @@ -1,111 +0,0 @@ -.PHONY: all - -all: alpine centos clefos debian ubuntu kali-rolling - -alpine: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.alpine . -t ztbuild/alpine-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.alpine . -t ztbuild/alpine-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.alpine . -t ztbuild/alpine-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.alpine . -t ztbuild/alpine-armel --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.alpine . -t ztbuild/alpine-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.alpine . -t ztbuild/alpine-ppc64le --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.alpine . -t ztbuild/alpine-s390x --load - -centos: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.centos7 . -t ztbuild/centos7-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.centos7-i386 . -t ztbuild/centos7-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.centos6 . -t ztbuild/centos6-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.centos6-i386 . -t ztbuild/centos6-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.centos8 . -t ztbuild/centos8-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.centos8 . -t ztbuild/centos8-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.centos8 . -t ztbuild/centos8-ppc64le --load - -clefos: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.clefos-s390x . -t ztbuild/clefos-s390x --load - -debian: debian-wheezy debian-jessie debian-buster debian-stretch debian-bullseye debian-sid - -debian-wheezy: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-wheezy . -t ztbuild/debian-wheezy-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-wheezy . -t ztbuild/debian-wheezy-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-wheezy . -t ztbuild/debian-wheezy-armel --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-wheezy . -t ztbuild/debian-wheezy-i386 --load - -debian-jessie: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-jessie . -t ztbuild/debian-jessie-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-jessie . -t ztbuild/debian-jessie-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-jessie . -t ztbuild/debian-jessie-armel --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-jessie . -t ztbuild/debian-jessie-i386 --load - -debian-buster: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-armel --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-buster . -t ztbuild/debian-buster-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.debian-buster . -t ztbuild/debian-buster-ppc64le --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.debian-buster . -t ztbuild/debian-buster-s390x --load - -debian-stretch: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-armel --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-ppc64le --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.debian-stretch . -t ztbuild/debian-stretch-s390x --load - -debian-bullseye: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-armel --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-ppc64le --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.debian-bullseye . -t ztbuild/debian-bullseye-s390x --load - -debian-sid: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v6 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-armel --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.debian-sid . -t ztbuild/debian-sid-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.debian-sid . -t ztbuild/debian-sid-ppc64le --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.debian-sid . -t ztbuild/debian-sid-s390x --load - -ubuntu: ubuntu-trusty ubuntu-xenial ubuntu-bionic ubuntu-eoan - -ubuntu-trusty: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.ubuntu-trusty . -t ztbuild/ubuntu-trusty-ppc64le --load - -ubuntu-xenial: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-ppc64le --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.ubuntu-xenial . -t ztbuild/ubuntu-xenial-s390x --load - -ubuntu-bionic: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-ppc64le --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.ubuntu-bionic . -t ztbuild/ubuntu-bionic-s390x --load - -ubuntu-eoan: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-amd64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-arm64.tar.gz" --platform linux/arm64 -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-arm64 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-armv6l.tar.gz" --platform linux/arm/v7 -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-armhf --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-386.tar.gz" --platform linux/386 -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-i386 --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-ppc64le.tar.gz" --platform linux/ppc64le -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-ppc64le --load - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-s390x.tar.gz" --platform linux/s390x -f Dockerfile.ubuntu-eoan . -t ztbuild/ubuntu-eoan-s390x --load - -kali-rolling: - @docker buildx build --build-arg go_pkg_url="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" --platform linux/amd64 -f Dockerfile.kali-rolling . -t ztbuild/kali-rolling-amd64 --load - diff --git a/attic/dockerbuild/authorized_keys b/attic/dockerbuild/authorized_keys deleted file mode 100644 index 0dd35c7b7..000000000 --- a/attic/dockerbuild/authorized_keys +++ /dev/null @@ -1,2 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC8hgysbj2Luu3aN/Ya2wr4Y9LpUGqWWfn3k+UhIwOIE/Kd7/YpLjxHpseUA1hLnj9kHFShH8eiqoY0S6EDIYrTUwbXMMu8454lX/LcJOCJ9RlSeMMf7vpkxcI7cVRgOA430a3FR7M0Q8vKlyJzxxAEjMIxMyuVyinknfanNt+sQFiDUvOXoacqgZAHBWMlO7wOPyHWHNOzy7g8N0dHiJveKZqX/UUwuqJuS6UBq7MBMSU6TcMvJwHr+AbNvfyIUWCqlTByqFL9cmviRbIvQanxoRxi/5fVUGhtVBXUYvbCdFxDw5W2Svo9fDMm4Z5xWAD7rY1J3AM15RVyRTTtYvgD - diff --git a/attic/dockerbuild/pipelint.sh b/attic/dockerbuild/pipelint.sh deleted file mode 100644 index 7fbd0de82..000000000 --- a/attic/dockerbuild/pipelint.sh +++ /dev/null @@ -1,13 +0,0 @@ -# curl (REST API) -# User -JENKINS_USER=grant - -# Api key from "/me/configure" on my Jenkins instance -JENKINS_USER_KEY=11edf2d49321321119712c46c6349eaad7 - -# Url for my local Jenkins instance. -JENKINS_URL=http://$JENKINS_USER:$JENKINS_USER_KEY@jenkins.int.zerotier.com - -# JENKINS_CRUMB is needed if your Jenkins master has CRSF protection enabled (which it should) -JENKINS_CRUMB=`curl "$JENKINS_URL/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,\":\",//crumb)"` -curl -X POST -H $JENKINS_CRUMB -F "jenkinsfile=\AppData\Local\Android\sdk\platforms\android-21) diff --git a/attic/java/build.xml b/attic/java/build.xml deleted file mode 100644 index 4604ad66e..000000000 --- a/attic/java/build.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/attic/java/jni/Android.mk b/attic/java/jni/Android.mk deleted file mode 100644 index 346b337af..000000000 --- a/attic/java/jni/Android.mk +++ /dev/null @@ -1,52 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := ZeroTierOneJNI -LOCAL_C_INCLUDES := \ - $(ZT1)/include \ - $(ZT1)/node \ - $(ZT1)/osdep - -LOCAL_LDLIBS := -llog -# LOCAL_CFLAGS := -g - -LOCAL_CFLAGS := -DZT_USE_MINIUPNPC - -# ZeroTierOne SDK source files -LOCAL_SRC_FILES := \ - $(ZT1)/node/C25519.cpp \ - $(ZT1)/node/Capability.cpp \ - $(ZT1)/node/MembershipCredential.cpp \ - $(ZT1)/node/OwnershipCredential.cpp \ - $(ZT1)/node/Identity.cpp \ - $(ZT1)/node/IncomingPacket.cpp \ - $(ZT1)/node/InetAddress.cpp \ - $(ZT1)/node/Membership.cpp \ - $(ZT1)/node/Multicaster.cpp \ - $(ZT1)/node/Network.cpp \ - $(ZT1)/node/NetworkConfig.cpp \ - $(ZT1)/node/Node.cpp \ - $(ZT1)/node/OutboundMulticast.cpp \ - $(ZT1)/node/Packet.cpp \ - $(ZT1)/node/Path.cpp \ - $(ZT1)/node/Peer.cpp \ - $(ZT1)/node/Poly1305.cpp \ - $(ZT1)/node/Revocation.cpp \ - $(ZT1)/node/Salsa20.cpp \ - $(ZT1)/node/SelfAwareness.cpp \ - $(ZT1)/node/SHA512.cpp \ - $(ZT1)/node/Switch.cpp \ - $(ZT1)/node/Tag.cpp \ - $(ZT1)/node/Topology.cpp \ - $(ZT1)/node/Trace.cpp \ - $(ZT1)/node/Utils.cpp \ - $(ZT1)/osdep/OSUtils.cpp - -# JNI Files -LOCAL_SRC_FILES += \ - com_zerotierone_sdk_Node.cpp \ - ZT_jniutils.cpp \ - ZT_jnilookup.cpp - -include $(BUILD_SHARED_LIBRARY) \ No newline at end of file diff --git a/attic/java/jni/Application.mk b/attic/java/jni/Application.mk deleted file mode 100644 index 4fc50f73d..000000000 --- a/attic/java/jni/Application.mk +++ /dev/null @@ -1,5 +0,0 @@ -# NDK_TOOLCHAIN_VERSION := clang3.5 -APP_STL := c++_static -APP_CPPFLAGS := -Wall -fstack-protector -fexceptions -fno-strict-aliasing -frtti -Wno-deprecated-register -DZT_NO_TYPE_PUNNING=1 -APP_PLATFORM := android-14 -APP_ABI := all diff --git a/attic/java/jni/ZT_jnilookup.cpp b/attic/java/jni/ZT_jnilookup.cpp deleted file mode 100644 index be52a3666..000000000 --- a/attic/java/jni/ZT_jnilookup.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include "ZT_jnilookup.h" -#include "ZT_jniutils.h" - -JniLookup::JniLookup() - : m_jvm(NULL) -{ - LOGV("JNI Cache Created"); -} - -JniLookup::JniLookup(JavaVM *jvm) - : m_jvm(jvm) -{ - LOGV("JNI Cache Created"); -} - -JniLookup::~JniLookup() -{ - LOGV("JNI Cache Destroyed"); -} - - -void JniLookup::setJavaVM(JavaVM *jvm) -{ - LOGV("Assigned JVM to object"); - m_jvm = jvm; -} - - -jclass JniLookup::findClass(const std::string &name) -{ - if(!m_jvm) - return NULL; - - // get the class from the JVM - JNIEnv *env = NULL; - if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) - { - LOGE("Error retreiving JNI Environment"); - return NULL; - } - - jclass cls = env->FindClass(name.c_str()); - if(env->ExceptionCheck()) - { - LOGE("Error finding class: %s", name.c_str()); - return NULL; - } - - return cls; -} - - -jmethodID JniLookup::findMethod(jclass cls, const std::string &methodName, const std::string &methodSig) -{ - if(!m_jvm) - return NULL; - - JNIEnv *env = NULL; - if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) - { - return NULL; - } - - jmethodID mid = env->GetMethodID(cls, methodName.c_str(), methodSig.c_str()); - if(env->ExceptionCheck()) - { - return NULL; - } - - return mid; -} - -jmethodID JniLookup::findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig) -{ - if(!m_jvm) - return NULL; - - JNIEnv *env = NULL; - if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) - { - return NULL; - } - - jmethodID mid = env->GetStaticMethodID(cls, methodName.c_str(), methodSig.c_str()); - if(env->ExceptionCheck()) - { - return NULL; - } - - return mid; -} - -jfieldID JniLookup::findField(jclass cls, const std::string &fieldName, const std::string &typeStr) -{ - if(!m_jvm) - return NULL; - - JNIEnv *env = NULL; - if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) - { - return NULL; - } - - jfieldID fid = env->GetFieldID(cls, fieldName.c_str(), typeStr.c_str()); - if(env->ExceptionCheck()) - { - return NULL; - } - - return fid; -} - -jfieldID JniLookup::findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr) -{ - if(!m_jvm) - return NULL; - - JNIEnv *env = NULL; - if(m_jvm->GetEnv((void**)&env, JNI_VERSION_1_6) != JNI_OK) - { - return NULL; - } - - jfieldID fid = env->GetStaticFieldID(cls, fieldName.c_str(), typeStr.c_str()); - if(env->ExceptionCheck()) - { - return NULL; - } - - return fid; -} \ No newline at end of file diff --git a/attic/java/jni/ZT_jnilookup.h b/attic/java/jni/ZT_jnilookup.h deleted file mode 100644 index f5bd97d7d..000000000 --- a/attic/java/jni/ZT_jnilookup.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#ifndef ZT_JNILOOKUP_H_ -#define ZT_JNILOOKUP_H_ - -#include -#include -#include - - - -class JniLookup { -public: - JniLookup(); - JniLookup(JavaVM *jvm); - ~JniLookup(); - - void setJavaVM(JavaVM *jvm); - - jclass findClass(const std::string &name); - jmethodID findMethod(jclass cls, const std::string &methodName, const std::string &methodSig); - jmethodID findStaticMethod(jclass cls, const std::string &methodName, const std::string &methodSig); - jfieldID findField(jclass cls, const std::string &fieldName, const std::string &typeStr); - jfieldID findStaticField(jclass cls, const std::string &fieldName, const std::string &typeStr); -private: - JavaVM *m_jvm; -}; - -#endif \ No newline at end of file diff --git a/attic/java/jni/ZT_jniutils.cpp b/attic/java/jni/ZT_jniutils.cpp deleted file mode 100644 index c52a2066b..000000000 --- a/attic/java/jni/ZT_jniutils.cpp +++ /dev/null @@ -1,944 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 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 . - */ - -#include "ZT_jniutils.h" -#include "ZT_jnilookup.h" -#include -#include - -extern JniLookup lookup; - -#ifdef __cplusplus -extern "C" { -#endif - -jobject createResultObject(JNIEnv *env, ZT_ResultCode code) -{ - jclass resultClass = NULL; - - jobject resultObject = NULL; - - resultClass = lookup.findClass("com/zerotier/sdk/ResultCode"); - if(resultClass == NULL) - { - LOGE("Couldnt find ResultCode class"); - return NULL; // exception thrown - } - - std::string fieldName; - switch(code) - { - case ZT_RESULT_OK: - LOGV("ZT_RESULT_OK"); - fieldName = "RESULT_OK"; - break; - case ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY: - LOGV("ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY"); - fieldName = "RESULT_FATAL_ERROR_OUT_OF_MEMORY"; - break; - case ZT_RESULT_FATAL_ERROR_DATA_STORE_FAILED: - LOGV("RESULT_FATAL_ERROR_DATA_STORE_FAILED"); - fieldName = "RESULT_FATAL_ERROR_DATA_STORE_FAILED"; - break; - case ZT_RESULT_ERROR_NETWORK_NOT_FOUND: - LOGV("RESULT_FATAL_ERROR_DATA_STORE_FAILED"); - fieldName = "RESULT_ERROR_NETWORK_NOT_FOUND"; - break; - case ZT_RESULT_FATAL_ERROR_INTERNAL: - default: - LOGV("RESULT_FATAL_ERROR_DATA_STORE_FAILED"); - fieldName = "RESULT_FATAL_ERROR_INTERNAL"; - break; - } - - jfieldID enumField = lookup.findStaticField(resultClass, fieldName.c_str(), "Lcom/zerotier/sdk/ResultCode;"); - if(env->ExceptionCheck() || enumField == NULL) - { - LOGE("Error on FindStaticField"); - return NULL; - } - - resultObject = env->GetStaticObjectField(resultClass, enumField); - if(env->ExceptionCheck() || resultObject == NULL) - { - LOGE("Error on GetStaticObjectField"); - } - return resultObject; -} - - -jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status) -{ - jobject statusObject = NULL; - - jclass statusClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkStatus"); - if(statusClass == NULL) - { - return NULL; // exception thrown - } - - std::string fieldName; - switch(status) - { - case ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION: - fieldName = "NETWORK_STATUS_REQUESTING_CONFIGURATION"; - break; - case ZT_NETWORK_STATUS_OK: - fieldName = "NETWORK_STATUS_OK"; - break; - case ZT_NETWORK_STATUS_ACCESS_DENIED: - fieldName = "NETWORK_STATUS_ACCESS_DENIED"; - break; - case ZT_NETWORK_STATUS_NOT_FOUND: - fieldName = "NETWORK_STATUS_NOT_FOUND"; - break; - case ZT_NETWORK_STATUS_PORT_ERROR: - fieldName = "NETWORK_STATUS_PORT_ERROR"; - break; - case ZT_NETWORK_STATUS_CLIENT_TOO_OLD: - fieldName = "NETWORK_STATUS_CLIENT_TOO_OLD"; - break; - } - - jfieldID enumField = lookup.findStaticField(statusClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkStatus;"); - - statusObject = env->GetStaticObjectField(statusClass, enumField); - - return statusObject; -} - -jobject createEvent(JNIEnv *env, ZT_Event event) -{ - jclass eventClass = NULL; - jobject eventObject = NULL; - - eventClass = lookup.findClass("com/zerotier/sdk/Event"); - if(eventClass == NULL) - { - return NULL; - } - - std::string fieldName; - switch(event) - { - case ZT_EVENT_UP: - fieldName = "EVENT_UP"; - break; - case ZT_EVENT_OFFLINE: - fieldName = "EVENT_OFFLINE"; - break; - case ZT_EVENT_ONLINE: - fieldName = "EVENT_ONLINE"; - break; - case ZT_EVENT_DOWN: - fieldName = "EVENT_DOWN"; - break; - case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: - fieldName = "EVENT_FATAL_ERROR_IDENTITY_COLLISION"; - break; - case ZT_EVENT_TRACE: - fieldName = "EVENT_TRACE"; - break; - case ZT_EVENT_USER_MESSAGE: - break; - case ZT_EVENT_REMOTE_TRACE: - default: - break; - } - - jfieldID enumField = lookup.findStaticField(eventClass, fieldName.c_str(), "Lcom/zerotier/sdk/Event;"); - - eventObject = env->GetStaticObjectField(eventClass, enumField); - - return eventObject; -} - -jobject createPeerRole(JNIEnv *env, ZT_PeerRole role) -{ - jclass peerRoleClass = NULL; - jobject peerRoleObject = NULL; - - peerRoleClass = lookup.findClass("com/zerotier/sdk/PeerRole"); - if(peerRoleClass == NULL) - { - return NULL; - } - - std::string fieldName; - switch(role) - { - case ZT_PEER_ROLE_LEAF: - fieldName = "PEER_ROLE_LEAF"; - break; - case ZT_PEER_ROLE_MOON: - fieldName = "PEER_ROLE_MOON"; - break; - case ZT_PEER_ROLE_PLANET: - fieldName = "PEER_ROLE_PLANET"; - break; - } - - jfieldID enumField = lookup.findStaticField(peerRoleClass, fieldName.c_str(), "Lcom/zerotier/sdk/PeerRole;"); - - peerRoleObject = env->GetStaticObjectField(peerRoleClass, enumField); - - return peerRoleObject; -} - -jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type) -{ - jclass vntypeClass = NULL; - jobject vntypeObject = NULL; - - vntypeClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkType"); - if(env->ExceptionCheck() || vntypeClass == NULL) - { - return NULL; - } - - std::string fieldName; - switch(type) - { - case ZT_NETWORK_TYPE_PRIVATE: - fieldName = "NETWORK_TYPE_PRIVATE"; - break; - case ZT_NETWORK_TYPE_PUBLIC: - fieldName = "NETWORK_TYPE_PUBLIC"; - break; - } - - jfieldID enumField = lookup.findStaticField(vntypeClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkType;"); - vntypeObject = env->GetStaticObjectField(vntypeClass, enumField); - return vntypeObject; -} - -jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT_VirtualNetworkConfigOperation op) -{ - jclass vnetConfigOpClass = NULL; - jobject vnetConfigOpObject = NULL; - - vnetConfigOpClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfigOperation"); - if(env->ExceptionCheck() || vnetConfigOpClass == NULL) - { - return NULL; - } - - std::string fieldName; - switch(op) - { - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP: - fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_UP"; - break; - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE: - fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE"; - break; - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN: - fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN"; - break; - case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY: - fieldName = "VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY"; - break; - } - - jfieldID enumField = lookup.findStaticField(vnetConfigOpClass, fieldName.c_str(), "Lcom/zerotier/sdk/VirtualNetworkConfigOperation;"); - vnetConfigOpObject = env->GetStaticObjectField(vnetConfigOpClass, enumField); - return vnetConfigOpObject; -} - -jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr) -{ - LOGV("newInetAddress"); - jclass inetAddressClass = NULL; - jmethodID inetAddress_getByAddress = NULL; - - inetAddressClass = lookup.findClass("java/net/InetAddress"); - if(env->ExceptionCheck() || inetAddressClass == NULL) - { - LOGE("Error finding InetAddress class"); - return NULL; - } - - inetAddress_getByAddress = lookup.findStaticMethod( - inetAddressClass, "getByAddress", "([B)Ljava/net/InetAddress;"); - if(env->ExceptionCheck() || inetAddress_getByAddress == NULL) - { - LOGE("Erorr finding getByAddress() static method"); - return NULL; - } - - jobject inetAddressObj = NULL; - switch(addr.ss_family) - { - case AF_INET6: - { - sockaddr_in6 *ipv6 = (sockaddr_in6*)&addr; - jbyteArray buff = env->NewByteArray(16); - if(buff == NULL) - { - LOGE("Error creating IPV6 byte array"); - return NULL; - } - - env->SetByteArrayRegion(buff, 0, 16, (jbyte*)ipv6->sin6_addr.s6_addr); - inetAddressObj = env->CallStaticObjectMethod( - inetAddressClass, inetAddress_getByAddress, buff); - } - break; - case AF_INET: - { - sockaddr_in *ipv4 = (sockaddr_in*)&addr; - jbyteArray buff = env->NewByteArray(4); - if(buff == NULL) - { - LOGE("Error creating IPV4 byte array"); - return NULL; - } - - env->SetByteArrayRegion(buff, 0, 4, (jbyte*)&ipv4->sin_addr); - inetAddressObj = env->CallStaticObjectMethod( - inetAddressClass, inetAddress_getByAddress, buff); - } - break; - } - if(env->ExceptionCheck() || inetAddressObj == NULL) { - LOGE("Error creating InetAddress object"); - return NULL; - } - - return inetAddressObj; -} - -jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr) -{ - LOGV("newInetSocketAddress Called"); - jclass inetSocketAddressClass = NULL; - jmethodID inetSocketAddress_constructor = NULL; - - inetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress"); - if(env->ExceptionCheck() || inetSocketAddressClass == NULL) - { - LOGE("Error finding InetSocketAddress Class"); - return NULL; - } - - jobject inetAddressObject = NULL; - - if(addr.ss_family != 0) - { - inetAddressObject = newInetAddress(env, addr); - - if(env->ExceptionCheck() || inetAddressObject == NULL) - { - LOGE("Error creating new inet address"); - return NULL; - } - } - else - { - return NULL; - } - - inetSocketAddress_constructor = lookup.findMethod( - inetSocketAddressClass, "", "(Ljava/net/InetAddress;I)V"); - if(env->ExceptionCheck() || inetSocketAddress_constructor == NULL) - { - LOGE("Error finding InetSocketAddress constructor"); - return NULL; - } - - int port = 0; - switch(addr.ss_family) - { - case AF_INET6: - { - LOGV("IPV6 Address"); - sockaddr_in6 *ipv6 = (sockaddr_in6*)&addr; - port = ntohs(ipv6->sin6_port); - LOGV("Port %d", port); - } - break; - case AF_INET: - { - LOGV("IPV4 Address"); - sockaddr_in *ipv4 = (sockaddr_in*)&addr; - port = ntohs(ipv4->sin_port); - LOGV("Port: %d", port); - } - break; - default: - { - break; - } - } - - - jobject inetSocketAddressObject = env->NewObject(inetSocketAddressClass, inetSocketAddress_constructor, inetAddressObject, port); - if(env->ExceptionCheck() || inetSocketAddressObject == NULL) { - LOGE("Error creating InetSocketAddress object"); - } - return inetSocketAddressObject; -} - -jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp) -{ - LOGV("newPeerPhysicalPath Called"); - jclass pppClass = NULL; - - jfieldID addressField = NULL; - jfieldID lastSendField = NULL; - jfieldID lastReceiveField = NULL; - jfieldID preferredField = NULL; - - jmethodID ppp_constructor = NULL; - - pppClass = lookup.findClass("com/zerotier/sdk/PeerPhysicalPath"); - if(env->ExceptionCheck() || pppClass == NULL) - { - LOGE("Error finding PeerPhysicalPath class"); - return NULL; - } - - addressField = lookup.findField(pppClass, "address", "Ljava/net/InetSocketAddress;"); - if(env->ExceptionCheck() || addressField == NULL) - { - LOGE("Error finding address field"); - return NULL; - } - - lastSendField = lookup.findField(pppClass, "lastSend", "J"); - if(env->ExceptionCheck() || lastSendField == NULL) - { - LOGE("Error finding lastSend field"); - return NULL; - } - - lastReceiveField = lookup.findField(pppClass, "lastReceive", "J"); - if(env->ExceptionCheck() || lastReceiveField == NULL) - { - LOGE("Error finding lastReceive field"); - return NULL; - } - - preferredField = lookup.findField(pppClass, "preferred", "Z"); - if(env->ExceptionCheck() || preferredField == NULL) - { - LOGE("Error finding preferred field"); - return NULL; - } - - ppp_constructor = lookup.findMethod(pppClass, "", "()V"); - if(env->ExceptionCheck() || ppp_constructor == NULL) - { - LOGE("Error finding PeerPhysicalPath constructor"); - return NULL; - } - - jobject pppObject = env->NewObject(pppClass, ppp_constructor); - if(env->ExceptionCheck() || pppObject == NULL) - { - LOGE("Error creating PPP object"); - return NULL; // out of memory - } - - jobject addressObject = newInetSocketAddress(env, ppp.address); - if(env->ExceptionCheck() || addressObject == NULL) { - LOGE("Error creating InetSocketAddress object"); - return NULL; - } - - env->SetObjectField(pppObject, addressField, addressObject); - env->SetLongField(pppObject, lastSendField, ppp.lastSend); - env->SetLongField(pppObject, lastReceiveField, ppp.lastReceive); - env->SetBooleanField(pppObject, preferredField, ppp.preferred); - - if(env->ExceptionCheck()) { - LOGE("Exception assigning fields to PeerPhysicalPath object"); - } - - return pppObject; -} - -jobject newPeer(JNIEnv *env, const ZT_Peer &peer) -{ - LOGV("newPeer called"); - - jclass peerClass = NULL; - - jfieldID addressField = NULL; - jfieldID versionMajorField = NULL; - jfieldID versionMinorField = NULL; - jfieldID versionRevField = NULL; - jfieldID latencyField = NULL; - jfieldID roleField = NULL; - jfieldID pathsField = NULL; - - jmethodID peer_constructor = NULL; - - peerClass = lookup.findClass("com/zerotier/sdk/Peer"); - if(env->ExceptionCheck() || peerClass == NULL) - { - LOGE("Error finding Peer class"); - return NULL; - } - - addressField = lookup.findField(peerClass, "address", "J"); - if(env->ExceptionCheck() || addressField == NULL) - { - LOGE("Error finding address field of Peer object"); - return NULL; - } - - versionMajorField = lookup.findField(peerClass, "versionMajor", "I"); - if(env->ExceptionCheck() || versionMajorField == NULL) - { - LOGE("Error finding versionMajor field of Peer object"); - return NULL; - } - - versionMinorField = lookup.findField(peerClass, "versionMinor", "I"); - if(env->ExceptionCheck() || versionMinorField == NULL) - { - LOGE("Error finding versionMinor field of Peer object"); - return NULL; - } - - versionRevField = lookup.findField(peerClass, "versionRev", "I"); - if(env->ExceptionCheck() || versionRevField == NULL) - { - LOGE("Error finding versionRev field of Peer object"); - return NULL; - } - - latencyField = lookup.findField(peerClass, "latency", "I"); - if(env->ExceptionCheck() || latencyField == NULL) - { - LOGE("Error finding latency field of Peer object"); - return NULL; - } - - roleField = lookup.findField(peerClass, "role", "Lcom/zerotier/sdk/PeerRole;"); - if(env->ExceptionCheck() || roleField == NULL) - { - LOGE("Error finding role field of Peer object"); - return NULL; - } - - pathsField = lookup.findField(peerClass, "paths", "[Lcom/zerotier/sdk/PeerPhysicalPath;"); - if(env->ExceptionCheck() || pathsField == NULL) - { - LOGE("Error finding paths field of Peer object"); - return NULL; - } - - peer_constructor = lookup.findMethod(peerClass, "", "()V"); - if(env->ExceptionCheck() || peer_constructor == NULL) - { - LOGE("Error finding Peer constructor"); - return NULL; - } - - jobject peerObject = env->NewObject(peerClass, peer_constructor); - if(env->ExceptionCheck() || peerObject == NULL) - { - LOGE("Error creating Peer object"); - return NULL; // out of memory - } - - env->SetLongField(peerObject, addressField, (jlong)peer.address); - env->SetIntField(peerObject, versionMajorField, peer.versionMajor); - env->SetIntField(peerObject, versionMinorField, peer.versionMinor); - env->SetIntField(peerObject, versionRevField, peer.versionRev); - env->SetIntField(peerObject, latencyField, peer.latency); - env->SetObjectField(peerObject, roleField, createPeerRole(env, peer.role)); - - jclass peerPhysicalPathClass = lookup.findClass("com/zerotier/sdk/PeerPhysicalPath"); - if(env->ExceptionCheck() || peerPhysicalPathClass == NULL) - { - LOGE("Error finding PeerPhysicalPath class"); - return NULL; - } - - jobjectArray arrayObject = env->NewObjectArray( - peer.pathCount, peerPhysicalPathClass, NULL); - if(env->ExceptionCheck() || arrayObject == NULL) - { - LOGE("Error creating PeerPhysicalPath[] array"); - return NULL; - } - - for(unsigned int i = 0; i < peer.pathCount; ++i) - { - jobject path = newPeerPhysicalPath(env, peer.paths[i]); - - env->SetObjectArrayElement(arrayObject, i, path); - if(env->ExceptionCheck()) { - LOGE("exception assigning PeerPhysicalPath to array"); - break; - } - } - - env->SetObjectField(peerObject, pathsField, arrayObject); - - return peerObject; -} - -jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &vnetConfig) -{ - jclass vnetConfigClass = NULL; - jmethodID vnetConfig_constructor = NULL; - jfieldID nwidField = NULL; - jfieldID macField = NULL; - jfieldID nameField = NULL; - jfieldID statusField = NULL; - jfieldID typeField = NULL; - jfieldID mtuField = NULL; - jfieldID dhcpField = NULL; - jfieldID bridgeField = NULL; - jfieldID broadcastEnabledField = NULL; - jfieldID portErrorField = NULL; - jfieldID netconfRevisionField = NULL; - jfieldID assignedAddressesField = NULL; - jfieldID routesField = NULL; - - vnetConfigClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfig"); - if(vnetConfigClass == NULL) - { - LOGE("Couldn't find com.zerotier.sdk.VirtualNetworkConfig"); - return NULL; - } - - vnetConfig_constructor = lookup.findMethod( - vnetConfigClass, "", "()V"); - if(env->ExceptionCheck() || vnetConfig_constructor == NULL) - { - LOGE("Couldn't find VirtualNetworkConfig Constructor"); - return NULL; - } - - jobject vnetConfigObj = env->NewObject(vnetConfigClass, vnetConfig_constructor); - if(env->ExceptionCheck() || vnetConfigObj == NULL) - { - LOGE("Error creating new VirtualNetworkConfig object"); - return NULL; - } - - nwidField = lookup.findField(vnetConfigClass, "nwid", "J"); - if(env->ExceptionCheck() || nwidField == NULL) - { - LOGE("Error getting nwid field"); - return NULL; - } - - macField = lookup.findField(vnetConfigClass, "mac", "J"); - if(env->ExceptionCheck() || macField == NULL) - { - LOGE("Error getting mac field"); - return NULL; - } - - nameField = lookup.findField(vnetConfigClass, "name", "Ljava/lang/String;"); - if(env->ExceptionCheck() || nameField == NULL) - { - LOGE("Error getting name field"); - return NULL; - } - - statusField = lookup.findField(vnetConfigClass, "status", "Lcom/zerotier/sdk/VirtualNetworkStatus;"); - if(env->ExceptionCheck() || statusField == NULL) - { - LOGE("Error getting status field"); - return NULL; - } - - typeField = lookup.findField(vnetConfigClass, "type", "Lcom/zerotier/sdk/VirtualNetworkType;"); - if(env->ExceptionCheck() || typeField == NULL) - { - LOGE("Error getting type field"); - return NULL; - } - - mtuField = lookup.findField(vnetConfigClass, "mtu", "I"); - if(env->ExceptionCheck() || mtuField == NULL) - { - LOGE("Error getting mtu field"); - return NULL; - } - - dhcpField = lookup.findField(vnetConfigClass, "dhcp", "Z"); - if(env->ExceptionCheck() || dhcpField == NULL) - { - LOGE("Error getting dhcp field"); - return NULL; - } - - bridgeField = lookup.findField(vnetConfigClass, "bridge", "Z"); - if(env->ExceptionCheck() || bridgeField == NULL) - { - LOGE("Error getting bridge field"); - return NULL; - } - - broadcastEnabledField = lookup.findField(vnetConfigClass, "broadcastEnabled", "Z"); - if(env->ExceptionCheck() || broadcastEnabledField == NULL) - { - LOGE("Error getting broadcastEnabled field"); - return NULL; - } - - portErrorField = lookup.findField(vnetConfigClass, "portError", "I"); - if(env->ExceptionCheck() || portErrorField == NULL) - { - LOGE("Error getting portError field"); - return NULL; - } - - netconfRevisionField = lookup.findField(vnetConfigClass, "netconfRevision", "J"); - if(env->ExceptionCheck() || netconfRevisionField == NULL) - { - LOGE("Error getting netconfRevision field"); - return NULL; - } - - assignedAddressesField = lookup.findField(vnetConfigClass, "assignedAddresses", - "[Ljava/net/InetSocketAddress;"); - if(env->ExceptionCheck() || assignedAddressesField == NULL) - { - LOGE("Error getting assignedAddresses field"); - return NULL; - } - - routesField = lookup.findField(vnetConfigClass, "routes", - "[Lcom/zerotier/sdk/VirtualNetworkRoute;"); - if(env->ExceptionCheck() || routesField == NULL) - { - LOGE("Error getting routes field"); - return NULL; - } - - env->SetLongField(vnetConfigObj, nwidField, vnetConfig.nwid); - env->SetLongField(vnetConfigObj, macField, vnetConfig.mac); - jstring nameStr = env->NewStringUTF(vnetConfig.name); - if(env->ExceptionCheck() || nameStr == NULL) - { - return NULL; // out of memory - } - env->SetObjectField(vnetConfigObj, nameField, nameStr); - - jobject statusObject = createVirtualNetworkStatus(env, vnetConfig.status); - if(env->ExceptionCheck() || statusObject == NULL) - { - return NULL; - } - env->SetObjectField(vnetConfigObj, statusField, statusObject); - - jobject typeObject = createVirtualNetworkType(env, vnetConfig.type); - if(env->ExceptionCheck() || typeObject == NULL) - { - return NULL; - } - env->SetObjectField(vnetConfigObj, typeField, typeObject); - - env->SetIntField(vnetConfigObj, mtuField, (int)vnetConfig.mtu); - env->SetBooleanField(vnetConfigObj, dhcpField, vnetConfig.dhcp); - env->SetBooleanField(vnetConfigObj, bridgeField, vnetConfig.bridge); - env->SetBooleanField(vnetConfigObj, broadcastEnabledField, vnetConfig.broadcastEnabled); - env->SetIntField(vnetConfigObj, portErrorField, vnetConfig.portError); - - jclass inetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress"); - if(env->ExceptionCheck() || inetSocketAddressClass == NULL) - { - LOGE("Error finding InetSocketAddress class"); - return NULL; - } - - jobjectArray assignedAddrArrayObj = env->NewObjectArray( - vnetConfig.assignedAddressCount, inetSocketAddressClass, NULL); - if(env->ExceptionCheck() || assignedAddrArrayObj == NULL) - { - LOGE("Error creating InetSocketAddress[] array"); - return NULL; - } - - for(unsigned int i = 0; i < vnetConfig.assignedAddressCount; ++i) - { - jobject inetAddrObj = newInetSocketAddress(env, vnetConfig.assignedAddresses[i]); - env->SetObjectArrayElement(assignedAddrArrayObj, i, inetAddrObj); - if(env->ExceptionCheck()) - { - LOGE("Error assigning InetSocketAddress to array"); - return NULL; - } - } - - env->SetObjectField(vnetConfigObj, assignedAddressesField, assignedAddrArrayObj); - - jclass virtualNetworkRouteClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkRoute"); - if(env->ExceptionCheck() || virtualNetworkRouteClass == NULL) - { - LOGE("Error finding VirtualNetworkRoute class"); - return NULL; - } - - jobjectArray routesArrayObj = env->NewObjectArray( - vnetConfig.routeCount, virtualNetworkRouteClass, NULL); - if(env->ExceptionCheck() || routesArrayObj == NULL) - { - LOGE("Error creating VirtualNetworkRoute[] array"); - return NULL; - } - - for(unsigned int i = 0; i < vnetConfig.routeCount; ++i) - { - jobject routeObj = newVirtualNetworkRoute(env, vnetConfig.routes[i]); - env->SetObjectArrayElement(routesArrayObj, i, routeObj); - if(env->ExceptionCheck()) - { - LOGE("Error assigning VirtualNetworkRoute to array"); - return NULL; - } - } - - env->SetObjectField(vnetConfigObj, routesField, routesArrayObj); - - return vnetConfigObj; -} - -jobject newVersion(JNIEnv *env, int major, int minor, int rev) -{ - // create a com.zerotier.sdk.Version object - jclass versionClass = NULL; - jmethodID versionConstructor = NULL; - - versionClass = lookup.findClass("com/zerotier/sdk/Version"); - if(env->ExceptionCheck() || versionClass == NULL) - { - return NULL; - } - - versionConstructor = lookup.findMethod( - versionClass, "", "()V"); - if(env->ExceptionCheck() || versionConstructor == NULL) - { - return NULL; - } - - jobject versionObj = env->NewObject(versionClass, versionConstructor); - if(env->ExceptionCheck() || versionObj == NULL) - { - return NULL; - } - - // copy data to Version object - jfieldID majorField = NULL; - jfieldID minorField = NULL; - jfieldID revisionField = NULL; - - majorField = lookup.findField(versionClass, "major", "I"); - if(env->ExceptionCheck() || majorField == NULL) - { - return NULL; - } - - minorField = lookup.findField(versionClass, "minor", "I"); - if(env->ExceptionCheck() || minorField == NULL) - { - return NULL; - } - - revisionField = lookup.findField(versionClass, "revision", "I"); - if(env->ExceptionCheck() || revisionField == NULL) - { - return NULL; - } - - env->SetIntField(versionObj, majorField, (jint)major); - env->SetIntField(versionObj, minorField, (jint)minor); - env->SetIntField(versionObj, revisionField, (jint)rev); - - return versionObj; -} - -jobject newVirtualNetworkRoute(JNIEnv *env, const ZT_VirtualNetworkRoute &route) -{ - jclass virtualNetworkRouteClass = NULL; - jmethodID routeConstructor = NULL; - - virtualNetworkRouteClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkRoute"); - if(env->ExceptionCheck() || virtualNetworkRouteClass == NULL) - { - return NULL; - } - - routeConstructor = lookup.findMethod(virtualNetworkRouteClass, "", "()V"); - if(env->ExceptionCheck() || routeConstructor == NULL) - { - return NULL; - } - - jobject routeObj = env->NewObject(virtualNetworkRouteClass, routeConstructor); - if(env->ExceptionCheck() || routeObj == NULL) - { - return NULL; - } - - jfieldID targetField = NULL; - jfieldID viaField = NULL; - jfieldID flagsField = NULL; - jfieldID metricField = NULL; - - targetField = lookup.findField(virtualNetworkRouteClass, "target", - "Ljava/net/InetSocketAddress;"); - if(env->ExceptionCheck() || targetField == NULL) - { - return NULL; - } - - viaField = lookup.findField(virtualNetworkRouteClass, "via", - "Ljava/net/InetSocketAddress;"); - if(env->ExceptionCheck() || targetField == NULL) - { - return NULL; - } - - flagsField = lookup.findField(virtualNetworkRouteClass, "flags", "I"); - if(env->ExceptionCheck() || flagsField == NULL) - { - return NULL; - } - - metricField = lookup.findField(virtualNetworkRouteClass, "metric", "I"); - if(env->ExceptionCheck() || metricField == NULL) - { - return NULL; - } - - jobject targetObj = newInetSocketAddress(env, route.target); - jobject viaObj = newInetSocketAddress(env, route.via); - - env->SetObjectField(routeObj, targetField, targetObj); - env->SetObjectField(routeObj, viaField, viaObj); - env->SetIntField(routeObj, flagsField, (jint)route.flags); - env->SetIntField(routeObj, metricField, (jint)route.metric); - - return routeObj; -} - -#ifdef __cplusplus -} -#endif - diff --git a/attic/java/jni/ZT_jniutils.h b/attic/java/jni/ZT_jniutils.h deleted file mode 100644 index 56b63179e..000000000 --- a/attic/java/jni/ZT_jniutils.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2016 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 . - */ - -#ifndef ZT_jniutils_h_ -#define ZT_jniutils_h_ -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define LOG_TAG "ZeroTierOneJNI" - -#if defined(__ANDROID__) - -#include - - #if !defined(NDEBUG) - #define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) - #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) - #else - #define LOGV(...) - #define LOGD(...) - #endif - - #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) - #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#else - #if !defined(NDEBUG) - #define LOGV(...) fprintf(stdout, __VA_ARGS__) - #define LOGD(...) fprintf(stdout, __VA_ARGS__) - #else - #define LOGV(...) - #define LOGD(...) - #endif - - #define LOGI(...) fprintf(stdout, __VA_ARGS__) - #define LOGE(...) fprintf(stdout, __VA_ARGS__) -#endif - -jobject createResultObject(JNIEnv *env, ZT_ResultCode code); -jobject createVirtualNetworkStatus(JNIEnv *env, ZT_VirtualNetworkStatus status); -jobject createVirtualNetworkType(JNIEnv *env, ZT_VirtualNetworkType type); -jobject createEvent(JNIEnv *env, ZT_Event event); -jobject createPeerRole(JNIEnv *env, ZT_PeerRole role); -jobject createVirtualNetworkConfigOperation(JNIEnv *env, ZT_VirtualNetworkConfigOperation op); - -jobject newInetSocketAddress(JNIEnv *env, const sockaddr_storage &addr); -jobject newInetAddress(JNIEnv *env, const sockaddr_storage &addr); - -jobject newMulticastGroup(JNIEnv *env, const ZT_MulticastGroup &mc); - -jobject newPeer(JNIEnv *env, const ZT_Peer &peer); -jobject newPeerPhysicalPath(JNIEnv *env, const ZT_PeerPhysicalPath &ppp); - -jobject newNetworkConfig(JNIEnv *env, const ZT_VirtualNetworkConfig &config); - -jobject newVersion(JNIEnv *env, int major, int minor, int rev); - -jobject newVirtualNetworkRoute(JNIEnv *env, const ZT_VirtualNetworkRoute &route); - -#ifdef __cplusplus -} -#endif - -#endif \ No newline at end of file diff --git a/attic/java/jni/com_zerotierone_sdk_Node.cpp b/attic/java/jni/com_zerotierone_sdk_Node.cpp deleted file mode 100644 index 6ddc35565..000000000 --- a/attic/java/jni/com_zerotierone_sdk_Node.cpp +++ /dev/null @@ -1,1615 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -#include "com_zerotierone_sdk_Node.h" -#include "ZT_jniutils.h" -#include "ZT_jnilookup.h" - -#include -#include "Mutex.hpp" - -#include -#include -#include -#include - -// global static JNI Lookup Object -JniLookup lookup; - -#ifdef __cplusplus -extern "C" { -#endif - -namespace { - struct JniRef - { - JniRef() - : jvm(NULL) - , node(NULL) - , dataStoreGetListener(NULL) - , dataStorePutListener(NULL) - , packetSender(NULL) - , eventListener(NULL) - , frameListener(NULL) - , configListener(NULL) - , pathChecker(NULL) - , callbacks(NULL) - { - callbacks = (ZT_Node_Callbacks*)malloc(sizeof(ZT_Node_Callbacks)); - memset(callbacks, 0, sizeof(ZT_Node_Callbacks)); - } - - ~JniRef() - { - JNIEnv *env = NULL; - jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - - env->DeleteGlobalRef(dataStoreGetListener); - env->DeleteGlobalRef(dataStorePutListener); - env->DeleteGlobalRef(packetSender); - env->DeleteGlobalRef(eventListener); - env->DeleteGlobalRef(frameListener); - env->DeleteGlobalRef(configListener); - env->DeleteGlobalRef(pathChecker); - - free(callbacks); - callbacks = NULL; - } - - int64_t id; - - JavaVM *jvm; - - ZT_Node *node; - - jobject dataStoreGetListener; - jobject dataStorePutListener; - jobject packetSender; - jobject eventListener; - jobject frameListener; - jobject configListener; - jobject pathChecker; - - ZT_Node_Callbacks *callbacks; - }; - - - int VirtualNetworkConfigFunctionCallback( - ZT_Node *node, - void *userData, - void *threadData, - uint64_t nwid, - void **, - enum ZT_VirtualNetworkConfigOperation operation, - const ZT_VirtualNetworkConfig *config) - { - LOGV("VritualNetworkConfigFunctionCallback"); - JniRef *ref = (JniRef*)userData; - JNIEnv *env = NULL; - ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - - if (ref->configListener == NULL) { - LOGE("configListener is NULL"); - return -1; - } - - jclass configListenerClass = env->GetObjectClass(ref->configListener); - if(configListenerClass == NULL) - { - LOGE("Couldn't find class for VirtualNetworkConfigListener instance"); - return -1; - } - - jmethodID configListenerCallbackMethod = lookup.findMethod(configListenerClass, - "onNetworkConfigurationUpdated", - "(JLcom/zerotier/sdk/VirtualNetworkConfigOperation;Lcom/zerotier/sdk/VirtualNetworkConfig;)I"); - if(configListenerCallbackMethod == NULL) - { - LOGE("Couldn't find onVirtualNetworkFrame() method"); - return -2; - } - - jobject operationObject = createVirtualNetworkConfigOperation(env, operation); - if(operationObject == NULL) - { - LOGE("Error creating VirtualNetworkConfigOperation object"); - return -3; - } - - jobject networkConfigObject = newNetworkConfig(env, *config); - if(networkConfigObject == NULL) - { - LOGE("Error creating VirtualNetworkConfig object"); - return -4; - } - - return env->CallIntMethod( - ref->configListener, - configListenerCallbackMethod, - (jlong)nwid, operationObject, networkConfigObject); - } - - void VirtualNetworkFrameFunctionCallback(ZT_Node *node, - void *userData, - void *threadData, - uint64_t nwid, - void**, - uint64_t sourceMac, - uint64_t destMac, - unsigned int etherType, - unsigned int vlanid, - const void *frameData, - unsigned int frameLength) - { - LOGV("VirtualNetworkFrameFunctionCallback"); -#ifndef NDEBUG - unsigned char* local = (unsigned char*)frameData; - LOGV("Type Bytes: 0x%02x%02x", local[12], local[13]); -#endif - JniRef *ref = (JniRef*)userData; - assert(ref->node == node); - JNIEnv *env = NULL; - ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - - if (ref->frameListener == NULL) { - LOGE("frameListener is NULL"); - return; - } - - jclass frameListenerClass = env->GetObjectClass(ref->frameListener); - if(env->ExceptionCheck() || frameListenerClass == NULL) - { - LOGE("Couldn't find class for VirtualNetworkFrameListener instance"); - return; - } - - jmethodID frameListenerCallbackMethod = lookup.findMethod( - frameListenerClass, - "onVirtualNetworkFrame", "(JJJJJ[B)V"); - if(env->ExceptionCheck() || frameListenerCallbackMethod == NULL) - { - LOGE("Couldn't find onVirtualNetworkFrame() method"); - return; - } - - jbyteArray dataArray = env->NewByteArray(frameLength); - if(env->ExceptionCheck() || dataArray == NULL) - { - LOGE("Couldn't create frame data array"); - return; - } - - void *data = env->GetPrimitiveArrayCritical(dataArray, NULL); - memcpy(data, frameData, frameLength); - env->ReleasePrimitiveArrayCritical(dataArray, data, 0); - - if(env->ExceptionCheck()) - { - LOGE("Error setting frame data to array"); - return; - } - - env->CallVoidMethod(ref->frameListener, frameListenerCallbackMethod, (jlong)nwid, (jlong)sourceMac, (jlong)destMac, (jlong)etherType, (jlong)vlanid, dataArray); - } - - - void EventCallback(ZT_Node *node, - void *userData, - void *threadData, - enum ZT_Event event, - const void *data) { - LOGV("EventCallback"); - JniRef *ref = (JniRef *) userData; - if (ref->node != node && event != ZT_EVENT_UP) { - LOGE("Nodes not equal. ref->node %p, node %p. Event: %d", ref->node, node, event); - return; - } - JNIEnv *env = NULL; - ref->jvm->GetEnv((void **) &env, JNI_VERSION_1_6); - - if (ref->eventListener == NULL) { - LOGE("eventListener is NULL"); - return; - } - - jclass eventListenerClass = env->GetObjectClass(ref->eventListener); - if (eventListenerClass == NULL) { - LOGE("Couldn't class for EventListener instance"); - return; - } - - jmethodID onEventMethod = lookup.findMethod(eventListenerClass, - "onEvent", "(Lcom/zerotier/sdk/Event;)V"); - if (onEventMethod == NULL) { - LOGE("Couldn't find onEvent method"); - return; - } - - jmethodID onTraceMethod = lookup.findMethod(eventListenerClass, - "onTrace", "(Ljava/lang/String;)V"); - if (onTraceMethod == NULL) { - LOGE("Couldn't find onTrace method"); - return; - } - - jobject eventObject = createEvent(env, event); - if (eventObject == NULL) { - return; - } - - switch (event) { - case ZT_EVENT_UP: { - LOGD("Event Up"); - env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject); - break; - } - case ZT_EVENT_OFFLINE: { - LOGD("Event Offline"); - env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject); - break; - } - case ZT_EVENT_ONLINE: { - LOGD("Event Online"); - env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject); - break; - } - case ZT_EVENT_DOWN: { - LOGD("Event Down"); - env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject); - break; - } - case ZT_EVENT_FATAL_ERROR_IDENTITY_COLLISION: { - LOGV("Identity Collision"); - // call onEvent() - env->CallVoidMethod(ref->eventListener, onEventMethod, eventObject); - } - break; - case ZT_EVENT_TRACE: { - LOGV("Trace Event"); - // call onTrace() - if (data != NULL) { - const char *message = (const char *) data; - jstring messageStr = env->NewStringUTF(message); - env->CallVoidMethod(ref->eventListener, onTraceMethod, messageStr); - } - } - break; - case ZT_EVENT_USER_MESSAGE: - case ZT_EVENT_REMOTE_TRACE: - default: - break; - } - } - - void StatePutFunction( - ZT_Node *node, - void *userData, - void *threadData, - enum ZT_StateObjectType type, - const uint64_t id[2], - const void *buffer, - int bufferLength) { - char p[4096] = {0}; - bool secure = false; - switch (type) { - case ZT_STATE_OBJECT_IDENTITY_PUBLIC: - snprintf(p, sizeof(p), "identity.public"); - break; - case ZT_STATE_OBJECT_IDENTITY_SECRET: - snprintf(p, sizeof(p), "identity.secret"); - secure = true; - break; - case ZT_STATE_OBJECT_PLANET: - snprintf(p, sizeof(p), "planet"); - break; - case ZT_STATE_OBJECT_MOON: - snprintf(p, sizeof(p), "moons.d/%.16llx.moon", (unsigned long long)id[0]); - break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - snprintf(p, sizeof(p), "networks.d/%.16llx.conf", (unsigned long long)id[0]); - break; - case ZT_STATE_OBJECT_PEER: - snprintf(p, sizeof(p), "peers.d/%.10llx", (unsigned long long)id[0]); - break; - default: - return; - } - - if (strlen(p) < 1) { - return; - } - - JniRef *ref = (JniRef*)userData; - JNIEnv *env = NULL; - ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - - if (ref->dataStorePutListener == NULL) { - LOGE("dataStorePutListener is NULL"); - return; - } - - jclass dataStorePutClass = env->GetObjectClass(ref->dataStorePutListener); - if (dataStorePutClass == NULL) - { - LOGE("Couldn't find class for DataStorePutListener instance"); - return; - } - - jmethodID dataStorePutCallbackMethod = lookup.findMethod( - dataStorePutClass, - "onDataStorePut", - "(Ljava/lang/String;[BZ)I"); - if(dataStorePutCallbackMethod == NULL) - { - LOGE("Couldn't find onDataStorePut method"); - return; - } - - jmethodID deleteMethod = lookup.findMethod(dataStorePutClass, - "onDelete", "(Ljava/lang/String;)I"); - if(deleteMethod == NULL) - { - LOGE("Couldn't find onDelete method"); - return; - } - - jstring nameStr = env->NewStringUTF(p); - - if (bufferLength >= 0) { - LOGD("JNI: Write file: %s", p); - // set operation - jbyteArray bufferObj = env->NewByteArray(bufferLength); - if(env->ExceptionCheck() || bufferObj == NULL) - { - LOGE("Error creating byte array buffer!"); - return; - } - - env->SetByteArrayRegion(bufferObj, 0, bufferLength, (jbyte*)buffer); - - env->CallIntMethod(ref->dataStorePutListener, - dataStorePutCallbackMethod, - nameStr, bufferObj, secure); - } else { - LOGD("JNI: Delete file: %s", p); - env->CallIntMethod(ref->dataStorePutListener, deleteMethod, nameStr); - } - } - - int StateGetFunction( - ZT_Node *node, - void *userData, - void *threadData, - ZT_StateObjectType type, - const uint64_t id[2], - void *buffer, - unsigned int bufferLength) { - char p[4096] = {0}; - switch (type) { - case ZT_STATE_OBJECT_IDENTITY_PUBLIC: - snprintf(p, sizeof(p), "identity.public"); - break; - case ZT_STATE_OBJECT_IDENTITY_SECRET: - snprintf(p, sizeof(p), "identity.secret"); - break; - case ZT_STATE_OBJECT_PLANET: - snprintf(p, sizeof(p), "planet"); - break; - case ZT_STATE_OBJECT_MOON: - snprintf(p, sizeof(p), "moons.d/%.16llx.moon", (unsigned long long)id[0]); - break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - snprintf(p, sizeof(p), "networks.d/%.16llx.conf", (unsigned long long)id[0]); - break; - case ZT_STATE_OBJECT_PEER: - snprintf(p, sizeof(p), "peers.d/%.10llx", (unsigned long long)id[0]); - break; - default: - return -1; - } - - if (strlen(p) < 1) { - return -1; - } - - JniRef *ref = (JniRef*)userData; - JNIEnv *env = NULL; - ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - - if (ref->dataStoreGetListener == NULL) { - LOGE("dataStoreGetListener is NULL"); - return -2; - } - - jclass dataStoreGetClass = env->GetObjectClass(ref->dataStoreGetListener); - if(dataStoreGetClass == NULL) - { - LOGE("Couldn't find class for DataStoreGetListener instance"); - return -2; - } - - jmethodID dataStoreGetCallbackMethod = lookup.findMethod( - dataStoreGetClass, - "onDataStoreGet", - "(Ljava/lang/String;[B)J"); - if(dataStoreGetCallbackMethod == NULL) - { - LOGE("Couldn't find onDataStoreGet method"); - return -2; - } - - jstring nameStr = env->NewStringUTF(p); - if(nameStr == NULL) - { - LOGE("Error creating name string object"); - return -2; // out of memory - } - - jbyteArray bufferObj = env->NewByteArray(bufferLength); - if(bufferObj == NULL) - { - LOGE("Error creating byte[] buffer of size: %u", bufferLength); - return -2; - } - - LOGV("Calling onDataStoreGet(%s, %p)", p, buffer); - - int retval = (int)env->CallLongMethod( - ref->dataStoreGetListener, - dataStoreGetCallbackMethod, - nameStr, - bufferObj); - - LOGV("onDataStoreGet returned %d", retval); - - if(retval > 0) - { - void *data = env->GetPrimitiveArrayCritical(bufferObj, NULL); - memcpy(buffer, data, retval); - env->ReleasePrimitiveArrayCritical(bufferObj, data, 0); - } - - return retval; - } - - int WirePacketSendFunction(ZT_Node *node, - void *userData, - void *threadData, - int64_t localSocket, - const struct sockaddr_storage *remoteAddress, - const void *buffer, - unsigned int bufferSize, - unsigned int ttl) - { - LOGV("WirePacketSendFunction(%lld, %p, %p, %d)", (long long)localSocket, remoteAddress, buffer, bufferSize); - JniRef *ref = (JniRef*)userData; - assert(ref->node == node); - - JNIEnv *env = NULL; - ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - - if (ref->packetSender == NULL) { - LOGE("packetSender is NULL"); - return -1; - } - - jclass packetSenderClass = env->GetObjectClass(ref->packetSender); - if(packetSenderClass == NULL) - { - LOGE("Couldn't find class for PacketSender instance"); - return -1; - } - - jmethodID packetSenderCallbackMethod = lookup.findMethod(packetSenderClass, - "onSendPacketRequested", "(JLjava/net/InetSocketAddress;[BI)I"); - if(packetSenderCallbackMethod == NULL) - { - LOGE("Couldn't find onSendPacketRequested method"); - return -2; - } - - jobject remoteAddressObj = newInetSocketAddress(env, *remoteAddress); - jbyteArray bufferObj = env->NewByteArray(bufferSize); - env->SetByteArrayRegion(bufferObj, 0, bufferSize, (jbyte*)buffer); - int retval = env->CallIntMethod(ref->packetSender, packetSenderCallbackMethod, localSocket, remoteAddressObj, bufferObj); - - LOGV("JNI Packet Sender returned: %d", retval); - return retval; - } - - int PathCheckFunction(ZT_Node *node, - void *userPtr, - void *threadPtr, - uint64_t address, - int64_t localSocket, - const struct sockaddr_storage *remoteAddress) - { - JniRef *ref = (JniRef*)userPtr; - assert(ref->node == node); - - if(ref->pathChecker == NULL) { - return true; - } - - JNIEnv *env = NULL; - ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - - jclass pathCheckerClass = env->GetObjectClass(ref->pathChecker); - if(pathCheckerClass == NULL) - { - LOGE("Couldn't find class for PathChecker instance"); - return true; - } - - jmethodID pathCheckCallbackMethod = lookup.findMethod(pathCheckerClass, - "onPathCheck", "(JJLjava/net/InetSocketAddress;)Z"); - if(pathCheckCallbackMethod == NULL) - { - LOGE("Couldn't find onPathCheck method implementation"); - return true; - } - - struct sockaddr_storage nullAddress = {0}; - jobject remoteAddressObj = NULL; - - if(memcmp(remoteAddress, &nullAddress, sizeof(sockaddr_storage)) != 0) - { - remoteAddressObj = newInetSocketAddress(env, *remoteAddress); - } - - return env->CallBooleanMethod(ref->pathChecker, pathCheckCallbackMethod, address, localSocket, remoteAddressObj); - } - - int PathLookupFunction(ZT_Node *node, - void *userPtr, - void *threadPtr, - uint64_t address, - int ss_family, - struct sockaddr_storage *result) - { - JniRef *ref = (JniRef*)userPtr; - assert(ref->node == node); - - if(ref->pathChecker == NULL) { - return false; - } - - JNIEnv *env = NULL; - ref->jvm->GetEnv((void**)&env, JNI_VERSION_1_6); - - jclass pathCheckerClass = env->GetObjectClass(ref->pathChecker); - if(pathCheckerClass == NULL) - { - LOGE("Couldn't find class for PathChecker instance"); - return false; - } - - jmethodID pathLookupMethod = lookup.findMethod(pathCheckerClass, - "onPathLookup", "(JI)Ljava/net/InetSocketAddress;"); - if(pathLookupMethod == NULL) { - return false; - } - - jobject sockAddressObject = env->CallObjectMethod(ref->pathChecker, pathLookupMethod, address, ss_family); - if(sockAddressObject == NULL) - { - LOGE("Unable to call onPathLookup implementation"); - return false; - } - - jclass inetSockAddressClass = env->GetObjectClass(sockAddressObject); - if(inetSockAddressClass == NULL) - { - LOGE("Unable to find InetSocketAddress class"); - return false; - } - - jmethodID getAddressMethod = lookup.findMethod(inetSockAddressClass, "getAddress", "()Ljava/net/InetAddress;"); - if(getAddressMethod == NULL) - { - LOGE("Unable to find InetSocketAddress.getAddress() method"); - return false; - } - - jmethodID getPortMethod = lookup.findMethod(inetSockAddressClass, "getPort", "()I"); - if(getPortMethod == NULL) - { - LOGE("Unable to find InetSocketAddress.getPort() method"); - return false; - } - - jint port = env->CallIntMethod(sockAddressObject, getPortMethod); - jobject addressObject = env->CallObjectMethod(sockAddressObject, getAddressMethod); - - jclass inetAddressClass = lookup.findClass("java/net/InetAddress"); - if(inetAddressClass == NULL) - { - LOGE("Unable to find InetAddress class"); - return false; - } - - getAddressMethod = lookup.findMethod(inetAddressClass, "getAddress", "()[B"); - if(getAddressMethod == NULL) - { - LOGE("Unable to find InetAddress.getAddress() method"); - return false; - } - - jbyteArray addressBytes = (jbyteArray)env->CallObjectMethod(addressObject, getAddressMethod); - if(addressBytes == NULL) - { - LOGE("Unable to call InetAddress.getBytes()"); - return false; - } - - int addressSize = env->GetArrayLength(addressBytes); - if(addressSize == 4) - { - // IPV4 - sockaddr_in *addr = (sockaddr_in*)result; - addr->sin_family = AF_INET; - addr->sin_port = htons(port); - - void *data = env->GetPrimitiveArrayCritical(addressBytes, NULL); - memcpy(&addr->sin_addr, data, 4); - env->ReleasePrimitiveArrayCritical(addressBytes, data, 0); - } - else if (addressSize == 16) - { - // IPV6 - sockaddr_in6 *addr = (sockaddr_in6*)result; - addr->sin6_family = AF_INET6; - addr->sin6_port = htons(port); - void *data = env->GetPrimitiveArrayCritical(addressBytes, NULL); - memcpy(&addr->sin6_addr, data, 16); - env->ReleasePrimitiveArrayCritical(addressBytes, data, 0); - } - else - { - return false; - } - - return true; - } - - typedef std::map NodeMap; - static NodeMap nodeMap; - ZeroTier::Mutex nodeMapMutex; - - ZT_Node* findNode(int64_t nodeId) - { - ZeroTier::Mutex::Lock lock(nodeMapMutex); - NodeMap::iterator found = nodeMap.find(nodeId); - if(found != nodeMap.end()) - { - JniRef *ref = found->second; - return ref->node; - } - return NULL; - } -} - -JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) -{ - lookup.setJavaVM(vm); - return JNI_VERSION_1_6; -} - -JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved) -{ - -} - - -/* - * Class: com_zerotier_sdk_Node - * Method: node_init - * Signature: (J)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init( - JNIEnv *env, jobject obj, jlong now) -{ - LOGV("Creating ZT_Node struct"); - jobject resultObject = createResultObject(env, ZT_RESULT_OK); - - ZT_Node *node; - JniRef *ref = new JniRef; - ref->id = (int64_t)now; - env->GetJavaVM(&ref->jvm); - - jclass cls = env->GetObjectClass(obj); - jfieldID fid = lookup.findField( - cls, "getListener", "Lcom/zerotier/sdk/DataStoreGetListener;"); - - if(fid == NULL) - { - return NULL; // exception already thrown - } - - jobject tmp = env->GetObjectField(obj, fid); - if(tmp == NULL) - { - return NULL; - } - ref->dataStoreGetListener = env->NewGlobalRef(tmp); - - fid = lookup.findField( - cls, "putListener", "Lcom/zerotier/sdk/DataStorePutListener;"); - - if(fid == NULL) - { - return NULL; // exception already thrown - } - - tmp = env->GetObjectField(obj, fid); - if(tmp == NULL) - { - return NULL; - } - ref->dataStorePutListener = env->NewGlobalRef(tmp); - - fid = lookup.findField( - cls, "sender", "Lcom/zerotier/sdk/PacketSender;"); - if(fid == NULL) - { - return NULL; // exception already thrown - } - - tmp = env->GetObjectField(obj, fid); - if(tmp == NULL) - { - return NULL; - } - ref->packetSender = env->NewGlobalRef(tmp); - - fid = lookup.findField( - cls, "frameListener", "Lcom/zerotier/sdk/VirtualNetworkFrameListener;"); - if(fid == NULL) - { - return NULL; // exception already thrown - } - - tmp = env->GetObjectField(obj, fid); - if(tmp == NULL) - { - return NULL; - } - ref->frameListener = env->NewGlobalRef(tmp); - - fid = lookup.findField( - cls, "configListener", "Lcom/zerotier/sdk/VirtualNetworkConfigListener;"); - if(fid == NULL) - { - return NULL; // exception already thrown - } - - tmp = env->GetObjectField(obj, fid); - if(tmp == NULL) - { - return NULL; - } - ref->configListener = env->NewGlobalRef(tmp); - - fid = lookup.findField( - cls, "eventListener", "Lcom/zerotier/sdk/EventListener;"); - if(fid == NULL) - { - return NULL; - } - - tmp = env->GetObjectField(obj, fid); - if(tmp == NULL) - { - return NULL; - } - ref->eventListener = env->NewGlobalRef(tmp); - - fid = lookup.findField( - cls, "pathChecker", "Lcom/zerotier/sdk/PathChecker;"); - if(fid == NULL) - { - LOGE("no path checker?"); - return NULL; - } - - tmp = env->GetObjectField(obj, fid); - if(tmp != NULL) - { - ref->pathChecker = env->NewGlobalRef(tmp); - } - - ref->callbacks->stateGetFunction = &StateGetFunction; - ref->callbacks->statePutFunction = &StatePutFunction; - ref->callbacks->wirePacketSendFunction = &WirePacketSendFunction; - ref->callbacks->virtualNetworkFrameFunction = &VirtualNetworkFrameFunctionCallback; - ref->callbacks->virtualNetworkConfigFunction = &VirtualNetworkConfigFunctionCallback; - ref->callbacks->eventCallback = &EventCallback; - ref->callbacks->pathCheckFunction = &PathCheckFunction; - ref->callbacks->pathLookupFunction = &PathLookupFunction; - - ZT_ResultCode rc = ZT_Node_new( - &node, - ref, - NULL, - ref->callbacks, - (int64_t)now); - - if(rc != ZT_RESULT_OK) - { - LOGE("Error creating Node: %d", rc); - resultObject = createResultObject(env, rc); - if(node) - { - ZT_Node_delete(node); - node = NULL; - } - delete ref; - ref = NULL; - return resultObject; - } - - ZeroTier::Mutex::Lock lock(nodeMapMutex); - ref->node = node; - nodeMap.insert(std::make_pair(ref->id, ref)); - - return resultObject; -} - -/* - * Class: com_zerotier_sdk_Node - * Method: node_delete - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_com_zerotier_sdk_Node_node_1delete( - JNIEnv *env, jobject obj, jlong id) -{ - LOGV("Destroying ZT_Node struct"); - int64_t nodeId = (int64_t)id; - - NodeMap::iterator found; - { - ZeroTier::Mutex::Lock lock(nodeMapMutex); - found = nodeMap.find(nodeId); - } - - if(found != nodeMap.end()) - { - JniRef *ref = found->second; - nodeMap.erase(found); - - ZT_Node_delete(ref->node); - - delete ref; - ref = NULL; - } - else - { - LOGE("Attempted to delete a node that doesn't exist!"); - } -} - -/* - * Class: com_zerotier_sdk_Node - * Method: processVirtualNetworkFrame - * Signature: (JJJJJII[B[J)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame( - JNIEnv *env, jobject obj, - jlong id, - jlong in_now, - jlong in_nwid, - jlong in_sourceMac, - jlong in_destMac, - jint in_etherType, - jint in_vlanId, - jbyteArray in_frameData, - jlongArray out_nextBackgroundTaskDeadline) -{ - int64_t nodeId = (int64_t) id; - - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline); - if(nbtd_len < 1) - { - // array for next background task length has 0 elements! - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - int64_t now = (int64_t)in_now; - uint64_t nwid = (uint64_t)in_nwid; - uint64_t sourceMac = (uint64_t)in_sourceMac; - uint64_t destMac = (uint64_t)in_destMac; - unsigned int etherType = (unsigned int)in_etherType; - unsigned int vlanId = (unsigned int)in_vlanId; - - unsigned int frameLength = env->GetArrayLength(in_frameData); - void *frameData = env->GetPrimitiveArrayCritical(in_frameData, NULL); - void *localData = malloc(frameLength); - memcpy(localData, frameData, frameLength); - env->ReleasePrimitiveArrayCritical(in_frameData, frameData, 0); - - int64_t nextBackgroundTaskDeadline = 0; - - ZT_ResultCode rc = ZT_Node_processVirtualNetworkFrame( - node, - NULL, - now, - nwid, - sourceMac, - destMac, - etherType, - vlanId, - (const void*)localData, - frameLength, - &nextBackgroundTaskDeadline); - - jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL); - outDeadline[0] = (jlong)nextBackgroundTaskDeadline; - env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0); - - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: processWirePacket - * Signature: (JJJLjava/net/InetSocketAddress;I[B[J)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket( - JNIEnv *env, jobject obj, - jlong id, - jlong in_now, - jlong in_localSocket, - jobject in_remoteAddress, - jbyteArray in_packetData, - jlongArray out_nextBackgroundTaskDeadline) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - LOGE("Couldn't find a valid node!"); - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - unsigned int nbtd_len = (unsigned int)env->GetArrayLength(out_nextBackgroundTaskDeadline); - if(nbtd_len < 1) - { - LOGE("nbtd_len < 1"); - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - int64_t now = (int64_t)in_now; - - // get the java.net.InetSocketAddress class and getAddress() method - jclass inetAddressClass = lookup.findClass("java/net/InetAddress"); - if(inetAddressClass == NULL) - { - LOGE("Can't find InetAddress class"); - // can't find java.net.InetAddress - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - jmethodID getAddressMethod = lookup.findMethod( - inetAddressClass, "getAddress", "()[B"); - if(getAddressMethod == NULL) - { - // cant find InetAddress.getAddres() - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - jclass InetSocketAddressClass = lookup.findClass("java/net/InetSocketAddress"); - if(InetSocketAddressClass == NULL) - { - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - jmethodID inetSockGetAddressMethod = lookup.findMethod( - InetSocketAddressClass, "getAddress", "()Ljava/net/InetAddress;"); - - jobject remoteAddrObject = env->CallObjectMethod(in_remoteAddress, inetSockGetAddressMethod); - - if(remoteAddrObject == NULL) - { - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - jmethodID inetSock_getPort = lookup.findMethod( - InetSocketAddressClass, "getPort", "()I"); - - if(env->ExceptionCheck() || inetSock_getPort == NULL) - { - LOGE("Couldn't find getPort method on InetSocketAddress"); - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - // call InetSocketAddress.getPort() - int remotePort = env->CallIntMethod(in_remoteAddress, inetSock_getPort); - if(env->ExceptionCheck()) - { - LOGE("Exception calling InetSocketAddress.getPort()"); - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - // Call InetAddress.getAddress() - jbyteArray remoteAddressArray = (jbyteArray)env->CallObjectMethod(remoteAddrObject, getAddressMethod); - if(remoteAddressArray == NULL) - { - LOGE("Unable to call getAddress()"); - // unable to call getAddress() - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - unsigned int addrSize = env->GetArrayLength(remoteAddressArray); - - - // get the address bytes - jbyte *addr = (jbyte*)env->GetPrimitiveArrayCritical(remoteAddressArray, NULL); - sockaddr_storage remoteAddress = {}; - - if(addrSize == 16) - { - // IPV6 address - sockaddr_in6 ipv6 = {}; - ipv6.sin6_family = AF_INET6; - ipv6.sin6_port = htons(remotePort); - memcpy(ipv6.sin6_addr.s6_addr, addr, 16); - memcpy(&remoteAddress, &ipv6, sizeof(sockaddr_in6)); - } - else if(addrSize == 4) - { - // IPV4 address - sockaddr_in ipv4 = {}; - ipv4.sin_family = AF_INET; - ipv4.sin_port = htons(remotePort); - memcpy(&ipv4.sin_addr, addr, 4); - memcpy(&remoteAddress, &ipv4, sizeof(sockaddr_in)); - } - else - { - LOGE("Unknown IP version"); - // unknown address type - env->ReleasePrimitiveArrayCritical(remoteAddressArray, addr, 0); - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - env->ReleasePrimitiveArrayCritical(remoteAddressArray, addr, 0); - - unsigned int packetLength = (unsigned int)env->GetArrayLength(in_packetData); - if(packetLength == 0) - { - LOGE("Empty packet?!?"); - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - void *packetData = env->GetPrimitiveArrayCritical(in_packetData, NULL); - void *localData = malloc(packetLength); - memcpy(localData, packetData, packetLength); - env->ReleasePrimitiveArrayCritical(in_packetData, packetData, 0); - - int64_t nextBackgroundTaskDeadline = 0; - - ZT_ResultCode rc = ZT_Node_processWirePacket( - node, - NULL, - now, - in_localSocket, - &remoteAddress, - localData, - packetLength, - &nextBackgroundTaskDeadline); - if(rc != ZT_RESULT_OK) - { - LOGE("ZT_Node_processWirePacket returned: %d", rc); - } - - free(localData); - - jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL); - outDeadline[0] = (jlong)nextBackgroundTaskDeadline; - env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0); - - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: processBackgroundTasks - * Signature: (JJ[J)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processBackgroundTasks( - JNIEnv *env, jobject obj, - jlong id, - jlong in_now, - jlongArray out_nextBackgroundTaskDeadline) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - unsigned int nbtd_len = env->GetArrayLength(out_nextBackgroundTaskDeadline); - if(nbtd_len < 1) - { - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - int64_t now = (int64_t)in_now; - int64_t nextBackgroundTaskDeadline = 0; - - ZT_ResultCode rc = ZT_Node_processBackgroundTasks(node, NULL, now, &nextBackgroundTaskDeadline); - - jlong *outDeadline = (jlong*)env->GetPrimitiveArrayCritical(out_nextBackgroundTaskDeadline, NULL); - outDeadline[0] = (jlong)nextBackgroundTaskDeadline; - env->ReleasePrimitiveArrayCritical(out_nextBackgroundTaskDeadline, outDeadline, 0); - - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: join - * Signature: (JJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_join( - JNIEnv *env, jobject obj, jlong id, jlong in_nwid) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - uint64_t nwid = (uint64_t)in_nwid; - - ZT_ResultCode rc = ZT_Node_join(node, nwid, NULL, NULL); - - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: leave - * Signature: (JJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_leave( - JNIEnv *env, jobject obj, jlong id, jlong in_nwid) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - uint64_t nwid = (uint64_t)in_nwid; - - ZT_ResultCode rc = ZT_Node_leave(node, nwid, NULL, NULL); - - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: multicastSubscribe - * Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastSubscribe( - JNIEnv *env, jobject obj, - jlong id, - jlong in_nwid, - jlong in_multicastGroup, - jlong in_multicastAdi) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - uint64_t nwid = (uint64_t)in_nwid; - uint64_t multicastGroup = (uint64_t)in_multicastGroup; - unsigned long multicastAdi = (unsigned long)in_multicastAdi; - - ZT_ResultCode rc = ZT_Node_multicastSubscribe( - node, NULL, nwid, multicastGroup, multicastAdi); - - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: multicastUnsubscribe - * Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastUnsubscribe( - JNIEnv *env, jobject obj, - jlong id, - jlong in_nwid, - jlong in_multicastGroup, - jlong in_multicastAdi) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - uint64_t nwid = (uint64_t)in_nwid; - uint64_t multicastGroup = (uint64_t)in_multicastGroup; - unsigned long multicastAdi = (unsigned long)in_multicastAdi; - - ZT_ResultCode rc = ZT_Node_multicastUnsubscribe( - node, nwid, multicastGroup, multicastAdi); - - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: orbit - * Signature: (JJJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_orbit( - JNIEnv *env, jobject obj, - jlong id, - jlong in_moonWorldId, - jlong in_moonSeed) -{ - int64_t nodeId = (int64_t)id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - uint64_t moonWorldId = (uint64_t)in_moonWorldId; - uint64_t moonSeed = (uint64_t)in_moonSeed; - - ZT_ResultCode rc = ZT_Node_orbit(node, NULL, moonWorldId, moonSeed); - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: deorbit - * Signature: (JJ)L/com/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_deorbit( - JNIEnv *env, jobject obj, - jlong id, - jlong in_moonWorldId) -{ - int64_t nodeId = (int64_t)id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - return createResultObject(env, ZT_RESULT_FATAL_ERROR_INTERNAL); - } - - uint64_t moonWorldId = (uint64_t)in_moonWorldId; - - ZT_ResultCode rc = ZT_Node_deorbit(node, NULL, moonWorldId); - return createResultObject(env, rc); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: address - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_com_zerotier_sdk_Node_address( - JNIEnv *env , jobject obj, jlong id) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return 0; - } - - uint64_t address = ZT_Node_address(node); - return (jlong)address; -} - -/* - * Class: com_zerotier_sdk_Node - * Method: status - * Signature: (J)Lcom/zerotier/sdk/NodeStatus; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_status - (JNIEnv *env, jobject obj, jlong id) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return 0; - } - - jclass nodeStatusClass = NULL; - jmethodID nodeStatusConstructor = NULL; - - // create a com.zerotier.sdk.NodeStatus object - nodeStatusClass = lookup.findClass("com/zerotier/sdk/NodeStatus"); - if(nodeStatusClass == NULL) - { - return NULL; - } - - nodeStatusConstructor = lookup.findMethod( - nodeStatusClass, "", "()V"); - if(nodeStatusConstructor == NULL) - { - return NULL; - } - - jobject nodeStatusObj = env->NewObject(nodeStatusClass, nodeStatusConstructor); - if(nodeStatusObj == NULL) - { - return NULL; - } - - ZT_NodeStatus nodeStatus; - ZT_Node_status(node, &nodeStatus); - - jfieldID addressField = NULL; - jfieldID publicIdentityField = NULL; - jfieldID secretIdentityField = NULL; - jfieldID onlineField = NULL; - - addressField = lookup.findField(nodeStatusClass, "address", "J"); - if(addressField == NULL) - { - return NULL; - } - - publicIdentityField = lookup.findField(nodeStatusClass, "publicIdentity", "Ljava/lang/String;"); - if(publicIdentityField == NULL) - { - return NULL; - } - - secretIdentityField = lookup.findField(nodeStatusClass, "secretIdentity", "Ljava/lang/String;"); - if(secretIdentityField == NULL) - { - return NULL; - } - - onlineField = lookup.findField(nodeStatusClass, "online", "Z"); - if(onlineField == NULL) - { - return NULL; - } - - env->SetLongField(nodeStatusObj, addressField, nodeStatus.address); - - jstring pubIdentStr = env->NewStringUTF(nodeStatus.publicIdentity); - if(pubIdentStr == NULL) - { - return NULL; // out of memory - } - env->SetObjectField(nodeStatusObj, publicIdentityField, pubIdentStr); - - jstring secIdentStr = env->NewStringUTF(nodeStatus.secretIdentity); - if(secIdentStr == NULL) - { - return NULL; // out of memory - } - env->SetObjectField(nodeStatusObj, secretIdentityField, secIdentStr); - - env->SetBooleanField(nodeStatusObj, onlineField, nodeStatus.online); - - return nodeStatusObj; -} - -/* - * Class: com_zerotier_sdk_Node - * Method: networkConfig - * Signature: (J)Lcom/zerotier/sdk/VirtualNetworkConfig; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_networkConfig( - JNIEnv *env, jobject obj, jlong id, jlong nwid) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return 0; - } - - ZT_VirtualNetworkConfig *vnetConfig = ZT_Node_networkConfig(node, nwid); - - jobject vnetConfigObject = newNetworkConfig(env, *vnetConfig); - - ZT_Node_freeQueryResult(node, vnetConfig); - - return vnetConfigObject; -} - -/* - * Class: com_zerotier_sdk_Node - * Method: version - * Signature: (J)Lcom/zerotier/sdk/Version; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_version( - JNIEnv *env, jobject obj) -{ - int major = 0; - int minor = 0; - int revision = 0; - - ZT_version(&major, &minor, &revision); - - return newVersion(env, major, minor, revision); -} - -/* - * Class: com_zerotier_sdk_Node - * Method: peers - * Signature: (J)[Lcom/zerotier/sdk/Peer; - */ -JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers( - JNIEnv *env, jobject obj, jlong id) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return 0; - } - - ZT_PeerList *peerList = ZT_Node_peers(node); - - if(peerList == NULL) - { - LOGE("ZT_Node_peers returned NULL"); - return NULL; - } - - int peerCount = peerList->peerCount * 100; - LOGV("Ensure Local Capacity: %d", peerCount); - if(env->EnsureLocalCapacity(peerCount)) - { - LOGE("EnsureLocalCapacity failed!!"); - ZT_Node_freeQueryResult(node, peerList); - return NULL; - } - - jclass peerClass = lookup.findClass("com/zerotier/sdk/Peer"); - if(env->ExceptionCheck() || peerClass == NULL) - { - LOGE("Error finding Peer class"); - ZT_Node_freeQueryResult(node, peerList); - return NULL; - } - - jobjectArray peerArrayObj = env->NewObjectArray( - peerList->peerCount, peerClass, NULL); - - if(env->ExceptionCheck() || peerArrayObj == NULL) - { - LOGE("Error creating Peer[] array"); - ZT_Node_freeQueryResult(node, peerList); - return NULL; - } - - - for(unsigned int i = 0; i < peerList->peerCount; ++i) - { - jobject peerObj = newPeer(env, peerList->peers[i]); - env->SetObjectArrayElement(peerArrayObj, i, peerObj); - if(env->ExceptionCheck()) - { - LOGE("Error assigning Peer object to array"); - break; - } - } - - ZT_Node_freeQueryResult(node, peerList); - peerList = NULL; - - return peerArrayObj; -} - -/* - * Class: com_zerotier_sdk_Node - * Method: networks - * Signature: (J)[Lcom/zerotier/sdk/VirtualNetworkConfig; - */ -JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks( - JNIEnv *env, jobject obj, jlong id) -{ - int64_t nodeId = (int64_t) id; - ZT_Node *node = findNode(nodeId); - if(node == NULL) - { - // cannot find valid node. We should never get here. - return 0; - } - - ZT_VirtualNetworkList *networkList = ZT_Node_networks(node); - if(networkList == NULL) - { - return NULL; - } - - jclass vnetConfigClass = lookup.findClass("com/zerotier/sdk/VirtualNetworkConfig"); - if(env->ExceptionCheck() || vnetConfigClass == NULL) - { - LOGE("Error finding VirtualNetworkConfig class"); - ZT_Node_freeQueryResult(node, networkList); - return NULL; - } - - jobjectArray networkListObject = env->NewObjectArray( - networkList->networkCount, vnetConfigClass, NULL); - if(env->ExceptionCheck() || networkListObject == NULL) - { - LOGE("Error creating VirtualNetworkConfig[] array"); - ZT_Node_freeQueryResult(node, networkList); - return NULL; - } - - for(unsigned int i = 0; i < networkList->networkCount; ++i) - { - jobject networkObject = newNetworkConfig(env, networkList->networks[i]); - env->SetObjectArrayElement(networkListObject, i, networkObject); - if(env->ExceptionCheck()) - { - LOGE("Error assigning VirtualNetworkConfig object to array"); - break; - } - } - - ZT_Node_freeQueryResult(node, networkList); - - return networkListObject; -} - -#ifdef __cplusplus -} // extern "C" -#endif \ No newline at end of file diff --git a/attic/java/jni/com_zerotierone_sdk_Node.h b/attic/java/jni/com_zerotierone_sdk_Node.h deleted file mode 100644 index 8487d8af2..000000000 --- a/attic/java/jni/com_zerotierone_sdk_Node.h +++ /dev/null @@ -1,133 +0,0 @@ -/* DO NOT EDIT THIS FILE - it is machine generated */ -#include -/* Header for class com_zerotier_sdk_Node */ - -#ifndef _Included_com_zerotierone_sdk_Node -#define _Included_com_zerotierone_sdk_Node -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: com_zerotier_sdk_Node - * Method: node_init - * Signature: (J)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_node_1init - (JNIEnv *, jobject, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: node_delete - * Signature: (J)V - */ -JNIEXPORT void JNICALL Java_com_zerotier_sdk_Node_node_1delete - (JNIEnv *, jobject, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: processVirtualNetworkFrame - * Signature: (JJJJJII[B[J)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processVirtualNetworkFrame - (JNIEnv *, jobject, jlong, jlong, jlong, jlong, jlong, jint, jint, jbyteArray, jlongArray); - -/* - * Class: com_zerotier_sdk_Node - * Method: processWirePacket - * Signature: (JJLjava/net/InetSockAddress;Ljava/net/InetSockAddress;[B[J)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processWirePacket - (JNIEnv *, jobject, jlong, jlong, jlong, jobject, jbyteArray, jlongArray); - -/* - * Class: com_zerotier_sdk_Node - * Method: processBackgroundTasks - * Signature: (JJ[J)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_processBackgroundTasks - (JNIEnv *, jobject, jlong, jlong, jlongArray); - -/* - * Class: com_zerotier_sdk_Node - * Method: join - * Signature: (JJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_join - (JNIEnv *, jobject, jlong, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: leave - * Signature: (JJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_leave - (JNIEnv *, jobject, jlong, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: multicastSubscribe - * Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastSubscribe - (JNIEnv *, jobject, jlong, jlong, jlong, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: multicastUnsubscribe - * Signature: (JJJJ)Lcom/zerotier/sdk/ResultCode; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_multicastUnsubscribe - (JNIEnv *, jobject, jlong, jlong, jlong, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: address - * Signature: (J)J - */ -JNIEXPORT jlong JNICALL Java_com_zerotier_sdk_Node_address - (JNIEnv *, jobject, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: status - * Signature: (J)Lcom/zerotier/sdk/NodeStatus; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_status - (JNIEnv *, jobject, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: networkConfig - * Signature: (JJ)Lcom/zerotier/sdk/VirtualNetworkConfig; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_networkConfig - (JNIEnv *, jobject, jlong, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: version - * Signature: ()Lcom/zerotier/sdk/Version; - */ -JNIEXPORT jobject JNICALL Java_com_zerotier_sdk_Node_version - (JNIEnv *, jobject); - -/* - * Class: com_zerotier_sdk_Node - * Method: peers - * Signature: (J)[Lcom/zerotier/sdk/Peer; - */ -JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_peers - (JNIEnv *, jobject, jlong); - -/* - * Class: com_zerotier_sdk_Node - * Method: networks - * Signature: (J)[Lcom/zerotier/sdk/VirtualNetworkConfig; - */ -JNIEXPORT jobjectArray JNICALL Java_com_zerotier_sdk_Node_networks - (JNIEnv *, jobject, jlong); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/attic/java/src/com/zerotier/sdk/DataStoreGetListener.java b/attic/java/src/com/zerotier/sdk/DataStoreGetListener.java deleted file mode 100644 index 317511e0c..000000000 --- a/attic/java/src/com/zerotier/sdk/DataStoreGetListener.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ -package com.zerotier.sdk; - -public interface DataStoreGetListener { - - /** - * Function to get an object from the data store - * - *

Object names can contain forward slash (/) path separators. They will - * never contain .. or backslash (\), so this is safe to map as a Unix-style - * path if the underlying storage permits. For security reasons we recommend - * returning errors if .. or \ are used.

- * - *

The function must return the actual number of bytes read. If the object - * doesn't exist, it should return -1. -2 should be returned on other errors - * such as errors accessing underlying storage.

- * - *

If the read doesn't fit in the buffer, the max number of bytes should be - * read. The caller may call the function multiple times to read the whole - * object.

- * - * @param name Name of the object in the data store - * @param out_buffer buffer to put the object in - * @return size of the object - */ - public long onDataStoreGet( - String name, - byte[] out_buffer); -} diff --git a/attic/java/src/com/zerotier/sdk/DataStorePutListener.java b/attic/java/src/com/zerotier/sdk/DataStorePutListener.java deleted file mode 100644 index 77e55027e..000000000 --- a/attic/java/src/com/zerotier/sdk/DataStorePutListener.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ -package com.zerotier.sdk; - -public interface DataStorePutListener { - - /** - * Function to store an object in the data store - * - *

If secure is true, the file should be set readable and writable only - * to the user running ZeroTier One. What this means is platform-specific.

- * - *

Name semantics are the same as {@link DataStoreGetListener}. This must return - * zero on success. You can return any OS-specific error code on failure, as these - * may be visible in logs or error messages and might aid in debugging.

- * - * @param name Object name - * @param buffer data to store - * @param secure set to user read/write only. - * @return 0 on success. - */ - public int onDataStorePut( - String name, - byte[] buffer, - boolean secure); - - /** - * Function to delete an object from the data store - * - * @param name Object name - * @return 0 on success. - */ - public int onDelete( - String name); -} diff --git a/attic/java/src/com/zerotier/sdk/Event.java b/attic/java/src/com/zerotier/sdk/Event.java deleted file mode 100644 index 22d350e1e..000000000 --- a/attic/java/src/com/zerotier/sdk/Event.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -public enum Event { - /** - * Node has been initialized - * - * This is the first event generated, and is always sent. It may occur - * before Node's constructor returns. - */ - EVENT_UP, - - /** - * Node is offline -- network does not seem to be reachable by any available strategy - */ - EVENT_OFFLINE, - - /** - * Node is online -- at least one upstream node appears reachable - * - * Meta-data: none - */ - EVENT_ONLINE, - - /** - * Node is shutting down - * - *

This is generated within Node's destructor when it is being shut down. - * It's done for convenience, since cleaning up other state in the event - * handler may appear more idiomatic.

- */ - EVENT_DOWN, - - /** - * Your identity has collided with another node's ZeroTier address - * - *

This happens if two different public keys both hash (via the algorithm - * in Identity::generate()) to the same 40-bit ZeroTier address.

- * - *

This is something you should "never" see, where "never" is defined as - * once per 2^39 new node initializations / identity creations. If you do - * see it, you're going to see it very soon after a node is first - * initialized.

- * - *

This is reported as an event rather than a return code since it's - * detected asynchronously via error messages from authoritative nodes.

- * - *

If this occurs, you must shut down and delete the node, delete the - * identity.secret record/file from the data store, and restart to generate - * a new identity. If you don't do this, you will not be able to communicate - * with other nodes.

- * - *

We'd automate this process, but we don't think silently deleting - * private keys or changing our address without telling the calling code - * is good form. It violates the principle of least surprise.

- * - *

You can technically get away with not handling this, but we recommend - * doing so in a mature reliable application. Besides, handling this - * condition is a good way to make sure it never arises. It's like how - * umbrellas prevent rain and smoke detectors prevent fires. They do, right?

- */ - EVENT_FATAL_ERROR_IDENTITY_COLLISION, - - /** - * Trace (debugging) message - * - *

These events are only generated if this is a TRACE-enabled build.

- * - *

Meta-data: {@link String}, TRACE message

- */ - EVENT_TRACE -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/EventListener.java b/attic/java/src/com/zerotier/sdk/EventListener.java deleted file mode 100644 index 91050aaa9..000000000 --- a/attic/java/src/com/zerotier/sdk/EventListener.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -import java.net.InetSocketAddress; -import java.lang.String; - -/** - * Interface to handle callbacks for ZeroTier One events. - */ -public interface EventListener { - /** - * Callback for events with no other associated metadata - * - * @param event {@link Event} enum - */ - public void onEvent(Event event); - - /** - * Trace messages - * - *

These events are only generated if the underlying ZeroTierOne SDK is a TRACE-enabled build.

- * - * @param message the trace message - */ - public void onTrace(String message); -} diff --git a/attic/java/src/com/zerotier/sdk/NativeUtils.java b/attic/java/src/com/zerotier/sdk/NativeUtils.java deleted file mode 100644 index 07e1ef5bc..000000000 --- a/attic/java/src/com/zerotier/sdk/NativeUtils.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.zerotier.sdk; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -/** - * Simple library class for working with JNI (Java Native Interface) - * - * @see http://adamheinrich.com/2012/how-to-load-native-jni-library-from-jar - * - * @author Adam Heirnich , http://www.adamh.cz - */ -public class NativeUtils { - - /** - * Private constructor - this class will never be instanced - */ - private NativeUtils() { - } - - /** - * Loads library from current JAR archive - * - * The file from JAR is copied into system temporary directory and then loaded. The temporary file is deleted after exiting. - * Method uses String as filename because the pathname is "abstract", not system-dependent. - * - * @param filename The filename inside JAR as absolute path (beginning with '/'), e.g. /package/File.ext - * @throws IOException If temporary file creation or read/write operation fails - * @throws IllegalArgumentException If source file (param path) does not exist - * @throws IllegalArgumentException If the path is not absolute or if the filename is shorter than three characters (restriction of {@see File#createTempFile(java.lang.String, java.lang.String)}). - */ - public static void loadLibraryFromJar(String path) throws IOException { - - if (!path.startsWith("/")) { - throw new IllegalArgumentException("The path has to be absolute (start with '/')."); - } - - // Obtain filename from path - String[] parts = path.split("/"); - String filename = (parts.length > 1) ? parts[parts.length - 1] : null; - - // Split filename to prexif and suffix (extension) - String prefix = ""; - String suffix = null; - if (filename != null) { - parts = filename.split("\\.", 2); - prefix = parts[0]; - suffix = (parts.length > 1) ? "."+parts[parts.length - 1] : null; // Thanks, davs! :-) - } - - // Check if the filename is okay - if (filename == null || prefix.length() < 3) { - throw new IllegalArgumentException("The filename has to be at least 3 characters long."); - } - - // Prepare temporary file - File temp = File.createTempFile(prefix, suffix); - temp.deleteOnExit(); - - if (!temp.exists()) { - throw new FileNotFoundException("File " + temp.getAbsolutePath() + " does not exist."); - } - - // Prepare buffer for data copying - byte[] buffer = new byte[1024]; - int readBytes; - - // Open and check input stream - InputStream is = NativeUtils.class.getResourceAsStream(path); - if (is == null) { - throw new FileNotFoundException("File " + path + " was not found inside JAR."); - } - - // Open output stream and copy data between source file in JAR and the temporary file - OutputStream os = new FileOutputStream(temp); - try { - while ((readBytes = is.read(buffer)) != -1) { - os.write(buffer, 0, readBytes); - } - } finally { - // If read/write fails, close streams safely before throwing an exception - os.close(); - is.close(); - } - - // Finally, load the library - System.load(temp.getAbsolutePath()); - } -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/Node.java b/attic/java/src/com/zerotier/sdk/Node.java deleted file mode 100644 index ef6ac9d2d..000000000 --- a/attic/java/src/com/zerotier/sdk/Node.java +++ /dev/null @@ -1,475 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.io.IOException; - -/** - * A ZeroTier One node - */ -public class Node { - static { - try { - System.loadLibrary("ZeroTierOneJNI"); - } catch (UnsatisfiedLinkError e) { - try { - if(System.getProperty("os.name").startsWith("Windows")) { - System.out.println("Arch: " + System.getProperty("sun.arch.data.model")); - if(System.getProperty("sun.arch.data.model").equals("64")) { - NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win64.dll"); - } else { - NativeUtils.loadLibraryFromJar("/lib/ZeroTierOneJNI_win32.dll"); - } - } else if(System.getProperty("os.name").startsWith("Mac")) { - NativeUtils.loadLibraryFromJar("/lib/libZeroTierOneJNI.jnilib"); - } else { - // TODO: Linux - } - } catch (IOException ioe) { - ioe.printStackTrace(); - } - } - } - - private static final String TAG = "NODE"; - - /** - * Node ID for JNI purposes. - * Currently set to the now value passed in at the constructor - * - * -1 if the node has already been closed - */ - private long nodeId; - - private final DataStoreGetListener getListener; - private final DataStorePutListener putListener; - private final PacketSender sender; - private final EventListener eventListener; - private final VirtualNetworkFrameListener frameListener; - private final VirtualNetworkConfigListener configListener; - private final PathChecker pathChecker; - - /** - * Create a new ZeroTier One node - * - *

Note that this can take a few seconds the first time it's called, as it - * will generate an identity.

- * - * @param now Current clock in milliseconds - * @param getListener User written instance of the {@link DataStoreGetListener} interface called to get objects from persistent storage. This instance must be unique per Node object. - * @param putListener User written intstance of the {@link DataStorePutListener} interface called to put objects in persistent storage. This instance must be unique per Node object. - * @param sender - * @param eventListener User written instance of the {@link EventListener} interface to receive status updates and non-fatal error notices. This instance must be unique per Node object. - * @param frameListener - * @param configListener User written instance of the {@link VirtualNetworkConfigListener} interface to be called when virtual LANs are created, deleted, or their config parameters change. This instance must be unique per Node object. - * @param pathChecker User written instance of the {@link PathChecker} interface. Not required and can be null. - */ - public Node(long now, - DataStoreGetListener getListener, - DataStorePutListener putListener, - PacketSender sender, - EventListener eventListener, - VirtualNetworkFrameListener frameListener, - VirtualNetworkConfigListener configListener, - PathChecker pathChecker) throws NodeException - { - this.nodeId = now; - - this.getListener = getListener; - this.putListener = putListener; - this.sender = sender; - this.eventListener = eventListener; - this.frameListener = frameListener; - this.configListener = configListener; - this.pathChecker = pathChecker; - - ResultCode rc = node_init(now); - if(rc != ResultCode.RESULT_OK) - { - // TODO: Throw Exception - throw new NodeException(rc.toString()); - } - } - - /** - * Close this Node. - * - *

The Node object can no longer be used once this method is called.

- */ - public void close() { - if(nodeId != -1) { - node_delete(nodeId); - nodeId = -1; - } - } - - @Override - protected void finalize() { - close(); - } - - /** - * Process a frame from a virtual network port - * - * @param now Current clock in milliseconds - * @param nwid ZeroTier 64-bit virtual network ID - * @param sourceMac Source MAC address (least significant 48 bits) - * @param destMac Destination MAC address (least significant 48 bits) - * @param etherType 16-bit Ethernet frame type - * @param vlanId 10-bit VLAN ID or 0 if none - * @param frameData Frame payload data - * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode processVirtualNetworkFrame( - long now, - long nwid, - long sourceMac, - long destMac, - int etherType, - int vlanId, - byte[] frameData, - long[] nextBackgroundTaskDeadline) { - return processVirtualNetworkFrame( - nodeId, now, nwid, sourceMac, destMac, etherType, vlanId, - frameData, nextBackgroundTaskDeadline); - } - - /** - * Process a packet received from the physical wire - * - * @param now Current clock in milliseconds - * @param remoteAddress Origin of packet - * @param packetData Packet data - * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode processWirePacket( - long now, - long localSocket, - InetSocketAddress remoteAddress, - byte[] packetData, - long[] nextBackgroundTaskDeadline) { - return processWirePacket( - nodeId, now, localSocket, remoteAddress, packetData, - nextBackgroundTaskDeadline); - } - - /** - * Perform periodic background operations - * - * @param now Current clock in milliseconds - * @param nextBackgroundTaskDeadline Value/result: set to deadline for next call to processBackgroundTasks() - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode processBackgroundTasks(long now, long[] nextBackgroundTaskDeadline) { - return processBackgroundTasks(nodeId, now, nextBackgroundTaskDeadline); - } - - /** - * Join a network - * - *

This may generate calls to the port config callback before it returns, - * or these may be deffered if a netconf is not available yet.

- * - *

If we are already a member of the network, nothing is done and OK is - * returned.

- * - * @param nwid 64-bit ZeroTier network ID - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode join(long nwid) { - return join(nodeId, nwid); - } - - /** - * Leave a network - * - *

If a port has been configured for this network this will generate a call - * to the port config callback with a NULL second parameter to indicate that - * the port is now deleted.

- * - * @param nwid 64-bit network ID - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode leave(long nwid) { - return leave(nodeId, nwid); - } - - /** - * Subscribe to an Ethernet multicast group - * - *

For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the - * broadcast address) but with an ADI equal to each IPv4 address in host - * byte order. This converts ARP from a non-scalable broadcast protocol to - * a scalable multicast protocol with perfect address specificity.

- * - *

If this is not done, ARP will not work reliably.

- * - *

Multiple calls to subscribe to the same multicast address will have no - * effect. It is perfectly safe to do this.

- * - *

This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.

- * - * @param nwid 64-bit network ID - * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode multicastSubscribe( - long nwid, - long multicastGroup) { - return multicastSubscribe(nodeId, nwid, multicastGroup, 0); - } - - /** - * Subscribe to an Ethernet multicast group - * - *

ADI stands for additional distinguishing information. This defaults to zero - * and is rarely used. Right now its only use is to enable IPv4 ARP to scale, - * and this must be done.

- * - *

For IPv4 ARP, the implementation must subscribe to 0xffffffffffff (the - * broadcast address) but with an ADI equal to each IPv4 address in host - * byte order. This converts ARP from a non-scalable broadcast protocol to - * a scalable multicast protocol with perfect address specificity.

- * - *

If this is not done, ARP will not work reliably.

- * - *

Multiple calls to subscribe to the same multicast address will have no - * effect. It is perfectly safe to do this.

- * - *

This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.

- * - * @param nwid 64-bit network ID - * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) - * @param multicastAdi Multicast ADI (least significant 32 bits only, default: 0) - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode multicastSubscribe( - long nwid, - long multicastGroup, - long multicastAdi) { - return multicastSubscribe(nodeId, nwid, multicastGroup, multicastAdi); - } - - - /** - * Unsubscribe from an Ethernet multicast group (or all groups) - * - *

If multicastGroup is zero (0), this will unsubscribe from all groups. If - * you are not subscribed to a group this has no effect.

- * - *

This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.

- * - * @param nwid 64-bit network ID - * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode multicastUnsubscribe( - long nwid, - long multicastGroup) { - return multicastUnsubscribe(nodeId, nwid, multicastGroup, 0); - } - - /** - * Unsubscribe from an Ethernet multicast group (or all groups) - * - *

If multicastGroup is zero (0), this will unsubscribe from all groups. If - * you are not subscribed to a group this has no effect.

- * - *

This does not generate an update call to the {@link VirtualNetworkConfigListener#onNetworkConfigurationUpdated} method.

- * - *

ADI stands for additional distinguishing information. This defaults to zero - * and is rarely used. Right now its only use is to enable IPv4 ARP to scale, - * and this must be done.

- * - * @param nwid 64-bit network ID - * @param multicastGroup Ethernet multicast or broadcast MAC (least significant 48 bits) - * @param multicastAdi Multicast ADI (least significant 32 bits only, default: 0) - * @return OK (0) or error code if a fatal error condition has occurred - */ - public ResultCode multicastUnsubscribe( - long nwid, - long multicastGroup, - long multicastAdi) { - return multicastUnsubscribe(nodeId, nwid, multicastGroup, multicastAdi); - } - - /** - * Add or update a moon - * - * Moons are persisted in the data store in moons.d/, so this can persist - * across invocations if the contents of moon.d are scanned and orbit is - * called for each on startup. - * - * @param moonWorldId Moon's world ID - * @param moonSeed If non-zero, the ZeroTier address of any member of the moon to query for moon definition - * @return Error if moon was invalid or failed to be added - */ - public ResultCode orbit( - long moonWorldId, - long moonSeed) { - return orbit(nodeId, moonWorldId, moonSeed); - } - - /** - * Remove a moon (does nothing if not present) - * - * @param moonWorldId World ID of moon to remove - * @return Error if anything bad happened - */ - public ResultCode deorbit( - long moonWorldId) { - return deorbit(nodeId, moonWorldId); - } - - /** - * Get this node's 40-bit ZeroTier address - * - * @return ZeroTier address (least significant 40 bits of 64-bit int) - */ - public long address() { - return address(nodeId); - } - - /** - * Get the status of this node - * - * @return @{link NodeStatus} struct with the current node status. - */ - public NodeStatus status() { - return status(nodeId); - } - - /** - * Get a list of known peer nodes - * - * @return List of known peers or NULL on failure - */ - public Peer[] peers() { - return peers(nodeId); - } - - /** - * Get the status of a virtual network - * - * @param nwid 64-bit network ID - * @return {@link VirtualNetworkConfig} or NULL if we are not a member of this network - */ - public VirtualNetworkConfig networkConfig(long nwid) { - return networkConfig(nodeId, nwid); - } - - /** - * Enumerate and get status of all networks - * - * @return List of networks or NULL on failure - */ - public VirtualNetworkConfig[] networks() { - return networks(nodeId); - } - - /** - * Get ZeroTier One version - * - * @return {@link Version} object with ZeroTierOne version information. - */ - public Version getVersion() { - return version(); - } - - // - // function declarations for JNI - // - private native ResultCode node_init(long now); - - private native void node_delete(long nodeId); - - private native ResultCode processVirtualNetworkFrame( - long nodeId, - long now, - long nwid, - long sourceMac, - long destMac, - int etherType, - int vlanId, - byte[] frameData, - long[] nextBackgroundTaskDeadline); - - private native ResultCode processWirePacket( - long nodeId, - long now, - long localSocket, - InetSocketAddress remoteAddress, - byte[] packetData, - long[] nextBackgroundTaskDeadline); - - private native ResultCode processBackgroundTasks( - long nodeId, - long now, - long[] nextBackgroundTaskDeadline); - - private native ResultCode join(long nodeId, long nwid); - - private native ResultCode leave(long nodeId, long nwid); - - private native ResultCode multicastSubscribe( - long nodeId, - long nwid, - long multicastGroup, - long multicastAdi); - - private native ResultCode multicastUnsubscribe( - long nodeId, - long nwid, - long multicastGroup, - long multicastAdi); - - private native ResultCode orbit( - long nodeId, - long moonWorldId, - long moonSeed); - - private native ResultCode deorbit( - long nodeId, - long moonWorldId); - - private native long address(long nodeId); - - private native NodeStatus status(long nodeId); - - private native VirtualNetworkConfig networkConfig(long nodeId, long nwid); - - private native Version version(); - - private native Peer[] peers(long nodeId); - - private native VirtualNetworkConfig[] networks(long nodeId); -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/NodeException.java b/attic/java/src/com/zerotier/sdk/NodeException.java deleted file mode 100644 index 1fdef72f8..000000000 --- a/attic/java/src/com/zerotier/sdk/NodeException.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -import java.lang.RuntimeException; - -public class NodeException extends RuntimeException { - public NodeException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/NodeStatus.java b/attic/java/src/com/zerotier/sdk/NodeStatus.java deleted file mode 100644 index 94376d85b..000000000 --- a/attic/java/src/com/zerotier/sdk/NodeStatus.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -public final class NodeStatus { - private long address; - private String publicIdentity; - private String secretIdentity; - private boolean online; - - private NodeStatus() {} - - /** - * 40-bit ZeroTier address of this node - */ - public final long getAddres() { - return address; - } - - /** - * Public identity in string-serialized form (safe to send to others) - * - *

This identity will remain valid as long as the node exists.

- */ - public final String getPublicIdentity() { - return publicIdentity; - } - - /** - * Full identity including secret key in string-serialized form - * - *

This identity will remain valid as long as the node exists.

- */ - public final String getSecretIdentity() { - return secretIdentity; - } - - /** - * True if some kind of connectivity appears available - */ - public final boolean isOnline() { - return online; - } -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/PacketSender.java b/attic/java/src/com/zerotier/sdk/PacketSender.java deleted file mode 100644 index 06ec01bcc..000000000 --- a/attic/java/src/com/zerotier/sdk/PacketSender.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ -package com.zerotier.sdk; - -import java.net.InetSocketAddress; - - -public interface PacketSender { - /** - * Function to send a ZeroTier packet out over the wire - * - *

The function must return zero on success and may return any error code - * on failure. Note that success does not (of course) guarantee packet - * delivery. It only means that the packet appears to have been sent.

- * - * @param localSocket socket file descriptor to send from. Set to -1 if not specified. - * @param remoteAddr {@link InetSocketAddress} to send to - * @param packetData data to send - * @return 0 on success, any error code on failure. - */ - public int onSendPacketRequested( - long localSocket, - InetSocketAddress remoteAddr, - byte[] packetData, - int ttl); -} diff --git a/attic/java/src/com/zerotier/sdk/PathChecker.java b/attic/java/src/com/zerotier/sdk/PathChecker.java deleted file mode 100644 index 6bf31df2b..000000000 --- a/attic/java/src/com/zerotier/sdk/PathChecker.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -import java.net.InetSocketAddress; - -public interface PathChecker { - /** - * Callback to check whether a path should be used for ZeroTier traffic - * - * This function must return true if the path should be used. - * - * If no path check function is specified, ZeroTier will still exclude paths - * that overlap with ZeroTier-assigned and managed IP address blocks. But the - * use of a path check function is recommended to ensure that recursion does - * not occur in cases where addresses are assigned by the OS or managed by - * an out of band mechanism like DHCP. The path check function should examine - * all configured ZeroTier interfaces and check to ensure that the supplied - * addresses will not result in ZeroTier traffic being sent over a ZeroTier - * interface (recursion). - * - * Obviously this is not required in configurations where this can't happen, - * such as network containers or embedded. - * - * @param ztAddress ZeroTier address or 0 for none/any - * @param localSocket Local interface socket. -1 if unspecified - * @param remoteAddress remote address - */ - boolean onPathCheck(long ztAddress, long localSocket, InetSocketAddress remoteAddress); - - /** - * Function to get physical addresses for ZeroTier peers - * - * If provided this function will be occasionally called to get physical - * addresses that might be tried to reach a ZeroTier address. - * - * @param ztAddress ZeroTier address (least significant 40 bits) - * @param ss_family desired address family or -1 for any - * @return address and port of ztAddress or null - */ - InetSocketAddress onPathLookup(long ztAddress, int ss_family); -} diff --git a/attic/java/src/com/zerotier/sdk/Peer.java b/attic/java/src/com/zerotier/sdk/Peer.java deleted file mode 100644 index eb3d71300..000000000 --- a/attic/java/src/com/zerotier/sdk/Peer.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -import java.util.ArrayList; - -/** - * Peer status result - */ -public final class Peer { - private long address; - private int versionMajor; - private int versionMinor; - private int versionRev; - private int latency; - private PeerRole role; - private PeerPhysicalPath[] paths; - - private Peer() {} - - /** - * ZeroTier address (40 bits) - */ - public final long address() { - return address; - } - - /** - * Remote major version or -1 if not known - */ - public final int versionMajor() { - return versionMajor; - } - - /** - * Remote minor version or -1 if not known - */ - public final int versionMinor() { - return versionMinor; - } - - /** - * Remote revision or -1 if not known - */ - public final int versionRev() { - return versionRev; - } - - /** - * Last measured latency in milliseconds or zero if unknown - */ - public final int latency() { - return latency; - } - - /** - * What trust hierarchy role does this device have? - */ - public final PeerRole role() { - return role; - } - - /** - * Known network paths to peer - */ - public final PeerPhysicalPath[] paths() { - return paths; - } -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/PeerPhysicalPath.java b/attic/java/src/com/zerotier/sdk/PeerPhysicalPath.java deleted file mode 100644 index 3f9a86128..000000000 --- a/attic/java/src/com/zerotier/sdk/PeerPhysicalPath.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -import java.net.InetSocketAddress; - -/** - * Physical network path to a peer - */ -public final class PeerPhysicalPath { - private InetSocketAddress address; - private long lastSend; - private long lastReceive; - private boolean fixed; - private boolean preferred; - - private PeerPhysicalPath() {} - - /** - * Address of endpoint - */ - public final InetSocketAddress address() { - return address; - } - - /** - * Time of last send in milliseconds or 0 for never - */ - public final long lastSend() { - return lastSend; - } - - /** - * Time of last receive in milliseconds or 0 for never - */ - public final long lastReceive() { - return lastReceive; - } - - /** - * Is path fixed? (i.e. not learned, static) - */ - public final boolean isFixed() { - return fixed; - } - - /** - * Is path preferred? - */ - public final boolean isPreferred() { - return preferred; - } -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/PeerRole.java b/attic/java/src/com/zerotier/sdk/PeerRole.java deleted file mode 100644 index fce183d9c..000000000 --- a/attic/java/src/com/zerotier/sdk/PeerRole.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -public enum PeerRole { - /** - * An ordinary node - */ - PEER_ROLE_LEAF, - - /** - * moon root - */ - PEER_ROLE_MOON, - - /** - * planetary root - */ - PEER_ROLE_PLANET -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/ResultCode.java b/attic/java/src/com/zerotier/sdk/ResultCode.java deleted file mode 100644 index 5da82b319..000000000 --- a/attic/java/src/com/zerotier/sdk/ResultCode.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -/** - * Function return code: OK (0) or error results - * - *

Use {@link ResultCode#isFatal) to check for a fatal error. If a fatal error - * occurs, the node should be considered to not be working correctly. These - * indicate serious problems like an inaccessible data store or a compile - * problem.

- */ -public enum ResultCode { - /** - * Operation completed normally - */ - RESULT_OK(0), - - // Fatal errors (> 0, < 1000) - /** - * Ran out of memory - */ - RESULT_FATAL_ERROR_OUT_OF_MEMORY(1), - - /** - * Data store is not writable or has failed - */ - RESULT_FATAL_ERROR_DATA_STORE_FAILED(2), - - /** - * Internal error (e.g. unexpected exception indicating bug or build problem) - */ - RESULT_FATAL_ERROR_INTERNAL(3), - - // non-fatal errors - - /** - * Network ID not valid - */ - RESULT_ERROR_NETWORK_NOT_FOUND(1000); - - private final int id; - ResultCode(int id) { this.id = id; } - public int getValue() { return id; } - - public boolean isFatal(int id) { - return (id > 0 && id < 1000); - } -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/Version.java b/attic/java/src/com/zerotier/sdk/Version.java deleted file mode 100644 index c93c25970..000000000 --- a/attic/java/src/com/zerotier/sdk/Version.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -public final class Version { - private Version() {} - - public int major = 0; - public int minor = 0; - public int revision = 0; -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/VirtualNetworkConfig.java b/attic/java/src/com/zerotier/sdk/VirtualNetworkConfig.java deleted file mode 100644 index 64512dadd..000000000 --- a/attic/java/src/com/zerotier/sdk/VirtualNetworkConfig.java +++ /dev/null @@ -1,210 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -import java.lang.Comparable; -import java.lang.Override; -import java.lang.String; -import java.util.ArrayList; -import java.net.InetSocketAddress; - -public final class VirtualNetworkConfig implements Comparable { - public static final int MAX_MULTICAST_SUBSCRIPTIONS = 4096; - public static final int ZT_MAX_ZT_ASSIGNED_ADDRESSES = 16; - - private long nwid; - private long mac; - private String name; - private VirtualNetworkStatus status; - private VirtualNetworkType type; - private int mtu; - private boolean dhcp; - private boolean bridge; - private boolean broadcastEnabled; - private int portError; - private boolean enabled; - private long netconfRevision; - private InetSocketAddress[] assignedAddresses; - private VirtualNetworkRoute[] routes; - - private VirtualNetworkConfig() { - - } - - public boolean equals(VirtualNetworkConfig cfg) { - boolean aaEqual = true; - if(assignedAddresses.length == cfg.assignedAddresses.length) { - for(int i = 0; i < assignedAddresses.length; ++i) { - if(!assignedAddresses[i].equals(cfg.assignedAddresses[i])) { - aaEqual = false; - } - } - } else { - aaEqual = false; - } - - boolean routesEqual = true; - if(routes.length == cfg.routes.length) { - for (int i = 0; i < routes.length; ++i) { - if (!routes[i].equals(cfg.routes[i])) { - routesEqual = false; - } - } - } else { - routesEqual = false; - } - - return nwid == cfg.nwid && - mac == cfg.mac && - name.equals(cfg.name) && - status.equals(cfg.status) && - type.equals(cfg.type) && - mtu == cfg.mtu && - dhcp == cfg.dhcp && - bridge == cfg.bridge && - broadcastEnabled == cfg.broadcastEnabled && - portError == cfg.portError && - enabled == cfg.enabled && - aaEqual && routesEqual; - } - - public int compareTo(VirtualNetworkConfig cfg) { - if(cfg.nwid == this.nwid) { - return 0; - } else { - return this.nwid > cfg.nwid ? 1 : -1; - } - } - - /** - * 64-bit ZeroTier network ID - */ - public final long networkId() { - return nwid; - } - - /** - * Ethernet MAC (40 bits) that should be assigned to port - */ - public final long macAddress() { - return mac; - } - - /** - * Network name (from network configuration master) - */ - public final String name() { - return name; - } - - /** - * Network configuration request status - */ - public final VirtualNetworkStatus networkStatus() { - return status; - } - - /** - * Network type - */ - public final VirtualNetworkType networkType() { - return type; - } - - /** - * Maximum interface MTU - */ - public final int mtu() { - return mtu; - } - - /** - * If the network this port belongs to indicates DHCP availability - * - *

This is a suggestion. The underlying implementation is free to ignore it - * for security or other reasons. This is simply a netconf parameter that - * means 'DHCP is available on this network.'

- */ - public final boolean isDhcpAvailable() { - return dhcp; - } - - /** - * If this port is allowed to bridge to other networks - * - *

This is informational. If this is false, bridged packets will simply - * be dropped and bridging won't work.

- */ - public final boolean isBridgeEnabled() { - return bridge; - } - - /** - * If true, this network supports and allows broadcast (ff:ff:ff:ff:ff:ff) traffic - */ - public final boolean broadcastEnabled() { - return broadcastEnabled; - } - - /** - * If the network is in PORT_ERROR state, this is the error most recently returned by the port config callback - */ - public final int portError() { - return portError; - } - - /** - * Network config revision as reported by netconf master - * - *

If this is zero, it means we're still waiting for our netconf.

- */ - public final long netconfRevision() { - return netconfRevision; - } - - /** - * ZeroTier-assigned addresses (in {@link java.net.InetSocketAddress} objects) - * - * For IP, the port number of the sockaddr_XX structure contains the number - * of bits in the address netmask. Only the IP address and port are used. - * Other fields like interface number can be ignored. - * - * This is only used for ZeroTier-managed address assignments sent by the - * virtual network's configuration master. - */ - public final InetSocketAddress[] assignedAddresses() { - return assignedAddresses; - } - - /** - * ZeroTier-assigned routes (in {@link com.zerotier.sdk.VirtualNetworkRoute} objects) - * - * @return - */ - public final VirtualNetworkRoute[] routes() { return routes; } -} diff --git a/attic/java/src/com/zerotier/sdk/VirtualNetworkConfigListener.java b/attic/java/src/com/zerotier/sdk/VirtualNetworkConfigListener.java deleted file mode 100644 index 15ae301cd..000000000 --- a/attic/java/src/com/zerotier/sdk/VirtualNetworkConfigListener.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - - -package com.zerotier.sdk; - - -public interface VirtualNetworkConfigListener { - /** - * Callback called to update virtual network port configuration - * - *

This can be called at any time to update the configuration of a virtual - * network port. The parameter after the network ID specifies whether this - * port is being brought up, updated, brought down, or permanently deleted. - * - * This in turn should be used by the underlying implementation to create - * and configure tap devices at the OS (or virtual network stack) layer.

- * - * This should not call {@link Node#multicastSubscribe} or other network-modifying - * methods, as this could cause a deadlock in multithreaded or interrupt - * driven environments. - * - * This must return 0 on success. It can return any OS-dependent error code - * on failure, and this results in the network being placed into the - * PORT_ERROR state. - * - * @param nwid network id - * @param op {@link VirtualNetworkConfigOperation} enum describing the configuration operation - * @param config {@link VirtualNetworkConfig} object with the new configuration - * @return 0 on success - */ - public int onNetworkConfigurationUpdated( - long nwid, - VirtualNetworkConfigOperation op, - VirtualNetworkConfig config); -} \ No newline at end of file diff --git a/attic/java/src/com/zerotier/sdk/VirtualNetworkConfigOperation.java b/attic/java/src/com/zerotier/sdk/VirtualNetworkConfigOperation.java deleted file mode 100644 index b70eb4786..000000000 --- a/attic/java/src/com/zerotier/sdk/VirtualNetworkConfigOperation.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ -package com.zerotier.sdk; - -public enum VirtualNetworkConfigOperation { - /** - * Network is coming up (either for the first time or after service restart) - */ - VIRTUAL_NETWORK_CONFIG_OPERATION_UP, - - /** - * Network configuration has been updated - */ - VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE, - - /** - * Network is going down (not permanently) - */ - VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN, - - /** - * Network is going down permanently (leave/delete) - */ - VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY -} diff --git a/attic/java/src/com/zerotier/sdk/VirtualNetworkFrameListener.java b/attic/java/src/com/zerotier/sdk/VirtualNetworkFrameListener.java deleted file mode 100644 index 9ad322825..000000000 --- a/attic/java/src/com/zerotier/sdk/VirtualNetworkFrameListener.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -public interface VirtualNetworkFrameListener { - /** - * Function to send a frame out to a virtual network port - * - * @param nwid ZeroTier One network ID - * @param srcMac source MAC address - * @param destMac destination MAC address - * @param ethertype - * @param vlanId - * @param frameData data to send - */ - public void onVirtualNetworkFrame( - long nwid, - long srcMac, - long destMac, - long etherType, - long vlanId, - byte[] frameData); -} diff --git a/attic/java/src/com/zerotier/sdk/VirtualNetworkRoute.java b/attic/java/src/com/zerotier/sdk/VirtualNetworkRoute.java deleted file mode 100644 index b89dce7ba..000000000 --- a/attic/java/src/com/zerotier/sdk/VirtualNetworkRoute.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ - -package com.zerotier.sdk; - -import java.net.InetSocketAddress; - -public final class VirtualNetworkRoute implements Comparable -{ - private VirtualNetworkRoute() { - target = null; - via = null; - flags = 0; - metric = 0; - } - - /** - * Target network / netmask bits (in port field) or NULL or 0.0.0.0/0 for default - */ - public InetSocketAddress target; - - /** - * Gateway IP address (port ignored) or NULL (family == 0) for LAN-local (no gateway) - */ - public InetSocketAddress via; - - /** - * Route flags - */ - public int flags; - - /** - * Route metric (not currently used) - */ - public int metric; - - - @Override - public int compareTo(VirtualNetworkRoute other) { - return target.toString().compareTo(other.target.toString()); - } - - public boolean equals(VirtualNetworkRoute other) { - boolean targetEquals; - if (target == null && other.target == null) { - targetEquals = true; - } - else if (target == null && other.target != null) { - targetEquals = false; - } - else if (target != null && other.target == null) { - targetEquals = false; - } - else { - targetEquals = target.equals(other.target); - } - - - boolean viaEquals; - if (via == null && other.via == null) { - viaEquals = true; - } - else if (via == null && other.via != null) { - viaEquals = false; - } - else if (via != null && other.via == null) { - viaEquals = false; - } - else { - viaEquals = via.equals(other.via); - } - - return viaEquals && - viaEquals && - flags == other.flags && - metric == other.metric; - } -} diff --git a/attic/java/src/com/zerotier/sdk/VirtualNetworkStatus.java b/attic/java/src/com/zerotier/sdk/VirtualNetworkStatus.java deleted file mode 100644 index 2d00561a1..000000000 --- a/attic/java/src/com/zerotier/sdk/VirtualNetworkStatus.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ -package com.zerotier.sdk; - -public enum VirtualNetworkStatus { - /** - * Waiting for network configuration (also means revision == 0) - */ - NETWORK_STATUS_REQUESTING_CONFIGURATION, - - /** - * Configuration received and we are authorized - */ - NETWORK_STATUS_OK, - - /** - * Netconf master told us 'nope' - */ - NETWORK_STATUS_ACCESS_DENIED, - - /** - * Netconf master exists, but this virtual network does not - */ - NETWORK_STATUS_NOT_FOUND, - - /** - * Initialization of network failed or other internal error - */ - NETWORK_STATUS_PORT_ERROR, - - /** - * ZeroTier One version too old - */ - NETWORK_STATUS_CLIENT_TOO_OLD -} diff --git a/attic/java/src/com/zerotier/sdk/VirtualNetworkType.java b/attic/java/src/com/zerotier/sdk/VirtualNetworkType.java deleted file mode 100644 index ab1f4e087..000000000 --- a/attic/java/src/com/zerotier/sdk/VirtualNetworkType.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * ZeroTier One - Network Virtualization Everywhere - * Copyright (C) 2011-2015 ZeroTier, Inc. - * - * 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 . - * - * -- - * - * ZeroTier may be used and distributed under the terms of the GPLv3, which - * are available at: http://www.gnu.org/licenses/gpl-3.0.html - * - * If you would like to embed ZeroTier into a commercial application or - * redistribute it in a modified binary form, please contact ZeroTier Networks - * LLC. Start here: http://www.zerotier.com/ - */ -package com.zerotier.sdk; - -public enum VirtualNetworkType { - /** - * Private networks are authorized via certificates of membership - */ - NETWORK_TYPE_PRIVATE, - - /** - * Public networks have no access control -- they'll always be AUTHORIZED - */ - NETWORK_TYPE_PUBLIC -} diff --git a/attic/make-bsd.mk b/attic/make-bsd.mk deleted file mode 100644 index 62a6d73e6..000000000 --- a/attic/make-bsd.mk +++ /dev/null @@ -1,174 +0,0 @@ -# This requires GNU make, which is typically "gmake" on BSD systems - -INCLUDES= -DEFS= -LIBS= - -include objects.mk -ONE_OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o - -# Build with address sanitization library for advanced debugging (clang) -ifeq ($(ZT_SANITIZE),1) - SANFLAGS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 -endif -# "make debug" is a shortcut for this -ifeq ($(ZT_DEBUG),1) - CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) - LDFLAGS+= - STRIP=echo - ZT_TRACE=1 - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in heavy testing without it. -node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) -else - CFLAGS?=-O3 -fstack-protector - CFLAGS+=-Wall -fPIE -fvisibility=hidden -fstack-protector -pthread $(INCLUDES) -DNDEBUG $(DEFS) - LDFLAGS+=-pie -Wl,-z,relro,-z,now - STRIP=strip --strip-all -endif - -ifeq ($(ZT_TRACE),1) - DEFS+=-DZT_TRACE -endif - -# Determine system build architecture from compiler target -CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1) -ZT_ARCHITECTURE=999 -ifeq ($(CC_MACH),x86_64) - ZT_ARCHITECTURE=2 - ZT_USE_X64_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),amd64) - ZT_ARCHITECTURE=2 - ZT_USE_X64_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),i386) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),i686) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),arm) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),armel) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),armhf) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),armv6) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),armv6zk) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),armv6kz) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),armv7) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_SALSA2012=1 -endif -ifeq ($(CC_MACH),arm64) - ZT_ARCHITECTURE=4 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),aarch64) - ZT_ARCHITECTURE=4 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),mipsel) - ZT_ARCHITECTURE=5 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),mips) - ZT_ARCHITECTURE=5 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),mips64) - ZT_ARCHITECTURE=6 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),mips64el) - ZT_ARCHITECTURE=6 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif - -# Fail if system architecture could not be determined -ifeq ($(ZT_ARCHITECTURE),999) -ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $CC_MACH) -.PHONY: err -err: ; $(ERR) -endif - -# Build faster crypto on some targets -ifeq ($(ZT_USE_X64_ASM_SALSA2012),1) - override DEFS+=-DZT_USE_X64_ASM_SALSA2012 - override CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o -endif -ifeq ($(ZT_USE_ARM32_NEON_ASM_SALSA2012),1) - override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012 - override CORE_OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o - override ASFLAGS+=-meabi=5 -endif - -override DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" - -CXXFLAGS+=$(CFLAGS) -std=c++11 #-D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1 - -all: one - -one: $(CORE_OBJS) $(ONE_OBJS) one.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS) - $(STRIP) zerotier-one - ln -sf zerotier-one zerotier-idtool - ln -sf zerotier-one zerotier-cli - -zerotier-one: one - -zerotier-idtool: one - -zerotier-cli: one - -libzerotiercore.a: $(CORE_OBJS) - ar rcs libzerotiercore.a $(CORE_OBJS) - ranlib libzerotiercore.a - -core: libzerotiercore.a - -selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(CORE_OBJS) $(ONE_OBJS) $(LIBS) - $(STRIP) zerotier-selftest - -zerotier-selftest: selftest - -clean: - rm -rf *.a *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o build-* zerotier-one zerotier-idtool zerotier-selftest zerotier-cli $(ONE_OBJS) $(CORE_OBJS) - -debug: FORCE - $(MAKE) -j ZT_DEBUG=1 - -install: one - rm -f /usr/local/sbin/zerotier-one - cp zerotier-one /usr/local/sbin - ln -sf /usr/local/sbin/zerotier-one /usr/local/sbin/zerotier-cli - ln -sf /usr/local/sbin/zerotier-one /usr/local/bin/zerotier-idtool - -uninstall: FORCE - rm -rf /usr/local/sbin/zerotier-one /usr/local/sbin/zerotier-cli /usr/local/bin/zerotier-idtool /var/db/zerotier-one/zerotier-one.port /var/db/zerotier-one/zerotier-one.pid /var/db/zerotier-one/iddb.d - -FORCE: diff --git a/attic/make-linux.mk b/attic/make-linux.mk deleted file mode 100644 index 8b63d7998..000000000 --- a/attic/make-linux.mk +++ /dev/null @@ -1,408 +0,0 @@ -# Automagically pick CLANG or RH/CentOS newer GCC if present -# This is only done if we have not overridden these with an environment or CLI variable -ifeq ($(origin CC),default) - CC:=$(shell if [ -e /usr/bin/clang ]; then echo clang; else echo gcc; fi) - CC:=$(shell if [ -e /opt/rh/devtoolset-8/root/usr/bin/gcc ]; then echo /opt/rh/devtoolset-8/root/usr/bin/gcc; else echo $(CC); fi) -endif -ifeq ($(origin CXX),default) - CXX:=$(shell if [ -e /usr/bin/clang++ ]; then echo clang++; else echo g++; fi) - CXX:=$(shell if [ -e /opt/rh/devtoolset-8/root/usr/bin/g++ ]; then echo /opt/rh/devtoolset-8/root/usr/bin/g++; else echo $(CXX); fi) -endif - -INCLUDES?= -DEFS?= -LDLIBS?= -DESTDIR?= - -include objects.mk -ONE_OBJS+=osdep/LinuxEthernetTap.o -ONE_OBJS+=osdep/LinuxNetLink.o - -# for central controller builds -TIMESTAMP=$(shell date +"%Y%m%d%H%M") - -# Auto-detect miniupnpc and nat-pmp as well and use system libs if present, -# otherwise build into binary as done on Mac and Windows. -ONE_OBJS+=osdep/PortMapper.o -override DEFS+=-DZT_USE_MINIUPNPC -MINIUPNPC_IS_NEW_ENOUGH=$(shell grep -sqr '.*define.*MINIUPNPC_VERSION.*"2..*"' /usr/include/miniupnpc/miniupnpc.h && echo 1) -#MINIUPNPC_IS_NEW_ENOUGH=$(shell grep -sqr '.*define.*MINIUPNPC_VERSION.*"2.."' /usr/include/miniupnpc/miniupnpc.h && echo 1) -ifeq ($(MINIUPNPC_IS_NEW_ENOUGH),1) - override DEFS+=-DZT_USE_SYSTEM_MINIUPNPC - LDLIBS+=-lminiupnpc -else - override DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING=\"Linux\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR - ONE_OBJS+=ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o -endif -ifeq ($(wildcard /usr/include/natpmp.h),) - ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o -else - LDLIBS+=-lnatpmp - override DEFS+=-DZT_USE_SYSTEM_NATPMP -endif - -# Use bundled http-parser since distribution versions are NOT API-stable or compatible! -# Trying to use dynamically linked libhttp-parser causes tons of compatibility problems. -ONE_OBJS+=ext/http-parser/http_parser.o - -# Build with address sanitization library for advanced debugging (clang) -ifeq ($(ZT_SANITIZE),1) - DEFS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 -endif -ifeq ($(ZT_DEBUG_TRACE),1) - DEFS+=-DZT_DEBUG_TRACE -endif -ifeq ($(ZT_TRACE),1) - DEFS+=-DZT_TRACE -endif - -ifeq ($(ZT_RULES_ENGINE_DEBUGGING),1) - override DEFS+=-DZT_RULES_ENGINE_DEBUGGING -endif - -# Build with address sanitization library for advanced debugging (clang) -ifeq ($(ZT_SANITIZE),1) - SANFLAGS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 -endif -ifeq ($(ZT_DEBUG),1) - override CFLAGS+=-Wall -Wno-deprecated -g -pthread $(INCLUDES) $(DEFS) - override CXXFLAGS+=-Wall -Wno-deprecated -g -std=c++11 -pthread $(INCLUDES) $(DEFS) - ZT_TRACE=1 - STRIP?=echo - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box! -node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CXXFLAGS=-Wall -O2 -g -pthread $(INCLUDES) $(DEFS) -else - CFLAGS?=-O3 -fstack-protector -fPIE - override CFLAGS+=-Wall -Wno-deprecated -pthread $(INCLUDES) -DNDEBUG $(DEFS) - CXXFLAGS?=-O3 -fstack-protector -fPIE - override CXXFLAGS+=-Wall -Wno-deprecated -std=c++11 -pthread $(INCLUDES) -DNDEBUG $(DEFS) - LDFLAGS=-pie -Wl,-z,relro,-z,now - STRIP?=strip - STRIP+=--strip-all -endif - -ifeq ($(ZT_QNAP), 1) - override DEFS+=-D__QNAP__ -endif - -ifeq ($(ZT_SYNOLOGY), 1) - override CFLAGS+=-fPIC - override CXXFLAGS+=-fPIC - override DEFS+=-D__SYNOLOGY__ -endif - -ifeq ($(ZT_DISABLE_COMPRESSION), 1) - override DEFS+=-DZT_DISABLE_COMPRESSION -endif - -ifeq ($(ZT_TRACE),1) - override DEFS+=-DZT_TRACE -endif - -ifeq ($(ZT_USE_TEST_TAP),1) - override DEFS+=-DZT_USE_TEST_TAP -endif - -ifeq ($(ZT_VAULT_SUPPORT),1) - override DEFS+=-DZT_VAULT_SUPPORT=1 - override LDLIBS+=-lcurl -endif - -# Uncomment for gprof profile build -#CFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS) -#CXXFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS) -#LDFLAGS= -#STRIP=echo - -# Determine system build architecture from compiler target -CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1) -ZT_ARCHITECTURE=999 -ifeq ($(CC_MACH),x86_64) - ZT_ARCHITECTURE=2 - ZT_USE_X64_ASM_SALSA=1 - ZT_USE_X64_ASM_ED25519=1 -endif -ifeq ($(CC_MACH),amd64) - ZT_ARCHITECTURE=2 - ZT_USE_X64_ASM_SALSA=1 - ZT_USE_X64_ASM_ED25519=1 -endif -ifeq ($(CC_MACH),powerpc64le) - ZT_ARCHITECTURE=8 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),powerpc) - ZT_ARCHITECTURE=8 - override DEFS+=-DZT_NO_TYPE_PUNNING - override DEFS+=-DZT_NO_CAPABILITIES -endif -ifeq ($(CC_MACH),ppc64le) - ZT_ARCHITECTURE=8 -endif -ifeq ($(CC_MACH),ppc64el) - ZT_ARCHITECTURE=8 -endif -ifeq ($(CC_MACH),i386) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),i486) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),i586) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),i686) - ZT_ARCHITECTURE=1 -endif -ifeq ($(CC_MACH),arm) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armel) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armhf) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armv6) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armv6l) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armv6zk) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armv6kz) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armv7) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armv7l) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),armv7hl) - ZT_ARCHITECTURE=3 - override DEFS+=-DZT_NO_TYPE_PUNNING - ZT_USE_ARM32_NEON_ASM_CRYPTO=1 -endif -ifeq ($(CC_MACH),arm64) - ZT_ARCHITECTURE=4 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),aarch64) - ZT_ARCHITECTURE=4 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),mipsel) - ZT_ARCHITECTURE=5 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),mips) - ZT_ARCHITECTURE=5 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),mips64) - ZT_ARCHITECTURE=6 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),mips64el) - ZT_ARCHITECTURE=6 - override DEFS+=-DZT_NO_TYPE_PUNNING -endif -ifeq ($(CC_MACH),s390x) - ZT_ARCHITECTURE=16 -endif - -# Fail if system architecture could not be determined -ifeq ($(ZT_ARCHITECTURE),999) -ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $CC_MACH) -.PHONY: err -err: ; $(ERR) -endif - -# Disable software updates by default on Linux since that is normally done with package management -override DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" - -# This forces libstdc++ not to include these abominations, especially mt and pool -override DEFS+=-D_MT_ALLOCATOR_H -D_POOL_ALLOCATOR_H -D_EXTPTR_ALLOCATOR_H -D_DEBUG_ALLOCATOR_H - -# Static builds, which are currently done for a number of Linux targets -ifeq ($(ZT_STATIC),1) - override LDFLAGS+=-static -endif - -# For building an official semi-static binary on CentOS 7 -ifeq ($(ZT_OFFICIAL),1) - CORE_OBJS+=ext/misc/linux-old-glibc-compat.o - override LDFLAGS+=-Wl,--wrap=memcpy -static-libstdc++ -endif - -# ARM32 hell -- use conservative CFLAGS -ifeq ($(ZT_ARCHITECTURE),3) - ifeq ($(shell if [ -e /usr/bin/dpkg ]; then dpkg --print-architecture; fi),armel) - override CFLAGS+=-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm - override CXXFLAGS+=-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm - ZT_USE_ARM32_NEON_ASM_CRYPTO=0 - else - override CFLAGS+=-march=armv5t -mno-unaligned-access -marm -fexceptions - override CXXFLAGS+=-march=armv5t -mno-unaligned-access -marm -fexceptions - ZT_USE_ARM32_NEON_ASM_CRYPTO=0 - endif -endif - -# Build faster crypto on some targets -ifeq ($(ZT_USE_X64_ASM_SALSA),1) - override DEFS+=-DZT_USE_X64_ASM_SALSA2012 - override CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o -endif -ifeq ($(ZT_USE_X64_ASM_ED25519),1) - override DEFS+=-DZT_USE_FAST_X64_ED25519 - override CORE_OBJS+=ext/ed25519-amd64-asm/choose_t.o ext/ed25519-amd64-asm/consts.o ext/ed25519-amd64-asm/fe25519_add.o ext/ed25519-amd64-asm/fe25519_freeze.o ext/ed25519-amd64-asm/fe25519_mul.o ext/ed25519-amd64-asm/fe25519_square.o ext/ed25519-amd64-asm/fe25519_sub.o ext/ed25519-amd64-asm/ge25519_add_p1p1.o ext/ed25519-amd64-asm/ge25519_dbl_p1p1.o ext/ed25519-amd64-asm/ge25519_nielsadd2.o ext/ed25519-amd64-asm/ge25519_nielsadd_p1p1.o ext/ed25519-amd64-asm/ge25519_p1p1_to_p2.o ext/ed25519-amd64-asm/ge25519_p1p1_to_p3.o ext/ed25519-amd64-asm/ge25519_pnielsadd_p1p1.o ext/ed25519-amd64-asm/heap_rootreplaced.o ext/ed25519-amd64-asm/heap_rootreplaced_1limb.o ext/ed25519-amd64-asm/heap_rootreplaced_2limbs.o ext/ed25519-amd64-asm/heap_rootreplaced_3limbs.o ext/ed25519-amd64-asm/sc25519_add.o ext/ed25519-amd64-asm/sc25519_barrett.o ext/ed25519-amd64-asm/sc25519_lt.o ext/ed25519-amd64-asm/sc25519_sub_nored.o ext/ed25519-amd64-asm/ull4_mul.o ext/ed25519-amd64-asm/fe25519_getparity.o ext/ed25519-amd64-asm/fe25519_invert.o ext/ed25519-amd64-asm/fe25519_iseq.o ext/ed25519-amd64-asm/fe25519_iszero.o ext/ed25519-amd64-asm/fe25519_neg.o ext/ed25519-amd64-asm/fe25519_pack.o ext/ed25519-amd64-asm/fe25519_pow2523.o ext/ed25519-amd64-asm/fe25519_setint.o ext/ed25519-amd64-asm/fe25519_unpack.o ext/ed25519-amd64-asm/ge25519_add.o ext/ed25519-amd64-asm/ge25519_base.o ext/ed25519-amd64-asm/ge25519_double.o ext/ed25519-amd64-asm/ge25519_double_scalarmult.o ext/ed25519-amd64-asm/ge25519_isneutral.o ext/ed25519-amd64-asm/ge25519_multi_scalarmult.o ext/ed25519-amd64-asm/ge25519_pack.o ext/ed25519-amd64-asm/ge25519_scalarmult_base.o ext/ed25519-amd64-asm/ge25519_unpackneg.o ext/ed25519-amd64-asm/hram.o ext/ed25519-amd64-asm/index_heap.o ext/ed25519-amd64-asm/sc25519_from32bytes.o ext/ed25519-amd64-asm/sc25519_from64bytes.o ext/ed25519-amd64-asm/sc25519_from_shortsc.o ext/ed25519-amd64-asm/sc25519_iszero.o ext/ed25519-amd64-asm/sc25519_mul.o ext/ed25519-amd64-asm/sc25519_mul_shortsc.o ext/ed25519-amd64-asm/sc25519_slide.o ext/ed25519-amd64-asm/sc25519_to32bytes.o ext/ed25519-amd64-asm/sc25519_window4.o ext/ed25519-amd64-asm/sign.o -endif -ifeq ($(ZT_USE_ARM32_NEON_ASM_CRYPTO),1) - override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012 - override CORE_OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o -endif - -.PHONY: all -all: one - -.PHONY: one -one: zerotier-one zerotier-idtool zerotier-cli - -zerotier-one: $(CORE_OBJS) $(ONE_OBJS) one.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LDLIBS) - $(STRIP) zerotier-one - -zerotier-idtool: zerotier-one - ln -sf zerotier-one zerotier-idtool - -zerotier-cli: zerotier-one - ln -sf zerotier-one zerotier-cli - -libzerotiercore.a: FORCE - make CFLAGS="-O3 -fstack-protector -fPIC" CXXFLAGS="-O3 -std=c++11 -fstack-protector -fPIC" $(CORE_OBJS) - ar rcs libzerotiercore.a $(CORE_OBJS) - ranlib libzerotiercore.a - -core: libzerotiercore.a - -selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(CORE_OBJS) $(ONE_OBJS) $(LDLIBS) - $(STRIP) zerotier-selftest - -zerotier-selftest: selftest - -manpages: FORCE - cd doc ; ./build.sh - -doc: manpages - -clean: FORCE - rm -rf *.a *.so *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/miniupnpc/*.o ext/libnatpmp/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm .depend debian/files debian/zerotier-one*.debhelper debian/zerotier-one.substvars debian/*.log debian/zerotier-one doc/node_modules ext/misc/*.o debian/.debhelper debian/debhelper-build-stamp docker/zerotier-one - -distclean: clean - -realclean: distclean - -official: FORCE - make -j4 ZT_OFFICIAL=1 all - -docker: FORCE - docker build -f ext/installfiles/linux/zerotier-containerized/Dockerfile -t zerotier-containerized . - -central-controller: FORCE - make -j4 LDLIBS="-L/usr/pgsql-10/lib/ -lpq -Lext/librabbitmq/centos_x64/lib/ -lrabbitmq" CXXFLAGS="-I/usr/pgsql-10/include -I./ext/librabbitmq/centos_x64/include -fPIC" DEFS="-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER" ZT_OFFICIAL=1 ZT_USE_X64_ASM_ED25519=1 one - -central-controller-docker: FORCE - docker build -t docker.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=`git name-rev --name-only HEAD` . - -debug: FORCE - make ZT_DEBUG=1 one - make ZT_DEBUG=1 selftest - -# Note: keep the symlinks in /var/lib/zerotier-one to the binaries since these -# provide backward compatibility with old releases where the binaries actually -# lived here. Folks got scripts. - -install: FORCE - mkdir -p $(DESTDIR)/usr/sbin - rm -f $(DESTDIR)/usr/sbin/zerotier-one - cp -f zerotier-one $(DESTDIR)/usr/sbin/zerotier-one - rm -f $(DESTDIR)/usr/sbin/zerotier-cli - rm -f $(DESTDIR)/usr/sbin/zerotier-idtool - ln -s zerotier-one $(DESTDIR)/usr/sbin/zerotier-cli - ln -s zerotier-one $(DESTDIR)/usr/sbin/zerotier-idtool - mkdir -p $(DESTDIR)/var/lib/zerotier-one - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-one - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-cli - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-idtool - ln -s ../../../usr/sbin/zerotier-one $(DESTDIR)/var/lib/zerotier-one/zerotier-one - ln -s ../../../usr/sbin/zerotier-one $(DESTDIR)/var/lib/zerotier-one/zerotier-cli - ln -s ../../../usr/sbin/zerotier-one $(DESTDIR)/var/lib/zerotier-one/zerotier-idtool - mkdir -p $(DESTDIR)/usr/share/man/man8 - rm -f $(DESTDIR)/usr/share/man/man8/zerotier-one.8.gz - cat doc/zerotier-one.8 | gzip -9 >$(DESTDIR)/usr/share/man/man8/zerotier-one.8.gz - mkdir -p $(DESTDIR)/usr/share/man/man1 - rm -f $(DESTDIR)/usr/share/man/man1/zerotier-idtool.1.gz - rm -f $(DESTDIR)/usr/share/man/man1/zerotier-cli.1.gz - cat doc/zerotier-cli.1 | gzip -9 >$(DESTDIR)/usr/share/man/man1/zerotier-cli.1.gz - cat doc/zerotier-idtool.1 | gzip -9 >$(DESTDIR)/usr/share/man/man1/zerotier-idtool.1.gz - -# Uninstall preserves identity.public and identity.secret since the user might -# want to save these. These are your ZeroTier address. - -uninstall: FORCE - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-one - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-cli - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-idtool - rm -f $(DESTDIR)/usr/sbin/zerotier-cli - rm -f $(DESTDIR)/usr/sbin/zerotier-idtool - rm -f $(DESTDIR)/usr/sbin/zerotier-one - rm -rf $(DESTDIR)/var/lib/zerotier-one/iddb.d - rm -rf $(DESTDIR)/var/lib/zerotier-one/updates.d - rm -rf $(DESTDIR)/var/lib/zerotier-one/networks.d - rm -f $(DESTDIR)/var/lib/zerotier-one/zerotier-one.port - rm -f $(DESTDIR)/usr/share/man/man8/zerotier-one.8.gz - rm -f $(DESTDIR)/usr/share/man/man1/zerotier-idtool.1.gz - rm -f $(DESTDIR)/usr/share/man/man1/zerotier-cli.1.gz - -# These are just for convenience for building Linux packages - -debian: FORCE - debuild --no-lintian -I -i -us -uc -nc -b - -debian-clean: FORCE - rm -rf debian/files debian/zerotier-one*.debhelper debian/zerotier-one.substvars debian/*.log debian/zerotier-one debian/.debhelper debian/debhelper-build-stamp - -redhat: FORCE - rpmbuild --target `rpm -q bash --qf "%{arch}"` -ba zerotier-one.spec - -# This installs the packages needed to build ZT locally on CentOS 7 and -# is here largely for documentation purposes. -centos-7-setup: FORCE - yum install -y gcc gcc-c++ make epel-release git - yum install -y centos-release-scl - yum install -y devtoolset-8-gcc devtoolset-8-gcc-c++ - -FORCE: diff --git a/attic/make-mac.mk b/attic/make-mac.mk deleted file mode 100644 index 2cdb9e087..000000000 --- a/attic/make-mac.mk +++ /dev/null @@ -1,162 +0,0 @@ -CC=clang -CXX=clang++ -INCLUDES= -DEFS= -LIBS= -ARCH_FLAGS= -CODESIGN=echo -PRODUCTSIGN=echo -CODESIGN_APP_CERT= -CODESIGN_INSTALLER_CERT= -NOTARIZE=echo -NOTARIZE_USER_ID=null - -ZT_BUILD_PLATFORM=3 -ZT_BUILD_ARCHITECTURE=2 -ZT_VERSION_MAJOR=$(shell cat version.h | grep -F VERSION_MAJOR | cut -d ' ' -f 3) -ZT_VERSION_MINOR=$(shell cat version.h | grep -F VERSION_MINOR | cut -d ' ' -f 3) -ZT_VERSION_REV=$(shell cat version.h | grep -F VERSION_REVISION | cut -d ' ' -f 3) -ZT_VERSION_BUILD=$(shell cat version.h | grep -F VERSION_BUILD | cut -d ' ' -f 3) - -# for central controller builds -TIMESTAMP=$(shell date +"%Y%m%d%H%M") - -DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE) - -include objects.mk -ONE_OBJS+=osdep/MacEthernetTap.o osdep/MacKextEthernetTap.o ext/http-parser/http_parser.o - -ifeq ($(ZT_CONTROLLER),1) - LIBS+=-L/usr/local/opt/libpq/lib -lpq -Lext/librabbitmq/macos/lib -lrabbitmq - DEFS+=-DZT_CONTROLLER_USE_LIBPQ -DZT_CONTROLLER - INCLUDES+=-Iext/librabbitmq/macos/include -I/usr/local/opt/libpq/include -endif - -# Official releases are signed with our Apple cert and apply software updates by default -ifeq ($(ZT_OFFICIAL_RELEASE),1) - DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"apply\"" - ZT_USE_MINIUPNPC=1 - CODESIGN=codesign - PRODUCTSIGN=productsign - CODESIGN_APP_CERT="Developer ID Application: ZeroTier, Inc (8ZD9JUCZ4V)" - CODESIGN_INSTALLER_CERT="Developer ID Installer: ZeroTier, Inc (8ZD9JUCZ4V)" - NOTARIZE=xcrun altool - NOTARIZE_USER_ID="adam.ierymenko@gmail.com" -else - DEFS+=-DZT_SOFTWARE_UPDATE_DEFAULT="\"download\"" -endif - -# Use fast ASM Salsa20/12 for x64 processors -DEFS+=-DZT_USE_X64_ASM_SALSA2012 -CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o - -# Build miniupnpc and nat-pmp as included libraries -- extra defs are required for these sources -DEFS+=-DMACOSX -DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -D_DARWIN_C_SOURCE -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"Darwin/15.0.0\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR -ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o - -# Build with address sanitization library for advanced debugging (clang) -ifeq ($(ZT_SANITIZE),1) - DEFS+=-fsanitize=address -DASAN_OPTIONS=symbolize=1 -endif -ifeq ($(ZT_DEBUG_TRACE),1) - DEFS+=-DZT_DEBUG_TRACE -endif -# Debug mode -- dump trace output, build binary with -g -ifeq ($(ZT_DEBUG),1) - ZT_TRACE=1 - CFLAGS+=-Wall -g -maes -mpclmul $(INCLUDES) $(DEFS) - STRIP=echo - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in heavy testing without it. -node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o node/AES.o: CFLAGS = -Wall -O2 -g -maes -mpclmul $(INCLUDES) $(DEFS) -else - CFLAGS?=-Ofast -fstack-protector-strong - CFLAGS+=$(ARCH_FLAGS) -Wall -flto -fPIE -maes -msse -msse2 -msse3 -mpclmul -mmacosx-version-min=10.9 -DNDEBUG -Wno-unused-private-field $(INCLUDES) $(DEFS) - STRIP=strip -endif - -ifeq ($(ZT_TRACE),1) - DEFS+=-DZT_TRACE -endif - -ifeq ($(ZT_VAULT_SUPPORT),1) - DEFS+=-DZT_VAULT_SUPPORT=1 - LIBS+=-lcurl -endif - -CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++ - -all: one macui - -ext/x64-salsa2012-asm/salsa2012.o: - $(CC) $(CFLAGS) -c ext/x64-salsa2012-asm/salsa2012.s -o ext/x64-salsa2012-asm/salsa2012.o - -mac-agent: FORCE - $(CC) -Ofast -o MacEthernetTapAgent osdep/MacEthernetTapAgent.c - $(CODESIGN) -f -s $(CODESIGN_APP_CERT) MacEthernetTapAgent - -one: $(CORE_OBJS) $(ONE_OBJS) one.o mac-agent - $(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS) - $(STRIP) zerotier-one - ln -sf zerotier-one zerotier-idtool - ln -sf zerotier-one zerotier-cli - $(CODESIGN) -f -s $(CODESIGN_APP_CERT) zerotier-one - -zerotier-one: one - -central-controller: - make ZT_CONTROLLER=1 one - -zerotier-idtool: one - -zerotier-cli: one - -libzerotiercore.a: $(CORE_OBJS) - ar rcs libzerotiercore.a $(CORE_OBJS) - ranlib libzerotiercore.a - -core: libzerotiercore.a - -macui: FORCE - cd macui && xcodebuild -target "ZeroTier One" -configuration Release - $(CODESIGN) -f -s $(CODESIGN_APP_CERT) "macui/build/Release/ZeroTier One.app" - -#cli: FORCE -# $(CXX) $(CXXFLAGS) -o zerotier cli/zerotier.cpp osdep/OSUtils.cpp node/InetAddress.cpp node/Utils.cpp node/Salsa20.cpp node/Identity.cpp node/SHA512.cpp node/C25519.cpp -lcurl -# $(STRIP) zerotier - -selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o - $(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(CORE_OBJS) $(ONE_OBJS) $(LIBS) - $(STRIP) zerotier-selftest - -zerotier-selftest: selftest - -# Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html -mac-dist-pkg: FORCE - packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" - rm -f "ZeroTier One Signed.pkg" - $(PRODUCTSIGN) --sign $(CODESIGN_INSTALLER_CERT) "ZeroTier One.pkg" "ZeroTier One Signed.pkg" - if [ -f "ZeroTier One Signed.pkg" ]; then mv -f "ZeroTier One Signed.pkg" "ZeroTier One.pkg"; fi - rm -f zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_* - cat ext/installfiles/mac-update/updater.tmpl.sh "ZeroTier One.pkg" >zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_$(ZT_VERSION_MAJOR).$(ZT_VERSION_MINOR).$(ZT_VERSION_REV)_$(ZT_VERSION_BUILD).exe - $(NOTARIZE) -t osx -f "ZeroTier One.pkg" --primary-bundle-id --output-format xml --notarize-app -u $(NOTARIZE_USER_ID) - echo '*** When Apple notifies that the app is notarized, run: xcrun stapler staple "ZeroTier One.pkg"' - -# For ZeroTier, Inc. to build official signed packages -official: FORCE - make clean - make ZT_OFFICIAL_RELEASE=1 -j 8 one - make ZT_OFFICIAL_RELEASE=1 macui - make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg - -central-controller-docker: FORCE - docker build -t docker.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=$(shell git name-rev --name-only HEAD) . - -clean: - rm -rf MacEthernetTapAgent *.dSYM build-* *.a *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli zerotier doc/node_modules macui/build zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_* - -distclean: clean - -realclean: clean - -FORCE: diff --git a/attic/make-netbsd.mk b/attic/make-netbsd.mk deleted file mode 100644 index f2490038b..000000000 --- a/attic/make-netbsd.mk +++ /dev/null @@ -1,65 +0,0 @@ -CC=gcc -CXX=g++ - -INCLUDES= -DEFS= -LIBS= - -include objects.mk -OBJS+=osdep/NetBSDEthernetTap.o ext/lz4/lz4.o ext/json-parser/json.o ext/http-parser/http_parser.o - -# "make official" is a shortcut for this -ifeq ($(ZT_OFFICIAL_RELEASE),1) - DEFS+=-DZT_OFFICIAL_RELEASE -endif - -# Build with ZT_ENABLE_CLUSTER=1 to build with cluster support -ifeq ($(ZT_ENABLE_CLUSTER),1) - DEFS+=-DZT_ENABLE_CLUSTER -endif - -# "make debug" is a shortcut for this -ifeq ($(ZT_DEBUG),1) - DEFS+=-DZT_TRACE - CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) - LDFLAGS+= - STRIP=echo - # The following line enables optimization for the crypto code, since - # C25519 in particular is almost UNUSABLE in heavy testing without it. -ext/lz4/lz4.o node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) -else - CFLAGS?=-O3 -fstack-protector - CFLAGS+=-fPIE -fvisibility=hidden -fstack-protector -pthread $(INCLUDES) -DNDEBUG $(DEFS) - LDFLAGS+=-pie -Wl,-z,relro,-z,now - STRIP=strip --strip-all -endif - -CXXFLAGS+=$(CFLAGS) -fno-rtti -fpermissive - -all: one - -one: $(OBJS) service/OneService.o one.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS) - $(STRIP) zerotier-one - ln -sf zerotier-one zerotier-idtool - ln -sf zerotier-one zerotier-cli - -selftest: $(OBJS) selftest.o - $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS) - $(STRIP) zerotier-selftest - -# No installer on FreeBSD yet -#installer: one FORCE -# ./buildinstaller.sh - -clean: - rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/lz4/*.o ext/json-parser/*.o build-* zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-* - -debug: FORCE - make -j 4 ZT_DEBUG=1 - -#official: FORCE -# make -j 4 ZT_OFFICIAL_RELEASE=1 -# ./buildinstaller.sh - -FORCE: diff --git a/attic/root/CMakeLists.txt b/attic/root/CMakeLists.txt deleted file mode 100644 index 3cea07e25..000000000 --- a/attic/root/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -cmake_minimum_required(VERSION 2.8) -project(zerotier-root) - -if(WIN32) - add_definitions(-DNOMINMAX) -endif(WIN32) - -add_executable(${PROJECT_NAME} root.cpp) - -target_link_libraries(${PROJECT_NAME} zt_core zt_osdep pthread resolv) - -target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) - -target_include_directories(${PROJECT_NAME} PRIVATE - ${CMAKE_SOURCE_DIR}/node - ${CMAKE_SOURCE_DIR}/osdep -) diff --git a/attic/root/geoip-html.h b/attic/root/geoip-html.h deleted file mode 100644 index 00e6f3c2f..000000000 --- a/attic/root/geoip-html.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -#ifndef ZT_ROOT_GEOIP_HTML_H -#define ZT_ROOT_GEOIP_HTML_H - -#define ZT_GEOIP_HTML_HEAD \ -"\n" \ -"\n" \ -" \n" \ -" \n" \ -" \n" \ -" \n" \ -" GeoIP Map\n" \ -" \n" \ -" \n" \ -" \n" \ -"
\n" \ -" \n" \ -" \n" \ -" \n" \ -" \n" \ -"" - -#endif diff --git a/attic/root/root.cpp b/attic/root/root.cpp deleted file mode 100644 index 6e3301642..000000000 --- a/attic/root/root.cpp +++ /dev/null @@ -1,1337 +0,0 @@ -/* - * Copyright (c)2013-2021 ZeroTier, Inc. - * - * Use of this software is governed by the Business Source License included - * in the LICENSE.TXT file in the project's root directory. - * - * Change Date: 2026-01-01 - * - * On the date above, in accordance with the Business Source License, use - * of this software will be governed by version 2.0 of the Apache License. - */ -/****/ - -// TODO: roots will need to PUSH_DIRECT_PATHS to make sure peers know both their IPv4 and IPv6 addresses. - -/* - * This is a high-throughput minimal root server. It implements only - * those functions of a ZT node that a root must perform and does so - * using highly efficient multithreaded I/O code. It's only been - * thoroughly tested on Linux but should also run on BSDs. - * - * Root configuration file format (JSON): - * - * { - * "name": Name of this root for documentation/UI purposes (string) - * "port": UDP port (int) - * "httpPort": Local HTTP port for basic stats (int) - * "relayMaxHops": Max hops (up to 7) - * "planetFile": Location of planet file for pre-2.x peers (string) - * "statsRoot": If present, path to periodically save stats files (string) - * "s_siblings": [ - * { - * "name": Sibling name for UI/documentation purposes (string) - * "id": Full public identity of subling (string) - * "ip": IP address of sibling (string) - * "port": port of subling (for ZeroTier UDP) (int) - * }, ... - * ] - * } - * - * The only required field is port. If statsRoot is present then files - * are periodically written there containing the root's current state. - * It should be a memory filesystem like /dev/shm on Linux as these - * files are large and rewritten frequently and do not need to be - * persisted. - * - * s_siblings are other root servers that should receive packets to peers - * that we can't find. This can occur due to e.g. network topology - * hiccups, IP blockages, etc. s_siblings are used in the order in which - * they appear with the first alive sibling being used. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "geoip-html.h" - -using namespace ZeroTier; -using json = nlohmann::json; - -#ifdef MSG_DONTWAIT -#define SENDTO_FLAGS MSG_DONTWAIT -#define RECVFROM_FLAGS 0 -#else -#define SENDTO_FLAGS 0 -#define RECVFROM_FLAGS 0 -#endif - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -/** - * RootPeer is a normal peer known to this root - * - * This struct must remain memcpy-able. Identity, InetAddress, and - * Atomic all satisfy this. Take care when adding fields that - * this remains true. - */ -struct RootPeer -{ - ZT_INLINE RootPeer() : lastSend(0),lastReceive(0),lastEcho(0),lastHello(0),vProto(-1),vMajor(-1),vMinor(-1),vRev(-1) {} - ZT_INLINE ~RootPeer() { Utils::burn(key,sizeof(key)); } - - Identity id; // Identity - uint8_t key[32]; // Shared secret key - InetAddress ip4,ip6; // IPv4 and IPv6 addresses - int64_t lastSend; // Time of last send (any packet) - int64_t lastReceive; // Time of last receive (any packet) - int64_t lastEcho; // Time of last received ECHO - int64_t lastHello; // Time of last received HELLO - int vProto; // Protocol version or -1 if unknown - int vMajor,vMinor,vRev; // Peer version or -1,-1,-1 if unknown - - std::atomic __refCount; -}; - -// Hashers for std::unordered_map -struct IdentityHasher { ZT_INLINE std::size_t operator()(const Identity &id) const { return (std::size_t)id.hashCode(); } }; -struct AddressHasher { ZT_INLINE std::size_t operator()(const Address &a) const { return (std::size_t)a.toInt(); } }; -struct InetAddressHasher { ZT_INLINE std::size_t operator()(const InetAddress &ip) const { return (std::size_t)ip.hashCode(); } }; -struct MulticastGroupHasher { ZT_INLINE std::size_t operator()(const MulticastGroup &mg) const { return (std::size_t)mg.hashCode(); } }; - -// An ordered tuple key representing an introduction of one peer to another -struct RendezvousKey -{ - RendezvousKey(const Address &aa,const Address &bb) - { - if (aa > bb) { - a = aa; - b = bb; - } else { - a = bb; - b = aa; - } - } - Address a,b; - ZT_INLINE bool operator==(const RendezvousKey &k) const { return ((a == k.a) && (b == k.b)); } - ZT_INLINE bool operator!=(const RendezvousKey &k) const { return ((a != k.a) || (b != k.b)); } - struct Hasher { ZT_INLINE std::size_t operator()(const RendezvousKey &k) const { return (std::size_t)(k.a.toInt() ^ k.b.toInt()); } }; -}; - -struct RendezvousStats -{ - RendezvousStats() : count(0),ts(0) {} - int64_t count; - int64_t ts; -}; - -// These fields are not locked as they're only initialized on startup or are atomic -static int64_t s_startTime; // Time service was started -static std::vector s_ports; // Ports to bind for UDP traffic -static int s_relayMaxHops = 0; // Max relay hops -static Identity s_self; // My identity (including secret) -static std::atomic_bool s_run; // Remains true until shutdown is ordered -static json s_config; // JSON config file contents -static std::string s_statsRoot; // Root to write stats, peers, etc. -static std::atomic_bool s_geoInit; // True if geoIP data is initialized -static std::string s_googleMapsAPIKey; // Google maps API key for GeoIP /map feature - -// These are only modified during GeoIP database load (if enabled) and become static after s_geoInit is set to true. -static std::map< std::pair< uint32_t,uint32_t >,std::pair< float,float > > s_geoIp4; -static std::map< std::pair< std::array< uint64_t,2 >,std::array< uint64_t,2 > >,std::pair< float,float > > s_geoIp6; - -// Rate meters for statistical purposes (locks are internal to Meter) -static Meter<> s_inputRate; -static Meter<> s_outputRate; -static Meter<> s_forwardRate; -static Meter<> s_discardedForwardRate; - -// These fields are locked using mutexes below as they're modified during runtime -static std::string s_planet; -static std::list< SharedPtr > s_peers; -static std::unordered_map< uint64_t,std::unordered_map< MulticastGroup,std::unordered_map< Address,int64_t,AddressHasher >,MulticastGroupHasher > > s_multicastSubscriptions; -static std::unordered_map< Identity,SharedPtr,IdentityHasher > s_peersByIdentity; -static std::unordered_map< Address,std::set< SharedPtr >,AddressHasher > s_peersByVirtAddr; -static std::unordered_map< RendezvousKey,RendezvousStats,RendezvousKey::Hasher > s_rendezvousTracking; - -static std::mutex s_planet_l; -static std::mutex s_peers_l; -static std::mutex s_multicastSubscriptions_l; -static std::mutex s_peersByIdentity_l; -static std::mutex s_peersByVirtAddr_l; -static std::mutex s_rendezvousTracking_l; - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -// Construct GeoIP key for IPv4 IPs -static ZT_INLINE uint32_t ip4ToH32(const InetAddress &ip) -{ - return Utils::ntoh((uint32_t)(((const struct sockaddr_in *)&ip)->sin_addr.s_addr)); -} - -// Construct GeoIP key for IPv6 IPs -static ZT_INLINE std::array< uint64_t,2 > ip6ToH128(const InetAddress &ip) -{ - std::array i128; - memcpy(i128.data(),ip.rawIpData(),16); - i128[0] = Utils::ntoh(i128[0]); - i128[1] = Utils::ntoh(i128[1]); - return i128; -} - -static void handlePacket(const int v4s,const int v6s,const InetAddress *const ip,Packet &pkt) -{ - char ipstr[128]; - const bool fragment = pkt[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR; - const Address source(pkt.source()); - const Address dest(pkt.destination()); - const int64_t now = OSUtils::now(); - - s_inputRate.log(now,pkt.size()); - - if ((!fragment)&&(pkt.size() < ZT_PROTO_MIN_PACKET_LENGTH)) - return; - - if ((!fragment)&&(!pkt.fragmented())&&(dest == s_self.address())) { - SharedPtr peer; - - // If this is an un-encrypted HELLO, either learn a new peer or verify - // that this is a peer we already know. - if ((pkt.cipher() == ZT_PROTO_CIPHER_SUITE__POLY1305_NONE)&&(pkt.verb() == Packet::VERB_HELLO)) { - Identity id; - if (id.deserialize(pkt,ZT_PROTO_VERB_HELLO_IDX_IDENTITY)) { - { - std::lock_guard pbi_l(s_peersByIdentity_l); - auto pById = s_peersByIdentity.find(id); - if (pById != s_peersByIdentity.end()) - peer = pById->second; - } - if (peer) { - if (!pkt.dearmor(peer->key)) { - printf("%s HELLO rejected: packet authentication failed" ZT_EOL_S,ip->toString(ipstr)); - return; - } - } else { - peer.set(new RootPeer); - - if (!s_self.agree(id,peer->key)) { - printf("%s HELLO rejected: key agreement failed" ZT_EOL_S,ip->toString(ipstr)); - return; - } - if (!pkt.dearmor(peer->key)) { - printf("%s HELLO rejected: packet authentication failed" ZT_EOL_S,ip->toString(ipstr)); - return; - } - if (!pkt.uncompress()) { - printf("%s HELLO rejected: decompression failed" ZT_EOL_S,ip->toString(ipstr)); - return; - } - - peer->id = id; - peer->lastReceive = now; - - bool added = false; - { - std::lock_guard pbi_l(s_peersByIdentity_l); - auto existing = s_peersByIdentity.find(id); // make sure another thread didn't do this while we were - if (existing == s_peersByIdentity.end()) { - s_peersByIdentity.emplace(id,peer); - added = true; - } else { - peer = existing->second; - } - } - if (added) { - { - std::lock_guard pl(s_peers_l); - s_peers.emplace_back(peer); - } - { - std::lock_guard pbv_l(s_peersByVirtAddr_l); - s_peersByVirtAddr[id.address()].emplace(peer); - } - } - } - } - } - - // If it wasn't a HELLO, check to see if any known identities for the sender's - // short ZT address successfully decrypt the packet. - if (!peer) { - std::lock_guard pbv_l(s_peersByVirtAddr_l); - auto peers = s_peersByVirtAddr.find(source); - if (peers != s_peersByVirtAddr.end()) { - for(auto p=peers->second.begin();p!=peers->second.end();++p) { - if (pkt.dearmor((*p)->key)) { - if (!pkt.uncompress()) { - printf("%s packet rejected: decompression failed" ZT_EOL_S,ip->toString(ipstr)); - return; - } - peer = (*p); - break; - } - } - } - } - - // If we found the peer, update IP and/or time and handle certain key packet types that the - // root must concern itself with. - if (peer) { - if (ip->isV4()) - peer->ip4 = ip; - else if (ip->isV6()) - peer->ip6 = ip; - - const int64_t now = OSUtils::now(); - peer->lastReceive = now; - - switch(pkt.verb()) { - case Packet::VERB_HELLO: - try { - if ((now - peer->lastHello) > 500) { - peer->lastHello = now; - - peer->vProto = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; - peer->vMajor = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; - peer->vMinor = (int)pkt[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; - peer->vRev = (int)pkt.template at(ZT_PROTO_VERB_HELLO_IDX_REVISION); - const uint64_t origId = pkt.packetId(); - const uint64_t ts = pkt.template at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); - - pkt.reset(source,s_self.address(),Packet::VERB_OK); - pkt.append((uint8_t)Packet::VERB_HELLO); - pkt.append(origId); - pkt.append(ts); - pkt.append((uint8_t)ZT_PROTO_VERSION); - pkt.append((uint8_t)0); - pkt.append((uint8_t)0); - pkt.append((uint16_t)0); - ip->serialize(pkt); - if (peer->vProto < 11) { // send planet file for pre-2.x peers - std::lock_guard pl(s_planet_l); - if (s_planet.length() > 0) { - pkt.append((uint16_t)s_planet.size()); - pkt.append((const uint8_t *)s_planet.data(),s_planet.size()); - } - } - pkt.armor(peer->key,true); - sendto(ip->isV4() ? v4s : v6s,pkt.data(),pkt.size(),SENDTO_FLAGS,(const struct sockaddr *)ip,(socklen_t)((ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))); - - s_outputRate.log(now,pkt.size()); - peer->lastSend = now; - } - } catch ( ... ) { - printf("* unexpected exception handling HELLO from %s" ZT_EOL_S,ip->toString(ipstr)); - } - break; - - case Packet::VERB_ECHO: - try { - if ((now - peer->lastEcho) > 500) { - peer->lastEcho = now; - - Packet outp(source,s_self.address(),Packet::VERB_OK); - outp.append((uint8_t)Packet::VERB_ECHO); - outp.append(pkt.packetId()); - outp.append(((const uint8_t *)pkt.data()) + ZT_PACKET_IDX_PAYLOAD,pkt.size() - ZT_PACKET_IDX_PAYLOAD); - outp.compress(); - outp.armor(peer->key,true); - sendto(ip->isV4() ? v4s : v6s,outp.data(),outp.size(),SENDTO_FLAGS,(const struct sockaddr *)ip,(socklen_t)((ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))); - - s_outputRate.log(now,outp.size()); - peer->lastSend = now; - } - } catch ( ... ) { - printf("* unexpected exception handling ECHO from %s" ZT_EOL_S,ip->toString(ipstr)); - } - - case Packet::VERB_WHOIS: - try { - std::vector< SharedPtr > results; - { - std::lock_guard l(s_peersByVirtAddr_l); - for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;(ptr+ZT_ADDRESS_LENGTH)<=pkt.size();ptr+=ZT_ADDRESS_LENGTH) { - auto peers = s_peersByVirtAddr.find(Address(pkt.field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH)); - if (peers != s_peersByVirtAddr.end()) { - for(auto p=peers->second.begin();p!=peers->second.end();++p) - results.push_back(*p); - } - } - } - - if (!results.empty()) { - const uint64_t origId = pkt.packetId(); - pkt.reset(source,s_self.address(),Packet::VERB_OK); - pkt.append((uint8_t)Packet::VERB_WHOIS); - pkt.append(origId); - for(auto p=results.begin();p!=results.end();++p) - (*p)->id.serialize(pkt,false); - pkt.armor(peer->key,true); - sendto(ip->isV4() ? v4s : v6s,pkt.data(),pkt.size(),SENDTO_FLAGS,(const struct sockaddr *)ip,(socklen_t)((ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))); - - s_outputRate.log(now,pkt.size()); - peer->lastSend = now; - } - } catch ( ... ) { - printf("* unexpected exception handling ECHO from %s" ZT_EOL_S,ip->toString(ipstr)); - } - - case Packet::VERB_MULTICAST_LIKE: - try { - std::lock_guard l(s_multicastSubscriptions_l); - for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;(ptr+18)<=pkt.size();ptr+=18) { - const uint64_t nwid = pkt.template at(ptr); - const MulticastGroup mg(MAC(pkt.field(ptr + 8,6),6),pkt.template at(ptr + 14)); - s_multicastSubscriptions[nwid][mg][source] = now; - } - } catch ( ... ) { - printf("* unexpected exception handling MULTICAST_LIKE from %s" ZT_EOL_S,ip->toString(ipstr)); - } - break; - - case Packet::VERB_MULTICAST_GATHER: - try { - const uint64_t nwid = pkt.template at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_NETWORK_ID); - //const unsigned int flags = pkt[ZT_PROTO_VERB_MULTICAST_GATHER_IDX_FLAGS]; - const MulticastGroup mg(MAC(pkt.field(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_MAC,6),6),pkt.template at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_ADI)); - unsigned int gatherLimit = pkt.template at(ZT_PROTO_VERB_MULTICAST_GATHER_IDX_GATHER_LIMIT); - if (gatherLimit > 255) - gatherLimit = 255; - - const uint64_t origId = pkt.packetId(); - pkt.reset(source,s_self.address(),Packet::VERB_OK); - pkt.append((uint8_t)Packet::VERB_MULTICAST_GATHER); - pkt.append(origId); - pkt.append(nwid); - mg.mac().appendTo(pkt); - pkt.append((uint32_t)mg.adi()); - - { - std::lock_guard l(s_multicastSubscriptions_l); - auto forNet = s_multicastSubscriptions.find(nwid); - if (forNet != s_multicastSubscriptions.end()) { - auto forGroup = forNet->second.find(mg); - if (forGroup != forNet->second.end()) { - pkt.append((uint32_t)forGroup->second.size()); - const unsigned int countAt = pkt.size(); - pkt.addSize(2); - - unsigned int l = 0; - for(auto g=forGroup->second.begin();((lsecond.end()));++g) { - if (g->first != source) { - ++l; - g->first.appendTo(pkt); - } - } - - if (l > 0) { - pkt.setAt(countAt,(uint16_t)l); - pkt.armor(peer->key,true); - sendto(ip->isV4() ? v4s : v6s,pkt.data(),pkt.size(),SENDTO_FLAGS,(const struct sockaddr *)ip,(socklen_t)(ip->isV4() ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))); - - s_outputRate.log(now,pkt.size()); - peer->lastSend = now; - } - } - } - } - } catch ( ... ) { - printf("* unexpected exception handling MULTICAST_GATHER from %s" ZT_EOL_S,ip->toString(ipstr)); - } - break; - - default: - break; - } - - return; - } - } - - // If we made it here, we are forwarding this packet to someone else and also possibly - // sending a RENDEZVOUS message. - - int hops = 0; - bool introduce = false; - if (fragment) { - if ((hops = (int)reinterpret_cast(&pkt)->incrementHops()) > s_relayMaxHops) { - s_discardedForwardRate.log(now,pkt.size()); - return; - } - } else { - if ((hops = (int)pkt.incrementHops()) > s_relayMaxHops) { - s_discardedForwardRate.log(now,pkt.size()); - return; - } - - if (hops == 1) { - RendezvousKey rk(source,dest); - std::lock_guard l(s_rendezvousTracking_l); - RendezvousStats &lr = s_rendezvousTracking[rk]; - if ((now - lr.ts) >= 30000) { - ++lr.count; - lr.ts = now; - introduce = true; - } - } - } - - std::vector< std::pair< InetAddress *,SharedPtr > > toAddrs; - { - std::lock_guard pbv_l(s_peersByVirtAddr_l); - auto peers = s_peersByVirtAddr.find(dest); - if (peers != s_peersByVirtAddr.end()) { - for(auto p=peers->second.begin();p!=peers->second.end();++p) { - if ((*p)->ip4) { - toAddrs.emplace_back(std::pair< InetAddress *,SharedPtr >(&((*p)->ip4),*p)); - } else if ((*p)->ip6) { - toAddrs.emplace_back(std::pair< InetAddress *,SharedPtr >(&((*p)->ip6),*p)); - } - } - } - } - if (toAddrs.empty()) { - s_discardedForwardRate.log(now,pkt.size()); - return; - } - - if (introduce) { - std::lock_guard l(s_peersByVirtAddr_l); - auto sources = s_peersByVirtAddr.find(source); - if (sources != s_peersByVirtAddr.end()) { - for(auto a=sources->second.begin();a!=sources->second.end();++a) { - for(auto b=toAddrs.begin();b!=toAddrs.end();++b) { - if (((*a)->ip6)&&(b->second->ip6)) { - - // Introduce source to destination (V6) - Packet outp(source,s_self.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - dest.appendTo(outp); - outp.append((uint16_t)b->second->ip6.port()); - outp.append((uint8_t)16); - outp.append((const uint8_t *)(b->second->ip6.rawIpData()),16); - outp.armor((*a)->key,true); - sendto(v6s,outp.data(),outp.size(),SENDTO_FLAGS,(const struct sockaddr *)&((*a)->ip6),(socklen_t)sizeof(struct sockaddr_in6)); - - s_outputRate.log(now,outp.size()); - (*a)->lastSend = now; - - // Introduce destination to source (V6) - outp.reset(dest,s_self.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - source.appendTo(outp); - outp.append((uint16_t)(*a)->ip6.port()); - outp.append((uint8_t)16); - outp.append((const uint8_t *)((*a)->ip6.rawIpData()),16); - outp.armor(b->second->key,true); - sendto(v6s,outp.data(),outp.size(),SENDTO_FLAGS,(const struct sockaddr *)&(b->second->ip6),(socklen_t)sizeof(struct sockaddr_in6)); - - s_outputRate.log(now,outp.size()); - b->second->lastSend = now; - } - if (((*a)->ip4)&&(b->second->ip4)) { - - // Introduce source to destination (V4) - Packet outp(source,s_self.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - dest.appendTo(outp); - outp.append((uint16_t)b->second->ip4.port()); - outp.append((uint8_t)4); - outp.append((const uint8_t *)b->second->ip4.rawIpData(),4); - outp.armor((*a)->key,true); - sendto(v4s,outp.data(),outp.size(),SENDTO_FLAGS,(const struct sockaddr *)&((*a)->ip4),(socklen_t)sizeof(struct sockaddr_in)); - - s_outputRate.log(now,outp.size()); - (*a)->lastSend = now; - - // Introduce destination to source (V4) - outp.reset(dest,s_self.address(),Packet::VERB_RENDEZVOUS); - outp.append((uint8_t)0); - source.appendTo(outp); - outp.append((uint16_t)(*a)->ip4.port()); - outp.append((uint8_t)4); - outp.append((const uint8_t *)((*a)->ip4.rawIpData()),4); - outp.armor(b->second->key,true); - sendto(v4s,outp.data(),outp.size(),SENDTO_FLAGS,(const struct sockaddr *)&(b->second->ip4),(socklen_t)sizeof(struct sockaddr_in)); - - s_outputRate.log(now,outp.size()); - b->second->lastSend = now; - } - } - } - } - } - - for(auto i=toAddrs.begin();i!=toAddrs.end();++i) { - if (sendto(i->first->isV4() ? v4s : v6s,pkt.data(),pkt.size(),SENDTO_FLAGS,(const struct sockaddr *)i->first,(socklen_t)(i->first->isV4() ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) > 0) { - s_outputRate.log(now,pkt.size()); - s_forwardRate.log(now,pkt.size()); - i->second->lastSend = now; - } - } -} - -////////////////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////////////////// - -static int bindSocket(struct sockaddr *const bindAddr) -{ - const int s = socket(bindAddr->sa_family,SOCK_DGRAM,0); - if (s < 0) { - close(s); - return -1; - } - - int f = 16777216; - while (f > 131072) { - if (setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char *)&f,sizeof(f)) == 0) - break; - f -= 131072; - } - f = 16777216; - while (f > 131072) { - if (setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char *)&f,sizeof(f)) == 0) - break; - f -= 131072; - } - - if (bindAddr->sa_family == AF_INET6) { - f = 1; setsockopt(s,IPPROTO_IPV6,IPV6_V6ONLY,(void *)&f,sizeof(f)); -#ifdef IPV6_MTU_DISCOVER - f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_MTU_DISCOVER,&f,sizeof(f)); -#endif -#ifdef IPV6_DONTFRAG - f = 0; setsockopt(s,IPPROTO_IPV6,IPV6_DONTFRAG,&f,sizeof(f)); -#endif - } -#ifdef IP_DONTFRAG - f = 0; setsockopt(s,IPPROTO_IP,IP_DONTFRAG,&f,sizeof(f)); -#endif -#ifdef IP_MTU_DISCOVER - f = IP_PMTUDISC_DONT; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f)); -#endif - -/* -#ifdef SO_NO_CHECK - if (bindAddr->sa_family == AF_INET) { - f = 1; setsockopt(s,SOL_SOCKET,SO_NO_CHECK,(void *)&f,sizeof(f)); - } -#endif -*/ - -#ifdef SO_REUSEPORT - f = 1; setsockopt(s,SOL_SOCKET,SO_REUSEPORT,(void *)&f,sizeof(f)); -#endif -#ifndef __LINUX__ // linux wants just SO_REUSEPORT - f = 1; setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(void *)&f,sizeof(f)); -#endif - -#ifdef __LINUX__ - struct timeval tv; - tv.tv_sec = 1; - tv.tv_usec = 0; - setsockopt(s,SOL_SOCKET,SO_RCVTIMEO,(const void *)&tv,sizeof(tv)); -#endif - - if (bind(s,bindAddr,(bindAddr->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6))) { - close(s); - //printf("%s\n",strerror(errno)); - return -1; - } - - return s; -} - -static void shutdownSigHandler(int sig) -{ - s_run = false; -} - -int main(int argc,char **argv) -{ - std::vector threads; - std::vector sockets; - int v4Sock = -1,v6Sock = -1; - - signal(SIGTERM,shutdownSigHandler); - signal(SIGINT,shutdownSigHandler); - signal(SIGQUIT,shutdownSigHandler); - signal(SIGPIPE,SIG_IGN); - signal(SIGUSR1,SIG_IGN); - signal(SIGUSR2,SIG_IGN); - signal(SIGCHLD,SIG_IGN); - - s_startTime = OSUtils::now(); - s_geoInit = false; - - if (argc < 3) { - printf("Usage: zerotier-root " ZT_EOL_S); - return 1; - } - - { - std::string myIdStr; - if (!OSUtils::readFile(argv[1],myIdStr)) { - printf("FATAL: cannot read identity.secret at %s" ZT_EOL_S,argv[1]); - return 1; - } - if (!s_self.fromString(myIdStr.c_str())) { - printf("FATAL: cannot read identity.secret at %s (invalid identity)" ZT_EOL_S,argv[1]); - return 1; - } - if (!s_self.hasPrivate()) { - printf("FATAL: cannot read identity.secret at %s (missing secret key)" ZT_EOL_S,argv[1]); - return 1; - } - } - { - std::string configStr; - if (!OSUtils::readFile(argv[2],configStr)) { - printf("FATAL: cannot read config file at %s" ZT_EOL_S,argv[2]); - return 1; - } - try { - s_config = json::parse(configStr); - } catch (std::exception &exc) { - printf("FATAL: config file at %s invalid: %s" ZT_EOL_S,argv[2],exc.what()); - return 1; - } catch ( ... ) { - printf("FATAL: config file at %s invalid: unknown exception" ZT_EOL_S,argv[2]); - return 1; - } - if (!s_config.is_object()) { - printf("FATAL: config file at %s invalid: does not contain a JSON object" ZT_EOL_S,argv[2]); - return 1; - } - } - - try { - auto jport = s_config["port"]; - if (jport.is_array()) { - for(long i=0;i<(long)jport.size();++i) { - int port = jport[i]; - if ((port <= 0)||(port > 65535)) { - printf("FATAL: invalid port in config file %d" ZT_EOL_S,port); - return 1; - } - s_ports.push_back(port); - } - } else { - int port = jport; - if ((port <= 0)||(port > 65535)) { - printf("FATAL: invalid port in config file %d" ZT_EOL_S,port); - return 1; - } - s_ports.push_back(port); - } - } catch ( ... ) {} - if (s_ports.empty()) - s_ports.push_back(ZT_DEFAULT_PORT); - std::sort(s_ports.begin(),s_ports.end()); - - int httpPort = ZT_DEFAULT_PORT; - try { - httpPort = s_config["httpPort"]; - if ((httpPort <= 0)||(httpPort > 65535)) { - printf("FATAL: invalid HTTP port in config file %d" ZT_EOL_S,httpPort); - return 1; - } - } catch ( ... ) { - httpPort = ZT_DEFAULT_PORT; - } - - std::string planetFilePath; - try { - planetFilePath = s_config["planetFile"]; - } catch ( ... ) { - planetFilePath = ""; - } - - try { - s_statsRoot = s_config["statsRoot"]; - while ((s_statsRoot.length() > 0)&&(s_statsRoot[s_statsRoot.length()-1] == ZT_PATH_SEPARATOR)) - s_statsRoot = s_statsRoot.substr(0,s_statsRoot.length()-1); - if (s_statsRoot.length() > 0) - OSUtils::mkdir(s_statsRoot); - } catch ( ... ) { - s_statsRoot = ""; - } - - s_relayMaxHops = ZT_RELAY_MAX_HOPS; - try { - s_relayMaxHops = s_config["relayMaxHops"]; - if (s_relayMaxHops > ZT_PROTO_MAX_HOPS) - s_relayMaxHops = ZT_PROTO_MAX_HOPS; - else if (s_relayMaxHops < 0) - s_relayMaxHops = 0; - } catch ( ... ) { - s_relayMaxHops = ZT_RELAY_MAX_HOPS; - } - - try { - s_googleMapsAPIKey = s_config["googleMapsAPIKey"]; - std::string geoIpPath = s_config["geoIp"]; - if (geoIpPath.length() > 0) { - FILE *gf = fopen(geoIpPath.c_str(),"rb"); - if (gf) { - threads.emplace_back(std::thread([gf]() { - try { - char line[1024]; - line[1023] = 0; - while (fgets(line,sizeof(line)-1,gf)) { - InetAddress start,end; - float lat = 0.0F,lon = 0.0F; - int field = 0; - for(char *saveptr=nullptr,*f=Utils::stok(line,",\r\n",&saveptr);(f);f=Utils::stok(nullptr,",\r\n",&saveptr)) { - switch(field++) { - case 0: - start.fromString(f); - break; - case 1: - end.fromString(f); - break; - case 2: - lat = strtof(f,nullptr); - break; - case 3: - lon = strtof(f,nullptr); - break; - } - } - if ((start)&&(end)&&(start.ss_family == end.ss_family)&&(lat >= -90.0F)&&(lat <= 90.0F)&&(lon >= -180.0F)&&(lon <= 180.0F)) { - if (start.ss_family == AF_INET) { - s_geoIp4[std::pair< uint32_t,uint32_t >(ip4ToH32(start),ip4ToH32(end))] = std::pair< float,float >(lat,lon); - } else if (start.ss_family == AF_INET6) { - s_geoIp6[std::pair< std::array< uint64_t,2 >,std::array< uint64_t,2 > >(ip6ToH128(start),ip6ToH128(end))] = std::pair< float,float >(lat,lon); - } - } - } - s_geoInit = true; - } catch ( ... ) {} - fclose(gf); - })); - } - } - } catch ( ... ) {} - - unsigned int ncores = std::thread::hardware_concurrency(); - if (ncores == 0) ncores = 1; - - s_run = true; - - for(auto port=s_ports.begin();port!=s_ports.end();++port) { - for(unsigned int tn=0;tnunsafeData(),pkt->capacity(),RECVFROM_FLAGS,(struct sockaddr *)&in6,&sl); - if (pl > 0) { - if ((pl >= ZT_PROTO_MIN_FRAGMENT_LENGTH)&&(pl <= ZT_PROTO_MAX_PACKET_LENGTH)) { - try { - pkt->setSize((unsigned int)pl); - handlePacket(s4,s6,reinterpret_cast(&in6),*pkt); - } catch (std::exception &exc) { - char ipstr[128]; - printf("WARNING: unexpected exception handling packet from %s: %s" ZT_EOL_S,reinterpret_cast(&in6)->toString(ipstr),exc.what()); - } catch (int exc) { - char ipstr[128]; - printf("WARNING: unexpected exception handling packet from %s: ZT exception code %d" ZT_EOL_S,reinterpret_cast(&in6)->toString(ipstr),exc); - } catch ( ... ) { - char ipstr[128]; - printf("WARNING: unexpected exception handling packet from %s: unknown exception" ZT_EOL_S,reinterpret_cast(&in6)->toString(ipstr)); - } - } - } else if (!s_run) { - break; - } - } - delete pkt; - })); - - threads.push_back(std::thread([s6,s4]() { - struct sockaddr_in in4; - Packet *pkt = new Packet(); - for(;;) { - memset(&in4,0,sizeof(in4)); - socklen_t sl = sizeof(in4); - const int pl = (int)recvfrom(s4,pkt->unsafeData(),pkt->capacity(),RECVFROM_FLAGS,(struct sockaddr *)&in4,&sl); - if (pl > 0) { - if ((pl >= ZT_PROTO_MIN_FRAGMENT_LENGTH)&&(pl <= ZT_PROTO_MAX_PACKET_LENGTH)) { - try { - pkt->setSize((unsigned int)pl); - handlePacket(s4,s6,reinterpret_cast(&in4),*pkt); - } catch (std::exception &exc) { - char ipstr[128]; - printf("WARNING: unexpected exception handling packet from %s: %s" ZT_EOL_S,reinterpret_cast(&in4)->toString(ipstr),exc.what()); - } catch (int exc) { - char ipstr[128]; - printf("WARNING: unexpected exception handling packet from %s: ZT exception code %d" ZT_EOL_S,reinterpret_cast(&in4)->toString(ipstr),exc); - } catch ( ... ) { - char ipstr[128]; - printf("WARNING: unexpected exception handling packet from %s: unknown exception" ZT_EOL_S,reinterpret_cast(&in4)->toString(ipstr)); - } - } - } else if (!s_run) { - break; - } - } - delete pkt; - })); - } - } - - // A minimal read-only local API for monitoring and status queries - httplib::Server apiServ; - threads.push_back(std::thread([&apiServ,httpPort]() { - // Human readable status page - apiServ.Get("/",[](const httplib::Request &req,httplib::Response &res) { - std::ostringstream o; - o << "ZeroTier Root Server " << ZEROTIER_ONE_VERSION_MAJOR << '.' << ZEROTIER_ONE_VERSION_MINOR << '.' << ZEROTIER_ONE_VERSION_REVISION << ZT_EOL_S; - o << "(c)2019 ZeroTier, Inc." ZT_EOL_S "Licensed under the ZeroTier BSL 1.1" ZT_EOL_S ZT_EOL_S; - s_peersByIdentity_l.lock(); - o << "Peers Online: " << s_peersByIdentity.size() << ZT_EOL_S; - s_peersByIdentity_l.unlock(); - res.set_content(o.str(),"text/plain"); - }); - - apiServ.Get("/metrics",[](const httplib::Request &req, httplib::Response &res) { - std::ostringstream o; - int64_t now = OSUtils::now(); - - char buf[11]; - const char *root_id = s_self.address().toString(buf); - o << "# HELP root_peers_online Number of active peers online" << ZT_EOL_S; - o << "# TYPE root_peers_online gauge" << ZT_EOL_S; - s_peersByIdentity_l.lock(); - o << "root_peers_online{root_id=\"" << root_id << "\"} " << s_peersByIdentity.size() << ZT_EOL_S; - s_peersByIdentity_l.unlock(); - o << "# HELP root_input_rate Input rate MiB/s" << ZT_EOL_S; - o << "# TYPE root_input_rate gauge" << ZT_EOL_S; - o << "root_input_rate{root_id=\"" << root_id << "\"} " << std::setprecision(5) << (s_inputRate.perSecond(now)/1048576.0) << ZT_EOL_S; - o << "# HELP root_output_rate Output rate MiB/s" << ZT_EOL_S; - o << "# TYPE root_output_rate gauge" << ZT_EOL_S; - o << "root_output_rate{root_id=\"" << root_id << "\"} " << std::setprecision(5) << (s_outputRate.perSecond(now)/1048576.0) << ZT_EOL_S; - o << "# HELP root_forwarded_rate Forwarded packet rate MiB/s" << ZT_EOL_S; - o << "# TYPE root_forwarded_rate gauge" << ZT_EOL_S; - o << "root_forwarded_rate{root_id=\"" << root_id << "\"} " << std::setprecision(5) << (s_forwardRate.perSecond(now)/1048576.0) << ZT_EOL_S; - o << "# HELP root_discarded_rate Discarded forwards MiB/s" << ZT_EOL_S; - o << "# TYPE root_discarded_rate gauge" << ZT_EOL_S; - o << "root_discarded_rate{root_id=\"" << root_id << "\"} " << std::setprecision(5) << (s_discardedForwardRate.perSecond(now)/1048576.0) << ZT_EOL_S; - - res.set_content(o.str(), "text/plain"); - }); - - // Peer list for compatibility with software that monitors regular nodes - apiServ.Get("/peer",[](const httplib::Request &req,httplib::Response &res) { - char tmp[256]; - std::ostringstream o; - o << '['; - try { - bool first = true; - std::lock_guard l(s_peers_l); - for(auto p=s_peers.begin();p!=s_peers.end();++p) { - if (first) - first = false; - else o << ','; - o << - "{\"address\":\"" << (*p)->id.address().toString(tmp) << "\"" - ",\"latency\":-1" - ",\"paths\":["; - if ((*p)->ip4) { - o << - "{\"active\":true" - ",\"address\":\"" << (*p)->ip4.toIpString(tmp) << "\\/" << (*p)->ip4.port() << "\"" - ",\"expired\":false" - ",\"lastReceive\":" << (*p)->lastReceive << - ",\"lastSend\":" << (*p)->lastSend << - ",\"preferred\":true" - ",\"trustedPathId\":0}"; - } - if ((*p)->ip6) { - if ((*p)->ip4) - o << ','; - o << - "{\"active\":true" - ",\"address\":\"" << (*p)->ip6.toIpString(tmp) << "\\/" << (*p)->ip6.port() << "\"" - ",\"expired\":false" - ",\"lastReceive\":" << (*p)->lastReceive << - ",\"lastSend\":" << (*p)->lastSend << - ",\"preferred\":" << (((*p)->ip4) ? "false" : "true") << - ",\"trustedPathId\":0}"; - } - o << "]" - ",\"role\":\"LEAF\"" - ",\"version\":\"" << (*p)->vMajor << '.' << (*p)->vMinor << '.' << (*p)->vRev << "\"" - ",\"versionMajor\":" << (*p)->vMajor << - ",\"versionMinor\":" << (*p)->vMinor << - ",\"versionRev\":" << (*p)->vRev << "}"; - } - } catch ( ... ) {} - o << ']'; - res.set_content(o.str(),"application/json"); - }); - - // GeoIP map if enabled - apiServ.Get("/map",[](const httplib::Request &req,httplib::Response &res) { - char tmp[4096]; - if (!s_geoInit) { - res.set_content("Not enabled or GeoIP CSV file not finished reading.","text/plain"); - return; - } - std::ostringstream o; - o << ZT_GEOIP_HTML_HEAD; - try { - bool firstCoord = true; - std::pair< uint32_t,uint32_t > k4(0,0xffffffff); - std::pair< std::array< uint64_t,2 >,std::array< uint64_t,2 > > k6; - k6.second[0] = 0xffffffffffffffffULL; k6.second[1] = 0xffffffffffffffffULL; - - std::unordered_map< InetAddress,std::set
,InetAddressHasher > ips; - { - std::lock_guard l(s_peers_l); - for(auto p=s_peers.begin();p!=s_peers.end();++p) { - if ((*p)->ip4) - ips[(*p)->ip4].insert((*p)->id.address()); - if ((*p)->ip6) - ips[(*p)->ip6].insert((*p)->id.address()); - } - } - - for(auto p=ips.begin();p!=ips.end();++p) { - if (p->first.isV4()) { - k4.first = ip4ToH32(p->first); - auto geo = std::map< std::pair< uint32_t,uint32_t >,std::pair< float,float > >::reverse_iterator(s_geoIp4.upper_bound(k4)); - uint32_t bestRangeSize = 0xffffffff; - std::pair< float,float > bestRangeLatLon; - while (geo != s_geoIp4.rend()) { - if ((geo->first.first <= k4.first)&&(geo->first.second >= k4.first)) { - uint32_t range = geo->first.second - geo->first.first; - if (range <= bestRangeSize) { - bestRangeSize = range; - bestRangeLatLon = geo->second; - } - } else if ((geo->first.first < k4.first)&&(geo->first.second < k4.first)) { - break; - } - ++geo; - } - if (bestRangeSize != 0xffffffff) { - if (!firstCoord) - o << ','; - firstCoord = false; - o << "{lat:" << bestRangeLatLon.first << ",lng:" << bestRangeLatLon.second << ",_l:\""; - bool firstAddr = true; - for(auto a=p->second.begin();a!=p->second.end();++a) { - if (!firstAddr) - o << ','; - o << a->toString(tmp); - firstAddr = false; - } - o << "\"}"; - } - } else if (p->first.isV6()) { - k6.first = ip6ToH128(p->first); - auto geo = std::map< std::pair< std::array< uint64_t,2 >,std::array< uint64_t,2 > >,std::pair< float,float > >::reverse_iterator(s_geoIp6.upper_bound(k6)); - while (geo != s_geoIp6.rend()) { - if ((geo->first.first <= k6.first)&&(geo->first.second >= k6.first)) { - if (!firstCoord) - o << ','; - firstCoord = false; - o << "{lat:" << geo->second.first << ",lng:" << geo->second.second << ",_l:\""; - bool firstAddr = true; - for(auto a=p->second.begin();a!=p->second.end();++a) { - if (!firstAddr) - o << ','; - o << a->toString(tmp); - firstAddr = false; - } - o << "\"}"; - break; - } else if ((geo->first.first < k6.first)&&(geo->first.second < k6.first)) { - break; - } - ++geo; - } - } - } - } catch ( ... ) { - res.set_content("Internal error: unexpected exception resolving GeoIP locations","text/plain"); - return; - } - OSUtils::ztsnprintf(tmp,sizeof(tmp),ZT_GEOIP_HTML_TAIL,s_googleMapsAPIKey.c_str()); - o << tmp; - res.set_content(o.str(),"text/html"); - }); - - apiServ.listen("127.0.0.1",httpPort,0); - })); - - // In the main thread periodically clean stuff up - int64_t lastCleaned = 0; - int64_t lastWroteStats = 0; - while (s_run) { - sleep(1); - - const int64_t now = OSUtils::now(); - - if ((now - lastCleaned) > 300000) { - lastCleaned = now; - - // Old multicast subscription cleanup - { - std::lock_guard l(s_multicastSubscriptions_l); - for(auto a=s_multicastSubscriptions.begin();a!=s_multicastSubscriptions.end();) { - for(auto b=a->second.begin();b!=a->second.end();) { - for(auto c=b->second.begin();c!=b->second.end();) { - if ((now - c->second) > ZT_PEER_ACTIVITY_TIMEOUT) - b->second.erase(c++); - else ++c; - } - if (b->second.empty()) - a->second.erase(b++); - else ++b; - } - if (a->second.empty()) - s_multicastSubscriptions.erase(a++); - else ++a; - } - } - - // Remove expired peers - try { - std::vector< SharedPtr > toRemove; - toRemove.reserve(1024); - { - std::lock_guard pbi_l(s_peers_l); - for(auto p=s_peers.begin();p!=s_peers.end();) { - if ((now - (*p)->lastReceive) > ZT_PEER_ACTIVITY_TIMEOUT) { - toRemove.emplace_back(*p); - s_peers.erase(p++); - } else ++p; - } - } - for(auto p=toRemove.begin();p!=toRemove.end();++p) { - { - std::lock_guard pbi_l(s_peersByIdentity_l); - s_peersByIdentity.erase((*p)->id); - } - { - std::lock_guard pbv_l(s_peersByVirtAddr_l); - auto pbv = s_peersByVirtAddr.find((*p)->id.address()); - if (pbv != s_peersByVirtAddr.end()) { - pbv->second.erase(*p); - if (pbv->second.empty()) - s_peersByVirtAddr.erase(pbv); - } - } - } - } catch ( ... ) {} - - // Remove old rendezvous entries - { - std::lock_guard l(s_rendezvousTracking_l); - for(auto lr=s_rendezvousTracking.begin();lr!=s_rendezvousTracking.end();) { - if ((now - lr->second.ts) > ZT_PEER_ACTIVITY_TIMEOUT) - s_rendezvousTracking.erase(lr++); - else ++lr; - } - } - } - - // Write stats if configured to do so, and periodically refresh planet file (if any) - if (((now - lastWroteStats) > 15000)&&(s_statsRoot.length() > 0)) { - lastWroteStats = now; - - try { - if (planetFilePath.length() > 0) { - std::string planetData; - if ((OSUtils::readFile(planetFilePath.c_str(),planetData))&&(planetData.length() > 0)) { - std::lock_guard pl(s_planet_l); - s_planet = planetData; - } - } - } catch ( ... ) { - std::lock_guard pl(s_planet_l); - s_planet.clear(); - } - - std::string peersFilePath(s_statsRoot); - peersFilePath.append("/.peers.tmp"); - FILE *pf = fopen(peersFilePath.c_str(),"wb"); - if (pf) { - std::vector< SharedPtr > sp; - { - std::lock_guard pbi_l(s_peers_l); - sp.reserve(s_peers.size()); - for(auto p=s_peers.begin();p!=s_peers.end();++p) { - sp.emplace_back(*p); - } - } - std::sort(sp.begin(),sp.end(),[](const SharedPtr &a,const SharedPtr &b) { return (a->id < b->id); }); - - fprintf(pf,"Address %21s %45s %10s %6s %10s" ZT_EOL_S,"IPv4","IPv6","Age(sec)","Vers","Fwd(KiB/s)"); - { - char ip4[128],ip6[128],ver[128]; - for(auto p=sp.begin();p!=sp.end();++p) { - if ((*p)->ip4) { - (*p)->ip4.toString(ip4); - } else { - ip4[0] = '-'; - ip4[1] = 0; - } - if ((*p)->ip6) { - (*p)->ip6.toString(ip6); - } else { - ip6[0] = '-'; - ip6[1] = 0; - } - OSUtils::ztsnprintf(ver,sizeof(ver),"%d.%d.%d",(*p)->vMajor,(*p)->vMinor,(*p)->vRev); - fprintf(pf,"%.10llx %21s %45s %10.4f %6s" ZT_EOL_S, - (unsigned long long)(*p)->id.address().toInt(), - ip4, - ip6, - fabs((double)(now - (*p)->lastReceive) / 1000.0), - ver); - } - } - - fclose(pf); - std::string peersFilePath2(s_statsRoot); - peersFilePath2.append("/peers"); - OSUtils::rm(peersFilePath2); - OSUtils::rename(peersFilePath.c_str(),peersFilePath2.c_str()); - } - - std::string statsFilePath(s_statsRoot); - statsFilePath.append("/.stats.tmp"); - FILE *sf = fopen(statsFilePath.c_str(),"wb"); - if (sf) { - fprintf(sf,"Uptime (seconds) : %ld" ZT_EOL_S,(long)((now - s_startTime) / 1000)); - s_peersByIdentity_l.lock(); - auto peersByIdentitySize = s_peersByIdentity.size(); - s_peersByIdentity_l.unlock(); - fprintf(sf,"Peers : %llu" ZT_EOL_S,(unsigned long long)peersByIdentitySize); - s_peersByVirtAddr_l.lock(); - fprintf(sf,"Virtual Address Collisions : %llu" ZT_EOL_S,(unsigned long long)(peersByIdentitySize - s_peersByVirtAddr.size())); - s_peersByVirtAddr_l.unlock(); - s_rendezvousTracking_l.lock(); - uint64_t unsuccessfulp2p = 0; - for(auto lr=s_rendezvousTracking.begin();lr!=s_rendezvousTracking.end();++lr) { - if (lr->second.count > 6) // 6 == two attempts per edge, one for each direction - ++unsuccessfulp2p; - } - fprintf(sf,"Recent P2P Graph Edges : %llu" ZT_EOL_S,(unsigned long long)s_rendezvousTracking.size()); - if (s_rendezvousTracking.empty()) { - fprintf(sf,"Recent P2P Success Rate : 100.0000%%" ZT_EOL_S); - } else { - fprintf(sf,"Recent P2P Success Rate : %.4f%%" ZT_EOL_S,(1.0 - ((double)unsuccessfulp2p / (double)s_rendezvousTracking.size())) * 100.0); - } - s_rendezvousTracking_l.unlock(); - fprintf(sf,"Input (MiB/s) : %.4f" ZT_EOL_S,s_inputRate.perSecond(now) / 1048576.0); - fprintf(sf,"Output (MiB/s) : %.4f" ZT_EOL_S,s_outputRate.perSecond(now) / 1048576.0); - fprintf(sf,"Forwarded (MiB/s) : %.4f" ZT_EOL_S,s_forwardRate.perSecond(now) / 1048576.0); - fprintf(sf,"Discarded Forward (MiB/s) : %.4f" ZT_EOL_S,s_discardedForwardRate.perSecond(now) / 1048576.0); - - fclose(sf); - std::string statsFilePath2(s_statsRoot); - statsFilePath2.append("/stats"); - OSUtils::rm(statsFilePath2); - OSUtils::rename(statsFilePath.c_str(),statsFilePath2.c_str()); - } - } - } - - // If we received a kill signal, close everything and wait - // for threads to die before exiting. - s_run = false; // sanity check - apiServ.stop(); - for(auto s=sockets.begin();s!=sockets.end();++s) { - shutdown(*s,SHUT_RDWR); - close(*s); - } - for(auto t=threads.begin();t!=threads.end();++t) - t->join(); - - return 0; -} diff --git a/attic/root/thirdparty/cpp-httplib/LICENSE b/attic/root/thirdparty/cpp-httplib/LICENSE deleted file mode 100644 index 3e5ed359a..000000000 --- a/attic/root/thirdparty/cpp-httplib/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 yhirose - -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. - diff --git a/attic/root/thirdparty/cpp-httplib/README.md b/attic/root/thirdparty/cpp-httplib/README.md deleted file mode 100644 index 6d0c8cb76..000000000 --- a/attic/root/thirdparty/cpp-httplib/README.md +++ /dev/null @@ -1,259 +0,0 @@ -cpp-httplib -=========== - -[![Build Status](https://travis-ci.org/yhirose/cpp-httplib.svg?branch=master)](https://travis-ci.org/yhirose/cpp-httplib) -[![Bulid Status](https://ci.appveyor.com/api/projects/status/github/yhirose/cpp-httplib?branch=master&svg=true)](https://ci.appveyor.com/project/yhirose/cpp-httplib) - -A C++ header-only cross platform HTTP/HTTPS library. - -It's extremely easy to setup. Just include **httplib.h** file in your code! - -Inspired by [Sinatra](http://www.sinatrarb.com/) and [express](https://github.com/visionmedia/express). - -Server Example --------------- - -```c++ -#include - -int main(void) -{ - using namespace httplib; - - Server svr; - - svr.Get("/hi", [](const Request& req, Response& res) { - res.set_content("Hello World!", "text/plain"); - }); - - svr.Get(R"(/numbers/(\d+))", [&](const Request& req, Response& res) { - auto numbers = req.matches[1]; - res.set_content(numbers, "text/plain"); - }); - - svr.listen("localhost", 1234); -} -``` - -`Post`, `Put`, `Delete` and `Options` methods are also supported. - -### Bind a socket to multiple interfaces and any available port - -```cpp -int port = svr.bind_to_any_port("0.0.0.0"); -svr.listen_after_bind(); -``` - -### Method Chain - -```cpp -svr.Get("/get", [](const auto& req, auto& res) { - res.set_content("get", "text/plain"); - }) - .Post("/post", [](const auto& req, auto& res) { - res.set_content(req.body(), "text/plain"); - }) - .listen("localhost", 1234); -``` - -### Static File Server - -```cpp -svr.set_base_dir("./www"); -``` - -### Logging - -```cpp -svr.set_logger([](const auto& req, const auto& res) { - your_logger(req, res); -}); -``` - -### Error Handler - -```cpp -svr.set_error_handler([](const auto& req, auto& res) { - const char* fmt = "

Error Status: %d

"; - char buf[BUFSIZ]; - snprintf(buf, sizeof(buf), fmt, res.status); - res.set_content(buf, "text/html"); -}); -``` - -### 'multipart/form-data' POST data - -```cpp -svr.Post("/multipart", [&](const auto& req, auto& res) { - auto size = req.files.size(); - auto ret = req.has_file("name1")); - const auto& file = req.get_file_value("name1"); - // file.filename; - // file.content_type; - auto body = req.body.substr(file.offset, file.length)); -}) -``` - -Client Example --------------- - -### GET - -```c++ -#include -#include - -int main(void) -{ - httplib::Client cli("localhost", 1234); - - auto res = cli.Get("/hi"); - if (res && res->status == 200) { - std::cout << res->body << std::endl; - } -} -``` - -### GET with Content Receiver - -```c++ - std::string body; - auto res = cli.Get("/large-data", [&](const char *data, size_t len) { - body.append(data, len); - }); - assert(res->body.empty()); -``` - -### POST - -```c++ -res = cli.Post("/post", "text", "text/plain"); -res = cli.Post("/person", "name=john1¬e=coder", "application/x-www-form-urlencoded"); -``` - -### POST with parameters - -```c++ -httplib::Params params; -params.emplace("name", "john"); -params.emplace("note", "coder"); - -auto res = cli.Post("/post", params); -``` - or - -```c++ -httplib::Params params{ - { "name", "john" }, - { "note", "coder" } -}; - -auto res = cli.Post("/post", params); -``` - -### PUT - -```c++ -res = cli.Put("/resource/s_arbitraryByte", "text", "text/plain"); -``` - -### DELETE - -```c++ -res = cli.Delete("/resource/s_arbitraryByte"); -``` - -### OPTIONS - -```c++ -res = cli.Options("*"); -res = cli.Options("/resource/s_arbitraryByte"); -``` - -### Connection Timeout - -```c++ -httplib::Client cli("localhost", 8080, 5); // timeouts in 5 seconds -``` -### With Progress Callback - -```cpp -httplib::Client client(url, port); - -// prints: 0 / 000 bytes => 50% complete -std::shared_ptr res = - cli.Get("/", [](uint64_t len, uint64_t total) { - printf("%lld / %lld bytes => %d%% complete\n", - len, total, - (int)((len/total)*100)); - return true; // return 'false' if you want to cancel the request. - } -); -``` - -![progress](https://user-images.githubusercontent.com/236374/33138910-495c4ecc-cf86-11e7-8693-2fc6d09615c4.gif) - -This feature was contributed by [underscorediscovery](https://github.com/yhirose/cpp-httplib/pull/23). - -### Basic Authentication - -```cpp -httplib::Client cli("httplib.org"); - -auto res = cli.Get("/basic-auth/hello/world", { - httplib::make_basic_authentication_header("hello", "world") -}); -// res->status should be 200 -// res->body should be "{\n \"authenticated\": true, \n \"user\": \"hello\"\n}\n". -``` - -### Range - -```cpp -httplib::Client cli("httpbin.org"); - -auto res = cli.Get("/range/32", { - httplib::make_range_header(1, 10) // 'Range: bytes=1-10' -}); -// res->status should be 206. -// res->body should be "bcdefghijk". -``` - -OpenSSL Support ---------------- - -SSL support is available with `CPPHTTPLIB_OPENSSL_SUPPORT`. `libssl` and `libcrypto` should be linked. - -```c++ -#define CPPHTTPLIB_OPENSSL_SUPPORT - -SSLServer svr("./cert.pem", "./key.pem"); - -SSLClient cli("localhost", 8080); -cli.set_ca_cert_path("./ca-bundle.crt"); -cli.enable_server_certificate_verification(true); -``` - -Zlib Support ------------- - -'gzip' compression is available with `CPPHTTPLIB_ZLIB_SUPPORT`. - -The server applies gzip compression to the following MIME type contents: - - * all text types - * image/svg+xml - * application/javascript - * application/json - * application/xml - * application/xhtml+xml - -NOTE ----- - -g++ 4.8 cannot build this library since `` in g++4.8 is [broken](https://stackoverflow.com/questions/12530406/is-gcc-4-8-or-earlier-buggy-about-regular-expressions). - -License -------- - -MIT license (© 2019 Yuji Hirose) diff --git a/attic/root/thirdparty/cpp-httplib/httplib.h b/attic/root/thirdparty/cpp-httplib/httplib.h deleted file mode 100644 index 5adfc2afe..000000000 --- a/attic/root/thirdparty/cpp-httplib/httplib.h +++ /dev/null @@ -1,2779 +0,0 @@ -// -// httplib.h -// -// Copyright (c) 2019 Yuji Hirose. All rights reserved. -// MIT License -// - -#ifndef CPPHTTPLIB_HTTPLIB_H -#define CPPHTTPLIB_HTTPLIB_H - -#ifdef _WIN32 -#ifndef _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_WARNINGS -#endif //_CRT_SECURE_NO_WARNINGS - -#ifndef _CRT_NONSTDC_NO_DEPRECATE -#define _CRT_NONSTDC_NO_DEPRECATE -#endif //_CRT_NONSTDC_NO_DEPRECATE - -#if defined(_MSC_VER) && _MSC_VER < 1900 -#define snprintf _snprintf_s -#endif // _MSC_VER - -#ifndef S_ISREG -#define S_ISREG(m) (((m)&S_IFREG) == S_IFREG) -#endif // S_ISREG - -#ifndef S_ISDIR -#define S_ISDIR(m) (((m)&S_IFDIR) == S_IFDIR) -#endif // S_ISDIR - -#ifndef NOMINMAX -#define NOMINMAX -#endif // NOMINMAX - -#include -#include -#include - -#pragma comment(lib, "ws2_32.lib") - -#ifndef strcasecmp -#define strcasecmp _stricmp -#endif // strcasecmp - -typedef SOCKET socket_t; -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef int socket_t; -#define INVALID_SOCKET (-1) -#endif //_WIN32 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -#include -#include -#include - -#if OPENSSL_VERSION_NUMBER < 0x10100000L -inline const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *asn1) { - return M_ASN1_STRING_data(asn1); -} -#endif -#endif - -#ifdef CPPHTTPLIB_ZLIB_SUPPORT -#include -#endif - -/* - * Configuration - */ -#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5 -#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND 0 -#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 5 -#define CPPHTTPLIB_READ_TIMEOUT_SECOND 5 -#define CPPHTTPLIB_READ_TIMEOUT_USECOND 0 -#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192 -#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (std::numeric_limits::max)() -#define CPPHTTPLIB_RECV_BUFSIZ size_t(4096u) - -namespace httplib { - -namespace detail { - -struct ci { - bool operator()(const std::string &s1, const std::string &s2) const { - return std::lexicographical_compare( - s1.begin(), s1.end(), s2.begin(), s2.end(), - [](char c1, char c2) { return ::tolower(c1) < ::tolower(c2); }); - } -}; - -} // namespace detail - -enum class HttpVersion { v1_0 = 0, v1_1 }; - -typedef std::multimap Headers; - -template -std::pair make_range_header(uint64_t value, - Args... args); - -typedef std::multimap Params; -typedef std::smatch Match; - -typedef std::function ContentProducer; -typedef std::function ContentReceiver; -typedef std::function Progress; - -struct MultipartFile { - std::string filename; - std::string content_type; - size_t offset = 0; - size_t length = 0; -}; -typedef std::multimap MultipartFiles; - -struct Request { - std::string version; - std::string method; - std::string target; - std::string path; - Headers headers; - std::string body; - Params params; - MultipartFiles files; - Match matches; - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT - const SSL *ssl; -#endif - - bool has_header(const char *key) const; - std::string get_header_value(const char *key, size_t id = 0) const; - size_t get_header_value_count(const char *key) const; - void set_header(const char *key, const char *val); - - bool has_param(const char *key) const; - std::string get_param_value(const char *key, size_t id = 0) const; - size_t get_param_value_count(const char *key) const; - - bool has_file(const char *key) const; - MultipartFile get_file_value(const char *key) const; -}; - -struct Response { - std::string version; - int status; - Headers headers; - std::string body; - - ContentProducer content_producer; - ContentReceiver content_receiver; - Progress progress; - - bool has_header(const char *key) const; - std::string get_header_value(const char *key, size_t id = 0) const; - size_t get_header_value_count(const char *key) const; - void set_header(const char *key, const char *val); - - void set_redirect(const char *uri); - void set_content(const char *s, size_t n, const char *content_type); - void set_content(const std::string &s, const char *content_type); - - Response() : status(-1) {} -}; - -class Stream { -public: - virtual ~Stream() {} - virtual int read(char *ptr, size_t size) = 0; - virtual int write(const char *ptr, size_t size1) = 0; - virtual int write(const char *ptr) = 0; - virtual std::string get_remote_addr() const = 0; - - template - void write_format(const char *fmt, const Args &... args); -}; - -class SocketStream : public Stream { -public: - SocketStream(socket_t sock); - virtual ~SocketStream(); - - virtual int read(char *ptr, size_t size); - virtual int write(const char *ptr, size_t size); - virtual int write(const char *ptr); - virtual std::string get_remote_addr() const; - -private: - socket_t sock_; -}; - -class BufferStream : public Stream { -public: - BufferStream() {} - virtual ~BufferStream() {} - - virtual int read(char *ptr, size_t size); - virtual int write(const char *ptr, size_t size); - virtual int write(const char *ptr); - virtual std::string get_remote_addr() const; - - const std::string &get_buffer() const; - -private: - std::string buffer; -}; - -class Server { -public: - typedef std::function Handler; - typedef std::function Logger; - - Server(); - - virtual ~Server(); - - virtual bool is_valid() const; - - Server &Get(const char *pattern, Handler handler); - Server &Post(const char *pattern, Handler handler); - - Server &Put(const char *pattern, Handler handler); - Server &Patch(const char *pattern, Handler handler); - Server &Delete(const char *pattern, Handler handler); - Server &Options(const char *pattern, Handler handler); - - bool set_base_dir(const char *path); - - void set_error_handler(Handler handler); - void set_logger(Logger logger); - - void set_keep_alive_max_count(size_t count); - void set_payload_max_length(uint64_t length); - - int bind_to_any_port(const char *host, int socket_flags = 0); - bool listen_after_bind(); - - bool listen(const char *host, int port, int socket_flags = 0); - - bool is_running() const; - void stop(); - -protected: - bool process_request(Stream &strm, bool last_connection, - bool &connection_close, - std::function setup_request = nullptr); - - size_t keep_alive_max_count_; - size_t payload_max_length_; - -private: - typedef std::vector> Handlers; - - socket_t create_server_socket(const char *host, int port, - int socket_flags) const; - int bind_internal(const char *host, int port, int socket_flags); - bool listen_internal(); - - bool routing(Request &req, Response &res); - bool handle_file_request(Request &req, Response &res); - bool dispatch_request(Request &req, Response &res, Handlers &handlers); - - bool parse_request_line(const char *s, Request &req); - void write_response(Stream &strm, bool last_connection, const Request &req, - Response &res); - - virtual bool read_and_close_socket(socket_t sock); - - std::atomic is_running_; - std::atomic svr_sock_; - std::string base_dir_; - Handlers get_handlers_; - Handlers post_handlers_; - Handlers put_handlers_; - Handlers patch_handlers_; - Handlers delete_handlers_; - Handlers options_handlers_; - Handler error_handler_; - Logger logger_; - - // TODO: Use thread pool... - std::mutex running_threads_mutex_; - int running_threads_; -}; - -class Client { -public: - Client(const char *host, int port = 80, time_t timeout_sec = 300); - - virtual ~Client(); - - virtual bool is_valid() const; - - std::shared_ptr Get(const char *path, Progress progress = nullptr); - std::shared_ptr Get(const char *path, const Headers &headers, - Progress progress = nullptr); - - std::shared_ptr Get(const char *path, - ContentReceiver content_receiver, - Progress progress = nullptr); - std::shared_ptr Get(const char *path, const Headers &headers, - ContentReceiver content_receiver, - Progress progress = nullptr); - - std::shared_ptr Head(const char *path); - std::shared_ptr Head(const char *path, const Headers &headers); - - std::shared_ptr Post(const char *path, const std::string &body, - const char *content_type); - std::shared_ptr Post(const char *path, const Headers &headers, - const std::string &body, - const char *content_type); - - std::shared_ptr Post(const char *path, const Params ¶ms); - std::shared_ptr Post(const char *path, const Headers &headers, - const Params ¶ms); - - std::shared_ptr Put(const char *path, const std::string &body, - const char *content_type); - std::shared_ptr Put(const char *path, const Headers &headers, - const std::string &body, - const char *content_type); - - std::shared_ptr Patch(const char *path, const std::string &body, - const char *content_type); - std::shared_ptr Patch(const char *path, const Headers &headers, - const std::string &body, - const char *content_type); - - std::shared_ptr Delete(const char *path, - const std::string &body = std::string(), - const char *content_type = nullptr); - std::shared_ptr Delete(const char *path, const Headers &headers, - const std::string &body = std::string(), - const char *content_type = nullptr); - - std::shared_ptr Options(const char *path); - std::shared_ptr Options(const char *path, const Headers &headers); - - bool send(Request &req, Response &res); - -protected: - bool process_request(Stream &strm, Request &req, Response &res, - bool &connection_close); - - const std::string host_; - const int port_; - time_t timeout_sec_; - const std::string host_and_port_; - -private: - socket_t create_client_socket() const; - bool read_response_line(Stream &strm, Response &res); - void write_request(Stream &strm, Request &req); - - virtual bool read_and_close_socket(socket_t sock, Request &req, - Response &res); - virtual bool is_ssl() const; -}; - -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -class SSLSocketStream : public Stream { -public: - SSLSocketStream(socket_t sock, SSL *ssl); - virtual ~SSLSocketStream(); - - virtual int read(char *ptr, size_t size); - virtual int write(const char *ptr, size_t size); - virtual int write(const char *ptr); - virtual std::string get_remote_addr() const; - -private: - socket_t sock_; - SSL *ssl_; -}; - -class SSLServer : public Server { -public: - SSLServer(const char *cert_path, const char *private_key_path, - const char *client_ca_cert_file_path = nullptr, - const char *client_ca_cert_dir_path = nullptr); - - virtual ~SSLServer(); - - virtual bool is_valid() const; - -private: - virtual bool read_and_close_socket(socket_t sock); - - SSL_CTX *ctx_; - std::mutex ctx_mutex_; -}; - -class SSLClient : public Client { -public: - SSLClient(const char *host, int port = 443, time_t timeout_sec = 300, - const char *client_cert_path = nullptr, - const char *client_key_path = nullptr); - - virtual ~SSLClient(); - - virtual bool is_valid() const; - - void set_ca_cert_path(const char *ca_ceert_file_path, - const char *ca_cert_dir_path = nullptr); - void enable_server_certificate_verification(bool enabled); - - long get_openssl_verify_result() const; - -private: - virtual bool read_and_close_socket(socket_t sock, Request &req, - Response &res); - virtual bool is_ssl() const; - - bool verify_host(X509 *server_cert) const; - bool verify_host_with_subject_alt_name(X509 *server_cert) const; - bool verify_host_with_common_name(X509 *server_cert) const; - bool check_host_name(const char *pattern, size_t pattern_len) const; - - SSL_CTX *ctx_; - std::mutex ctx_mutex_; - std::vector host_components_; - std::string ca_cert_file_path_; - std::string ca_cert_dir_path_; - bool server_certificate_verification_ = false; - long verify_result_ = 0; -}; -#endif - -/* - * Implementation - */ -namespace detail { - -inline bool is_hex(char c, int &v) { - if (0x20 <= c && isdigit(c)) { - v = c - '0'; - return true; - } else if ('A' <= c && c <= 'F') { - v = c - 'A' + 10; - return true; - } else if ('a' <= c && c <= 'f') { - v = c - 'a' + 10; - return true; - } - return false; -} - -inline bool from_hex_to_i(const std::string &s, size_t i, size_t cnt, - int &val) { - if (i >= s.size()) { return false; } - - val = 0; - for (; cnt; i++, cnt--) { - if (!s[i]) { return false; } - int v = 0; - if (is_hex(s[i], v)) { - val = val * 16 + v; - } else { - return false; - } - } - return true; -} - -inline std::string from_i_to_hex(uint64_t n) { - const char *charset = "0123456789abcdef"; - std::string ret; - do { - ret = charset[n & 15] + ret; - n >>= 4; - } while (n > 0); - return ret; -} - -inline size_t to_utf8(int code, char *buff) { - if (code < 0x0080) { - buff[0] = (code & 0x7F); - return 1; - } else if (code < 0x0800) { - buff[0] = (0xC0 | ((code >> 6) & 0x1F)); - buff[1] = (0x80 | (code & 0x3F)); - return 2; - } else if (code < 0xD800) { - buff[0] = (0xE0 | ((code >> 12) & 0xF)); - buff[1] = (0x80 | ((code >> 6) & 0x3F)); - buff[2] = (0x80 | (code & 0x3F)); - return 3; - } else if (code < 0xE000) { // D800 - DFFF is invalid... - return 0; - } else if (code < 0x10000) { - buff[0] = (0xE0 | ((code >> 12) & 0xF)); - buff[1] = (0x80 | ((code >> 6) & 0x3F)); - buff[2] = (0x80 | (code & 0x3F)); - return 3; - } else if (code < 0x110000) { - buff[0] = (0xF0 | ((code >> 18) & 0x7)); - buff[1] = (0x80 | ((code >> 12) & 0x3F)); - buff[2] = (0x80 | ((code >> 6) & 0x3F)); - buff[3] = (0x80 | (code & 0x3F)); - return 4; - } - - // NOTREACHED - return 0; -} - -// NOTE: This code came up with the following stackoverflow post: -// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c -inline std::string base64_encode(const std::string &in) { - static const auto lookup = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - std::string out; - out.reserve(in.size()); - - int val = 0; - int valb = -6; - - for (uint8_t c : in) { - val = (val << 8) + c; - valb += 8; - while (valb >= 0) { - out.push_back(lookup[(val >> valb) & 0x3F]); - valb -= 6; - } - } - - if (valb > -6) { - out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); - } - - while (out.size() % 4) { - out.push_back('='); - } - - return out; -} - -inline bool is_file(const std::string &path) { - struct stat st; - return stat(path.c_str(), &st) >= 0 && S_ISREG(st.st_mode); -} - -inline bool is_dir(const std::string &path) { - struct stat st; - return stat(path.c_str(), &st) >= 0 && S_ISDIR(st.st_mode); -} - -inline bool is_valid_path(const std::string &path) { - size_t level = 0; - size_t i = 0; - - // Skip slash - while (i < path.size() && path[i] == '/') { - i++; - } - - while (i < path.size()) { - // Read component - auto beg = i; - while (i < path.size() && path[i] != '/') { - i++; - } - - auto len = i - beg; - assert(len > 0); - - if (!path.compare(beg, len, ".")) { - ; - } else if (!path.compare(beg, len, "..")) { - if (level == 0) { return false; } - level--; - } else { - level++; - } - - // Skip slash - while (i < path.size() && path[i] == '/') { - i++; - } - } - - return true; -} - -inline void read_file(const std::string &path, std::string &out) { - std::ifstream fs(path, std::ios_base::binary); - fs.seekg(0, std::ios_base::end); - auto size = fs.tellg(); - fs.seekg(0); - out.resize(static_cast(size)); - fs.read(&out[0], size); -} - -inline std::string file_extension(const std::string &path) { - std::smatch m; - auto pat = std::regex("\\.([a-zA-Z0-9]+)$"); - if (std::regex_search(path, m, pat)) { return m[1].str(); } - return std::string(); -} - -template void split(const char *b, const char *e, char d, Fn fn) { - int i = 0; - int beg = 0; - - while (e ? (b + i != e) : (b[i] != '\0')) { - if (b[i] == d) { - fn(&b[beg], &b[i]); - beg = i + 1; - } - i++; - } - - if (i) { fn(&b[beg], &b[i]); } -} - -// NOTE: until the read size reaches `fixed_buffer_size`, use `fixed_buffer` -// to store data. The call can set memory on stack for performance. -class stream_line_reader { -public: - stream_line_reader(Stream &strm, char *fixed_buffer, size_t fixed_buffer_size) - : strm_(strm), fixed_buffer_(fixed_buffer), - fixed_buffer_size_(fixed_buffer_size) {} - - const char *ptr() const { - if (glowable_buffer_.empty()) { - return fixed_buffer_; - } else { - return glowable_buffer_.data(); - } - } - - size_t size() const { - if (glowable_buffer_.empty()) { - return fixed_buffer_used_size_; - } else { - return glowable_buffer_.size(); - } - } - - bool getline() { - fixed_buffer_used_size_ = 0; - glowable_buffer_.clear(); - - for (size_t i = 0;; i++) { - char byte; - auto n = strm_.read(&byte, 1); - - if (n < 0) { - return false; - } else if (n == 0) { - if (i == 0) { - return false; - } else { - break; - } - } - - append(byte); - - if (byte == '\n') { break; } - } - - return true; - } - -private: - void append(char c) { - if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) { - fixed_buffer_[fixed_buffer_used_size_++] = c; - fixed_buffer_[fixed_buffer_used_size_] = '\0'; - } else { - if (glowable_buffer_.empty()) { - assert(fixed_buffer_[fixed_buffer_used_size_] == '\0'); - glowable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_); - } - glowable_buffer_ += c; - } - } - - Stream &strm_; - char *fixed_buffer_; - const size_t fixed_buffer_size_; - size_t fixed_buffer_used_size_; - std::string glowable_buffer_; -}; - -inline int close_socket(socket_t sock) { -#ifdef _WIN32 - return closesocket(sock); -#else - return close(sock); -#endif -} - -inline int select_read(socket_t sock, time_t sec, time_t usec) { - fd_set fds; - FD_ZERO(&fds); - FD_SET(sock, &fds); - - timeval tv; - tv.tv_sec = static_cast(sec); - tv.tv_usec = static_cast(usec); - - return select(static_cast(sock + 1), &fds, nullptr, nullptr, &tv); -} - -inline bool wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec) { - fd_set fdsr; - FD_ZERO(&fdsr); - FD_SET(sock, &fdsr); - - auto fdsw = fdsr; - auto fdse = fdsr; - - timeval tv; - tv.tv_sec = static_cast(sec); - tv.tv_usec = static_cast(usec); - - if (select(static_cast(sock + 1), &fdsr, &fdsw, &fdse, &tv) < 0) { - return false; - } else if (FD_ISSET(sock, &fdsr) || FD_ISSET(sock, &fdsw)) { - int error = 0; - socklen_t len = sizeof(error); - if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char *)&error, &len) < 0 || - error) { - return false; - } - } else { - return false; - } - - return true; -} - -template -inline bool read_and_close_socket(socket_t sock, size_t keep_alive_max_count, - T callback) { - bool ret = false; - - if (keep_alive_max_count > 0) { - auto count = keep_alive_max_count; - while (count > 0 && - detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND, - CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND) > 0) { - SocketStream strm(sock); - auto last_connection = count == 1; - auto connection_close = false; - - ret = callback(strm, last_connection, connection_close); - if (!ret || connection_close) { break; } - - count--; - } - } else { - SocketStream strm(sock); - auto dummy_connection_close = false; - ret = callback(strm, true, dummy_connection_close); - } - - close_socket(sock); - return ret; -} - -inline int shutdown_socket(socket_t sock) { -#ifdef _WIN32 - return shutdown(sock, SD_BOTH); -#else - return shutdown(sock, SHUT_RDWR); -#endif -} - -template -socket_t create_socket(const char *host, int port, Fn fn, - int socket_flags = 0) { -#ifdef _WIN32 -#define SO_SYNCHRONOUS_NONALERT 0x20 -#define SO_OPENTYPE 0x7008 - - int opt = SO_SYNCHRONOUS_NONALERT; - setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, - sizeof(opt)); -#endif - - // Get address info - struct addrinfo hints; - struct addrinfo *result; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = socket_flags; - hints.ai_protocol = 0; - - auto service = std::to_string(port); - - if (getaddrinfo(host, service.c_str(), &hints, &result)) { - return INVALID_SOCKET; - } - - for (auto rp = result; rp; rp = rp->ai_next) { - // Create a socket -#ifdef _WIN32 - auto sock = WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol, - nullptr, 0, WSA_FLAG_NO_HANDLE_INHERIT); -#else - auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); -#endif - if (sock == INVALID_SOCKET) { continue; } - -#ifndef _WIN32 - if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) { continue; } -#endif - - // Make 'reuse address' option available - int yes = 1; - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes)); -#ifdef SO_REUSEPORT - setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (char *)&yes, sizeof(yes)); -#endif - - // bind or connect - if (fn(sock, *rp)) { - freeaddrinfo(result); - return sock; - } - - close_socket(sock); - } - - freeaddrinfo(result); - return INVALID_SOCKET; -} - -inline void set_nonblocking(socket_t sock, bool nonblocking) { -#ifdef _WIN32 - auto flags = nonblocking ? 1UL : 0UL; - ioctlsocket(sock, FIONBIO, &flags); -#else - auto flags = fcntl(sock, F_GETFL, 0); - fcntl(sock, F_SETFL, - nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK))); -#endif -} - -inline bool is_connection_error() { -#ifdef _WIN32 - return WSAGetLastError() != WSAEWOULDBLOCK; -#else - return errno != EINPROGRESS; -#endif -} - -inline std::string get_remote_addr(socket_t sock) { - struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - - if (!getpeername(sock, (struct sockaddr *)&addr, &len)) { - char ipstr[NI_MAXHOST]; - - if (!getnameinfo((struct sockaddr *)&addr, len, ipstr, sizeof(ipstr), - nullptr, 0, NI_NUMERICHOST)) { - return ipstr; - } - } - - return std::string(); -} - -inline const char *find_content_type(const std::string &path) { - auto ext = file_extension(path); - if (ext == "txt") { - return "text/plain"; - } else if (ext == "html") { - return "text/html"; - } else if (ext == "css") { - return "text/css"; - } else if (ext == "jpeg" || ext == "jpg") { - return "image/jpg"; - } else if (ext == "png") { - return "image/png"; - } else if (ext == "gif") { - return "image/gif"; - } else if (ext == "svg") { - return "image/svg+xml"; - } else if (ext == "ico") { - return "image/x-icon"; - } else if (ext == "json") { - return "application/json"; - } else if (ext == "pdf") { - return "application/pdf"; - } else if (ext == "js") { - return "application/javascript"; - } else if (ext == "xml") { - return "application/xml"; - } else if (ext == "xhtml") { - return "application/xhtml+xml"; - } - return nullptr; -} - -inline const char *status_message(int status) { - switch (status) { - case 200: return "OK"; - case 301: return "Moved Permanently"; - case 302: return "Found"; - case 303: return "See Other"; - case 304: return "Not Modified"; - case 400: return "Bad Request"; - case 403: return "Forbidden"; - case 404: return "Not Found"; - case 413: return "Payload Too Large"; - case 414: return "Request-URI Too Long"; - case 415: return "Unsupported Media Type"; - default: - case 500: return "Internal Server Error"; - } -} - -#ifdef CPPHTTPLIB_ZLIB_SUPPORT -inline bool can_compress(const std::string &content_type) { - return !content_type.find("text/") || content_type == "image/svg+xml" || - content_type == "application/javascript" || - content_type == "application/json" || - content_type == "application/xml" || - content_type == "application/xhtml+xml"; -} - -inline bool compress(std::string &content) { - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - - auto ret = deflateInit2(&strm, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, - Z_DEFAULT_STRATEGY); - if (ret != Z_OK) { return false; } - - strm.avail_in = content.size(); - strm.next_in = (Bytef *)content.data(); - - std::string compressed; - - const auto bufsiz = 16384; - char buff[bufsiz]; - do { - strm.avail_out = bufsiz; - strm.next_out = (Bytef *)buff; - ret = deflate(&strm, Z_FINISH); - assert(ret != Z_STREAM_ERROR); - compressed.append(buff, bufsiz - strm.avail_out); - } while (strm.avail_out == 0); - - assert(ret == Z_STREAM_END); - assert(strm.avail_in == 0); - - content.swap(compressed); - - deflateEnd(&strm); - return true; -} - -class decompressor { -public: - decompressor() { - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - - // 15 is the value of wbits, which should be at the maximum possible value - // to ensure that any gzip stream can be decoded. The offset of 16 specifies - // that the stream to decompress will be formatted with a gzip wrapper. - is_valid_ = inflateInit2(&strm, 16 + 15) == Z_OK; - } - - ~decompressor() { inflateEnd(&strm); } - - bool is_valid() const { return is_valid_; } - - template - bool decompress(const char *data, size_t data_len, T callback) { - int ret = Z_OK; - std::string decompressed; - - // strm.avail_in = content.size(); - // strm.next_in = (Bytef *)content.data(); - strm.avail_in = data_len; - strm.next_in = (Bytef *)data; - - const auto bufsiz = 16384; - char buff[bufsiz]; - do { - strm.avail_out = bufsiz; - strm.next_out = (Bytef *)buff; - - ret = inflate(&strm, Z_NO_FLUSH); - assert(ret != Z_STREAM_ERROR); - switch (ret) { - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_MEM_ERROR: inflateEnd(&strm); return false; - } - - decompressed.append(buff, bufsiz - strm.avail_out); - } while (strm.avail_out == 0); - - if (ret == Z_STREAM_END) { - callback(decompressed.data(), decompressed.size()); - return true; - } - - return false; - } - -private: - bool is_valid_; - z_stream strm; -}; -#endif - -inline bool has_header(const Headers &headers, const char *key) { - return headers.find(key) != headers.end(); -} - -inline const char *get_header_value(const Headers &headers, const char *key, - size_t id = 0, const char *def = nullptr) { - auto it = headers.find(key); - std::advance(it, id); - if (it != headers.end()) { return it->second.c_str(); } - return def; -} - -inline uint64_t get_header_value_uint64(const Headers &headers, const char *key, - int def = 0) { - auto it = headers.find(key); - if (it != headers.end()) { - return std::strtoull(it->second.data(), nullptr, 10); - } - return def; -} - -inline bool read_headers(Stream &strm, Headers &headers) { - static std::regex re(R"((.+?):\s*(.+?)\s*\r\n)"); - - const auto bufsiz = 2048; - char buf[bufsiz]; - - stream_line_reader reader(strm, buf, bufsiz); - - for (;;) { - if (!reader.getline()) { return false; } - if (!strcmp(reader.ptr(), "\r\n")) { break; } - std::cmatch m; - if (std::regex_match(reader.ptr(), m, re)) { - auto key = std::string(m[1]); - auto val = std::string(m[2]); - headers.emplace(key, val); - } - } - - return true; -} - -template -inline bool read_content_with_length(Stream &strm, size_t len, - Progress progress, T callback) { - char buf[CPPHTTPLIB_RECV_BUFSIZ]; - - size_t r = 0; - while (r < len) { - auto n = strm.read(buf, std::min((len - r), CPPHTTPLIB_RECV_BUFSIZ)); - if (n <= 0) { return false; } - - callback(buf, n); - - r += n; - - if (progress) { - if (!progress(r, len)) { return false; } - } - } - - return true; -} - -inline void skip_content_with_length(Stream &strm, size_t len) { - char buf[CPPHTTPLIB_RECV_BUFSIZ]; - size_t r = 0; - while (r < len) { - auto n = strm.read(buf, std::min((len - r), CPPHTTPLIB_RECV_BUFSIZ)); - if (n <= 0) { return; } - r += n; - } -} - -template -inline bool read_content_without_length(Stream &strm, T callback) { - char buf[CPPHTTPLIB_RECV_BUFSIZ]; - for (;;) { - auto n = strm.read(buf, CPPHTTPLIB_RECV_BUFSIZ); - if (n < 0) { - return false; - } else if (n == 0) { - return true; - } - callback(buf, n); - } - - return true; -} - -template -inline bool read_content_chunked(Stream &strm, T callback) { - const auto bufsiz = 16; - char buf[bufsiz]; - - stream_line_reader reader(strm, buf, bufsiz); - - if (!reader.getline()) { return false; } - - auto chunk_len = std::stoi(reader.ptr(), 0, 16); - - while (chunk_len > 0) { - if (!read_content_with_length(strm, chunk_len, nullptr, callback)) { - return false; - } - - if (!reader.getline()) { return false; } - - if (strcmp(reader.ptr(), "\r\n")) { break; } - - if (!reader.getline()) { return false; } - - chunk_len = std::stoi(reader.ptr(), 0, 16); - } - - if (chunk_len == 0) { - // Reader terminator after chunks - if (!reader.getline() || strcmp(reader.ptr(), "\r\n")) return false; - } - - return true; -} - -inline bool is_chunked_transfer_encoding(const Headers &headers) { - return !strcasecmp(get_header_value(headers, "Transfer-Encoding", 0, ""), - "chunked"); -} - -template -bool read_content(Stream &strm, T &x, uint64_t payload_max_length, int &status, - Progress progress, U callback) { - - ContentReceiver out = [&](const char *buf, size_t n) { callback(buf, n); }; - -#ifdef CPPHTTPLIB_ZLIB_SUPPORT - detail::decompressor decompressor; - - if (!decompressor.is_valid()) { - status = 500; - return false; - } - - if (x.get_header_value("Content-Encoding") == "gzip") { - out = [&](const char *buf, size_t n) { - decompressor.decompress( - buf, n, [&](const char *buf, size_t n) { callback(buf, n); }); - }; - } -#else - if (x.get_header_value("Content-Encoding") == "gzip") { - status = 415; - return false; - } -#endif - - auto ret = true; - auto exceed_payload_max_length = false; - - if (is_chunked_transfer_encoding(x.headers)) { - ret = read_content_chunked(strm, out); - } else if (!has_header(x.headers, "Content-Length")) { - ret = read_content_without_length(strm, out); - } else { - auto len = get_header_value_uint64(x.headers, "Content-Length", 0); - if (len > 0) { - if ((len > payload_max_length) || - // For 32-bit platform - (sizeof(size_t) < sizeof(uint64_t) && - len > std::numeric_limits::max())) { - exceed_payload_max_length = true; - skip_content_with_length(strm, len); - ret = false; - } else { - ret = read_content_with_length(strm, len, progress, out); - } - } - } - - if (!ret) { status = exceed_payload_max_length ? 413 : 400; } - - return ret; -} - -template inline void write_headers(Stream &strm, const T &info) { - for (const auto &x : info.headers) { - strm.write_format("%s: %s\r\n", x.first.c_str(), x.second.c_str()); - } - strm.write("\r\n"); -} - -template -inline void write_content_chunked(Stream &strm, const T &x) { - auto chunked_response = !x.has_header("Content-Length"); - uint64_t offset = 0; - auto data_available = true; - while (data_available) { - auto chunk = x.content_producer(offset); - offset += chunk.size(); - data_available = !chunk.empty(); - - // Emit chunked response header and footer for each chunk - if (chunked_response) { - chunk = from_i_to_hex(chunk.size()) + "\r\n" + chunk + "\r\n"; - } - - if (strm.write(chunk.c_str(), chunk.size()) < 0) { - break; // Stop on error - } - } -} - -inline std::string encode_url(const std::string &s) { - std::string result; - - for (auto i = 0; s[i]; i++) { - switch (s[i]) { - case ' ': result += "%20"; break; - case '+': result += "%2B"; break; - case '\r': result += "%0D"; break; - case '\n': result += "%0A"; break; - case '\'': result += "%27"; break; - case ',': result += "%2C"; break; - case ':': result += "%3A"; break; - case ';': result += "%3B"; break; - default: - auto c = static_cast(s[i]); - if (c >= 0x80) { - result += '%'; - char hex[4]; - size_t len = snprintf(hex, sizeof(hex) - 1, "%02X", c); - assert(len == 2); - result.append(hex, len); - } else { - result += s[i]; - } - break; - } - } - - return result; -} - -inline std::string decode_url(const std::string &s) { - std::string result; - - for (size_t i = 0; i < s.size(); i++) { - if (s[i] == '%' && i + 1 < s.size()) { - if (s[i + 1] == 'u') { - int val = 0; - if (from_hex_to_i(s, i + 2, 4, val)) { - // 4 digits Unicode codes - char buff[4]; - size_t len = to_utf8(val, buff); - if (len > 0) { result.append(buff, len); } - i += 5; // 'u0000' - } else { - result += s[i]; - } - } else { - int val = 0; - if (from_hex_to_i(s, i + 1, 2, val)) { - // 2 digits hex codes - result += val; - i += 2; // '00' - } else { - result += s[i]; - } - } - } else if (s[i] == '+') { - result += ' '; - } else { - result += s[i]; - } - } - - return result; -} - -inline void parse_query_text(const std::string &s, Params ¶ms) { - split(&s[0], &s[s.size()], '&', [&](const char *b, const char *e) { - std::string key; - std::string val; - split(b, e, '=', [&](const char *b, const char *e) { - if (key.empty()) { - key.assign(b, e); - } else { - val.assign(b, e); - } - }); - params.emplace(key, decode_url(val)); - }); -} - -inline bool parse_multipart_boundary(const std::string &content_type, - std::string &boundary) { - auto pos = content_type.find("boundary="); - if (pos == std::string::npos) { return false; } - - boundary = content_type.substr(pos + 9); - return true; -} - -inline bool parse_multipart_formdata(const std::string &boundary, - const std::string &body, - MultipartFiles &files) { - static std::string dash = "--"; - static std::string crlf = "\r\n"; - - static std::regex re_content_type("Content-Type: (.*?)", - std::regex_constants::icase); - - static std::regex re_content_disposition( - "Content-Disposition: form-data; name=\"(.*?)\"(?:; filename=\"(.*?)\")?", - std::regex_constants::icase); - - auto dash_boundary = dash + boundary; - - auto pos = body.find(dash_boundary); - if (pos != 0) { return false; } - - pos += dash_boundary.size(); - - auto next_pos = body.find(crlf, pos); - if (next_pos == std::string::npos) { return false; } - - pos = next_pos + crlf.size(); - - while (pos < body.size()) { - next_pos = body.find(crlf, pos); - if (next_pos == std::string::npos) { return false; } - - std::string name; - MultipartFile file; - - auto header = body.substr(pos, (next_pos - pos)); - - while (pos != next_pos) { - std::smatch m; - if (std::regex_match(header, m, re_content_type)) { - file.content_type = m[1]; - } else if (std::regex_match(header, m, re_content_disposition)) { - name = m[1]; - file.filename = m[2]; - } - - pos = next_pos + crlf.size(); - - next_pos = body.find(crlf, pos); - if (next_pos == std::string::npos) { return false; } - - header = body.substr(pos, (next_pos - pos)); - } - - pos = next_pos + crlf.size(); - - next_pos = body.find(crlf + dash_boundary, pos); - - if (next_pos == std::string::npos) { return false; } - - file.offset = pos; - file.length = next_pos - pos; - - pos = next_pos + crlf.size() + dash_boundary.size(); - - next_pos = body.find(crlf, pos); - if (next_pos == std::string::npos) { return false; } - - files.emplace(name, file); - - pos = next_pos + crlf.size(); - } - - return true; -} - -inline std::string to_lower(const char *beg, const char *end) { - std::string out; - auto it = beg; - while (it != end) { - out += ::tolower(*it); - it++; - } - return out; -} - -inline void make_range_header_core(std::string &) {} - -template -inline void make_range_header_core(std::string &field, uint64_t value) { - if (!field.empty()) { field += ", "; } - field += std::to_string(value) + "-"; -} - -template -inline void make_range_header_core(std::string &field, uint64_t value1, - uint64_t value2, Args... args) { - if (!field.empty()) { field += ", "; } - field += std::to_string(value1) + "-" + std::to_string(value2); - make_range_header_core(field, args...); -} - -#ifdef _WIN32 -class WSInit { -public: - WSInit() { - WSADATA wsaData; - WSAStartup(0x0002, &wsaData); - } - - ~WSInit() { WSACleanup(); } -}; - -static WSInit wsinit_; -#endif - -} // namespace detail - -// Header utilities -template -inline std::pair make_range_header(uint64_t value, - Args... args) { - std::string field; - detail::make_range_header_core(field, value, args...); - field.insert(0, "bytes="); - return std::make_pair("Range", field); -} - - -inline std::pair -make_basic_authentication_header(const std::string& username, const std::string& password) { - auto field = "Basic " + detail::base64_encode(username + ":" + password); - return std::make_pair("Authorization", field); -} -// Request implementation -inline bool Request::has_header(const char *key) const { - return detail::has_header(headers, key); -} - -inline std::string Request::get_header_value(const char *key, size_t id) const { - return detail::get_header_value(headers, key, id, ""); -} - -inline size_t Request::get_header_value_count(const char *key) const { - auto r = headers.equal_range(key); - return std::distance(r.first, r.second); -} - -inline void Request::set_header(const char *key, const char *val) { - headers.emplace(key, val); -} - -inline bool Request::has_param(const char *key) const { - return params.find(key) != params.end(); -} - -inline std::string Request::get_param_value(const char *key, size_t id) const { - auto it = params.find(key); - std::advance(it, id); - if (it != params.end()) { return it->second; } - return std::string(); -} - -inline size_t Request::get_param_value_count(const char *key) const { - auto r = params.equal_range(key); - return std::distance(r.first, r.second); -} - -inline bool Request::has_file(const char *key) const { - return files.find(key) != files.end(); -} - -inline MultipartFile Request::get_file_value(const char *key) const { - auto it = files.find(key); - if (it != files.end()) { return it->second; } - return MultipartFile(); -} - -// Response implementation -inline bool Response::has_header(const char *key) const { - return headers.find(key) != headers.end(); -} - -inline std::string Response::get_header_value(const char *key, - size_t id) const { - return detail::get_header_value(headers, key, id, ""); -} - -inline size_t Response::get_header_value_count(const char *key) const { - auto r = headers.equal_range(key); - return std::distance(r.first, r.second); -} - -inline void Response::set_header(const char *key, const char *val) { - headers.emplace(key, val); -} - -inline void Response::set_redirect(const char *url) { - set_header("Location", url); - status = 302; -} - -inline void Response::set_content(const char *s, size_t n, - const char *content_type) { - body.assign(s, n); - set_header("Content-Type", content_type); -} - -inline void Response::set_content(const std::string &s, - const char *content_type) { - body = s; - set_header("Content-Type", content_type); -} - -// Rstream implementation -template -inline void Stream::write_format(const char *fmt, const Args &... args) { - const auto bufsiz = 2048; - char buf[bufsiz]; - -#if defined(_MSC_VER) && _MSC_VER < 1900 - auto n = _snprintf_s(buf, bufsiz, bufsiz - 1, fmt, args...); -#else - auto n = snprintf(buf, bufsiz - 1, fmt, args...); -#endif - if (n > 0) { - if (n >= bufsiz - 1) { - std::vector glowable_buf(bufsiz); - - while (n >= static_cast(glowable_buf.size() - 1)) { - glowable_buf.resize(glowable_buf.size() * 2); -#if defined(_MSC_VER) && _MSC_VER < 1900 - n = _snprintf_s(&glowable_buf[0], glowable_buf.size(), - glowable_buf.size() - 1, fmt, args...); -#else - n = snprintf(&glowable_buf[0], glowable_buf.size() - 1, fmt, args...); -#endif - } - write(&glowable_buf[0], n); - } else { - write(buf, n); - } - } -} - -// Socket stream implementation -inline SocketStream::SocketStream(socket_t sock) : sock_(sock) {} - -inline SocketStream::~SocketStream() {} - -inline int SocketStream::read(char *ptr, size_t size) { - if (detail::select_read(sock_, CPPHTTPLIB_READ_TIMEOUT_SECOND, - CPPHTTPLIB_READ_TIMEOUT_USECOND) > 0) { - return recv(sock_, ptr, static_cast(size), 0); - } - return -1; -} - -inline int SocketStream::write(const char *ptr, size_t size) { - return send(sock_, ptr, static_cast(size), 0); -} - -inline int SocketStream::write(const char *ptr) { - return write(ptr, strlen(ptr)); -} - -inline std::string SocketStream::get_remote_addr() const { - return detail::get_remote_addr(sock_); -} - -// Buffer stream implementation -inline int BufferStream::read(char *ptr, size_t size) { -#if defined(_MSC_VER) && _MSC_VER < 1900 - return static_cast(buffer._Copy_s(ptr, size, size)); -#else - return static_cast(buffer.copy(ptr, size)); -#endif -} - -inline int BufferStream::write(const char *ptr, size_t size) { - buffer.append(ptr, size); - return static_cast(size); -} - -inline int BufferStream::write(const char *ptr) { - size_t size = strlen(ptr); - buffer.append(ptr, size); - return static_cast(size); -} - -inline std::string BufferStream::get_remote_addr() const { return ""; } - -inline const std::string &BufferStream::get_buffer() const { return buffer; } - -// HTTP server implementation -inline Server::Server() - : keep_alive_max_count_(CPPHTTPLIB_KEEPALIVE_MAX_COUNT), - payload_max_length_(CPPHTTPLIB_PAYLOAD_MAX_LENGTH), is_running_(false), - svr_sock_(INVALID_SOCKET), running_threads_(0) { -#ifndef _WIN32 - signal(SIGPIPE, SIG_IGN); -#endif -} - -inline Server::~Server() {} - -inline Server &Server::Get(const char *pattern, Handler handler) { - get_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); - return *this; -} - -inline Server &Server::Post(const char *pattern, Handler handler) { - post_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); - return *this; -} - -inline Server &Server::Put(const char *pattern, Handler handler) { - put_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); - return *this; -} - -inline Server &Server::Patch(const char *pattern, Handler handler) { - patch_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); - return *this; -} - -inline Server &Server::Delete(const char *pattern, Handler handler) { - delete_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); - return *this; -} - -inline Server &Server::Options(const char *pattern, Handler handler) { - options_handlers_.push_back(std::make_pair(std::regex(pattern), handler)); - return *this; -} - -inline bool Server::set_base_dir(const char *path) { - if (detail::is_dir(path)) { - base_dir_ = path; - return true; - } - return false; -} - -inline void Server::set_error_handler(Handler handler) { - error_handler_ = handler; -} - -inline void Server::set_logger(Logger logger) { logger_ = logger; } - -inline void Server::set_keep_alive_max_count(size_t count) { - keep_alive_max_count_ = count; -} - -inline void Server::set_payload_max_length(uint64_t length) { - payload_max_length_ = length; -} - -inline int Server::bind_to_any_port(const char *host, int socket_flags) { - return bind_internal(host, 0, socket_flags); -} - -inline bool Server::listen_after_bind() { return listen_internal(); } - -inline bool Server::listen(const char *host, int port, int socket_flags) { - if (bind_internal(host, port, socket_flags) < 0) return false; - return listen_internal(); -} - -inline bool Server::is_running() const { return is_running_; } - -inline void Server::stop() { - if (is_running_) { - assert(svr_sock_ != INVALID_SOCKET); - std::atomic sock(svr_sock_.exchange(INVALID_SOCKET)); - detail::shutdown_socket(sock); - detail::close_socket(sock); - } -} - -inline bool Server::parse_request_line(const char *s, Request &req) { - static std::regex re("(GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS) " - "(([^?]+)(?:\\?(.+?))?) (HTTP/1\\.[01])\r\n"); - - std::cmatch m; - if (std::regex_match(s, m, re)) { - req.version = std::string(m[5]); - req.method = std::string(m[1]); - req.target = std::string(m[2]); - req.path = detail::decode_url(m[3]); - - // Parse query text - auto len = std::distance(m[4].first, m[4].second); - if (len > 0) { detail::parse_query_text(m[4], req.params); } - - return true; - } - - return false; -} - -inline void Server::write_response(Stream &strm, bool last_connection, - const Request &req, Response &res) { - assert(res.status != -1); - - if (400 <= res.status && error_handler_) { error_handler_(req, res); } - - // Response line - strm.write_format("HTTP/1.1 %d %s\r\n", res.status, - detail::status_message(res.status)); - - // Headers - if (last_connection || req.get_header_value("Connection") == "close") { - res.set_header("Connection", "close"); - } - - if (!last_connection && req.get_header_value("Connection") == "Keep-Alive") { - res.set_header("Connection", "Keep-Alive"); - } - - if (res.body.empty()) { - if (!res.has_header("Content-Length")) { - if (res.content_producer) { - // Streamed response - res.set_header("Transfer-Encoding", "chunked"); - } else { - res.set_header("Content-Length", "0"); - } - } - } else { -#ifdef CPPHTTPLIB_ZLIB_SUPPORT - // TODO: 'Accpet-Encoding' has gzip, not gzip;q=0 - const auto &encodings = req.get_header_value("Accept-Encoding"); - if (encodings.find("gzip") != std::string::npos && - detail::can_compress(res.get_header_value("Content-Type"))) { - if (detail::compress(res.body)) { - res.set_header("Content-Encoding", "gzip"); - } - } -#endif - - if (!res.has_header("Content-Type")) { - res.set_header("Content-Type", "text/plain"); - } - - auto length = std::to_string(res.body.size()); - res.set_header("Content-Length", length.c_str()); - } - - detail::write_headers(strm, res); - - // Body - if (req.method != "HEAD") { - if (!res.body.empty()) { - strm.write(res.body.c_str(), res.body.size()); - } else if (res.content_producer) { - detail::write_content_chunked(strm, res); - } - } - - // Log - if (logger_) { logger_(req, res); } -} - -inline bool Server::handle_file_request(Request &req, Response &res) { - if (!base_dir_.empty() && detail::is_valid_path(req.path)) { - std::string path = base_dir_ + req.path; - - if (!path.empty() && path.back() == '/') { path += "index.html"; } - - if (detail::is_file(path)) { - detail::read_file(path, res.body); - auto type = detail::find_content_type(path); - if (type) { res.set_header("Content-Type", type); } - res.status = 200; - return true; - } - } - - return false; -} - -inline socket_t Server::create_server_socket(const char *host, int port, - int socket_flags) const { - return detail::create_socket( - host, port, - [](socket_t sock, struct addrinfo &ai) -> bool { - if (::bind(sock, ai.ai_addr, static_cast(ai.ai_addrlen))) { - return false; - } - if (::listen(sock, 5)) { // Listen through 5 channels - return false; - } - return true; - }, - socket_flags); -} - -inline int Server::bind_internal(const char *host, int port, int socket_flags) { - if (!is_valid()) { return -1; } - - svr_sock_ = create_server_socket(host, port, socket_flags); - if (svr_sock_ == INVALID_SOCKET) { return -1; } - - if (port == 0) { - struct sockaddr_storage address; - socklen_t len = sizeof(address); - if (getsockname(svr_sock_, reinterpret_cast(&address), - &len) == -1) { - return -1; - } - if (address.ss_family == AF_INET) { - return ntohs(reinterpret_cast(&address)->sin_port); - } else if (address.ss_family == AF_INET6) { - return ntohs( - reinterpret_cast(&address)->sin6_port); - } else { - return -1; - } - } else { - return port; - } -} - -inline bool Server::listen_internal() { - auto ret = true; - - is_running_ = true; - - for (;;) { - if (svr_sock_ == INVALID_SOCKET) { - // The server socket was closed by 'stop' method. - break; - } - - auto val = detail::select_read(svr_sock_, 0, 100000); - - if (val == 0) { // Timeout - continue; - } - - socket_t sock = accept(svr_sock_, nullptr, nullptr); - - if (sock == INVALID_SOCKET) { - if (svr_sock_ != INVALID_SOCKET) { - detail::close_socket(svr_sock_); - ret = false; - } else { - ; // The server socket was closed by user. - } - break; - } - - // TODO: Use thread pool... - std::thread([=]() { - { - std::lock_guard guard(running_threads_mutex_); - running_threads_++; - } - - read_and_close_socket(sock); - - { - std::lock_guard guard(running_threads_mutex_); - running_threads_--; - } - }).detach(); - } - - // TODO: Use thread pool... - for (;;) { - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - std::lock_guard guard(running_threads_mutex_); - if (!running_threads_) { break; } - } - - is_running_ = false; - - return ret; -} - -inline bool Server::routing(Request &req, Response &res) { - if (req.method == "GET" && handle_file_request(req, res)) { return true; } - - if (req.method == "GET" || req.method == "HEAD") { - return dispatch_request(req, res, get_handlers_); - } else if (req.method == "POST") { - return dispatch_request(req, res, post_handlers_); - } else if (req.method == "PUT") { - return dispatch_request(req, res, put_handlers_); - } else if (req.method == "PATCH") { - return dispatch_request(req, res, patch_handlers_); - } else if (req.method == "DELETE") { - return dispatch_request(req, res, delete_handlers_); - } else if (req.method == "OPTIONS") { - return dispatch_request(req, res, options_handlers_); - } - return false; -} - -inline bool Server::dispatch_request(Request &req, Response &res, - Handlers &handlers) { - for (const auto &x : handlers) { - const auto &pattern = x.first; - const auto &handler = x.second; - - if (std::regex_match(req.path, req.matches, pattern)) { - handler(req, res); - return true; - } - } - return false; -} - -inline bool -Server::process_request(Stream &strm, bool last_connection, - bool &connection_close, - std::function setup_request) { - const auto bufsiz = 2048; - char buf[bufsiz]; - - detail::stream_line_reader reader(strm, buf, bufsiz); - - // Connection has been closed on client - if (!reader.getline()) { return false; } - - Request req; - Response res; - - res.version = "HTTP/1.1"; - - // Check if the request URI doesn't exceed the limit - if (reader.size() > CPPHTTPLIB_REQUEST_URI_MAX_LENGTH) { - res.status = 414; - write_response(strm, last_connection, req, res); - return true; - } - - // Request line and headers - if (!parse_request_line(reader.ptr(), req) || - !detail::read_headers(strm, req.headers)) { - res.status = 400; - write_response(strm, last_connection, req, res); - return true; - } - - if (req.get_header_value("Connection") == "close") { - connection_close = true; - } - - req.set_header("REMOTE_ADDR", strm.get_remote_addr().c_str()); - - // Body - if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") { - if (!detail::read_content( - strm, req, payload_max_length_, res.status, Progress(), - [&](const char *buf, size_t n) { req.body.append(buf, n); })) { - write_response(strm, last_connection, req, res); - return true; - } - - const auto &content_type = req.get_header_value("Content-Type"); - - if (!content_type.find("application/x-www-form-urlencoded")) { - detail::parse_query_text(req.body, req.params); - } else if (!content_type.find("multipart/form-data")) { - std::string boundary; - if (!detail::parse_multipart_boundary(content_type, boundary) || - !detail::parse_multipart_formdata(boundary, req.body, req.files)) { - res.status = 400; - write_response(strm, last_connection, req, res); - return true; - } - } - } - - // TODO: Add additional request info - if (setup_request) { setup_request(req); } - - if (routing(req, res)) { - if (res.status == -1) { res.status = 200; } - } else { - res.status = 404; - } - - write_response(strm, last_connection, req, res); - return true; -} - -inline bool Server::is_valid() const { return true; } - -inline bool Server::read_and_close_socket(socket_t sock) { - return detail::read_and_close_socket( - sock, keep_alive_max_count_, - [this](Stream &strm, bool last_connection, bool &connection_close) { - return process_request(strm, last_connection, connection_close); - }); -} - -// HTTP client implementation -inline Client::Client(const char *host, int port, time_t timeout_sec) - : host_(host), port_(port), timeout_sec_(timeout_sec), - host_and_port_(host_ + ":" + std::to_string(port_)) {} - -inline Client::~Client() {} - -inline bool Client::is_valid() const { return true; } - -inline socket_t Client::create_client_socket() const { - return detail::create_socket( - host_.c_str(), port_, [=](socket_t sock, struct addrinfo &ai) -> bool { - detail::set_nonblocking(sock, true); - - auto ret = connect(sock, ai.ai_addr, static_cast(ai.ai_addrlen)); - if (ret < 0) { - if (detail::is_connection_error() || - !detail::wait_until_socket_is_ready(sock, timeout_sec_, 0)) { - detail::close_socket(sock); - return false; - } - } - - detail::set_nonblocking(sock, false); - return true; - }); -} - -inline bool Client::read_response_line(Stream &strm, Response &res) { - const auto bufsiz = 2048; - char buf[bufsiz]; - - detail::stream_line_reader reader(strm, buf, bufsiz); - - if (!reader.getline()) { return false; } - - const static std::regex re("(HTTP/1\\.[01]) (\\d+?) .*\r\n"); - - std::cmatch m; - if (std::regex_match(reader.ptr(), m, re)) { - res.version = std::string(m[1]); - res.status = std::stoi(std::string(m[2])); - } - - return true; -} - -inline bool Client::send(Request &req, Response &res) { - if (req.path.empty()) { return false; } - - auto sock = create_client_socket(); - if (sock == INVALID_SOCKET) { return false; } - - return read_and_close_socket(sock, req, res); -} - -inline void Client::write_request(Stream &strm, Request &req) { - BufferStream bstrm; - - // Request line - auto path = detail::encode_url(req.path); - - bstrm.write_format("%s %s HTTP/1.1\r\n", req.method.c_str(), path.c_str()); - - // Headers - if (!req.has_header("Host")) { - if (is_ssl()) { - if (port_ == 443) { - req.set_header("Host", host_.c_str()); - } else { - req.set_header("Host", host_and_port_.c_str()); - } - } else { - if (port_ == 80) { - req.set_header("Host", host_.c_str()); - } else { - req.set_header("Host", host_and_port_.c_str()); - } - } - } - - if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); } - - if (!req.has_header("User-Agent")) { - req.set_header("User-Agent", "cpp-httplib/0.2"); - } - - // TODO: Support KeepAlive connection - // if (!req.has_header("Connection")) { - req.set_header("Connection", "close"); - // } - - if (req.body.empty()) { - if (req.method == "POST" || req.method == "PUT" || req.method == "PATCH") { - req.set_header("Content-Length", "0"); - } - } else { - if (!req.has_header("Content-Type")) { - req.set_header("Content-Type", "text/plain"); - } - - if (!req.has_header("Content-Length")) { - auto length = std::to_string(req.body.size()); - req.set_header("Content-Length", length.c_str()); - } - } - - detail::write_headers(bstrm, req); - - // Body - if (!req.body.empty()) { bstrm.write(req.body.c_str(), req.body.size()); } - - // Flush buffer - auto &data = bstrm.get_buffer(); - strm.write(data.data(), data.size()); -} - -inline bool Client::process_request(Stream &strm, Request &req, Response &res, - bool &connection_close) { - // Send request - write_request(strm, req); - - // Receive response and headers - if (!read_response_line(strm, res) || - !detail::read_headers(strm, res.headers)) { - return false; - } - - if (res.get_header_value("Connection") == "close" || - res.version == "HTTP/1.0") { - connection_close = true; - } - - // Body - if (req.method != "HEAD") { - ContentReceiver out = [&](const char *buf, size_t n) { - res.body.append(buf, n); - }; - - if (res.content_receiver) { - out = [&](const char *buf, size_t n) { res.content_receiver(buf, n); }; - } - - int dummy_status; - if (!detail::read_content(strm, res, std::numeric_limits::max(), - dummy_status, res.progress, out)) { - return false; - } - } - - return true; -} - -inline bool Client::read_and_close_socket(socket_t sock, Request &req, - Response &res) { - return detail::read_and_close_socket( - sock, 0, - [&](Stream &strm, bool /*last_connection*/, bool &connection_close) { - return process_request(strm, req, res, connection_close); - }); -} - -inline bool Client::is_ssl() const { return false; } - -inline std::shared_ptr Client::Get(const char *path, - Progress progress) { - return Get(path, Headers(), progress); -} - -inline std::shared_ptr -Client::Get(const char *path, const Headers &headers, Progress progress) { - Request req; - req.method = "GET"; - req.path = path; - req.headers = headers; - - auto res = std::make_shared(); - res->progress = progress; - - return send(req, *res) ? res : nullptr; -} - -inline std::shared_ptr Client::Get(const char *path, - ContentReceiver content_receiver, - Progress progress) { - return Get(path, Headers(), content_receiver, progress); -} - -inline std::shared_ptr Client::Get(const char *path, - const Headers &headers, - ContentReceiver content_receiver, - Progress progress) { - Request req; - req.method = "GET"; - req.path = path; - req.headers = headers; - - auto res = std::make_shared(); - res->content_receiver = content_receiver; - res->progress = progress; - - return send(req, *res) ? res : nullptr; -} - -inline std::shared_ptr Client::Head(const char *path) { - return Head(path, Headers()); -} - -inline std::shared_ptr Client::Head(const char *path, - const Headers &headers) { - Request req; - req.method = "HEAD"; - req.headers = headers; - req.path = path; - - auto res = std::make_shared(); - - return send(req, *res) ? res : nullptr; -} - -inline std::shared_ptr Client::Post(const char *path, - const std::string &body, - const char *content_type) { - return Post(path, Headers(), body, content_type); -} - -inline std::shared_ptr Client::Post(const char *path, - const Headers &headers, - const std::string &body, - const char *content_type) { - Request req; - req.method = "POST"; - req.headers = headers; - req.path = path; - - req.headers.emplace("Content-Type", content_type); - req.body = body; - - auto res = std::make_shared(); - - return send(req, *res) ? res : nullptr; -} - -inline std::shared_ptr Client::Post(const char *path, - const Params ¶ms) { - return Post(path, Headers(), params); -} - -inline std::shared_ptr -Client::Post(const char *path, const Headers &headers, const Params ¶ms) { - std::string query; - for (auto it = params.begin(); it != params.end(); ++it) { - if (it != params.begin()) { query += "&"; } - query += it->first; - query += "="; - query += detail::encode_url(it->second); - } - - return Post(path, headers, query, "application/x-www-form-urlencoded"); -} - -inline std::shared_ptr Client::Put(const char *path, - const std::string &body, - const char *content_type) { - return Put(path, Headers(), body, content_type); -} - -inline std::shared_ptr Client::Put(const char *path, - const Headers &headers, - const std::string &body, - const char *content_type) { - Request req; - req.method = "PUT"; - req.headers = headers; - req.path = path; - - req.headers.emplace("Content-Type", content_type); - req.body = body; - - auto res = std::make_shared(); - - return send(req, *res) ? res : nullptr; -} - -inline std::shared_ptr Client::Patch(const char *path, - const std::string &body, - const char *content_type) { - return Patch(path, Headers(), body, content_type); -} - -inline std::shared_ptr Client::Patch(const char *path, - const Headers &headers, - const std::string &body, - const char *content_type) { - Request req; - req.method = "PATCH"; - req.headers = headers; - req.path = path; - - req.headers.emplace("Content-Type", content_type); - req.body = body; - - auto res = std::make_shared(); - - return send(req, *res) ? res : nullptr; -} - -inline std::shared_ptr Client::Delete(const char *path, - const std::string &body, - const char *content_type) { - return Delete(path, Headers(), body, content_type); -} - -inline std::shared_ptr Client::Delete(const char *path, - const Headers &headers, - const std::string &body, - const char *content_type) { - Request req; - req.method = "DELETE"; - req.headers = headers; - req.path = path; - - if (content_type) { req.headers.emplace("Content-Type", content_type); } - req.body = body; - - auto res = std::make_shared(); - - return send(req, *res) ? res : nullptr; -} - -inline std::shared_ptr Client::Options(const char *path) { - return Options(path, Headers()); -} - -inline std::shared_ptr Client::Options(const char *path, - const Headers &headers) { - Request req; - req.method = "OPTIONS"; - req.path = path; - req.headers = headers; - - auto res = std::make_shared(); - - return send(req, *res) ? res : nullptr; -} - -/* - * SSL Implementation - */ -#ifdef CPPHTTPLIB_OPENSSL_SUPPORT -namespace detail { - -template -inline bool -read_and_close_socket_ssl(socket_t sock, size_t keep_alive_max_count, - // TODO: OpenSSL 1.0.2 occasionally crashes... - // The upcoming 1.1.0 is going to be thread safe. - SSL_CTX *ctx, std::mutex &ctx_mutex, - U SSL_connect_or_accept, V setup, T callback) { - SSL *ssl = nullptr; - { - std::lock_guard guard(ctx_mutex); - ssl = SSL_new(ctx); - } - - if (!ssl) { - close_socket(sock); - return false; - } - - auto bio = BIO_new_socket(sock, BIO_NOCLOSE); - SSL_set_bio(ssl, bio, bio); - - if (!setup(ssl)) { - SSL_shutdown(ssl); - { - std::lock_guard guard(ctx_mutex); - SSL_free(ssl); - } - - close_socket(sock); - return false; - } - - bool ret = false; - - if (SSL_connect_or_accept(ssl) == 1) { - if (keep_alive_max_count > 0) { - auto count = keep_alive_max_count; - while (count > 0 && - detail::select_read(sock, CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND, - CPPHTTPLIB_KEEPALIVE_TIMEOUT_USECOND) > 0) { - SSLSocketStream strm(sock, ssl); - auto last_connection = count == 1; - auto connection_close = false; - - ret = callback(ssl, strm, last_connection, connection_close); - if (!ret || connection_close) { break; } - - count--; - } - } else { - SSLSocketStream strm(sock, ssl); - auto dummy_connection_close = false; - ret = callback(ssl, strm, true, dummy_connection_close); - } - } - - SSL_shutdown(ssl); - { - std::lock_guard guard(ctx_mutex); - SSL_free(ssl); - } - - close_socket(sock); - - return ret; -} - -class SSLInit { -public: - SSLInit() { - SSL_load_error_strings(); - SSL_library_init(); - } - - ~SSLInit() { ERR_free_strings(); } -}; - -static SSLInit sslinit_; - -} // namespace detail - -// SSL socket stream implementation -inline SSLSocketStream::SSLSocketStream(socket_t sock, SSL *ssl) - : sock_(sock), ssl_(ssl) {} - -inline SSLSocketStream::~SSLSocketStream() {} - -inline int SSLSocketStream::read(char *ptr, size_t size) { - if (SSL_pending(ssl_) > 0 || - detail::select_read(sock_, CPPHTTPLIB_READ_TIMEOUT_SECOND, - CPPHTTPLIB_READ_TIMEOUT_USECOND) > 0) { - return SSL_read(ssl_, ptr, size); - } - return -1; -} - -inline int SSLSocketStream::write(const char *ptr, size_t size) { - return SSL_write(ssl_, ptr, size); -} - -inline int SSLSocketStream::write(const char *ptr) { - return write(ptr, strlen(ptr)); -} - -inline std::string SSLSocketStream::get_remote_addr() const { - return detail::get_remote_addr(sock_); -} - -// SSL HTTP server implementation -inline SSLServer::SSLServer(const char *cert_path, const char *private_key_path, - const char *client_ca_cert_file_path, - const char *client_ca_cert_dir_path) { - ctx_ = SSL_CTX_new(SSLv23_server_method()); - - if (ctx_) { - SSL_CTX_set_options(ctx_, - SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | - SSL_OP_NO_COMPRESSION | - SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); - - // auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); - // SSL_CTX_set_tmp_ecdh(ctx_, ecdh); - // EC_KEY_free(ecdh); - - if (SSL_CTX_use_certificate_chain_file(ctx_, cert_path) != 1 || - SSL_CTX_use_PrivateKey_file(ctx_, private_key_path, SSL_FILETYPE_PEM) != - 1) { - SSL_CTX_free(ctx_); - ctx_ = nullptr; - } else if (client_ca_cert_file_path || client_ca_cert_dir_path) { - // if (client_ca_cert_file_path) { - // auto list = SSL_load_client_CA_file(client_ca_cert_file_path); - // SSL_CTX_set_client_CA_list(ctx_, list); - // } - - SSL_CTX_load_verify_locations(ctx_, client_ca_cert_file_path, - client_ca_cert_dir_path); - - SSL_CTX_set_verify( - ctx_, - SSL_VERIFY_PEER | - SSL_VERIFY_FAIL_IF_NO_PEER_CERT, // SSL_VERIFY_CLIENT_ONCE, - nullptr); - } - } -} - -inline SSLServer::~SSLServer() { - if (ctx_) { SSL_CTX_free(ctx_); } -} - -inline bool SSLServer::is_valid() const { return ctx_; } - -inline bool SSLServer::read_and_close_socket(socket_t sock) { - return detail::read_and_close_socket_ssl( - sock, keep_alive_max_count_, ctx_, ctx_mutex_, SSL_accept, - [](SSL * /*ssl*/) { return true; }, - [this](SSL *ssl, Stream &strm, bool last_connection, - bool &connection_close) { - return process_request(strm, last_connection, connection_close, - [&](Request &req) { req.ssl = ssl; }); - }); -} - -// SSL HTTP client implementation -inline SSLClient::SSLClient(const char *host, int port, time_t timeout_sec, - const char *client_cert_path, - const char *client_key_path) - : Client(host, port, timeout_sec) { - ctx_ = SSL_CTX_new(SSLv23_client_method()); - - detail::split(&host_[0], &host_[host_.size()], '.', - [&](const char *b, const char *e) { - host_components_.emplace_back(std::string(b, e)); - }); - if (client_cert_path && client_key_path) { - if (SSL_CTX_use_certificate_file(ctx_, client_cert_path, - SSL_FILETYPE_PEM) != 1 || - SSL_CTX_use_PrivateKey_file(ctx_, client_key_path, SSL_FILETYPE_PEM) != - 1) { - SSL_CTX_free(ctx_); - ctx_ = nullptr; - } - } -} - -inline SSLClient::~SSLClient() { - if (ctx_) { SSL_CTX_free(ctx_); } -} - -inline bool SSLClient::is_valid() const { return ctx_; } - -inline void SSLClient::set_ca_cert_path(const char *ca_cert_file_path, - const char *ca_cert_dir_path) { - if (ca_cert_file_path) { ca_cert_file_path_ = ca_cert_file_path; } - if (ca_cert_dir_path) { ca_cert_dir_path_ = ca_cert_dir_path; } -} - -inline void SSLClient::enable_server_certificate_verification(bool enabled) { - server_certificate_verification_ = enabled; -} - -inline long SSLClient::get_openssl_verify_result() const { - return verify_result_; -} - -inline bool SSLClient::read_and_close_socket(socket_t sock, Request &req, - Response &res) { - - return is_valid() && - detail::read_and_close_socket_ssl( - sock, 0, ctx_, ctx_mutex_, - [&](SSL *ssl) { - if (ca_cert_file_path_.empty()) { - SSL_CTX_set_verify(ctx_, SSL_VERIFY_NONE, nullptr); - } else { - if (!SSL_CTX_load_verify_locations( - ctx_, ca_cert_file_path_.c_str(), nullptr)) { - return false; - } - SSL_CTX_set_verify(ctx_, SSL_VERIFY_PEER, nullptr); - } - - if (SSL_connect(ssl) != 1) { return false; } - - if (server_certificate_verification_) { - verify_result_ = SSL_get_verify_result(ssl); - - if (verify_result_ != X509_V_OK) { return false; } - - auto server_cert = SSL_get_peer_certificate(ssl); - - if (server_cert == nullptr) { return false; } - - if (!verify_host(server_cert)) { - X509_free(server_cert); - return false; - } - X509_free(server_cert); - } - - return true; - }, - [&](SSL *ssl) { - SSL_set_tlsext_host_name(ssl, host_.c_str()); - return true; - }, - [&](SSL * /*ssl*/, Stream &strm, bool /*last_connection*/, - bool &connection_close) { - return process_request(strm, req, res, connection_close); - }); -} - -inline bool SSLClient::is_ssl() const { return true; } - -inline bool SSLClient::verify_host(X509 *server_cert) const { - /* Quote from RFC2818 section 3.1 "Server Identity" - - If a subjectAltName extension of type dNSName is present, that MUST - be used as the identity. Otherwise, the (most specific) Common Name - field in the Subject field of the certificate MUST be used. Although - the use of the Common Name is existing practice, it is deprecated and - Certification Authorities are encouraged to use the dNSName instead. - - Matching is performed using the matching rules specified by - [RFC2459]. If more than one identity of a given type is present in - the certificate (e.g., more than one dNSName name, a match in any one - of the set is considered acceptable.) Names may contain the wildcard - character * which is considered to match any single domain name - component or component fragment. E.g., *.a.com matches foo.a.com but - not bar.foo.a.com. f*.com matches foo.com but not bar.com. - - In some cases, the URI is specified as an IP address rather than a - hostname. In this case, the iPAddress subjectAltName must be present - in the certificate and must exactly match the IP in the URI. - - */ - return verify_host_with_subject_alt_name(server_cert) || - verify_host_with_common_name(server_cert); -} - -inline bool -SSLClient::verify_host_with_subject_alt_name(X509 *server_cert) const { - auto ret = false; - - auto type = GEN_DNS; - - struct in6_addr addr6; - struct in_addr addr; - size_t addr_len = 0; - - if (inet_pton(AF_INET6, host_.c_str(), &addr6)) { - type = GEN_IPADD; - addr_len = sizeof(struct in6_addr); - } else if (inet_pton(AF_INET, host_.c_str(), &addr)) { - type = GEN_IPADD; - addr_len = sizeof(struct in_addr); - } - - auto alt_names = static_cast( - X509_get_ext_d2i(server_cert, NID_subject_alt_name, nullptr, nullptr)); - - if (alt_names) { - auto dsn_matched = false; - auto ip_mached = false; - - auto count = sk_GENERAL_NAME_num(alt_names); - - for (auto i = 0; i < count && !dsn_matched; i++) { - auto val = sk_GENERAL_NAME_value(alt_names, i); - if (val->type == type) { - auto name = (const char *)ASN1_STRING_get0_data(val->d.ia5); - auto name_len = (size_t)ASN1_STRING_length(val->d.ia5); - - if (strlen(name) == name_len) { - switch (type) { - case GEN_DNS: dsn_matched = check_host_name(name, name_len); break; - - case GEN_IPADD: - if (!memcmp(&addr6, name, addr_len) || - !memcmp(&addr, name, addr_len)) { - ip_mached = true; - } - break; - } - } - } - } - - if (dsn_matched || ip_mached) { ret = true; } - } - - GENERAL_NAMES_free((STACK_OF(GENERAL_NAME) *)alt_names); - - return ret; -} - -inline bool SSLClient::verify_host_with_common_name(X509 *server_cert) const { - const auto subject_name = X509_get_subject_name(server_cert); - - if (subject_name != nullptr) { - char name[BUFSIZ]; - auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName, - name, sizeof(name)); - - if (name_len != -1) { return check_host_name(name, name_len); } - } - - return false; -} - -inline bool SSLClient::check_host_name(const char *pattern, - size_t pattern_len) const { - if (host_.size() == pattern_len && host_ == pattern) { return true; } - - // Wildcard match - // https://bugs.launchpad.net/ubuntu/+source/firefox-3.0/+bug/376484 - std::vector pattern_components; - detail::split(&pattern[0], &pattern[pattern_len], '.', - [&](const char *b, const char *e) { - pattern_components.emplace_back(std::string(b, e)); - }); - - if (host_components_.size() != pattern_components.size()) { return false; } - - auto itr = pattern_components.begin(); - for (const auto &h : host_components_) { - auto &p = *itr; - if (p != h && p != "*") { - auto partial_match = (p.size() > 0 && p[p.size() - 1] == '*' && - !p.compare(0, p.size() - 1, h)); - if (!partial_match) { return false; } - } - ++itr; - } - - return true; -} -#endif - -} // namespace httplib - -#endif // CPPHTTPLIB_HTTPLIB_H diff --git a/attic/root/thirdparty/json/LICENSE.MIT b/attic/root/thirdparty/json/LICENSE.MIT deleted file mode 100644 index 00599afe6..000000000 --- a/attic/root/thirdparty/json/LICENSE.MIT +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2013-2017 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. diff --git a/attic/root/thirdparty/json/README.md b/attic/root/thirdparty/json/README.md deleted file mode 100644 index 918c2567e..000000000 --- a/attic/root/thirdparty/json/README.md +++ /dev/null @@ -1,1123 +0,0 @@ -[![JSON for Modern C++](https://raw.githubusercontent.com/nlohmann/json/master/doc/json.gif)](https://github.com/nlohmann/json/releases) - -[![Build Status](https://travis-ci.org/nlohmann/json.svg?branch=master)](https://travis-ci.org/nlohmann/json) -[![Build Status](https://ci.appveyor.com/api/projects/status/1acb366xfyg3qybk/branch/develop?svg=true)](https://ci.appveyor.com/project/nlohmann/json) -[![Coverage Status](https://img.shields.io/coveralls/nlohmann/json.svg)](https://coveralls.io/r/nlohmann/json) -[![Coverity Scan Build Status](https://scan.coverity.com/projects/5550/badge.svg)](https://scan.coverity.com/projects/nlohmann-json) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/f3732b3327e34358a0e9d1fe9f661f08)](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade) -[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) -[![Documentation](https://img.shields.io/badge/docs-doxygen-blue.svg)](http://nlohmann.github.io/json) -[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT) -[![GitHub Releases](https://img.shields.io/github/release/nlohmann/json.svg)](https://github.com/nlohmann/json/releases) -[![GitHub Issues](https://img.shields.io/github/issues/nlohmann/json.svg)](http://github.com/nlohmann/json/issues) -[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/nlohmann/json.svg)](http://isitmaintained.com/project/nlohmann/json "Average time to resolve an issue") -[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/289/badge)](https://bestpractices.coreinfrastructure.org/projects/289) - -- [Design goals](#design-goals) -- [Integration](#integration) -- [Examples](#examples) - - [JSON as first-class data type](#json-as-first-class-data-type) - - [Serialization / Deserialization](#serialization--deserialization) - - [STL-like access](#stl-like-access) - - [Conversion from STL containers](#conversion-from-stl-containers) - - [JSON Pointer and JSON Patch](#json-pointer-and-json-patch) - - [JSON Merge Patch](#json-merge-patch) - - [Implicit conversions](#implicit-conversions) - - [Conversions to/from arbitrary types](#arbitrary-types-conversions) - - [Binary formats (CBOR, MessagePack, and UBJSON)](#binary-formats-cbor-messagepack-and-ubjson) -- [Supported compilers](#supported-compilers) -- [License](#license) -- [Contact](#contact) -- [Thanks](#thanks) -- [Used third-party tools](#used-third-party-tools) -- [Projects using JSON for Modern C++](#projects-using-json-for-modern-c) -- [Notes](#notes) -- [Execute unit tests](#execute-unit-tests) - -## Design goals - -There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals: - -- **Intuitive syntax**. In languages such as Python, JSON feels like a first class data type. We used all the operator magic of modern C++ to achieve the same feeling in your code. Check out the [examples below](#examples) and you'll know what I mean. - -- **Trivial integration**. Our whole code consists of a single header file [`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp). That's it. No library, no subproject, no dependencies, no complex build system. The class is written in vanilla C++11. All in all, everything should require no adjustment of your compiler flags or project settings. - -- **Serious testing**. Our class is heavily [unit-tested](https://github.com/nlohmann/json/tree/develop/test/src) and covers [100%](https://coveralls.io/r/nlohmann/json) of the code, including all exceptional behavior. Furthermore, we checked with [Valgrind](http://valgrind.org) and the [Clang Sanitizers](https://clang.llvm.org/docs/index.html) that there are no memory leaks. [Google OSS-Fuzz](https://github.com/google/oss-fuzz/tree/master/projects/json) additionally runs fuzz tests agains all parsers 24/7, effectively executing billions of tests so far. To maintain high quality, the project is following the [Core Infrastructure Initiative (CII) best practices](https://bestpractices.coreinfrastructure.org/projects/289). - -Other aspects were not so important to us: - -- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs. - -- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set. - -See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information. - - -## Integration - -[`json.hpp`](https://github.com/nlohmann/json/blob/develop/single_include/nlohmann/json.hpp) is the single required file in `single_include/nlohmann` or [released here](https://github.com/nlohmann/json/releases). You need to add - -```cpp -#include - -// for convenience -using json = nlohmann::json; -``` - -to the files you want to process JSON and set the necessary switches to enable C++11 (e.g., `-std=c++11` for GCC and Clang). - -You can further use file [`include/nlohmann/json_fwd.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/json_fwd.hpp) for forward-declarations. The installation of json_fwd.hpp (as part of cmake's install step), can be achieved by setting `-DJSON_MultipleHeaders=ON`. - -### Package Managers - -:beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`. - -If you are using the [Meson Build System](http://mesonbuild.com), then you can wrap this repository as a subproject. - -If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `jsonformoderncpp/x.y.z@vthiery/stable` to your `conanfile.py`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/vthiery/conan-jsonformoderncpp/issues) if you experience problems with the packages. - -If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the `nlohmann_json` package. Please see the [spack project](https://github.com/spack/spack) for any issues regarding the packaging. - -If you are using [hunter](https://github.com/ruslo/hunter/) on your project for external dependencies, then you can use the [nlohmann_json package](https://docs.hunter.sh/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging. - -If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo install nlohmann/json`. Please file issues [here](https://github.com/LoopPerfect/buckaroo-recipes/issues/new?title=nlohmann/nlohmann/json). - -If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging. - -If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). - -If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open). - -## Examples - -Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). - -### JSON as first-class data type - -Here are some examples to give you an idea how to use the class. - -Assume you want to create the JSON object - -```json -{ - "pi": 3.141, - "happy": true, - "name": "Niels", - "nothing": null, - "answer": { - "everything": 42 - }, - "list": [1, 0, 2], - "object": { - "currency": "USD", - "value": 42.99 - } -} -``` - -With this library, you could write: - -```cpp -// create an empty structure (null) -json j; - -// add a number that is stored as double (note the implicit conversion of j to an object) -j["pi"] = 3.141; - -// add a Boolean that is stored as bool -j["happy"] = true; - -// add a string that is stored as std::string -j["name"] = "Niels"; - -// add another null object by passing nullptr -j["nothing"] = nullptr; - -// add an object inside the object -j["answer"]["everything"] = 42; - -// add an array that is stored as std::vector (using an initializer list) -j["list"] = { 1, 0, 2 }; - -// add another object (using an initializer list of pairs) -j["object"] = { {"currency", "USD"}, {"value", 42.99} }; - -// instead, you could also write (which looks very similar to the JSON above) -json j2 = { - {"pi", 3.141}, - {"happy", true}, - {"name", "Niels"}, - {"nothing", nullptr}, - {"answer", { - {"everything", 42} - }}, - {"list", {1, 0, 2}}, - {"object", { - {"currency", "USD"}, - {"value", 42.99} - }} -}; -``` - -Note that in all these cases, you never need to "tell" the compiler which JSON value type you want to use. If you want to be explicit or express some edge cases, the functions [`json::array`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa80485befaffcadaa39965494e0b4d2e.html#aa80485befaffcadaa39965494e0b4d2e) and [`json::object`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa13f7c0615867542ce80337cbcf13ada.html#aa13f7c0615867542ce80337cbcf13ada) will help: - -```cpp -// a way to express the empty array [] -json empty_array_explicit = json::array(); - -// ways to express the empty object {} -json empty_object_implicit = json({}); -json empty_object_explicit = json::object(); - -// a way to express an _array_ of key/value pairs [["currency", "USD"], ["value", 42.99]] -json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} }); -``` - -### Serialization / Deserialization - -#### To/from strings - -You can create a JSON value (deserialization) by appending `_json` to a string literal: - -```cpp -// create object from string literal -json j = "{ \"happy\": true, \"pi\": 3.141 }"_json; - -// or even nicer with a raw string literal -auto j2 = R"( - { - "happy": true, - "pi": 3.141 - } -)"_json; -``` - -Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object. - -The above example can also be expressed explicitly using [`json::parse()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_aa9676414f2e36383c4b181fe856aa3c0.html#aa9676414f2e36383c4b181fe856aa3c0): - -```cpp -// parse explicitly -auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }"); -``` - -You can also get a string representation of a JSON value (serialize): - -```cpp -// explicit conversion to string -std::string s = j.dump(); // {\"happy\":true,\"pi\":3.141} - -// serialization with pretty printing -// pass in the amount of spaces to indent -std::cout << j.dump(4) << std::endl; -// { -// "happy": true, -// "pi": 3.141 -// } -``` - -Note the difference between serialization and assignment: - -```cpp -// store a string in a JSON value -json j_string = "this is a string"; - -// retrieve the string value (implicit JSON to std::string conversion) -std::string cpp_string = j_string; -// retrieve the string value (explicit JSON to std::string conversion) -auto cpp_string2 = j_string.get(); - -// retrieve the serialized value (explicit JSON serialization) -std::string serialized_string = j_string.dump(); - -// output of original string -std::cout << cpp_string << " == " << cpp_string2 << " == " << j_string.get() << '\n'; -// output of serialized value -std::cout << j_string << " == " << serialized_string << std::endl; -``` - -[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) always returns the serialized value, and [`.get()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a16f9445f7629f634221a42b967cdcd43.html#a16f9445f7629f634221a42b967cdcd43) returns the originally stored string value. - -Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) may throw an exception. - -#### To/from streams (e.g. files, string streams) - -You can also use streams to serialize and deserialize: - -```cpp -// deserialize from standard input -json j; -std::cin >> j; - -// serialize to standard output -std::cout << j; - -// the setw manipulator was overloaded to set the indentation for pretty printing -std::cout << std::setw(4) << j << std::endl; -``` - -These operators work for any subclasses of `std::istream` or `std::ostream`. Here is the same example with files: - -```cpp -// read a JSON file -std::ifstream i("file.json"); -json j; -i >> j; - -// write prettified JSON to another file -std::ofstream o("pretty.json"); -o << std::setw(4) << j << std::endl; -``` - -Please note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use. - -#### Read from iterator range - -You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector`: - -```cpp -std::vector v = {'t', 'r', 'u', 'e'}; -json j = json::parse(v.begin(), v.end()); -``` - -You may leave the iterators for the range [begin, end): - -```cpp -std::vector v = {'t', 'r', 'u', 'e'}; -json j = json::parse(v); -``` - -#### SAX interface - -The library uses a SAX-like interface with the following functions: - -```cpp -// called when null is parsed -bool null(); - -// called when a boolean is parsed; value is passed -bool boolean(bool val); - -// called when a signed or unsigned integer number is parsed; value is passed -bool number_integer(number_integer_t val); -bool number_unsigned(number_unsigned_t val); - -// called when a floating-point number is parsed; value and original string is passed -bool number_float(number_float_t val, const string_t& s); - -// called when a string is parsed; value is passed and can be safely moved away -bool string(string_t& val); - -// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known) -bool start_object(std::size_t elements); -bool end_object(); -bool start_array(std::size_t elements); -bool end_array(); -// called when an object key is parsed; value is passed and can be safely moved away -bool key(string_t& val); - -// called when a parse error occurs; byte position, the last token, and an exception is passed -bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex); -``` - -The return value of each function determines whether parsing should proceed. - -To implement your own SAX handler, proceed as follows: - -1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax` as base class, but you can also use any class where the functions described above are implemented and public. -2. Create an object of your SAX interface class, e.g. `my_sax`. -3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface. - -Note the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp). - - -### STL-like access - -We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirement. - -```cpp -// create an array using push_back -json j; -j.push_back("s_arbitraryByte"); -j.push_back(1); -j.push_back(true); - -// also use emplace_back -j.emplace_back(1.78); - -// iterate the array -for (json::iterator it = j.begin(); it != j.end(); ++it) { - std::cout << *it << '\n'; -} - -// range-based for -for (auto& element : j) { - std::cout << element << '\n'; -} - -// getter/setter -const std::string tmp = j[0]; -j[1] = 42; -bool s_arbitraryByte = j.at(2); - -// comparison -j == "[\"s_arbitraryByte\", 1, true]"_json; // true - -// other stuff -j.size(); // 3 entries -j.empty(); // false -j.type(); // json::value_t::array -j.clear(); // the array is empty again - -// convenience type checkers -j.is_null(); -j.is_boolean(); -j.is_number(); -j.is_object(); -j.is_array(); -j.is_string(); - -// create an object -json o; -o["s_arbitraryByte"] = 23; -o["bar"] = false; -o["baz"] = 3.141; - -// also use emplace -o.emplace("weather", "sunny"); - -// special iterator member functions for objects -for (json::iterator it = o.begin(); it != o.end(); ++it) { - std::cout << it.key() << " : " << it.value() << "\n"; -} - -// find an entry -if (o.find("s_arbitraryByte") != o.end()) { - // there is an entry with key "s_arbitraryByte" -} - -// or simpler using count() -int foo_present = o.count("s_arbitraryByte"); // 1 -int fob_present = o.count("fob"); // 0 - -// delete an entry -o.erase("s_arbitraryByte"); -``` - - -### Conversion from STL containers - -Any sequence container (`std::array`, `std::vector`, `std::deque`, `std::forward_list`, `std::list`) whose values can be used to construct JSON values (e.g., integers, floating point numbers, Booleans, string types, or again STL containers described in this section) can be used to create a JSON array. The same holds for similar associative containers (`std::set`, `std::multiset`, `std::unordered_set`, `std::unordered_multiset`), but in these cases the order of the elements of the array depends on how the elements are ordered in the respective STL container. - -```cpp -std::vector c_vector {1, 2, 3, 4}; -json j_vec(c_vector); -// [1, 2, 3, 4] - -std::deque c_deque {1.2, 2.3, 3.4, 5.6}; -json j_deque(c_deque); -// [1.2, 2.3, 3.4, 5.6] - -std::list c_list {true, true, false, true}; -json j_list(c_list); -// [true, true, false, true] - -std::forward_list c_flist {12345678909876, 23456789098765, 34567890987654, 45678909876543}; -json j_flist(c_flist); -// [12345678909876, 23456789098765, 34567890987654, 45678909876543] - -std::array c_array {{1, 2, 3, 4}}; -json j_array(c_array); -// [1, 2, 3, 4] - -std::set c_set {"one", "two", "three", "four", "one"}; -json j_set(c_set); // only one entry for "one" is used -// ["four", "one", "three", "two"] - -std::unordered_set c_uset {"one", "two", "three", "four", "one"}; -json j_uset(c_uset); // only one entry for "one" is used -// maybe ["two", "three", "four", "one"] - -std::multiset c_mset {"one", "two", "one", "four"}; -json j_mset(c_mset); // both entries for "one" are used -// maybe ["one", "two", "one", "four"] - -std::unordered_multiset c_umset {"one", "two", "one", "four"}; -json j_umset(c_umset); // both entries for "one" are used -// maybe ["one", "two", "one", "four"] -``` - -Likewise, any associative key-value containers (`std::map`, `std::multimap`, `std::unordered_map`, `std::unordered_multimap`) whose keys can construct an `std::string` and whose values can be used to construct JSON values (see examples above) can be used to create a JSON object. Note that in case of multimaps only one key is used in the JSON object and the value depends on the internal order of the STL container. - -```cpp -std::map c_map { {"one", 1}, {"two", 2}, {"three", 3} }; -json j_map(c_map); -// {"one": 1, "three": 3, "two": 2 } - -std::unordered_map c_umap { {"one", 1.2}, {"two", 2.3}, {"three", 3.4} }; -json j_umap(c_umap); -// {"one": 1.2, "two": 2.3, "three": 3.4} - -std::multimap c_mmap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; -json j_mmap(c_mmap); // only one entry for key "three" is used -// maybe {"one": true, "two": true, "three": true} - -std::unordered_multimap c_ummap { {"one", true}, {"two", true}, {"three", false}, {"three", true} }; -json j_ummap(c_ummap); // only one entry for key "three" is used -// maybe {"one": true, "two": true, "three": true} -``` - -### JSON Pointer and JSON Patch - -The library supports **JSON Pointer** ([RFC 6901](https://tools.ietf.org/html/rfc6901)) as alternative means to address structured values. On top of this, **JSON Patch** ([RFC 6902](https://tools.ietf.org/html/rfc6902)) allows to describe differences between two JSON values - effectively allowing patch and diff operations known from Unix. - -```cpp -// a JSON value -json j_original = R"({ - "baz": ["one", "two", "three"], - "s_arbitraryByte": "bar" -})"_json; - -// access members with a JSON pointer (RFC 6901) -j_original["/baz/1"_json_pointer]; -// "two" - -// a JSON patch (RFC 6902) -json j_patch = R"([ - { "op": "replace", "path": "/baz", "value": "boo" }, - { "op": "add", "path": "/hello", "value": ["world"] }, - { "op": "remove", "path": "/s_arbitraryByte"} -])"_json; - -// apply the patch -json j_result = j_original.patch(j_patch); -// { -// "baz": "boo", -// "hello": ["world"] -// } - -// calculate a JSON patch from two JSON values -json::diff(j_result, j_original); -// [ -// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, -// { "op": "remove","path": "/hello" }, -// { "op": "add", "path": "/s_arbitraryByte", "value": "bar" } -// ] -``` - -### JSON Merge Patch - -The library supports **JSON Merge Patch** ([RFC 7386](https://tools.ietf.org/html/rfc7386)) as a patch format. Instead of using JSON Pointer (see above) to specify values to be manipulated, it describes the changes using a syntax that closely mimics the document being modified. - -```cpp -// a JSON value -json j_document = R"({ - "a": "b", - "c": { - "d": "e", - "f": "g" - } -})"_json; - -// a patch -json j_patch = R"({ - "a":"z", - "c": { - "f": null - } -})"_json; - -// apply the patch -j_original.merge_patch(j_patch); -// { -// "a": "z", -// "c": { -// "d": "e" -// } -// } -``` - -### Implicit conversions - -The type of the JSON object is determined automatically by the expression to store. Likewise, the stored value is implicitly converted. - -```cpp -// strings -std::string s1 = "Hello, world!"; -json js = s1; -std::string s2 = js; - -// Booleans -bool b1 = true; -json jb = b1; -bool b2 = jb; - -// numbers -int i = 42; -json jn = i; -double f = jn; - -// etc. -``` - -You can also explicitly ask for the value: - -```cpp -std::string vs = js.get(); -bool vb = jb.get(); -int vi = jn.get(); - -// etc. -``` - -Note that `char` types are not automatically converted to JSON strings, but to integer numbers. A conversion to a string must be specified explicitly: - -```cpp -char ch = 'A'; // ASCII value 65 -json j_default = ch; // stores integer number 65 -json j_string = std::string(1, ch); // stores string "A" -``` - -### Arbitrary types conversions - -Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines: - -```cpp -namespace ns { - // a simple struct to model a person - struct person { - std::string name; - std::string address; - int age; - }; -} - -ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60}; - -// convert to JSON: copy each value into the JSON object -json j; -j["name"] = p.name; -j["address"] = p.address; -j["age"] = p.age; - -// ... - -// convert from JSON: copy each value from the JSON object -ns::person p { - j["name"].get(), - j["address"].get(), - j["age"].get() -}; -``` - -It works, but that's quite a lot of boilerplate... Fortunately, there's a better way: - -```cpp -// create a person -ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60}; - -// conversion: person -> json -json j = p; - -std::cout << j << std::endl; -// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"} - -// conversion: json -> person -ns::person p2 = j; - -// that's it -assert(p == p2); -``` - -#### Basic usage - -To make this work with one of your types, you only need to provide two functions: - -```cpp -using nlohmann::json; - -namespace ns { - void to_json(json& j, const person& p) { - j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}}; - } - - void from_json(const json& j, person& p) { - p.name = j.at("name").get(); - p.address = j.at("address").get(); - p.age = j.at("age").get(); - } -} // namespace ns -``` - -That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called. -Likewise, when calling `get()`, the `from_json` method will be called. - -Some important things: - -* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). -* Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use the implicit conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. -* When using `get()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) -* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. -* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get();` instead. -* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. -* Be careful with the definition order of the `from_json`/`to_json` functions: If a type `B` has a member of type `A`, you **MUST** define `to_json(A)` before `to_json(B)`. Look at [issue 561](https://github.com/nlohmann/json/issues/561) for more details. - - -#### How do I convert third-party types? - -This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: - -The library uses **JSON Serializers** to convert types to json. -The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)). - -It is implemented like this (simplified): - -```cpp -template -struct adl_serializer { - static void to_json(json& j, const T& value) { - // calls the "to_json" method in T's namespace - } - - static void from_json(const json& j, T& value) { - // same thing, but with the "from_json" method - } -}; -``` - -This serializer works fine when you have control over the type's namespace. However, what about `boost::optional` or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`... - -To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example: - -```cpp -// partial specialization (full specialization works too) -namespace nlohmann { - template - struct adl_serializer> { - static void to_json(json& j, const boost::optional& opt) { - if (opt == boost::none) { - j = nullptr; - } else { - j = *opt; // this will call adl_serializer::to_json which will - // find the free function to_json in T's namespace! - } - } - - static void from_json(const json& j, boost::optional& opt) { - if (j.is_null()) { - opt = boost::none; - } else { - opt = j.get(); // same as above, but with - // adl_serializer::from_json - } - } - }; -} -``` - -#### How can I use `get()` for non-default constructible/non-copyable types? - -There is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload: - -```cpp -struct move_only_type { - move_only_type() = delete; - move_only_type(int ii): i(ii) {} - move_only_type(const move_only_type&) = delete; - move_only_type(move_only_type&&) = default; - - int i; -}; - -namespace nlohmann { - template <> - struct adl_serializer { - // note: the return type is no longer 'void', and the method only takes - // one argument - static move_only_type from_json(const json& j) { - return {j.get()}; - } - - // Here's the catch! You must provide a to_json method! Otherwise you - // will not be able to convert move_only_type to json, since you fully - // specialized adl_serializer on that type - static void to_json(json& j, move_only_type t) { - j = t.i; - } - }; -} -``` - -#### Can I write my own serializer? (Advanced use) - -Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/test/src/unit-udt.cpp) in the test suite, to see a few examples. - -If you write your own serializer, you'll need to do a few things: - -- use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`) -- use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods -- use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL - -Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL. - -```cpp -// You should use void as a second template argument -// if you don't need compile-time checks on T -template::type> -struct less_than_32_serializer { - template - static void to_json(BasicJsonType& j, T value) { - // we want to use ADL, and call the correct to_json overload - using nlohmann::to_json; // this method is called by adl_serializer, - // this is where the magic happens - to_json(j, value); - } - - template - static void from_json(const BasicJsonType& j, T& value) { - // same thing here - using nlohmann::from_json; - from_json(j, value); - } -}; -``` - -Be **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention: - -```cpp -template -struct bad_serializer -{ - template - static void to_json(BasicJsonType& j, const T& value) { - // this calls BasicJsonType::json_serializer::to_json(j, value); - // if BasicJsonType::json_serializer == bad_serializer ... oops! - j = value; - } - - template - static void to_json(const BasicJsonType& j, T& value) { - // this calls BasicJsonType::json_serializer::from_json(j, value); - // if BasicJsonType::json_serializer == bad_serializer ... oops! - value = j.template get(); // oops! - } -}; -``` - -### Binary formats (CBOR, MessagePack, and UBJSON) - -Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [CBOR](http://cbor.io) (Concise Binary Object Representation), [MessagePack](http://msgpack.org), and [UBJSON](http://ubjson.org) (Universal Binary JSON Specification) to efficiently encode JSON values to byte vectors and to decode such vectors. - -```cpp -// create a JSON value -json j = R"({"compact": true, "schema": 0})"_json; - -// serialize to CBOR -std::vector v_cbor = json::to_cbor(j); - -// 0xA2, 0x67, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xF5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00 - -// roundtrip -json j_from_cbor = json::from_cbor(v_cbor); - -// serialize to MessagePack -std::vector v_msgpack = json::to_msgpack(j); - -// 0x82, 0xA7, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0xC3, 0xA6, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x00 - -// roundtrip -json j_from_msgpack = json::from_msgpack(v_msgpack); - -// serialize to UBJSON -std::vector v_ubjson = json::to_ubjson(j); - -// 0x7B, 0x69, 0x07, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x63, 0x74, 0x54, 0x69, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6D, 0x61, 0x69, 0x00, 0x7D - -// roundtrip -json j_from_ubjson = json::from_ubjson(v_ubjson); -``` - - -## Supported compilers - -Though it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: - -- GCC 4.9 - 8.2 (and possibly later) -- Clang 3.4 - 6.1 (and possibly later) -- Intel C++ Compiler 17.0.2 (and possibly later) -- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) -- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) - -I would be happy to learn about other compilers/versions. - -Please note: - -- GCC 4.8 does not work because of two bugs ([55817](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55817) and [57824](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57824)) in the C++11 support. Note there is a [pull request](https://github.com/nlohmann/json/pull/212) to fix some of the issues. -- Android defaults to using very old compilers and C++ libraries. To fix this, add the following to your `Application.mk`. This will switch to the LLVM C++ library, the Clang compiler, and enable C++11 and other features disabled by default. - - ``` - APP_STL := c++_shared - NDK_TOOLCHAIN_VERSION := clang3.6 - APP_CPPFLAGS += -frtti -fexceptions - ``` - - The code compiles successfully with [Android NDK](https://developer.android.com/ndk/index.html?hl=ml), Revision 9 - 11 (and possibly later) and [CrystaX's Android NDK](https://www.crystax.net/en/android/ndk) version 10. - -- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). - -- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case. - -The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json) and [AppVeyor](https://ci.appveyor.com/project/nlohmann/json): - -| Compiler | Operating System | Version String | -|-----------------|------------------------------|----------------| -| GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 | -| GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 | -| GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 | -| GCC 7.3.0 | Ubuntu 14.04.1 LTS | g++-7 (Ubuntu 7.3.0-21ubuntu1~14.04) 7.3.0 | -| GCC 7.3.0 | Windows Server 2012 R2 (x64) | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0 | -| GCC 8.1.0 | Ubuntu 14.04.1 LTS | g++-8 (Ubuntu 8.1.0-5ubuntu1~14.04) 8.1.0 | -| Clang 3.5.0 | Ubuntu 14.04.1 LTS | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0) | -| Clang 3.6.2 | Ubuntu 14.04.1 LTS | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) (based on LLVM 3.6.2) | -| Clang 3.7.1 | Ubuntu 14.04.1 LTS | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) (based on LLVM 3.7.1) | -| Clang 3.8.0 | Ubuntu 14.04.1 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) | -| Clang 3.9.1 | Ubuntu 14.04.1 LTS | clang version 3.9.1-4ubuntu3~14.04.3 (tags/RELEASE_391/rc2) | -| Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) | -| Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) | -| Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) | -| Clang Xcode 6.4 | OSX 10.10.5 | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) | -| Clang Xcode 7.3 | OSX 10.11.6 | Apple LLVM version 7.3.0 (clang-703.0.31) | -| Clang Xcode 8.0 | OSX 10.11.6 | Apple LLVM version 8.0.0 (clang-800.0.38) | -| Clang Xcode 8.1 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) | -| Clang Xcode 8.2 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) | -| Clang Xcode 8.3 | OSX 10.11.6 | Apple LLVM version 8.1.0 (clang-802.0.38) | -| Clang Xcode 9.0 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.37) | -| Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) | -| Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) | -| Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) | -| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | -| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 | - -## License - - - -The class is licensed under the [MIT License](http://opensource.org/licenses/MIT): - -Copyright © 2013-2018 [Niels Lohmann](http://nlohmann.me) - -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. - -* * * - -The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2008-2009 [Björn Hoehrmann](http://bjoern.hoehrmann.de/) - -The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](http://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](http://florian.loitsch.com/) - -## Contact - -If you have questions regarding the library, I would like to invite you to [open an issue at GitHub](https://github.com/nlohmann/json/issues/new). Please describe your request, problem, or question as detailed as possible, and also mention the version of the library you are using as well as the version of your compiler and operating system. Opening an issue at GitHub allows other users and contributors to this library to collaborate. For instance, I have little experience with MSVC, and most issues in this regard have been solved by a growing community. If you have a look at the [closed issues](https://github.com/nlohmann/json/issues?q=is%3Aissue+is%3Aclosed), you will see that we react quite timely in most cases. - -Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc). - -## Security - -[Commits by Niels Lohmann](https://github.com/nlohmann/json/commits) and [releases](https://github.com/nlohmann/json/releases) are signed with this [PGP Key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69). - -## Thanks - -I deeply appreciate the help of the following people. - -![Contributors](https://raw.githubusercontent.com/nlohmann/json/develop/doc/avatars.png) - -- [Teemperor](https://github.com/Teemperor) implemented CMake support and lcov integration, realized escape and Unicode handling in the string parser, and fixed the JSON serialization. -- [elliotgoodrich](https://github.com/elliotgoodrich) fixed an issue with double deletion in the iterator classes. -- [kirkshoop](https://github.com/kirkshoop) made the iterators of the class composable to other libraries. -- [wancw](https://github.com/wanwc) fixed a bug that hindered the class to compile with Clang. -- Tomas Åblad found a bug in the iterator implementation. -- [Joshua C. Randall](https://github.com/jrandall) fixed a bug in the floating-point serialization. -- [Aaron Burghardt](https://github.com/aburgh) implemented code to parse streams incrementally. Furthermore, he greatly improved the parser class by allowing the definition of a filter function to discard undesired elements while parsing. -- [Daniel Kopeček](https://github.com/dkopecek) fixed a bug in the compilation with GCC 5.0. -- [Florian Weber](https://github.com/Florianjw) fixed a bug in and improved the performance of the comparison operators. -- [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping. -- [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums. -- [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio. -- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types. -- [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling. -- [dariomt](https://github.com/dariomt) fixed some typos in the examples. -- [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation. -- [Colin Hirsch](https://github.com/ColinH) took care of a small namespace issue. -- [Huu Nguyen](https://github.com/whoshuu) correct a variable name in the documentation. -- [Silverweed](https://github.com/silverweed) overloaded `parse()` to accept an rvalue reference. -- [dariomt](https://github.com/dariomt) fixed a subtlety in MSVC type support and implemented the `get_ref()` function to get a reference to stored values. -- [ZahlGraf](https://github.com/ZahlGraf) added a workaround that allows compilation using Android NDK. -- [whackashoe](https://github.com/whackashoe) replaced a function that was marked as unsafe by Visual Studio. -- [406345](https://github.com/406345) fixed two small warnings. -- [Glen Fernandes](https://github.com/glenfe) noted a potential portability problem in the `has_mapped_type` function. -- [Corbin Hughes](https://github.com/nibroc) fixed some typos in the contribution guidelines. -- [twelsby](https://github.com/twelsby) fixed the array subscript operator, an issue that failed the MSVC build, and floating-point parsing/dumping. He further added support for unsigned integer numbers and implemented better roundtrip support for parsed numbers. -- [Volker Diels-Grabsch](https://github.com/vog) fixed a link in the README file. -- [msm-](https://github.com/msm-) added support for American Fuzzy Lop. -- [Annihil](https://github.com/Annihil) fixed an example in the README file. -- [Themercee](https://github.com/Themercee) noted a wrong URL in the README file. -- [Lv Zheng](https://github.com/lv-zheng) fixed a namespace issue with `int64_t` and `uint64_t`. -- [abc100m](https://github.com/abc100m) analyzed the issues with GCC 4.8 and proposed a [partial solution](https://github.com/nlohmann/json/pull/212). -- [zewt](https://github.com/zewt) added useful notes to the README file about Android. -- [Róbert Márki](https://github.com/robertmrk) added a fix to use move iterators and improved the integration via CMake. -- [Chris Kitching](https://github.com/ChrisKitching) cleaned up the CMake files. -- [Tom Needham](https://github.com/06needhamt) fixed a subtle bug with MSVC 2015 which was also proposed by [Michael K.](https://github.com/Epidal). -- [Mário Feroldi](https://github.com/thelostt) fixed a small typo. -- [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release. -- [Damien](https://github.com/dtoma) fixed one of the last conversion warnings. -- [Thomas Braun](https://github.com/t-b) fixed a warning in a test case. -- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types and split the single header file into smaller chunks. -- [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation. -- [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`. -- [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion. -- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix. -- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. -- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function. -- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing. -- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan. -- [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning. -- [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check. -- [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one. -- [Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers. -- [Jonathan Lee](https://github.com/vjon) fixed an example in the README file. -- [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types. -- [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio. -- [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types. -- [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example. -- [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite. -- [ukhegg](https://github.com/ukhegg) found proposed an improvement for the examples section. -- [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README. -- [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s. -- [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation. -- [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings. -- [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible. -- [ftillier](https://github.com/ftillier) fixed a compiler warning. -- [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped. -- [Fytch](https://github.com/Fytch) found a bug in the documentation. -- [Jay Sistar](https://github.com/Type1J) implemented a Meson build description. -- [Henry Lee](https://github.com/HenryRLee) fixed a warning in ICC and improved the iterator implementation. -- [Vincent Thiery](https://github.com/vthiery) maintains a package for the Conan package manager. -- [Steffen](https://github.com/koemeet) fixed a potential issue with MSVC and `std::min`. -- [Mike Tzou](https://github.com/Chocobo1) fixed some typos. -- [amrcode](https://github.com/amrcode) noted a misleading documentation about comparison of floats. -- [Oleg Endo](https://github.com/olegendo) reduced the memory consumption by replacing `` with ``. -- [dan-42](https://github.com/dan-42) cleaned up the CMake files to simplify including/reusing of the library. -- [Nikita Ofitserov](https://github.com/himikof) allowed for moving values from initializer lists. -- [Greg Hurrell](https://github.com/wincent) fixed a typo. -- [Dmitry Kukovinets](https://github.com/DmitryKuk) fixed a typo. -- [kbthomp1](https://github.com/kbthomp1) fixed an issue related to the Intel OSX compiler. -- [Markus Werle](https://github.com/daixtrose) fixed a typo. -- [WebProdPP](https://github.com/WebProdPP) fixed a subtle error in a precondition check. -- [Alex](https://github.com/leha-bot) noted an error in a code sample. -- [Tom de Geus](https://github.com/tdegeus) reported some warnings with ICC and helped fixing them. -- [Perry Kundert](https://github.com/pjkundert) simplified reading from input streams. -- [Sonu Lohani](https://github.com/sonulohani) fixed a small compilation error. -- [Jamie Seward](https://github.com/jseward) fixed all MSVC warnings. -- [Nate Vargas](https://github.com/eld00d) added a Doxygen tag file. -- [pvleuven](https://github.com/pvleuven) helped fixing a warning in ICC. -- [Pavel](https://github.com/crea7or) helped fixing some warnings in MSVC. -- [Jamie Seward](https://github.com/jseward) avoided unnecessary string copies in `find()` and `count()`. -- [Mitja](https://github.com/Itja) fixed some typos. -- [Jorrit Wronski](https://github.com/jowr) updated the Hunter package links. -- [Matthias Möller](https://github.com/TinyTinni) added a `.natvis` for the MSVC debug view. -- [bogemic](https://github.com/bogemic) fixed some C++17 deprecation warnings. -- [Eren Okka](https://github.com/erengy) fixed some MSVC warnings. -- [abolz](https://github.com/abolz) integrated the Grisu2 algorithm for proper floating-point formatting, allowing more roundtrip checks to succeed. -- [Vadim Evard](https://github.com/Pipeliner) fixed a Markdown issue in the README. -- [zerodefect](https://github.com/zerodefect) fixed a compiler warning. -- [Kert](https://github.com/kaidokert) allowed to template the string type in the serialization and added the possibility to override the exceptional behavior. -- [mark-99](https://github.com/mark-99) helped fixing an ICC error. -- [Patrik Huber](https://github.com/patrikhuber) fixed links in the README file. -- [johnfb](https://github.com/johnfb) found a bug in the implementation of CBOR's indefinite length strings. -- [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager. -- [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise. -- [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback. -- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type. -- [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake. -- [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io). -- [Carlos O'Ryan](https://github.com/coryan) fixed a typo. -- [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section. -- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines -- [Jan Schöppach](https://github.com/dns13) fixed a typo. -- [martin-mfg](https://github.com/martin-mfg) fixed a typo. -- [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`. -- [agrianius](https://github.com/agrianius) added code to use alternative string implementations. -- [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function. -- [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com). -- [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode. -- [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases. -- [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library. -- [thyu](https://github.com/thyu) fixed a compiler warning. - -Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. - - -## Used third-party tools - -The library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot! - -- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file -- [**American fuzzy lop**](http://lcamtuf.coredump.cx/afl/) for fuzz testing -- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows -- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code identation -- [**Catch**](https://github.com/philsquared/Catch) for the unit tests -- [**Clang**](http://clang.llvm.org) for compilation with code sanitizers -- [**Cmake**](https://cmake.org) for build automation -- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) -- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) -- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json) -- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis -- [**Doxygen**](http://www.stack.nl/~dimitri/doxygen/) to generate [documentation](https://nlohmann.github.io/json/) -- [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages -- [**GitHub Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md) -- [**Google Benchmark**](https://github.com/google/benchmark) to implement the benchmarks -- [**libFuzzer**](http://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz -- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library ([project repository](https://github.com/google/oss-fuzz/tree/master/projects/json)) -- [**Probot**](https://probot.github.io) for automating maintainer tasks such as closing stale issues, requesting missing information, or detecting toxic comments. -- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox) -- [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS -- [**Valgrind**](http://valgrind.org) to check for correct memory management -- [**Wandbox**](http://melpon.org/wandbox) for [online examples](https://wandbox.org/permlink/TarF5pPn9NtHQjhf) - - -## Projects using JSON for Modern C++ - -The library is currently used in Apple macOS Sierra and iOS 10. I am not sure what they are using the library for, but I am happy that it runs on so many devices. - - -## Notes - -- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726). -- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. -- The library supports **Unicode input** as follows: - - Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](http://rfc7159.net/rfc7159#rfc.section.8.1). - - Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse or serialization errors. - - [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library. - - Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors. - - The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs. -- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag. -- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by an `abort()` call. -- By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc7159.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) ([integration](https://github.com/nlohmann/json/issues/546#issuecomment-304447518)) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map) ([integration](https://github.com/nlohmann/json/issues/485#issuecomment-333652309)). - - -## Execute unit tests - -To compile and run the tests, you need to execute - -```sh -$ mkdir build -$ cd build -$ cmake .. -$ cmake --build . -$ ctest --output-on-failure -``` - -For more information, have a look at the file [.travis.yml](https://github.com/nlohmann/json/blob/master/.travis.yml). diff --git a/attic/root/thirdparty/json/json.hpp b/attic/root/thirdparty/json/json.hpp deleted file mode 100644 index b80386f3f..000000000 --- a/attic/root/thirdparty/json/json.hpp +++ /dev/null @@ -1,18912 +0,0 @@ -/* - __ _____ _____ _____ - __| | __| | | | JSON for Modern C++ -| | |__ | | | | | | version 3.2.0 -|_____|_____|_____|_|___| https://github.com/nlohmann/json - -Licensed under the MIT License . -SPDX-License-Identifier: MIT -Copyright (c) 2013-2018 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. -*/ - -#ifndef NLOHMANN_JSON_HPP -#define NLOHMANN_JSON_HPP - -#define NLOHMANN_JSON_VERSION_MAJOR 3 -#define NLOHMANN_JSON_VERSION_MINOR 2 -#define NLOHMANN_JSON_VERSION_PATCH 0 - -#include // all_of, find, for_each -#include // assert -#include // and, not, or -#include // nullptr_t, ptrdiff_t, size_t -#include // hash, less -#include // initializer_list -#include // istream, ostream -#include // iterator_traits, random_access_iterator_tag -#include // accumulate -#include // string, stoi, to_string -#include // declval, forward, move, pair, swap - -// #include -#ifndef NLOHMANN_JSON_FWD_HPP -#define NLOHMANN_JSON_FWD_HPP - -#include // int64_t, uint64_t -#include // map -#include // allocator -#include // string -#include // vector - -/*! -@brief namespace for Niels Lohmann -@see https://github.com/nlohmann -@since version 1.0.0 -*/ -namespace nlohmann -{ -/*! -@brief default JSONSerializer template argument - -This serializer ignores the template arguments and uses ADL -([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) -for serialization. -*/ -template -struct adl_serializer; - -template class ObjectType = - std::map, - template class ArrayType = std::vector, - class StringType = std::string, class BooleanType = bool, - class NumberIntegerType = std::int64_t, - class NumberUnsignedType = std::uint64_t, - class NumberFloatType = double, - template class AllocatorType = std::allocator, - template class JSONSerializer = - adl_serializer> -class basic_json; - -/*! -@brief JSON Pointer - -A JSON pointer defines a string syntax for identifying a specific value -within a JSON document. It can be used with functions `at` and -`operator[]`. Furthermore, JSON pointers are the base for JSON patches. - -@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) - -@since version 2.0.0 -*/ -template -class json_pointer; - -/*! -@brief default JSON class - -This type is the default specialization of the @ref basic_json class which -uses the standard template types. - -@since version 1.0.0 -*/ -using json = basic_json<>; -} - -#endif - -// #include - - -// This file contains all internal macro definitions -// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them - -// exclude unsupported compilers -#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) - #if defined(__clang__) - #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 - #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) - #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 - #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" - #endif - #endif -#endif - -// disable float-equal warnings on GCC/clang -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wfloat-equal" -#endif - -// disable documentation warnings on clang -#if defined(__clang__) - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdocumentation" -#endif - -// allow for portable deprecation warnings -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_DEPRECATED __attribute__((deprecated)) -#elif defined(_MSC_VER) - #define JSON_DEPRECATED __declspec(deprecated) -#else - #define JSON_DEPRECATED -#endif - -// allow to disable exceptions -#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) - #define JSON_THROW(exception) throw exception - #define JSON_TRY try - #define JSON_CATCH(exception) catch(exception) - #define JSON_INTERNAL_CATCH(exception) catch(exception) -#else - #define JSON_THROW(exception) std::abort() - #define JSON_TRY if(true) - #define JSON_CATCH(exception) if(false) - #define JSON_INTERNAL_CATCH(exception) if(false) -#endif - -// override exception macros -#if defined(JSON_THROW_USER) - #undef JSON_THROW - #define JSON_THROW JSON_THROW_USER -#endif -#if defined(JSON_TRY_USER) - #undef JSON_TRY - #define JSON_TRY JSON_TRY_USER -#endif -#if defined(JSON_CATCH_USER) - #undef JSON_CATCH - #define JSON_CATCH JSON_CATCH_USER - #define JSON_INTERNAL_CATCH JSON_CATCH_USER -#endif -#if defined(JSON_INTERNAL_CATCH_USER) - #undef JSON_INTERNAL_CATCH - #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER -#endif - -// manual branch prediction -#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) - #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) - #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) -#else - #define JSON_LIKELY(x) x - #define JSON_UNLIKELY(x) x -#endif - -// C++ language standard detection -#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 - #define JSON_HAS_CPP_17 - #define JSON_HAS_CPP_14 -#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) - #define JSON_HAS_CPP_14 -#endif - -// Ugly macros to avoid uglier copy-paste when specializing basic_json. They -// may be removed in the future once the class is split. - -#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ - template class ObjectType, \ - template class ArrayType, \ - class StringType, class BooleanType, class NumberIntegerType, \ - class NumberUnsignedType, class NumberFloatType, \ - template class AllocatorType, \ - template class JSONSerializer> - -#define NLOHMANN_BASIC_JSON_TPL \ - basic_json - -/*! -@brief Helper to determine whether there's a key_type for T. - -This helper is used to tell associative containers apart from other containers -such as sequence containers. For instance, `std::map` passes the test as it -contains a `mapped_type`, whereas `std::vector` fails the test. - -@sa http://stackoverflow.com/a/7728728/266378 -@since version 1.0.0, overworked in version 2.0.6 -*/ -#define NLOHMANN_JSON_HAS_HELPER(type) \ - template struct has_##type { \ - private: \ - template \ - static int detect(U &&); \ - static void detect(...); \ - public: \ - static constexpr bool value = \ - std::is_integral()))>::value; \ - } - -// #include - - -#include // not -#include // size_t -#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type - -namespace nlohmann -{ -namespace detail -{ -// alias templates to reduce boilerplate -template -using enable_if_t = typename std::enable_if::type; - -template -using uncvref_t = typename std::remove_cv::type>::type; - -// implementation of C++14 index_sequence and affiliates -// source: https://stackoverflow.com/a/32223343 -template -struct index_sequence -{ - using type = index_sequence; - using value_type = std::size_t; - static constexpr std::size_t size() noexcept - { - return sizeof...(Ints); - } -}; - -template -struct merge_and_renumber; - -template -struct merge_and_renumber, index_sequence> - : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; - -template -struct make_index_sequence - : merge_and_renumber < typename make_index_sequence < N / 2 >::type, - typename make_index_sequence < N - N / 2 >::type > {}; - -template<> struct make_index_sequence<0> : index_sequence<> {}; -template<> struct make_index_sequence<1> : index_sequence<0> {}; - -template -using index_sequence_for = make_index_sequence; - -/* -Implementation of two C++17 constructs: conjunction, negation. This is needed -to avoid evaluating all the traits in a condition - -For example: not std::is_same::value and has_value_type::value -will not compile when T = void (on MSVC at least). Whereas -conjunction>, has_value_type>::value will -stop evaluating if negation<...>::value == false - -Please note that those constructs must be used with caution, since symbols can -become very long quickly (which can slow down compilation and cause MSVC -internal compiler errors). Only use it when you have to (see example ahead). -*/ -template struct conjunction : std::true_type {}; -template struct conjunction : B1 {}; -template -struct conjunction : std::conditional, B1>::type {}; - -template struct negation : std::integral_constant {}; - -// dispatch utility (taken from ranges-v3) -template struct priority_tag : priority_tag < N - 1 > {}; -template<> struct priority_tag<0> {}; - -// taken from ranges-v3 -template -struct static_const -{ - static constexpr T value{}; -}; - -template -constexpr T static_const::value; -} -} - -// #include - - -#include // not -#include // numeric_limits -#include // false_type, is_constructible, is_integral, is_same, true_type -#include // declval - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -/*! -@brief detail namespace with internal helper functions - -This namespace collects functions that should not be exposed, -implementations of some @ref basic_json methods, and meta-programming helpers. - -@since version 2.1.0 -*/ -namespace detail -{ -///////////// -// helpers // -///////////// - -template struct is_basic_json : std::false_type {}; - -NLOHMANN_BASIC_JSON_TPL_DECLARATION -struct is_basic_json : std::true_type {}; - -//////////////////////// -// has_/is_ functions // -//////////////////////// - -// source: https://stackoverflow.com/a/37193089/4116453 - -template -struct is_complete_type : std::false_type {}; - -template -struct is_complete_type : std::true_type {}; - -NLOHMANN_JSON_HAS_HELPER(mapped_type); -NLOHMANN_JSON_HAS_HELPER(key_type); -NLOHMANN_JSON_HAS_HELPER(value_type); -NLOHMANN_JSON_HAS_HELPER(iterator); - -template -struct is_compatible_object_type_impl : std::false_type {}; - -template -struct is_compatible_object_type_impl -{ - static constexpr auto value = - std::is_constructible::value and - std::is_constructible::value; -}; - -template -struct is_compatible_string_type_impl : std::false_type {}; - -template -struct is_compatible_string_type_impl -{ - static constexpr auto value = - std::is_same::value and - std::is_constructible::value; -}; - -template -struct is_compatible_object_type -{ - static auto constexpr value = is_compatible_object_type_impl < - conjunction>, - has_mapped_type, - has_key_type>::value, - typename BasicJsonType::object_t, CompatibleObjectType >::value; -}; - -template -struct is_compatible_string_type -{ - static auto constexpr value = is_compatible_string_type_impl < - conjunction>, - has_value_type>::value, - typename BasicJsonType::string_t, CompatibleStringType >::value; -}; - -template -struct is_basic_json_nested_type -{ - static auto constexpr value = std::is_same::value or - std::is_same::value or - std::is_same::value or - std::is_same::value; -}; - -template -struct is_compatible_array_type -{ - static auto constexpr value = - conjunction>, - negation>, - negation>, - negation>, - has_value_type, - has_iterator>::value; -}; - -template -struct is_compatible_integer_type_impl : std::false_type {}; - -template -struct is_compatible_integer_type_impl -{ - // is there an assert somewhere on overflows? - using RealLimits = std::numeric_limits; - using CompatibleLimits = std::numeric_limits; - - static constexpr auto value = - std::is_constructible::value and - CompatibleLimits::is_integer and - RealLimits::is_signed == CompatibleLimits::is_signed; -}; - -template -struct is_compatible_integer_type -{ - static constexpr auto value = - is_compatible_integer_type_impl < - std::is_integral::value and - not std::is_same::value, - RealIntegerType, CompatibleNumberIntegerType > ::value; -}; - -// trait checking if JSONSerializer::from_json(json const&, udt&) exists -template -struct has_from_json -{ - private: - // also check the return type of from_json - template::from_json( - std::declval(), std::declval()))>::value>> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if JSONSerializer::from_json(json const&) exists -// this overload is used for non-default-constructible user-defined-types -template -struct has_non_default_from_json -{ - private: - template < - typename U, - typename = enable_if_t::from_json(std::declval()))>::value >> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -// This trait checks if BasicJsonType::json_serializer::to_json exists -template -struct has_to_json -{ - private: - template::to_json( - std::declval(), std::declval()))> - static int detect(U&&); - static void detect(...); - - public: - static constexpr bool value = std::is_integral>()))>::value; -}; - -template -struct is_compatible_complete_type -{ - static constexpr bool value = - not std::is_base_of::value and - not is_basic_json::value and - not is_basic_json_nested_type::value and - has_to_json::value; -}; - -template -struct is_compatible_type - : conjunction, - is_compatible_complete_type> -{ -}; -} -} - -// #include - - -#include // exception -#include // runtime_error -#include // to_string - -namespace nlohmann -{ -namespace detail -{ -//////////////// -// exceptions // -//////////////// - -/*! -@brief general exception of the @ref basic_json class - -This class is an extension of `std::exception` objects with a member @a id for -exception ids. It is used as the base class for all exceptions thrown by the -@ref basic_json class. This class can hence be used as "wildcard" to catch -exceptions. - -Subclasses: -- @ref parse_error for exceptions indicating a parse error -- @ref invalid_iterator for exceptions indicating errors with iterators -- @ref type_error for exceptions indicating executing a member function with - a wrong type -- @ref out_of_range for exceptions indicating access out of the defined range -- @ref other_error for exceptions indicating other library errors - -@internal -@note To have nothrow-copy-constructible exceptions, we internally use - `std::runtime_error` which can cope with arbitrary-length error messages. - Intermediate strings are built with static functions and then passed to - the actual constructor. -@endinternal - -@liveexample{The following code shows how arbitrary library exceptions can be -caught.,exception} - -@since version 3.0.0 -*/ -class exception : public std::exception -{ - public: - /// returns the explanatory string - const char* what() const noexcept override - { - return m.what(); - } - - /// the id of the exception - const int id; - - protected: - exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} - - static std::string name(const std::string& ename, int id_) - { - return "[json.exception." + ename + "." + std::to_string(id_) + "] "; - } - - private: - /// an exception object as storage for error messages - std::runtime_error m; -}; - -/*! -@brief exception indicating a parse error - -This exception is thrown by the library when a parse error occurs. Parse errors -can occur during the deserialization of JSON text, CBOR, MessagePack, as well -as when using JSON Patch. - -Member @a byte holds the byte index of the last read character in the input -file. - -Exceptions have ids 1xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.parse_error.101 | parse error at 2: unexpected end of input; expected string literal | This error indicates a syntax error while deserializing a JSON text. The error message describes that an unexpected token (character) was encountered, and the member @a byte indicates the error position. -json.exception.parse_error.102 | parse error at 14: missing or wrong low surrogate | JSON uses the `\uxxxx` format to describe Unicode characters. Code points above above 0xFFFF are split into two `\uxxxx` entries ("surrogate pairs"). This error indicates that the surrogate pair is incomplete or contains an invalid code point. -json.exception.parse_error.103 | parse error: code points above 0x10FFFF are invalid | Unicode supports code points up to 0x10FFFF. Code points above 0x10FFFF are invalid. -json.exception.parse_error.104 | parse error: JSON patch must be an array of objects | [RFC 6902](https://tools.ietf.org/html/rfc6902) requires a JSON Patch document to be a JSON document that represents an array of objects. -json.exception.parse_error.105 | parse error: operation must have string member 'op' | An operation of a JSON Patch document must contain exactly one "op" member, whose value indicates the operation to perform. Its value must be one of "add", "remove", "replace", "move", "copy", or "test"; other values are errors. -json.exception.parse_error.106 | parse error: array index '01' must not begin with '0' | An array index in a JSON Pointer ([RFC 6901](https://tools.ietf.org/html/rfc6901)) may be `0` or any number without a leading `0`. -json.exception.parse_error.107 | parse error: JSON pointer must be empty or begin with '/' - was: 'foo' | A JSON Pointer must be a Unicode string containing a sequence of zero or more reference tokens, each prefixed by a `/` character. -json.exception.parse_error.108 | parse error: escape character '~' must be followed with '0' or '1' | In a JSON Pointer, only `~0` and `~1` are valid escape sequences. -json.exception.parse_error.109 | parse error: array index 'one' is not a number | A JSON Pointer array index must be a number. -json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vector | When parsing CBOR or MessagePack, the byte vector ends before the complete value has been read. -json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xF8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. -json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. - -@note For an input with n bytes, 1 is the index of the first character and n+1 - is the index of the terminating null byte or the end of file. This also - holds true when reading a byte vector (CBOR or MessagePack). - -@liveexample{The following code shows how a `parse_error` exception can be -caught.,parse_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class parse_error : public exception -{ - public: - /*! - @brief create a parse error exception - @param[in] id_ the id of the exception - @param[in] byte_ the byte index where the error occurred (or 0 if the - position cannot be determined) - @param[in] what_arg the explanatory string - @return parse_error object - */ - static parse_error create(int id_, std::size_t byte_, const std::string& what_arg) - { - std::string w = exception::name("parse_error", id_) + "parse error" + - (byte_ != 0 ? (" at " + std::to_string(byte_)) : "") + - ": " + what_arg; - return parse_error(id_, byte_, w.c_str()); - } - - /*! - @brief byte index of the parse error - - The byte index of the last read character in the input file. - - @note For an input with n bytes, 1 is the index of the first character and - n+1 is the index of the terminating null byte or the end of file. - This also holds true when reading a byte vector (CBOR or MessagePack). - */ - const std::size_t byte; - - private: - parse_error(int id_, std::size_t byte_, const char* what_arg) - : exception(id_, what_arg), byte(byte_) {} -}; - -/*! -@brief exception indicating errors with iterators - -This exception is thrown if iterators passed to a library function do not match -the expected semantics. - -Exceptions have ids 2xx. - -name / id | example message | description ------------------------------------ | --------------- | ------------------------- -json.exception.invalid_iterator.201 | iterators are not compatible | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.202 | iterator does not fit current value | In an erase or insert function, the passed iterator @a pos does not belong to the JSON value for which the function was called. It hence does not define a valid position for the deletion/insertion. -json.exception.invalid_iterator.203 | iterators do not fit current value | Either iterator passed to function @ref erase(IteratorType first, IteratorType last) does not belong to the JSON value from which values shall be erased. It hence does not define a valid range to delete values from. -json.exception.invalid_iterator.204 | iterators out of range | When an iterator range for a primitive type (number, boolean, or string) is passed to a constructor or an erase function, this range has to be exactly (@ref begin(), @ref end()), because this is the only way the single stored value is expressed. All other ranges are invalid. -json.exception.invalid_iterator.205 | iterator out of range | When an iterator for a primitive type (number, boolean, or string) is passed to an erase function, the iterator has to be the @ref begin() iterator, because it is the only way to address the stored value. All other iterators are invalid. -json.exception.invalid_iterator.206 | cannot construct with iterators from null | The iterators passed to constructor @ref basic_json(InputIT first, InputIT last) belong to a JSON null value and hence to not define a valid range. -json.exception.invalid_iterator.207 | cannot use key() for non-object iterators | The key() member function can only be used on iterators belonging to a JSON object, because other types do not have a concept of a key. -json.exception.invalid_iterator.208 | cannot use operator[] for object iterators | The operator[] to specify a concrete offset cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.209 | cannot use offsets with object iterators | The offset operators (+, -, +=, -=) cannot be used on iterators belonging to a JSON object, because JSON objects are unordered. -json.exception.invalid_iterator.210 | iterators do not fit | The iterator range passed to the insert function are not compatible, meaning they do not belong to the same container. Therefore, the range (@a first, @a last) is invalid. -json.exception.invalid_iterator.211 | passed iterators may not belong to container | The iterator range passed to the insert function must not be a subrange of the container to insert to. -json.exception.invalid_iterator.212 | cannot compare iterators of different containers | When two iterators are compared, they must belong to the same container. -json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. -json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). - -@liveexample{The following code shows how an `invalid_iterator` exception can be -caught.,invalid_iterator} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class invalid_iterator : public exception -{ - public: - static invalid_iterator create(int id_, const std::string& what_arg) - { - std::string w = exception::name("invalid_iterator", id_) + what_arg; - return invalid_iterator(id_, w.c_str()); - } - - private: - invalid_iterator(int id_, const char* what_arg) - : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating executing a member function with a wrong type - -This exception is thrown in case of a type error; that is, a library function is -executed on a JSON value whose type does not match the expected semantics. - -Exceptions have ids 3xx. - -name / id | example message | description ------------------------------ | --------------- | ------------------------- -json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. -json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. -json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. -json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. -json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. -json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. -json.exception.type_error.307 | cannot use erase() with string | The @ref erase() member functions can only be executed for certain JSON types. -json.exception.type_error.308 | cannot use push_back() with string | The @ref push_back() and @ref operator+= member functions can only be executed for certain JSON types. -json.exception.type_error.309 | cannot use insert() with | The @ref insert() member functions can only be executed for certain JSON types. -json.exception.type_error.310 | cannot use swap() with number | The @ref swap() member functions can only be executed for certain JSON types. -json.exception.type_error.311 | cannot use emplace_back() with string | The @ref emplace_back() member function can only be executed for certain JSON types. -json.exception.type_error.312 | cannot use update() with string | The @ref update() member functions can only be executed for certain JSON types. -json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten function converts an object whose keys are JSON Pointers back into an arbitrary nested JSON value. The JSON Pointers must not overlap, because then the resulting value would not be well defined. -json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. -json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. -json.exception.type_error.316 | invalid UTF-8 byte at index 10: 0x7E | The @ref dump function only works with UTF-8 encoded strings; that is, if you assign a `std::string` to a JSON value, make sure it is UTF-8 encoded. | - -@liveexample{The following code shows how a `type_error` exception can be -caught.,type_error} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref out_of_range for exceptions indicating access out of the defined range -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class type_error : public exception -{ - public: - static type_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("type_error", id_) + what_arg; - return type_error(id_, w.c_str()); - } - - private: - type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating access out of the defined range - -This exception is thrown in case a library function is called on an input -parameter that exceeds the expected range, for instance in case of array -indices or nonexisting object keys. - -Exceptions have ids 4xx. - -name / id | example message | description -------------------------------- | --------------- | ------------------------- -json.exception.out_of_range.401 | array index 3 is out of range | The provided array index @a i is larger than @a size-1. -json.exception.out_of_range.402 | array index '-' (3) is out of range | The special array index `-` in a JSON Pointer never describes a valid element of the array, but the index past the end. That is, it can only be used to add elements at this position, but not to read it. -json.exception.out_of_range.403 | key 'foo' not found | The provided key was not found in the JSON object. -json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. -json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. -json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. -json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | -json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | - -@liveexample{The following code shows how an `out_of_range` exception can be -caught.,out_of_range} - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref other_error for exceptions indicating other library errors - -@since version 3.0.0 -*/ -class out_of_range : public exception -{ - public: - static out_of_range create(int id_, const std::string& what_arg) - { - std::string w = exception::name("out_of_range", id_) + what_arg; - return out_of_range(id_, w.c_str()); - } - - private: - out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; - -/*! -@brief exception indicating other library errors - -This exception is thrown in case of errors that cannot be classified with the -other exception types. - -Exceptions have ids 5xx. - -name / id | example message | description ------------------------------- | --------------- | ------------------------- -json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. - -@sa @ref exception for the base class of the library exceptions -@sa @ref parse_error for exceptions indicating a parse error -@sa @ref invalid_iterator for exceptions indicating errors with iterators -@sa @ref type_error for exceptions indicating executing a member function with - a wrong type -@sa @ref out_of_range for exceptions indicating access out of the defined range - -@liveexample{The following code shows how an `other_error` exception can be -caught.,other_error} - -@since version 3.0.0 -*/ -class other_error : public exception -{ - public: - static other_error create(int id_, const std::string& what_arg) - { - std::string w = exception::name("other_error", id_) + what_arg; - return other_error(id_, w.c_str()); - } - - private: - other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} -}; -} -} - -// #include - - -#include // array -#include // and -#include // size_t -#include // uint8_t - -namespace nlohmann -{ -namespace detail -{ -/////////////////////////// -// JSON type enumeration // -/////////////////////////// - -/*! -@brief the JSON type enumeration - -This enumeration collects the different JSON types. It is internally used to -distinguish the stored values, and the functions @ref basic_json::is_null(), -@ref basic_json::is_object(), @ref basic_json::is_array(), -@ref basic_json::is_string(), @ref basic_json::is_boolean(), -@ref basic_json::is_number() (with @ref basic_json::is_number_integer(), -@ref basic_json::is_number_unsigned(), and @ref basic_json::is_number_float()), -@ref basic_json::is_discarded(), @ref basic_json::is_primitive(), and -@ref basic_json::is_structured() rely on it. - -@note There are three enumeration entries (number_integer, number_unsigned, and -number_float), because the library distinguishes these three types for numbers: -@ref basic_json::number_unsigned_t is used for unsigned integers, -@ref basic_json::number_integer_t is used for signed integers, and -@ref basic_json::number_float_t is used for floating-point numbers or to -approximate integers which do not fit in the limits of their respective type. - -@sa @ref basic_json::basic_json(const value_t value_type) -- create a JSON -value with the default value for a given type - -@since version 1.0.0 -*/ -enum class value_t : std::uint8_t -{ - null, ///< null value - object, ///< object (unordered set of name/value pairs) - array, ///< array (ordered collection of values) - string, ///< string value - boolean, ///< boolean value - number_integer, ///< number value (signed integer) - number_unsigned, ///< number value (unsigned integer) - number_float, ///< number value (floating-point) - discarded ///< discarded by the the parser callback function -}; - -/*! -@brief comparison operator for JSON types - -Returns an ordering that is similar to Python: -- order: null < boolean < number < object < array < string -- furthermore, each type is not smaller than itself -- discarded values are not comparable - -@since version 1.0.0 -*/ -inline bool operator<(const value_t lhs, const value_t rhs) noexcept -{ - static constexpr std::array order = {{ - 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, - 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ - } - }; - - const auto l_index = static_cast(lhs); - const auto r_index = static_cast(rhs); - return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; -} -} -} - -// #include - - -#include // transform -#include // array -#include // and, not -#include // forward_list -#include // inserter, front_inserter, end -#include // map -#include // string -#include // tuple, make_tuple -#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible -#include // unordered_map -#include // pair, declval -#include // valarray - -// #include - -// #include - -// #include - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template -void from_json(const BasicJsonType& j, typename std::nullptr_t& n) -{ - if (JSON_UNLIKELY(not j.is_null())) - { - JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); - } - n = nullptr; -} - -// overloads for basic_json template parameters -template::value and - not std::is_same::value, - int> = 0> -void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); - } -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) -{ - if (JSON_UNLIKELY(not j.is_boolean())) - { - JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); - } - b = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) -{ - if (JSON_UNLIKELY(not j.is_string())) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); - } - s = *j.template get_ptr(); -} - -template < - typename BasicJsonType, typename CompatibleStringType, - enable_if_t < - is_compatible_string_type::value and - not std::is_same::value, - int > = 0 > -void from_json(const BasicJsonType& j, CompatibleStringType& s) -{ - if (JSON_UNLIKELY(not j.is_string())) - { - JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); - } - - s = *j.template get_ptr(); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) -{ - get_arithmetic_value(j, val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) -{ - get_arithmetic_value(j, val); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, EnumType& e) -{ - typename std::underlying_type::type val; - get_arithmetic_value(j, val); - e = static_cast(val); -} - -template -void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - arr = *j.template get_ptr(); -} - -// forward_list doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::forward_list& l) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - std::transform(j.rbegin(), j.rend(), - std::front_inserter(l), [](const BasicJsonType & i) - { - return i.template get(); - }); -} - -// valarray doesn't have an insert method -template::value, int> = 0> -void from_json(const BasicJsonType& j, std::valarray& l) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - l.resize(j.size()); - std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); -} - -template -void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) -{ - using std::end; - - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); -} - -template -auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) --> decltype( - arr.reserve(std::declval()), - void()) -{ - using std::end; - - arr.reserve(j.size()); - std::transform(j.begin(), j.end(), - std::inserter(arr, end(arr)), [](const BasicJsonType & i) - { - // get() returns *this, this won't call a from_json - // method when value_type is BasicJsonType - return i.template get(); - }); -} - -template -void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) -{ - for (std::size_t i = 0; i < N; ++i) - { - arr[i] = j.at(i).template get(); - } -} - -template < - typename BasicJsonType, typename CompatibleArrayType, - enable_if_t < - is_compatible_array_type::value and - not std::is_same::value and - std::is_constructible < - BasicJsonType, typename CompatibleArrayType::value_type >::value, - int > = 0 > -void from_json(const BasicJsonType& j, CompatibleArrayType& arr) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + - std::string(j.type_name()))); - } - - from_json_array_impl(j, arr, priority_tag<2> {}); -} - -template::value, int> = 0> -void from_json(const BasicJsonType& j, CompatibleObjectType& obj) -{ - if (JSON_UNLIKELY(not j.is_object())) - { - JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); - } - - auto inner_object = j.template get_ptr(); - using value_type = typename CompatibleObjectType::value_type; - std::transform( - inner_object->begin(), inner_object->end(), - std::inserter(obj, obj.begin()), - [](typename BasicJsonType::object_t::value_type const & p) - { - return value_type(p.first, p.second.template get()); - }); -} - -// overload for arithmetic types, not chosen for basic_json template arguments -// (BooleanType, etc..); note: Is it really necessary to provide explicit -// overloads for boolean_t etc. in case of a custom BooleanType which is not -// an arithmetic type? -template::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value and - not std::is_same::value, - int> = 0> -void from_json(const BasicJsonType& j, ArithmeticType& val) -{ - switch (static_cast(j)) - { - case value_t::number_unsigned: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_integer: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::number_float: - { - val = static_cast(*j.template get_ptr()); - break; - } - case value_t::boolean: - { - val = static_cast(*j.template get_ptr()); - break; - } - - default: - JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); - } -} - -template -void from_json(const BasicJsonType& j, std::pair& p) -{ - p = {j.at(0).template get(), j.at(1).template get()}; -} - -template -void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) -{ - t = std::make_tuple(j.at(Idx).template get::type>()...); -} - -template -void from_json(const BasicJsonType& j, std::tuple& t) -{ - from_json_tuple_impl(j, t, index_sequence_for {}); -} - -template ::value>> -void from_json(const BasicJsonType& j, std::map& m) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - for (const auto& p : j) - { - if (JSON_UNLIKELY(not p.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); - } - m.emplace(p.at(0).template get(), p.at(1).template get()); - } -} - -template ::value>> -void from_json(const BasicJsonType& j, std::unordered_map& m) -{ - if (JSON_UNLIKELY(not j.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); - } - for (const auto& p : j) - { - if (JSON_UNLIKELY(not p.is_array())) - { - JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); - } - m.emplace(p.at(0).template get(), p.at(1).template get()); - } -} - -struct from_json_fn -{ - private: - template - auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const - noexcept(noexcept(from_json(j, val))) - -> decltype(from_json(j, val), void()) - { - return from_json(j, val); - } - - template - void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find from_json() method in T's namespace"); -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template - void operator()(const BasicJsonType& j, T& val) const - noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) - { - return call(j, val, priority_tag<1> {}); - } -}; -} - -/// namespace to hold default `from_json` function -/// to see why this is required: -/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html -namespace -{ -constexpr const auto& from_json = detail::static_const::value; -} -} - -// #include - - -#include // or, and, not -#include // begin, end -#include // tuple, get -#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type -#include // move, forward, declval, pair -#include // valarray -#include // vector - -// #include - -// #include - -// #include - -// #include - - -#include // size_t -#include // string, to_string -#include // input_iterator_tag - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/// proxy class for the items() function -template class iteration_proxy -{ - private: - /// helper class for iteration - class iteration_proxy_internal - { - public: - using difference_type = std::ptrdiff_t; - using value_type = iteration_proxy_internal; - using pointer = iteration_proxy_internal*; - using reference = iteration_proxy_internal&; - using iterator_category = std::input_iterator_tag; - - private: - /// the iterator - IteratorType anchor; - /// an index for arrays (used to create key names) - std::size_t array_index = 0; - /// last stringified array index - mutable std::size_t array_index_last = 0; - /// a string representation of the array index - mutable std::string array_index_str = "0"; - /// an empty string (to return a reference for primitive values) - const std::string empty_str = ""; - - public: - explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} - - iteration_proxy_internal(const iteration_proxy_internal&) = default; - iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default; - - /// dereference operator (needed for range-based for) - iteration_proxy_internal& operator*() - { - return *this; - } - - /// increment operator (needed for range-based for) - iteration_proxy_internal& operator++() - { - ++anchor; - ++array_index; - - return *this; - } - - /// equality operator (needed for InputIterator) - bool operator==(const iteration_proxy_internal& o) const noexcept - { - return anchor == o.anchor; - } - - /// inequality operator (needed for range-based for) - bool operator!=(const iteration_proxy_internal& o) const noexcept - { - return anchor != o.anchor; - } - - /// return key of the iterator - const std::string& key() const - { - assert(anchor.m_object != nullptr); - - switch (anchor.m_object->type()) - { - // use integer array index as key - case value_t::array: - { - if (array_index != array_index_last) - { - array_index_str = std::to_string(array_index); - array_index_last = array_index; - } - return array_index_str; - } - - // use key from the object - case value_t::object: - return anchor.key(); - - // use an empty key for all primitive types - default: - return empty_str; - } - } - - /// return value of the iterator - typename IteratorType::reference value() const - { - return anchor.value(); - } - }; - - /// the container to iterate - typename IteratorType::reference container; - - public: - /// construct iteration proxy from a container - explicit iteration_proxy(typename IteratorType::reference cont) noexcept - : container(cont) {} - - /// return iterator begin (needed for range-based for) - iteration_proxy_internal begin() noexcept - { - return iteration_proxy_internal(container.begin()); - } - - /// return iterator end (needed for range-based for) - iteration_proxy_internal end() noexcept - { - return iteration_proxy_internal(container.end()); - } -}; -} -} - - -namespace nlohmann -{ -namespace detail -{ -////////////////// -// constructors // -////////////////// - -template struct external_constructor; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::boolean_t b) noexcept - { - j.m_type = value_t::boolean; - j.m_value = b; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::string_t& s) - { - j.m_type = value_t::string; - j.m_value = s; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::string_t&& s) - { - j.m_type = value_t::string; - j.m_value = std::move(s); - j.assert_invariant(); - } - - template::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleStringType& str) - { - j.m_type = value_t::string; - j.m_value.string = j.template create(str); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_float_t val) noexcept - { - j.m_type = value_t::number_float; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_unsigned_t val) noexcept - { - j.m_type = value_t::number_unsigned; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, typename BasicJsonType::number_integer_t val) noexcept - { - j.m_type = value_t::number_integer; - j.m_value = val; - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::array_t& arr) - { - j.m_type = value_t::array; - j.m_value = arr; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::array_t&& arr) - { - j.m_type = value_t::array; - j.m_value = std::move(arr); - j.assert_invariant(); - } - - template::value, - int> = 0> - static void construct(BasicJsonType& j, const CompatibleArrayType& arr) - { - using std::begin; - using std::end; - j.m_type = value_t::array; - j.m_value.array = j.template create(begin(arr), end(arr)); - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, const std::vector& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->reserve(arr.size()); - for (const bool x : arr) - { - j.m_value.array->push_back(x); - } - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const std::valarray& arr) - { - j.m_type = value_t::array; - j.m_value = value_t::array; - j.m_value.array->resize(arr.size()); - std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); - j.assert_invariant(); - } -}; - -template<> -struct external_constructor -{ - template - static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) - { - j.m_type = value_t::object; - j.m_value = obj; - j.assert_invariant(); - } - - template - static void construct(BasicJsonType& j, typename BasicJsonType::object_t&& obj) - { - j.m_type = value_t::object; - j.m_value = std::move(obj); - j.assert_invariant(); - } - - template::value, int> = 0> - static void construct(BasicJsonType& j, const CompatibleObjectType& obj) - { - using std::begin; - using std::end; - - j.m_type = value_t::object; - j.m_value.object = j.template create(begin(obj), end(obj)); - j.assert_invariant(); - } -}; - -///////////// -// to_json // -///////////// - -template::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept -{ - external_constructor::construct(j, b); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleString& s) -{ - external_constructor::construct(j, s); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) -{ - external_constructor::construct(j, std::move(s)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, FloatType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept -{ - external_constructor::construct(j, static_cast(val)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, EnumType e) noexcept -{ - using underlying_type = typename std::underlying_type::type; - external_constructor::construct(j, static_cast(e)); -} - -template -void to_json(BasicJsonType& j, const std::vector& e) -{ - external_constructor::construct(j, e); -} - -template::value or - std::is_same::value, - int> = 0> -void to_json(BasicJsonType& j, const CompatibleArrayType& arr) -{ - external_constructor::construct(j, arr); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const std::valarray& arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr) -{ - external_constructor::construct(j, std::move(arr)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, const CompatibleObjectType& obj) -{ - external_constructor::construct(j, obj); -} - -template -void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) -{ - external_constructor::construct(j, std::move(obj)); -} - -template::value, int> = 0> -void to_json(BasicJsonType& j, T (&arr)[N]) -{ - external_constructor::construct(j, arr); -} - -template -void to_json(BasicJsonType& j, const std::pair& p) -{ - j = {p.first, p.second}; -} - -// for https://github.com/nlohmann/json/pull/1134 -template::iteration_proxy_internal>::value, int> = 0> -void to_json(BasicJsonType& j, T b) noexcept -{ - j = {{b.key(), b.value()}}; -} - -template -void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) -{ - j = {std::get(t)...}; -} - -template -void to_json(BasicJsonType& j, const std::tuple& t) -{ - to_json_tuple_impl(j, t, index_sequence_for {}); -} - -struct to_json_fn -{ - private: - template - auto call(BasicJsonType& j, T&& val, priority_tag<1> /*unused*/) const noexcept(noexcept(to_json(j, std::forward(val)))) - -> decltype(to_json(j, std::forward(val)), void()) - { - return to_json(j, std::forward(val)); - } - - template - void call(BasicJsonType& /*unused*/, T&& /*unused*/, priority_tag<0> /*unused*/) const noexcept - { - static_assert(sizeof(BasicJsonType) == 0, - "could not find to_json() method in T's namespace"); - -#ifdef _MSC_VER - // MSVC does not show a stacktrace for the above assert - using decayed = uncvref_t; - static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, - "forcing MSVC stacktrace to show which T we're talking about."); -#endif - } - - public: - template - void operator()(BasicJsonType& j, T&& val) const - noexcept(noexcept(std::declval().call(j, std::forward(val), priority_tag<1> {}))) - { - return call(j, std::forward(val), priority_tag<1> {}); - } -}; -} - -/// namespace to hold default `to_json` function -namespace -{ -constexpr const auto& to_json = detail::static_const::value; -} -} - -// #include - - -#include // assert -#include // size_t -#include // strlen -#include // istream -#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next -#include // shared_ptr, make_shared, addressof -#include // accumulate -#include // string, char_traits -#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer -#include // pair, declval - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/// the supported input formats -enum class input_format_t { json, cbor, msgpack, ubjson }; - -//////////////////// -// input adapters // -//////////////////// - -/*! -@brief abstract input adapter interface - -Produces a stream of std::char_traits::int_type characters from a -std::istream, a buffer, or some other input type. Accepts the return of -exactly one non-EOF character for future input. The int_type characters -returned consist of all valid char values as positive values (typically -unsigned char), plus an EOF value outside that range, specified by the value -of the function std::char_traits::eof(). This value is typically -1, but -could be any arbitrary value which is not a valid char value. -*/ -struct input_adapter_protocol -{ - /// get a character [0,255] or std::char_traits::eof(). - virtual std::char_traits::int_type get_character() = 0; - virtual ~input_adapter_protocol() = default; -}; - -/// a type to simplify interfaces -using input_adapter_t = std::shared_ptr; - -/*! -Input adapter for a (caching) istream. Ignores a UFT Byte Order Mark at -beginning of input. Does not support changing the underlying std::streambuf -in mid-input. Maintains underlying std::istream and std::streambuf to support -subsequent use of standard std::istream operations to process any input -characters following those used in parsing the JSON input. Clears the -std::istream flags; any input errors (e.g., EOF) will be detected by the first -subsequent call for input from the std::istream. -*/ -class input_stream_adapter : public input_adapter_protocol -{ - public: - ~input_stream_adapter() override - { - // clear stream flags; we use underlying streambuf I/O, do not - // maintain ifstream flags - is.clear(); - } - - explicit input_stream_adapter(std::istream& i) - : is(i), sb(*i.rdbuf()) - {} - - // delete because of pointer members - input_stream_adapter(const input_stream_adapter&) = delete; - input_stream_adapter& operator=(input_stream_adapter&) = delete; - - // std::istream/std::streambuf use std::char_traits::to_int_type, to - // ensure that std::char_traits::eof() and the character 0xFF do not - // end up as the same value, eg. 0xFFFFFFFF. - std::char_traits::int_type get_character() override - { - return sb.sbumpc(); - } - - private: - /// the associated input stream - std::istream& is; - std::streambuf& sb; -}; - -/// input adapter for buffer input -class input_buffer_adapter : public input_adapter_protocol -{ - public: - input_buffer_adapter(const char* b, const std::size_t l) - : cursor(b), limit(b + l) - {} - - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - - std::char_traits::int_type get_character() noexcept override - { - if (JSON_LIKELY(cursor < limit)) - { - return std::char_traits::to_int_type(*(cursor++)); - } - - return std::char_traits::eof(); - } - - private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* const limit; -}; - -template -class wide_string_input_adapter : public input_adapter_protocol -{ - public: - explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} - - std::char_traits::int_type get_character() noexcept override - { - // check if buffer needs to be filled - if (utf8_bytes_index == utf8_bytes_filled) - { - if (sizeof(typename WideStringType::value_type) == 2) - { - fill_buffer_utf16(); - } - else - { - fill_buffer_utf32(); - } - - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index == 0); - } - - // use buffer - assert(utf8_bytes_filled > 0); - assert(utf8_bytes_index < utf8_bytes_filled); - return utf8_bytes[utf8_bytes_index++]; - } - - private: - void fill_buffer_utf16() - { - utf8_bytes_index = 0; - - if (current_wchar == str.size()) - { - utf8_bytes[0] = std::char_traits::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const int wc = static_cast(str[current_wchar++]); - - // UTF-16 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = 0xC0 | ((wc >> 6)); - utf8_bytes[1] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 2; - } - else if (0xD800 > wc or wc >= 0xE000) - { - utf8_bytes[0] = 0xE0 | ((wc >> 12)); - utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[2] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 3; - } - else - { - if (current_wchar < str.size()) - { - const int wc2 = static_cast(str[current_wchar++]); - const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF)); - utf8_bytes[0] = 0xf0 | (charcode >> 18); - utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F); - utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F); - utf8_bytes[3] = 0x80 | (charcode & 0x3F); - utf8_bytes_filled = 4; - } - else - { - // unknown character - ++current_wchar; - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } - } - } - } - - void fill_buffer_utf32() - { - utf8_bytes_index = 0; - - if (current_wchar == str.size()) - { - utf8_bytes[0] = std::char_traits::eof(); - utf8_bytes_filled = 1; - } - else - { - // get the current character - const int wc = static_cast(str[current_wchar++]); - - // UTF-32 to UTF-8 encoding - if (wc < 0x80) - { - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } - else if (wc <= 0x7FF) - { - utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); - utf8_bytes[1] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 2; - } - else if (wc <= 0xFFFF) - { - utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); - utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[2] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 3; - } - else if (wc <= 0x10FFFF) - { - utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07); - utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); - utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); - utf8_bytes[3] = 0x80 | (wc & 0x3F); - utf8_bytes_filled = 4; - } - else - { - // unknown character - utf8_bytes[0] = wc; - utf8_bytes_filled = 1; - } - } - } - - private: - /// the wstring to process - const WideStringType& str; - - /// index of the current wchar in str - std::size_t current_wchar = 0; - - /// a buffer for UTF-8 bytes - std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; - - /// index to the utf8_codes array for the next valid byte - std::size_t utf8_bytes_index = 0; - /// number of valid bytes in the utf8_codes array - std::size_t utf8_bytes_filled = 0; -}; - -class input_adapter -{ - public: - // native support - - /// input adapter for input stream - input_adapter(std::istream& i) - : ia(std::make_shared(i)) {} - - /// input adapter for input stream - input_adapter(std::istream&& i) - : ia(std::make_shared(i)) {} - - input_adapter(const std::wstring& ws) - : ia(std::make_shared>(ws)) {} - - input_adapter(const std::u16string& ws) - : ia(std::make_shared>(ws)) {} - - input_adapter(const std::u32string& ws) - : ia(std::make_shared>(ws)) {} - - /// input adapter for buffer - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b, std::size_t l) - : ia(std::make_shared(reinterpret_cast(b), l)) {} - - // derived support - - /// input adapter for string literal - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - input_adapter(CharT b) - : input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))) {} - - /// input adapter for iterator range with contiguous storage - template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> - input_adapter(IteratorType first, IteratorType last) - { - // assertion to check that the iterator range is indeed contiguous, - // see http://stackoverflow.com/a/35008842/266378 for more discussion - assert(std::accumulate( - first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first); - - // assertion to check that each element is 1 byte long - static_assert( - sizeof(typename std::iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - const auto len = static_cast(std::distance(first, last)); - if (JSON_LIKELY(len > 0)) - { - // there is at least one element: use the address of first - ia = std::make_shared(reinterpret_cast(&(*first)), len); - } - else - { - // the address of first cannot be used: use nullptr - ia = std::make_shared(nullptr, len); - } - } - - /// input adapter for array - template - input_adapter(T (&array)[N]) - : input_adapter(std::begin(array), std::end(array)) {} - - /// input adapter for contiguous container - template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> - input_adapter(const ContiguousContainer& c) - : input_adapter(std::begin(c), std::end(c)) {} - - operator input_adapter_t() - { - return ia; - } - - private: - /// the actual adapter - input_adapter_t ia = nullptr; -}; -} -} - -// #include - - -#include // localeconv -#include // size_t -#include // strtof, strtod, strtold, strtoll, strtoull -#include // snprintf -#include // initializer_list -#include // char_traits, string -#include // vector - -// #include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -/////////// -// lexer // -/////////// - -/*! -@brief lexical analysis - -This class organizes the lexical analysis during JSON deserialization. -*/ -template -class lexer -{ - using number_integer_t = typename BasicJsonType::number_integer_t; - using number_unsigned_t = typename BasicJsonType::number_unsigned_t; - using number_float_t = typename BasicJsonType::number_float_t; - using string_t = typename BasicJsonType::string_t; - - public: - /// token types for the parser - enum class token_type - { - uninitialized, ///< indicating the scanner is uninitialized - literal_true, ///< the `true` literal - literal_false, ///< the `false` literal - literal_null, ///< the `null` literal - value_string, ///< a string -- use get_string() for actual value - value_unsigned, ///< an unsigned integer -- use get_number_unsigned() for actual value - value_integer, ///< a signed integer -- use get_number_integer() for actual value - value_float, ///< an floating point number -- use get_number_float() for actual value - begin_array, ///< the character for array begin `[` - begin_object, ///< the character for object begin `{` - end_array, ///< the character for array end `]` - end_object, ///< the character for object end `}` - name_separator, ///< the name separator `:` - value_separator, ///< the value separator `,` - parse_error, ///< indicating a parse error - end_of_input, ///< indicating the end of the input buffer - literal_or_value ///< a literal or the begin of a value (only for diagnostics) - }; - - /// return name of values of type token_type (only used for errors) - static const char* token_type_name(const token_type t) noexcept - { - switch (t) - { - case token_type::uninitialized: - return ""; - case token_type::literal_true: - return "true literal"; - case token_type::literal_false: - return "false literal"; - case token_type::literal_null: - return "null literal"; - case token_type::value_string: - return "string literal"; - case lexer::token_type::value_unsigned: - case lexer::token_type::value_integer: - case lexer::token_type::value_float: - return "number literal"; - case token_type::begin_array: - return "'['"; - case token_type::begin_object: - return "'{'"; - case token_type::end_array: - return "']'"; - case token_type::end_object: - return "'}'"; - case token_type::name_separator: - return "':'"; - case token_type::value_separator: - return "','"; - case token_type::parse_error: - return ""; - case token_type::end_of_input: - return "end of input"; - case token_type::literal_or_value: - return "'[', '{', or a literal"; - // LCOV_EXCL_START - default: // catch non-enum values - return "unknown token"; - // LCOV_EXCL_STOP - } - } - - explicit lexer(detail::input_adapter_t&& adapter) - : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} - - // delete because of pointer members - lexer(const lexer&) = delete; - lexer& operator=(lexer&) = delete; - - private: - ///////////////////// - // locales - ///////////////////// - - /// return the locale-dependent decimal point - static char get_decimal_point() noexcept - { - const auto loc = localeconv(); - assert(loc != nullptr); - return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point); - } - - ///////////////////// - // scan functions - ///////////////////// - - /*! - @brief get codepoint from 4 hex characters following `\u` - - For input "\u c1 c2 c3 c4" the codepoint is: - (c1 * 0x1000) + (c2 * 0x0100) + (c3 * 0x0010) + c4 - = (c1 << 12) + (c2 << 8) + (c3 << 4) + (c4 << 0) - - Furthermore, the possible characters '0'..'9', 'A'..'F', and 'a'..'f' - must be converted to the integers 0x0..0x9, 0xA..0xF, 0xA..0xF, resp. The - conversion is done by subtracting the offset (0x30, 0x37, and 0x57) - between the ASCII value of the character and the desired integer value. - - @return codepoint (0x0000..0xFFFF) or -1 in case of an error (e.g. EOF or - non-hex character) - */ - int get_codepoint() - { - // this function only makes sense after reading `\u` - assert(current == 'u'); - int codepoint = 0; - - const auto factors = { 12, 8, 4, 0 }; - for (const auto factor : factors) - { - get(); - - if (current >= '0' and current <= '9') - { - codepoint += ((current - 0x30) << factor); - } - else if (current >= 'A' and current <= 'F') - { - codepoint += ((current - 0x37) << factor); - } - else if (current >= 'a' and current <= 'f') - { - codepoint += ((current - 0x57) << factor); - } - else - { - return -1; - } - } - - assert(0x0000 <= codepoint and codepoint <= 0xFFFF); - return codepoint; - } - - /*! - @brief check if the next byte(s) are inside a given range - - Adds the current byte and, for each passed range, reads a new byte and - checks if it is inside the range. If a violation was detected, set up an - error message and return false. Otherwise, return true. - - @param[in] ranges list of integers; interpreted as list of pairs of - inclusive lower and upper bound, respectively - - @pre The passed list @a ranges must have 2, 4, or 6 elements; that is, - 1, 2, or 3 pairs. This precondition is enforced by an assertion. - - @return true if and only if no range violation was detected - */ - bool next_byte_in_range(std::initializer_list ranges) - { - assert(ranges.size() == 2 or ranges.size() == 4 or ranges.size() == 6); - add(current); - - for (auto range = ranges.begin(); range != ranges.end(); ++range) - { - get(); - if (JSON_LIKELY(*range <= current and current <= *(++range))) - { - add(current); - } - else - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return false; - } - } - - return true; - } - - /*! - @brief scan a string literal - - This function scans a string according to Sect. 7 of RFC 7159. While - scanning, bytes are escaped and copied into buffer token_buffer. Then the - function returns successfully, token_buffer is *not* null-terminated (as it - may contain \0 bytes), and token_buffer.size() is the number of bytes in the - string. - - @return token_type::value_string if string could be successfully scanned, - token_type::parse_error otherwise - - @note In case of errors, variable error_message contains a textual - description. - */ - token_type scan_string() - { - // reset token_buffer (ignore opening quote) - reset(); - - // we entered the function by reading an open quote - assert(current == '\"'); - - while (true) - { - // get next character - switch (get()) - { - // end of file while parsing string - case std::char_traits::eof(): - { - error_message = "invalid string: missing closing quote"; - return token_type::parse_error; - } - - // closing quote - case '\"': - { - return token_type::value_string; - } - - // escapes - case '\\': - { - switch (get()) - { - // quotation mark - case '\"': - add('\"'); - break; - // reverse solidus - case '\\': - add('\\'); - break; - // solidus - case '/': - add('/'); - break; - // backspace - case 'b': - add('\b'); - break; - // form feed - case 'f': - add('\f'); - break; - // line feed - case 'n': - add('\n'); - break; - // carriage return - case 'r': - add('\r'); - break; - // tab - case 't': - add('\t'); - break; - - // unicode escapes - case 'u': - { - const int codepoint1 = get_codepoint(); - int codepoint = codepoint1; // start with codepoint1 - - if (JSON_UNLIKELY(codepoint1 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if code point is a high surrogate - if (0xD800 <= codepoint1 and codepoint1 <= 0xDBFF) - { - // expect next \uxxxx entry - if (JSON_LIKELY(get() == '\\' and get() == 'u')) - { - const int codepoint2 = get_codepoint(); - - if (JSON_UNLIKELY(codepoint2 == -1)) - { - error_message = "invalid string: '\\u' must be followed by 4 hex digits"; - return token_type::parse_error; - } - - // check if codepoint2 is a low surrogate - if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) - { - // overwrite codepoint - codepoint = - // high surrogate occupies the most significant 22 bits - (codepoint1 << 10) - // low surrogate occupies the least significant 15 bits - + codepoint2 - // there is still the 0xD800, 0xDC00 and 0x10000 noise - // in the result so we have to subtract with: - // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 - - 0x35FDC00; - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must be followed by U+DC00..U+DFFF"; - return token_type::parse_error; - } - } - else - { - if (JSON_UNLIKELY(0xDC00 <= codepoint1 and codepoint1 <= 0xDFFF)) - { - error_message = "invalid string: surrogate U+DC00..U+DFFF must follow U+D800..U+DBFF"; - return token_type::parse_error; - } - } - - // result of the above calculation yields a proper codepoint - assert(0x00 <= codepoint and codepoint <= 0x10FFFF); - - // translate codepoint into bytes - if (codepoint < 0x80) - { - // 1-byte characters: 0xxxxxxx (ASCII) - add(codepoint); - } - else if (codepoint <= 0x7FF) - { - // 2-byte characters: 110xxxxx 10xxxxxx - add(0xC0 | (codepoint >> 6)); - add(0x80 | (codepoint & 0x3F)); - } - else if (codepoint <= 0xFFFF) - { - // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx - add(0xE0 | (codepoint >> 12)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - else - { - // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - add(0xF0 | (codepoint >> 18)); - add(0x80 | ((codepoint >> 12) & 0x3F)); - add(0x80 | ((codepoint >> 6) & 0x3F)); - add(0x80 | (codepoint & 0x3F)); - } - - break; - } - - // other characters after escape - default: - error_message = "invalid string: forbidden character after backslash"; - return token_type::parse_error; - } - - break; - } - - // invalid control characters - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x04: - case 0x05: - case 0x06: - case 0x07: - case 0x08: - case 0x09: - case 0x0A: - case 0x0B: - case 0x0C: - case 0x0D: - case 0x0E: - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x14: - case 0x15: - case 0x16: - case 0x17: - case 0x18: - case 0x19: - case 0x1A: - case 0x1B: - case 0x1C: - case 0x1D: - case 0x1E: - case 0x1F: - { - error_message = "invalid string: control character must be escaped"; - return token_type::parse_error; - } - - // U+0020..U+007F (except U+0022 (quote) and U+005C (backspace)) - case 0x20: - case 0x21: - case 0x23: - case 0x24: - case 0x25: - case 0x26: - case 0x27: - case 0x28: - case 0x29: - case 0x2A: - case 0x2B: - case 0x2C: - case 0x2D: - case 0x2E: - case 0x2F: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x34: - case 0x35: - case 0x36: - case 0x37: - case 0x38: - case 0x39: - case 0x3A: - case 0x3B: - case 0x3C: - case 0x3D: - case 0x3E: - case 0x3F: - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - case 0x50: - case 0x51: - case 0x52: - case 0x53: - case 0x54: - case 0x55: - case 0x56: - case 0x57: - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: - case 0x5D: - case 0x5E: - case 0x5F: - case 0x60: - case 0x61: - case 0x62: - case 0x63: - case 0x64: - case 0x65: - case 0x66: - case 0x67: - case 0x68: - case 0x69: - case 0x6A: - case 0x6B: - case 0x6C: - case 0x6D: - case 0x6E: - case 0x6F: - case 0x70: - case 0x71: - case 0x72: - case 0x73: - case 0x74: - case 0x75: - case 0x76: - case 0x77: - case 0x78: - case 0x79: - case 0x7A: - case 0x7B: - case 0x7C: - case 0x7D: - case 0x7E: - case 0x7F: - { - add(current); - break; - } - - // U+0080..U+07FF: bytes C2..DF 80..BF - case 0xC2: - case 0xC3: - case 0xC4: - case 0xC5: - case 0xC6: - case 0xC7: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - case 0xCC: - case 0xCD: - case 0xCE: - case 0xCF: - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - case 0xD4: - case 0xD5: - case 0xD6: - case 0xD7: - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDC: - case 0xDD: - case 0xDE: - case 0xDF: - { - if (JSON_UNLIKELY(not next_byte_in_range({0x80, 0xBF}))) - { - return token_type::parse_error; - } - break; - } - - // U+0800..U+0FFF: bytes E0 A0..BF 80..BF - case 0xE0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0xA0, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+1000..U+CFFF: bytes E1..EC 80..BF 80..BF - // U+E000..U+FFFF: bytes EE..EF 80..BF 80..BF - case 0xE1: - case 0xE2: - case 0xE3: - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xE8: - case 0xE9: - case 0xEA: - case 0xEB: - case 0xEC: - case 0xEE: - case 0xEF: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+D000..U+D7FF: bytes ED 80..9F 80..BF - case 0xED: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x9F, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+10000..U+3FFFF F0 90..BF 80..BF 80..BF - case 0xF0: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x90, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+40000..U+FFFFF F1..F3 80..BF 80..BF 80..BF - case 0xF1: - case 0xF2: - case 0xF3: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0xBF, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // U+100000..U+10FFFF F4 80..8F 80..BF 80..BF - case 0xF4: - { - if (JSON_UNLIKELY(not (next_byte_in_range({0x80, 0x8F, 0x80, 0xBF, 0x80, 0xBF})))) - { - return token_type::parse_error; - } - break; - } - - // remaining bytes (80..C1 and F5..FF) are ill-formed - default: - { - error_message = "invalid string: ill-formed UTF-8 byte"; - return token_type::parse_error; - } - } - } - } - - static void strtof(float& f, const char* str, char** endptr) noexcept - { - f = std::strtof(str, endptr); - } - - static void strtof(double& f, const char* str, char** endptr) noexcept - { - f = std::strtod(str, endptr); - } - - static void strtof(long double& f, const char* str, char** endptr) noexcept - { - f = std::strtold(str, endptr); - } - - /*! - @brief scan a number literal - - This function scans a string according to Sect. 6 of RFC 7159. - - The function is realized with a deterministic finite state machine derived - from the grammar described in RFC 7159. Starting in state "init", the - input is read and used to determined the next state. Only state "done" - accepts the number. State "error" is a trap state to model errors. In the - table below, "anything" means any character but the ones listed before. - - state | 0 | 1-9 | e E | + | - | . | anything - ---------|----------|----------|----------|---------|---------|----------|----------- - init | zero | any1 | [error] | [error] | minus | [error] | [error] - minus | zero | any1 | [error] | [error] | [error] | [error] | [error] - zero | done | done | exponent | done | done | decimal1 | done - any1 | any1 | any1 | exponent | done | done | decimal1 | done - decimal1 | decimal2 | [error] | [error] | [error] | [error] | [error] | [error] - decimal2 | decimal2 | decimal2 | exponent | done | done | done | done - exponent | any2 | any2 | [error] | sign | sign | [error] | [error] - sign | any2 | any2 | [error] | [error] | [error] | [error] | [error] - any2 | any2 | any2 | done | done | done | done | done - - The state machine is realized with one label per state (prefixed with - "scan_number_") and `goto` statements between them. The state machine - contains cycles, but any cycle can be left when EOF is read. Therefore, - the function is guaranteed to terminate. - - During scanning, the read bytes are stored in token_buffer. This string is - then converted to a signed integer, an unsigned integer, or a - floating-point number. - - @return token_type::value_unsigned, token_type::value_integer, or - token_type::value_float if number could be successfully scanned, - token_type::parse_error otherwise - - @note The scanner is independent of the current locale. Internally, the - locale's decimal point is used instead of `.` to work with the - locale-dependent converters. - */ - token_type scan_number() - { - // reset token_buffer to store the number's bytes - reset(); - - // the type of the parsed number; initially set to unsigned; will be - // changed if minus sign, decimal point or exponent is read - token_type number_type = token_type::value_unsigned; - - // state (init): we just found out we need to scan a number - switch (current) - { - case '-': - { - add(current); - goto scan_number_minus; - } - - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - // LCOV_EXCL_START - default: - { - // all other characters are rejected outside scan_number() - assert(false); - } - // LCOV_EXCL_STOP - } - -scan_number_minus: - // state: we just parsed a leading minus sign - number_type = token_type::value_integer; - switch (get()) - { - case '0': - { - add(current); - goto scan_number_zero; - } - - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - default: - { - error_message = "invalid number; expected digit after '-'"; - return token_type::parse_error; - } - } - -scan_number_zero: - // state: we just parse a zero (maybe with a leading minus sign) - switch (get()) - { - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_any1: - // state: we just parsed a number 0-9 (maybe with a leading minus sign) - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any1; - } - - case '.': - { - add(decimal_point_char); - goto scan_number_decimal1; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_decimal1: - // state: we just parsed a decimal point - number_type = token_type::value_float; - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - default: - { - error_message = "invalid number; expected digit after '.'"; - return token_type::parse_error; - } - } - -scan_number_decimal2: - // we just parsed at least one number after a decimal point - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_decimal2; - } - - case 'e': - case 'E': - { - add(current); - goto scan_number_exponent; - } - - default: - goto scan_number_done; - } - -scan_number_exponent: - // we just parsed an exponent - number_type = token_type::value_float; - switch (get()) - { - case '+': - case '-': - { - add(current); - goto scan_number_sign; - } - - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = - "invalid number; expected '+', '-', or digit after exponent"; - return token_type::parse_error; - } - } - -scan_number_sign: - // we just parsed an exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - { - error_message = "invalid number; expected digit after exponent sign"; - return token_type::parse_error; - } - } - -scan_number_any2: - // we just parsed a number after the exponent or exponent sign - switch (get()) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - { - add(current); - goto scan_number_any2; - } - - default: - goto scan_number_done; - } - -scan_number_done: - // unget the character after the number (we only read it to know that - // we are done scanning a number) - unget(); - - char* endptr = nullptr; - errno = 0; - - // try to parse integers first and fall back to floats - if (number_type == token_type::value_unsigned) - { - const auto x = std::strtoull(token_buffer.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); - - if (errno == 0) - { - value_unsigned = static_cast(x); - if (value_unsigned == x) - { - return token_type::value_unsigned; - } - } - } - else if (number_type == token_type::value_integer) - { - const auto x = std::strtoll(token_buffer.data(), &endptr, 10); - - // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); - - if (errno == 0) - { - value_integer = static_cast(x); - if (value_integer == x) - { - return token_type::value_integer; - } - } - } - - // this code is reached if we parse a floating-point number or if an - // integer conversion above failed - strtof(value_float, token_buffer.data(), &endptr); - - // we checked the number format before - assert(endptr == token_buffer.data() + token_buffer.size()); - - return token_type::value_float; - } - - /*! - @param[in] literal_text the literal text to expect - @param[in] length the length of the passed literal text - @param[in] return_type the token type to return on success - */ - token_type scan_literal(const char* literal_text, const std::size_t length, - token_type return_type) - { - assert(current == literal_text[0]); - for (std::size_t i = 1; i < length; ++i) - { - if (JSON_UNLIKELY(get() != literal_text[i])) - { - error_message = "invalid literal"; - return token_type::parse_error; - } - } - return return_type; - } - - ///////////////////// - // input management - ///////////////////// - - /// reset token_buffer; current character is beginning of token - void reset() noexcept - { - token_buffer.clear(); - token_string.clear(); - token_string.push_back(std::char_traits::to_char_type(current)); - } - - /* - @brief get next character from the input - - This function provides the interface to the used input adapter. It does - not throw in case the input reached EOF, but returns a - `std::char_traits::eof()` in that case. Stores the scanned characters - for use in error messages. - - @return character read from the input - */ - std::char_traits::int_type get() - { - ++chars_read; - if (next_unget) - { - // just reset the next_unget variable and work with current - next_unget = false; - } - else - { - current = ia->get_character(); - } - - if (JSON_LIKELY(current != std::char_traits::eof())) - { - token_string.push_back(std::char_traits::to_char_type(current)); - } - return current; - } - - /*! - @brief unget current character (read it again on next get) - - We implement unget by setting variable next_unget to true. The input is not - changed - we just simulate ungetting by modifying chars_read and - token_string. The next call to get() will behave as if the unget character - is read again. - */ - void unget() - { - next_unget = true; - --chars_read; - if (JSON_LIKELY(current != std::char_traits::eof())) - { - assert(token_string.size() != 0); - token_string.pop_back(); - } - } - - /// add a character to token_buffer - void add(int c) - { - token_buffer.push_back(std::char_traits::to_char_type(c)); - } - - public: - ///////////////////// - // value getters - ///////////////////// - - /// return integer value - constexpr number_integer_t get_number_integer() const noexcept - { - return value_integer; - } - - /// return unsigned integer value - constexpr number_unsigned_t get_number_unsigned() const noexcept - { - return value_unsigned; - } - - /// return floating-point value - constexpr number_float_t get_number_float() const noexcept - { - return value_float; - } - - /// return current string value (implicitly resets the token; useful only once) - string_t& get_string() - { - return token_buffer; - } - - ///////////////////// - // diagnostics - ///////////////////// - - /// return position of last read token - constexpr std::size_t get_position() const noexcept - { - return chars_read; - } - - /// return the last read token (for errors only). Will never contain EOF - /// (an arbitrary value that is not a valid char value, often -1), because - /// 255 may legitimately occur. May contain NUL, which should be escaped. - std::string get_token_string() const - { - // escape control characters - std::string result; - for (const auto c : token_string) - { - if ('\x00' <= c and c <= '\x1F') - { - // escape control characters - char cs[9]; - snprintf(cs, 9, "", static_cast(c)); - result += cs; - } - else - { - // add character as is - result.push_back(c); - } - } - - return result; - } - - /// return syntax error message - constexpr const char* get_error_message() const noexcept - { - return error_message; - } - - ///////////////////// - // actual scanner - ///////////////////// - - /*! - @brief skip the UTF-8 byte order mark - @return true iff there is no BOM or the correct BOM has been skipped - */ - bool skip_bom() - { - if (get() == 0xEF) - { - if (get() == 0xBB and get() == 0xBF) - { - // we completely parsed the BOM - return true; - } - else - { - // after reading 0xEF, an unexpected character followed - return false; - } - } - else - { - // the first character is not the beginning of the BOM; unget it to - // process is later - unget(); - return true; - } - } - - token_type scan() - { - // initially, skip the BOM - if (chars_read == 0 and not skip_bom()) - { - error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; - return token_type::parse_error; - } - - // read next character and ignore whitespace - do - { - get(); - } - while (current == ' ' or current == '\t' or current == '\n' or current == '\r'); - - switch (current) - { - // structural characters - case '[': - return token_type::begin_array; - case ']': - return token_type::end_array; - case '{': - return token_type::begin_object; - case '}': - return token_type::end_object; - case ':': - return token_type::name_separator; - case ',': - return token_type::value_separator; - - // literals - case 't': - return scan_literal("true", 4, token_type::literal_true); - case 'f': - return scan_literal("false", 5, token_type::literal_false); - case 'n': - return scan_literal("null", 4, token_type::literal_null); - - // string - case '\"': - return scan_string(); - - // number - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return scan_number(); - - // end of input (the null byte is needed when parsing from - // string literals) - case '\0': - case std::char_traits::eof(): - return token_type::end_of_input; - - // error - default: - error_message = "invalid literal"; - return token_type::parse_error; - } - } - - private: - /// input adapter - detail::input_adapter_t ia = nullptr; - - /// the current character - std::char_traits::int_type current = std::char_traits::eof(); - - /// whether the next get() call should just return current - bool next_unget = false; - - /// the number of characters read - std::size_t chars_read = 0; - - /// raw input token string (for error messages) - std::vector token_string {}; - - /// buffer for variable-length tokens (numbers, strings) - string_t token_buffer {}; - - /// a description of occurred lexer errors - const char* error_message = ""; - - // number values - number_integer_t value_integer = 0; - number_unsigned_t value_unsigned = 0; - number_float_t value_float = 0; - - /// the decimal point - const char decimal_point_char = '.'; -}; -} -} - -// #include - - -#include // assert -#include // isfinite -#include // uint8_t -#include // function -#include // string -#include // move - -// #include - -// #include - -// #include - - -#include // size_t -#include // declval - -// #include - - -#include - -// #include - - -namespace nlohmann -{ -namespace detail -{ -template -using void_t = void; -} -} - - -// http://en.cppreference.com/w/cpp/experimental/is_detected -namespace nlohmann -{ -namespace detail -{ -struct nonesuch -{ - nonesuch() = delete; - ~nonesuch() = delete; - nonesuch(nonesuch const&) = delete; - void operator=(nonesuch const&) = delete; -}; - -template class Op, - class... Args> -struct detector -{ - using value_t = std::false_type; - using type = Default; -}; - -template class Op, class... Args> -struct detector>, Op, Args...> -{ - using value_t = std::true_type; - using type = Op; -}; - -template