first commit

This commit is contained in:
Ayxan
2022-05-23 00:16:32 +04:00
commit d660f2a4ca
24786 changed files with 4428337 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
"""Import basic exposure of libzmq C API as a backend"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import os
import platform
from .select import public_api, select_backend
if 'PYZMQ_BACKEND' in os.environ:
backend = os.environ['PYZMQ_BACKEND']
if backend in ('cython', 'cffi'):
backend = 'zmq.backend.%s' % backend
_ns = select_backend(backend)
else:
# default to cython, fallback to cffi
# (reverse on PyPy)
if platform.python_implementation() == 'PyPy':
first, second = ('zmq.backend.cffi', 'zmq.backend.cython')
else:
first, second = ('zmq.backend.cython', 'zmq.backend.cffi')
try:
_ns = select_backend(first)
except Exception as original_error:
try:
_ns = select_backend(second)
except ImportError:
raise original_error from None
globals().update(_ns)
__all__ = public_api

View File

@@ -0,0 +1,114 @@
from typing import Any, List, Optional, Set, Tuple, TypeVar, Union, overload
from typing_extensions import Literal
import zmq
from .select import select_backend
# avoid collision in Frame.bytes
_bytestr = bytes
T = TypeVar("T")
class Frame:
buffer: Any
bytes: bytes
more: bool
tracker: Any
def __init__(
self,
data: Any = None,
track: bool = False,
copy: Optional[bool] = None,
copy_threshold: Optional[int] = None,
): ...
def copy_fast(self: T) -> T: ...
def get(self, option: int) -> Union[int, _bytestr, str]: ...
def set(self, option: int, value: Union[int, _bytestr, str]) -> None: ...
class Socket:
underlying: int
context: "zmq.Context"
copy_threshold: int
# specific option types
FD: int
def close(self, linger: Optional[int] = ...) -> None: ...
def get(self, option: int) -> Union[int, bytes, str]: ...
def set(self, option: int, value: Union[int, bytes, str]) -> None: ...
def connect(self, url: str): ...
def disconnect(self, url: str) -> None: ...
def bind(self, url: str): ...
def unbind(self, url: str) -> None: ...
def send(
self,
data: Any,
flags: int = ...,
copy: bool = ...,
track: bool = ...,
) -> Optional["zmq.MessageTracker"]: ...
@overload
def recv(
self,
flags: int = ...,
*,
copy: Literal[False],
track: bool = ...,
) -> "zmq.Frame": ...
@overload
def recv(
self,
flags: int = ...,
*,
copy: Literal[True],
track: bool = ...,
) -> bytes: ...
@overload
def recv(
self,
flags: int = ...,
track: bool = False,
) -> bytes: ...
@overload
def recv(
self,
flags: Optional[int] = ...,
copy: bool = ...,
track: Optional[bool] = False,
) -> Union["zmq.Frame", bytes]: ...
def monitor(self, addr: Optional[str], events: int) -> None: ...
# draft methods
def join(self, group: str) -> None: ...
def leave(self, group: str) -> None: ...
class Context:
underlying: int
def __init__(self, io_threads: int = 1, shadow: Any = None): ...
def get(self, option: int) -> Union[int, bytes, str]: ...
def set(self, option: int, value: Union[int, bytes, str]) -> None: ...
def socket(self, socket_type: int) -> Socket: ...
def term(self) -> None: ...
IPC_PATH_MAX_LEN: int
def has(capability: str) -> bool: ...
def curve_keypair() -> Tuple[bytes, bytes]: ...
def curve_public(secret_key: bytes) -> bytes: ...
def strerror(errno: Optional[int] = ...) -> str: ...
def zmq_errno() -> int: ...
def zmq_version() -> str: ...
def zmq_version_info() -> Tuple[int, int, int]: ...
def zmq_poll(
sockets: List[Any], timeout: Optional[int] = ...
) -> List[Tuple[Socket, int]]: ...
def device(
device_type: int, frontend: Socket, backend: Optional[Socket] = ...
) -> int: ...
def proxy(frontend: Socket, backend: Socket) -> int: ...
def proxy_steerable(
frontend: Socket,
backend: Socket,
capture: Optional[Socket] = ...,
control: Optional[Socket] = ...,
) -> int: ...

View File

@@ -0,0 +1,33 @@
"""CFFI backend (for PyPy)"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from zmq.backend.cffi import _poll, context, devices, error, message, socket, utils
from ._cffi import ffi
from ._cffi import lib as C
def zmq_version_info():
"""Get libzmq version as tuple of ints"""
major = ffi.new('int*')
minor = ffi.new('int*')
patch = ffi.new('int*')
C.zmq_version(major, minor, patch)
return (int(major[0]), int(minor[0]), int(patch[0]))
__all__ = ["zmq_version_info"]
for submod in (error, message, context, socket, _poll, devices, utils):
__all__.extend(submod.__all__)
from ._poll import *
from .context import *
from .devices import *
from .error import *
from .message import *
from .socket import *
from .utils import *

View File

@@ -0,0 +1,90 @@
void zmq_version(int *major, int *minor, int *patch);
void* zmq_socket(void *context, int type);
int zmq_close(void *socket);
int zmq_bind(void *socket, const char *endpoint);
int zmq_connect(void *socket, const char *endpoint);
int zmq_errno(void);
const char * zmq_strerror(int errnum);
int zmq_device(int device, void *frontend, void *backend);
int zmq_unbind(void *socket, const char *endpoint);
int zmq_disconnect(void *socket, const char *endpoint);
void* zmq_ctx_new();
int zmq_ctx_destroy(void *context);
int zmq_ctx_get(void *context, int opt);
int zmq_ctx_set(void *context, int opt, int optval);
int zmq_proxy(void *frontend, void *backend, void *capture);
int zmq_proxy_steerable(void *frontend,
void *backend,
void *capture,
void *control);
int zmq_socket_monitor(void *socket, const char *addr, int events);
int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key);
int zmq_curve_public (char *z85_public_key, char *z85_secret_key);
int zmq_has (const char *capability);
typedef struct { ...; } zmq_msg_t;
typedef ... zmq_free_fn;
int zmq_msg_init(zmq_msg_t *msg);
int zmq_msg_init_size(zmq_msg_t *msg, size_t size);
int zmq_msg_init_data(zmq_msg_t *msg,
void *data,
size_t size,
zmq_free_fn *ffn,
void *hint);
size_t zmq_msg_size(zmq_msg_t *msg);
void *zmq_msg_data(zmq_msg_t *msg);
int zmq_msg_close(zmq_msg_t *msg);
int zmq_msg_copy(zmq_msg_t *dst, zmq_msg_t *src);
int zmq_msg_send(zmq_msg_t *msg, void *socket, int flags);
int zmq_msg_recv(zmq_msg_t *msg, void *socket, int flags);
int zmq_getsockopt(void *socket,
int option_name,
void *option_value,
size_t *option_len);
int zmq_setsockopt(void *socket,
int option_name,
const void *option_value,
size_t option_len);
typedef int... ZMQ_FD_T;
typedef struct
{
void *socket;
ZMQ_FD_T fd;
short events;
short revents;
} zmq_pollitem_t;
int zmq_poll(zmq_pollitem_t *items, int nitems, long timeout);
// miscellany
void * memcpy(void *restrict s1, const void *restrict s2, size_t n);
void * malloc(size_t sz);
void free(void *p);
int get_ipc_path_max_len(void);
typedef struct _zhint {
void *sock;
void *mutex;
size_t id;
} zhint;
typedef ... mutex_t;
mutex_t* mutex_allocate();
int zmq_wrap_msg_init_data(zmq_msg_t *msg,
void *data,
size_t size,
void *hint);

