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
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Install black
|
||||
run: pip3 install black
|
||||
|
||||
- name: Format code
|
||||
run: ./build.sh format-code
|
||||
run: ./build.sh format-code "all"
|
||||
|
||||
- name: Commit changes
|
||||
uses: joseph-henry/add-and-commit@v7
|
||||
|
||||
94
build.sh
94
build.sh
@@ -4,6 +4,13 @@
|
||||
# | SYSTEM DISCOVERY AND CONFIGURATION |
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
CLANG_FORMAT=clang-format-11
|
||||
|
||||
PYTHON=python3
|
||||
PIP=pip3
|
||||
|
||||
libzt=$(pwd)
|
||||
|
||||
# Find and set cmake
|
||||
CMAKE=cmake3
|
||||
if [[ $(which $CMAKE) = "" ]];
|
||||
@@ -356,7 +363,7 @@ host-uninstall()
|
||||
# └── pkg
|
||||
# └── libzt-1.3.4b1-cp39-cp39-macosx_11_0_x86_64.whl
|
||||
#
|
||||
host-python-wheel()
|
||||
host-python()
|
||||
{
|
||||
ARTIFACT="python"
|
||||
# Default to release
|
||||
@@ -365,30 +372,47 @@ host-python-wheel()
|
||||
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
|
||||
PKG_OUTPUT_DIR=$TARGET_BUILD_DIR/pkg
|
||||
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
|
||||
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
|
||||
host-python()
|
||||
{
|
||||
ARTIFACT="python"
|
||||
# Default to release
|
||||
BUILD_TYPE=${1:-release}
|
||||
VARIANT="-DZTS_ENABLE_PYTHON=True"
|
||||
CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
|
||||
TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
|
||||
LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
|
||||
rm -rf $LIB_OUTPUT_DIR
|
||||
mkdir -p $LIB_OUTPUT_DIR
|
||||
# Optional step to generate new SWIG wrapper
|
||||
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 --build $CACHE_DIR $BUILD_CONCURRENCY
|
||||
cp -f $CACHE_DIR/lib/$SHARED_LIB_NAME $LIB_OUTPUT_DIR/_libzt.so
|
||||
echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
|
||||
$TREE $TARGET_BUILD_DIR
|
||||
}
|
||||
#host-python()
|
||||
#{
|
||||
# ARTIFACT="python"
|
||||
# # Default to release
|
||||
# BUILD_TYPE=${1:-release}
|
||||
# VARIANT="-DZTS_ENABLE_PYTHON=True"
|
||||
# CACHE_DIR=$DEFAULT_HOST_BUILD_CACHE_DIR-$ARTIFACT-$BUILD_TYPE
|
||||
# TARGET_BUILD_DIR=$DEFAULT_HOST_BIN_OUTPUT_DIR-$ARTIFACT-$BUILD_TYPE
|
||||
# LIB_OUTPUT_DIR=$TARGET_BUILD_DIR/lib
|
||||
# rm -rf $LIB_OUTPUT_DIR
|
||||
# mkdir -p $LIB_OUTPUT_DIR
|
||||
# # Optional step to generate new SWIG wrapper
|
||||
# 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 --build $CACHE_DIR $BUILD_CONCURRENCY
|
||||
# cp -f $CACHE_DIR/lib/$SHARED_LIB_NAME $LIB_OUTPUT_DIR/_libzt.so
|
||||
# echo -e "\n - Build cache : $CACHE_DIR\n - Build output : $BUILD_OUTPUT_DIR\n"
|
||||
# $TREE $TARGET_BUILD_DIR
|
||||
#}
|
||||
|
||||
# Build shared library with P/INVOKE wrapper symbols exported
|
||||
host-pinvoke()
|
||||
@@ -579,10 +603,17 @@ test()
|
||||
|
||||
format-code()
|
||||
{
|
||||
if [[ ! $(which clang-format) = "" ]];
|
||||
if [[ $1 = *"all"* ]]; then
|
||||
format-code "clang"
|
||||
format-code "python"
|
||||
fi
|
||||
|
||||
# Clang-format
|
||||
if [[ $1 = *"clang"* ]]; then
|
||||
if [[ ! $(which $CLANG_FORMAT) = "" ]];
|
||||
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 {} \;
|
||||
clang-format-11 -i include/*.h \
|
||||
$CLANG_FORMAT -i include/*.h \
|
||||
src/*.c \
|
||||
src/*.cpp \
|
||||
src/*.hpp \
|
||||
@@ -595,10 +626,23 @@ format-code()
|
||||
src/bindings/csharp/*.cxx \
|
||||
src/bindings/java/*.java \
|
||||
src/bindings/java/*.cxx \
|
||||
examples/csharp/*.cs
|
||||
examples/csharp/*.cs \
|
||||
src/bindings/python/*.cxx \
|
||||
src/bindings/python/*.h
|
||||
return 0
|
||||
else
|
||||
echo "Please install clang-format."
|
||||
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
|
||||
}
|
||||
|
||||
@@ -637,6 +681,8 @@ clean()
|
||||
rm -rf $ANDROID_PKG_PROJ_DIR/app/build
|
||||
rm -rf $ANDROID_PKG_PROJ_DIR/app/src/main/java/com/zerotier/libzt/*.java
|
||||
rm -rf $ANDROID_PKG_PROJ_DIR/app/.externalNativeBuild
|
||||
# Python pkg
|
||||
cd pkg/pypi && ./build.sh clean
|
||||
# Remove whatever remains
|
||||
find . \
|
||||
\( -name '*.dylib' \
|
||||
|
||||
@@ -1,106 +1,92 @@
|
||||
'''Example low-level socket usage'''
|
||||
"""Example low-level socket usage"""
|
||||
|
||||
import time
|
||||
import sys
|
||||
|
||||
import libzt
|
||||
|
||||
|
||||
def print_usage():
|
||||
'''print help'''
|
||||
"""print help"""
|
||||
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 demo.py client . 0123456789abcdef 9994 192.168.22.1 8080\n")
|
||||
if len(sys.argv) < 6:
|
||||
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) > 7:
|
||||
if len(sys.argv) > 6:
|
||||
print("Too many arguments")
|
||||
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
|
||||
#
|
||||
def main():
|
||||
global is_online
|
||||
global is_joined
|
||||
|
||||
key_file_path = "." # Where identity files are stored
|
||||
network_id = 0 # Network to join
|
||||
# Port used by ZeroTier to send encpryted UDP traffic
|
||||
# NOTE: Should be different from other instances of ZeroTier
|
||||
# running on the same machine
|
||||
zt_service_port = 9997
|
||||
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
|
||||
mode = None # client|server
|
||||
|
||||
if len(sys.argv) < 6 or len(sys.argv) > 7:
|
||||
if len(sys.argv) < 5 or len(sys.argv) > 6:
|
||||
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]
|
||||
key_file_path = sys.argv[2]
|
||||
network_id = int(sys.argv[3], 16)
|
||||
zt_service_port = int(sys.argv[4])
|
||||
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 sys.argv[1] == "client" and len(sys.argv) == 7:
|
||||
mode = sys.argv[1]
|
||||
key_file_path = sys.argv[2]
|
||||
network_id = int(sys.argv[3], 16)
|
||||
zt_service_port = int(sys.argv[4])
|
||||
remote_ip = sys.argv[5]
|
||||
remote_port = int(sys.argv[6])
|
||||
if mode is None:
|
||||
print_usage()
|
||||
print("mode = ", mode)
|
||||
print("path = ", key_file_path)
|
||||
print("network_id = ", network_id)
|
||||
print("zt_service_port = ", zt_service_port)
|
||||
print("storage_path = ", storage_path)
|
||||
print("net_id = ", net_id)
|
||||
print("remote_ip = ", remote_ip)
|
||||
print("remote_port = ", remote_port)
|
||||
|
||||
#
|
||||
# Example start and join logic
|
||||
# Node initialization and start
|
||||
#
|
||||
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...")
|
||||
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)
|
||||
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")
|
||||
|
||||
#
|
||||
@@ -140,7 +126,7 @@ def main():
|
||||
try:
|
||||
print("connecting...")
|
||||
client.connect((remote_ip, remote_port))
|
||||
data = "Hello, world!"
|
||||
data = "Hello, roots!"
|
||||
print("send: ", data)
|
||||
sent_bytes = client.send(data)
|
||||
print("sent: " + str(sent_bytes) + " byte(s)")
|
||||
@@ -150,5 +136,6 @@ def main():
|
||||
print(ex)
|
||||
print("errno=", libzt.errno())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
@@ -1058,6 +1058,10 @@ int zts_py_getblocking(int fd);
|
||||
// Central API //
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
#ifdef ZTS_ENABLE_PYTHON
|
||||
#define ZTS_DISABLE_CENTRAL_API 1
|
||||
#endif
|
||||
|
||||
#ifndef ZTS_DISABLE_CENTRAL_API
|
||||
|
||||
#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
|
||||
ln -s ../../ native
|
||||
# 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
|
||||
cp -f native/src/bindings/python/*.py libzt/
|
||||
cp -f native/LICENSE.txt LICENSE
|
||||
@@ -30,6 +30,7 @@ clean()
|
||||
find . -name '__pycache__' -type d -delete
|
||||
rm -rf libzt/sockets.py
|
||||
rm -rf libzt/libzt.py
|
||||
rm -rf libzt/node.py
|
||||
rm -rf src ext build dist native
|
||||
rm -rf libzt.egg-info
|
||||
rm -rf LICENSE
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from .libzt import *
|
||||
from .sockets import *
|
||||
from .node import *
|
||||
from .version import __version__
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "1.3.4b1"
|
||||
__version__ = "1.4.0a0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[metadata]
|
||||
version = attr: libzt.__version__
|
||||
description-file = README.md
|
||||
description_file = README.md
|
||||
license_files =
|
||||
native/LICENSE.txt
|
||||
native/ext/THIRDPARTY.txt
|
||||
|
||||
@@ -19,6 +19,27 @@ class BinaryDistribution(Distribution):
|
||||
def is_pure(self):
|
||||
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 = []
|
||||
c_glob = []
|
||||
|
||||
@@ -30,7 +51,7 @@ if os.name == 'nt':
|
||||
|
||||
# Everything 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/ext/ZeroTierOne/node/*.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-contrib/ports/unix/port/include',
|
||||
'native/ext/ZeroTierOne/include',
|
||||
'native/ext/ZeroTierOne',
|
||||
'native/ext/ZeroTierOne/node',
|
||||
'native/ext/ZeroTierOne/service',
|
||||
'native/ext/ZeroTierOne/osdep',
|
||||
'native/ext/ZeroTierOne/controller']
|
||||
|
||||
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)
|
||||
|
||||
# Separate C library, this is needed since C++ compiler flags are applied
|
||||
|
||||
@@ -11,12 +11,13 @@
|
||||
*/
|
||||
/****/
|
||||
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#ifndef ZTS_DISABLE_CENTRAL_API
|
||||
|
||||
#include "Debug.hpp"
|
||||
#include "Mutex.hpp"
|
||||
#include "OSUtils.hpp"
|
||||
#include "ZeroTierSockets.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "Events.hpp"
|
||||
#include "NodeService.hpp"
|
||||
#include "Signals.hpp"
|
||||
#include "VirtualTap.hpp"
|
||||
|
||||
#include <string.h>
|
||||
@@ -65,7 +66,7 @@ int init_subsystems()
|
||||
return ZTS_ERR_SERVICE;
|
||||
}
|
||||
#ifdef ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
||||
_install_signal_handlers();
|
||||
zts_install_signal_handlers();
|
||||
#endif // ZTS_ENABLE_CUSTOM_SIGNAL_HANDLERS
|
||||
if (! zts_service) {
|
||||
zts_service = new NodeService();
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <execinfo.h>
|
||||
#include <signal.h>
|
||||
|
||||
void _signal_handler(int signal)
|
||||
void zts_signal_handler(int signal)
|
||||
{
|
||||
/*
|
||||
switch(signal)
|
||||
@@ -65,15 +65,15 @@ void _signal_handler(int 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(SIGFPE, &_signal_handler);
|
||||
signal(SIGILL, &_signal_handler);
|
||||
signal(SIGSEGV, &_signal_handler);
|
||||
signal(SIGTERM, &_signal_handler);
|
||||
signal(SIGABRT, &zts_signal_handler);
|
||||
signal(SIGFPE, &zts_signal_handler);
|
||||
signal(SIGILL, &zts_signal_handler);
|
||||
signal(SIGSEGV, &zts_signal_handler);
|
||||
signal(SIGTERM, &zts_signal_handler);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
|
||||
#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
|
||||
|
||||
|
||||
@@ -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)
|
||||
44
src/bindings/python/sockets.py
Normal file → Executable file
44
src/bindings/python/sockets.py
Normal file → Executable file
@@ -2,9 +2,6 @@
|
||||
|
||||
import libzt
|
||||
|
||||
class EventCallbackClass(libzt.PythonDirectorCallbackClass):
|
||||
"""ZeroTier event callback class"""
|
||||
pass
|
||||
|
||||
def handle_error(err):
|
||||
"""Convert libzt error code to exception"""
|
||||
@@ -20,6 +17,7 @@ def handle_error(err):
|
||||
if err == libzt.ZTS_ERR_GENERAL:
|
||||
raise Exception("ZTS_ERR_GENERAL (" + str(err) + ")")
|
||||
|
||||
|
||||
# This implementation of errno is NOT thread safe
|
||||
# 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
|
||||
@@ -28,41 +26,10 @@ def errno():
|
||||
"""Return errno value of low-level socket layer"""
|
||||
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:
|
||||
"""Pythonic class that wraps low-level sockets"""
|
||||
|
||||
_fd = -1 # native layer file descriptor
|
||||
_family = -1
|
||||
_type = -1
|
||||
@@ -131,7 +98,9 @@ class socket:
|
||||
"""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)"""
|
||||
raise NotImplementedError("libzt does not support this (yet?)")
|
||||
|
||||
@@ -285,7 +254,8 @@ class socket:
|
||||
def detach(self):
|
||||
"""libzt does not support this"""
|
||||
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):
|
||||
"""libzt does not support this"""
|
||||
|
||||
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