Add WIP Java language bindings

This commit is contained in:
Joseph Henry
2021-04-29 19:51:07 -07:00
parent 904e50e8e9
commit 782d221eb9
16 changed files with 3833 additions and 1074 deletions

757
build.sh
View File

@@ -8,47 +8,47 @@
CMAKE=cmake3 CMAKE=cmake3
if [[ $(which $CMAKE) = "" ]]; if [[ $(which $CMAKE) = "" ]];
then then
CMAKE=cmake # try this next CMAKE=cmake # try this next
fi fi
if [[ $(which $CMAKE) = "" ]]; if [[ $(which $CMAKE) = "" ]];
then then
echo "CMake (cmake) not found. Please install before continuing." echo "CMake (cmake) not found. Please install before continuing."
exit exit
fi fi
# #
if [[ ! $(which tree) = "" ]]; if [[ ! $(which tree) = "" ]];
then then
TREE=tree TREE=tree
else else
TREE="du -a " TREE="du -a "
fi fi
# Determine operating system # Determine operating system
OSNAME=$(uname | tr '[A-Z]' '[a-z]') OSNAME=$(uname | tr '[A-Z]' '[a-z]')
if [[ $OSNAME = *"darwin"* ]]; then if [[ $OSNAME = *"darwin"* ]]; then
SHARED_LIB_NAME="libzt.dylib" SHARED_LIB_NAME="libzt.dylib"
STATIC_LIB_NAME="libzt.a" STATIC_LIB_NAME="libzt.a"
HOST_PLATFORM="macos" HOST_PLATFORM="macos"
fi fi
if [[ $OSNAME = *"linux"* ]]; then if [[ $OSNAME = *"linux"* ]]; then
SHARED_LIB_NAME="libzt.so" SHARED_LIB_NAME="libzt.so"
STATIC_LIB_NAME="libzt.a" STATIC_LIB_NAME="libzt.a"
HOST_PLATFORM="linux" HOST_PLATFORM="linux"
fi fi
# Determine and normalize machine type # Determine and normalize machine type
HOST_MACHINE_TYPE=$(uname -m) HOST_MACHINE_TYPE=$(uname -m)
if [[ $HOST_MACHINE_TYPE = *"x86_64"* ]]; then if [[ $HOST_MACHINE_TYPE = *"x86_64"* ]]; then
HOST_MACHINE_TYPE="x64" HOST_MACHINE_TYPE="x64"
fi fi
# Determine number of cores. We'll tell CMake to use them all # Determine number of cores. We'll tell CMake to use them all
if [[ $OSNAME = *"darwin"* ]]; then if [[ $OSNAME = *"darwin"* ]]; then
N_PROCESSORS=$(sysctl -n hw.ncpu) N_PROCESSORS=$(sysctl -n hw.ncpu)
fi fi
if [[ $OSNAME = *"linux"* ]]; then if [[ $OSNAME = *"linux"* ]]; then
N_PROCESSORS=$(nproc --all) N_PROCESSORS=$(nproc --all)
fi fi
# How many processor cores CMake should use during builds, # How many processor cores CMake should use during builds,
@@ -63,7 +63,7 @@ function ver()
printf "%02d%02d%02d%02d" ${1//./ } printf "%02d%02d%02d%02d" ${1//./ }
} }
if [[ (( $(ver $CMAKE_VERSION) > $(ver "3.12") )) ]]; then if [[ (( $(ver $CMAKE_VERSION) > $(ver "3.12") )) ]]; then
BUILD_CONCURRENCY="-j $N_PROCESSORS" BUILD_CONCURRENCY="-j $N_PROCESSORS"
fi fi
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -87,7 +87,7 @@ DEFAULT_HOST_BUILD_CACHE_DIR=$BUILD_CACHE_DIR/$HOST_PLATFORM-$HOST_MACHINE_TYPE
gethosttype() gethosttype()
{ {
echo $HOST_PLATFORM-$HOST_MACHINE_TYPE echo $HOST_PLATFORM-$HOST_MACHINE_TYPE
} }
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
@@ -100,8 +100,8 @@ gethosttype()
# #
# Example output: # Example output:
# #
# - Cache : libzt/cache/apple-xcframework-debug # - Cache : libzt/cache/apple-xcframework-debug
# - Build output : libzt/dist # - Build output : libzt/dist
# #
# apple-xcframework-debug # apple-xcframework-debug
# └── pkg # └── pkg
@@ -119,36 +119,36 @@ gethosttype()
# #
xcframework() xcframework()
{ {
if [[ ! $OSNAME = *"darwin"* ]]; then if [[ ! $OSNAME = *"darwin"* ]]; then
echo "Can only build this on a Mac" echo "Can only build this on a Mac"
exit 0 exit 0
fi fi
BUILD_TYPE=${1:-release} BUILD_TYPE=${1:-release}
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}" UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
# Build all frameworks # Build all frameworks
macos-framework $BUILD_TYPE macos-framework $BUILD_TYPE
iphoneos-framework $BUILD_TYPE iphoneos-framework $BUILD_TYPE
iphonesimulator-framework $BUILD_TYPE iphonesimulator-framework $BUILD_TYPE
ARTIFACT="xcframework" ARTIFACT="xcframework"
TARGET_PLATFORM="apple" TARGET_PLATFORM="apple"
TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR mkdir -p $PKG_OUTPUT_DIR
MACOS_FRAMEWORK_DIR=macos-x64-framework-$BUILD_TYPE MACOS_FRAMEWORK_DIR=macos-x64-framework-$BUILD_TYPE
IOS_FRAMEWORK_DIR=iphoneos-arm64-framework-$BUILD_TYPE IOS_FRAMEWORK_DIR=iphoneos-arm64-framework-$BUILD_TYPE
IOS_SIM_FRAMEWORK_DIR=iphonesimulator-x64-framework-$BUILD_TYPE IOS_SIM_FRAMEWORK_DIR=iphonesimulator-x64-framework-$BUILD_TYPE
# Pack everything # Pack everything
rm -rf $PKG_OUTPUT_DIR/zt.xcframework # Remove prior to move to prevent error rm -rf $PKG_OUTPUT_DIR/zt.xcframework # Remove prior to move to prevent error
xcodebuild -create-xcframework \ xcodebuild -create-xcframework \
-framework $BUILD_CACHE_DIR/$MACOS_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \ -framework $BUILD_CACHE_DIR/$MACOS_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \
-framework $BUILD_CACHE_DIR/$IOS_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \ -framework $BUILD_CACHE_DIR/$IOS_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \
-framework $BUILD_CACHE_DIR/$IOS_SIM_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \ -framework $BUILD_CACHE_DIR/$IOS_SIM_FRAMEWORK_DIR/lib/$UPPERCASE_BUILD_TYPE/zt.framework \
-output $PKG_OUTPUT_DIR/zt.xcframework -output $PKG_OUTPUT_DIR/zt.xcframework
} }
# Build iOS framework # Build iOS framework
@@ -157,8 +157,8 @@ xcframework()
# #
# Example output: # Example output:
# #
# - Cache : libzt/cache/iphonesimulator-x64-framework-debug # - Cache : libzt/cache/iphonesimulator-x64-framework-debug
# - Build output : libzt/dist # - Build output : libzt/dist
# #
# libzt/dist/iphonesimulator-x64-framework-debug # libzt/dist/iphonesimulator-x64-framework-debug
# └── pkg # └── pkg
@@ -172,32 +172,32 @@ xcframework()
# #
iphonesimulator-framework() iphonesimulator-framework()
{ {
if [[ ! $OSNAME = *"darwin"* ]]; then if [[ ! $OSNAME = *"darwin"* ]]; then
echo "Can only build this on a Mac" echo "Can only build this on a Mac"
exit 0 exit 0
fi fi
ARTIFACT="framework" ARTIFACT="framework"
BUILD_TYPE=${1:-Release} BUILD_TYPE=${1:-Release}
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}" UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
VARIANT="-DBUILD_IOS_FRAMEWORK=True" VARIANT="-DBUILD_IOS_FRAMEWORK=True"
TARGET_PLATFORM="iphonesimulator" TARGET_PLATFORM="iphonesimulator"
TARGET_MACHINE_TYPE="x64" # presumably TARGET_MACHINE_TYPE="x64" # presumably
CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR mkdir -p $PKG_OUTPUT_DIR
# Generate project # Generate project
mkdir -p $CACHE_DIR mkdir -p $CACHE_DIR
cd $CACHE_DIR cd $CACHE_DIR
# iOS (SDK 11+, 64-bit only, arm64) # iOS (SDK 11+, 64-bit only, arm64)
$CMAKE -G Xcode ../../ $VARIANT $CMAKE -G Xcode ../../ $VARIANT
# Build framework # Build framework
xcodebuild -target zt -configuration "$UPPERCASE_BUILD_TYPE" -sdk "iphonesimulator" xcodebuild -target zt -configuration "$UPPERCASE_BUILD_TYPE" -sdk "iphonesimulator"
cd - cd -
cp -rf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR cp -rf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $TREE $TARGET_BUILD_DIR
} }
# Build macOS framework # Build macOS framework
@@ -206,8 +206,8 @@ iphonesimulator-framework()
# #
# Example output: # Example output:
# #
# - Cache : libzt/cache/macos-x64-framework-debug # - Cache : libzt/cache/macos-x64-framework-debug
# - Build output : libzt/dist # - Build output : libzt/dist
# #
# libzt/dist/macos-x64-framework-debug # libzt/dist/macos-x64-framework-debug
# └── pkg # └── pkg
@@ -221,29 +221,29 @@ iphonesimulator-framework()
# #
macos-framework() macos-framework()
{ {
if [[ ! $OSNAME = *"darwin"* ]]; then if [[ ! $OSNAME = *"darwin"* ]]; then
echo "Can only build this on a Mac" echo "Can only build this on a Mac"
exit 0 exit 0
fi fi
ARTIFACT="framework" ARTIFACT="framework"
BUILD_TYPE=${1:-Release} BUILD_TYPE=${1:-Release}
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}" UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
VARIANT="-DBUILD_MACOS_FRAMEWORK=True" VARIANT="-DBUILD_MACOS_FRAMEWORK=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR mkdir -p $PKG_OUTPUT_DIR
# Generate project # Generate project
mkdir -p $CACHE_DIR mkdir -p $CACHE_DIR
cd $CACHE_DIR cd $CACHE_DIR
$CMAKE -G Xcode ../../ $VARIANT $CMAKE -G Xcode ../../ $VARIANT
# Build framework # Build framework
xcodebuild -target zt -configuration $UPPERCASE_BUILD_TYPE -sdk "macosx" xcodebuild -target zt -configuration $UPPERCASE_BUILD_TYPE -sdk "macosx"
cd - cd -
cp -rf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR cp -rf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $TREE $TARGET_BUILD_DIR
} }
# Build iOS framework # Build iOS framework
@@ -252,8 +252,8 @@ macos-framework()
# #
# Example output: # Example output:
# #
# - Cache : libzt/cache/iphoneos-arm64-framework-debug # - Cache : libzt/cache/iphoneos-arm64-framework-debug
# - Build output : libzt/dist # - Build output : libzt/dist
# #
# libzt/dist/iphoneos-arm64-framework-debug # libzt/dist/iphoneos-arm64-framework-debug
# └── pkg # └── pkg
@@ -267,33 +267,33 @@ macos-framework()
# #
iphoneos-framework() iphoneos-framework()
{ {
if [[ ! $OSNAME = *"darwin"* ]]; then if [[ ! $OSNAME = *"darwin"* ]]; then
echo "Can only build this on a Mac" echo "Can only build this on a Mac"
exit 0 exit 0
fi fi
ARTIFACT="framework" ARTIFACT="framework"
BUILD_TYPE=${1:-Release} BUILD_TYPE=${1:-Release}
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}" UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
VARIANT="-DBUILD_IOS_FRAMEWORK=True -DIOS_ARM64=True" VARIANT="-DBUILD_IOS_FRAMEWORK=True -DIOS_ARM64=True"
TARGET_PLATFORM="iphoneos" TARGET_PLATFORM="iphoneos"
TARGET_MACHINE_TYPE=arm64 TARGET_MACHINE_TYPE=arm64
CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR mkdir -p $PKG_OUTPUT_DIR
# Generate project # Generate project
mkdir -p $CACHE_DIR mkdir -p $CACHE_DIR
cd $CACHE_DIR cd $CACHE_DIR
# iOS (SDK 11+, 64-bit only, arm64) # iOS (SDK 11+, 64-bit only, arm64)
$CMAKE -G Xcode ../../ $VARIANT $CMAKE -G Xcode ../../ $VARIANT
sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj sed -i '' 's/x86_64/$(CURRENT_ARCH)/g' zt.xcodeproj/project.pbxproj
# Build framework # Build framework
xcodebuild -arch $TARGET_MACHINE_TYPE -target zt -configuration "$UPPERCASE_BUILD_TYPE" -sdk "iphoneos" xcodebuild -arch $TARGET_MACHINE_TYPE -target zt -configuration "$UPPERCASE_BUILD_TYPE" -sdk "iphoneos"
cd - cd -
cp -rvf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR cp -rvf $CACHE_DIR/lib/$UPPERCASE_BUILD_TYPE/*.framework $PKG_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $TREE $TARGET_BUILD_DIR
} }
# Build standard libraries, examples, and selftest # Build standard libraries, examples, and selftest
@@ -302,8 +302,8 @@ iphoneos-framework()
# #
# Example output: # Example output:
# #
# - Cache : libzt/cache/linux-x64-host-release # - Cache : libzt/cache/linux-x64-host-release
# - Build output : libzt/dist # - Build output : libzt/dist
# #
# linux-x64-host-release # linux-x64-host-release
# ├── bin # ├── bin
@@ -315,35 +315,35 @@ iphoneos-framework()
# #
host() host()
{ {
ARTIFACT="host" ARTIFACT="host"
# Default to release # Default to release
BUILD_TYPE=${1:-release} BUILD_TYPE=${1:-release}
VARIANT="-DBUILD_HOST=True" VARIANT="-DBUILD_HOST=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
mkdir -p $LIB_OUTPUT_DIR mkdir -p $LIB_OUTPUT_DIR
mkdir -p $BIN_OUTPUT_DIR mkdir -p $BIN_OUTPUT_DIR
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY $CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR
cp -f $CACHE_DIR/bin/* $BIN_OUTPUT_DIR cp -f $CACHE_DIR/bin/* $BIN_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $TREE $TARGET_BUILD_DIR
} }
host-install() host-install()
{ {
cd cache/$HOST_PLATFORM-$HOST_MACHINE_TYPE-host-$1/ cd cache/$HOST_PLATFORM-$HOST_MACHINE_TYPE-host-$1/
make install make install
cd - cd -
} }
host-uninstall() host-uninstall()
{ {
cd cache/$HOST_PLATFORM-$HOST_MACHINE_TYPE-host-$1/ cd cache/$HOST_PLATFORM-$HOST_MACHINE_TYPE-host-$1/
xargs rm < install_manifest.txt xargs rm < install_manifest.txt
cd - cd -
} }
# Build C extension module (*.so), python module, package both into wheel # Build C extension module (*.so), python module, package both into wheel
@@ -358,98 +358,117 @@ host-uninstall()
# #
host-python-wheel() host-python-wheel()
{ {
ARTIFACT="python" ARTIFACT="python"
# Default to release # Default to release
BUILD_TYPE=${1:-release} BUILD_TYPE=${1:-release}
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR mkdir -p $PKG_OUTPUT_DIR
# Requires setuptools, etc # Requires setuptools, etc
cd pkg/pypi && ./build.sh wheel && cp -f dist/*.whl $PKG_OUTPUT_DIR cd pkg/pypi && ./build.sh wheel && cp -f dist/*.whl $PKG_OUTPUT_DIR
} }
# Build shared library with python wrapper symbols exported # Build shared library with python wrapper symbols exported
host-python() host-python()
{ {
ARTIFACT="python" ARTIFACT="python"
# Default to release # Default to release
BUILD_TYPE=${1:-release} BUILD_TYPE=${1:-release}
VARIANT="-DZTS_ENABLE_PYTHON=True" VARIANT="-DZTS_ENABLE_PYTHON=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
rm -rf $LIB_OUTPUT_DIR rm -rf $LIB_OUTPUT_DIR
mkdir -p $LIB_OUTPUT_DIR mkdir -p $LIB_OUTPUT_DIR
# Optional step to generate new SWIG wrapper # Optional step to generate new SWIG wrapper
swig -c++ -python -o src/bindings/python/zt_wrap.cxx -Iinclude src/bindings/python/zt.i swig -c++ -python -o src/bindings/python/zt_wrap.cxx -Iinclude src/bindings/python/zt.i
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY $CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
cp -f $CACHE_DIR/lib/$SHARED_LIB_NAME $LIB_OUTPUT_DIR/_libzt.so cp -f $CACHE_DIR/lib/$SHARED_LIB_NAME $LIB_OUTPUT_DIR/_libzt.so
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $TREE $TARGET_BUILD_DIR
} }
# Build shared library with P/INVOKE wrapper symbols exported # Build shared library with P/INVOKE wrapper symbols exported
host-pinvoke() host-pinvoke()
{ {
ARTIFACT="pinvoke" ARTIFACT="pinvoke"
# Default to release # Default to release
BUILD_TYPE=${1:-release} BUILD_TYPE=${1:-release}
VARIANT="-DZTS_ENABLE_PINVOKE=True" VARIANT="-DZTS_ENABLE_PINVOKE=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
mkdir -p $LIB_OUTPUT_DIR mkdir -p $LIB_OUTPUT_DIR
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY $CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR cp -f $CACHE_DIR/lib/libzt.* $LIB_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $TREE $TARGET_BUILD_DIR
} }
# Build shared library with Java JNI wrapper symbols exported (.jar) # Build shared library with Java JNI wrapper symbols exported (.jar)
host-jar() host-jar()
{ {
ARTIFACT="jar" ARTIFACT="jar"
# Default to release # Default to release
BUILD_TYPE=${1:-release} BUILD_TYPE=${1:-release}
if [[ $1 = *"docs"* ]]; then if [[ $1 = *"docs"* ]]; then
# Generate documentation # Generate documentation
javadoc src/bindings/java/*.java -d docs/java javadoc src/bindings/java/*.java -d docs/java
exit 0 exit 0
fi fi
VARIANT="-DZTS_ENABLE_JAVA=True" VARIANT="-DZTS_ENABLE_JAVA=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
mkdir -p $PKG_OUTPUT_DIR mkdir -p $PKG_OUTPUT_DIR
# Share same cache dir with CMake # Share same cache dir with CMake
JAVA_JAR_DIR=$CACHE_DIR/pkg/jar JAVA_JAR_DIR=$CACHE_DIR/pkg/jar
JAVA_JAR_SOURCE_TREE_DIR=$JAVA_JAR_DIR/com/zerotier/libzt/ JAVA_JAR_SOURCE_TREE_DIR=$JAVA_JAR_DIR/com/zerotier/sdk/
mkdir -p $JAVA_JAR_SOURCE_TREE_DIR mkdir -p $JAVA_JAR_SOURCE_TREE_DIR
cp -f src/bindings/java/*.java $JAVA_JAR_SOURCE_TREE_DIR cp -f src/bindings/java/*.java $JAVA_JAR_SOURCE_TREE_DIR
# Build # Build
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY $CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
# Package everything # Package everything
cp -f $CACHE_DIR/lib/libzt.* $JAVA_JAR_DIR cp -f $CACHE_DIR/lib/libzt.* $JAVA_JAR_DIR
cd $JAVA_JAR_DIR cd $JAVA_JAR_DIR
export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8 export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
javac -Xlint:deprecation com/zerotier/libzt/*.java javac -Xlint:deprecation com/zerotier/sdk/*.java
jar cf libzt-"$(git describe --abbrev=0)".jar $SHARED_LIB_NAME com/zerotier/libzt/*.class jar cf libzt-"$(git describe --abbrev=0)".jar $SHARED_LIB_NAME com/zerotier/sdk/*.class
rm -rf com $SHARED_LIB_NAME rm -rf com $SHARED_LIB_NAME
cd - cd -
# Copy JAR to dist/ # Copy JAR to dist/
echo -e "\nContents of JAR:\n" echo -e "\nContents of JAR:\n"
jar tf $JAVA_JAR_DIR/*.jar jar tf $JAVA_JAR_DIR/*.jar
echo -e echo -e
mv $JAVA_JAR_DIR/*.jar $PKG_OUTPUT_DIR mv $JAVA_JAR_DIR/*.jar $PKG_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $TREE $TARGET_BUILD_DIR
# Test JAR
if [[ $2 = *"test"* ]]; then
if [[ -z "${alice_path}" ]]; then
echo "Please set necessary environment variables for test"
exit 0
fi
cd test
rm -rf *.dylib
rm -rf *.jar
cp -f $PKG_OUTPUT_DIR/*.jar .
# Unpack JAR to get access to shared library
jar xf *.jar libzt.dylib
javac -cp *.jar selftest.java
# Start Alice as server
java -cp ".:libzt-"$(git describe --abbrev=0)".jar" selftest server $alice_path $testnet $port4 &
# Start Bob as client
java -cp ".:libzt-"$(git describe --abbrev=0)".jar" selftest client $bob_path $testnet $alice_ip4 $port4 &
fi
} }
@@ -463,13 +482,12 @@ ANDROID_PKG_PROJ_DIR=$(pwd)/pkg/android
#export PATH=/Library/Java/JavaVirtualMachines/$JDK/Contents/Home/bin/:${PATH} #export PATH=/Library/Java/JavaVirtualMachines/$JDK/Contents/Home/bin/:${PATH}
#export PATH=/Users/$USER/Library/Android/sdk/platform-tools/:${PATH} #export PATH=/Users/$USER/Library/Android/sdk/platform-tools/:${PATH}
GRADLE_ARGS=--stacktrace GRADLE_ARGS=--stacktrace
#ANDROID_APP_NAME=com.example.mynewestapplication
# for our purposes we limit this to execution on macOS # for our purposes we limit this to execution on macOS
if [[ $OSNAME = *"linux"* ]]; then if [[ $OSNAME = *"linux"* ]]; then
export ANDROID_HOME=/usr/lib/android-sdk/ export ANDROID_HOME=/usr/lib/android-sdk/
fi fi
if [[ $OSNAME = *"darwin"* ]]; then if [[ $OSNAME = *"darwin"* ]]; then
export ANDROID_HOME=/Users/$USER/Library/Android/sdk export ANDROID_HOME=/Users/$USER/Library/Android/sdk
fi fi
# Build shared library with Java JNI wrapper symbols exported (.aar) # Build shared library with Java JNI wrapper symbols exported (.aar)
@@ -478,179 +496,182 @@ fi
# #
# Example output: # Example output:
# #
# - Cache : libzt/cache/android-any-android-release # - Cache : libzt/cache/android-any-android-release
# - Build output : libzt/dist # - Build output : libzt/dist
# #
# android-any-android-release # android-any-android-release
# └── libzt-release.aar # └── libzt-release.aar
# #
android-aar() android-aar()
{ {
ARTIFACT="android" ARTIFACT="android"
BUILD_TYPE=${1:-release} # Default to release BUILD_TYPE=${1:-release} # Default to release
CMAKE_SWITCH="ZTS_ENABLE_JAVA" CMAKE_SWITCH="ZTS_ENABLE_JAVA"
TARGET_PLATFORM="android" TARGET_PLATFORM="android"
TARGET_MACHINE_TYPE=any TARGET_MACHINE_TYPE=any
CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$BUILD_CACHE_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
PKG_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE PKG_OUTPUT_DIR=$BUILD_OUTPUT_DIR/$TARGET_PLATFORM-$TARGET_MACHINE_TYPE-$ARTIFACT-$BUILD_TYPE
mkdir -p $CACHE_DIR mkdir -p $CACHE_DIR
mkdir -p $PKG_OUTPUT_DIR mkdir -p $PKG_OUTPUT_DIR
# Unsure why, but Gradle's build script chokes on this non-source file now # Unsure why, but Gradle's build script chokes on this non-source file now
rm -rf ext/ZeroTierOne/ext/miniupnpc/VERSION rm -rf ext/ZeroTierOne/ext/miniupnpc/VERSION
export PATH=$ANDROID_HOME/cmdline-tools/tools/bin:$PATH export PATH=$ANDROID_HOME/cmdline-tools/tools/bin:$PATH
# Copy source files into project # Copy source files into project
cp -f src/bindings/java/*.java ${ANDROID_PKG_PROJ_DIR}/app/src/main/java/com/zerotier/libzt cp -f src/bindings/java/*.java ${ANDROID_PKG_PROJ_DIR}/app/src/main/java/com/zerotier/libzt
# Build # Build
UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}" UPPERCASE_BUILD_TYPE="$(tr '[:lower:]' '[:upper:]' <<< ${BUILD_TYPE:0:1})${BUILD_TYPE:1}"
CMAKE_FLAGS="-D${CMAKE_SWITCH}=1 -D${CMAKE_SWITCH}=ON" CMAKE_FLAGS="-D${CMAKE_SWITCH}=1 -D${CMAKE_SWITCH}=ON"
cd $ANDROID_PKG_PROJ_DIR cd $ANDROID_PKG_PROJ_DIR
./gradlew $GRADLE_ARGS assemble$UPPERCASE_BUILD_TYPE # assembleRelease / assembleDebug ./gradlew $GRADLE_ARGS assemble$UPPERCASE_BUILD_TYPE # assembleRelease / assembleDebug
mv $ANDROID_PKG_PROJ_DIR/app/build/outputs/aar/*.aar \ mv $ANDROID_PKG_PROJ_DIR/app/build/outputs/aar/*.aar \
$PKG_OUTPUT_DIR/libzt-$BUILD_TYPE.aar $PKG_OUTPUT_DIR/libzt-$BUILD_TYPE.aar
cd - cd -
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $PKG_OUTPUT_DIR $TREE $PKG_OUTPUT_DIR
} }
# Build static library and selftest. Currently this only tests # Build static library and selftest. Currently this only tests
# the core C API, not any of the language bindings. # the core C API, not any of the language bindings.
test() test()
{ {
ARTIFACT="test" ARTIFACT="test"
# Default to release # Default to release
BUILD_TYPE=${1:-release} BUILD_TYPE=${1:-release}
VARIANT="-DBUILD_HOST_SELFTEST_ONLY=True" VARIANT="-DBUILD_HOST_SELFTEST_ONLY=True"
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
mkdir -p $BIN_OUTPUT_DIR mkdir -p $BIN_OUTPUT_DIR
$CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE $CMAKE $VARIANT -H. -B$CACHE_DIR -DCMAKE_BUILD_TYPE=$BUILD_TYPE
$CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY $CMAKE --build $CACHE_DIR $BUILD_CONCURRENCY
cp -f $CACHE_DIR/bin/* $BIN_OUTPUT_DIR cp -f $CACHE_DIR/bin/* $BIN_OUTPUT_DIR
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n" echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
$TREE $TARGET_BUILD_DIR $TREE $TARGET_BUILD_DIR
# Test # Test
cd $CACHE_DIR cd $CACHE_DIR
#ctest -C release #ctest -C release
cd - cd -
} }
format-code() format-code()
{ {
if [[ ! $(which clang-format) = "" ]]; if [[ ! $(which clang-format) = "" ]];
then then
# Eventually: find . -path ./ext -prune -false -o -type f \( -iname \*.c -o -iname \*.h -o -iname \*.cpp -o -iname \*.hpp \) -exec clang-format -i {} \; # Eventually: find . -path ./ext -prune -false -o -type f \( -iname \*.c -o -iname \*.h -o -iname \*.cpp -o -iname \*.hpp \) -exec clang-format -i {} \;
clang-format -i include/*.h \ clang-format -i include/*.h \
src/*.c \ src/*.c \
src/*.cpp \ src/*.cpp \
src/*.hpp \ src/*.hpp \
examples/c/*.c \ examples/c/*.c \
test/*.c \ examples/csharp/*.cs \
src/bindings/csharp/*.cs \ examples/java/*.java \
src/bindings/csharp/*.cxx \ test/*.c \
examples/csharp/*.cs test/*.cs \
return 0 src/bindings/csharp/*.cs \
else src/bindings/csharp/*.cxx \
echo "Please install clang-format." src/bindings/java/*.java \
fi src/bindings/java/*.cxx \
examples/csharp/*.cs
return 0
else
echo "Please install clang-format."
fi
} }
# Test C API # Test C API
test-c() test-c()
{ {
if [[ -z "${alice_path}" ]]; then if [[ -z "${alice_path}" ]]; then
echo "Please set necessary environment variables for test" echo "Please set necessary environment variables for test"
#exit 0 #exit 0
fi fi
BUILD_TYPE=${1:-debug} BUILD_TYPE=${1:-debug}
test $BUILD_TYPE #BUILD_TYPE="ASAN"
# Build selftest # Build selftest
#test $BUILD_TYPE test $BUILD_TYPE
# Clear logs # Start Alice as server
rm -rf test/*.txt "$BIN_OUTPUT_DIR/selftest-c" $alice_path $testnet $port4 $port6 &
# Start Alice as server # Start Bob as client
echo "$BIN_OUTPUT_DIR/selftest-c" $alice_path $testnet $port4 $port6 & "$BIN_OUTPUT_DIR/selftest-c" $bob_path $testnet $port4 $alice_ip4 $port6 $alice_ip6 &
# Start Bob as client
echo "$BIN_OUTPUT_DIR/selftest-c" $bob_path $testnet $port4 $alice_ip4 $port6 $alice_ip6 &
} }
# Test C# API # Test C# API
test-cs() test-cs()
{ {
if [[ -z "${alice_path}" ]]; then if [[ -z "${alice_path}" ]]; then
echo "Please set necessary environment variables for test" echo "Please set necessary environment variables for test"
exit 0 exit 0
fi fi
ARTIFACT="pinvoke" ARTIFACT="pinvoke"
# Default to debug so asserts aren't optimized out # Default to debug so asserts aren't optimized out
BUILD_TYPE=${1:-debug} BUILD_TYPE=${1:-debug}
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin BIN_OUTPUT_DIR=$TARGET_BUILD_DIR/bin
rm -rf $TARGET_BUILD_DIR rm -rf $TARGET_BUILD_DIR
# Build C shared library exporting C# symbols # Build C shared library exporting C# symbols
host-pinvoke $1 host-pinvoke $1
# TODO: This should eventually be converted to a proper dotnet project # TODO: This should eventually be converted to a proper dotnet project
# Build C# managed API library # Build C# managed API library
csc -target:library -doc:$LIB_OUTPUT_DIR/ZeroTier.Sockets.xml -out:$LIB_OUTPUT_DIR/ZeroTier.Sockets.dll src/bindings/csharp/*.cs csc -target:library -doc:$LIB_OUTPUT_DIR/ZeroTier.Sockets.xml -out:$LIB_OUTPUT_DIR/ZeroTier.Sockets.dll src/bindings/csharp/*.cs
# Build selftest # Build selftest
mkdir -p $BIN_OUTPUT_DIR mkdir -p $BIN_OUTPUT_DIR
csc -out:$BIN_OUTPUT_DIR/selftest.exe -reference:$LIB_OUTPUT_DIR/ZeroTier.Sockets.dll test/selftest.cs csc -out:$BIN_OUTPUT_DIR/selftest.exe -reference:$LIB_OUTPUT_DIR/ZeroTier.Sockets.dll test/selftest.cs
# Copy shared libraries into bin directory so they can be discovered by dlopen # Copy shared libraries into bin directory so they can be discovered by dlopen
cp $LIB_OUTPUT_DIR/* $BIN_OUTPUT_DIR cp $LIB_OUTPUT_DIR/* $BIN_OUTPUT_DIR
# Start Alice as server # Start Alice as server
mono --debug "$BIN_OUTPUT_DIR/selftest.exe" $alice_path $testnet $port4 $port6 & mono --debug "$BIN_OUTPUT_DIR/selftest.exe" $alice_path $testnet $port4 $port6 &
sleep 10 sleep 10
# Start Bob as client # Start Bob as client
mono --debug "$BIN_OUTPUT_DIR/selftest.exe" $bob_path $testnet $port4 $alice_ip4 $port6 $alice_ip6 & mono --debug "$BIN_OUTPUT_DIR/selftest.exe" $bob_path $testnet $port4 $alice_ip4 $port6 $alice_ip6 &
} }
# Recursive deep clean # Recursive deep clean
clean() clean()
{ {
# Finished artifacts # Finished artifacts
rm -rf $BUILD_OUTPUT_DIR rm -rf $BUILD_OUTPUT_DIR
# CMake's build system cache # CMake's build system cache
rm -rf $BUILD_CACHE_DIR rm -rf $BUILD_CACHE_DIR
# CMake test output # CMake test output
rm -rf bin rm -rf bin
rm -rf Testing rm -rf Testing
rm -rf CMakeFiles rm -rf CMakeFiles
rm -rf *.cmake rm -rf *.cmake
rm -rf CMakeCache.txt rm -rf CMakeCache.txt
rm -rf Makefile rm -rf Makefile
# Android AAR project binaries and sources (copied from src/bindings/java) # Android AAR project binaries and sources (copied from src/bindings/java)
rm -rf $ANDROID_PKG_PROJ_DIR/app/build rm -rf $ANDROID_PKG_PROJ_DIR/app/build
rm -rf $ANDROID_PKG_PROJ_DIR/app/src/main/java/com/zerotier/libzt/*.java rm -rf $ANDROID_PKG_PROJ_DIR/app/src/main/java/com/zerotier/libzt/*.java
rm -rf $ANDROID_PKG_PROJ_DIR/app/.externalNativeBuild rm -rf $ANDROID_PKG_PROJ_DIR/app/.externalNativeBuild
# Remove whatever remains # Remove whatever remains
find . \ find . \
\( -name '*.dylib' \ \( -name '*.dylib' \
-o -name '*.dll' \ -o -name '*.dll' \
-o -name '*.aar' \ -o -name '*.aar' \
-o -name '*.jar' \ -o -name '*.jar' \
-o -name '*.so' \ -o -name '*.so' \
-o -name '*.a' \ -o -name '*.a' \
-o -name '*.o' \ -o -name '*.o' \
-o -name '*.exe' \ -o -name '*.exe' \
-o -name '*.o.d' \ -o -name '*.o.d' \
-o -name '*.out' \ -o -name '*.out' \
-o -name '*.log' \ -o -name '*.log' \
-o -name '*.dSYM' \ -o -name '*.dSYM' \
-o -name '*.class' \ -o -name '*.class' \
\) -exec rm -rf {} + \) -exec rm -rf {} +
find . -type d -name "__pycache__" -exec rm -rf {} + find . -type d -name "__pycache__" -exec rm -rf {} +
} }
list() list()
{ {
IFS=$'\n' IFS=$'\n'
for f in $(declare -F); do for f in $(declare -F); do
echo "${f:11}" echo "${f:11}"
done done
} }
"$@" "$@"

View File

@@ -1,161 +1,138 @@
//package com.zerotier.libzt.javasimpleexample; import com.zerotier.sdk.*;
import java.io.DataInputStream;
import com.zerotier.libzt.ZeroTier; import java.io.DataOutputStream;
import com.zerotier.libzt.ZeroTierEventListener;
import java.math.BigInteger; import java.math.BigInteger;
public class Example { public class selftest {
public static void main(String[] args)
{
System.err.println(args.length);
if (args.length < 4 || args.length > 5) {
System.err.println("Invalid arguments");
System.err.println(" Usage: <server|client> <id_path> <network> <addr> <port>");
System.err.println(" example server ./ 0123456789abcdef 8080");
System.err.println(" example client ./ 0123456789abcdef 192.168.22.1 8080\n");
System.exit(1);
}
static void sleep(int ms) { String storagePath = "";
try { String remoteAddr = "";
Thread.sleep(ms); int port = 0;
} catch (InterruptedException e) { String mode = args[0];
e.printStackTrace(); storagePath = args[1];
} BigInteger networkId = new BigInteger(args[2], 16);
} if (args.length == 4) {
port = Integer.parseInt(args[3]);
}
if (args.length == 5) {
remoteAddr = args[3];
port = Integer.parseInt(args[4]);
}
System.out.println("mode = " + mode);
System.out.println("networkId = " + Long.toHexString(networkId.longValue()));
System.out.println("storagePath = " + storagePath);
System.out.println("remoteAddr = " + remoteAddr);
System.out.println("port = " + port);
public static void main(String[] args) { // ZeroTier setup
String keyPath="."; // Default to current directory
BigInteger networkId;
Integer servicePort=0;
if (args.length != 3) {
System.err.println(" Invalid arguments");
System.err.println(" Usage: example <path_to_write_keys> <nwid> <ztServicePort>");
System.exit(1);
}
keyPath = args[0];
networkId = new BigInteger(args[1], 16);
servicePort = Integer.parseInt(args[2]);
System.out.println("networkId = " + Long.toHexString(networkId.longValue()));
System.out.println("keyPath = " + keyPath);
System.out.println("servicePort = " + servicePort);
// ZeroTierNode node = new ZeroTierNode();
// BEGIN SETUP
//
// Set up event listener and start service node.initFromStorage(storagePath);
MyZeroTierEventListener listener = new MyZeroTierEventListener(); // node.initSetEventHandler(new MyZeroTierEventListener());
ZeroTier.start(keyPath, (ZeroTierEventListener)listener, servicePort); // node.initSetPort(9994);
// Wait for EVENT_NODE_ONLINE node.start();
System.out.println("waiting for node to come online...");
while (listener.isOnline == false) { sleep(50); }
System.out.println("joining network");
ZeroTier.join(networkId.longValue());
// Wait for EVENT_NETWORK_READY_IP4/6
System.out.println("waiting for network config...");
while (listener.isNetworkReady == false) { sleep(50); }
System.out.println("joined");
// System.out.println("Waiting for node to come online...");
// END SETUP while (! node.isOnline()) {
// ZeroTierNative.zts_util_delay(50);
}
System.out.println("Node ID: " + Long.toHexString(node.getId()));
System.out.println("Joining network...");
node.join(networkId.longValue());
System.out.println("Waiting for network...");
while (! node.isNetworkTransportReady(networkId.longValue())) {
ZeroTierNative.zts_util_delay(50);
}
System.out.println("joined");
sleep(120000); // Socket logic
/** if (mode.equals("server")) {
* System.out.println("Starting server...");
* Begin using socket API after this point: try {
* ZeroTierSocket socket =
* ZeroTier.ZeroTierSocket, ZeroTier.ZeroTierSocketFactory, etc new ZeroTierSocket(ZeroTierNative.ZTS_AF_INET, ZeroTierNative.ZTS_SOCK_STREAM, 0);
* socket.bind("0.0.0.0", port);
* (or) socket.listen(100);
* ZeroTierSocket newConnection = socket.accept();
* ZeroTier.socket(), ZeroTier.connect(), etc ZeroTierInputStream inputStream = newConnection.getInputStream();
*/ DataInputStream dataInputStream = new DataInputStream(inputStream);
} String message = dataInputStream.readUTF();
System.out.println("recv: " + message);
socket.close();
newConnection.close();
}
catch (Exception ex) {
System.out.println(ex);
}
}
if (mode.equals("client")) {
System.out.println("Starting client...");
try {
ZeroTierSocket socket =
new ZeroTierSocket(ZeroTierNative.ZTS_AF_INET, ZeroTierNative.ZTS_SOCK_STREAM, 0);
socket.connect(remoteAddr, port);
ZeroTierOutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF("Hello from java!");
socket.close();
}
catch (Exception ex) {
System.out.println(ex);
}
}
}
} }
/** /**
* Example event handling * (OPTIONAL) event handler
*/ */
class MyZeroTierEventListener implements ZeroTierEventListener {
public boolean isNetworkReady = false;
public boolean isOnline = false;
public void onZeroTierEvent(long id, int eventCode) {
if (eventCode == ZeroTier.EVENT_NODE_UP) {
System.out.println("EVENT_NODE_UP: nodeId=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NODE_ONLINE) {
// The core service is running properly and can join networks now
System.out.println("EVENT_NODE_ONLINE: nodeId=" + Long.toHexString(id));
isOnline = true;
}
if (eventCode == ZeroTier.EVENT_NODE_OFFLINE) {
// Network does not seem to be reachable by any available strategy
System.out.println("EVENT_NODE_OFFLINE");
}
if (eventCode == ZeroTier.EVENT_NODE_DOWN) {
// Called when the node is shutting down
System.out.println("EVENT_NODE_DOWN");
}
if (eventCode == ZeroTier.EVENT_NODE_IDENTITY_COLLISION) {
// Another node with this identity already exists
System.out.println("EVENT_NODE_IDENTITY_COLLISION");
}
if (eventCode == ZeroTier.EVENT_NODE_UNRECOVERABLE_ERROR) {
// Try again
System.out.println("EVENT_NODE_UNRECOVERABLE_ERROR");
}
if (eventCode == ZeroTier.EVENT_NODE_NORMAL_TERMINATION) {
// Normal closure
System.out.println("EVENT_NODE_NORMAL_TERMINATION");
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP4) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP4: nwid=" + Long.toHexString(id));
isNetworkReady = true;
}
if (eventCode == ZeroTier.EVENT_NETWORK_READY_IP6) {
// We have at least one assigned address and we've received a network configuration
System.out.println("ZTS_EVENT_NETWORK_READY_IP6: nwid=" + Long.toHexString(id));
//isNetworkReady = true;
}
if (eventCode == ZeroTier.EVENT_NETWORK_DOWN) {
// Someone called leave(), we have no assigned addresses, or otherwise cannot use this interface
System.out.println("EVENT_NETWORK_DOWN: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_REQ_CONFIG) {
// Waiting for network configuration
System.out.println("EVENT_NETWORK_REQ_CONFIG: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_OK) {
// Config received and this node is authorized for this network
System.out.println("EVENT_NETWORK_OK: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_ACCESS_DENIED) {
// You are not authorized to join this network
System.out.println("EVENT_NETWORK_ACCESS_DENIED: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_NOT_FOUND) {
// The virtual network does not exist
System.out.println("EVENT_NETWORK_NOT_FOUND: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_NETWORK_CLIENT_TOO_OLD) {
// The core version is too old
System.out.println("EVENT_NETWORK_CLIENT_TOO_OLD: nwid=" + Long.toHexString(id));
}
if (eventCode == ZeroTier.EVENT_PEER_DIRECT) {
System.out.println("EVENT_PEER_DIRECT: id=" + Long.toHexString(id));
/* /*
ZeroTierPeerDetails details = new ZeroTierPeerDetails(); class MyZeroTierEventListener implements ZeroTierEventListener {
ZeroTier.get_peer(id, details); public void onZeroTierEvent(long id, int event_code)
System.out.println("address="+Long.toHexString(details.address)); {
System.out.println("pathCount="+details.pathCount); if (event_code == ZeroTierNative.ZTS_EVENT_NODE_UP) {
System.out.println("version="+details.versionMajor+"."+details.versionMinor+"."+details.versionRev); System.out.println("EVENT_NODE_UP");
System.out.println("latency="+details.latency); // Not relevant }
System.out.println("role="+details.role); // Not relevent if (event_code == ZeroTierNative.ZTS_EVENT_NODE_ONLINE) {
// Print all known paths System.out.println("EVENT_NODE_ONLINE: " + Long.toHexString(id));
for (int i=0; i<details.pathCount; i++) { }
System.out.println("addr="+details.paths[i].toString()); if (event_code == ZeroTierNative.ZTS_EVENT_NODE_OFFLINE) {
} System.out.println("EVENT_NODE_OFFLINE");
*/ }
} if (event_code == ZeroTierNative.ZTS_EVENT_NODE_DOWN) {
if (eventCode == ZeroTier.EVENT_PEER_RELAY) { System.out.println("EVENT_NODE_DOWN");
System.out.println("EVENT_PEER_RELAY: id=" + Long.toHexString(id)); }
} if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_READY_IP4) {
} System.out.println("ZTS_EVENT_NETWORK_READY_IP4: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_READY_IP6) {
System.out.println("ZTS_EVENT_NETWORK_READY_IP6: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_DOWN) {
System.out.println("EVENT_NETWORK_DOWN: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_OK) {
System.out.println("EVENT_NETWORK_OK: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_ACCESS_DENIED) {
System.out.println("EVENT_NETWORK_ACCESS_DENIED: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_NOT_FOUND) {
System.out.println("EVENT_NETWORK_NOT_FOUND: " + Long.toHexString(id));
}
}
} }
*/

View File

@@ -1,9 +1,9 @@
# Java example # Java example
1). Build or download the `zt-1.3.3.jar`, copy it to this directory 1). Build or download the `libzt-1.3.3.jar`, copy it to this directory
2). Run `make` 2). Run `make`
3). `java -cp ".:zt-1.3.3.jar" Example id_path 0123456789abcdef 9997` 3). `java -cp ".:libzt-1.3.3.jar" Example id_path 0123456789abcdef 9997`
See [src/bindings/java](../../src/bindings/java) for wrapper implementation code. See [src/bindings/java](../../src/bindings/java) for wrapper implementation code.