View File

@@ -0,0 +1,92 @@
"""zmq poll function"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
try:
from time import monotonic
except ImportError:
from time import clock as monotonic
import warnings
from zmq.error import InterruptedSystemCall, _check_rc
from ._cffi import ffi
from ._cffi import lib as C
def _make_zmq_pollitem(socket, flags):
zmq_socket = socket._zmq_socket
zmq_pollitem = ffi.new('zmq_pollitem_t*')
zmq_pollitem.socket = zmq_socket
zmq_pollitem.fd = 0
zmq_pollitem.events = flags
zmq_pollitem.revents = 0
return zmq_pollitem[0]
def _make_zmq_pollitem_fromfd(socket_fd, flags):
zmq_pollitem = ffi.new('zmq_pollitem_t*')
zmq_pollitem.socket = ffi.NULL
zmq_pollitem.fd = socket_fd
zmq_pollitem.events = flags
zmq_pollitem.revents = 0
return zmq_pollitem[0]
def zmq_poll(sockets, timeout):
cffi_pollitem_list = []
low_level_to_socket_obj = {}
from zmq import Socket
for item in sockets:
if isinstance(item[0], Socket):
low_level_to_socket_obj[item[0]._zmq_socket] = item
cffi_pollitem_list.append(_make_zmq_pollitem(item[0], item[1]))
else:
if not isinstance(item[0], int):
# not an FD, get it from fileno()
item = (item[0].fileno(), item[1])
low_level_to_socket_obj[item[0]] = item
cffi_pollitem_list.append(_make_zmq_pollitem_fromfd(item[0], item[1]))
items = ffi.new('zmq_pollitem_t[]', cffi_pollitem_list)
list_length = ffi.cast('int', len(cffi_pollitem_list))
while True:
c_timeout = ffi.cast('long', timeout)
start = monotonic()
rc = C.zmq_poll(items, list_length, c_timeout)
try:
_check_rc(rc)
except InterruptedSystemCall:
if timeout > 0:
ms_passed = int(1000 * (monotonic() - start))
if ms_passed < 0:
# don't allow negative ms_passed,
# which can happen on old Python versions without time.monotonic.
warnings.warn(
"Negative elapsed time for interrupted poll: %s."
" Did the clock change?" % ms_passed,
RuntimeWarning,
)
ms_passed = 0
timeout = max(0, timeout - ms_passed)
continue
else:
break
result = []
for index in range(len(items)):
if items[index].revents > 0:
if not items[index].socket == ffi.NULL:
result.append(
(
low_level_to_socket_obj[items[index].socket][0],
items[index].revents,
)
)
else:
result.append((items[index].fd, items[index].revents))
return result
__all__ = ['zmq_poll']

View File

@@ -0,0 +1,78 @@
"""zmq Context class"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from zmq.constants import EINVAL, IO_THREADS
from zmq.error import InterruptedSystemCall, ZMQError, _check_rc
from ._cffi import ffi
from ._cffi import lib as C
class Context:
_zmq_ctx = None
_iothreads = None
_closed = None
_shadow = False
def __init__(self, io_threads=1, shadow=None):
if shadow:
self._zmq_ctx = ffi.cast("void *", shadow)
self._shadow = True
else:
self._shadow = False
if not io_threads >= 0:
raise ZMQError(EINVAL)
self._zmq_ctx = C.zmq_ctx_new()
if self._zmq_ctx == ffi.NULL:
raise ZMQError(C.zmq_errno())
if not shadow:
C.zmq_ctx_set(self._zmq_ctx, IO_THREADS, io_threads)
self._closed = False
@property
def underlying(self):
"""The address of the underlying libzmq context"""
return int(ffi.cast('size_t', self._zmq_ctx))
@property
def closed(self):
return self._closed
def set(self, option, value):
"""set a context option
see zmq_ctx_set
"""
rc = C.zmq_ctx_set(self._zmq_ctx, option, value)
_check_rc(rc)
def get(self, option):
"""get context option
see zmq_ctx_get
"""
rc = C.zmq_ctx_get(self._zmq_ctx, option)
_check_rc(rc, error_without_errno=False)
return rc
def term(self):
if self.closed:
return
rc = C.zmq_ctx_destroy(self._zmq_ctx)
try:
_check_rc(rc)
except InterruptedSystemCall:
# ignore interrupted term
# see PEP 475 notes about close & EINTR for why
pass
self._zmq_ctx = None
self._closed = True
__all__ = ['Context']

View File

@@ -0,0 +1,63 @@
"""zmq device functions"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from ._cffi import ffi
from ._cffi import lib as C
from .socket import Socket
from .utils import _retry_sys_call
def device(device_type, frontend, backend):
return proxy(frontend, backend)
def proxy(frontend, backend, capture=None):
if isinstance(capture, Socket):
capture = capture._zmq_socket
else:
capture = ffi.NULL
_retry_sys_call(C.zmq_proxy, frontend._zmq_socket, backend._zmq_socket, capture)
def proxy_steerable(frontend, backend, capture=None, control=None):
"""proxy_steerable(frontend, backend, capture, control)
Start a zeromq proxy with control flow.
.. versionadded:: libzmq-4.1
.. versionadded:: 18.0
Parameters
----------
frontend : Socket
The Socket instance for the incoming traffic.
backend : Socket
The Socket instance for the outbound traffic.
capture : Socket (optional)
The Socket instance for capturing traffic.
control : Socket (optional)
The Socket instance for control flow.
"""
if isinstance(capture, Socket):
capture = capture._zmq_socket
else:
capture = ffi.NULL
if isinstance(control, Socket):
control = control._zmq_socket
else:
control = ffi.NULL
_retry_sys_call(
C.zmq_proxy_steerable,
frontend._zmq_socket,
backend._zmq_socket,
capture,
control,
)
__all__ = ['device', 'proxy', 'proxy_steerable']

View File

@@ -0,0 +1,20 @@
"""zmq error functions"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from ._cffi import ffi
from ._cffi import lib as C
def strerror(errno):
s = ffi.string(C.zmq_strerror(errno))
if not isinstance(s, str):
# py3
s = s.decode()
return s
zmq_errno = C.zmq_errno
__all__ = ['strerror', 'zmq_errno']

