summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorJoseph Henry <[email protected]>2021-03-01 21:10:39 -0800
committerJoseph Henry <[email protected]>2021-03-01 21:10:39 -0800
commit64a0d5d0d725023fa456407b7c88cd4eba66e286 (patch)
treed3e4d1992e39c5e5fc6529264132a8341b4816d2 /examples
parent32da07ccb7d95d54605a60e75bcab0c9ea4e3b5d (diff)
Add working Python wrapper and examples (WIP)
Diffstat (limited to 'examples')
-rw-r--r--examples/python/Makefile15
-rw-r--r--examples/python/README.md23
-rw-r--r--examples/python/example.py159
-rw-r--r--examples/python/zt.i30
4 files changed, 197 insertions, 30 deletions
diff --git a/examples/python/Makefile b/examples/python/Makefile
new file mode 100644
index 0000000..2b7cce3
--- /dev/null
+++ b/examples/python/Makefile
@@ -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 \ No newline at end of file
diff --git a/examples/python/README.md b/examples/python/README.md
new file mode 100644
index 0000000..640d97b
--- /dev/null
+++ b/examples/python/README.md
@@ -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)
diff --git a/examples/python/example.py b/examples/python/example.py
new file mode 100644
index 0000000..5a4a759
--- /dev/null
+++ b/examples/python/example.py
@@ -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)
+
diff --git a/examples/python/zt.i b/examples/python/zt.i
deleted file mode 100644
index 69aa836..0000000
--- a/examples/python/zt.i
+++ /dev/null
@@ -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"