Run Python language bindings and example code through a linter and formatter

This commit is contained in:
Joseph Henry
2021-03-07 21:11:21 -08:00
parent e1d0f92d61
commit dd6cf48d61
2 changed files with 526 additions and 467 deletions

View File

@@ -1,347 +1,408 @@
"""ZeroTier low-level socket interface"""
import libzt
class EventCallbackClass(libzt.PythonDirectorCallbackClass):
pass
"""ZeroTier event callback class"""
pass
# 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) + ')')
"""Convert libzt error code to exception"""
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) + ")")
# 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
# threads making socket calls.
def errno():
return libzt.cvar.zts_errno
"""Return errno value of low-level socket layer"""
return libzt.cvar.zts_errno
# Start the ZeroTier service
def start(path, callback, port):
libzt.zts_start(path, callback, port)
"""Start the ZeroTier service"""
libzt.zts_start(path, callback, port)
# Stop the ZeroTier service
def stop():
libzt.zts_stop()
"""Stop the ZeroTier service"""
libzt.zts_stop()
# [debug] Restarts the ZeroTier service and network stack
def restart():
libzt.zts_restart()
"""[debug] Restarts the ZeroTier service and network stack"""
libzt.zts_restart()
# Permenantly shuts down the network stack.
def free():
libzt.zts_free()
# Join a ZeroTier network
def join(networkId):
libzt.zts_join(networkId)
# Leave a ZeroTier network
def leave(networkId):
libzt.zts_leave(networkId)
# Orbit a moon
def zts_orbit(moonWorldId, moonSeed):
return libzt.zts_orbit(moonWorldId, moonSeed)
# De-orbit a moon
def zts_deorbit(moonWorldId):
return libzt.zts_deorbit(moonWorldId)
# Pythonic class that wraps low-level sockets
class socket():
_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
@property
def proto(self):
return _proto
# Intentionally not supported
def socketpair(self, family, type, proto):
raise NotImplementedError("socketpair(): libzt does not support AF_UNIX sockets")
# Convenience function to create a connection to a remote host
def create_connection(self, remote_address):
# TODO: implement timeout
conn = socket(libzt.ZTS_AF_INET, libzt.ZTS_SOCK_STREAM, 0)
conn.connect(remote_address)
return conn
# Convenience function to create a listening socket
def create_server(self, local_address, family=libzt.ZTS_AF_INET, backlog=None):
# TODO: implement reuse_port
conn = socket(libzt.ZTS_AF_INET, libzt.ZTS_SOCK_STREAM, 0)
conn.bind(local_address)
conn.listen(backlog)
return conn
def fromfd(self, fd, family, type, proto=0):
raise NotImplementedError("fromfd(): Not supported. OS File descriptors aren't used in libzt.")
def fromshare(self, data):
raise NotImplementedError("libzt does not support this (yet?)")
def close(self, fd):
raise NotImplementedError("close(fd): Not supported OS File descriptors aren't used in libzt.")
def getaddrinfo(self, host, port, family=0, type=0, proto=0, flags=0):
raise NotImplementedError("libzt does not support this (yet?)")
def getfqdn(self, name):
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyname(self, hostname):
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyname_ex(self, hostname):
raise NotImplementedError("libzt does not support this (yet?)")
def gethostname(self):
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyaddr(self, ip_address):
raise NotImplementedError("libzt does not support this (yet?)")
def getnameinfo(self, sockaddr, flags):
raise NotImplementedError("libzt does not support this (yet?)")
def getprotobyname(self, protocolname):
raise NotImplementedError("libzt does not support this (yet?)")
def getservbyname(self, servicename, protocolname):
raise NotImplementedError("libzt does not support this (yet?)")
def getservbyport(self, port, protocolname):
raise NotImplementedError("libzt does not support this (yet?)")
def ntohl(x):
raise NotImplementedError("libzt does not support this (yet?)")
def ntohs(x):
raise NotImplementedError("libzt does not support this (yet?)")
def htonl(x):
raise NotImplementedError("libzt does not support this (yet?)")
def htons(x):
raise NotImplementedError("libzt does not support this (yet?)")
def inet_aton(ip_string):
raise NotImplementedError("libzt does not support this (yet?)")
def inet_ntoa(packed_ip):
raise NotImplementedError("libzt does not support this (yet?)")
def inet_pton(address_family, ip_string):
raise NotImplementedError("libzt does not support this (yet?)")
def inet_ntop(address_family, packed_ip):
raise NotImplementedError("libzt does not support this (yet?)")
def CMSG_LEN(length):
raise NotImplementedError("libzt does not support this (yet?)")
def CMSG_SPACE(length):
raise NotImplementedError("libzt does not support this (yet?)")
def getdefaulttimeout(self):
raise NotImplementedError("libzt does not support this (yet?)")
def setdefaulttimeout(self, timeout):
raise NotImplementedError("libzt does not support this (yet?)")
def sethostname(self, name):
raise NotImplementedError("libzt does not support this (yet?)")
def if_nameindex(self):
raise NotImplementedError("libzt does not support this (yet?)")
def if_nametoindex(self, if_name):
raise NotImplementedError("if_nametoindex(): libzt does not name interfaces.")
def if_indextoname(self, if_index):
raise NotImplementedError("if_indextoname(): libzt does not name interfaces.")
# Accept connection on the socket
def accept(self):
new_conn_fd, addr, port = libzt.zts_py_accept(self._fd)
if (new_conn_fd < 0):
handle_error(new_conn_fd)
return None
return ztsocket(self._family, self._type, self._proto, new_conn_fd), addr
# 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):
handle_error(err)
# Close the socket
def close(self):
err = libzt.zts_py_close(self._fd)
if (err < 0):
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):
handle_error(err)
# Connect to remote host but return low-level result code, and errno on failure
# This uses a non-thread-safe implementation of errno
def connect_ex(self, remote_address):
err = libzt.zts_py_connect(self._fd, self._family, self._type, remote_address)
if (err < 0):
return errno()
return err
def detach(self):
raise NotImplementedError("detach(): Not supported. OS File descriptors aren't used in libzt.")
def dup(self):
raise NotImplementedError("libzt does not support this (yet?)")
def fileno(self):
raise NotImplementedError("libzt does not support this (yet?)")
def get_inheritable(self):
raise NotImplementedError("libzt does not support this (yet?)")
def getpeername(self):
raise NotImplementedError("libzt does not support this (yet?)")
def getsockname(self):
raise NotImplementedError("libzt does not support this (yet?)")
def getsockopt(self, level, optname, buflen):
raise NotImplementedError("libzt does not support this (yet?)")
# Get whether this socket is in blocking or non-blocking mode
def getblocking(self):
return libzt.zts_py_getblocking(self._fd)
def gettimeout(self):
raise NotImplementedError("libzt does not support this (yet?)")
def ioctl(self, control, option):
raise NotImplementedError("libzt does not support this (yet?)")
# 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):
handle_error(err)
def makefile(mode='r', buffering=None, *, encoding=None, errors=None, newline=None):
raise NotImplementedError("libzt does not support this (yet?)")
# 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):
handle_error(err)
return None
return data
def recvfrom(self, bufsize, flags):
raise NotImplementedError("libzt does not support this (yet?)")
def recvmsg(self, bufsize, ancbufsize, flags):
raise NotImplementedError("libzt does not support this (yet?)")
def recvmsg_into(self, buffers, ancbufsize, flags):
raise NotImplementedError("libzt does not support this (yet?)")
def recvfrom_into(self, buffer, nbytes, flags):
raise NotImplementedError("libzt does not support this (yet?)")
def recv_into(self, buffer, nbytes, flags):
raise NotImplementedError("libzt does not support this (yet?)")
# 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):
handle_error(err)
return err
def sendall(self, bytes, flags):
raise NotImplementedError("libzt does not support this (yet?)")
def sendto(self, bytes, address):
raise NotImplementedError("libzt does not support this (yet?)")
def sendto(self, bytes, flags, address):
raise NotImplementedError("libzt does not support this (yet?)")
def sendmsg(self, buffers, ancdata, flags, address):
raise NotImplementedError("libzt does not support this (yet?)")
def sendmsg_afalg(self, msg, *, op, iv, assoclen, flags):
raise NotImplementedError("sendmsg_afalg(): libzt does not support AF_ALG")
def send_fds(self, sock, buffers, fds, flags, address):
raise NotImplementedError("libzt does not support this (yet?)")
def recv_fds(self, sock, bufsize, maxfds, flags):
raise NotImplementedError("libzt does not support this (yet?)")
def sendfile(self, file, offset=0, count=None):
raise NotImplementedError("libzt does not support this (yet?)")
def set_inheritable(self, inheritable):
raise NotImplementedError("libzt does not support this (yet?)")
# Set whether this socket is in blocking or non-blocking mode
def setblocking(self, flag):
libzt.zts_py_setblocking(self._fd, flag)
def settimeout(self, value):
raise NotImplementedError("libzt does not support this (yet?)")
def setsockopt(self, level, optname, value):
# TODO: value: buffer
# TODO: value: int
# TODO: value: None -> optlen required
raise NotImplementedError("libzt does not support this (yet?)")
# Shut down one or more aspects (rx/tx) of the socket
def shutdown(self, how):
libzt.shutdown(self._fd, how)
"""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
_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 is None:
self._fd = libzt.zts_socket(sock_family, sock_type, sock_proto)
def has_dualstack_ipv6(self):
"""Return whether libzt supports dual stack sockets: yes"""
return True
@property
def family(self):
"""Return family of socket"""
return self._family
@property
def type(self):
"""Return type of socket"""
return self._type
@property
def proto(self):
"""Return protocol of socket"""
return self._proto
def socketpair(self, sock_family, sock_type, sock_proto):
"""Intentionally not supported"""
raise NotImplementedError(
"socketpair(): libzt does not support AF_UNIX sockets"
)
def create_connection(self, remote_address):
"""Convenience function to create a connection to a remote host"""
# TODO: implement timeout
conn = socket(libzt.ZTS_AF_INET, libzt.ZTS_SOCK_STREAM, 0)
conn.connect(remote_address)
return conn
def create_server(self, local_address, sock_family=libzt.ZTS_AF_INET, backlog=None):
"""Convenience function to create a listening socket"""
# TODO: implement reuse_port
conn = socket(sock_family, libzt.ZTS_SOCK_STREAM, 0)
conn.bind(local_address)
conn.listen(backlog)
return conn
def fromfd(self, fd, sock_family, sock_type, sock_proto=0):
"""libzt does not support this (yet)"""
raise NotImplementedError(
"fromfd(): Not supported. OS File descriptors aren't used in libzt."
)
def fromshare(self, data):
"""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):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getfqdn(self, name):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyname(self, hostname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyname_ex(self, hostname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def gethostname(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def gethostbyaddr(self, ip_address):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getnameinfo(self, sockaddr, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getprotobyname(self, protocolname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getservbyname(self, servicename, protocolname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getservbyport(self, port, protocolname):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def ntohl(x):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def ntohs(x):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def htonl(x):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def htons(x):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def inet_aton(ip_string):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def inet_ntoa(packed_ip):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def inet_pton(address_family, ip_string):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def inet_ntop(address_family, packed_ip):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def CMSG_LEN(length):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def CMSG_SPACE(length):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getdefaulttimeout(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def setdefaulttimeout(self, timeout):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sethostname(self, name):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def if_nameindex(self):
"""libzt does not support this"""
raise NotImplementedError("if_nameindex(): libzt does not name interfaces.")
def if_nametoindex(self, if_name):
"""libzt does not support this"""
raise NotImplementedError("if_nametoindex(): libzt does not name interfaces.")
def if_indextoname(self, if_index):
"""libzt does not support this"""
raise NotImplementedError("if_indextoname(): libzt does not name interfaces.")
def accept(self):
"""Accept connection on the socket"""
new_conn_fd, addr, port = libzt.zts_py_accept(self._fd)
if new_conn_fd < 0:
handle_error(new_conn_fd)
return None
return socket(self._family, self._type, self._proto, new_conn_fd), addr
def bind(self, local_address):
"""Bind the socket to a local interface address"""
err = libzt.zts_py_bind(self._fd, self._family, self._type, local_address)
if err < 0:
handle_error(err)
def close(self):
"""Close the socket"""
err = libzt.zts_py_close(self._fd)
if err < 0:
handle_error(err)
def connect(self, remote_address):
"""Connect the socket to a remote address"""
err = libzt.zts_py_connect(self._fd, self._family, self._type, remote_address)
if err < 0:
handle_error(err)
def connect_ex(self, remote_address):
"""Connect to remote host but return low-level result code, and errno on failure
This uses a non-thread-safe implementation of errno
"""
err = libzt.zts_py_connect(self._fd, self._family, self._type, remote_address)
if err < 0:
return errno()
return err
def detach(self):
"""libzt does not support this"""
raise NotImplementedError(
"detach(): Not supported. OS File descriptors aren't used in libzt.")
def dup(self):
"""libzt does not support this"""
raise NotImplementedError("libzt does not support this (yet?)")
def fileno(self):
"""libzt does not support this"""
raise NotImplementedError("libzt does not support this (yet?)")
def get_inheritable(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getpeername(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getsockname(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getsockopt(self, level, optname, buflen):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def getblocking(self):
"""Get whether this socket is in blocking or non-blocking mode"""
return libzt.zts_py_getblocking(self._fd)
def gettimeout(self):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def ioctl(self, control, option):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def listen(self, backlog):
"""Put the socket in a listening state (with an optional backlog argument)"""
err = libzt.zts_py_listen(self._fd, backlog)
if err < 0:
handle_error(err)
def makefile(mode="r", buffering=None, *, encoding=None, errors=None, newline=None):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recv(self, n_bytes, flags=0):
"""Read data from the socket"""
err, data = libzt.zts_py_recv(self._fd, n_bytes, flags)
if err < 0:
handle_error(err)
return None
return data
def recvfrom(self, bufsize, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recvmsg(self, bufsize, ancbufsize, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recvmsg_into(self, buffers, ancbufsize, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recvfrom_into(self, buffer, n_bytes, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recv_into(self, buffer, n_bytes, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def send(self, data, flags=0):
"""Write data to the socket"""
err = libzt.zts_py_send(self._fd, data, len(data), flags)
if err < 0:
handle_error(err)
return err
def sendall(self, n_bytes, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sendto(self, n_bytes, flags, address):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sendmsg(self, buffers, ancdata, flags, address):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sendmsg_afalg(self, msg, *, op, iv, assoclen, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("sendmsg_afalg(): libzt does not support AF_ALG")
def send_fds(self, sock, buffers, fds, flags, address):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def recv_fds(self, sock, bufsize, maxfds, flags):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def sendfile(self, file, offset=0, count=None):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def set_inheritable(self, inheritable):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def setblocking(self, flag):
"""Set whether this socket is in blocking or non-blocking mode"""
libzt.zts_py_setblocking(self._fd, flag)
def settimeout(self, value):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
# TODO: value: buffer
# TODO: value: int
# TODO: value: None -> optlen required
def setsockopt(self, level, optname, value):
"""libzt does not support this (yet)"""
raise NotImplementedError("libzt does not support this (yet?)")
def shutdown(self, how):
"""Shut down one or more aspects (rx/tx) of the socket"""
libzt.zts_shutdown(self._fd, how)