View File

@@ -0,0 +1,225 @@
"""Dummy Frame object"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import errno
from threading import Event
import zmq
import zmq.error
from zmq.constants import ETERM
from ._cffi import ffi
from ._cffi import lib as C
zmq_gc = None
try:
from __pypy__.bufferable import bufferable as maybe_bufferable
except ImportError:
maybe_bufferable = object
def _content(obj):
"""Return content of obj as bytes"""
if type(obj) is bytes:
return obj
if not isinstance(obj, memoryview):
obj = memoryview(obj)
return obj.tobytes()
def _check_rc(rc):
err = C.zmq_errno()
if rc == -1:
if err == errno.EINTR:
raise zmq.error.InterrruptedSystemCall(err)
elif err == errno.EAGAIN:
raise zmq.error.Again(errno)
elif err == ETERM:
raise zmq.error.ContextTerminated(err)
else:
raise zmq.error.ZMQError(err)
return 0
class Frame(maybe_bufferable):
_data = None
tracker = None
closed = False
more = False
_buffer = None
_bytes = None
_failed_init = False
tracker_event = None
zmq_msg = None
def __init__(self, data=None, track=False, copy=None, copy_threshold=None):
self._failed_init = True
self.zmq_msg = ffi.cast('zmq_msg_t[1]', C.malloc(ffi.sizeof("zmq_msg_t")))
# self.tracker should start finished
# except in the case where we are sharing memory with libzmq
if track:
self.tracker = zmq._FINISHED_TRACKER
if isinstance(data, str):
raise TypeError(
"Unicode strings are not allowed. Only: bytes, buffer interfaces."
)
if data is None:
rc = C.zmq_msg_init(self.zmq_msg)
_check_rc(rc)
self._failed_init = False
return
self._data = data
if type(data) is bytes:
# avoid unnecessary copy on .bytes access
self._bytes = data
self._buffer = memoryview(data)
c_data = ffi.from_buffer(self._buffer)
data_len_c = self._buffer.nbytes
if copy is None:
if copy_threshold and data_len_c < copy_threshold:
copy = True
else:
copy = False
if copy:
# copy message data instead of sharing memory
rc = C.zmq_msg_init_size(self.zmq_msg, data_len_c)
_check_rc(rc)
ffi.buffer(C.zmq_msg_data(self.zmq_msg), data_len_c)[:] = self._buffer
self._failed_init = False
return
# Getting here means that we are doing a true zero-copy Frame,
# where libzmq and Python are sharing memory.
# Hook up garbage collection with MessageTracker and zmq_free_fn
# Event and MessageTracker for monitoring when zmq is done with data:
if track:
evt = Event()
self.tracker_event = evt
self.tracker = zmq.MessageTracker(evt)
# create the hint for zmq_free_fn
# two pointers: the zmq_gc context and a message to be sent to the zmq_gc PULL socket
# allows libzmq to signal to Python when it is done with Python-owned memory.
global zmq_gc
if zmq_gc is None:
from zmq.utils.garbage import gc as zmq_gc
# can't use ffi.new because it will be freed at the wrong time!
hint = ffi.cast("zhint[1]", C.malloc(ffi.sizeof("zhint")))
hint[0].id = zmq_gc.store(data, self.tracker_event)
if not zmq_gc._push_mutex:
zmq_gc._push_mutex = C.mutex_allocate()
hint[0].mutex = ffi.cast("mutex_t*", zmq_gc._push_mutex)
hint[0].sock = ffi.cast("void*", zmq_gc._push_socket.underlying)
# calls zmq_wrap_msg_init_data with the C.free_python_msg callback
rc = C.zmq_wrap_msg_init_data(
self.zmq_msg,
c_data,
data_len_c,
hint,
)
if rc != 0:
C.free(hint)
C.free(self.zmq_msg)
_check_rc(rc)
self._failed_init = False
def __del__(self):
if not self.closed and not self._failed_init:
self.close()
def close(self):
if self.closed or self._failed_init or self.zmq_msg is None:
return
self.closed = True
rc = C.zmq_msg_close(self.zmq_msg)
C.free(self.zmq_msg)
self.zmq_msg = None
if rc != 0:
_check_rc(rc)
def _buffer_from_zmq_msg(self):
"""one-time extract buffer from zmq_msg
for Frames created by recv
"""
if self._data is None:
self._data = ffi.buffer(
C.zmq_msg_data(self.zmq_msg), C.zmq_msg_size(self.zmq_msg)
)
if self._buffer is None:
self._buffer = memoryview(self._data)
@property
def buffer(self):
if self._buffer is None:
self._buffer_from_zmq_msg()
return self._buffer
@property
def bytes(self):
if self._bytes is None:
self._bytes = self.buffer.tobytes()
return self._bytes
def __len__(self):
return self.buffer.nbytes
def __eq__(self, other):
return self.bytes == _content(other)
def __str__(self):
return self.bytes.decode()
@property
def done(self):
return self.tracker.done()
def __buffer__(self, flags):
return self.buffer
def __copy__(self):
"""Create a shallow copy of the message.
This does not copy the contents of the Frame, just the pointer.
This will increment the 0MQ ref count of the message, but not
the ref count of the Python object. That is only done once when
the Python is first turned into a 0MQ message.
"""
return self.fast_copy()
def fast_copy(self):
"""Fast shallow copy of the Frame.
Does not copy underlying data.
"""
new_msg = Frame()
# This does not copy the contents, but just increases the ref-count
# of the zmq_msg by one.
C.zmq_msg_copy(new_msg.zmq_msg, self.zmq_msg)
# Copy the ref to underlying data
new_msg._data = self._data
new_msg._buffer = self._buffer
# Frame copies share the tracker and tracker_event
new_msg.tracker_event = self.tracker_event
new_msg.tracker = self.tracker
return new_msg
Message = Frame
__all__ = ['Frame', 'Message']

View File

@@ -0,0 +1,351 @@
"""zmq Socket class"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import errno as errno_mod
from ._cffi import ffi
from ._cffi import lib as C
nsp = new_sizet_pointer = lambda length: ffi.new('size_t*', length)
new_uint64_pointer = lambda: (ffi.new('uint64_t*'), nsp(ffi.sizeof('uint64_t')))
new_int64_pointer = lambda: (ffi.new('int64_t*'), nsp(ffi.sizeof('int64_t')))
new_int_pointer = lambda: (ffi.new('int*'), nsp(ffi.sizeof('int')))
new_binary_data = lambda length: (
ffi.new('char[%d]' % (length)),
nsp(ffi.sizeof('char') * length),
)
value_uint64_pointer = lambda val: (ffi.new('uint64_t*', val), ffi.sizeof('uint64_t'))
value_int64_pointer = lambda val: (ffi.new('int64_t*', val), ffi.sizeof('int64_t'))
value_int_pointer = lambda val: (ffi.new('int*', val), ffi.sizeof('int'))
value_binary_data = lambda val, length: (
ffi.new('char[%d]' % (length + 1), val),
ffi.sizeof('char') * length,
)
ZMQ_FD_64BIT = ffi.sizeof('ZMQ_FD_T') == 8
IPC_PATH_MAX_LEN = C.get_ipc_path_max_len()
import zmq
from zmq.constants import SocketOption, _OptType
from zmq.error import ZMQError, _check_rc, _check_version
from .message import Frame
from .utils import _retry_sys_call
def new_pointer_from_opt(option, length=0):
opt_type = getattr(option, "_opt_type", _OptType.int)
if opt_type == _OptType.int64 or (ZMQ_FD_64BIT and opt_type == _OptType.fd):
return new_int64_pointer()
elif opt_type == _OptType.bytes:
return new_binary_data(length)
else:
# default
return new_int_pointer()
def value_from_opt_pointer(option, opt_pointer, length=0):
try:
option = SocketOption(option)
except ValueError:
# unrecognized option,
# assume from the future,
# let EINVAL raise
opt_type = _OptType.int
else:
opt_type = option._opt_type
if opt_type == _OptType.bytes:
return ffi.buffer(opt_pointer, length)[:]
else:
return int(opt_pointer[0])
def initialize_opt_pointer(option, value, length=0):
opt_type = getattr(option, "_opt_type", _OptType.int)
if opt_type == _OptType.int64 or (ZMQ_FD_64BIT and opt_type == _OptType.fd):
return value_int64_pointer(value)
elif opt_type == _OptType.bytes:
return value_binary_data(value, length)
else:
return value_int_pointer(value)
class Socket:
context = None
socket_type = None
_zmq_socket = None
_closed = None
_ref = None
_shadow = False
copy_threshold = 0
def __init__(self, context=None, socket_type=None, shadow=None):
self.context = context
if shadow is not None:
if isinstance(shadow, Socket):
shadow = shadow.underlying
self._zmq_socket = ffi.cast("void *", shadow)
self._shadow = True
else:
self._shadow = False
self._zmq_socket = C.zmq_socket(context._zmq_ctx, socket_type)
if self._zmq_socket == ffi.NULL:
raise ZMQError()
self._closed = False
@property
def underlying(self):
"""The address of the underlying libzmq socket"""
return int(ffi.cast('size_t', self._zmq_socket))
def _check_closed_deep(self):
"""thorough check of whether the socket has been closed,
even if by another entity (e.g. ctx.destroy).
Only used by the `closed` property.
returns True if closed, False otherwise
"""
if self._closed:
return True
try:
self.get(zmq.TYPE)
except ZMQError as e:
if e.errno == zmq.ENOTSOCK:
self._closed = True
return True
else:
raise
return False
@property
def closed(self):
return self._check_closed_deep()
def close(self, linger=None):
rc = 0
if not self._closed and hasattr(self, '_zmq_socket'):
if self._zmq_socket is not None:
if linger is not None:
self.set(zmq.LINGER, linger)
rc = C.zmq_close(self._zmq_socket)
self._closed = True
if rc < 0:
_check_rc(rc)
def bind(self, address):
if isinstance(address, str):
address_b = address.encode('utf8')
else:
address_b = address
if isinstance(address, bytes):
address = address_b.decode('utf8')
rc = C.zmq_bind(self._zmq_socket, address_b)
if rc < 0:
if IPC_PATH_MAX_LEN and C.zmq_errno() == errno_mod.ENAMETOOLONG:
path = address.split('://', 1)[-1]
msg = (
'ipc path "{}" is longer than {} '
'characters (sizeof(sockaddr_un.sun_path)).'.format(
path, IPC_PATH_MAX_LEN
)
)
raise ZMQError(C.zmq_errno(), msg=msg)
elif C.zmq_errno() == errno_mod.ENOENT:
path = address.split('://', 1)[-1]
msg = f'No such file or directory for ipc path "{path}".'
raise ZMQError(C.zmq_errno(), msg=msg)
else:
_check_rc(rc)
def unbind(self, address):
_check_version((3, 2), "unbind")
if isinstance(address, str):
address = address.encode('utf8')
rc = C.zmq_unbind(self._zmq_socket, address)
_check_rc(rc)
def connect(self, address):
if isinstance(address, str):
address = address.encode('utf8')
rc = C.zmq_connect(self._zmq_socket, address)
_check_rc(rc)
def disconnect(self, address):
_check_version((3, 2), "disconnect")
if isinstance(address, str):
address = address.encode('utf8')
rc = C.zmq_disconnect(self._zmq_socket, address)
_check_rc(rc)
def set(self, option, value):
length = None
if isinstance(value, str):
raise TypeError("unicode not allowed, use bytes")
try:
option = SocketOption(option)
except ValueError:
# unrecognized option,
# assume from the future,
# let EINVAL raise
opt_type = _OptType.int
else:
opt_type = option._opt_type
if isinstance(value, bytes):
if opt_type != _OptType.bytes:
raise TypeError("not a bytes sockopt: %s" % option)
length = len(value)
c_value_pointer, c_sizet = initialize_opt_pointer(option, value, length)
_retry_sys_call(
C.zmq_setsockopt,
self._zmq_socket,
option,
ffi.cast('void*', c_value_pointer),
c_sizet,
)
def get(self, option):
try:
option = SocketOption(option)
except ValueError:
# unrecognized option,
# assume from the future,
# let EINVAL raise
opt_type = _OptType.int
else:
opt_type = option._opt_type
c_value_pointer, c_sizet_pointer = new_pointer_from_opt(option, length=255)
_retry_sys_call(
C.zmq_getsockopt, self._zmq_socket, option, c_value_pointer, c_sizet_pointer
)
sz = c_sizet_pointer[0]
v = value_from_opt_pointer(option, c_value_pointer, sz)
if (
option != zmq.SocketOption.ROUTING_ID
and opt_type == _OptType.bytes
and v.endswith(b'\0')
):
v = v[:-1]
return v
def _send_copy(self, buf, flags):
"""Send a copy of a bufferable"""
zmq_msg = ffi.new('zmq_msg_t*')
if not isinstance(buf, bytes):
# cast any bufferable data to bytes via memoryview
buf = memoryview(buf).tobytes()
c_message = ffi.new('char[]', buf)
rc = C.zmq_msg_init_size(zmq_msg, len(buf))
_check_rc(rc)
C.memcpy(C.zmq_msg_data(zmq_msg), c_message, len(buf))
_retry_sys_call(C.zmq_msg_send, zmq_msg, self._zmq_socket, flags)
rc2 = C.zmq_msg_close(zmq_msg)
_check_rc(rc2)
def _send_frame(self, frame, flags):
"""Send a Frame on this socket in a non-copy manner."""
# Always copy the Frame so the original message isn't garbage collected.
# This doesn't do a real copy, just a reference.
frame_copy = frame.fast_copy()
zmq_msg = frame_copy.zmq_msg
_retry_sys_call(C.zmq_msg_send, zmq_msg, self._zmq_socket, flags)
tracker = frame_copy.tracker
frame_copy.close()
return tracker
def send(self, data, flags=0, copy=False, track=False):
if isinstance(data, str):
raise TypeError("Message must be in bytes, not a unicode object")
if copy and not isinstance(data, Frame):
return self._send_copy(data, flags)
else:
close_frame = False
if isinstance(data, Frame):
if track and not data.tracker:
raise ValueError('Not a tracked message')
frame = data
else:
if self.copy_threshold:
buf = memoryview(data)
# always copy messages smaller than copy_threshold
if buf.nbytes < self.copy_threshold:
self._send_copy(buf, flags)
return zmq._FINISHED_TRACKER
frame = Frame(data, track=track, copy_threshold=self.copy_threshold)
close_frame = True
tracker = self._send_frame(frame, flags)
if close_frame:
frame.close()
return tracker
def recv(self, flags=0, copy=True, track=False):
if copy:
zmq_msg = ffi.new('zmq_msg_t*')
C.zmq_msg_init(zmq_msg)
else:
frame = zmq.Frame(track=track)
zmq_msg = frame.zmq_msg
try:
_retry_sys_call(C.zmq_msg_recv, zmq_msg, self._zmq_socket, flags)
except Exception:
if copy:
C.zmq_msg_close(zmq_msg)
raise
if not copy:
return frame
_buffer = ffi.buffer(C.zmq_msg_data(zmq_msg), C.zmq_msg_size(zmq_msg))
_bytes = _buffer[:]
rc = C.zmq_msg_close(zmq_msg)
_check_rc(rc)
return _bytes
def monitor(self, addr, events=-1):
"""s.monitor(addr, flags)
Start publishing socket events on inproc.
See libzmq docs for zmq_monitor for details.
Note: requires libzmq >= 3.2
Parameters
----------
addr : str
The inproc url used for monitoring. Passing None as
the addr will cause an existing socket monitor to be
deregistered.
events : int [default: zmq.EVENT_ALL]
The zmq event bitmask for which events will be sent to the monitor.
"""
_check_version((3, 2), "monitor")
if events < 0:
events = zmq.EVENT_ALL
if addr is None:
addr = ffi.NULL
if isinstance(addr, str):
addr = addr.encode('utf8')
C.zmq_socket_monitor(self._zmq_socket, addr, events)
__all__ = ['Socket', 'IPC_PATH_MAX_LEN']

