Update Python bindings to 1.4.0 API (WIP)
This commit is contained in:
5
.github/workflows/auto-format.yml
vendored
5
.github/workflows/auto-format.yml
vendored
@@ -9,8 +9,11 @@ jobs:
|
|||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install black
|
||||||
|
run: pip3 install black
|
||||||
|
|
||||||
- name: Format code
|
- name: Format code
|
||||||
run: ./build.sh format-code
|
run: ./build.sh format-code "all"
|
||||||
|
|
||||||
- name: Commit changes
|
- name: Commit changes
|
||||||
uses: joseph-henry/add-and-commit@v7
|
uses: joseph-henry/add-and-commit@v7
|
||||||
|
|||||||
126
build.sh
126
build.sh
@@ -4,6 +4,13 @@
|
|||||||
# | SYSTEM DISCOVERY AND CONFIGURATION |
|
# | SYSTEM DISCOVERY AND CONFIGURATION |
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
CLANG_FORMAT=clang-format-11
|
||||||
|
|
||||||
|
PYTHON=python3
|
||||||
|
PIP=pip3
|
||||||
|
|
||||||
|
libzt=$(pwd)
|
||||||
|
|
||||||
# Find and set cmake
|
# Find and set cmake
|
||||||
CMAKE=cmake3
|
CMAKE=cmake3
|
||||||
if [[ $(which $CMAKE) = "" ]];
|
if [[ $(which $CMAKE) = "" ]];
|
||||||
@@ -356,7 +363,7 @@ host-uninstall()
|
|||||||
# └── pkg
|
# └── pkg
|
||||||
# └── libzt-1.3.4b1-cp39-cp39-macosx_11_0_x86_64.whl
|
# └── libzt-1.3.4b1-cp39-cp39-macosx_11_0_x86_64.whl
|
||||||
#
|
#
|
||||||
host-python-wheel()
|
host-python()
|
||||||
{
|
{
|
||||||
ARTIFACT="python"
|
ARTIFACT="python"
|
||||||
# Default to release
|
# Default to release
|
||||||
@@ -365,30 +372,47 @@ host-python-wheel()
|
|||||||
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
|
||||||
|
# Generate new wrapper
|
||||||
|
#swig -c++ -python -o src/bindings/python/zt_wrap.cxx -Iinclude src/bindings/python/zt.i
|
||||||
# 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
|
||||||
|
echo -e "\nFinished wheel:\n"
|
||||||
|
echo $PKG_OUTPUT_DIR/*.whl
|
||||||
|
|
||||||
|
# Test Python wheel
|
||||||
|
if [[ $2 = *"test"* ]]; then
|
||||||
|
if [[ -z "${alice_path}" ]]; then
|
||||||
|
echo "Please set necessary environment variables for test"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
pip3 uninstall -y libzt
|
||||||
|
pip3 install $PKG_OUTPUT_DIR/*.whl
|
||||||
|
cd $libzt
|
||||||
|
$PYTHON test/selftest.py server $alice_path $testnet $port4 &
|
||||||
|
$PYTHON test/selftest.py client $bob_path $testnet $alice_ip4 $port4 &
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# 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()
|
||||||
@@ -579,26 +603,46 @@ test()
|
|||||||
|
|
||||||
format-code()
|
format-code()
|
||||||
{
|
{
|
||||||
if [[ ! $(which clang-format) = "" ]];
|
if [[ $1 = *"all"* ]]; then
|
||||||
then
|
format-code "clang"
|
||||||
# Eventually: find . -path ./ext -prune -false -o -type f \( -iname \*.c -o -iname \*.h -o -iname \*.cpp -o -iname \*.hpp \) -exec clang-format -i {} \;
|
format-code "python"
|
||||||
clang-format-11 -i include/*.h \
|
fi
|
||||||
src/*.c \
|
|
||||||
src/*.cpp \
|
# Clang-format
|
||||||
src/*.hpp \
|
if [[ $1 = *"clang"* ]]; then
|
||||||
examples/c/*.c \
|
if [[ ! $(which $CLANG_FORMAT) = "" ]];
|
||||||
examples/csharp/*.cs \
|
then
|
||||||
examples/java/*.java \
|
# Eventually: find . -path ./ext -prune -false -o -type f \( -iname \*.c -o -iname \*.h -o -iname \*.cpp -o -iname \*.hpp \) -exec clang-format -i {} \;
|
||||||
test/*.c \
|
$CLANG_FORMAT -i include/*.h \
|
||||||
test/*.cs \
|
src/*.c \
|
||||||
src/bindings/csharp/*.cs \
|
src/*.cpp \
|
||||||
src/bindings/csharp/*.cxx \
|
src/*.hpp \
|
||||||
src/bindings/java/*.java \
|
examples/c/*.c \
|
||||||
src/bindings/java/*.cxx \
|
examples/csharp/*.cs \
|
||||||
examples/csharp/*.cs
|
examples/java/*.java \
|
||||||
return 0
|
test/*.c \
|
||||||
else
|
test/*.cs \
|
||||||
echo "Please install clang-format."
|
src/bindings/csharp/*.cs \
|
||||||
|
src/bindings/csharp/*.cxx \
|
||||||
|
src/bindings/java/*.java \
|
||||||
|
src/bindings/java/*.cxx \
|
||||||
|
examples/csharp/*.cs \
|
||||||
|
src/bindings/python/*.cxx \
|
||||||
|
src/bindings/python/*.h
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
echo "Please install clang-format"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
# Python
|
||||||
|
if [[ $1 = *"python"* ]]; then
|
||||||
|
if [[ ! $($PIP list | grep black) = "" ]];
|
||||||
|
then
|
||||||
|
$PYTHON -m black src/bindings/python/*.py
|
||||||
|
$PYTHON -m black examples/python/*.py
|
||||||
|
else
|
||||||
|
echo "Please install python module (black)"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,6 +681,8 @@ clean()
|
|||||||
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
|
||||||
|
# Python pkg
|
||||||
|
cd pkg/pypi && ./build.sh clean
|
||||||
# Remove whatever remains
|
# Remove whatever remains
|
||||||
find . \
|
find . \
|
||||||
\( -name '*.dylib' \
|
\( -name '*.dylib' \
|
||||||
|
|||||||
@@ -1,106 +1,92 @@
|
|||||||
'''Example low-level socket usage'''
|
"""Example low-level socket usage"""
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import libzt
|
import libzt
|
||||||
|
|
||||||
|
|
||||||
def print_usage():
|
def print_usage():
|
||||||
'''print help'''
|
"""print help"""
|
||||||
print(
|
print(
|
||||||
"\nUsage: <server|client> <id_path> <nwid> <zt_service_port> <remote_ip> <remote_port>\n"
|
"\nUsage: <server|client> <storage_path> <net_id> <remote_ip> <remote_port>\n"
|
||||||
)
|
)
|
||||||
print("Ex: python3 demo.py server . 0123456789abcdef 9994 8080")
|
print("Ex: python3 example.py server . 0123456789abcdef 8080")
|
||||||
print("Ex: python3 demo.py client . 0123456789abcdef 9994 192.168.22.1 8080\n")
|
print("Ex: python3 example.py client . 0123456789abcdef 192.168.22.1 8080\n")
|
||||||
if len(sys.argv) < 6:
|
if len(sys.argv) < 5:
|
||||||
print("Too few arguments")
|
print("Too few arguments")
|
||||||
if len(sys.argv) > 7:
|
if len(sys.argv) > 6:
|
||||||
print("Too many arguments")
|
print("Too many arguments")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
is_joined = False # Flags to keep state
|
#
|
||||||
is_online = False # Flags to keep state
|
# (Optional) Event handler
|
||||||
|
#
|
||||||
|
def on_zerotier_event(event_code, id):
|
||||||
|
if event_code == libzt.ZTS_EVENT_NODE_ONLINE:
|
||||||
|
print("ZTS_EVENT_NODE_ONLINE (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_NODE_OFFLINE:
|
||||||
|
print("ZTS_EVENT_NODE_OFFLINE (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_NETWORK_READY_IP4:
|
||||||
|
print("ZTS_EVENT_NETWORK_READY_IP4 (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_NETWORK_READY_IP6:
|
||||||
|
print("ZTS_EVENT_NETWORK_READY_IP6 (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_PEER_DIRECT:
|
||||||
|
print("ZTS_EVENT_PEER_DIRECT (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_PEER_RELAY:
|
||||||
|
print("ZTS_EVENT_PEER_RELAY (" + str(event_code) + ") : " + hex(id))
|
||||||
|
|
||||||
#
|
|
||||||
# Event handler
|
|
||||||
#
|
|
||||||
class MyEventCallbackClass(libzt.EventCallbackClass):
|
|
||||||
def on_zerotier_event(self, msg):
|
|
||||||
global is_online
|
|
||||||
global is_joined
|
|
||||||
print("eventCode=", msg.eventCode)
|
|
||||||
if msg.eventCode == libzt.ZTS_EVENT_NODE_ONLINE:
|
|
||||||
print("ZTS_EVENT_NODE_ONLINE")
|
|
||||||
print("nodeId=" + hex(msg.node.address))
|
|
||||||
# The node is now online, you can join/leave networks
|
|
||||||
is_online = True
|
|
||||||
if msg.eventCode == libzt.ZTS_EVENT_NODE_OFFLINE:
|
|
||||||
print("ZTS_EVENT_NODE_OFFLINE")
|
|
||||||
if msg.eventCode == libzt.ZTS_EVENT_NETWORK_READY_IP4:
|
|
||||||
print("ZTS_EVENT_NETWORK_READY_IP4")
|
|
||||||
is_joined = True
|
|
||||||
# The node has successfully joined a network and has an address
|
|
||||||
# you can perform network calls now
|
|
||||||
if msg.eventCode == libzt.ZTS_EVENT_PEER_DIRECT:
|
|
||||||
print("ZTS_EVENT_PEER_DIRECT")
|
|
||||||
if msg.eventCode == libzt.ZTS_EVENT_PEER_RELAY:
|
|
||||||
print("ZTS_EVENT_PEER_RELAY")
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Main
|
# Main
|
||||||
#
|
#
|
||||||
def main():
|
def main():
|
||||||
global is_online
|
mode = None # client|server
|
||||||
global is_joined
|
storage_path = "." # Where identity files are stored
|
||||||
|
net_id = 0 # Network to join
|
||||||
|
remote_ip = None # ZeroTier IP of remote node
|
||||||
|
remote_port = 8080 # ZeroTier port your app logic may use
|
||||||
|
|
||||||
key_file_path = "." # Where identity files are stored
|
if len(sys.argv) < 5 or len(sys.argv) > 6:
|
||||||
network_id = 0 # Network to join
|
|
||||||
# Port used by ZeroTier to send encpryted UDP traffic
|
|
||||||
# NOTE: Should be different from other instances of ZeroTier
|
|
||||||
# running on the same machine
|
|
||||||
zt_service_port = 9997
|
|
||||||
remote_ip = None # ZeroTier IP of remote node
|
|
||||||
remote_port = 8080 # ZeroTier port your app logic may use
|
|
||||||
mode = None # client|server
|
|
||||||
|
|
||||||
if len(sys.argv) < 6 or len(sys.argv) > 7:
|
|
||||||
print_usage()
|
print_usage()
|
||||||
if sys.argv[1] == "server" and len(sys.argv) == 6:
|
if sys.argv[1] == "server" and len(sys.argv) == 5:
|
||||||
mode = sys.argv[1]
|
mode = sys.argv[1]
|
||||||
key_file_path = sys.argv[2]
|
storage_path = sys.argv[2]
|
||||||
network_id = int(sys.argv[3], 16)
|
net_id = int(sys.argv[3], 16)
|
||||||
zt_service_port = int(sys.argv[4])
|
remote_port = int(sys.argv[4])
|
||||||
|
if sys.argv[1] == "client" and len(sys.argv) == 6:
|
||||||
|
mode = sys.argv[1]
|
||||||
|
storage_path = sys.argv[2]
|
||||||
|
net_id = int(sys.argv[3], 16)
|
||||||
|
remote_ip = sys.argv[4]
|
||||||
remote_port = int(sys.argv[5])
|
remote_port = int(sys.argv[5])
|
||||||
if sys.argv[1] == "client" and len(sys.argv) == 7:
|
|
||||||
mode = sys.argv[1]
|
|
||||||
key_file_path = sys.argv[2]
|
|
||||||
network_id = int(sys.argv[3], 16)
|
|
||||||
zt_service_port = int(sys.argv[4])
|
|
||||||
remote_ip = sys.argv[5]
|
|
||||||
remote_port = int(sys.argv[6])
|
|
||||||
if mode is None:
|
if mode is None:
|
||||||
print_usage()
|
print_usage()
|
||||||
print("mode = ", mode)
|
print("mode = ", mode)
|
||||||
print("path = ", key_file_path)
|
print("storage_path = ", storage_path)
|
||||||
print("network_id = ", network_id)
|
print("net_id = ", net_id)
|
||||||
print("zt_service_port = ", zt_service_port)
|
print("remote_ip = ", remote_ip)
|
||||||
print("remote_ip = ", remote_ip)
|
print("remote_port = ", remote_port)
|
||||||
print("remote_port = ", remote_port)
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Example start and join logic
|
# Node initialization and start
|
||||||
#
|
#
|
||||||
print("Starting ZeroTier...")
|
print("Starting ZeroTier...")
|
||||||
event_callback = MyEventCallbackClass()
|
|
||||||
libzt.start(key_file_path, event_callback, zt_service_port)
|
n = libzt.ZeroTierNode()
|
||||||
|
n.init_set_event_handler(on_zerotier_event) # Optional
|
||||||
|
n.init_from_storage(storage_path) # Optional
|
||||||
|
n.init_set_port(9994) # Optional
|
||||||
|
n.node_start()
|
||||||
|
|
||||||
print("Waiting for node to come online...")
|
print("Waiting for node to come online...")
|
||||||
while not is_online:
|
while not n.node_is_online():
|
||||||
|
time.sleep(1)
|
||||||
|
print("Joining network:", hex(net_id))
|
||||||
|
n.net_join(net_id)
|
||||||
|
while not n.net_transport_is_ready(net_id):
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
print("Joining network:", hex(network_id))
|
|
||||||
libzt.join(network_id)
|
|
||||||
while not is_joined:
|
|
||||||
time.sleep(1) # You can ping this app at this point
|
|
||||||
print("Joined network")
|
print("Joined network")
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -140,7 +126,7 @@ def main():
|
|||||||
try:
|
try:
|
||||||
print("connecting...")
|
print("connecting...")
|
||||||
client.connect((remote_ip, remote_port))
|
client.connect((remote_ip, remote_port))
|
||||||
data = "Hello, world!"
|
data = "Hello, roots!"
|
||||||
print("send: ", data)
|
print("send: ", data)
|
||||||
sent_bytes = client.send(data)
|
sent_bytes = client.send(data)
|
||||||
print("sent: " + str(sent_bytes) + " byte(s)")
|
print("sent: " + str(sent_bytes) + " byte(s)")
|
||||||
@@ -150,5 +136,6 @@ def main():
|
|||||||
print(ex)
|
print(ex)
|
||||||
print("errno=", libzt.errno())
|
print("errno=", libzt.errno())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -1058,6 +1058,10 @@ int zts_py_getblocking(int fd);
|
|||||||
// Central API //
|
// Central API //
|
||||||
//----------------------------------------------------------------------------//
|
//----------------------------------------------------------------------------//
|
||||||
|
|
||||||
|
#ifdef ZTS_ENABLE_PYTHON
|
||||||
|
#define ZTS_DISABLE_CENTRAL_API 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ZTS_DISABLE_CENTRAL_API
|
#ifndef ZTS_DISABLE_CENTRAL_API
|
||||||
|
|
||||||
#define ZTS_CENTRAL_DEFAULT_URL "https://my.zerotier.com"
|
#define ZTS_CENTRAL_DEFAULT_URL "https://my.zerotier.com"
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
README.md
|
|
||||||
setup.cfg
|
|
||||||
setup.py
|
|
||||||
@@ -8,7 +8,7 @@ ext()
|
|||||||
# Symbolic link to source tree so that sdist structure makes sense
|
# Symbolic link to source tree so that sdist structure makes sense
|
||||||
ln -s ../../ native
|
ln -s ../../ native
|
||||||
# Re-build wrapper to export C symbols
|
# Re-build wrapper to export C symbols
|
||||||
swig -c++ -python -o native/src/bindings/python/zt_wrap.cpp -I./native/include native/src/bindings/python/zt.i
|
swig -c++ -python -o native/src/bindings/python/zt_wrap.cxx -I./native/include native/src/bindings/python/zt.i
|
||||||
# Copy language bindings into module directory
|
# Copy language bindings into module directory
|
||||||
cp -f native/src/bindings/python/*.py libzt/
|
cp -f native/src/bindings/python/*.py libzt/
|
||||||
cp -f native/LICENSE.txt LICENSE
|
cp -f native/LICENSE.txt LICENSE
|
||||||
@@ -30,6 +30,7 @@ clean()
|
|||||||
find . -name '__pycache__' -type d -delete
|
find . -name '__pycache__' -type d -delete
|
||||||
rm -rf libzt/sockets.py
|
rm -rf libzt/sockets.py
|
||||||
rm -rf libzt/libzt.py
|
rm -rf libzt/libzt.py
|
||||||
|
rm -rf libzt/node.py
|
||||||
rm -rf src ext build dist native
|
rm -rf src ext build dist native
|
||||||
rm -rf libzt.egg-info
|
rm -rf libzt.egg-info
|
||||||
rm -rf LICENSE
|
rm -rf LICENSE
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
from .libzt import *
|
from .libzt import *
|
||||||
from .sockets import *
|
from .sockets import *
|
||||||
|
from .node import *
|
||||||
from .version import __version__
|
from .version import __version__
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "1.3.4b1"
|
__version__ = "1.4.0a0"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
version = attr: libzt.__version__
|
version = attr: libzt.__version__
|
||||||
description-file = README.md
|
description_file = README.md
|
||||||
license_files =
|
license_files =
|
||||||
native/LICENSE.txt
|
native/LICENSE.txt
|
||||||
native/ext/THIRDPARTY.txt
|
native/ext/THIRDPARTY.txt
|
||||||
|
|||||||
@@ -19,6 +19,27 @@ class BinaryDistribution(Distribution):
|
|||||||
def is_pure(self):
|
def is_pure(self):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
# monkey-patch for parallel compilation
|
||||||
|
# Copied from: https://stackoverflow.com/a/13176803
|
||||||
|
def parallelCCompile(self, sources, output_dir=None, macros=None, include_dirs=None, debug=0, extra_preargs=None, extra_postargs=None, depends=None):
|
||||||
|
# those lines are copied from distutils.ccompiler.CCompiler directly
|
||||||
|
macros, objects, extra_postargs, pp_opts, build = self._setup_compile(output_dir, macros, include_dirs, sources, depends, extra_postargs)
|
||||||
|
cc_args = self._get_cc_args(pp_opts, debug, extra_preargs)
|
||||||
|
# parallel code
|
||||||
|
N=16 # number of parallel compilations
|
||||||
|
import multiprocessing.pool
|
||||||
|
def _single_compile(obj):
|
||||||
|
try: src, ext = build[obj]
|
||||||
|
except KeyError: return
|
||||||
|
self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts)
|
||||||
|
# convert to list, imap is evaluated on-demand
|
||||||
|
list(multiprocessing.pool.ThreadPool(N).imap(_single_compile,objects))
|
||||||
|
return objects
|
||||||
|
import distutils.ccompiler
|
||||||
|
distutils.ccompiler.CCompiler.compile=parallelCCompile
|
||||||
|
|
||||||
|
# Build
|
||||||
|
|
||||||
cpp_glob = []
|
cpp_glob = []
|
||||||
c_glob = []
|
c_glob = []
|
||||||
|
|
||||||
@@ -30,7 +51,7 @@ if os.name == 'nt':
|
|||||||
|
|
||||||
# Everything else
|
# Everything else
|
||||||
else:
|
else:
|
||||||
cpp_glob.extend(list(glob.glob('native/src/bindings/python/*.cpp')))
|
cpp_glob.extend(list(glob.glob('native/src/bindings/python/*.cxx')))
|
||||||
cpp_glob.extend(list(glob.glob('native/src/*.cpp')))
|
cpp_glob.extend(list(glob.glob('native/src/*.cpp')))
|
||||||
cpp_glob.extend(list(glob.glob('native/ext/ZeroTierOne/node/*.cpp')))
|
cpp_glob.extend(list(glob.glob('native/ext/ZeroTierOne/node/*.cpp')))
|
||||||
cpp_glob.extend(list(glob.glob('native/ext/ZeroTierOne/osdep/OSUtils.cpp')))
|
cpp_glob.extend(list(glob.glob('native/ext/ZeroTierOne/osdep/OSUtils.cpp')))
|
||||||
@@ -44,13 +65,14 @@ else:
|
|||||||
'native/ext/lwip/src/include',
|
'native/ext/lwip/src/include',
|
||||||
'native/ext/lwip-contrib/ports/unix/port/include',
|
'native/ext/lwip-contrib/ports/unix/port/include',
|
||||||
'native/ext/ZeroTierOne/include',
|
'native/ext/ZeroTierOne/include',
|
||||||
|
'native/ext/ZeroTierOne',
|
||||||
'native/ext/ZeroTierOne/node',
|
'native/ext/ZeroTierOne/node',
|
||||||
'native/ext/ZeroTierOne/service',
|
'native/ext/ZeroTierOne/service',
|
||||||
'native/ext/ZeroTierOne/osdep',
|
'native/ext/ZeroTierOne/osdep',
|
||||||
'native/ext/ZeroTierOne/controller']
|
'native/ext/ZeroTierOne/controller']
|
||||||
|
|
||||||
libzt_module = Extension('libzt._libzt',
|
libzt_module = Extension('libzt._libzt',
|
||||||
extra_compile_args=['-std=c++11', '-DZTS_ENABLE_PYTHON=1', '-DZT_SDK'],
|
extra_compile_args=['-std=c++11', '-DZTS_ENABLE_PYTHON=1', '-DZT_SDK', '-Wno-parentheses-equality', '-Wno-macro-redefined', '-Wno-tautological-overlap-compare', '-Wno-tautological-constant-out-of-range-compare'],
|
||||||
sources=cpp_glob, include_dirs=my_include_dirs)
|
sources=cpp_glob, include_dirs=my_include_dirs)
|
||||||
|
|
||||||
# Separate C library, this is needed since C++ compiler flags are applied
|
# Separate C library, this is needed since C++ compiler flags are applied
|
||||||
|
|||||||
@@ -11,12 +11,13 @@
|
|||||||
*/
|
*/
|
||||||
/****/
|
/****/
|
||||||
|
|
||||||
|
#include "ZeroTierSockets.h"
|
||||||
|
|
||||||
#ifndef ZTS_DISABLE_CENTRAL_API
|
#ifndef ZTS_DISABLE_CENTRAL_API
|
||||||
|
|
||||||
#include "Debug.hpp"
|
#include "Debug.hpp"
|
||||||
#include "Mutex.hpp"
|
#include "Mutex.hpp"
|
||||||
#include "OSUtils.hpp"
|
#include "OSUtils.hpp"
|
||||||
#include "ZeroTierSockets.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "Events.hpp"
|
#include "Events.hpp"
|
||||||
#include "NodeService.hpp"
|
#include "NodeService.hpp"
|
||||||
|
#include "Signals.hpp"
|
||||||
#include "VirtualTap.hpp"
|
#include "VirtualTap.hpp"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -65,7 +66,7 @@ int init_subsystems()
|
|||||||
return ZTS_ERR_SERVICE;
|
return ZTS_ERR_SERVICE;
|
||||||
}
|
}
|
||||||
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
||||||
_install_signal_handlers();
|
zts_install_signal_handlers();
|
||||||
#endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
#endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
||||||
if (! zts_service) {
|
if (! zts_service) {
|
||||||
zts_service = new NodeService();
|
zts_service = new NodeService();
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
void _signal_handler(int signal)
|
void zts_signal_handler(int signal)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
switch(signal)
|
switch(signal)
|
||||||
@@ -65,15 +65,15 @@ void _signal_handler(int signal)
|
|||||||
exit(signal);
|
exit(signal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _install_signal_handlers()
|
void zts_install_signal_handlers()
|
||||||
{
|
{
|
||||||
signal(SIGINT, &_signal_handler);
|
signal(SIGINT, &zts_signal_handler);
|
||||||
/*
|
/*
|
||||||
signal(SIGABRT, &_signal_handler);
|
signal(SIGABRT, &zts_signal_handler);
|
||||||
signal(SIGFPE, &_signal_handler);
|
signal(SIGFPE, &zts_signal_handler);
|
||||||
signal(SIGILL, &_signal_handler);
|
signal(SIGILL, &zts_signal_handler);
|
||||||
signal(SIGSEGV, &_signal_handler);
|
signal(SIGSEGV, &zts_signal_handler);
|
||||||
signal(SIGTERM, &_signal_handler);
|
signal(SIGTERM, &zts_signal_handler);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,9 +26,9 @@
|
|||||||
|
|
||||||
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
||||||
|
|
||||||
void _signal_handler(int signal);
|
void zts_signal_handler(int signal);
|
||||||
|
|
||||||
void _install_signal_handlers();
|
void zts_install_signal_handlers();
|
||||||
|
|
||||||
#endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
#endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
||||||
|
|
||||||
|
|||||||
@@ -1,218 +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 (Python)
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "lwip/sockets.h"
|
|
||||||
#include "lwip/inet.h"
|
|
||||||
|
|
||||||
#include "ZeroTierSockets.h"
|
|
||||||
|
|
||||||
#ifdef ZTS_ENABLE_PYTHON
|
|
||||||
|
|
||||||
int zts_py_setblocking(int fd, int block)
|
|
||||||
{
|
|
||||||
int new_flags, cur_flags, err = 0;
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
cur_flags = zts_fcntl(fd, F_GETFL, 0);
|
|
||||||
|
|
||||||
if (cur_flags < 0) {
|
|
||||||
err = ZTS_ERR_SOCKET;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!block) {
|
|
||||||
new_flags |= ZTS_O_NONBLOCK;
|
|
||||||
} else {
|
|
||||||
new_flags &= ~ZTS_O_NONBLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_flags != cur_flags) {
|
|
||||||
err = zts_fcntl(fd, F_SETFL, new_flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int zts_py_getblocking(int fd)
|
|
||||||
{
|
|
||||||
int flags;
|
|
||||||
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
flags = zts_fcntl(fd, F_GETFL, 0);
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
|
|
||||||
if (flags < 0) {
|
|
||||||
return ZTS_ERR_SOCKET;
|
|
||||||
}
|
|
||||||
return flags & ZTS_O_NONBLOCK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int zts_py_tuple_to_sockaddr(int family,
|
|
||||||
PyObject *addr_obj, struct zts_sockaddr *dst_addr, int *addrlen)
|
|
||||||
{
|
|
||||||
if (family == AF_INET) {
|
|
||||||
struct zts_sockaddr_in* addr;
|
|
||||||
char *host_str;
|
|
||||||
int result, port;
|
|
||||||
if (!PyTuple_Check(addr_obj)) {
|
|
||||||
return ZTS_ERR_ARG;
|
|
||||||
}
|
|
||||||
if (!PyArg_ParseTuple(addr_obj,
|
|
||||||
"eti:zts_py_tuple_to_sockaddr", "idna", &host_str, &port)) {
|
|
||||||
return ZTS_ERR_ARG;
|
|
||||||
}
|
|
||||||
addr = (struct zts_sockaddr_in*)dst_addr;
|
|
||||||
zts_inet_pton(ZTS_AF_INET, host_str, &(addr->sin_addr.s_addr));
|
|
||||||
PyMem_Free(host_str);
|
|
||||||
if (port < 0 || port > 0xFFFF) {
|
|
||||||
return ZTS_ERR_ARG;
|
|
||||||
}
|
|
||||||
if (result < 0) {
|
|
||||||
return ZTS_ERR_ARG;
|
|
||||||
}
|
|
||||||
addr->sin_family = AF_INET;
|
|
||||||
addr->sin_port = lwip_htons((short)port);
|
|
||||||
*addrlen = sizeof *addr;
|
|
||||||
return ZTS_ERR_OK;
|
|
||||||
}
|
|
||||||
if (family == AF_INET6) {
|
|
||||||
// TODO
|
|
||||||
}
|
|
||||||
return ZTS_ERR_ARG;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject * zts_py_accept(int fd)
|
|
||||||
{
|
|
||||||
struct zts_sockaddr_in addrbuf;
|
|
||||||
socklen_t addrlen = sizeof(addrbuf);
|
|
||||||
memset(&addrbuf, 0, addrlen);
|
|
||||||
int err = zts_accept(fd, (struct zts_sockaddr*)&addrbuf, &addrlen);
|
|
||||||
char ipstr[ZTS_INET_ADDRSTRLEN];
|
|
||||||
memset(ipstr, 0, sizeof(ipstr));
|
|
||||||
zts_inet_ntop(ZTS_AF_INET, &(addrbuf.sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
|
|
||||||
PyObject *t;
|
|
||||||
t = PyTuple_New(3);
|
|
||||||
PyTuple_SetItem(t, 0, PyLong_FromLong(err)); // New file descriptor
|
|
||||||
PyTuple_SetItem(t, 1, PyUnicode_FromString(ipstr));
|
|
||||||
PyTuple_SetItem(t, 2, PyLong_FromLong(lwip_ntohs(addrbuf.sin_port)));
|
|
||||||
Py_INCREF(t);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
int zts_py_listen(int fd, int backlog)
|
|
||||||
{
|
|
||||||
if (backlog < 0) {
|
|
||||||
backlog = 128;
|
|
||||||
}
|
|
||||||
return zts_listen(fd, backlog);
|
|
||||||
}
|
|
||||||
|
|
||||||
int zts_py_bind(int fd, int family, int type, PyObject *addr_obj)
|
|
||||||
{
|
|
||||||
struct zts_sockaddr_storage addrbuf;
|
|
||||||
int addrlen;
|
|
||||||
int err;
|
|
||||||
if (zts_py_tuple_to_sockaddr(family, addr_obj,
|
|
||||||
(struct zts_sockaddr *)&addrbuf, &addrlen) != ZTS_ERR_OK)
|
|
||||||
{
|
|
||||||
return ZTS_ERR_ARG;
|
|
||||||
}
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
err = zts_bind(fd, (struct zts_sockaddr *)&addrbuf, addrlen);
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int zts_py_connect(int fd, int family, int type, PyObject *addr_obj)
|
|
||||||
{
|
|
||||||
struct zts_sockaddr_storage addrbuf;
|
|
||||||
int addrlen;
|
|
||||||
int err;
|
|
||||||
if (zts_py_tuple_to_sockaddr(family, addr_obj,
|
|
||||||
(struct zts_sockaddr *)&addrbuf, &addrlen) != ZTS_ERR_OK)
|
|
||||||
{
|
|
||||||
return ZTS_ERR_ARG;
|
|
||||||
}
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
err = zts_connect(fd, (struct zts_sockaddr *)&addrbuf, addrlen);
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject * zts_py_recv(int fd, int len, int flags)
|
|
||||||
{
|
|
||||||
PyObject *t, *buf;
|
|
||||||
int bytes_read;
|
|
||||||
|
|
||||||
buf = PyBytes_FromStringAndSize((char *) 0, len);
|
|
||||||
if (buf == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_read = zts_recv(fd, PyBytes_AS_STRING(buf), len, flags);
|
|
||||||
t = PyTuple_New(2);
|
|
||||||
PyTuple_SetItem(t, 0, PyLong_FromLong(bytes_read));
|
|
||||||
|
|
||||||
if (bytes_read < 0) {
|
|
||||||
Py_DECREF(buf);
|
|
||||||
Py_INCREF(Py_None);
|
|
||||||
PyTuple_SetItem(t, 1, Py_None);
|
|
||||||
Py_INCREF(t);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bytes_read != len) {
|
|
||||||
_PyBytes_Resize(&buf, bytes_read);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyTuple_SetItem(t, 1, buf);
|
|
||||||
Py_INCREF(t);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
int zts_py_send(int fd, PyObject *buf, int flags)
|
|
||||||
{
|
|
||||||
Py_buffer output;
|
|
||||||
int bytes_sent;
|
|
||||||
|
|
||||||
if (PyObject_GetBuffer(buf, &output, PyBUF_SIMPLE) != 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bytes_sent = zts_send(fd, output.buf, output.len, flags);
|
|
||||||
PyBuffer_Release(&output);
|
|
||||||
|
|
||||||
return bytes_sent;
|
|
||||||
}
|
|
||||||
|
|
||||||
int zts_py_close(int fd)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
Py_BEGIN_ALLOW_THREADS
|
|
||||||
err = zts_close(fd);
|
|
||||||
Py_END_ALLOW_THREADS
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // ZTS_ENABLE_PYTHON
|
|
||||||
203
src/bindings/python/PythonSockets.cxx
Normal file
203
src/bindings/python/PythonSockets.cxx
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* ZeroTier Socket API (Python)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ZeroTierSockets.h"
|
||||||
|
#include "lwip/inet.h"
|
||||||
|
#include "lwip/sockets.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef ZTS_ENABLE_PYTHON
|
||||||
|
|
||||||
|
int zts_py_setblocking(int fd, int block)
|
||||||
|
{
|
||||||
|
int new_flags, cur_flags, err = 0;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS cur_flags = zts_fcntl(fd, F_GETFL, 0);
|
||||||
|
|
||||||
|
if (cur_flags < 0) {
|
||||||
|
err = ZTS_ERR_SOCKET;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! block) {
|
||||||
|
new_flags |= ZTS_O_NONBLOCK;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
new_flags &= ~ZTS_O_NONBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_flags != cur_flags) {
|
||||||
|
err = zts_fcntl(fd, F_SETFL, new_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_getblocking(int fd)
|
||||||
|
{
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
Py_BEGIN_ALLOW_THREADS flags = zts_fcntl(fd, F_GETFL, 0);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
if (flags < 0)
|
||||||
|
{
|
||||||
|
return ZTS_ERR_SOCKET;
|
||||||
|
}
|
||||||
|
return flags & ZTS_O_NONBLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int zts_py_tuple_to_sockaddr(int family, PyObject* addr_obj, struct zts_sockaddr* dst_addr, int* addrlen)
|
||||||
|
{
|
||||||
|
if (family == AF_INET) {
|
||||||
|
struct zts_sockaddr_in* addr;
|
||||||
|
char* host_str;
|
||||||
|
int result, port;
|
||||||
|
if (! PyTuple_Check(addr_obj)) {
|
||||||
|
return ZTS_ERR_ARG;
|
||||||
|
}
|
||||||
|
if (! PyArg_ParseTuple(addr_obj, "eti:zts_py_tuple_to_sockaddr", "idna", &host_str, &port)) {
|
||||||
|
return ZTS_ERR_ARG;
|
||||||
|
}
|
||||||
|
addr = (struct zts_sockaddr_in*)dst_addr;
|
||||||
|
zts_inet_pton(ZTS_AF_INET, host_str, &(addr->sin_addr.s_addr));
|
||||||
|
PyMem_Free(host_str);
|
||||||
|
if (port < 0 || port > 0xFFFF) {
|
||||||
|
return ZTS_ERR_ARG;
|
||||||
|
}
|
||||||
|
if (result < 0) {
|
||||||
|
return ZTS_ERR_ARG;
|
||||||
|
}
|
||||||
|
addr->sin_family = AF_INET;
|
||||||
|
addr->sin_port = lwip_htons((short)port);
|
||||||
|
*addrlen = sizeof *addr;
|
||||||
|
return ZTS_ERR_OK;
|
||||||
|
}
|
||||||
|
if (family == AF_INET6) {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
return ZTS_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* zts_py_accept(int fd)
|
||||||
|
{
|
||||||
|
struct zts_sockaddr_in addrbuf = { 0 };
|
||||||
|
socklen_t addrlen = sizeof(addrbuf);
|
||||||
|
int err = zts_accept(fd, (struct zts_sockaddr*)&addrbuf, &addrlen);
|
||||||
|
char ipstr[ZTS_INET_ADDRSTRLEN] = { 0 };
|
||||||
|
zts_inet_ntop(ZTS_AF_INET, &(addrbuf.sin_addr), ipstr, ZTS_INET_ADDRSTRLEN);
|
||||||
|
PyObject* t;
|
||||||
|
t = PyTuple_New(3);
|
||||||
|
PyTuple_SetItem(t, 0, PyLong_FromLong(err)); // New file descriptor
|
||||||
|
PyTuple_SetItem(t, 1, PyUnicode_FromString(ipstr));
|
||||||
|
PyTuple_SetItem(t, 2, PyLong_FromLong(lwip_ntohs(addrbuf.sin_port)));
|
||||||
|
Py_INCREF(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_listen(int fd, int backlog)
|
||||||
|
{
|
||||||
|
if (backlog < 0) {
|
||||||
|
backlog = 128;
|
||||||
|
}
|
||||||
|
return zts_listen(fd, backlog);
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_bind(int fd, int family, int type, PyObject* addr_obj)
|
||||||
|
{
|
||||||
|
struct zts_sockaddr_storage addrbuf;
|
||||||
|
int addrlen;
|
||||||
|
int err;
|
||||||
|
if (zts_py_tuple_to_sockaddr(family, addr_obj, (struct zts_sockaddr*)&addrbuf, &addrlen) != ZTS_ERR_OK) {
|
||||||
|
return ZTS_ERR_ARG;
|
||||||
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS err = zts_bind(fd, (struct zts_sockaddr*)&addrbuf, addrlen);
|
||||||
|
Py_END_ALLOW_THREADS return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_connect(int fd, int family, int type, PyObject* addr_obj)
|
||||||
|
{
|
||||||
|
struct zts_sockaddr_storage addrbuf;
|
||||||
|
int addrlen;
|
||||||
|
int err;
|
||||||
|
if (zts_py_tuple_to_sockaddr(family, addr_obj, (struct zts_sockaddr*)&addrbuf, &addrlen) != ZTS_ERR_OK) {
|
||||||
|
return ZTS_ERR_ARG;
|
||||||
|
}
|
||||||
|
Py_BEGIN_ALLOW_THREADS err = zts_connect(fd, (struct zts_sockaddr*)&addrbuf, addrlen);
|
||||||
|
Py_END_ALLOW_THREADS return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject* zts_py_recv(int fd, int len, int flags)
|
||||||
|
{
|
||||||
|
PyObject *t, *buf;
|
||||||
|
int bytes_read;
|
||||||
|
|
||||||
|
buf = PyBytes_FromStringAndSize((char*)0, len);
|
||||||
|
if (buf == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_read = zts_recv(fd, PyBytes_AS_STRING(buf), len, flags);
|
||||||
|
t = PyTuple_New(2);
|
||||||
|
PyTuple_SetItem(t, 0, PyLong_FromLong(bytes_read));
|
||||||
|
|
||||||
|
if (bytes_read < 0) {
|
||||||
|
Py_DECREF(buf);
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
PyTuple_SetItem(t, 1, Py_None);
|
||||||
|
Py_INCREF(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_read != len) {
|
||||||
|
_PyBytes_Resize(&buf, bytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyTuple_SetItem(t, 1, buf);
|
||||||
|
Py_INCREF(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_send(int fd, PyObject* buf, int flags)
|
||||||
|
{
|
||||||
|
Py_buffer output;
|
||||||
|
int bytes_sent;
|
||||||
|
|
||||||
|
if (PyObject_GetBuffer(buf, &output, PyBUF_SIMPLE) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes_sent = zts_send(fd, output.buf, output.len, flags);
|
||||||
|
PyBuffer_Release(&output);
|
||||||
|
|
||||||
|
return bytes_sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_close(int fd)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
Py_BEGIN_ALLOW_THREADS err = zts_close(fd);
|
||||||
|
Py_END_ALLOW_THREADS return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ZTS_ENABLE_PYTHON
|
||||||
79
src/bindings/python/node.py
Normal file
79
src/bindings/python/node.py
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import libzt
|
||||||
|
|
||||||
|
_user_specified_event_handler = None
|
||||||
|
|
||||||
|
|
||||||
|
class _EventCallbackClass(libzt.PythonDirectorCallbackClass):
|
||||||
|
"""ZeroTier event callback class"""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MyEventCallbackClass(_EventCallbackClass):
|
||||||
|
def on_zerotier_event(self, msg):
|
||||||
|
id = 0
|
||||||
|
if msg.event_code == libzt.ZTS_EVENT_NODE_ONLINE:
|
||||||
|
id = msg.node.node_id
|
||||||
|
if msg.event_code == libzt.ZTS_EVENT_NODE_OFFLINE:
|
||||||
|
id = msg.node.node_id
|
||||||
|
if msg.event_code == libzt.ZTS_EVENT_NETWORK_READY_IP4:
|
||||||
|
id = msg.network.net_id
|
||||||
|
if msg.event_code == libzt.ZTS_EVENT_NETWORK_READY_IP6:
|
||||||
|
id = msg.network.net_id
|
||||||
|
if msg.event_code == libzt.ZTS_EVENT_PEER_DIRECT:
|
||||||
|
id = msg.peer.peer_id
|
||||||
|
if msg.event_code == libzt.ZTS_EVENT_PEER_RELAY:
|
||||||
|
id = msg.peer.peer_id
|
||||||
|
# Now that we've adjusted internal state, notify user
|
||||||
|
global _user_specified_event_handler
|
||||||
|
_user_specified_event_handler(msg.event_code, id)
|
||||||
|
|
||||||
|
|
||||||
|
class ZeroTierNode:
|
||||||
|
native_event_handler = None
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.native_event_handler = MyEventCallbackClass()
|
||||||
|
libzt.zts_init_set_event_handler(self.native_event_handler)
|
||||||
|
|
||||||
|
"""ZeroTier Node"""
|
||||||
|
|
||||||
|
def init_from_storage(self, storage_path):
|
||||||
|
"""Initialize the node from storage (or tell it to write to that location)"""
|
||||||
|
return libzt.zts_init_from_storage(storage_path)
|
||||||
|
|
||||||
|
"""Set the node's event handler"""
|
||||||
|
|
||||||
|
def init_set_event_handler(self, event_handler):
|
||||||
|
global _user_specified_event_handler
|
||||||
|
_user_specified_event_handler = event_handler
|
||||||
|
|
||||||
|
def init_set_port(self, port):
|
||||||
|
"""Set the node's primary port"""
|
||||||
|
return libzt.zts_init_set_port(port)
|
||||||
|
|
||||||
|
def node_start(self):
|
||||||
|
"""Start the ZeroTier service"""
|
||||||
|
return libzt.zts_node_start()
|
||||||
|
|
||||||
|
def node_stop(self):
|
||||||
|
"""Stop the ZeroTier service"""
|
||||||
|
return libzt.zts_node_stop()
|
||||||
|
|
||||||
|
def node_free(self):
|
||||||
|
"""Permanently shut down the network stack"""
|
||||||
|
return libzt.zts_node_free()
|
||||||
|
|
||||||
|
def net_join(self, net_id):
|
||||||
|
"""Join a ZeroTier network"""
|
||||||
|
return libzt.zts_net_join(net_id)
|
||||||
|
|
||||||
|
def net_leave(self, net_id):
|
||||||
|
"""Leave a ZeroTier network"""
|
||||||
|
return libzt.zts_net_leave(net_id)
|
||||||
|
|
||||||
|
def node_is_online(self):
|
||||||
|
return libzt.zts_node_is_online()
|
||||||
|
|
||||||
|
def net_transport_is_ready(self, net_id):
|
||||||
|
return libzt.zts_net_transport_is_ready(net_id)
|
||||||
46
src/bindings/python/sockets.py
Normal file → Executable file
46
src/bindings/python/sockets.py
Normal file → Executable file
@@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
import libzt
|
import libzt
|
||||||
|
|
||||||
class EventCallbackClass(libzt.PythonDirectorCallbackClass):
|
|
||||||
"""ZeroTier event callback class"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
def handle_error(err):
|
def handle_error(err):
|
||||||
"""Convert libzt error code to exception"""
|
"""Convert libzt error code to exception"""
|
||||||
@@ -20,6 +17,7 @@ def handle_error(err):
|
|||||||
if err == libzt.ZTS_ERR_GENERAL:
|
if err == libzt.ZTS_ERR_GENERAL:
|
||||||
raise Exception("ZTS_ERR_GENERAL (" + str(err) + ")")
|
raise Exception("ZTS_ERR_GENERAL (" + str(err) + ")")
|
||||||
|
|
||||||
|
|
||||||
# This implementation of errno is NOT thread safe
|
# This implementation of errno is NOT thread safe
|
||||||
# That is, this value is shared among all lower-level socket calls
|
# That is, this value is shared among all lower-level socket calls
|
||||||
# and may change for any reason at any time if you have multiple
|
# and may change for any reason at any time if you have multiple
|
||||||
@@ -28,41 +26,10 @@ def errno():
|
|||||||
"""Return errno value of low-level socket layer"""
|
"""Return errno value of low-level socket layer"""
|
||||||
return libzt.cvar.zts_errno
|
return libzt.cvar.zts_errno
|
||||||
|
|
||||||
def start(path, callback, port):
|
|
||||||
"""Start the ZeroTier service"""
|
|
||||||
libzt.zts_start(path, callback, port)
|
|
||||||
|
|
||||||
def stop():
|
|
||||||
"""Stop the ZeroTier service"""
|
|
||||||
libzt.zts_stop()
|
|
||||||
|
|
||||||
def restart():
|
|
||||||
"""[debug] Restarts the ZeroTier service and network stack"""
|
|
||||||
libzt.zts_restart()
|
|
||||||
|
|
||||||
def free():
|
|
||||||
"""Permenantly shuts down the network stack"""
|
|
||||||
libzt.zts_free()
|
|
||||||
|
|
||||||
def join(network_id):
|
|
||||||
"""Join a ZeroTier network"""
|
|
||||||
libzt.zts_join(network_id)
|
|
||||||
|
|
||||||
def leave(network_id):
|
|
||||||
"""Leave a ZeroTier network"""
|
|
||||||
libzt.zts_leave(network_id)
|
|
||||||
|
|
||||||
def zts_orbit(moon_world_id, moon_seed):
|
|
||||||
"""Orbit a moon"""
|
|
||||||
return libzt.zts_orbit(moon_world_id, moon_seed)
|
|
||||||
|
|
||||||
def zts_deorbit(moon_world_id):
|
|
||||||
"""De-orbit a moon"""
|
|
||||||
return libzt.zts_deorbit(moon_world_id)
|
|
||||||
|
|
||||||
|
|
||||||
class socket:
|
class socket:
|
||||||
"""Pythonic class that wraps low-level sockets"""
|
"""Pythonic class that wraps low-level sockets"""
|
||||||
|
|
||||||
_fd = -1 # native layer file descriptor
|
_fd = -1 # native layer file descriptor
|
||||||
_family = -1
|
_family = -1
|
||||||
_type = -1
|
_type = -1
|
||||||
@@ -131,7 +98,9 @@ class socket:
|
|||||||
"""libzt does not support this (yet)"""
|
"""libzt does not support this (yet)"""
|
||||||
raise NotImplementedError("libzt does not support this (yet?)")
|
raise NotImplementedError("libzt does not support this (yet?)")
|
||||||
|
|
||||||
def getaddrinfo(self, host, port, sock_family=0, sock_type=0, sock_proto=0, flags=0):
|
def getaddrinfo(
|
||||||
|
self, host, port, sock_family=0, sock_type=0, sock_proto=0, flags=0
|
||||||
|
):
|
||||||
"""libzt does not support this (yet)"""
|
"""libzt does not support this (yet)"""
|
||||||
raise NotImplementedError("libzt does not support this (yet?)")
|
raise NotImplementedError("libzt does not support this (yet?)")
|
||||||
|
|
||||||
@@ -285,7 +254,8 @@ class socket:
|
|||||||
def detach(self):
|
def detach(self):
|
||||||
"""libzt does not support this"""
|
"""libzt does not support this"""
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"detach(): Not supported. OS File descriptors aren't used in libzt.")
|
"detach(): Not supported. OS File descriptors aren't used in libzt."
|
||||||
|
)
|
||||||
|
|
||||||
def dup(self):
|
def dup(self):
|
||||||
"""libzt does not support this"""
|
"""libzt does not support this"""
|
||||||
@@ -336,7 +306,7 @@ class socket:
|
|||||||
if backlog is not None and backlog < 0:
|
if backlog is not None and backlog < 0:
|
||||||
backlog = 0
|
backlog = 0
|
||||||
if backlog is None:
|
if backlog is None:
|
||||||
backlog = -1 # Lower-level code picks default
|
backlog = -1 # Lower-level code picks default
|
||||||
|
|
||||||
err = libzt.zts_py_listen(self._fd, backlog)
|
err = libzt.zts_py_listen(self._fd, backlog)
|
||||||
if err < 0:
|
if err < 0:
|
||||||
|
|||||||
133
test/selftest.py
Normal file
133
test/selftest.py
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
'''Example low-level socket usage'''
|
||||||
|
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import libzt
|
||||||
|
|
||||||
|
def print_usage():
|
||||||
|
'''print help'''
|
||||||
|
print(
|
||||||
|
"\nUsage: <server|client> <storage_path> <net_id> <remote_ip> <remote_port>\n"
|
||||||
|
)
|
||||||
|
print("Ex: python3 example.py server . 0123456789abcdef 8080")
|
||||||
|
print("Ex: python3 example.py client . 0123456789abcdef 192.168.22.1 8080\n")
|
||||||
|
if len(sys.argv) < 5:
|
||||||
|
print("Too few arguments")
|
||||||
|
if len(sys.argv) > 6:
|
||||||
|
print("Too many arguments")
|
||||||
|
sys.exit(0)
|
||||||
|
|
||||||
|
#
|
||||||
|
# (Optional) Event handler
|
||||||
|
#
|
||||||
|
def on_zerotier_event(event_code, id):
|
||||||
|
if event_code == libzt.ZTS_EVENT_NODE_ONLINE:
|
||||||
|
print("ZTS_EVENT_NODE_ONLINE (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_NODE_OFFLINE:
|
||||||
|
print("ZTS_EVENT_NODE_OFFLINE (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_NETWORK_READY_IP4:
|
||||||
|
print("ZTS_EVENT_NETWORK_READY_IP4 (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_NETWORK_READY_IP6:
|
||||||
|
print("ZTS_EVENT_NETWORK_READY_IP6 (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_PEER_DIRECT:
|
||||||
|
print("ZTS_EVENT_PEER_DIRECT (" + str(event_code) + ") : " + hex(id))
|
||||||
|
if event_code == libzt.ZTS_EVENT_PEER_RELAY:
|
||||||
|
print("ZTS_EVENT_PEER_RELAY (" + str(event_code) + ") : " + hex(id))
|
||||||
|
|
||||||
|
#
|
||||||
|
# Main
|
||||||
|
#
|
||||||
|
def main():
|
||||||
|
mode = None # client|server
|
||||||
|
storage_path = "." # Where identity files are stored
|
||||||
|
net_id = 0 # Network to join
|
||||||
|
remote_ip = None # ZeroTier IP of remote node
|
||||||
|
remote_port = 8080 # ZeroTier port your app logic may use
|
||||||
|
|
||||||
|
if len(sys.argv) < 5 or len(sys.argv) > 6:
|
||||||
|
print_usage()
|
||||||
|
if sys.argv[1] == "server" and len(sys.argv) == 5:
|
||||||
|
mode = sys.argv[1]
|
||||||
|
storage_path = sys.argv[2]
|
||||||
|
net_id = int(sys.argv[3], 16)
|
||||||
|
remote_port = int(sys.argv[4])
|
||||||
|
if sys.argv[1] == "client" and len(sys.argv) == 6:
|
||||||
|
mode = sys.argv[1]
|
||||||
|
storage_path = sys.argv[2]
|
||||||
|
net_id = int(sys.argv[3], 16)
|
||||||
|
remote_ip = sys.argv[4]
|
||||||
|
remote_port = int(sys.argv[5])
|
||||||
|
if mode is None:
|
||||||
|
print_usage()
|
||||||
|
print("mode = ", mode)
|
||||||
|
print("storage_path = ", storage_path)
|
||||||
|
print("net_id = ", net_id)
|
||||||
|
print("remote_ip = ", remote_ip)
|
||||||
|
print("remote_port = ", remote_port)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Node initialization and start
|
||||||
|
#
|
||||||
|
print("Starting ZeroTier...")
|
||||||
|
|
||||||
|
n = libzt.ZeroTierNode()
|
||||||
|
n.init_set_event_handler(on_zerotier_event) # Optional
|
||||||
|
n.init_from_storage(storage_path) # Optional
|
||||||
|
n.init_set_port(9994) # Optional
|
||||||
|
n.node_start()
|
||||||
|
|
||||||
|
print("Waiting for node to come online...")
|
||||||
|
while not n.node_is_online():
|
||||||
|
time.sleep(1)
|
||||||
|
print("Joining network:", hex(net_id))
|
||||||
|
n.net_join(net_id)
|
||||||
|
while not n.net_transport_is_ready(net_id):
|
||||||
|
time.sleep(1)
|
||||||
|
print("Joined network")
|
||||||
|
|
||||||
|
#
|
||||||
|
# Example server
|
||||||
|
#
|
||||||
|
if mode == "server":
|
||||||
|
print("Starting server...")
|
||||||
|
serv = libzt.socket(libzt.ZTS_AF_INET, libzt.ZTS_SOCK_STREAM, 0)
|
||||||
|
try:
|
||||||
|
# serv.setblocking(True)
|
||||||
|
serv.bind(("0.0.0.0", remote_port))
|
||||||
|
serv.listen(5)
|
||||||
|
conn, addr = serv.accept()
|
||||||
|
print("Accepted connection from: ", addr)
|
||||||
|
data = conn.recv(4096)
|
||||||
|
if data:
|
||||||
|
print("recv: ", data)
|
||||||
|
print("send: ", data)
|
||||||
|
sent_bytes = conn.send(data) # echo back to the server
|
||||||
|
print("sent: " + str(sent_bytes) + " byte(s)")
|
||||||
|
conn.close()
|
||||||
|
print("client disconnected")
|
||||||
|
except Exception as ex:
|
||||||
|
print(ex)
|
||||||
|
print("errno=", libzt.errno()) # See include/ZeroTierSockets.h for codes
|
||||||
|
|
||||||
|
#
|
||||||
|
# Example client
|
||||||
|
#
|
||||||
|
if mode == "client":
|
||||||
|
print("Starting client...")
|
||||||
|
client = libzt.socket(libzt.ZTS_AF_INET, libzt.ZTS_SOCK_STREAM, 0)
|
||||||
|
try:
|
||||||
|
print("connecting...")
|
||||||
|
client.connect((remote_ip, remote_port))
|
||||||
|
data = "Hello, world!"
|
||||||
|
print("send: ", data)
|
||||||
|
sent_bytes = client.send(data.encode('utf-8'))
|
||||||
|
print("sent: " + str(sent_bytes) + " byte(s)")
|
||||||
|
data = client.recv(1024)
|
||||||
|
print("recv: ", repr(data))
|
||||||
|
except Exception as ex:
|
||||||
|
print(ex)
|
||||||
|
print("errno=", libzt.errno())
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user