diff options
Diffstat (limited to 'ouroboros/dev.py')
| -rw-r--r-- | ouroboros/dev.py | 135 |
1 files changed, 116 insertions, 19 deletions
diff --git a/ouroboros/dev.py b/ouroboros/dev.py index e0b1488..d36a3ef 100644 --- a/ouroboros/dev.py +++ b/ouroboros/dev.py @@ -1,7 +1,7 @@ # -# Ouroboros - Copyright (C) 2016 - 2020 +# Ouroboros - Copyright (C) 2016 - 2026 # -# Python API for applications +# Python API for Ouroboros # # Dimitri Staessens <dimitri@ouroboros.rocks> # @@ -21,14 +21,96 @@ import errno from enum import IntFlag +from math import modf +from typing import Optional -from _ouroboros_cffi import ffi, lib +from _ouroboros_dev_cffi import ffi, lib from ouroboros.qos import * -from ouroboros.qos import _qos_to_qosspec, _fl_to_timespec, _qosspec_to_qos, _timespec_to_fl + + +def _check_ouroboros_version(): + ouro_major = lib.OUROBOROS_VERSION_MAJOR + ouro_minor = lib.OUROBOROS_VERSION_MINOR + try: + from importlib.metadata import version, PackageNotFoundError + try: + pyouro_parts = version('PyOuroboros').split('.') + except PackageNotFoundError: + return # running from source, skip check + if ouro_major != int(pyouro_parts[0]) or \ + ouro_minor != int(pyouro_parts[1]): + raise RuntimeError( + f"Ouroboros version mismatch: library is " + f"{ouro_major}.{ouro_minor}, " + f"pyouroboros is " + f"{pyouro_parts[0]}.{pyouro_parts[1]}" + ) + except ImportError: + pass # Python < 3.8 + + +_check_ouroboros_version() # Some constants -MILLION = 1000_1000 -BILLION = 1000_1000_1000 +MILLION = 1000 * 1000 +BILLION = 1000 * 1000 * 1000 + + +def _fl_to_timespec(timeo: float): + if timeo is None: + return ffi.NULL + elif timeo <= 0: + return ffi.new("struct timespec *", [0, 0]) + else: + frac, whole = modf(timeo) + _timeo = ffi.new("struct timespec *") + _timeo.tv_sec = int(whole) + _timeo.tv_nsec = int(frac * BILLION) + return _timeo + + +def _timespec_to_fl(_timeo) -> Optional[float]: + if _timeo is ffi.NULL: + return None + elif _timeo.tv_sec <= 0 and _timeo.tv_nsec == 0: + return 0 + else: + return _timeo.tv_sec + _timeo.tv_nsec / BILLION + + +# Intentionally duplicated, dev uses a separate FFI (ouroboros-dev). +def _qos_to_qosspec(qos: QoSSpec): + if qos is None: + return ffi.NULL + else: + return ffi.new("qosspec_t *", + [qos.delay, + qos.bandwidth, + qos.availability, + qos.loss, + qos.ber, + qos.in_order, + qos.max_gap, + qos.timeout]) + + +def _qosspec_to_qos(_qos) -> Optional[QoSSpec]: + if _qos is ffi.NULL: + return None + else: + return QoSSpec(delay=_qos.delay, + bandwidth=_qos.bandwidth, + availability=_qos.availability, + loss=_qos.loss, + ber=_qos.ber, + in_order=_qos.in_order, + max_gap=_qos.max_gap, + timeout=_qos.timeout) + +# FRCT flags +FRCT_RETRANSMIT = 0o1 +FRCT_RESCNTL = 0o2 +FRCT_LINGER = 0o4 # ouroboros exceptions @@ -144,8 +226,7 @@ class Flow: def join(self, dst: str, - qos: QoSSpec = None, - timeo: float = None) -> Optional[QoSSpec]: + timeo: float = None) -> None: """ Join a broadcast layer @@ -158,16 +239,12 @@ class Flow: if self.__fd >= 0: raise FlowAllocatedException() - _qos = _qos_to_qosspec(qos) - _timeo = _fl_to_timespec(timeo) - self.__fd = lib.flow_join(dst.encode(), _qos, _timeo) + self.__fd = lib.flow_join(dst.encode(), _timeo) _raise(self.__fd) - return _qosspec_to_qos(_qos) - def dealloc(self): """ Deallocate a flow @@ -253,7 +330,7 @@ class Flow: """ _timeo = _fl_to_timespec(timeo) - if lib.flow_set_snd_timout(self.__fd, _timeo) != 0: + if lib.flow_set_snd_timeout(self.__fd, _timeo) != 0: raise FlowPermissionException() def get_snd_timeout(self) -> float: @@ -276,7 +353,7 @@ class Flow: """ _timeo = _fl_to_timespec(timeo) - if lib.flow_set_rcv_timout(self.__fd, _timeo) != 0: + if lib.flow_set_rcv_timeout(self.__fd, _timeo) != 0: raise FlowPermissionException() def get_rcv_timeout(self) -> float: @@ -336,9 +413,7 @@ class Flow: :param flags: """ - _flags = ffi.new("uint32_t *", int(flags)) - - if lib.flow_set_flag(self.__fd, _flags): + if lib.flow_set_flags(self.__fd, int(flags)): raise FlowPermissionException() def get_flags(self) -> FlowProperties: @@ -346,12 +421,34 @@ class Flow: Get the flags for this flow """ - flags = lib.flow_get_flag(self.__fd) + flags = lib.flow_get_flags(self.__fd) if flags < 0: raise FlowPermissionException() return FlowProperties(int(flags)) + def set_frct_flags(self, flags: int): + """ + Set FRCT flags for this flow. + :param flags: Bitmask of FRCT_RETRANSMIT, FRCT_RESCNTL, FRCT_LINGER + """ + + if lib.flow_set_frct_flags(self.__fd, flags): + raise FlowPermissionException() + + def get_frct_flags(self) -> int: + """ + Get the FRCT flags for this flow + + :return: Bitmask of FRCT flags + """ + + flags = lib.flow_get_frct_flags(self.__fd) + if flags < 0: + raise FlowPermissionException() + + return int(flags) + def flow_alloc(dst: str, qos: QoSSpec = None, |