View File

@@ -0,0 +1,78 @@
"""miscellaneous zmq_utils wrapping"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from zmq.error import InterruptedSystemCall, _check_rc, _check_version
from ._cffi import ffi
from ._cffi import lib as C
def has(capability):
"""Check for zmq capability by name (e.g. 'ipc', 'curve')
.. versionadded:: libzmq-4.1
.. versionadded:: 14.1
"""
_check_version((4, 1), 'zmq.has')
if isinstance(capability, str):
capability = capability.encode('utf8')
return bool(C.zmq_has(capability))
def curve_keypair():
"""generate a Z85 keypair for use with zmq.CURVE security
Requires libzmq (≥ 4.0) to have been built with CURVE support.
Returns
-------
(public, secret) : two bytestrings
The public and private keypair as 40 byte z85-encoded bytestrings.
"""
_check_version((3, 2), "curve_keypair")
public = ffi.new('char[64]')
private = ffi.new('char[64]')
rc = C.zmq_curve_keypair(public, private)
_check_rc(rc)
return ffi.buffer(public)[:40], ffi.buffer(private)[:40]
def curve_public(private):
"""Compute the public key corresponding to a private key for use
with zmq.CURVE security
Requires libzmq (≥ 4.2) to have been built with CURVE support.
Parameters
----------
private
The private key as a 40 byte z85-encoded bytestring
Returns
-------
bytestring
The public key as a 40 byte z85-encoded bytestring.
"""
if isinstance(private, str):
private = private.encode('utf8')
_check_version((4, 2), "curve_public")
public = ffi.new('char[64]')
rc = C.zmq_curve_public(public, private)
_check_rc(rc)
return ffi.buffer(public)[:40]
def _retry_sys_call(f, *args, **kwargs):
"""make a call, retrying if interrupted with EINTR"""
while True:
rc = f(*args)
try:
_check_rc(rc)
except InterruptedSystemCall:
continue
else:
break
__all__ = ['has', 'curve_keypair', 'curve_public']

View File

@@ -0,0 +1,3 @@
from zmq.backend.cython.context cimport Context
from zmq.backend.cython.message cimport Frame
from zmq.backend.cython.socket cimport Socket

View File

@@ -0,0 +1,40 @@
"""Python bindings for core 0MQ objects."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Lesser GNU Public License (LGPL).
from . import (
_device,
_poll,
_proxy_steerable,
_version,
context,
error,
message,
socket,
utils,
)
__all__ = []
for submod in (
error,
message,
context,
socket,
utils,
_poll,
_version,
_device,
_proxy_steerable,
):
__all__.extend(submod.__all__)
from ._device import * # noqa
from ._poll import * # noqa
from ._proxy_steerable import * # noqa
from ._version import * # noqa
from .context import * # noqa
from .error import * # noqa
from .message import * # noqa
from .socket import * # noqa
from .utils import * # noqa