View File

@@ -1,557 +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: 2025-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
/**
* @file
*
* ZeroTier Socket API
*/
#ifdef ZTS_ENABLE_JAVA
#include "lwip/sockets.h"
#include "lwip/def.h"
#include "lwip/inet.h"
#include "lwip/stats.h"
#include "ZeroTierSockets.h"
#define ZTS_STATE_NODE_RUNNING 0x01
#define ZTS_STATE_STACK_RUNNING 0x02
#define ZTS_STATE_NET_SERVICE_RUNNING 0x04
#define ZTS_STATE_CALLBACKS_RUNNING 0x08
#define ZTS_STATE_FREE_CALLED 0x10
#include <jni.h>
extern int zts_errno;
namespace ZeroTier {
extern uint8_t _serviceStateFlags;
#ifdef __cplusplus
extern "C" {
#endif
void ss2zta(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr);
void zta2ss(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr);
void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, zts_fd_set *dest_fd_set);
void fdset2ztfdset(JNIEnv *env, int nfds, zts_fd_set *src_fd_set, jobject dest_ztfd_set);
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_socket(
JNIEnv *env, jobject thisObj, jint family, jint type, jint protocol)
{
int retval = zts_socket(family, type, protocol);
return retval > -1 ? retval : -(zts_errno); // Encode lwIP errno into return value for JNI functions only
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_connect(
JNIEnv *env, jobject thisObj, jint fd, jobject addr)
{
struct zts_sockaddr_storage ss;
zta2ss(env, &ss, addr);
socklen_t addrlen = ss.ss_family == ZTS_AF_INET ? sizeof(struct zts_sockaddr_in) : sizeof(struct zts_sockaddr_in6);
int retval = zts_connect(fd, (struct zts_sockaddr *)&ss, addrlen);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_bind(
JNIEnv *env, jobject thisObj, jint fd, jobject addr)
{
struct zts_sockaddr_storage ss;
zta2ss(env, &ss, addr);
zts_socklen_t addrlen = ss.ss_family == ZTS_AF_INET ? sizeof(struct zts_sockaddr_in) : sizeof(struct zts_sockaddr_in6);
int retval = zts_bind(fd, (struct zts_sockaddr*)&ss, addrlen);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_listen(
JNIEnv *env, jobject thisObj, jint fd, int backlog)
{
int retval = zts_listen(fd, backlog);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_accept(
JNIEnv *env, jobject thisObj, jint fd, jobject addr, jint port)
{
struct zts_sockaddr_storage ss;
zts_socklen_t addrlen = sizeof(struct zts_sockaddr_storage);
int retval = zts_accept(fd, (zts_sockaddr*)&ss, &addrlen);
ss2zta(env, &ss, addr);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_setsockopt(
JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jobject optval)
{
jclass c = env->GetObjectClass(optval);
if (!c) {
return ZTS_ERR_SERVICE;
}
int optval_int = -1;
if (optname == SO_BROADCAST
|| optname == SO_KEEPALIVE
|| optname == SO_REUSEADDR
|| optname == SO_REUSEPORT
|| optname == TCP_NODELAY)
{
jfieldID fid = env->GetFieldID(c, "booleanValue", "Z");
optval_int = (int)(env->GetBooleanField(optval, fid));
}
if (optname == IP_TTL
|| optname == SO_RCVTIMEO
|| optname == IP_TOS
|| optname == SO_LINGER
|| optname == SO_RCVBUF
|| optname == SO_SNDBUF)
{
jfieldID fid = env->GetFieldID(c, "integerValue", "I");
optval_int = env->GetIntField(optval, fid);
}
int retval = ZTS_ERR_OK;
if (optname == SO_RCVTIMEO) {
struct timeval tv;
// Convert milliseconds from setSoTimeout() call to seconds and microseconds
tv.tv_usec = optval_int * 1000;
tv.tv_sec = optval_int / 1000000;
retval = zts_setsockopt(fd, level, optname, &tv, sizeof(tv));
}
else {
retval = zts_setsockopt(fd, level, optname, &optval_int, sizeof(optval_int));
}
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getsockopt(
JNIEnv *env, jobject thisObj, jint fd, jint level, jint optname, jobject optval)
{
jclass c = env->GetObjectClass(optval);
if (!c) {
return ZTS_ERR_SERVICE;
}
int optval_int = 0;
zts_socklen_t optlen; // Intentionally not used
int retval;
if (optname == SO_RCVTIMEO) {
struct zts_timeval tv;
optlen = sizeof(tv);
retval = zts_getsockopt(fd, level, optname, &tv, &optlen);
// Convert seconds and microseconds back to milliseconds
optval_int = (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
}
else {
retval = zts_getsockopt(fd, level, optname, &optval_int, &optlen);
}
if (optname == SO_BROADCAST
|| optname == SO_KEEPALIVE
|| optname == SO_REUSEADDR
|| optname == SO_REUSEPORT
|| optname == TCP_NODELAY)
{
jfieldID fid = env->GetFieldID(c, "isBoolean", "Z");
env->SetBooleanField(optval, fid, true);
fid = env->GetFieldID(c, "booleanValue", "Z");
env->SetBooleanField(optval, fid, (bool)optval_int);
}
if (optname == IP_TTL
|| optname == SO_RCVTIMEO
|| optname == IP_TOS
|| optname == SO_LINGER
|| optname == SO_RCVBUF
|| optname == SO_SNDBUF)
{
jfieldID fid = env->GetFieldID(c, "isInteger", "Z");
env->SetBooleanField(optval, fid, true);
fid = env->GetFieldID(c, "integerValue", "I");
env->SetIntField(optval, fid, optval_int);
}
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jboolean JNICALL Java_com_zerotier_libzt_ZeroTier_getsockname(JNIEnv *env, jobject thisObj,
jint fd, jobject addr)
{
struct zts_sockaddr_storage ss;
zts_socklen_t addrlen = sizeof(struct zts_sockaddr_storage);
int retval = zts_getsockname(fd, (struct zts_sockaddr *)&ss, &addrlen);
ss2zta(env, &ss, addr);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_getpeername(JNIEnv *env, jobject thisObj,
jint fd, jobject addr)
{
struct zts_sockaddr_storage ss;
int retval = zts_getpeername(fd, (struct zts_sockaddr *)&ss, (zts_socklen_t*)sizeof(struct zts_sockaddr_storage));
ss2zta(env, &ss, addr);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_close(
JNIEnv *env, jobject thisObj, jint fd)
{
return zts_close(fd);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_select(JNIEnv *env, jobject thisObj,
jint nfds, jobject readfds, jobject writefds, jobject exceptfds, jint timeout_sec, jint timeout_usec)
{
struct zts_timeval _timeout;
_timeout.tv_sec = timeout_sec;
_timeout.tv_usec = timeout_usec;
zts_fd_set _readfds, _writefds, _exceptfds;
zts_fd_set *r = NULL;
zts_fd_set *w = NULL;
zts_fd_set *e = NULL;
if (readfds) {
r = &_readfds;
ztfdset2fdset(env, nfds, readfds, &_readfds);
}
if (writefds) {
w = &_writefds;
ztfdset2fdset(env, nfds, writefds, &_writefds);
}
if (exceptfds) {
e = &_exceptfds;
ztfdset2fdset(env, nfds, exceptfds, &_exceptfds);
}
int retval = zts_select(nfds, r, w, e, &_timeout);
if (readfds) {
fdset2ztfdset(env, nfds, &_readfds, readfds);
}
if (writefds) {
fdset2ztfdset(env, nfds, &_writefds, writefds);
}
if (exceptfds) {
fdset2ztfdset(env, nfds, &_exceptfds, exceptfds);
}
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_fcntl(
JNIEnv *env, jobject thisObj, jint fd, jint cmd, jint flags)
{
int retval = zts_fcntl(fd, cmd, flags);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT int JNICALL Java_com_zerotier_libzt_ZeroTier_ioctl(
JNIEnv *env, jobject thisObj, jint fd, jlong request, jobject argp)
{
int retval = ZTS_ERR_OK;
if (request == FIONREAD) {
int bytesRemaining = 0;
retval = zts_ioctl(fd, request, &bytesRemaining);
// set value in general object
jclass c = env->GetObjectClass(argp);
if (!c) {
return ZTS_ERR_ARG;
}
jfieldID fid = env->GetFieldID(c, "integer", "I");
env->SetIntField(argp, fid, bytesRemaining);
}
if (request == FIONBIO) {
// TODO: double check
int meaninglessVariable = 0;
retval = zts_ioctl(fd, request, &meaninglessVariable);
}
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_send(
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, int flags)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_send(fd, data, env->GetArrayLength(buf), flags);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_sendto(
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint flags, jobject addr)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
struct zts_sockaddr_storage ss;
zta2ss(env, &ss, addr);
zts_socklen_t addrlen = ss.ss_family == ZTS_AF_INET ? sizeof(struct zts_sockaddr_in) : sizeof(struct zts_sockaddr_in6);
int retval = zts_sendto(fd, data, env->GetArrayLength(buf), flags, (struct zts_sockaddr *)&ss, addrlen);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recv(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf, jint flags)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_recv(fd, data, env->GetArrayLength(buf), flags);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_recvfrom(
JNIEnv *env, jobject thisObj, jint fd, jbyteArray buf, jint flags, jobject addr)
{
zts_socklen_t addrlen = sizeof(struct zts_sockaddr_storage);
struct zts_sockaddr_storage ss;
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_recvfrom(fd, data, env->GetArrayLength(buf), flags, (struct zts_sockaddr *)&ss, &addrlen);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
ss2zta(env, &ss, addr);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_read(fd, data, env->GetArrayLength(buf));
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
ssize_t zts_read_offset(int fd, void *buf, size_t offset, size_t len)
{
if (!(_serviceStateFlags & ZTS_STATE_NET_SERVICE_RUNNING)) {
return ZTS_ERR_SERVICE;
}
if (!buf) {
return ZTS_ERR_ARG;
}
char *cbuf = (char*)buf;
return lwip_read(fd, &(cbuf[offset]), len);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1offset(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf, jint offset, jint len)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_read_offset(fd, data, offset, len);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_read_1length(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf, jint len)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_read(fd, data, len);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write__IB(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf)
{
void *data = env->GetPrimitiveArrayCritical(buf, NULL);
int retval = zts_write(fd, data, env->GetArrayLength(buf));
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write_1offset(JNIEnv *env, jobject thisObj,
jint fd, jbyteArray buf, jint offset, jint len)
{
void *data = env->GetPrimitiveArrayCritical(&(buf[offset]), NULL); // PENDING: check?
int retval = zts_write(fd, data, len);
env->ReleasePrimitiveArrayCritical(buf, data, 0);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_write_1byte(JNIEnv *env, jobject thisObj,
jint fd, jbyte buf)
{
int retval = zts_write(fd, &buf, 1);
return retval > -1 ? retval : -(zts_errno);
}
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_shutdown(
JNIEnv *env, jobject thisObj, int fd, int how)
{
return zts_shutdown(fd, how);
}
#ifdef ZTS_ENABLE_STATS
JNIEXPORT jint JNICALL Java_com_zerotier_libzt_ZeroTier_get_1protocol_1stats(
JNIEnv *env, jobject thisObj, jint protocolType, jobject protoStatsObj)
{
struct stats_proto stats;
int retval = zts_get_protocol_stats(protocolType, &stats);
// Copy stats into Java object
jclass c = env->GetObjectClass(protoStatsObj);
if (!c) {
return ZTS_ERR_ARG;
}
jfieldID fid;
fid = env->GetFieldID(c, "xmit", "I");
env->SetIntField(protoStatsObj, fid, stats.xmit);
fid = env->GetFieldID(c, "recv", "I");
env->SetIntField(protoStatsObj, fid, stats.recv);
fid = env->GetFieldID(c, "fw", "I");
env->SetIntField(protoStatsObj, fid, stats.fw);
fid = env->GetFieldID(c, "drop", "I");
env->SetIntField(protoStatsObj, fid, stats.drop);
fid = env->GetFieldID(c, "chkerr", "I");
env->SetIntField(protoStatsObj, fid, stats.chkerr);
fid = env->GetFieldID(c, "lenerr", "I");
env->SetIntField(protoStatsObj, fid, stats.lenerr);
fid = env->GetFieldID(c, "memerr", "I");
env->SetIntField(protoStatsObj, fid, stats.memerr);
fid = env->GetFieldID(c, "rterr", "I");
env->SetIntField(protoStatsObj, fid, stats.rterr);
fid = env->GetFieldID(c, "proterr", "I");
env->SetIntField(protoStatsObj, fid, stats.proterr);
fid = env->GetFieldID(c, "opterr", "I");
env->SetIntField(protoStatsObj, fid, stats.opterr);
fid = env->GetFieldID(c, "err", "I");
env->SetIntField(protoStatsObj, fid, stats.err);
fid = env->GetFieldID(c, "cachehit", "I");
env->SetIntField(protoStatsObj, fid, stats.cachehit);
return retval;
}
#endif // ZTS_ENABLE_STATS
void ztfdset2fdset(JNIEnv *env, int nfds, jobject src_ztfd_set, zts_fd_set *dest_fd_set)
{
jclass c = env->GetObjectClass(src_ztfd_set);
if (!c) {
return;
}
ZTS_FD_ZERO(dest_fd_set);
jfieldID fid = env->GetFieldID(c, "fds_bits", "[B");
jobject fdData = env->GetObjectField (src_ztfd_set, fid);
jbyteArray * arr = reinterpret_cast<jbyteArray*>(&fdData);
char *data = (char*)env->GetByteArrayElements(*arr, NULL);
for (int i=0; i<nfds; i++) {
if (data[i] == 0x01) {
ZTS_FD_SET(i, dest_fd_set);
}
}
env->ReleaseByteArrayElements(*arr, (jbyte*)data, 0);
return;
}
void fdset2ztfdset(JNIEnv *env, int nfds, zts_fd_set *src_fd_set, jobject dest_ztfd_set)
{
jclass c = env->GetObjectClass(dest_ztfd_set);
if (!c) {
return;
}
jfieldID fid = env->GetFieldID(c, "fds_bits", "[B");
jobject fdData = env->GetObjectField (dest_ztfd_set, fid);
jbyteArray * arr = reinterpret_cast<jbyteArray*>(&fdData);
char *data = (char*)env->GetByteArrayElements(*arr, NULL);
for (int i=0; i<nfds; i++) {
if (ZTS_FD_ISSET(i, src_fd_set)) {
data[i] = 0x01;
}
}
env->ReleaseByteArrayElements(*arr, (jbyte*)data, 0);
return;
}
//////////////////////////////////////////////////////////////////////////////
// Helpers (for moving data across the JNI barrier) //
//////////////////////////////////////////////////////////////////////////////
void ss2zta(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr)
{
jclass c = env->GetObjectClass(addr);
if (!c) {
return;
}
if(ss->ss_family == ZTS_AF_INET)
{
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)ss;
jfieldID fid = env->GetFieldID(c, "_port", "I");
env->SetIntField(addr, fid, lwip_ntohs(in4->sin_port));
fid = env->GetFieldID(c,"_family", "I");
env->SetIntField(addr, fid, (in4->sin_family));
fid = env->GetFieldID(c, "_ip4", "[B");
jobject ipData = env->GetObjectField (addr, fid);
jbyteArray * arr = reinterpret_cast<jbyteArray*>(&ipData);
char *data = (char*)env->GetByteArrayElements(*arr, NULL);
memcpy(data, &(in4->sin_addr.s_addr), 4);
env->ReleaseByteArrayElements(*arr, (jbyte*)data, 0);
return;
}
if(ss->ss_family == ZTS_AF_INET6)
{
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)ss;
jfieldID fid = env->GetFieldID(c, "_port", "I");
env->SetIntField(addr, fid, lwip_ntohs(in6->sin6_port));
fid = env->GetFieldID(c,"_family", "I");
env->SetIntField(addr, fid, (in6->sin6_family));
fid = env->GetFieldID(c, "_ip6", "[B");
jobject ipData = env->GetObjectField (addr, fid);
jbyteArray * arr = reinterpret_cast<jbyteArray*>(&ipData);
char *data = (char*)env->GetByteArrayElements(*arr, NULL);
memcpy(data, &(in6->sin6_addr.s6_addr), 16);
env->ReleaseByteArrayElements(*arr, (jbyte*)data, 0);
return;
}
}
void zta2ss(JNIEnv *env, struct zts_sockaddr_storage *ss, jobject addr)
{
jclass c = env->GetObjectClass(addr);
if (!c) {
return;
}
jfieldID fid = env->GetFieldID(c, "_family", "I");
int family = env->GetIntField(addr, fid);
if (family == ZTS_AF_INET)
{
struct zts_sockaddr_in *in4 = (struct zts_sockaddr_in*)ss;
fid = env->GetFieldID(c, "_port", "I");
in4->sin_port = lwip_htons(env->GetIntField(addr, fid));
in4->sin_family = ZTS_AF_INET;
fid = env->GetFieldID(c, "_ip4", "[B");
jobject ipData = env->GetObjectField (addr, fid);
jbyteArray * arr = reinterpret_cast<jbyteArray*>(&ipData);
char *data = (char*)env->GetByteArrayElements(*arr, NULL);
memcpy(&(in4->sin_addr.s_addr), data, 4);
env->ReleaseByteArrayElements(*arr, (jbyte*)data, 0);
return;
}
if (family == ZTS_AF_INET6)
{
struct zts_sockaddr_in6 *in6 = (struct zts_sockaddr_in6*)ss;
jfieldID fid = env->GetFieldID(c, "_port", "I");
in6->sin6_port = lwip_htons(env->GetIntField(addr, fid));
fid = env->GetFieldID(c,"_family", "I");
in6->sin6_family = ZTS_AF_INET6;
fid = env->GetFieldID(c, "_ip6", "[B");
jobject ipData = env->GetObjectField (addr, fid);
jbyteArray * arr = reinterpret_cast<jbyteArray*>(&ipData);
char *data = (char*)env->GetByteArrayElements(*arr, NULL);
memcpy(&(in6->sin6_addr.s6_addr), data, 16);
env->ReleaseByteArrayElements(*arr, (jbyte*)data, 0);
return;
}
}
#ifdef __cplusplus
}
#endif
} // namespace ZeroTier
#endif // ZTS_ENABLE_JAVA

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
Java Language Bindings
=====
See [examples/java](./../../../examples/java/) for usage.

View File

@@ -0,0 +1,24 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
/**
* Class that must be implemented to receive ZeroTier event notifications.
*/
interface ZeroTierEventListener {
/*
* Called when an even occurs within ZeroTier
*/
public void onZeroTierEvent(long nwid, int event_code);
}

View File

@@ -0,0 +1,55 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
/**
* This class provides an fdset-like behavior to ZeroTierSocket
*/
class ZeroTierFileDescriptorSet {
byte[] fds_bits = new byte[1024];
/**
* Clear bit
*/
public void CLR(int fd)
{
fds_bits[fd] = 0x00;
}
/**
* Check if bit is set
*/
public boolean ISSET(int fd)
{
return fds_bits[fd] == 0x01;
}
/**
* Set bit
*/
public void SET(int fd)
{
fds_bits[fd] = 0x01;
}
/**
* Zero-out all bits
*/
public void ZERO()
{
for (int i = 0; i < 1024; i++) {
fds_bits[i] = 0x00;
}
}
}

View File

@@ -0,0 +1,209 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
import com.zerotier.sdk.ZeroTierNative;
import java.io.*;
import java.util.Objects;
/**
* Extends InputStream using ZeroTier as a transport
*/
public class ZeroTierInputStream extends InputStream {
/**
* File descriptor used by lower native layer
*/
public int zfd = -1;
/**
* Close the ZeroTierInputStream
* @exception IOException when an I/O error occurs
*/
public void close() throws IOException
{
/* Note: this operation currently only stops RX on a socket that is shared
between both I/OStreams. This means that closing this stream will only shutdown
that aspect of the socket but not actually close it and free resources. Resources
will be properly freed when the socket implementation's close() is called or if
both I/OStreams are closed separately */
ZeroTierNative.zts_shutdown(zfd, ZeroTierNative.ZTS_SHUT_RD);
zfd = -1;
}
/**
* Transfer bytes from this stream to another
* @param destStream Unused
* @return Number of bytes transferred
* @exception IOException when an I/O error occurs
*/
public long transferTo(OutputStream destStream) throws IOException
{
Objects.requireNonNull(destStream, "destStream must not be null");
int bytesTransferred = 0, bytesRead;
byte[] buf = new byte[8192];
while (((bytesRead = ZeroTierNative.zts_read(zfd, buf)) >= 0)) {
destStream.write(buf, 0, bytesRead);
bytesTransferred += bytesRead;
}
return bytesTransferred;
}
/**
* Read a single byte from the stream
* @return Single byte read
* @exception IOException when an I/O error occurs
*/
public int read() throws IOException
{
byte[] buf = new byte[1];
// Unlike a native read(), if nothing is read we should return -1
int retval = ZeroTierNative.zts_read(zfd, buf);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
return -1;
}
if (retval < 0) {
throw new IOException("read(), errno=" + retval);
}
return buf[0];
}
/**
* Read from stream into buffer
* @param destBuffer Destination buffer
* @return Number of bytes read
* @exception IOException when an I/O error occurs
*/
public int read(byte[] destBuffer) throws IOException
{
Objects.requireNonNull(destBuffer, "input byte array must not be null");
// Unlike a native read(), if nothing is read we should return -1
int retval = ZeroTierNative.zts_read(zfd, destBuffer);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
return -1;
}
if (retval < 0) {
throw new IOException("read(destBuffer), errno=" + retval);
}
return retval;
}
/**
* Read from stream into buffer at offset
* @param destBuffer Destination buffer
* @param offset Where in the destination buffer bytes should be written
* @param numBytes Number of bytes to read
* @return Number of bytes read.
* @exception IOException when an I/O error occurs
*/
public int read(byte[] destBuffer, int offset, int numBytes) throws IOException
{
Objects.requireNonNull(destBuffer, "input byte array must not be null");
if (offset < 0) {
throw new IndexOutOfBoundsException("offset < 0");
}
if (numBytes < 0) {
throw new IndexOutOfBoundsException("numBytes < 0");
}
if (numBytes > (destBuffer.length - offset)) {
throw new IndexOutOfBoundsException("numBytes > (destBuffer.length - offset");
}
if (numBytes == 0) {
return 0;
}
// Unlike a native read(), if nothing is read we should return -1
int retval = ZeroTierNative.zts_read_offset(zfd, destBuffer, offset, numBytes);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
return -1;
}
if (retval < 0) {
throw new IOException("read(destBuffer, offset, numBytes), errno=" + retval);
}
return retval;
}
/**
* Read all available data from stream
* @return Array of bytes
* @exception IOException when an I/O error occurs
*/
public byte[] readAllBytes() throws IOException
{
int pendingDataSize = ZeroTierNative.zts_simple_get_pending_data_size(zfd);
byte[] buf = new byte[pendingDataSize];
int retval = ZeroTierNative.zts_read(zfd, buf);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
// No action needed
}
if (retval < 0) {
throw new IOException("readAllBytes(), errno=" + retval);
}
return buf;
}
/**
* Read a given number of bytes from the stream into a buffer
* @param destBuffer Destination buffer
* @param offset Where in the destination buffer bytes should be written
* @param numBytes Number of bytes to read
* @return Nothing.
* @exception IOException when an I/O error occurs
*/
public int readNBytes(byte[] destBuffer, int offset, int numBytes) throws IOException
{
Objects.requireNonNull(destBuffer, "input byte array must not be null");
if (offset < 0) {
throw new IndexOutOfBoundsException("offset < 0");
}
if (numBytes < 0) {
throw new IndexOutOfBoundsException("numBytes < 0");
}
if (numBytes > (destBuffer.length - offset)) {
throw new IndexOutOfBoundsException("numBytes > destBuffer.length - offset");
}
if (numBytes == 0) {
return 0;
}
int retval = ZeroTierNative.zts_read_offset(zfd, destBuffer, offset, numBytes);
if ((retval == 0) | (retval == -104) /* EINTR, from SO_RCVTIMEO */) {
// No action needed
}
if (retval < 0) {
throw new IOException("readNBytes(destBuffer, offset, numBytes), errno=" + retval);
}
return retval;
}
/**
* Skip a certain number of bytes
* @param numBytes Unused
* @return Nothing.
* @exception IOException when an I/O error occurs
*/
public long skip(long numBytes) throws IOException
{
if (numBytes <= 0) {
return 0;
}
long bytesRemaining = numBytes, bytesRead;
int bufSize = (int)Math.min(2048, bytesRemaining);
byte[] buf = new byte[bufSize];
while (bytesRemaining > 0) {
if ((bytesRead = ZeroTierNative.zts_read_length(zfd, buf, (int)Math.min(bufSize, bytesRemaining))) < 0) {
break;
}
bytesRemaining -= bytesRead;
}
return numBytes - bytesRemaining;
}
}

View File

@@ -0,0 +1,603 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
/**
* Class that exposes the low-level C socket interface provided by libzt. This
* can be used instead of the higher-level ZeroTierSocket API.
*/
public class ZeroTierNative {
// Only to be called by static initializer of this class
public static native int zts_init();
static
{
// Loads dynamic library at initialization time
System.loadLibrary("zt");
if (zts_init() != ZeroTierNative.ZTS_ERR_OK) {
throw new ExceptionInInitializerError("JNI init() failed (see GetJavaVM())");
}
}
//----------------------------------------------------------------------------//
// Event codes //
//----------------------------------------------------------------------------//
/**
* Node has been initialized
*
* This is the first event generated; and is always sent. It may occur
* before node's constructor returns.
*
*/
public static int ZTS_EVENT_NODE_UP = 200;
/**
* Node is online -- at least one upstream node appears reachable
*
*/
public static int ZTS_EVENT_NODE_ONLINE = 201;
/**
* Node is offline -- network does not seem to be reachable by any available
* strategy
*
*/
public static int ZTS_EVENT_NODE_OFFLINE = 202;
/**
* 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.
*
*/
public static int ZTS_EVENT_NODE_DOWN = 203;
/**
* A fatal error has occurred. One possible reason is:
*
* 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?
*
* Meta-data: none
*/
public static int ZTS_EVENT_NODE_FATAL_ERROR = 204;
/** Network ID does not correspond to a known network */
public static int ZTS_EVENT_NETWORK_NOT_FOUND = 210;
/** The version of ZeroTier inside libzt is too old */
public static int ZTS_EVENT_NETWORK_CLIENT_TOO_OLD = 211;
/** The configuration for a network has been requested (no action needed) */
public static int ZTS_EVENT_NETWORK_REQ_CONFIG = 212;
/** The node joined the network successfully (no action needed) */
public static int ZTS_EVENT_NETWORK_OK = 213;
/** The node is not allowed to join the network (you must authorize node) */
public static int ZTS_EVENT_NETWORK_ACCESS_DENIED = 214;
/** The node has received an IPv4 address from the network controller */
public static int ZTS_EVENT_NETWORK_READY_IP4 = 215;
/** The node has received an IPv6 address from the network controller */
public static int ZTS_EVENT_NETWORK_READY_IP6 = 216;
/** Deprecated */
public static int ZTS_EVENT_NETWORK_READY_IP4_IP6 = 217;
/** Network controller is unreachable */
public static int ZTS_EVENT_NETWORK_DOWN = 218;
/** Network change received from controller */
public static int ZTS_EVENT_NETWORK_UPDATE = 219;
/** TCP/IP stack (lwIP) is up (for debug purposes) */
public static int ZTS_EVENT_STACK_UP = 220;
/** TCP/IP stack (lwIP) id down (for debug purposes) */
public static int ZTS_EVENT_STACK_DOWN = 221;
/** lwIP netif up (for debug purposes) */
public static int ZTS_EVENT_NETIF_UP = 230;
/** lwIP netif down (for debug purposes) */
public static int ZTS_EVENT_NETIF_DOWN = 231;
/** lwIP netif removed (for debug purposes) */
public static int ZTS_EVENT_NETIF_REMOVED = 232;
/** lwIP netif link up (for debug purposes) */
public static int ZTS_EVENT_NETIF_LINK_UP = 233;
/** lwIP netif link down (for debug purposes) */
public static int ZTS_EVENT_NETIF_LINK_DOWN = 234;
/** A direct P2P path to peer is known */
public static int ZTS_EVENT_PEER_DIRECT = 240;
/** A direct P2P path to peer is NOT known. Traffic is now relayed */
public static int ZTS_EVENT_PEER_RELAY = 241;
/** A peer is unreachable. Check NAT/Firewall settings */
public static int ZTS_EVENT_PEER_UNREACHABLE = 242;
/** A new path to a peer was discovered */
public static int ZTS_EVENT_PEER_PATH_DISCOVERED = 243;
/** A known path to a peer is now considered dead */
public static int ZTS_EVENT_PEER_PATH_DEAD = 244;
/** A new managed network route was added */
public static int ZTS_EVENT_ROUTE_ADDED = 250;
/** A managed network route was removed */
public static int ZTS_EVENT_ROUTE_REMOVED = 251;
/** A new managed IPv4 address was assigned to this peer */
public static int ZTS_EVENT_ADDR_ADDED_IP4 = 260;
/** A managed IPv4 address assignment was removed from this peer */
public static int ZTS_EVENT_ADDR_REMOVED_IP4 = 261;
/** A new managed IPv4 address was assigned to this peer */
public static int ZTS_EVENT_ADDR_ADDED_IP6 = 262;
/** A managed IPv6 address assignment was removed from this peer */
public static int ZTS_EVENT_ADDR_REMOVED_IP6 = 263;
/** The node's secret key (identity) */
public static int ZTS_EVENT_STORE_IDENTITY_SECRET = 270;
/** The node's public key (identity) */
public static int ZTS_EVENT_STORE_IDENTITY_PUBLIC = 271;
/** The node has received an updated planet config */
public static int ZTS_EVENT_STORE_PLANET = 272;
/** New reachability hints and peer configuration */
public static int ZTS_EVENT_STORE_PEER = 273;
/** New network config */
public static int ZTS_EVENT_STORE_NETWORK = 274;
// Socket protocol types
/** Stream socket */
public static int ZTS_SOCK_STREAM = 0x00000001;
/** Datagram socket */
public static int ZTS_SOCK_DGRAM = 0x00000002;
public static int ZTS_SOCK_RAW = 0x00000003;
// Socket family types
/** IPv4 address family */
public static int ZTS_AF_INET = 0x00000002;
// another test comment
/** IPv6 address family */
public static int ZTS_AF_INET6 = 0x0000000a;
/* yet one more */
public static int ZTS_PF_INET = ZTS_AF_INET;
public static int ZTS_PF_INET6 = ZTS_AF_INET6;
// Used as level numbers for setsockopt() and getsockopt()
public static int ZTS_IPPROTO_IP = 0x00000000;
public static int ZTS_IPPROTO_ICMP = 0x00000001;
public static int ZTS_IPPROTO_TCP = 0x00000006;
public static int ZTS_IPPROTO_UDP = 0x00000011;
public static int ZTS_IPPROTO_IPV6 = 0x00000029;
public static int ZTS_IPPROTO_ICMPV6 = 0x0000003a;
public static int ZTS_IPPROTO_UDPLITE = 0x00000088;
public static int ZTS_IPPROTO_RAW = 0x000000ff;
// send() and recv() flags
public static int ZTS_MSG_PEEK = 0x00000001;
public static int ZTS_MSG_WAITALL = 0x00000002;
public static int ZTS_MSG_OOB = 0x00000004;
public static int ZTS_MSG_DONTWAIT = 0x00000008;
public static int ZTS_MSG_MORE = 0x00000010;
// fnctl() commands
public static int ZTS_F_GETFL = 0x00000003;
public static int ZTS_F_SETFL = 0x00000004;
// fnctl() flags
public static int ZTS_O_NONBLOCK = 0x00000001;
public static int ZTS_O_NDELAY = 0x00000001;
// Shutdown commands
public static int ZTS_SHUT_RD = 0x00000000;
public static int ZTS_SHUT_WR = 0x00000001;
public static int ZTS_SHUT_RDWR = 0x00000002;
// ioctl() commands
public static int ZTS_FIONREAD = 0x4008667F;
public static int ZTS_FIONBIO = 0x8008667E;
// Socket level option number
public static int ZTS_SOL_SOCKET = 0x00000FFF;
// Socket options
public static int ZTS_SO_REUSEADDR = 0x00000004;
public static int ZTS_SO_KEEPALIVE = 0x00000008;
public static int ZTS_SO_BROADCAST = 0x00000020;
// Socket options
public static int ZTS_SO_DEBUG = 0x00000001; // NOT YET SUPPORTED
public static int ZTS_SO_ACCEPTCONN = 0x00000002;
public static int ZTS_SO_DONTROUTE = 0x00000010; // NOT YET SUPPORTED
public static int ZTS_SO_USELOOPBACK = 0x00000040; // NOT YET SUPPORTED
public static int ZTS_SO_LINGER = 0x00000080;
public static int ZTS_SO_DONTLINGER = ((int)(~ZTS_SO_LINGER));
public static int ZTS_SO_OOBINLINE = 0x00000100; // NOT YET SUPPORTED
public static int ZTS_SO_REUSEPORT = 0x00000200; // NOT YET SUPPORTED
public static int ZTS_SO_SNDBUF = 0x00001001; // NOT YET SUPPORTED
public static int ZTS_SO_RCVBUF = 0x00001002;
public static int ZTS_SO_SNDLOWAT = 0x00001003; // NOT YET SUPPORTED
public static int ZTS_SO_RCVLOWAT = 0x00001004; // NOT YET SUPPORTED
public static int ZTS_SO_SNDTIMEO = 0x00001005;
public static int ZTS_SO_RCVTIMEO = 0x00001006;
public static int ZTS_SO_ERROR = 0x00001007;
public static int ZTS_SO_TYPE = 0x00001008;
public static int ZTS_SO_CONTIMEO = 0x00001009; // NOT YET SUPPORTED
public static int ZTS_SO_NO_CHECK = 0x0000100a;
// IPPROTO_IP options
public static int ZTS_IP_TOS = 0x00000001;
public static int ZTS_IP_TTL = 0x00000002;
// IPPROTO_TCP options
public static int ZTS_TCP_NODELAY = 0x00000001;
public static int ZTS_TCP_KEEPALIVE = 0x00000002;
public static int ZTS_TCP_KEEPIDLE = 0x00000003;
public static int ZTS_TCP_KEEPINTVL = 0x00000004;
public static int ZTS_TCP_KEEPCNT = 0x00000005;
//----------------------------------------------------------------------------//
// ZeroTier Service Controls //
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
// Error codes //
//----------------------------------------------------------------------------//
/** (0) No error */
public static int ZTS_ERR_OK = 0;
/** (-1) Socket error, see zts_errno */
public static int ZTS_ERR_SOCKET = -1;
/** (-2) You probably did something at the wrong time */
public static int ZTS_ERR_SERVICE = -2;
/** (-3) Invalid argument */
public static int ZTS_ERR_ARG = -3;
/** (-4) No result (not necessarily an error) */
public static int ZTS_ERR_RESULT = -4;
/** (-5) Consider filing a bug report */
public static int ZTS_ERR_GENERAL = -5;
//----------------------------------------------------------------------------//
// zts_errno Error codes //
//----------------------------------------------------------------------------//
/** Operation not permitted (`zts_errno` value) */
public static int ZTS_EPERM = 1;
/** No such file or directory */
public static int ZTS_ENOENT = 2;
/** No such process */
public static int ZTS_ESRCH = 3;
/** Interrupted system call */
public static int ZTS_EINTR = 4;
/** I/O error */
public static int ZTS_EIO = 5;
/** No such device or address */
public static int ZTS_ENXIO = 6;
/** Bad file number */
public static int ZTS_EBADF = 9;
/** Try again */
public static int ZTS_EAGAIN = 11;
/** Operation would block */
public static int ZTS_EWOULDBLOCK = 11;
/** Out of memory */
public static int ZTS_ENOMEM = 12;
/** Permission denied */
public static int ZTS_EACCES = 13;
/** Bad address */
public static int ZTS_EFAULT = 14;
/** Device or resource busy */
public static int ZTS_EBUSY = 16;
/** File exists */
public static int ZTS_EEXIST = 17;
/** No such device */
public static int ZTS_ENODEV = 19;
/** Invalid argument */
public static int ZTS_EINVAL = 22;
/** File table overflow */
public static int ZTS_ENFILE = 23;
/** Too many open files */
public static int ZTS_EMFILE = 24;
/** Function not implemented */
public static int ZTS_ENOSYS = 38;
/** Socket operation on non-socket */
public static int ZTS_ENOTSOCK = 88;
/** Destination address required */
public static int ZTS_EDESTADDRREQ = 89;
/** Message too long */
public static int ZTS_EMSGSIZE = 90;
/** Protocol wrong type for socket */
public static int ZTS_EPROTOTYPE = 91;
/** Protocol not available */
public static int ZTS_ENOPROTOOPT = 92;
/** Protocol not supported */
public static int ZTS_EPROTONOSUPPORT = 93;
/** Socket type not supported */
public static int ZTS_ESOCKTNOSUPPORT = 94;
/** Operation not supported on transport endpoint */
public static int ZTS_EOPNOTSUPP = 95;
/** Protocol family not supported */
public static int ZTS_EPFNOSUPPORT = 96;
/** Address family not supported by protocol */
public static int ZTS_EAFNOSUPPORT = 97;
/** Address already in use */
public static int ZTS_EADDRINUSE = 98;
/** Cannot assign requested address */
public static int ZTS_EADDRNOTAVAIL = 99;
/** Network is down */
public static int ZTS_ENETDOWN = 100;
/** Network is unreachable */
public static int ZTS_ENETUNREACH = 101;
/** Software caused connection abort */
public static int ZTS_ECONNABORTED = 103;
/** Connection reset by peer */
public static int ZTS_ECONNRESET = 104;
/** No buffer space available */
public static int ZTS_ENOBUFS = 105;
/** Transport endpoint is already connected */
public static int ZTS_EISCONN = 106;
/** Transport endpoint is not connected */
public static int ZTS_ENOTCONN = 107;
/** Connection timed out */
public static int ZTS_ETIMEDOUT = 110;
/** No route to host */
public static int ZTS_EHOSTUNREACH = 113;
/** Operation already in progress */
public static int ZTS_EALREADY = 114;
/** Operation now in progress */
public static int ZTS_EINPROGRESS = 115;
//----------------------------------------------------------------------------//
// Misc definitions //
//----------------------------------------------------------------------------//
/**
* Length of human-readable MAC address string
*/
public static int ZTS_MAC_ADDRSTRLEN = 18;
/**
* Max length of human-readable IPv4 string
*/
public static int ZTS_INET_ADDRSTRLEN = 16;
/**
* Max length of human-readable IPv6 string
*/
public static int ZTS_INET6_ADDRSTRLEN = 46;
/**
* Maximum (and required) length of string buffers used to receive
* string-format IP addresses from the API. This is set to `ZTS_INET6_ADDRSTRLEN`
* to handle all cases: `ZTS_AF_INET` and `ZTS_AF_INET6`
*/
public static int ZTS_IP_MAX_STR_LEN = 46;
/**
* Required buffer length to safely receive data store items
*/
public static int ZTS_STORE_DATA_LEN = 4096;
/**
* Maximum length of network short name
*/
public static int ZTS_MAX_NETWORK_SHORT_NAME_LENGTH = 127;
/**
* Maximum number of pushed routes on a network
*/
public static int ZTS_MAX_NETWORK_ROUTES = 32;
/**
* Maximum number of statically assigned IP addresses per network endpoint
* using ZT address management (not DHCP)
*/
public static int ZTS_MAX_ASSIGNED_ADDRESSES = 16;
/**
* Maximum number of direct network paths to a given peer
*/
public static int ZTS_MAX_PEER_NETWORK_PATHS = 16;
/**
* Maximum number of multicast groups a device / network interface can be
* subscribed to at once
*/
public static int ZTS_MAX_MULTICAST_SUBSCRIPTIONS = 1024;
/**
* The length of a human-friendly identity key pair string
*/
public static int ZTS_ID_STR_BUF_LEN = 384;
// public static native int zts_id_new(char* key, int* key_buf_len);
// public static native int zts_id_pair_is_valid(/*const*/ char* key, int len);
public static native int zts_init_from_storage(String path);
public static native int zts_init_set_event_handler(ZeroTierEventListener callbackClass);
public static native int zts_init_set_port(short port);
// public static native int zts_init_from_memory(/*const*/ char* key, int len);
public static native int zts_init_blacklist_if(/*const*/ String prefix, int len);
// public static native int zts_init_set_roots(/*const*/ void* roots_data, int len);
public static native int zts_init_allow_net_cache(int allowed);
public static native int zts_init_allow_peer_cache(int allowed);
public static native int zts_init_allow_roots_cache(int allowed);
public static native int zts_init_allow_id_cache(int allowed);
public static native int zts_addr_is_assigned(long net_id, int family);
// public static native int zts_addr_get(long net_id, int family, struct sockaddr_storage* addr);
// public static native int zts_addr_get_str(long net_id, int family, char* dst, int len);
// public static native int zts_addr_get_all(long net_id, struct sockaddr_storage* addr, int* count);
// public static native int zts_addr_compute_6plane(/*const*/ long net_id, /*const*/ long node_id, struct
// sockaddr_storage* addr); public static native int zts_addr_compute_rfc4193(/*const*/ long net_id, /*const*/ long
// node_id, struct sockaddr_storage* addr);
public static native int zts_addr_compute_rfc4193_str(long net_id, long node_id, String dst, int len);
public static native int zts_addr_compute_6plane_str(long net_id, long node_id, String dst, int len);
public static native long zts_net_compute_adhoc_id(short start_port, short end_port);
public static native int zts_net_join(long net_id);
public static native int zts_net_leave(long net_id);
public static native int zts_net_transport_is_ready(/*const*/ long net_id);
public static native long zts_net_get_mac(long net_id);
public static native int zts_net_get_mac_str(long net_id, String dst, int len);
public static native int zts_net_get_broadcast(long net_id);
public static native int zts_net_get_mtu(long net_id);
public static native int zts_net_get_name(long net_id, String dst, int len);
public static native int zts_net_get_status(long net_id);
public static native int zts_net_get_type(long net_id);
public static native int zts_route_is_assigned(long net_id, int family);
public static native int zts_node_start();
public static native int zts_node_is_online();
public static native long zts_node_get_id();
// public static native int zts_node_get_id_pair(char* key, int* key_buf_len);
public static native int zts_node_get_port();
public static native int zts_node_stop();
public static native int zts_node_free();
public static native int zts_moon_orbit(long moon_roots_id, long moon_seed);
public static native int zts_moon_deorbit(long moon_roots_id);
// public static native int zts_socket(int family, int type, int protocol);
// public static native int zts_connect(int fd, /*const*/ struct sockaddr* addr, socklen_t addrlen);
// public static native int zts_bind(int fd, /*const*/ struct sockaddr* addr, socklen_t addrlen);
// public static native int zts_listen(int fd, int backlog);
// public static native int zts_accept(int fd, struct sockaddr* addr, socklen_t* addrlen);
// public static native int zts_setsockopt(int fd, int level, int optname, /*const*/ void* optval, socklen_t
// optlen); public static native int zts_getsockopt(int fd, int level, int optname, void* optval, socklen_t*
// optlen); public static native int zts_getsockname(int fd, struct sockaddr* addr, socklen_t* addrlen); public
// static native int zts_getpeername(int fd, struct sockaddr* addr, socklen_t* addrlen); public static native int
// zts_close(int fd); public static native int zts_select(int nfds, fd_set* readfds, fd_set* writefds, fd_set*
// exceptfds, struct timeval* timeout); public static native int zts_fcntl(int fd, int cmd, int flags); public
// static native int zts_poll(struct pollfd* fds, nfds_t nfds, int timeout); public static native int zts_ioctl(int
// fd, long request, void* argp); public static native int send(int fd, /*const*/ void* buf, size_t len, int
// flags); public static native int sendto(int fd,
// /*const*/ void* buf, size_t len, int flags, /*const*/ struct sockaddr* addr, socklen_t addrlen); public static
// native int sendmsg(int fd, /*const*/ struct msghdr* msg, int flags); public static native int recv(int fd,
// void* buf, size_t len, int flags); public static native int recvfrom(int fd, void* buf, size_t len, int flags,
// struct sockaddr* addr, socklen_t* addrlen); public static native int recvmsg(int fd, struct msghdr* msg, int
// flags); public static native int read(int fd, void* buf, size_t len); public static native int readv(int fd,
// /*const*/ struct iovec* iov, int iovcnt); public static native int write(int fd, /*const*/ void* buf, size_t
// len); public static native int writev(int fd, /*const*/ struct iovec* iov, int iovcnt); public static native int
// shutdown(int fd, int how);
public static native int zts_simple_connect(int fd, /*const*/ String ipstr, int port, int timeout_ms);
public static native int zts_simple_bind(int fd, /*const*/ String ipstr, int port);
// public static native int zts_simple_accept(int fd, String remote_addr, int len, int* port);
public static native int zts_simple_tcp_client(/*const*/ String remote_ipstr, int remote_port);
// public static native int zts_simple_tcp_server(/*const*/ String local_ipstr, int local_port, String remote_ipstr,
// int len, int* remote_port);
public static native int zts_simple_udp_server(/*const*/ String local_ipstr, int local_port);
public static native int zts_simple_udp_client(/*const*/ String remote_ipstr);
public static native int zts_simple_set_no_delay(int fd, int enabled);
public static native int zts_simple_get_no_delay(int fd);
public static native int zts_simple_set_linger(int fd, int enabled, int value);
public static native int zts_simple_get_linger_enabled(int fd);
public static native int zts_simple_get_linger_value(int fd);
public static native int zts_simple_get_pending_data_size(int fd);
public static native int zts_simple_set_reuse_addr(int fd, int enabled);
public static native int zts_simple_get_reuse_addr(int fd);
public static native int zts_simple_set_recv_timeout(int fd, int seconds, int microseconds);
public static native int zts_simple_get_recv_timeout(int fd);
public static native int zts_simple_set_send_timeout(int fd, int seconds, int microseconds);
public static native int zts_simple_get_send_timeout(int fd);
public static native int zts_simple_set_send_buf_size(int fd, int size);
public static native int zts_simple_get_send_buf_size(int fd);
public static native int zts_simple_set_recv_buf_size(int fd, int size);
public static native int zts_simple_get_recv_buf_size(int fd);
public static native int zts_simple_set_ttl(int fd, int ttl);
public static native int zts_simple_get_ttl(int fd);
public static native int zts_simple_set_blocking(int fd, int enabled);
public static native int zts_simple_get_blocking(int fd);
public static native int zts_simple_set_keepalive(int fd, int enabled);
public static native int zts_simple_get_keepalive(int fd);
// struct hostent* gethostbyname(/*const*/ String name);
// public static native int zts_dns_set_server(uint8_t index, /*const*/ ip_addr* addr);
// ZTS_API /*const*/ ip_addr* ZTCALL dns_get_server(uint8_t index);
public static native int zts_core_lock_obtain();
public static native int zts_core_lock_release();
public static native int zts_core_query_addr_count(long net_id);
public static native int zts_core_query_addr(long net_id, int idx, String addr, int len);
public static native int zts_core_query_route_count(long net_id);
/*
public static native int zts_core_query_route(
long net_id,
int idx,
String target,
String via,
int len,
short* flags,
short* metric);
*/
public static native int zts_core_query_path_count(long peer_id);
public static native int zts_core_query_path(long peer_id, int idx, String dst, int len);
public static native int zts_core_query_mc_count(long net_id);
// public static native int zts_core_query_mc(long net_id, int idx, long* mac, uint32_t* adi);
/*
public static native int zts_util_roots_new(
char* roots_out,
int* roots_len,
char* prev_key,
int* prev_key_len,
char* curr_key,
int* curr_key_len,
long id,
long ts,
roots_t* roots_spec);
*/
public static native void zts_util_delay(long milliseconds);
//////////////////////////////////////////////////////////////////////////////
// Socket API //
//////////////////////////////////////////////////////////////////////////////
public static native int zts_socket(int family, int type, int protocol);
// public static native int zts_connect(int fd, ZeroTierSocketAddress addr);
// public static native int zts_bind(int fd, ZeroTierSocketAddress addr);
public static native int zts_listen(int fd, int backlog);
public static native int zts_accept(int fd, ZeroTierSocketAddress addr);
// public static native int zts_setsockopt(int fd, int level, int optname, ZeroTierSocketOptionValue optval);
// public static native int zts_getsockopt(int fd, int level, int optname, ZeroTierSocketOptionValue optval);
public static native int zts_read(int fd, byte[] buf);
public static native int zts_read_offset(int fd, byte[] buf, int offset, int len);
public static native int zts_read_length(int fd, byte[] buf, int len);
public static native int zts_recv(int fd, byte[] buf, int flags);
public static native int zts_recvfrom(int fd, byte[] buf, int flags, ZeroTierSocketAddress addr);
public static native int zts_write(int fd, byte[] buf);
public static native int zts_write_byte(int fd, byte b);
public static native int zts_write_offset(int fd, byte[] buf, int offset, int len);
public static native int zts_sendto(int fd, byte[] buf, int flags, ZeroTierSocketAddress addr);
public static native int zts_send(int fd, byte[] buf, int flags);
public static native int zts_shutdown(int fd, int how);
public static native int zts_close(int fd);
public static native boolean zts_getsockname(int fd, ZeroTierSocketAddress addr);
public static native int zts_getpeername(int fd, ZeroTierSocketAddress addr);
public static native int zts_fcntl(int sock, int cmd, int flag);
// public static native int zts_ioctl(int fd, long request, ZeroTierIoctlArg arg);
public static native int zts_select(
int nfds,
ZeroTierFileDescriptorSet readfds,
ZeroTierFileDescriptorSet writefds,
ZeroTierFileDescriptorSet exceptfds,
int timeout_sec,
int timeout_usec);
}

View File

@@ -0,0 +1,194 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
import com.zerotier.sdk.*;
/**
* Class that provides a control interface for nodes and networks by
* wrapping the ZeroTierNative class.
*/
public class ZeroTierNode {
/**
* Start the ZeroTier node
*
* @return Standard
*/
public int start()
{
return ZeroTierNative.zts_node_start();
}
/**
* Stop the ZeroTier node
*
* @return return
*/
public int stop()
{
return ZeroTierNative.zts_node_stop();
}
/**
* (Optional) Instruct ZeroTier to read and write identities and cache from a
* storage location. Note that this is an initialization method that should
* be called before {@code start()}.
*
* @param storagePath Where to read and write files
*
* @return return
*/
public int initFromStorage(String storagePath)
{
return ZeroTierNative.zts_init_from_storage(storagePath);
}
/**
* (Optional) Whether caching of peer address information to storage is allowed. This
* is true by default if {@code initFromStorage()} is used. Note that this is an
* initialization method that can only be called before {@code start()}.
*
* @param allowed Whether caching or storage of this item is allowed
*
* @return return
*/
public int initAllowPeerCache(boolean allowed)
{
return ZeroTierNative.zts_init_allow_peer_cache(allowed ? 1 : 0);
}
/**
* (Optional) Whether caching of network configuration data to storage is allowed. This
* is true by default if {@code initFromStorage()} is used. Note that this is an
* initialization method that can only be called before {@code start()}.
*
* @param allowed Whether caching or storage of this item is allowed
*
* @return return
*/
public int initAllowNetworkCache(boolean allowed)
{
return ZeroTierNative.zts_init_allow_net_cache(allowed ? 1 : 0);
}
/**
* (Optional) Whether caching of identity key pairs to storage is allowed. This
* is true by default if {@code initFromStorage()} is used. Note that this is an
* initialization method that can only be called before {@code start()}.
*
* @param allowed Whether caching or storage of this item is allowed
*
* @return return
*/
public int initAllowIdCache(boolean allowed)
{
return ZeroTierNative.zts_init_allow_id_cache(allowed ? 1 : 0);
}
/**
* (Optional) Whether caching of root topology to storage is allowed. This
* is true by default if {@code initFromStorage()} is used. Note that this is an
* initialization method that can only be called before {@code start()}.
*
* @param allowed Whether caching or storage of this item is allowed
*
* @return return
*/
public int initAllowRootsCache(boolean allowed)
{
return ZeroTierNative.zts_init_allow_roots_cache(allowed ? 1 : 0);
}
/**
* (Optional) Set the ZeroTier service port. Note that this is an
* initialization method that can only be called before {@code start()}.
*
* @param port Port number
*
* @return return
*/
public int initSetPort(short port)
{
return ZeroTierNative.zts_init_set_port(port);
}
/**
* (Optional) Set the event handler function. Note that this is an
* initialization method that can only be called before {@code start()}.
*
* @param handler Function to handle internal ZeroTier events
*
* @return return
*/
public int initSetEventHandler(ZeroTierEventListener handler)
{
return ZeroTierNative.zts_init_set_event_handler(handler);
}
/**
* Return whether the ZeroTier node is currently online (able to reach a root)
*
* @return return
*/
public boolean isOnline()
{
return ZeroTierNative.zts_node_is_online() == 1;
}
/**
* Join a network
*
* @param networkId Network to join
*
* @return return
*/
public int join(long networkId)
{
return ZeroTierNative.zts_net_join(networkId);
}
/**
* Leave a network
*
* @param networkId Network to leave
*
* @return return
*/
public int leave(long networkId)
{
return ZeroTierNative.zts_net_leave(networkId);
}
/**
* Return whether the given network is ready to process traffic
*
* @param networkId Network to test
*
* @return return
*/
public boolean isNetworkTransportReady(long networkId)
{
return ZeroTierNative.zts_net_transport_is_ready(networkId) == 1;
}
/**
* Get the identity of this node (public key)
*
* @return 64-bit integer representing the 10-digit hexadecimal node ID
*/
public long getId()
{
return ZeroTierNative.zts_node_get_id();
}
}

View File

@@ -0,0 +1,97 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
import com.zerotier.sdk.*;
import java.io.*;
import java.util.Arrays;
import java.util.Objects;
/**
* Extends OutputStream using ZeroTier as a transport
*/
public class ZeroTierOutputStream extends OutputStream {
/**
* File descriptor used by lower native layer
*/
public int zfd = -1;
/**
* Close the stream
* @exception IOException when an I/O error occurs
*/
public void close() throws IOException
{
/* Note: this operation currently only stops RX on a socket that is
shared between both I/OStreams. This means that closing this stream
will only shutdown that aspect of the socket but not actually close
it and free resources. Resources will be properly freed when the
socket implementation's native close() is called or if both I/OStreams
are closed separately */
ZeroTierNative.zts_shutdown(zfd, ZeroTierNative.ZTS_SHUT_WR);
zfd = -1;
}
/**
* Write a buffer
* @param originBuffer Source buffer
* @exception IOException when an I/O error occurs
*/
public void write(byte[] originBuffer) throws IOException
{
int bytesWritten = ZeroTierNative.zts_write(zfd, originBuffer);
if (bytesWritten < 0) {
throw new IOException("write(originBuffer[]), errno=" + bytesWritten);
}
}
/**
* Write a buffer at offset
* @param originBuffer Source buffer
* @param offset Where in the buffer to start
* @param numBytes Number of bytes to write
* @exception IOException when an I/O error occurs
*/
public void write(byte[] originBuffer, int offset, int numBytes) throws IOException
{
Objects.requireNonNull(originBuffer, "input byte array (originBuffer) must not be null");
if (offset < 0) {
throw new IndexOutOfBoundsException("offset < 0");
}
if (numBytes < 0) {
throw new IndexOutOfBoundsException("numBytes < 0");
}
if ((offset + numBytes) > originBuffer.length) {
throw new IndexOutOfBoundsException("(offset+numBytes) > originBuffer.length");
}
int bytesWritten = ZeroTierNative.zts_write_offset(zfd, originBuffer, offset, numBytes);
if (bytesWritten < 0) {
throw new IOException("write(originBuffer[],offset,numBytes), errno=" + bytesWritten);
}
}
/**
* Write low byte
* @param d Integer containing low byte to write
* @exception IOException when an I/O error occurs
*/
public void write(int d) throws IOException
{
byte lowByte = (byte)(d & 0xFF);
int bytesWritten = ZeroTierNative.zts_write_byte(zfd, lowByte);
if (bytesWritten < 0) {
throw new IOException("write(d), errno=" + bytesWritten);
}
}
}

View File

@@ -0,0 +1,61 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
import com.zerotier.sdk.*;
/**
* This class encapsulates details about a Peer on a ZeroTier network
*/
class ZeroTierPeerDetails {
/**
* ZeroTier address (40 bits)
*/
public long address;
/**
* Remote major version or -1 if not known
*/
public int versionMajor;
/**
* Remote minor version or -1 if not known
*/
public int versionMinor;
/**
* Remote revision or -1 if not known
*/
public int versionRev;
/**
* Last measured latency in milliseconds or -1 if unknown
*/
public int latency;
/**
* What trust hierarchy role does this device have?
*/
public int role;
/**
* Number of paths (size of paths[])
*/
public int pathCount;
/**
* Known network paths to peer
*/
public ZeroTierSocketAddress[] paths = new ZeroTierSocketAddress[ZeroTierNative.ZTS_MAX_PEER_NETWORK_PATHS];
}

View File

@@ -0,0 +1,617 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
import com.zerotier.sdk.*;
import java.io.*;
import java.net.*;
/**
* Implements Socket-like behavior over ZeroTier
*
* @author ZeroTier, Inc.
*/
public class ZeroTierSocket {
// File descriptor from lower native layer
private int _zfd = -1;
private int _family = -1;
private int _type = -1;
private int _protocol = -1;
// State flags
private boolean _isClosed = false;
private boolean _isConnected = false;
private boolean _isBound = false;
private boolean _inputHasBeenShutdown = false;
private boolean _outputHasBeenShutdown = false;
// Input and Output streams
private ZeroTierInputStream _inputStream = new ZeroTierInputStream();
private ZeroTierOutputStream _outputStream = new ZeroTierOutputStream();
// The remote address to which the ZeroTierSocket is connected
private InetAddress _remoteAddr;
private int _remotePort;
private InetAddress _localAddr;
private int _localPort;
private void setNativeFileDescriptor(int fd)
{
_zfd = fd;
_inputStream.zfd = fd;
_outputStream.zfd = fd;
}
private ZeroTierSocket(int family, int type, int protocol, int zfd)
{
_family = family;
_type = type;
_protocol = protocol;
setNativeFileDescriptor(zfd);
// Since we only call this from accept() we will mark it as connected
_isConnected = true;
}
/**
* Create a new ZeroTierSocket with the given attributes
* @param family The socket family
* @param type The socket type
* @param protocol Supported protocol
*
* @exception IOException when an I/O error occurs
*/
public ZeroTierSocket(int family, int type, int protocol) throws IOException
{
if (_zfd > -1) {
throw new IOException("This socket has already been created (fd=" + _zfd + ")");
}
_zfd = ZeroTierNative.zts_socket(ZeroTierNative.ZTS_AF_INET, ZeroTierNative.ZTS_SOCK_STREAM, protocol);
if (_zfd < 0) {
throw new IOException("Error while creating socket (" + _zfd + ")");
}
_family = family;
_type = type;
_protocol = protocol;
setNativeFileDescriptor(_zfd);
}
/**
* Connect to a remote host
* @param remoteAddr Remote address to which this socket should connect
* @param remotePort Remote port to which this socket should connect
*
* @exception IOException when an I/O error occurs
*/
public void connect(InetAddress remoteAddr, int remotePort) throws IOException
{
if (_zfd < 0) {
throw new IOException("Invalid socket (fd < 0)");
}
if ((remoteAddr instanceof Inet4Address) && _family != ZeroTierNative.ZTS_AF_INET) {
throw new IOException("Invalid address type. Socket is of type AF_INET");
}
if ((remoteAddr instanceof Inet6Address) && _family != ZeroTierNative.ZTS_AF_INET6) {
throw new IOException("Invalid address type. Socket is of type AF_INET6");
}
int err;
if ((err = ZeroTierNative.zts_simple_connect(_zfd, remoteAddr.getHostAddress(), remotePort, 0)) < 0) {
throw new IOException("Error while connecting to remote host (" + err + ")");
}
_isConnected = true;
}
/**
* Connect to a remote host
* @param remoteAddr Remote address to which this socket should connect
* @param remotePort Remote port to which this socket should connect
*
* @exception IOException when an I/O error occurs
*/
public void connect(String remoteAddr, int remotePort) throws IOException
{
InetAddress remoteInetAddr = InetAddress.getByName(remoteAddr);
connect(remoteInetAddr, remotePort);
}
/**
* Connect to a remote host
* @param remoteAddr Remote address to which this socket should connect
*
* @exception IOException when an I/O error occurs
*/
public void connect(SocketAddress remoteAddr) throws IOException
{
int remotePort = ((InetSocketAddress)remoteAddr).getPort();
connect(((InetSocketAddress)remoteAddr).getHostString(), remotePort);
}
/**
* Bind to a local address
* @param localAddr Local address to which this socket should bind
* @param localPort Local port to which this socket should bind
*
* @exception IOException when an I/O error occurs
*/
public void bind(InetAddress localAddr, int localPort) throws IOException
{
if (_zfd < 0) {
throw new IOException("Invalid socket (fd < 0)");
}
if ((localAddr instanceof Inet4Address) && _family != ZeroTierNative.ZTS_AF_INET) {
throw new IOException("Invalid address type. Socket is of type AF_INET");
}
if ((localAddr instanceof Inet6Address) && _family != ZeroTierNative.ZTS_AF_INET6) {
throw new IOException("Invalid address type. Socket is of type AF_INET6");
}
int err;
if ((err = ZeroTierNative.zts_simple_bind(_zfd, localAddr.getHostAddress(), localPort)) < 0) {
throw new IOException("Error while connecting to remote host (" + err + ")");
}
_localPort = localPort;
_isBound = true;
}
/**
* Bind to a local address
* @param localAddr Local address to which this socket should bind
* @param localPort Local port to which this socket should bind
*
* @exception IOException when an I/O error occurs
*/
public void bind(String localAddr, int localPort) throws IOException
{
InetAddress localInetAddr = InetAddress.getByName(localAddr);
bind(localInetAddr, localPort);
}
/**
* Put the ZeroTierSocket into a listening state
* @param backlog Size of connection backlog
*
* @exception IOException when an I/O error occurs
*/
public void listen(int backlog) throws IOException
{
if (_zfd < 0) {
throw new IOException("Invalid socket (fd < 0)");
}
if (backlog < 0) {
throw new IOException("Invalid backlog value");
}
int err;
if ((err = ZeroTierNative.zts_listen(_zfd, backlog)) < 0) {
throw new IOException("Error while putting socket into listening state (" + err + ")");
}
}
/**
* Accept incoming connections on this ZeroTierSocket
* @return New ZeroTierSocket representing the accepted connection
* @exception IOException when an I/O error occurs
*/
public ZeroTierSocket accept() throws IOException
{
if (_zfd < 0) {
throw new IOException("Invalid socket (fd < 0)");
}
int accetpedFd = -1;
ZeroTierSocketAddress addr = new ZeroTierSocketAddress();
if ((accetpedFd = ZeroTierNative.zts_accept(_zfd, addr)) < 0) {
throw new IOException("Error while accepting connection (" + accetpedFd + ")");
}
return new ZeroTierSocket(_family, _type, _protocol, accetpedFd);
}
/**
* Close the ZeroTierSocket.
*
* @exception IOException when an I/O error occurs
*/
public void close() throws IOException
{
if (_zfd < 0) {
throw new IOException("Invalid socket (fd < 0)");
}
ZeroTierNative.zts_close(_zfd);
_isClosed = true;
}
/**
* Return whether keepalive is enabled.
* @return true or false
* @exception SocketException when an error occurs in the native socket layer
*/
public boolean getKeepAlive() throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
return ZeroTierNative.zts_simple_get_keepalive(_zfd) == 1;
}
/**
* Get the local port to which this ZeroTierSocket is bound
* @return Local port
*/
public int getLocalPort()
{
if (! _isBound) {
return -1;
}
return _localPort;
}
/**
* Get the local address to which this ZeroTierSocket is bound
* @return Local address
*/
public InetAddress getLocalAddress()
{
if (! _isBound) {
return null;
}
return _localAddr;
}
/**
* Get the remote port to which this ZeroTierSocket is bound
* @return Remote port
*/
public int getRemotePort()
{
if (! _isConnected) {
return -1;
}
return _remotePort;
}
/**
* Get the remote address to which this ZeroTierSocket is bound
* @return Remote address
*/
public InetAddress getRemoteAddress()
{
if (! _isConnected) {
return null;
}
return _remoteAddr;
}
/**
* Return the size of the receive buffer for the ZeroTierSocket's ZeroTierInputStream (SO_RCVBUF)
* @return Size of the receive buffer
* @exception SocketException when an error occurs in the native socket layer
*/
public int getReceiveBufferSize() throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
return ZeroTierNative.zts_simple_get_recv_buf_size(_zfd);
}
/**
* Return the size of the send buffer for the ZeroTierSocket's ZeroTierOutputStream (SO_SNDBUF)
* @return Size of the send buffer
* @exception SocketException when an error occurs in the native socket layer
*/
public int getSendBufferSize() throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
return ZeroTierNative.zts_simple_get_send_buf_size(_zfd);
}
/**
* Return whether address reuse is enabled on this ZeroTierSocket (SO_REUSEADDR)
* @return true or false
* @exception SocketException when an error occurs in the native socket layer
*/
public boolean getReuseAddressEnabled() throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
return ZeroTierNative.zts_simple_get_reuse_addr(_zfd) == 1;
}
/**
* Return the amount of time that a ZeroTierSocket will linger after closure (SO_LINGER)
* @return Nothing.
* @exception SocketException when an error occurs in the native socket layer
*/
public int getSoLingerTime() throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
return ZeroTierNative.zts_simple_get_linger_value(_zfd);
}
/**
* Get the ZeroTierSocket's timeout value (SO_RCVTIMEO)
* @return Nothing.
* @exception SocketException when an error occurs in the native socket layer
*/
public int getSoTimeout() throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
return ZeroTierNative.zts_simple_get_recv_timeout(_zfd);
}
/**
* Return whether TCP no-delay is enabled (TCP_NODELAY)
* @return true or false
* @exception SocketException when an error occurs in the native socket layer
*/
public boolean tcpNoDelayEnabled() throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
return ZeroTierNative.zts_simple_get_no_delay(_zfd) == 1;
}
/**
* Return whether this ZeroTierSocket is bound to a local address
* @return true or false
*/
public boolean isBound()
{
return _isBound;
}
/**
* Return whether this ZeroTierSocket has been closed
* @return true or false
*/
public boolean isClosed()
{
return _isClosed;
}
/**
* Return whether this ZeroTierSocket is connected to a remote address
* @return true or false
*/
public boolean isConnected()
{
return _isConnected;
}
/**
* Disable the input-aspect of the ZeroTierSocket.
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void shutdownInput() throws SocketException
{
if (! _isConnected) {
throw new SocketException("Error: ZeroTierSocket is not connected");
}
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (_inputHasBeenShutdown) {
throw new SocketException("Error: ZeroTierSocket input has been shut down");
}
ZeroTierNative.zts_shutdown(_zfd, ZeroTierNative.ZTS_SHUT_RD);
_inputHasBeenShutdown = true;
}
/**
* Disable the output-aspect of the ZeroTierSocket.
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void shutdownOutput() throws SocketException
{
if (! _isConnected) {
throw new SocketException("Error: ZeroTierSocket is not connected");
}
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (_outputHasBeenShutdown) {
throw new SocketException("Error: ZeroTierSocket output has been shut down");
}
ZeroTierNative.zts_shutdown(_zfd, ZeroTierNative.ZTS_SHUT_WR);
_outputHasBeenShutdown = true;
}
/**
* Return a reference to the ZeroTierInputStream used by this ZeroTierSocket
* @return A reference to the ZeroTierInputStream
* @exception SocketException when an error occurs in the native socket layer
*/
public ZeroTierInputStream getInputStream() throws SocketException
{
if (! _isConnected) {
throw new SocketException("Error: ZeroTierSocket is not connected");
}
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (_inputHasBeenShutdown) {
throw new SocketException("Error: ZeroTierSocket input has been shut down");
}
return _inputStream;
}
/**
* Return a reference to the ZeroTierOutputStream used by this ZeroTierSocket
* @return A reference to the ZeroTierOutputStream
* @exception SocketException when an error occurs in the native socket layer
*/
public ZeroTierOutputStream getOutputStream() throws SocketException
{
if (! _isConnected) {
throw new SocketException("Error: ZeroTierSocket is not connected");
}
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (_outputHasBeenShutdown) {
throw new SocketException("Error: ZeroTierSocket output has been shut down");
}
return _outputStream;
}
/**
* Return whether the input-aspect of the ZeroTierSocket has been disabled.
* @return true or false
*/
public boolean inputStreamHasBeenShutdown()
{
return _inputHasBeenShutdown;
}
/**
* Return whether the output-aspect of the ZeroTierSocket has been disabled.
* @return true or false
*/
public boolean outputStreamHasBeenShutdown()
{
return _outputHasBeenShutdown;
}
/**
* Enable or disable the keepalive setting (SO_KEEPALIVE)
* @param enabled Whether SO_KEEPALIVE is enabled.
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void setKeepAliveEnabled(boolean enabled) throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (ZeroTierNative.zts_simple_set_keepalive(_zfd, (enabled ? 1 : 0)) != ZeroTierNative.ZTS_ERR_OK) {
throw new SocketException("Error: Could not set SO_KEEPALIVE");
}
}
/**
* Set the size of the receive buffer for the ZeroTierSocket's ZeroTierInputStream.
* @param bufferSize Size of receive buffer
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void setReceiveBufferSize(int bufferSize) throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (bufferSize <= 0) {
throw new IllegalArgumentException("Error: bufferSize <= 0");
}
if (ZeroTierNative.zts_simple_set_recv_buf_size(_zfd, bufferSize) != ZeroTierNative.ZTS_ERR_OK) {
throw new SocketException("Error: Could not set receive buffer size");
}
}
/**
* Enable or disable the re-use of addresses (SO_REUSEADDR)
* @param enabled Whether SO_REUSEADDR is enabled
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void setReuseAddress(boolean enabled) throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (ZeroTierNative.zts_simple_set_reuse_addr(_zfd, (enabled ? 1 : 0)) != ZeroTierNative.ZTS_ERR_OK) {
throw new SocketException("Error: Could not set SO_REUSEADDR");
}
}
/**
* Set the size of the send buffer for the ZeroTierSocket's ZeroTierOutputStream (SO_SNDBUF)
* @param bufferSize Size of send buffer
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void setSendBufferSize(int bufferSize) throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (bufferSize <= 0) {
throw new IllegalArgumentException("Error: bufferSize <= 0");
}
if (ZeroTierNative.zts_simple_set_send_buf_size(_zfd, bufferSize) != ZeroTierNative.ZTS_ERR_OK) {
throw new SocketException("Error: Could not set SO_SNDBUF");
}
}
/**
* Set the amount of time that a ZeroTierSocket will linger after closure (SO_LINGER)
* @param enabled Whether SO_LINGER is enabled
* @param lingerTime SO_LINGER time
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void setSoLinger(boolean enabled, int lingerTime) throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (lingerTime < 0) {
throw new IllegalArgumentException("Error: lingerTime < 0");
}
if (ZeroTierNative.zts_simple_set_linger(_zfd, (enabled ? 1 : 0), lingerTime) != ZeroTierNative.ZTS_ERR_OK) {
throw new SocketException("Error: Could not set ZTS_SO_LINGER");
}
}
/**
* Set the timeout value for SO_RCVTIMEO
* @param timeout Socket receive timeout value.
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void setSoTimeoutValue(int timeout) throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (timeout < 0) {
throw new IllegalArgumentException("Error: SO_TIMEOUT < 0");
}
// TODO: This is incorrect
if (ZeroTierNative.zts_simple_set_recv_timeout(_zfd, timeout, timeout) != ZeroTierNative.ZTS_ERR_OK) {
throw new SocketException("Error: Could not set SO_RCVTIMEO");
}
}
/**
* Enable or disable TCP_NODELAY
* @param enabled Whether TCP_NODELAY is enabled
*
* @exception SocketException when an error occurs in the native socket layer
*/
public void setTcpNoDelayEnabled(boolean enabled) throws SocketException
{
if (_isClosed) {
throw new SocketException("Error: ZeroTierSocket is closed");
}
if (ZeroTierNative.zts_simple_set_no_delay(_zfd, (enabled ? 1 : 0)) != ZeroTierNative.ZTS_ERR_OK) {
throw new SocketException("Error: Could not set TCP_NODELAY");
}
}
}

View File

@@ -0,0 +1,124 @@
/*
* 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.
*/
/****/
package com.zerotier.sdk;
import com.zerotier.sdk.ZeroTierNative;
import java.net.InetAddress;
/**
* Convenience class for holding address information. Used internally by JNI layer.
*/
class ZeroTierSocketAddress {
private byte[] _ip6 = new byte[16];
private byte[] _ip4 = new byte[4];
private int _family;
private int _port; // Also reused for netmask or prefix
public ZeroTierSocketAddress()
{
}
/**
* Constructor
*/
public ZeroTierSocketAddress(String ipStr, int port)
{
if (ipStr.contains(":")) {
_family = ZeroTierNative.ZTS_AF_INET6;
try {
InetAddress ip = InetAddress.getByName(ipStr);
_ip6 = ip.getAddress();
}
catch (Exception e) {
}
}
else if (ipStr.contains(".")) {
_family = ZeroTierNative.ZTS_AF_INET;
try {
InetAddress ip = InetAddress.getByName(ipStr);
_ip4 = ip.getAddress();
}
catch (Exception e) {
}
}
_port = port;
}
/**
* Convert to string (ip portion only)
*/
public String ipString()
{
if (_family == ZeroTierNative.ZTS_AF_INET) {
try {
InetAddress inet = InetAddress.getByAddress(_ip4);
return "" + inet.getHostAddress();
}
catch (Exception e) {
System.out.println(e);
}
}
if (_family == ZeroTierNative.ZTS_AF_INET6) {
try {
InetAddress inet = InetAddress.getByAddress(_ip6);
return "" + inet.getHostAddress();
}
catch (Exception e) {
System.out.println(e);
}
}
return "";
}
/**
* Convert to string (ip and port)
*/
public String toString()
{
return ipString() + ":" + _port;
}
/**
* Convert to string (ip+netmask and port)
*/
public String toCIDR()
{
return ipString() + "/" + _port;
}
/**
* Get port
*/
public int getPort()
{
return _port;
}
/**
* Get netmask
*/
public int getNetmask()
{
return _port;
}
/**
* Get prefix (stored in port)
*/
public int getPrefix()
{
return _port;
}
}

138
test/selftest.java Normal file
View File

@@ -0,0 +1,138 @@
import com.zerotier.sdk.*;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.math.BigInteger;
public class selftest {
public static void main(String[] args)
{
System.err.println(args.length);
if (args.length < 4 || args.length > 5) {
System.err.println("Invalid arguments");
System.err.println(" Usage: <server|client> <id_path> <network> <addr> <port>");
System.err.println(" example server ./ 0123456789abcdef 8080");
System.err.println(" example client ./ 0123456789abcdef 192.168.22.1 8080\n");
System.exit(1);
}
String storagePath = "";
String remoteAddr = "";
int port = 0;
String mode = args[0];
storagePath = args[1];
BigInteger networkId = new BigInteger(args[2], 16);
if (args.length == 4) {
port = Integer.parseInt(args[3]);
}
if (args.length == 5) {
remoteAddr = args[3];
port = Integer.parseInt(args[4]);
}
System.out.println("mode = " + mode);
System.out.println("networkId = " + Long.toHexString(networkId.longValue()));
System.out.println("storagePath = " + storagePath);
System.out.println("remoteAddr = " + remoteAddr);
System.out.println("port = " + port);
// ZeroTier setup
ZeroTierNode node = new ZeroTierNode();
node.initFromStorage(storagePath);
// node.initSetEventHandler(new MyZeroTierEventListener());
// node.initSetPort(9994);
node.start();
System.out.println("Waiting for node to come online...");
while (! node.isOnline()) {
ZeroTierNative.zts_util_delay(50);
}
System.out.println("Node ID: " + Long.toHexString(node.getId()));
System.out.println("Joining network...");
node.join(networkId.longValue());
System.out.println("Waiting for network...");
while (! node.isNetworkTransportReady(networkId.longValue())) {
ZeroTierNative.zts_util_delay(50);
}
System.out.println("joined");
// Socket logic
if (mode.equals("server")) {
System.out.println("Starting server...");
try {
ZeroTierSocket socket =
new ZeroTierSocket(ZeroTierNative.ZTS_AF_INET, ZeroTierNative.ZTS_SOCK_STREAM, 0);
socket.bind("0.0.0.0", port);
socket.listen(100);
ZeroTierSocket newConnection = socket.accept();
ZeroTierInputStream inputStream = newConnection.getInputStream();
DataInputStream dataInputStream = new DataInputStream(inputStream);
String message = dataInputStream.readUTF();
System.out.println("recv: " + message);
socket.close();
newConnection.close();
}
catch (Exception ex) {
System.out.println(ex);
}
}
if (mode.equals("client")) {
System.out.println("Starting client...");
try {
ZeroTierSocket socket =
new ZeroTierSocket(ZeroTierNative.ZTS_AF_INET, ZeroTierNative.ZTS_SOCK_STREAM, 0);
socket.connect(remoteAddr, port);
ZeroTierOutputStream outputStream = socket.getOutputStream();
DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
dataOutputStream.writeUTF("Hello from java!");
socket.close();
}
catch (Exception ex) {
System.out.println(ex);
}
}
}
}
/**
* (OPTIONAL) event handler
*/
/*
class MyZeroTierEventListener implements ZeroTierEventListener {
public void onZeroTierEvent(long id, int event_code)
{
if (event_code == ZeroTierNative.ZTS_EVENT_NODE_UP) {
System.out.println("EVENT_NODE_UP");
}
if (event_code == ZeroTierNative.ZTS_EVENT_NODE_ONLINE) {
System.out.println("EVENT_NODE_ONLINE: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NODE_OFFLINE) {
System.out.println("EVENT_NODE_OFFLINE");
}
if (event_code == ZeroTierNative.ZTS_EVENT_NODE_DOWN) {
System.out.println("EVENT_NODE_DOWN");
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_READY_IP4) {
System.out.println("ZTS_EVENT_NETWORK_READY_IP4: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_READY_IP6) {
System.out.println("ZTS_EVENT_NETWORK_READY_IP6: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_DOWN) {
System.out.println("EVENT_NETWORK_DOWN: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_OK) {
System.out.println("EVENT_NETWORK_OK: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_ACCESS_DENIED) {
System.out.println("EVENT_NETWORK_ACCESS_DENIED: " + Long.toHexString(id));
}
if (event_code == ZeroTierNative.ZTS_EVENT_NETWORK_NOT_FOUND) {
System.out.println("EVENT_NETWORK_NOT_FOUND: " + Long.toHexString(id));
}
}
}
*/