Add working Python wrapper and examples (WIP)
This commit is contained in:
15
examples/python/Makefile
Normal file
15
examples/python/Makefile
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
LIB_OUTPUT_DIR = $(shell cd ../../ && ./build.sh gethosttype)
|
||||||
|
|
||||||
|
copy_wrapper_sources:
|
||||||
|
cp -f ../../src/bindings/python/*.py .
|
||||||
|
|
||||||
|
debug: copy_wrapper_sources
|
||||||
|
cd ../../ && ./build.sh host-python "debug"
|
||||||
|
cp -f ../../dist/$(LIB_OUTPUT_DIR)-python-debug/lib/*.so .
|
||||||
|
|
||||||
|
release: copy_wrapper_sources
|
||||||
|
cd ../../ && ./build.sh host-python "release"
|
||||||
|
cp -f ../../dist/$(LIB_OUTPUT_DIR)-python-release/lib/*.so .
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf *.so libzt.py prototype.py
|
||||||
23
examples/python/README.md
Normal file
23
examples/python/README.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Python example
|
||||||
|
|
||||||
|
This example demonstrates how to use the ZeroTier socket interface provided by libzt in a Python application. The API is designed to be a drop-in replacement for the Python [Low-level networking interface](https://docs.python.org/3/library/socket.html).
|
||||||
|
|
||||||
|
Note: Only `AF_INET` and `AF_INET6` address families are supported.
|
||||||
|
|
||||||
|
### Install
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install libzt
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run
|
||||||
|
```
|
||||||
|
python3 example.py server id-path/bob 0123456789abcdef 9997 8080
|
||||||
|
python3 example.py client id-path/alice 0123456789abcdef 9996 11.22.33.44 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
*Where `9996` and `9997` are arbitrary ports that you allow ZeroTier to use for encrypted UDP traffic, port `8080` is an arbitrary port used by the client/server socket code, and `11.22.33.44` should be whatever IP address the network assigns your node.*
|
||||||
|
|
||||||
|
### Implementation Details
|
||||||
|
|
||||||
|
- See [src/bindings/python](../../src/bindings/python)
|
||||||
159
examples/python/example.py
Normal file
159
examples/python/example.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import time, sys
|
||||||
|
|
||||||
|
import libzt
|
||||||
|
from prototype import *
|
||||||
|
|
||||||
|
# Where identity files are stored
|
||||||
|
keyPath = "."
|
||||||
|
|
||||||
|
# Network to join
|
||||||
|
networkId = 0
|
||||||
|
|
||||||
|
# Port used by ZeroTier to send encpryted UDP traffic
|
||||||
|
# NOTE: Should be different from other instances of ZeroTier
|
||||||
|
# running on the same machine
|
||||||
|
ztServicePort = 9997
|
||||||
|
|
||||||
|
remoteIP = None
|
||||||
|
|
||||||
|
# A port your app logic may use
|
||||||
|
serverPort = 8080
|
||||||
|
|
||||||
|
# Flags to keep state
|
||||||
|
is_joined = False
|
||||||
|
is_online = False
|
||||||
|
mode = None
|
||||||
|
|
||||||
|
def print_usage():
|
||||||
|
print("\nUsage: <server|client> <id_path> <nwid> <ztServicePort> <remoteIP> <serverPort>\n")
|
||||||
|
print(" Ex: python3 example.py server . 0123456789abcdef 9994 8080")
|
||||||
|
print(" Ex: python3 example.py client . 0123456789abcdef 9994 192.168.22.1 8080\n")
|
||||||
|
if (len(sys.argv) < 6):
|
||||||
|
print('Too few arguments')
|
||||||
|
if (len(sys.argv) > 7):
|
||||||
|
print('Too many arguments')
|
||||||
|
exit(0)
|
||||||
|
#
|
||||||
|
if (len(sys.argv) < 6 or len(sys.argv) > 7):
|
||||||
|
print_usage()
|
||||||
|
|
||||||
|
if (sys.argv[1] == 'server' and len(sys.argv) == 6):
|
||||||
|
mode = sys.argv[1]
|
||||||
|
keyPath = sys.argv[2]
|
||||||
|
networkId = int(sys.argv[3],16)
|
||||||
|
ztServicePort = int(sys.argv[4])
|
||||||
|
serverPort = int(sys.argv[5])
|
||||||
|
|
||||||
|
if (sys.argv[1] == 'client' and len(sys.argv) == 7):
|
||||||
|
mode = sys.argv[1]
|
||||||
|
keyPath = sys.argv[2]
|
||||||
|
networkId = int(sys.argv[3],16)
|
||||||
|
ztServicePort = int(sys.argv[4])
|
||||||
|
remoteIP = sys.argv[5]
|
||||||
|
serverPort = int(sys.argv[6])
|
||||||
|
|
||||||
|
if (mode is None):
|
||||||
|
print_usage()
|
||||||
|
|
||||||
|
print('mode = ', mode)
|
||||||
|
print('path = ', keyPath)
|
||||||
|
print('networkId = ', networkId)
|
||||||
|
print('ztServicePort = ', ztServicePort)
|
||||||
|
print('remoteIP = ', remoteIP)
|
||||||
|
print('serverPort = ', serverPort)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Event handler
|
||||||
|
#
|
||||||
|
class MyEventCallbackClass(libzt.PythonDirectorCallbackClass):
|
||||||
|
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")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Example start and join logic
|
||||||
|
#
|
||||||
|
print("Starting ZeroTier...");
|
||||||
|
eventCallback = MyEventCallbackClass()
|
||||||
|
libzt.zts_start(keyPath, eventCallback, ztServicePort)
|
||||||
|
print("Waiting for node to come online...")
|
||||||
|
while (not is_online):
|
||||||
|
time.sleep(1)
|
||||||
|
print("Joining network:", hex(networkId));
|
||||||
|
libzt.zts_join(networkId)
|
||||||
|
while (not is_joined):
|
||||||
|
time.sleep(1) # You can ping this app at this point
|
||||||
|
print('Joined network')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Example server
|
||||||
|
#
|
||||||
|
if (mode == 'server'):
|
||||||
|
print("Starting server...")
|
||||||
|
try:
|
||||||
|
serv = zerotier.socket(libzt.ZTS_AF_INET6, libzt.ZTS_SOCK_STREAM, 0)
|
||||||
|
serv.bind(('::', serverPort))
|
||||||
|
serv.listen(5)
|
||||||
|
while True:
|
||||||
|
conn, addr = serv.accept()
|
||||||
|
print('Accepted connection from: ', addr)
|
||||||
|
while True:
|
||||||
|
print('recv()...')
|
||||||
|
data = conn.recv(4096)
|
||||||
|
if data:
|
||||||
|
print('data = ', data)
|
||||||
|
#print(type(b'what'))
|
||||||
|
#exit(0)
|
||||||
|
if not data: break
|
||||||
|
print('send()...')
|
||||||
|
#bytes(data, 'ascii') + b'\x00'
|
||||||
|
n_bytes = conn.send(data) # echo back to the server
|
||||||
|
print('sent ' + str(n_bytes) + ' byte(s)')
|
||||||
|
conn.close()
|
||||||
|
print('client disconnected')
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Example client
|
||||||
|
#
|
||||||
|
if (mode == 'client'):
|
||||||
|
print("Starting client...")
|
||||||
|
try:
|
||||||
|
client = zerotier.socket(libzt.ZTS_AF_INET6, libzt.ZTS_SOCK_STREAM, 0)
|
||||||
|
print("connecting...")
|
||||||
|
client.connect((remoteIP, serverPort))
|
||||||
|
print("send...")
|
||||||
|
data = 'Hello, world!'
|
||||||
|
client.send(data)
|
||||||
|
print("rx...")
|
||||||
|
data = client.recv(1024)
|
||||||
|
|
||||||
|
print('Received', repr(data))
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/* libzt.i */
|
|
||||||
|
|
||||||
%begin
|
|
||||||
%{
|
|
||||||
#define SWIG_PYTHON_CAST_MODE
|
|
||||||
%}
|
|
||||||
|
|
||||||
%include <stdint.i>
|
|
||||||
|
|
||||||
#define PYTHON_BUILD 1
|
|
||||||
|
|
||||||
%module libzt
|
|
||||||
%{
|
|
||||||
#include "../include/ZeroTier.h"
|
|
||||||
#include "../include/ZeroTierConstants.h"
|
|
||||||
%}
|
|
||||||
|
|
||||||
%define %cs_callback(TYPE, CSTYPE)
|
|
||||||
%typemap(ctype) TYPE, TYPE& "void *"
|
|
||||||
%typemap(in) TYPE %{ $1 = ($1_type)$input; %}
|
|
||||||
%typemap(in) TYPE& %{ $1 = ($1_type)&$input; %}
|
|
||||||
%typemap(imtype, out="IntPtr") TYPE, TYPE& "CSTYPE"
|
|
||||||
%typemap(cstype, out="IntPtr") TYPE, TYPE& "CSTYPE"
|
|
||||||
%typemap(csin) TYPE, TYPE& "$csinput"
|
|
||||||
%enddef
|
|
||||||
|
|
||||||
%cs_callback(userCallbackFunc, CSharpCallback)
|
|
||||||
|
|
||||||
%include "../include/ZeroTier.h"
|
|
||||||
%include "../include/ZeroTierConstants.h"
|
|
||||||
148
src/bindings/python/PythonSockets.cpp
Normal file
148
src/bindings/python/PythonSockets.cpp
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* 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 "lwip/sockets.h"
|
||||||
|
#include "ZeroTierSockets.h"
|
||||||
|
|
||||||
|
#ifdef ZTS_ENABLE_PYTHON
|
||||||
|
|
||||||
|
static int 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:tuple_to_sockaddr", "idna", &host_str, &port)) {
|
||||||
|
return ZTS_ERR_ARG;
|
||||||
|
}
|
||||||
|
addr = (struct zts_sockaddr_in*)dst_addr;
|
||||||
|
addr->sin_addr.s_addr = zts_inet_addr(host_str);
|
||||||
|
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 = 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(zts_ntohs(addrbuf.sin_port)));
|
||||||
|
Py_INCREF(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_listen(int fd, int backlog)
|
||||||
|
{
|
||||||
|
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 (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
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
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 (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
|
||||||
|
Py_INCREF(Py_None);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyObject * zts_py_recv(int fd, int len, int flags)
|
||||||
|
{
|
||||||
|
PyObject *t;
|
||||||
|
char buf[4096];
|
||||||
|
int err = zts_recv(fd, buf, len, flags);
|
||||||
|
if (err < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
t = PyTuple_New(2);
|
||||||
|
PyTuple_SetItem(t, 0, PyLong_FromLong(err));
|
||||||
|
PyTuple_SetItem(t, 1, PyUnicode_FromString(buf));
|
||||||
|
Py_INCREF(t);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_send(int fd, PyObject *buf, int len, int flags)
|
||||||
|
{
|
||||||
|
int err = ZTS_ERR_OK;
|
||||||
|
PyObject *encodedStr = PyUnicode_AsEncodedString(buf, "UTF-8", "strict");
|
||||||
|
if (encodedStr) {
|
||||||
|
char *bytes = PyBytes_AsString(encodedStr);
|
||||||
|
err = zts_send(fd, bytes, len, flags);
|
||||||
|
Py_DECREF(encodedStr);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zts_py_close(int fd)
|
||||||
|
{
|
||||||
|
return zts_close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // ZTS_ENABLE_PYTHON
|
||||||
4
src/bindings/python/README.md
Normal file
4
src/bindings/python/README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Python Language Bindings
|
||||||
|
|
||||||
|
- Install (via [PyPI package](https://pypi.org/project/libzt/)): `pip install libzt`
|
||||||
|
- Example usage: [examples/python](./../../../examples/python/)
|
||||||
103
src/bindings/python/prototype.py
Normal file
103
src/bindings/python/prototype.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import libzt
|
||||||
|
|
||||||
|
import time
|
||||||
|
import struct
|
||||||
|
import pprint
|
||||||
|
pp = pprint.PrettyPrinter(width=41, compact=True)
|
||||||
|
|
||||||
|
class zerotier():
|
||||||
|
# Create a socket
|
||||||
|
def socket(sock_family, sock_type, sock_proto=0):
|
||||||
|
return ztsocket(sock_family, sock_type, sock_proto)
|
||||||
|
# Convert libzt error code to exception
|
||||||
|
def handle_error(err):
|
||||||
|
if (err == libzt.ZTS_ERR_SOCKET):
|
||||||
|
raise Exception('ZTS_ERR_SOCKET (' + str(err) + ')')
|
||||||
|
if (err == libzt.ZTS_ERR_SERVICE):
|
||||||
|
raise Exception('ZTS_ERR_SERVICE (' + str(err) + ')')
|
||||||
|
if (err == libzt.ZTS_ERR_ARG):
|
||||||
|
raise Exception('ZTS_ERR_ARG (' + str(err) + ')')
|
||||||
|
# ZTS_ERR_NO_RESULT isn't strictly an error
|
||||||
|
#if (err == libzt.ZTS_ERR_NO_RESULT):
|
||||||
|
# raise Exception('ZTS_ERR_NO_RESULT (' + err + ')')
|
||||||
|
if (err == libzt.ZTS_ERR_GENERAL):
|
||||||
|
raise Exception('ZTS_ERR_GENERAL (' + str(err) + ')')
|
||||||
|
|
||||||
|
# ZeroTier pythonic low-level socket class
|
||||||
|
class ztsocket():
|
||||||
|
|
||||||
|
_fd = -1 # native layer file descriptor
|
||||||
|
_family = -1
|
||||||
|
_type = -1
|
||||||
|
_proto = -1
|
||||||
|
_connected = False
|
||||||
|
_closed = True
|
||||||
|
_bound = False
|
||||||
|
|
||||||
|
def __init__(self, sock_family=-1, sock_type=-1, sock_proto=-1, sock_fd=None):
|
||||||
|
self._fd = sock_fd
|
||||||
|
self._family = sock_family
|
||||||
|
self._type = sock_type
|
||||||
|
self._family = sock_family
|
||||||
|
# Only create native socket if no fd was provided. We may have
|
||||||
|
# accepted a connection
|
||||||
|
if (sock_fd == None):
|
||||||
|
self._fd = libzt.zts_socket(sock_family, sock_type, sock_proto)
|
||||||
|
|
||||||
|
def has_dualstack_ipv6():
|
||||||
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def family(self):
|
||||||
|
return _family
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self):
|
||||||
|
return _type
|
||||||
|
|
||||||
|
# Bind the socket to a local interface address
|
||||||
|
def bind(self, local_address):
|
||||||
|
err = libzt.zts_py_bind(self._fd, self._family, self._type, local_address)
|
||||||
|
if (err < 0):
|
||||||
|
zerotier.handle_error(err)
|
||||||
|
|
||||||
|
# Connect the socket to a remote address
|
||||||
|
def connect(self, remote_address):
|
||||||
|
err = libzt.zts_py_connect(self._fd, self._family, self._type, remote_address)
|
||||||
|
if (err < 0):
|
||||||
|
zerotier.handle_error(err)
|
||||||
|
|
||||||
|
# Put the socket in a listening state (with an optional backlog argument)
|
||||||
|
def listen(self, backlog):
|
||||||
|
err = libzt.zts_py_listen(self._fd, backlog)
|
||||||
|
if (err < 0):
|
||||||
|
zerotier.handle_error(err)
|
||||||
|
|
||||||
|
# Accept connection on the socket
|
||||||
|
def accept(self):
|
||||||
|
new_conn_fd, addr, port = libzt.zts_py_accept(self._fd)
|
||||||
|
if (new_conn_fd < 0):
|
||||||
|
zerotier.handle_error(acc_fd)
|
||||||
|
return None
|
||||||
|
return ztsocket(self._family, self._type, self._proto, new_conn_fd), addr
|
||||||
|
|
||||||
|
# Read data from the socket
|
||||||
|
def recv(self, n_bytes, flags=0):
|
||||||
|
err, data = libzt.zts_py_recv(self._fd, n_bytes, flags)
|
||||||
|
if (err < 0):
|
||||||
|
zerotier.handle_error(err)
|
||||||
|
return None
|
||||||
|
return data
|
||||||
|
|
||||||
|
# Write data to the socket
|
||||||
|
def send(self, data, flags=0):
|
||||||
|
err = libzt.zts_py_send(self._fd, data, len(data), flags)
|
||||||
|
if (err < 0):
|
||||||
|
zerotier.handle_error(err)
|
||||||
|
return err
|
||||||
|
|
||||||
|
# Close the socket
|
||||||
|
def close(self):
|
||||||
|
err = libzt.zts_py_close(self._fd)
|
||||||
|
if (err < 0):
|
||||||
|
zerotier.handle_error(err)
|
||||||
39
src/bindings/python/zt.i
Normal file
39
src/bindings/python/zt.i
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/* libzt.i */
|
||||||
|
|
||||||
|
%begin
|
||||||
|
%{
|
||||||
|
#define SWIG_PYTHON_CAST_MODE
|
||||||
|
%}
|
||||||
|
|
||||||
|
%include <stdint.i>
|
||||||
|
|
||||||
|
#define ZTS_ENABLE_PYTHON 1
|
||||||
|
|
||||||
|
%module(directors="1") libzt
|
||||||
|
%module libzt
|
||||||
|
%{
|
||||||
|
#include "ZeroTierSockets.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
%feature("director") PythonDirectorCallbackClass;
|
||||||
|
|
||||||
|
%ignore zts_in6_addr;
|
||||||
|
%ignore zts_sockaddr;
|
||||||
|
%ignore zts_in_addr;
|
||||||
|
%ignore zts_sockaddr_in;
|
||||||
|
%ignore zts_sockaddr_storage;
|
||||||
|
%ignore zts_sockaddr_in6;
|
||||||
|
|
||||||
|
%ignore zts_linger;
|
||||||
|
%ignore zts_accept4;
|
||||||
|
%ignore zts_ip_mreq;
|
||||||
|
%ignore zts_in_pktinfo;
|
||||||
|
%ignore zts_ipv6_mreq;
|
||||||
|
|
||||||
|
%ignore zts_fd_set;
|
||||||
|
%ignore zts_pollfd;
|
||||||
|
%ignore zts_nfds_t;
|
||||||
|
%ignore zts_msghdr;
|
||||||
|
%ignore zts_inet_addr;
|
||||||
|
|
||||||
|
%include "ZeroTierSockets.h"
|
||||||
Reference in New Issue
Block a user