View File

@@ -0,0 +1,29 @@
from cpython cimport PyErr_CheckSignals
from libc.errno cimport EAGAIN, EINTR
from .libzmq cimport ZMQ_ETERM, zmq_errno
cdef inline int _check_rc(int rc, bint error_without_errno=True) except -1:
"""internal utility for checking zmq return condition
and raising the appropriate Exception class
"""
cdef int errno = zmq_errno()
PyErr_CheckSignals()
if errno == 0 and not error_without_errno:
return 0
if rc == -1: # if rc < -1, it's a bug in libzmq. Should we warn?
if errno == EINTR:
from zmq.error import InterruptedSystemCall
raise InterruptedSystemCall(errno)
elif errno == EAGAIN:
from zmq.error import Again
raise Again(errno)
elif errno == ZMQ_ETERM:
from zmq.error import ContextTerminated
raise ContextTerminated(errno)
else:
from zmq.error import ZMQError
raise ZMQError(errno)
return 0

View File

@@ -0,0 +1,228 @@
cdef extern from "zmq.h" nogil:
enum: PYZMQ_DRAFT_API
enum: ZMQ_VERSION
enum: ZMQ_VERSION_MAJOR
enum: ZMQ_VERSION_MINOR
enum: ZMQ_VERSION_PATCH
enum: ZMQ_IO_THREADS
enum: ZMQ_MAX_SOCKETS
enum: ZMQ_SOCKET_LIMIT
enum: ZMQ_THREAD_PRIORITY
enum: ZMQ_THREAD_SCHED_POLICY
enum: ZMQ_MAX_MSGSZ
enum: ZMQ_MSG_T_SIZE
enum: ZMQ_THREAD_AFFINITY_CPU_ADD
enum: ZMQ_THREAD_AFFINITY_CPU_REMOVE
enum: ZMQ_THREAD_NAME_PREFIX
enum: ZMQ_STREAMER
enum: ZMQ_FORWARDER
enum: ZMQ_QUEUE
enum: ZMQ_EAGAIN "EAGAIN"
enum: ZMQ_EFAULT "EFAULT"
enum: ZMQ_EINVAL "EINVAL"
enum: ZMQ_ENOTSUP "ENOTSUP"
enum: ZMQ_EPROTONOSUPPORT "EPROTONOSUPPORT"
enum: ZMQ_ENOBUFS "ENOBUFS"
enum: ZMQ_ENETDOWN "ENETDOWN"
enum: ZMQ_EADDRINUSE "EADDRINUSE"
enum: ZMQ_EADDRNOTAVAIL "EADDRNOTAVAIL"
enum: ZMQ_ECONNREFUSED "ECONNREFUSED"
enum: ZMQ_EINPROGRESS "EINPROGRESS"
enum: ZMQ_ENOTSOCK "ENOTSOCK"
enum: ZMQ_EMSGSIZE "EMSGSIZE"
enum: ZMQ_EAFNOSUPPORT "EAFNOSUPPORT"
enum: ZMQ_ENETUNREACH "ENETUNREACH"
enum: ZMQ_ECONNABORTED "ECONNABORTED"
enum: ZMQ_ECONNRESET "ECONNRESET"
enum: ZMQ_ENOTCONN "ENOTCONN"
enum: ZMQ_ETIMEDOUT "ETIMEDOUT"
enum: ZMQ_EHOSTUNREACH "EHOSTUNREACH"
enum: ZMQ_ENETRESET "ENETRESET"
enum: ZMQ_EFSM "EFSM"
enum: ZMQ_ENOCOMPATPROTO "ENOCOMPATPROTO"
enum: ZMQ_ETERM "ETERM"
enum: ZMQ_EMTHREAD "EMTHREAD"
enum: ZMQ_EVENT_CONNECTED
enum: ZMQ_EVENT_CONNECT_DELAYED
enum: ZMQ_EVENT_CONNECT_RETRIED
enum: ZMQ_EVENT_LISTENING
enum: ZMQ_EVENT_BIND_FAILED
enum: ZMQ_EVENT_ACCEPTED
enum: ZMQ_EVENT_ACCEPT_FAILED
enum: ZMQ_EVENT_CLOSED
enum: ZMQ_EVENT_CLOSE_FAILED
enum: ZMQ_EVENT_DISCONNECTED
enum: ZMQ_EVENT_MONITOR_STOPPED
enum: ZMQ_EVENT_ALL
enum: ZMQ_HANDSHAKE_FAILED_NO_DETAIL
enum: ZMQ_HANDSHAKE_SUCCEEDED
enum: ZMQ_HANDSHAKE_FAILED_PROTOCOL
enum: ZMQ_HANDSHAKE_FAILED_AUTH
enum: ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED
enum: ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
enum: ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE
enum: ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE
enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED
enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO
enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE
enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR
enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY
enum: ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME
enum: ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA
enum: ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
enum: ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH
enum: ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED
enum: ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY
enum: ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID
enum: ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION
enum: ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE
enum: ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA
enum: ZMQ_PROTOCOL_ERROR_WS_UNSPECIFIED
enum: ZMQ_EVENT_PIPES_STATS
enum: ZMQ_EVENT_ALL_V1
enum: ZMQ_EVENT_ALL_V2
enum: ZMQ_DONTWAIT
enum: ZMQ_SNDMORE
enum: ZMQ_NOBLOCK
enum: ZMQ_MORE
enum: ZMQ_SHARED
enum: ZMQ_SRCFD
enum: ZMQ_POLLIN
enum: ZMQ_POLLOUT
enum: ZMQ_POLLERR
enum: ZMQ_POLLPRI
enum: ZMQ_NULL
enum: ZMQ_PLAIN
enum: ZMQ_CURVE
enum: ZMQ_GSSAPI
enum: ZMQ_HWM
enum: ZMQ_AFFINITY
enum: ZMQ_ROUTING_ID
enum: ZMQ_SUBSCRIBE
enum: ZMQ_UNSUBSCRIBE
enum: ZMQ_RATE
enum: ZMQ_RECOVERY_IVL
enum: ZMQ_SNDBUF
enum: ZMQ_RCVBUF
enum: ZMQ_RCVMORE
enum: ZMQ_FD
enum: ZMQ_EVENTS
enum: ZMQ_TYPE
enum: ZMQ_LINGER
enum: ZMQ_RECONNECT_IVL
enum: ZMQ_BACKLOG
enum: ZMQ_RECONNECT_IVL_MAX
enum: ZMQ_MAXMSGSIZE
enum: ZMQ_SNDHWM
enum: ZMQ_RCVHWM
enum: ZMQ_MULTICAST_HOPS
enum: ZMQ_RCVTIMEO
enum: ZMQ_SNDTIMEO
enum: ZMQ_LAST_ENDPOINT
enum: ZMQ_ROUTER_MANDATORY
enum: ZMQ_TCP_KEEPALIVE
enum: ZMQ_TCP_KEEPALIVE_CNT
enum: ZMQ_TCP_KEEPALIVE_IDLE
enum: ZMQ_TCP_KEEPALIVE_INTVL
enum: ZMQ_IMMEDIATE
enum: ZMQ_XPUB_VERBOSE
enum: ZMQ_ROUTER_RAW
enum: ZMQ_IPV6
enum: ZMQ_MECHANISM
enum: ZMQ_PLAIN_SERVER
enum: ZMQ_PLAIN_USERNAME
enum: ZMQ_PLAIN_PASSWORD
enum: ZMQ_CURVE_SERVER
enum: ZMQ_CURVE_PUBLICKEY
enum: ZMQ_CURVE_SECRETKEY
enum: ZMQ_CURVE_SERVERKEY
enum: ZMQ_PROBE_ROUTER
enum: ZMQ_REQ_CORRELATE
enum: ZMQ_REQ_RELAXED
enum: ZMQ_CONFLATE
enum: ZMQ_ZAP_DOMAIN
enum: ZMQ_ROUTER_HANDOVER
enum: ZMQ_TOS
enum: ZMQ_CONNECT_ROUTING_ID
enum: ZMQ_GSSAPI_SERVER
enum: ZMQ_GSSAPI_PRINCIPAL
enum: ZMQ_GSSAPI_SERVICE_PRINCIPAL
enum: ZMQ_GSSAPI_PLAINTEXT
enum: ZMQ_HANDSHAKE_IVL
enum: ZMQ_SOCKS_PROXY
enum: ZMQ_XPUB_NODROP
enum: ZMQ_BLOCKY
enum: ZMQ_XPUB_MANUAL
enum: ZMQ_XPUB_WELCOME_MSG
enum: ZMQ_STREAM_NOTIFY
enum: ZMQ_INVERT_MATCHING
enum: ZMQ_HEARTBEAT_IVL
enum: ZMQ_HEARTBEAT_TTL
enum: ZMQ_HEARTBEAT_TIMEOUT
enum: ZMQ_XPUB_VERBOSER
enum: ZMQ_CONNECT_TIMEOUT
enum: ZMQ_TCP_MAXRT
enum: ZMQ_THREAD_SAFE
enum: ZMQ_MULTICAST_MAXTPDU
enum: ZMQ_VMCI_BUFFER_SIZE
enum: ZMQ_VMCI_BUFFER_MIN_SIZE
enum: ZMQ_VMCI_BUFFER_MAX_SIZE
enum: ZMQ_VMCI_CONNECT_TIMEOUT
enum: ZMQ_USE_FD
enum: ZMQ_GSSAPI_PRINCIPAL_NAMETYPE
enum: ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE
enum: ZMQ_BINDTODEVICE
enum: ZMQ_IDENTITY
enum: ZMQ_CONNECT_RID
enum: ZMQ_TCP_ACCEPT_FILTER
enum: ZMQ_IPC_FILTER_PID
enum: ZMQ_IPC_FILTER_UID
enum: ZMQ_IPC_FILTER_GID
enum: ZMQ_IPV4ONLY
enum: ZMQ_DELAY_ATTACH_ON_CONNECT
enum: ZMQ_FAIL_UNROUTABLE
enum: ZMQ_ROUTER_BEHAVIOR
enum: ZMQ_ZAP_ENFORCE_DOMAIN
enum: ZMQ_LOOPBACK_FASTPATH
enum: ZMQ_METADATA
enum: ZMQ_MULTICAST_LOOP
enum: ZMQ_ROUTER_NOTIFY
enum: ZMQ_XPUB_MANUAL_LAST_VALUE
enum: ZMQ_SOCKS_USERNAME
enum: ZMQ_SOCKS_PASSWORD
enum: ZMQ_IN_BATCH_SIZE
enum: ZMQ_OUT_BATCH_SIZE
enum: ZMQ_WSS_KEY_PEM
enum: ZMQ_WSS_CERT_PEM
enum: ZMQ_WSS_TRUST_PEM
enum: ZMQ_WSS_HOSTNAME
enum: ZMQ_WSS_TRUST_SYSTEM
enum: ZMQ_ONLY_FIRST_SUBSCRIBE
enum: ZMQ_RECONNECT_STOP
enum: ZMQ_HELLO_MSG
enum: ZMQ_DISCONNECT_MSG
enum: ZMQ_PRIORITY
enum: ZMQ_PAIR
enum: ZMQ_PUB
enum: ZMQ_SUB
enum: ZMQ_REQ
enum: ZMQ_REP
enum: ZMQ_DEALER
enum: ZMQ_ROUTER
enum: ZMQ_PULL
enum: ZMQ_PUSH
enum: ZMQ_XPUB
enum: ZMQ_XSUB
enum: ZMQ_STREAM
enum: ZMQ_XREQ
enum: ZMQ_XREP
enum: ZMQ_SERVER
enum: ZMQ_CLIENT
enum: ZMQ_RADIO
enum: ZMQ_DISH
enum: ZMQ_GATHER
enum: ZMQ_SCATTER
enum: ZMQ_DGRAM
enum: ZMQ_PEER
enum: ZMQ_CHANNEL

View File

@@ -0,0 +1,34 @@
"""0MQ Context class declaration."""
#
# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
#
# This file is part of pyzmq.
#
# pyzmq is free software; you can redistribute it and/or modify it under
# the terms of the Lesser GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# pyzmq is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Lesser GNU General Public License for more details.
#
# You should have received a copy of the Lesser GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
cdef class Context:
cdef object __weakref__ # enable weakref
cdef void *handle # The C handle for the underlying zmq object.
cdef bint _shadow # whether the Context is a shadow wrapper of another
cdef int _pid # the pid of the process which created me (for fork safety)
cdef public bint closed # bool property for a closed context.
cdef inline int _term(self)

View File

@@ -0,0 +1,122 @@
"""All the C imports for 0MQ"""
#
# Copyright (c) 2010 Brian E. Granger & Min Ragan-Kelley
#
# This file is part of pyzmq.
#
# pyzmq is free software; you can redistribute it and/or modify it under
# the terms of the Lesser GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# pyzmq is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Lesser GNU General Public License for more details.
#
# You should have received a copy of the Lesser GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Import the C header files
#-----------------------------------------------------------------------------
# common includes, such as zmq compat, pyversion_compat
# make sure we load pyversion compat in every Cython module
cdef extern from "pyversion_compat.h":
pass
# were it not for Windows,
# we could cimport these from libc.stdint
cdef extern from "zmq_compat.h":
ctypedef signed long long int64_t "pyzmq_int64_t"
ctypedef unsigned int uint32_t "pyzmq_uint32_t"
include "constant_enums.pxi"
cdef extern from "zmq.h" nogil:
void _zmq_version "zmq_version"(int *major, int *minor, int *patch)
ctypedef int fd_t "ZMQ_FD_T"
enum: errno
const char *zmq_strerror (int errnum)
int zmq_errno()
void *zmq_ctx_new ()
int zmq_ctx_destroy (void *context)
int zmq_ctx_set (void *context, int option, int optval)
int zmq_ctx_get (void *context, int option)
void *zmq_init (int io_threads)
int zmq_term (void *context)
# blackbox def for zmq_msg_t
ctypedef void * zmq_msg_t "zmq_msg_t"
ctypedef void zmq_free_fn(void *data, void *hint)
int zmq_msg_init (zmq_msg_t *msg)
int zmq_msg_init_size (zmq_msg_t *msg, size_t size)
int zmq_msg_init_data (zmq_msg_t *msg, void *data,
size_t size, zmq_free_fn *ffn, void *hint)
int zmq_msg_send (zmq_msg_t *msg, void *s, int flags)
int zmq_msg_recv (zmq_msg_t *msg, void *s, int flags)
int zmq_msg_close (zmq_msg_t *msg)
int zmq_msg_move (zmq_msg_t *dest, zmq_msg_t *src)
int zmq_msg_copy (zmq_msg_t *dest, zmq_msg_t *src)
void *zmq_msg_data (zmq_msg_t *msg)
size_t zmq_msg_size (zmq_msg_t *msg)
int zmq_msg_more (zmq_msg_t *msg)
int zmq_msg_get (zmq_msg_t *msg, int option)
int zmq_msg_set (zmq_msg_t *msg, int option, int optval)
const char *zmq_msg_gets (zmq_msg_t *msg, const char *property)
int zmq_has (const char *capability)
void *zmq_socket (void *context, int type)
int zmq_close (void *s)
int zmq_setsockopt (void *s, int option, void *optval, size_t optvallen)
int zmq_getsockopt (void *s, int option, void *optval, size_t *optvallen)
int zmq_bind (void *s, char *addr)
int zmq_connect (void *s, char *addr)
int zmq_unbind (void *s, char *addr)
int zmq_disconnect (void *s, char *addr)
int zmq_socket_monitor (void *s, char *addr, int flags)
# send/recv
int zmq_sendbuf (void *s, const void *buf, size_t n, int flags)
int zmq_recvbuf (void *s, void *buf, size_t n, int flags)
ctypedef struct zmq_pollitem_t:
void *socket
fd_t fd
short events
short revents
int zmq_poll (zmq_pollitem_t *items, int nitems, long timeout)
int zmq_device (int device_, void *insocket_, void *outsocket_)
int zmq_proxy (void *frontend, void *backend, void *capture)
int zmq_proxy_steerable (void *frontend,
void *backend,
void *capture,
void *control)
int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key)
int zmq_curve_public (char *z85_public_key, char *z85_secret_key)
# 4.2 draft
int zmq_join (void *s, const char *group)
int zmq_leave (void *s, const char *group)
int zmq_msg_set_routing_id(zmq_msg_t *msg, uint32_t routing_id)
uint32_t zmq_msg_routing_id(zmq_msg_t *msg)
int zmq_msg_set_group(zmq_msg_t *msg, const char *group)
const char *zmq_msg_group(zmq_msg_t *msg)

View File

@@ -0,0 +1,61 @@
"""0MQ Message related class declarations."""
#
# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
#
# This file is part of pyzmq.
#
# pyzmq is free software; you can redistribute it and/or modify it under
# the terms of the Lesser GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# pyzmq is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Lesser GNU General Public License for more details.
#
# You should have received a copy of the Lesser GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from cpython cimport PyBytes_FromStringAndSize
from zmq.backend.cython.libzmq cimport zmq_msg_data, zmq_msg_size, zmq_msg_t
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
cdef class MessageTracker(object):
cdef set events # Message Event objects to track.
cdef set peers # Other Message or MessageTracker objects.
cdef class Frame:
cdef zmq_msg_t zmq_msg
cdef object _data # The actual message data as a Python object.
cdef object _buffer # A Python Buffer/View of the message contents
cdef object _bytes # A bytes/str copy of the message.
cdef bint _failed_init # Flag to handle failed zmq_msg_init
cdef public object tracker_event # Event for use with zmq_free_fn.
cdef public object tracker # MessageTracker object.
cdef public bint more # whether RCVMORE was set
cdef Frame fast_copy(self) # Create shallow copy of Message object.
cdef object _getbuffer(self) # Construct self._buffer.
cdef inline object copy_zmq_msg_bytes(zmq_msg_t *zmq_msg):
""" Copy the data from a zmq_msg_t """
cdef char *data_c = NULL
cdef Py_ssize_t data_len_c
data_c = <char *>zmq_msg_data(zmq_msg)
data_len_c = zmq_msg_size(zmq_msg)
return PyBytes_FromStringAndSize(data_c, data_len_c)

View File

@@ -0,0 +1,48 @@
"""0MQ Socket class declaration."""
#
# Copyright (c) 2010-2011 Brian E. Granger & Min Ragan-Kelley
#
# This file is part of pyzmq.
#
# pyzmq is free software; you can redistribute it and/or modify it under
# the terms of the Lesser GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# pyzmq is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# Lesser GNU General Public License for more details.
#
# You should have received a copy of the Lesser GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
from .context cimport Context
#-----------------------------------------------------------------------------
# Code
#-----------------------------------------------------------------------------
cdef class Socket:
cdef object __weakref__ # enable weakref
cdef void *handle # The C handle for the underlying zmq object.
cdef bint _shadow # whether the Socket is a shadow wrapper of another
# Hold on to a reference to the context to make sure it is not garbage
# collected until the socket it done with it.
cdef public Context context # The zmq Context object that owns this.
cdef public bint _closed # bool property for a closed socket.
cdef public int copy_threshold # threshold below which pyzmq will always copy messages
cdef int _pid # the pid of the process which created me (for fork safety)
cdef void _c_close(self) # underlying close of zmq socket
# cpdef methods for direct-cython access:
cpdef object send(self, object data, int flags=*, copy=*, track=*)
cpdef object recv(self, int flags=*, copy=*, track=*)

View File

@@ -0,0 +1,40 @@
"""Import basic exposure of libzmq C API as a backend"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from importlib import import_module
from typing import Dict
public_api = [
'Context',
'Socket',
'Frame',
'Message',
'device',
'proxy',
'proxy_steerable',
'zmq_poll',
'strerror',
'zmq_errno',
'has',
'curve_keypair',
'curve_public',
'zmq_version_info',
'IPC_PATH_MAX_LEN',
]
def select_backend(name: str) -> Dict:
"""Select the pyzmq backend"""
try:
mod = import_module(name)
except ImportError:
raise
except Exception as e:
raise ImportError(f"Importing {name} failed with {e}") from e
ns = {}
for key in public_api:
ns[key] = getattr(mod, key)
return ns