Uploaded Test files

This commit is contained in:
Batuhan Berk Başoğlu 2020-11-12 11:05:57 -05:00
parent f584ad9d97
commit 2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions

View file

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

View file

@ -0,0 +1,73 @@
"""Python bindings for 0MQ."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
# load bundled libzmq, if there is one:
def _load_libzmq():
"""load bundled libzmq if there is one"""
import sys, platform, os
dlopen = hasattr(sys, 'getdlopenflags') # unix-only
# RTLD flags are added to os in Python 3
# get values from os because ctypes values are WRONG on pypy
PYPY = platform.python_implementation().lower() == 'pypy'
if dlopen:
import ctypes
dlflags = sys.getdlopenflags()
# set RTLD_GLOBAL, unset RTLD_LOCAL
flags = ctypes.RTLD_GLOBAL | dlflags
# ctypes.RTLD_LOCAL is 0 on pypy, which is *wrong*
flags &= ~ getattr(os, 'RTLD_LOCAL', 4)
# pypy on darwin needs RTLD_LAZY for some reason
if PYPY and sys.platform == 'darwin':
flags |= getattr(os, 'RTLD_LAZY', 1)
flags &= ~ getattr(os, 'RTLD_NOW', 2)
sys.setdlopenflags(flags)
try:
from . import libzmq
except ImportError:
pass
else:
# store libzmq as zmq._libzmq for backward-compat
globals()['_libzmq'] = libzmq
if PYPY:
# should already have been imported above, so reimporting is as cheap as checking
import ctypes
# some versions of pypy (5.3 < ? < 5.8) needs explicit CDLL load for some reason,
# otherwise symbols won't be globally available
# do this unconditionally because it should be harmless (?)
ctypes.CDLL(libzmq.__file__, ctypes.RTLD_GLOBAL)
finally:
if dlopen:
sys.setdlopenflags(dlflags)
_load_libzmq()
# zmq top-level imports
from zmq import backend
from zmq.backend import *
from zmq import sugar
from zmq.sugar import *
def get_includes():
"""Return a list of directories to include for linking against pyzmq with cython."""
from os.path import join, dirname, abspath, pardir, exists
base = dirname(__file__)
parent = abspath(join(base, pardir))
includes = [ parent ] + [ join(parent, base, subdir) for subdir in ('utils',) ]
if exists(join(parent, base, 'include')):
includes.append(join(parent, base, 'include'))
return includes
def get_library_dirs():
"""Return a list of directories used to link against pyzmq's bundled libzmq."""
from os.path import join, dirname, abspath, pardir
base = dirname(__file__)
parent = abspath(join(base, pardir))
return [ join(parent, base) ]
COPY_THRESHOLD = 65536
__all__ = ['get_includes', 'COPY_THRESHOLD'] + sugar.__all__ + backend.__all__

View file

@ -0,0 +1,545 @@
"""Future-returning APIs for coroutines."""
# Copyright (c) PyZMQ Developers.
# Distributed under the terms of the Modified BSD License.
from collections import namedtuple, deque
from itertools import chain
from zmq import EVENTS, POLLOUT, POLLIN
import zmq as _zmq
_FutureEvent = namedtuple('_FutureEvent', ('future', 'kind', 'kwargs', 'msg'))
# These are incomplete classes and need a Mixin for compatibility with an eventloop
# defining the followig attributes:
#
# _Future
# _READ
# _WRITE
# _default_loop()
class _AsyncPoller(_zmq.Poller):
"""Poller that returns a Future on poll, instead of blocking."""
def poll(self, timeout=-1):
"""Return a Future for a poll event"""
future = self._Future()
if timeout == 0:
try:
result = super(_AsyncPoller, self).poll(0)
except Exception as e:
future.set_exception(e)
else:
future.set_result(result)
return future
loop = self._default_loop()
# register Future to be called as soon as any event is available on any socket
watcher = self._Future()
# watch raw sockets:
raw_sockets = []
def wake_raw(*args):
if not watcher.done():
watcher.set_result(None)
watcher.add_done_callback(lambda f: self._unwatch_raw_sockets(loop, *raw_sockets))
for socket, mask in self.sockets:
if isinstance(socket, _zmq.Socket):
if not isinstance(socket, self._socket_class):
# it's a blocking zmq.Socket, wrap it in async
socket = self._socket_class.from_socket(socket)
if mask & _zmq.POLLIN:
socket._add_recv_event('poll', future=watcher)
if mask & _zmq.POLLOUT:
socket._add_send_event('poll', future=watcher)
else:
raw_sockets.append(socket)
evt = 0
if mask & _zmq.POLLIN:
evt |= self._READ
if mask & _zmq.POLLOUT:
evt |= self._WRITE
self._watch_raw_socket(loop, socket, evt, wake_raw)
def on_poll_ready(f):
if future.done():
return
if watcher.cancelled():
try:
future.cancel()
except RuntimeError:
# RuntimeError may be called during teardown
pass
return
if watcher.exception():
future.set_exception(watcher.exception())
else:
try:
result = super(_AsyncPoller, self).poll(0)
except Exception as e:
future.set_exception(e)
else:
future.set_result(result)
watcher.add_done_callback(on_poll_ready)
if timeout is not None and timeout > 0:
# schedule cancel to fire on poll timeout, if any
def trigger_timeout():
if not watcher.done():
watcher.set_result(None)
timeout_handle = loop.call_later(
1e-3 * timeout,
trigger_timeout
)
def cancel_timeout(f):
if hasattr(timeout_handle, 'cancel'):
timeout_handle.cancel()
else:
loop.remove_timeout(timeout_handle)
future.add_done_callback(cancel_timeout)
def cancel_watcher(f):
if not watcher.done():
watcher.cancel()
future.add_done_callback(cancel_watcher)
return future
class _AsyncSocket(_zmq.Socket):
# Warning : these class variables are only here to allow to call super().__setattr__.
# They be overridden at instance initialization and not shared in the whole class
_recv_futures = None
_send_futures = None
_state = 0
_shadow_sock = None
_poller_class = _AsyncPoller
io_loop = None
_fd = None
def __init__(self, context=None, socket_type=-1, io_loop=None, **kwargs):
if isinstance(context, _zmq.Socket):
context, from_socket = (None, context)
else:
from_socket = kwargs.pop('_from_socket', None)
if from_socket is not None:
super(_AsyncSocket, self).__init__(shadow=from_socket.underlying)
self._shadow_sock = from_socket
else:
super(_AsyncSocket, self).__init__(context, socket_type, **kwargs)
self._shadow_sock = _zmq.Socket.shadow(self.underlying)
self.io_loop = io_loop or self._default_loop()
self._recv_futures = deque()
self._send_futures = deque()
self._state = 0
self._fd = self._shadow_sock.FD
self._init_io_state()
@classmethod
def from_socket(cls, socket, io_loop=None):
"""Create an async socket from an existing Socket"""
return cls(_from_socket=socket, io_loop=io_loop)
def close(self, linger=None):
if not self.closed:
for event in list(chain(self._recv_futures, self._send_futures)):
if not event.future.done():
try:
event.future.cancel()
except RuntimeError:
# RuntimeError may be called during teardown
pass
self._clear_io_state()
super(_AsyncSocket, self).close(linger=linger)
close.__doc__ = _zmq.Socket.close.__doc__
def get(self, key):
result = super(_AsyncSocket, self).get(key)
if key == EVENTS:
self._schedule_remaining_events(result)
return result
get.__doc__ = _zmq.Socket.get.__doc__
def recv_multipart(self, flags=0, copy=True, track=False):
"""Receive a complete multipart zmq message.
Returns a Future whose result will be a multipart message.
"""
return self._add_recv_event('recv_multipart',
dict(flags=flags, copy=copy, track=track)
)
def recv(self, flags=0, copy=True, track=False):
"""Receive a single zmq frame.
Returns a Future, whose result will be the received frame.
Recommend using recv_multipart instead.
"""
return self._add_recv_event('recv',
dict(flags=flags, copy=copy, track=track)
)
def send_multipart(self, msg, flags=0, copy=True, track=False, **kwargs):
"""Send a complete multipart zmq message.
Returns a Future that resolves when sending is complete.
"""
kwargs['flags'] = flags
kwargs['copy'] = copy
kwargs['track'] = track
return self._add_send_event('send_multipart', msg=msg, kwargs=kwargs)
def send(self, msg, flags=0, copy=True, track=False, **kwargs):
"""Send a single zmq frame.
Returns a Future that resolves when sending is complete.
Recommend using send_multipart instead.
"""
kwargs['flags'] = flags
kwargs['copy'] = copy
kwargs['track'] = track
kwargs.update(dict(flags=flags, copy=copy, track=track))
return self._add_send_event('send', msg=msg, kwargs=kwargs)
def _deserialize(self, recvd, load):
"""Deserialize with Futures"""
f = self._Future()
def _chain(_):
"""Chain result through serialization to recvd"""
if f.done():
return
if recvd.exception():
f.set_exception(recvd.exception())
else:
buf = recvd.result()
try:
loaded = load(buf)
except Exception as e:
f.set_exception(e)
else:
f.set_result(loaded)
recvd.add_done_callback(_chain)
def _chain_cancel(_):
"""Chain cancellation from f to recvd"""
if recvd.done():
return
if f.cancelled():
recvd.cancel()
f.add_done_callback(_chain_cancel)
return f
def poll(self, timeout=None, flags=_zmq.POLLIN):
"""poll the socket for events
returns a Future for the poll results.
"""
if self.closed:
raise _zmq.ZMQError(_zmq.ENOTSUP)
p = self._poller_class()
p.register(self, flags)
f = p.poll(timeout)
future = self._Future()
def unwrap_result(f):
if future.done():
return
if f.cancelled():
try:
future.cancel()
except RuntimeError:
# RuntimeError may be called during teardown
pass
return
if f.exception():
future.set_exception(f.exception())
else:
evts = dict(f.result())
future.set_result(evts.get(self, 0))
if f.done():
# hook up result if
unwrap_result(f)
else:
f.add_done_callback(unwrap_result)
return future
def _add_timeout(self, future, timeout):
"""Add a timeout for a send or recv Future"""
def future_timeout():
if future.done():
# future already resolved, do nothing
return
# raise EAGAIN
future.set_exception(_zmq.Again())
self._call_later(timeout, future_timeout)
def _call_later(self, delay, callback):
"""Schedule a function to be called later
Override for different IOLoop implementations
Tornado and asyncio happen to both have ioloop.call_later
with the same signature.
"""
self.io_loop.call_later(delay, callback)
@staticmethod
def _remove_finished_future(future, event_list):
"""Make sure that futures are removed from the event list when they resolve
Avoids delaying cleanup until the next send/recv event,
which may never come.
"""
for f_idx, (f, kind, kwargs, _) in enumerate(event_list):
if f is future:
break
else:
return
# "future" instance is shared between sockets, but each socket has its own event list.
event_list.remove(event_list[f_idx])
def _add_recv_event(self, kind, kwargs=None, future=None):
"""Add a recv event, returning the corresponding Future"""
f = future or self._Future()
if kind.startswith('recv') and kwargs.get('flags', 0) & _zmq.DONTWAIT:
# short-circuit non-blocking calls
recv = getattr(self._shadow_sock, kind)
try:
r = recv(**kwargs)
except Exception as e:
f.set_exception(e)
else:
f.set_result(r)
return f
# we add it to the list of futures before we add the timeout as the
# timeout will remove the future from recv_futures to avoid leaks
self._recv_futures.append(
_FutureEvent(f, kind, kwargs, msg=None)
)
# Don't let the Future sit in _recv_events after it's done
f.add_done_callback(lambda f: self._remove_finished_future(f, self._recv_futures))
if hasattr(_zmq, 'RCVTIMEO'):
timeout_ms = self._shadow_sock.rcvtimeo
if timeout_ms >= 0:
self._add_timeout(f, timeout_ms * 1e-3)
if self._shadow_sock.get(EVENTS) & POLLIN:
# recv immediately, if we can
self._handle_recv()
if self._recv_futures:
self._add_io_state(POLLIN)
return f
def _add_send_event(self, kind, msg=None, kwargs=None, future=None):
"""Add a send event, returning the corresponding Future"""
f = future or self._Future()
# attempt send with DONTWAIT if no futures are waiting
# short-circuit for sends that will resolve immediately
# only call if no send Futures are waiting
if (
kind in ('send', 'send_multipart')
and not self._send_futures
):
flags = kwargs.get('flags', 0)
nowait_kwargs = kwargs.copy()
nowait_kwargs['flags'] = flags | _zmq.DONTWAIT
# short-circuit non-blocking calls
send = getattr(self._shadow_sock, kind)
# track if the send resolved or not
# (EAGAIN if DONTWAIT is not set should proceed with)
finish_early = True
try:
r = send(msg, **nowait_kwargs)
except _zmq.Again as e:
if flags & _zmq.DONTWAIT:
f.set_exception(e)
else:
# EAGAIN raised and DONTWAIT not requested,
# proceed with async send
finish_early = False
except Exception as e:
f.set_exception(e)
else:
f.set_result(r)
if finish_early:
# short-circuit resolved, return finished Future
# schedule wake for recv if there are any receivers waiting
if self._recv_futures:
self._schedule_remaining_events()
return f
# we add it to the list of futures before we add the timeout as the
# timeout will remove the future from recv_futures to avoid leaks
self._send_futures.append(
_FutureEvent(f, kind, kwargs=kwargs, msg=msg)
)
# Don't let the Future sit in _send_futures after it's done
f.add_done_callback(lambda f: self._remove_finished_future(f, self._send_futures))
if hasattr(_zmq, 'SNDTIMEO'):
timeout_ms = self._shadow_sock.get(_zmq.SNDTIMEO)
if timeout_ms >= 0:
self._add_timeout(f, timeout_ms * 1e-3)
self._add_io_state(POLLOUT)
return f
def _handle_recv(self):
"""Handle recv events"""
if not self._shadow_sock.get(EVENTS) & POLLIN:
# event triggered, but state may have been changed between trigger and callback
return
f = None
while self._recv_futures:
f, kind, kwargs, _ = self._recv_futures.popleft()
# skip any cancelled futures
if f.done():
f = None
else:
break
if not self._recv_futures:
self._drop_io_state(POLLIN)
if f is None:
return
if kind == 'poll':
# on poll event, just signal ready, nothing else.
f.set_result(None)
return
elif kind == 'recv_multipart':
recv = self._shadow_sock.recv_multipart
elif kind == 'recv':
recv = self._shadow_sock.recv
else:
raise ValueError("Unhandled recv event type: %r" % kind)
kwargs['flags'] |= _zmq.DONTWAIT
try:
result = recv(**kwargs)
except Exception as e:
f.set_exception(e)
else:
f.set_result(result)
def _handle_send(self):
if not self._shadow_sock.get(EVENTS) & POLLOUT:
# event triggered, but state may have been changed between trigger and callback
return
f = None
while self._send_futures:
f, kind, kwargs, msg = self._send_futures.popleft()
# skip any cancelled futures
if f.done():
f = None
else:
break
if not self._send_futures:
self._drop_io_state(POLLOUT)
if f is None:
return
if kind == 'poll':
# on poll event, just signal ready, nothing else.
f.set_result(None)
return
elif kind == 'send_multipart':
send = self._shadow_sock.send_multipart
elif kind == 'send':
send = self._shadow_sock.send
else:
raise ValueError("Unhandled send event type: %r" % kind)
kwargs['flags'] |= _zmq.DONTWAIT
try:
result = send(msg, **kwargs)
except Exception as e:
f.set_exception(e)
else:
f.set_result(result)
# event masking from ZMQStream
def _handle_events(self, fd=0, events=0):
"""Dispatch IO events to _handle_recv, etc."""
zmq_events = self._shadow_sock.get(EVENTS)
if zmq_events & _zmq.POLLIN:
self._handle_recv()
if zmq_events & _zmq.POLLOUT:
self._handle_send()
self._schedule_remaining_events()
def _schedule_remaining_events(self, events=None):
"""Schedule a call to handle_events next loop iteration
If there are still events to handle.
"""
# edge-triggered handling
# allow passing events in, in case this is triggered by retrieving events,
# so we don't have to retrieve it twice.
if self._state == 0:
# not watching for anything, nothing to schedule
return
if events is None:
events = self._shadow_sock.get(EVENTS)
if events & self._state:
self._call_later(0, self._handle_events)
def _add_io_state(self, state):
"""Add io_state to poller."""
if self._state != state:
state = self._state = self._state | state
self._update_handler(self._state)
def _drop_io_state(self, state):
"""Stop poller from watching an io_state."""
if self._state & state:
self._state = self._state & (~state)
self._update_handler(self._state)
def _update_handler(self, state):
"""Update IOLoop handler with state.
zmq FD is always read-only.
"""
self._schedule_remaining_events()
def _init_io_state(self):
"""initialize the ioloop event handler"""
self.io_loop.add_handler(self._shadow_sock, self._handle_events, self._READ)
self._call_later(0, self._handle_events)
def _clear_io_state(self):
"""unregister the ioloop event handler
called once during close
"""
fd = self._shadow_sock
if self._shadow_sock.closed:
fd = self._fd
self.io_loop.remove_handler(fd)

View file

@ -0,0 +1,105 @@
"""AsyncIO support for zmq
Requires asyncio and Python 3.
"""
# Copyright (c) PyZMQ Developers.
# Distributed under the terms of the Modified BSD License.
import zmq as _zmq
from zmq import _future
# TODO: support trollius for Legacy Python? (probably not)
import asyncio
from asyncio import SelectorEventLoop, Future
try:
import selectors
except ImportError:
from asyncio import selectors # py33
class _AsyncIO(object):
_Future = Future
_WRITE = selectors.EVENT_WRITE
_READ = selectors.EVENT_READ
def _default_loop(self):
return asyncio.get_event_loop()
class Poller(_AsyncIO, _future._AsyncPoller):
"""Poller returning asyncio.Future for poll results."""
def _watch_raw_socket(self, loop, socket, evt, f):
"""Schedule callback for a raw socket"""
if evt & self._READ:
loop.add_reader(socket, lambda *args: f())
if evt & self._WRITE:
loop.add_writer(socket, lambda *args: f())
def _unwatch_raw_sockets(self, loop, *sockets):
"""Unschedule callback for a raw socket"""
for socket in sockets:
loop.remove_reader(socket)
loop.remove_writer(socket)
class Socket(_AsyncIO, _future._AsyncSocket):
"""Socket returning asyncio Futures for send/recv/poll methods."""
_poller_class = Poller
def _init_io_state(self):
"""initialize the ioloop event handler"""
self.io_loop.add_reader(self._fd, lambda : self._handle_events(0, 0))
def _clear_io_state(self):
"""clear any ioloop event handler
called once at close
"""
self.io_loop.remove_reader(self._fd)
Poller._socket_class = Socket
class Context(_zmq.Context):
"""Context for creating asyncio-compatible Sockets"""
_socket_class = Socket
# avoid sharing instance with base Context class
_instance = None
class ZMQEventLoop(SelectorEventLoop):
"""DEPRECATED: AsyncIO eventloop using zmq_poll.
pyzmq sockets should work with any asyncio event loop as of pyzmq 17.
"""
def __init__(self, selector=None):
_deprecated()
return super(ZMQEventLoop, self).__init__(selector)
_loop = None
def _deprecated():
if _deprecated.called:
return
_deprecated.called = True
import warnings
warnings.warn("ZMQEventLoop and zmq.asyncio.install are deprecated in pyzmq 17. Special eventloop integration is no longer needed.", DeprecationWarning, stacklevel=3)
_deprecated.called = False
def install():
"""DEPRECATED: No longer needed in pyzmq 17"""
_deprecated()
__all__ = [
'Context',
'Socket',
'Poller',
'ZMQEventLoop',
'install',
]

View file

@ -0,0 +1,11 @@
"""Utilities for ZAP authentication.
To run authentication in a background thread, see :mod:`zmq.auth.thread`.
For integration with the tornado eventloop, see :mod:`zmq.auth.ioloop`.
For integration with the asyncio event loop, see :mod:`zmq.auth.asyncio`.
.. versionadded:: 14.1
"""
from .base import *
from .certs import *

View file

@ -0,0 +1,50 @@
"""ZAP Authenticator integrated with the asyncio IO loop.
.. versionadded:: 15.2
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import asyncio
import zmq
from zmq.asyncio import Poller
from ..base import Authenticator
class AsyncioAuthenticator(Authenticator):
"""ZAP authentication for use in the asyncio IO loop"""
def __init__(self, context=None, loop=None):
super().__init__(context)
self.loop = loop or asyncio.get_event_loop()
self.__poller = None
self.__task = None
@asyncio.coroutine
def __handle_zap(self):
while True:
events = yield from self.__poller.poll()
if self.zap_socket in dict(events):
msg = yield from self.zap_socket.recv_multipart()
self.handle_zap_message(msg)
def start(self):
"""Start ZAP authentication"""
super().start()
self.__poller = Poller()
self.__poller.register(self.zap_socket, zmq.POLLIN)
self.__task = asyncio.ensure_future(self.__handle_zap())
def stop(self):
"""Stop ZAP authentication"""
if self.__task:
self.__task.cancel()
if self.__poller:
self.__poller.unregister(self.zap_socket)
self.__poller = None
super().stop()
__all__ = ['AsyncioAuthenticator']

View file

@ -0,0 +1,379 @@
"""Base implementation of 0MQ authentication."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import logging
import zmq
from zmq.utils import z85
from zmq.utils.strtypes import bytes, unicode, b, u
from zmq.error import _check_version
from .certs import load_certificates
CURVE_ALLOW_ANY = '*'
VERSION = b'1.0'
class Authenticator(object):
"""Implementation of ZAP authentication for zmq connections.
Note:
- libzmq provides four levels of security: default NULL (which the Authenticator does
not see), and authenticated NULL, PLAIN, CURVE, and GSSAPI, which the Authenticator can see.
- until you add policies, all incoming NULL connections are allowed.
(classic ZeroMQ behavior), and all PLAIN and CURVE connections are denied.
- GSSAPI requires no configuration.
"""
def __init__(self, context=None, encoding='utf-8', log=None):
_check_version((4,0), "security")
self.context = context or zmq.Context.instance()
self.encoding = encoding
self.allow_any = False
self.credentials_providers = {}
self.zap_socket = None
self.whitelist = set()
self.blacklist = set()
# passwords is a dict keyed by domain and contains values
# of dicts with username:password pairs.
self.passwords = {}
# certs is dict keyed by domain and contains values
# of dicts keyed by the public keys from the specified location.
self.certs = {}
self.log = log or logging.getLogger('zmq.auth')
def start(self):
"""Create and bind the ZAP socket"""
self.zap_socket = self.context.socket(zmq.REP)
self.zap_socket.linger = 1
self.zap_socket.bind("inproc://zeromq.zap.01")
self.log.debug("Starting")
def stop(self):
"""Close the ZAP socket"""
if self.zap_socket:
self.zap_socket.close()
self.zap_socket = None
def allow(self, *addresses):
"""Allow (whitelist) IP address(es).
Connections from addresses not in the whitelist will be rejected.
- For NULL, all clients from this address will be accepted.
- For real auth setups, they will be allowed to continue with authentication.
whitelist is mutually exclusive with blacklist.
"""
if self.blacklist:
raise ValueError("Only use a whitelist or a blacklist, not both")
self.log.debug("Allowing %s", ','.join(addresses))
self.whitelist.update(addresses)
def deny(self, *addresses):
"""Deny (blacklist) IP address(es).
Addresses not in the blacklist will be allowed to continue with authentication.
Blacklist is mutually exclusive with whitelist.
"""
if self.whitelist:
raise ValueError("Only use a whitelist or a blacklist, not both")
self.log.debug("Denying %s", ','.join(addresses))
self.blacklist.update(addresses)
def configure_plain(self, domain='*', passwords=None):
"""Configure PLAIN authentication for a given domain.
PLAIN authentication uses a plain-text password file.
To cover all domains, use "*".
You can modify the password file at any time; it is reloaded automatically.
"""
if passwords:
self.passwords[domain] = passwords
self.log.debug("Configure plain: %s", domain)
def configure_curve(self, domain='*', location=None):
"""Configure CURVE authentication for a given domain.
CURVE authentication uses a directory that holds all public client certificates,
i.e. their public keys.
To cover all domains, use "*".
You can add and remove certificates in that directory at any time. configure_curve must be called
every time certificates are added or removed, in order to update the Authenticator's state
To allow all client keys without checking, specify CURVE_ALLOW_ANY for the location.
"""
# If location is CURVE_ALLOW_ANY then allow all clients. Otherwise
# treat location as a directory that holds the certificates.
self.log.debug("Configure curve: %s[%s]", domain, location)
if location == CURVE_ALLOW_ANY:
self.allow_any = True
else:
self.allow_any = False
try:
self.certs[domain] = load_certificates(location)
except Exception as e:
self.log.error("Failed to load CURVE certs from %s: %s", location, e)
def configure_curve_callback(self, domain='*', credentials_provider=None):
"""Configure CURVE authentication for a given domain.
CURVE authentication using a callback function validating
the client public key according to a custom mechanism, e.g. checking the
key against records in a db. credentials_provider is an object of a class which
implements a callback method accepting two parameters (domain and key), e.g.::
class CredentialsProvider(object):
def __init__(self):
...e.g. db connection
def callback(self, domain, key):
valid = ...lookup key and/or domain in db
if valid:
logging.info('Authorizing: {0}, {1}'.format(domain, key))
return True
else:
logging.warning('NOT Authorizing: {0}, {1}'.format(domain, key))
return False
To cover all domains, use "*".
To allow all client keys without checking, specify CURVE_ALLOW_ANY for the location.
"""
self.allow_any = False
if credentials_provider is not None:
self.credentials_providers[domain] = credentials_provider
else:
self.log.error("None credentials_provider provided for domain:%s",domain)
def curve_user_id(self, client_public_key):
"""Return the User-Id corresponding to a CURVE client's public key
Default implementation uses the z85-encoding of the public key.
Override to define a custom mapping of public key : user-id
This is only called on successful authentication.
Parameters
----------
client_public_key: bytes
The client public key used for the given message
Returns
-------
user_id: unicode
The user ID as text
"""
return z85.encode(client_public_key).decode('ascii')
def configure_gssapi(self, domain='*', location=None):
"""Configure GSSAPI authentication
Currently this is a no-op because there is nothing to configure with GSSAPI.
"""
pass
def handle_zap_message(self, msg):
"""Perform ZAP authentication"""
if len(msg) < 6:
self.log.error("Invalid ZAP message, not enough frames: %r", msg)
if len(msg) < 2:
self.log.error("Not enough information to reply")
else:
self._send_zap_reply(msg[1], b"400", b"Not enough frames")
return
version, request_id, domain, address, identity, mechanism = msg[:6]
credentials = msg[6:]
domain = u(domain, self.encoding, 'replace')
address = u(address, self.encoding, 'replace')
if (version != VERSION):
self.log.error("Invalid ZAP version: %r", msg)
self._send_zap_reply(request_id, b"400", b"Invalid version")
return
self.log.debug("version: %r, request_id: %r, domain: %r,"
" address: %r, identity: %r, mechanism: %r",
version, request_id, domain,
address, identity, mechanism,
)
# Is address is explicitly whitelisted or blacklisted?
allowed = False
denied = False
reason = b"NO ACCESS"
if self.whitelist:
if address in self.whitelist:
allowed = True
self.log.debug("PASSED (whitelist) address=%s", address)
else:
denied = True
reason = b"Address not in whitelist"
self.log.debug("DENIED (not in whitelist) address=%s", address)
elif self.blacklist:
if address in self.blacklist:
denied = True
reason = b"Address is blacklisted"
self.log.debug("DENIED (blacklist) address=%s", address)
else:
allowed = True
self.log.debug("PASSED (not in blacklist) address=%s", address)
# Perform authentication mechanism-specific checks if necessary
username = u("anonymous")
if not denied:
if mechanism == b'NULL' and not allowed:
# For NULL, we allow if the address wasn't blacklisted
self.log.debug("ALLOWED (NULL)")
allowed = True
elif mechanism == b'PLAIN':
# For PLAIN, even a whitelisted address must authenticate
if len(credentials) != 2:
self.log.error("Invalid PLAIN credentials: %r", credentials)
self._send_zap_reply(request_id, b"400", b"Invalid credentials")
return
username, password = [ u(c, self.encoding, 'replace') for c in credentials ]
allowed, reason = self._authenticate_plain(domain, username, password)
elif mechanism == b'CURVE':
# For CURVE, even a whitelisted address must authenticate
if len(credentials) != 1:
self.log.error("Invalid CURVE credentials: %r", credentials)
self._send_zap_reply(request_id, b"400", b"Invalid credentials")
return
key = credentials[0]
allowed, reason = self._authenticate_curve(domain, key)
if allowed:
username = self.curve_user_id(key)
elif mechanism == b'GSSAPI':
if len(credentials) != 1:
self.log.error("Invalid GSSAPI credentials: %r", credentials)
self._send_zap_reply(request_id, b"400", b"Invalid credentials")
return
# use principal as user-id for now
principal = username = credentials[0]
allowed, reason = self._authenticate_gssapi(domain, principal)
if allowed:
self._send_zap_reply(request_id, b"200", b"OK", username)
else:
self._send_zap_reply(request_id, b"400", reason)
def _authenticate_plain(self, domain, username, password):
"""PLAIN ZAP authentication"""
allowed = False
reason = b""
if self.passwords:
# If no domain is not specified then use the default domain
if not domain:
domain = '*'
if domain in self.passwords:
if username in self.passwords[domain]:
if password == self.passwords[domain][username]:
allowed = True
else:
reason = b"Invalid password"
else:
reason = b"Invalid username"
else:
reason = b"Invalid domain"
if allowed:
self.log.debug("ALLOWED (PLAIN) domain=%s username=%s password=%s",
domain, username, password,
)
else:
self.log.debug("DENIED %s", reason)
else:
reason = b"No passwords defined"
self.log.debug("DENIED (PLAIN) %s", reason)
return allowed, reason
def _authenticate_curve(self, domain, client_key):
"""CURVE ZAP authentication"""
allowed = False
reason = b""
if self.allow_any:
allowed = True
reason = b"OK"
self.log.debug("ALLOWED (CURVE allow any client)")
elif self.credentials_providers != {}:
# If no explicit domain is specified then use the default domain
if not domain:
domain = '*'
if domain in self.credentials_providers:
z85_client_key = z85.encode(client_key)
# Callback to check if key is Allowed
if (self.credentials_providers[domain].callback(domain, z85_client_key)):
allowed = True
reason = b"OK"
else:
reason = b"Unknown key"
status = "ALLOWED" if allowed else "DENIED"
self.log.debug("%s (CURVE auth_callback) domain=%s client_key=%s",
status, domain, z85_client_key,
)
else:
reason = b"Unknown domain"
else:
# If no explicit domain is specified then use the default domain
if not domain:
domain = '*'
if domain in self.certs:
# The certs dict stores keys in z85 format, convert binary key to z85 bytes
z85_client_key = z85.encode(client_key)
if self.certs[domain].get(z85_client_key):
allowed = True
reason = b"OK"
else:
reason = b"Unknown key"
status = "ALLOWED" if allowed else "DENIED"
self.log.debug("%s (CURVE) domain=%s client_key=%s",
status, domain, z85_client_key,
)
else:
reason = b"Unknown domain"
return allowed, reason
def _authenticate_gssapi(self, domain, principal):
"""Nothing to do for GSSAPI, which has already been handled by an external service."""
self.log.debug("ALLOWED (GSSAPI) domain=%s principal=%s", domain, principal)
return True, b'OK'
def _send_zap_reply(self, request_id, status_code, status_text, user_id='anonymous'):
"""Send a ZAP reply to finish the authentication."""
user_id = user_id if status_code == b'200' else b''
if isinstance(user_id, unicode):
user_id = user_id.encode(self.encoding, 'replace')
metadata = b'' # not currently used
self.log.debug("ZAP reply code=%s text=%s", status_code, status_text)
reply = [VERSION, request_id, status_code, status_text, user_id, metadata]
self.zap_socket.send_multipart(reply)
__all__ = ['Authenticator', 'CURVE_ALLOW_ANY']

View file

@ -0,0 +1,126 @@
"""0MQ authentication related functions and classes."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import datetime
import glob
import io
import os
import zmq
from zmq.utils.strtypes import bytes, unicode, b, u
_cert_secret_banner = u("""# **** Generated on {0} by pyzmq ****
# ZeroMQ CURVE **Secret** Certificate
# DO NOT PROVIDE THIS FILE TO OTHER USERS nor change its permissions.
""")
_cert_public_banner = u("""# **** Generated on {0} by pyzmq ****
# ZeroMQ CURVE Public Certificate
# Exchange securely, or use a secure mechanism to verify the contents
# of this file after exchange. Store public certificates in your home
# directory, in the .curve subdirectory.
""")
def _write_key_file(key_filename, banner, public_key, secret_key=None, metadata=None, encoding='utf-8'):
"""Create a certificate file"""
if isinstance(public_key, bytes):
public_key = public_key.decode(encoding)
if isinstance(secret_key, bytes):
secret_key = secret_key.decode(encoding)
with io.open(key_filename, 'w', encoding='utf8') as f:
f.write(banner.format(datetime.datetime.now()))
f.write(u('metadata\n'))
if metadata:
for k, v in metadata.items():
if isinstance(k, bytes):
k = k.decode(encoding)
if isinstance(v, bytes):
v = v.decode(encoding)
f.write(u(" {0} = {1}\n").format(k, v))
f.write(u('curve\n'))
f.write(u(" public-key = \"{0}\"\n").format(public_key))
if secret_key:
f.write(u(" secret-key = \"{0}\"\n").format(secret_key))
def create_certificates(key_dir, name, metadata=None):
"""Create zmq certificates.
Returns the file paths to the public and secret certificate files.
"""
public_key, secret_key = zmq.curve_keypair()
base_filename = os.path.join(key_dir, name)
secret_key_file = "{0}.key_secret".format(base_filename)
public_key_file = "{0}.key".format(base_filename)
now = datetime.datetime.now()
_write_key_file(public_key_file,
_cert_public_banner.format(now),
public_key)
_write_key_file(secret_key_file,
_cert_secret_banner.format(now),
public_key,
secret_key=secret_key,
metadata=metadata)
return public_key_file, secret_key_file
def load_certificate(filename):
"""Load public and secret key from a zmq certificate.
Returns (public_key, secret_key)
If the certificate file only contains the public key,
secret_key will be None.
If there is no public key found in the file, ValueError will be raised.
"""
public_key = None
secret_key = None
if not os.path.exists(filename):
raise IOError("Invalid certificate file: {0}".format(filename))
with open(filename, 'rb') as f:
for line in f:
line = line.strip()
if line.startswith(b'#'):
continue
if line.startswith(b'public-key'):
public_key = line.split(b"=", 1)[1].strip(b' \t\'"')
if line.startswith(b'secret-key'):
secret_key = line.split(b"=", 1)[1].strip(b' \t\'"')
if public_key and secret_key:
break
if public_key is None:
raise ValueError("No public key found in %s" % filename)
return public_key, secret_key
def load_certificates(directory='.'):
"""Load public keys from all certificates in a directory"""
certs = {}
if not os.path.isdir(directory):
raise IOError("Invalid certificate directory: {0}".format(directory))
# Follow czmq pattern of public keys stored in *.key files.
glob_string = os.path.join(directory, "*.key")
cert_files = glob.glob(glob_string)
for cert_file in cert_files:
public_key, _ = load_certificate(cert_file)
if public_key:
certs[public_key] = True
return certs
__all__ = ['create_certificates', 'load_certificate', 'load_certificates']

View file

@ -0,0 +1,35 @@
"""ZAP Authenticator integrated with the tornado IOLoop.
.. versionadded:: 14.1
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from tornado import ioloop
from zmq.eventloop import zmqstream
from .base import Authenticator
class IOLoopAuthenticator(Authenticator):
"""ZAP authentication for use in the tornado IOLoop"""
def __init__(self, context=None, encoding='utf-8', log=None, io_loop=None):
super(IOLoopAuthenticator, self).__init__(context, encoding, log)
self.zap_stream = None
self.io_loop = io_loop or ioloop.IOLoop.current()
def start(self):
"""Start ZAP authentication"""
super(IOLoopAuthenticator, self).start()
self.zap_stream = zmqstream.ZMQStream(self.zap_socket, self.io_loop)
self.zap_stream.on_recv(self.handle_zap_message)
def stop(self):
"""Stop ZAP authentication"""
if self.zap_stream:
self.zap_stream.close()
self.zap_stream = None
super(IOLoopAuthenticator, self).stop()
__all__ = ['IOLoopAuthenticator']

View file

@ -0,0 +1,226 @@
"""ZAP Authenticator in a Python Thread.
.. versionadded:: 14.1
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import time
import logging
from threading import Thread, Event
import zmq
from zmq.utils import jsonapi
from zmq.utils.strtypes import bytes, unicode, b, u
import sys
from .base import Authenticator
class AuthenticationThread(Thread):
"""A Thread for running a zmq Authenticator
This is run in the background by ThreadedAuthenticator
"""
def __init__(self, context, endpoint, encoding='utf-8', log=None, authenticator=None):
super(AuthenticationThread, self).__init__()
self.context = context or zmq.Context.instance()
self.encoding = encoding
self.log = log = log or logging.getLogger('zmq.auth')
self.started = Event()
self.authenticator = authenticator or Authenticator(context, encoding=encoding, log=log)
# create a socket to communicate back to main thread.
self.pipe = context.socket(zmq.PAIR)
self.pipe.linger = 1
self.pipe.connect(endpoint)
def run(self):
"""Start the Authentication Agent thread task"""
self.authenticator.start()
self.started.set()
zap = self.authenticator.zap_socket
poller = zmq.Poller()
poller.register(self.pipe, zmq.POLLIN)
poller.register(zap, zmq.POLLIN)
while True:
try:
socks = dict(poller.poll())
except zmq.ZMQError:
break # interrupted
if self.pipe in socks and socks[self.pipe] == zmq.POLLIN:
# Make sure all API requests are processed before
# looking at the ZAP socket.
while True:
try:
msg = self.pipe.recv_multipart(flags=zmq.NOBLOCK)
except zmq.Again:
break
terminate = self._handle_pipe(msg)
if terminate:
break
if terminate:
break
if zap in socks and socks[zap] == zmq.POLLIN:
self._handle_zap()
self.pipe.close()
self.authenticator.stop()
def _handle_zap(self):
"""
Handle a message from the ZAP socket.
"""
msg = self.authenticator.zap_socket.recv_multipart()
if not msg: return
self.authenticator.handle_zap_message(msg)
def _handle_pipe(self, msg):
"""
Handle a message from front-end API.
"""
terminate = False
if msg is None:
terminate = True
return terminate
command = msg[0]
self.log.debug("auth received API command %r", command)
if command == b'ALLOW':
addresses = [u(m, self.encoding) for m in msg[1:]]
try:
self.authenticator.allow(*addresses)
except Exception as e:
self.log.exception("Failed to allow %s", addresses)
elif command == b'DENY':
addresses = [u(m, self.encoding) for m in msg[1:]]
try:
self.authenticator.deny(*addresses)
except Exception as e:
self.log.exception("Failed to deny %s", addresses)
elif command == b'PLAIN':
domain = u(msg[1], self.encoding)
json_passwords = msg[2]
self.authenticator.configure_plain(domain, jsonapi.loads(json_passwords))
elif command == b'CURVE':
# For now we don't do anything with domains
domain = u(msg[1], self.encoding)
# If location is CURVE_ALLOW_ANY, allow all clients. Otherwise
# treat location as a directory that holds the certificates.
location = u(msg[2], self.encoding)
self.authenticator.configure_curve(domain, location)
elif command == b'TERMINATE':
terminate = True
else:
self.log.error("Invalid auth command from API: %r", command)
return terminate
def _inherit_docstrings(cls):
"""inherit docstrings from Authenticator, so we don't duplicate them"""
for name, method in cls.__dict__.items():
if name.startswith('_') or not callable(method):
continue
upstream_method = getattr(Authenticator, name, None)
if not method.__doc__:
method.__doc__ = upstream_method.__doc__
return cls
@_inherit_docstrings
class ThreadAuthenticator(object):
"""Run ZAP authentication in a background thread"""
context = None
log = None
encoding = None
pipe = None
pipe_endpoint = ''
thread = None
auth = None
def __init__(self, context=None, encoding='utf-8', log=None):
self.context = context or zmq.Context.instance()
self.log = log
self.encoding = encoding
self.pipe = None
self.pipe_endpoint = "inproc://{0}.inproc".format(id(self))
self.thread = None
# proxy base Authenticator attributes
def __setattr__(self, key, value):
for obj in [self] + self.__class__.mro():
if key in obj.__dict__:
object.__setattr__(self, key, value)
return
setattr(self.thread.authenticator, key, value)
def __getattr__(self, key):
try:
object.__getattr__(self, key)
except AttributeError:
return getattr(self.thread.authenticator, key)
def allow(self, *addresses):
self.pipe.send_multipart([b'ALLOW'] + [b(a, self.encoding) for a in addresses])
def deny(self, *addresses):
self.pipe.send_multipart([b'DENY'] + [b(a, self.encoding) for a in addresses])
def configure_plain(self, domain='*', passwords=None):
self.pipe.send_multipart([b'PLAIN', b(domain, self.encoding), jsonapi.dumps(passwords or {})])
def configure_curve(self, domain='*', location=''):
domain = b(domain, self.encoding)
location = b(location, self.encoding)
self.pipe.send_multipart([b'CURVE', domain, location])
def configure_curve_callback(self, domain='*', credentials_provider=None):
self.thread.authenticator.configure_curve_callback(domain, credentials_provider=credentials_provider)
def start(self):
"""Start the authentication thread"""
# create a socket to communicate with auth thread.
self.pipe = self.context.socket(zmq.PAIR)
self.pipe.linger = 1
self.pipe.bind(self.pipe_endpoint)
self.thread = AuthenticationThread(self.context, self.pipe_endpoint, encoding=self.encoding, log=self.log)
self.thread.start()
# Event.wait:Changed in version 2.7: Previously, the method always returned None.
if sys.version_info < (2,7):
self.thread.started.wait(timeout=10)
else:
if not self.thread.started.wait(timeout=10):
raise RuntimeError("Authenticator thread failed to start")
def stop(self):
"""Stop the authentication thread"""
if self.pipe:
self.pipe.send(b'TERMINATE')
if self.is_alive():
self.thread.join()
self.thread = None
self.pipe.close()
self.pipe = None
def is_alive(self):
"""Is the ZAP thread currently running?"""
if self.thread and self.thread.is_alive():
return True
return False
def __del__(self):
self.stop()
__all__ = ['ThreadAuthenticator']

View file

@ -0,0 +1,44 @@
"""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
import sys
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:
exc_info = sys.exc_info()
exc = exc_info[1]
try:
_ns = select_backend(second)
except ImportError:
# prevent 'During handling of the above exception...' on py3
# can't use `raise ... from` on Python 2
if hasattr(exc, '__cause__'):
exc.__cause__ = None
# raise the *first* error, not the fallback
from zmq.utils.sixcerpt import reraise
reraise(*exc_info)
globals().update(_ns)
__all__ = public_api

View file

@ -0,0 +1,22 @@
"""CFFI backend (for PyPY)"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from zmq.backend.cffi import (constants, error, message, context, socket,
_poll, devices, utils)
__all__ = []
for submod in (constants, error, message, context, socket,
_poll, devices, utils):
__all__.extend(submod.__all__)
from .constants import *
from .error import *
from .message import *
from .context import *
from .socket import *
from .devices import *
from ._poll import *
from ._cffi import zmq_version_info, ffi
from .utils import *

View file

@ -0,0 +1,70 @@
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_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 struct
{
void *socket;
int 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);
int get_ipc_path_max_len(void);

View file

@ -0,0 +1,127 @@
# coding: utf-8
"""The main CFFI wrapping of libzmq"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import json
import os
from os.path import dirname, join
from cffi import FFI
from zmq.utils.constant_names import all_names, no_prefix
base_zmq_version = (3,2,2)
def load_compiler_config():
"""load pyzmq compiler arguments"""
import zmq
zmq_dir = dirname(zmq.__file__)
zmq_parent = dirname(zmq_dir)
fname = join(zmq_dir, 'utils', 'compiler.json')
if os.path.exists(fname):
with open(fname) as f:
cfg = json.load(f)
else:
cfg = {}
cfg.setdefault("include_dirs", [])
cfg.setdefault("library_dirs", [])
cfg.setdefault("runtime_library_dirs", [])
cfg.setdefault("libraries", ["zmq"])
# cast to str, because cffi can't handle unicode paths (?!)
cfg['libraries'] = [str(lib) for lib in cfg['libraries']]
for key in ("include_dirs", "library_dirs", "runtime_library_dirs"):
# interpret paths relative to parent of zmq (like source tree)
abs_paths = []
for p in cfg[key]:
if p.startswith('zmq'):
p = join(zmq_parent, p)
abs_paths.append(str(p))
cfg[key] = abs_paths
return cfg
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]))
cfg = load_compiler_config()
ffi = FFI()
def _make_defines(names):
_names = []
for name in names:
define_line = "#define %s ..." % (name)
_names.append(define_line)
return "\n".join(_names)
c_constant_names = ['PYZMQ_DRAFT_API']
for name in all_names:
if no_prefix(name):
c_constant_names.append(name)
else:
c_constant_names.append("ZMQ_" + name)
# load ffi definitions
here = os.path.dirname(__file__)
with open(os.path.join(here, '_cdefs.h')) as f:
_cdefs = f.read()
with open(os.path.join(here, '_verify.c')) as f:
_verify = f.read()
ffi.cdef(_cdefs)
ffi.cdef(_make_defines(c_constant_names))
try:
C = ffi.verify(_verify,
modulename='_cffi_ext',
libraries=cfg['libraries'],
include_dirs=cfg['include_dirs'],
library_dirs=cfg['library_dirs'],
runtime_library_dirs=cfg['runtime_library_dirs'],
)
_version_info = zmq_version_info()
except Exception as e:
raise ImportError("PyZMQ CFFI backend couldn't find zeromq: %s\n"
"Please check that you have zeromq headers and libraries." % e)
if _version_info < (3,2,2):
raise ImportError("PyZMQ CFFI backend requires zeromq >= 3.2.2,"
" but found %i.%i.%i" % _version_info
)
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)
IPC_PATH_MAX_LEN = C.get_ipc_path_max_len()

View file

@ -0,0 +1,80 @@
# coding: utf-8
"""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 ._cffi import C, ffi
from zmq.error import InterruptedSystemCall, _check_rc
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,7 @@
#include <stdio.h>
#include <string.h>
#include <zmq.h>
#include "zmq_compat.h"
#include "ipcmaxlen.h"

View file

@ -0,0 +1,16 @@
# coding: utf-8
"""zmq constants"""
from ._cffi import C, c_constant_names
from zmq.utils.constant_names import all_names
g = globals()
for cname in c_constant_names:
if cname.startswith("ZMQ_"):
name = cname[4:]
else:
name = cname
g[name] = getattr(C, cname)
DRAFT_API = C.PYZMQ_DRAFT_API
__all__ = ['DRAFT_API'] + all_names

View file

@ -0,0 +1,77 @@
# coding: utf-8
"""zmq Context class"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from ._cffi import C, ffi
from .constants import EINVAL, IO_THREADS, LINGER
from zmq.error import ZMQError, InterruptedSystemCall, _check_rc
class Context(object):
_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)
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,68 @@
# coding: utf-8
"""zmq device functions"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from ._cffi import C, ffi
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,17 @@
"""zmq error functions"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from ._cffi import C, ffi
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,64 @@
"""Dummy Frame object"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from ._cffi import ffi, C
import zmq
from zmq.utils.strtypes import unicode
_content = lambda x: x.tobytes() if type(x) == memoryview else x
class Frame(object):
_data = None
tracker = None
closed = False
more = False
buffer = None
def __init__(self, data, track=False, copy=None, copy_threshold=None):
try:
memoryview(data)
except TypeError:
raise
self._data = data
if isinstance(data, unicode):
raise TypeError("Unicode objects not allowed. Only: str/bytes, " +
"buffer interfaces.")
self.more = False
self.tracker = None
self.closed = False
if track:
self.tracker = zmq._FINISHED_TRACKER
self.buffer = memoryview(self.bytes)
@property
def bytes(self):
data = _content(self._data)
return data
def __len__(self):
return len(self.bytes)
def __eq__(self, other):
return self.bytes == _content(other)
def __str__(self):
if str is unicode:
return self.bytes.decode()
else:
return self.bytes
@property
def done(self):
return True
Message = Frame
__all__ = ['Frame', 'Message']

View file

@ -0,0 +1,279 @@
# coding: utf-8
"""zmq Socket class"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import errno as errno_mod
from ._cffi import (C, ffi, new_uint64_pointer, new_int64_pointer,
new_int_pointer, new_binary_data, value_uint64_pointer,
value_int64_pointer, value_int_pointer, value_binary_data,
IPC_PATH_MAX_LEN)
from .message import Frame
from .constants import RCVMORE
from .utils import _retry_sys_call
import zmq
from zmq.error import ZMQError, _check_rc, _check_version
from zmq.utils.strtypes import unicode
def new_pointer_from_opt(option, length=0):
from zmq.sugar.constants import (
int64_sockopts, bytes_sockopts,
)
if option in int64_sockopts:
return new_int64_pointer()
elif option in bytes_sockopts:
return new_binary_data(length)
else:
# default
return new_int_pointer()
def value_from_opt_pointer(option, opt_pointer, length=0):
from zmq.sugar.constants import (
int64_sockopts, bytes_sockopts,
)
if option in int64_sockopts:
return int(opt_pointer[0])
elif option in bytes_sockopts:
return ffi.buffer(opt_pointer, length)[:]
else:
return int(opt_pointer[0])
def initialize_opt_pointer(option, value, length=0):
from zmq.sugar.constants import (
int64_sockopts, bytes_sockopts,
)
if option in int64_sockopts:
return value_int64_pointer(value)
elif option in bytes_sockopts:
return value_binary_data(value, length)
else:
return value_int_pointer(value)
class Socket(object):
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, unicode):
address = address.encode('utf8')
rc = C.zmq_bind(self._zmq_socket, address)
if rc < 0:
if IPC_PATH_MAX_LEN and C.zmq_errno() == errno_mod.ENAMETOOLONG:
# py3compat: address is bytes, but msg wants str
if str is unicode:
address = address.decode('utf-8', 'replace')
path = address.split('://', 1)[-1]
msg = ('ipc path "{0}" is longer than {1} '
'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:
# py3compat: address is bytes, but msg wants str
if str is unicode:
address = address.decode('utf-8', 'replace')
path = address.split('://', 1)[-1]
msg = ('No such file or directory for ipc path "{0}".'.format(
path))
raise ZMQError(C.zmq_errno(), msg=msg)
else:
_check_rc(rc)
def unbind(self, address):
_check_version((3,2), "unbind")
if isinstance(address, unicode):
address = address.encode('utf8')
rc = C.zmq_unbind(self._zmq_socket, address)
_check_rc(rc)
def connect(self, address):
if isinstance(address, unicode):
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, unicode):
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, unicode):
raise TypeError("unicode not allowed, use bytes")
if isinstance(value, bytes):
if option not in zmq.constants.bytes_sockopts:
raise TypeError("not a bytes sockopt: %s" % option)
length = len(value)
c_data = initialize_opt_pointer(option, value, length)
c_value_pointer = c_data[0]
c_sizet = c_data[1]
_retry_sys_call(C.zmq_setsockopt,
self._zmq_socket,
option,
ffi.cast('void*', c_value_pointer),
c_sizet)
def get(self, option):
c_data = new_pointer_from_opt(option, length=255)
c_value_pointer = c_data[0]
c_sizet_pointer = c_data[1]
_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.IDENTITY and option in zmq.constants.bytes_sockopts and v.endswith(b'\0'):
v = v[:-1]
return v
def send(self, message, flags=0, copy=False, track=False):
if isinstance(message, unicode):
raise TypeError("Message must be in bytes, not an unicode Object")
if isinstance(message, Frame):
message = message.bytes
zmq_msg = ffi.new('zmq_msg_t*')
if not isinstance(message, bytes):
# cast any bufferable data to bytes via memoryview
message = memoryview(message).tobytes()
c_message = ffi.new('char[]', message)
rc = C.zmq_msg_init_size(zmq_msg, len(message))
_check_rc(rc)
C.memcpy(C.zmq_msg_data(zmq_msg), c_message, len(message))
_retry_sys_call(C.zmq_msg_send, zmq_msg, self._zmq_socket, flags)
rc2 = C.zmq_msg_close(zmq_msg)
_check_rc(rc2)
if track:
return zmq.MessageTracker()
def recv(self, flags=0, copy=True, track=False):
zmq_msg = ffi.new('zmq_msg_t*')
C.zmq_msg_init(zmq_msg)
try:
_retry_sys_call(C.zmq_msg_recv, zmq_msg, self._zmq_socket, flags)
except Exception:
C.zmq_msg_close(zmq_msg)
raise
_buffer = ffi.buffer(C.zmq_msg_data(zmq_msg), C.zmq_msg_size(zmq_msg))
value = _buffer[:]
rc = C.zmq_msg_close(zmq_msg)
_check_rc(rc)
frame = Frame(value, track=track)
frame.more = self.getsockopt(RCVMORE)
if copy:
return frame.bytes
else:
return frame
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, unicode):
addr = addr.encode('utf8')
rc = C.zmq_socket_monitor(self._zmq_socket, addr, events)
__all__ = ['Socket', 'IPC_PATH_MAX_LEN']

View file

@ -0,0 +1,81 @@
# coding: utf-8
"""miscellaneous zmq_utils wrapping"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from errno import EINTR
from ._cffi import ffi, C
from zmq.error import ZMQError, InterruptedSystemCall, _check_rc, _check_version
from zmq.utils.strtypes import unicode
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, unicode):
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, unicode):
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.socket cimport Socket
from zmq.backend.cython.message cimport Frame

View file

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

View file

@ -0,0 +1,27 @@
from libc.errno cimport EINTR, EAGAIN
from cpython cimport PyErr_CheckSignals
from .libzmq cimport zmq_errno, ZMQ_ETERM
cdef inline int _check_rc(int rc) except -1:
"""internal utility for checking zmq return condition
and raising the appropriate Exception class
"""
cdef int errno = zmq_errno()
PyErr_CheckSignals()
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,222 @@
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_NOBLOCK
enum: ZMQ_DONTWAIT
enum: ZMQ_POLLIN
enum: ZMQ_POLLOUT
enum: ZMQ_POLLERR
enum: ZMQ_POLLPRI
enum: ZMQ_SNDMORE
enum: ZMQ_STREAMER
enum: ZMQ_FORWARDER
enum: ZMQ_QUEUE
enum: ZMQ_IO_THREADS_DFLT
enum: ZMQ_MAX_SOCKETS_DFLT
enum: ZMQ_POLLITEMS_DFLT
enum: ZMQ_THREAD_PRIORITY_DFLT
enum: ZMQ_THREAD_SCHED_POLICY_DFLT
enum: ZMQ_PAIR
enum: ZMQ_PUB
enum: ZMQ_SUB
enum: ZMQ_REQ
enum: ZMQ_REP
enum: ZMQ_DEALER
enum: ZMQ_ROUTER
enum: ZMQ_XREQ
enum: ZMQ_XREP
enum: ZMQ_PULL
enum: ZMQ_PUSH
enum: ZMQ_XPUB
enum: ZMQ_XSUB
enum: ZMQ_UPSTREAM
enum: ZMQ_DOWNSTREAM
enum: ZMQ_STREAM
enum: ZMQ_SERVER
enum: ZMQ_CLIENT
enum: ZMQ_RADIO
enum: ZMQ_DISH
enum: ZMQ_GATHER
enum: ZMQ_SCATTER
enum: ZMQ_DGRAM
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_ALL
enum: ZMQ_EVENT_MONITOR_STOPPED
enum: ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL
enum: ZMQ_EVENT_HANDSHAKE_SUCCEEDED
enum: ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL
enum: ZMQ_EVENT_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_NOTIFY_CONNECT
enum: ZMQ_NOTIFY_DISCONNECT
enum: ZMQ_NULL
enum: ZMQ_PLAIN
enum: ZMQ_CURVE
enum: ZMQ_GSSAPI
enum: ZMQ_GSSAPI_NT_HOSTBASED
enum: ZMQ_GSSAPI_NT_USER_NAME
enum: ZMQ_GSSAPI_NT_KRB5_PRINCIPAL
enum: ZMQ_EAGAIN "EAGAIN"
enum: ZMQ_EINVAL "EINVAL"
enum: ZMQ_EFAULT "EFAULT"
enum: ZMQ_ENOMEM "ENOMEM"
enum: ZMQ_ENODEV "ENODEV"
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_HAUSNUMERO
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_EFSM "EFSM"
enum: ZMQ_ENOCOMPATPROTO "ENOCOMPATPROTO"
enum: ZMQ_ETERM "ETERM"
enum: ZMQ_EMTHREAD "EMTHREAD"
enum: ZMQ_IO_THREADS
enum: ZMQ_MAX_SOCKETS
enum: ZMQ_SOCKET_LIMIT
enum: ZMQ_THREAD_PRIORITY
enum: ZMQ_THREAD_SCHED_POLICY
enum: ZMQ_BLOCKY
enum: ZMQ_MSG_T_SIZE
enum: ZMQ_THREAD_AFFINITY_CPU_ADD
enum: ZMQ_THREAD_AFFINITY_CPU_REMOVE
enum: ZMQ_THREAD_NAME_PREFIX
enum: ZMQ_IDENTITY
enum: ZMQ_SUBSCRIBE
enum: ZMQ_UNSUBSCRIBE
enum: ZMQ_LAST_ENDPOINT
enum: ZMQ_TCP_ACCEPT_FILTER
enum: ZMQ_PLAIN_USERNAME
enum: ZMQ_PLAIN_PASSWORD
enum: ZMQ_CURVE_PUBLICKEY
enum: ZMQ_CURVE_SECRETKEY
enum: ZMQ_CURVE_SERVERKEY
enum: ZMQ_ZAP_DOMAIN
enum: ZMQ_CONNECT_RID
enum: ZMQ_GSSAPI_PRINCIPAL
enum: ZMQ_GSSAPI_SERVICE_PRINCIPAL
enum: ZMQ_SOCKS_PROXY
enum: ZMQ_XPUB_WELCOME_MSG
enum: ZMQ_ROUTING_ID
enum: ZMQ_CONNECT_ROUTING_ID
enum: ZMQ_BINDTODEVICE
enum: ZMQ_FD
enum: ZMQ_RECONNECT_IVL_MAX
enum: ZMQ_SNDTIMEO
enum: ZMQ_RCVTIMEO
enum: ZMQ_SNDHWM
enum: ZMQ_RCVHWM
enum: ZMQ_MULTICAST_HOPS
enum: ZMQ_IPV4ONLY
enum: ZMQ_ROUTER_BEHAVIOR
enum: ZMQ_TCP_KEEPALIVE
enum: ZMQ_TCP_KEEPALIVE_CNT
enum: ZMQ_TCP_KEEPALIVE_IDLE
enum: ZMQ_TCP_KEEPALIVE_INTVL
enum: ZMQ_DELAY_ATTACH_ON_CONNECT
enum: ZMQ_XPUB_VERBOSE
enum: ZMQ_EVENTS
enum: ZMQ_TYPE
enum: ZMQ_LINGER
enum: ZMQ_RECONNECT_IVL
enum: ZMQ_BACKLOG
enum: ZMQ_ROUTER_MANDATORY
enum: ZMQ_FAIL_UNROUTABLE
enum: ZMQ_ROUTER_RAW
enum: ZMQ_IMMEDIATE
enum: ZMQ_IPV6
enum: ZMQ_MECHANISM
enum: ZMQ_PLAIN_SERVER
enum: ZMQ_CURVE_SERVER
enum: ZMQ_PROBE_ROUTER
enum: ZMQ_REQ_RELAXED
enum: ZMQ_REQ_CORRELATE
enum: ZMQ_CONFLATE
enum: ZMQ_ROUTER_HANDOVER
enum: ZMQ_TOS
enum: ZMQ_IPC_FILTER_PID
enum: ZMQ_IPC_FILTER_UID
enum: ZMQ_IPC_FILTER_GID
enum: ZMQ_GSSAPI_SERVER
enum: ZMQ_GSSAPI_PLAINTEXT
enum: ZMQ_HANDSHAKE_IVL
enum: ZMQ_XPUB_NODROP
enum: ZMQ_XPUB_MANUAL
enum: ZMQ_STREAM_NOTIFY
enum: ZMQ_INVERT_MATCHING
enum: ZMQ_XPUB_VERBOSER
enum: ZMQ_HEARTBEAT_IVL
enum: ZMQ_HEARTBEAT_TTL
enum: ZMQ_HEARTBEAT_TIMEOUT
enum: ZMQ_CONNECT_TIMEOUT
enum: ZMQ_TCP_MAXRT
enum: ZMQ_THREAD_SAFE
enum: ZMQ_MULTICAST_MAXTPDU
enum: ZMQ_VMCI_CONNECT_TIMEOUT
enum: ZMQ_USE_FD
enum: ZMQ_GSSAPI_PRINCIPAL_NAMETYPE
enum: ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE
enum: ZMQ_MULTICAST_LOOP
enum: ZMQ_ROUTER_NOTIFY
enum: ZMQ_ZAP_ENFORCE_DOMAIN
enum: ZMQ_AFFINITY
enum: ZMQ_MAXMSGSIZE
enum: ZMQ_HWM
enum: ZMQ_SWAP
enum: ZMQ_MCAST_LOOP
enum: ZMQ_RECOVERY_IVL_MSEC
enum: ZMQ_VMCI_BUFFER_SIZE
enum: ZMQ_VMCI_BUFFER_MIN_SIZE
enum: ZMQ_VMCI_BUFFER_MAX_SIZE
enum: ZMQ_RATE
enum: ZMQ_RECOVERY_IVL
enum: ZMQ_SNDBUF
enum: ZMQ_RCVBUF
enum: ZMQ_RCVMORE
enum: ZMQ_MORE
enum: ZMQ_SRCFD
enum: ZMQ_SHARED

View file

@ -0,0 +1,453 @@
#-----------------------------------------------------------------------------
# Python module level constants
#-----------------------------------------------------------------------------
DRAFT_API = PYZMQ_DRAFT_API
VERSION = ZMQ_VERSION
VERSION_MAJOR = ZMQ_VERSION_MAJOR
VERSION_MINOR = ZMQ_VERSION_MINOR
VERSION_PATCH = ZMQ_VERSION_PATCH
NOBLOCK = ZMQ_NOBLOCK
DONTWAIT = ZMQ_DONTWAIT
POLLIN = ZMQ_POLLIN
POLLOUT = ZMQ_POLLOUT
POLLERR = ZMQ_POLLERR
POLLPRI = ZMQ_POLLPRI
SNDMORE = ZMQ_SNDMORE
STREAMER = ZMQ_STREAMER
FORWARDER = ZMQ_FORWARDER
QUEUE = ZMQ_QUEUE
IO_THREADS_DFLT = ZMQ_IO_THREADS_DFLT
MAX_SOCKETS_DFLT = ZMQ_MAX_SOCKETS_DFLT
POLLITEMS_DFLT = ZMQ_POLLITEMS_DFLT
THREAD_PRIORITY_DFLT = ZMQ_THREAD_PRIORITY_DFLT
THREAD_SCHED_POLICY_DFLT = ZMQ_THREAD_SCHED_POLICY_DFLT
PAIR = ZMQ_PAIR
PUB = ZMQ_PUB
SUB = ZMQ_SUB
REQ = ZMQ_REQ
REP = ZMQ_REP
DEALER = ZMQ_DEALER
ROUTER = ZMQ_ROUTER
XREQ = ZMQ_XREQ
XREP = ZMQ_XREP
PULL = ZMQ_PULL
PUSH = ZMQ_PUSH
XPUB = ZMQ_XPUB
XSUB = ZMQ_XSUB
UPSTREAM = ZMQ_UPSTREAM
DOWNSTREAM = ZMQ_DOWNSTREAM
STREAM = ZMQ_STREAM
SERVER = ZMQ_SERVER
CLIENT = ZMQ_CLIENT
RADIO = ZMQ_RADIO
DISH = ZMQ_DISH
GATHER = ZMQ_GATHER
SCATTER = ZMQ_SCATTER
DGRAM = ZMQ_DGRAM
EVENT_CONNECTED = ZMQ_EVENT_CONNECTED
EVENT_CONNECT_DELAYED = ZMQ_EVENT_CONNECT_DELAYED
EVENT_CONNECT_RETRIED = ZMQ_EVENT_CONNECT_RETRIED
EVENT_LISTENING = ZMQ_EVENT_LISTENING
EVENT_BIND_FAILED = ZMQ_EVENT_BIND_FAILED
EVENT_ACCEPTED = ZMQ_EVENT_ACCEPTED
EVENT_ACCEPT_FAILED = ZMQ_EVENT_ACCEPT_FAILED
EVENT_CLOSED = ZMQ_EVENT_CLOSED
EVENT_CLOSE_FAILED = ZMQ_EVENT_CLOSE_FAILED
EVENT_DISCONNECTED = ZMQ_EVENT_DISCONNECTED
EVENT_ALL = ZMQ_EVENT_ALL
EVENT_MONITOR_STOPPED = ZMQ_EVENT_MONITOR_STOPPED
EVENT_HANDSHAKE_FAILED_NO_DETAIL = ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL
EVENT_HANDSHAKE_SUCCEEDED = ZMQ_EVENT_HANDSHAKE_SUCCEEDED
EVENT_HANDSHAKE_FAILED_PROTOCOL = ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL
EVENT_HANDSHAKE_FAILED_AUTH = ZMQ_EVENT_HANDSHAKE_FAILED_AUTH
PROTOCOL_ERROR_ZMTP_UNSPECIFIED = ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED
PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND = ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE = ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE
PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE = ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY
PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME
PROTOCOL_ERROR_ZMTP_INVALID_METADATA = ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA
PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC = ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH = ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH
PROTOCOL_ERROR_ZAP_UNSPECIFIED = ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED
PROTOCOL_ERROR_ZAP_MALFORMED_REPLY = ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY
PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID = ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID
PROTOCOL_ERROR_ZAP_BAD_VERSION = ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION
PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE = ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE
PROTOCOL_ERROR_ZAP_INVALID_METADATA = ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA
NOTIFY_CONNECT = ZMQ_NOTIFY_CONNECT
NOTIFY_DISCONNECT = ZMQ_NOTIFY_DISCONNECT
globals()['NULL'] = ZMQ_NULL
PLAIN = ZMQ_PLAIN
CURVE = ZMQ_CURVE
GSSAPI = ZMQ_GSSAPI
GSSAPI_NT_HOSTBASED = ZMQ_GSSAPI_NT_HOSTBASED
GSSAPI_NT_USER_NAME = ZMQ_GSSAPI_NT_USER_NAME
GSSAPI_NT_KRB5_PRINCIPAL = ZMQ_GSSAPI_NT_KRB5_PRINCIPAL
EAGAIN = ZMQ_EAGAIN
EINVAL = ZMQ_EINVAL
EFAULT = ZMQ_EFAULT
ENOMEM = ZMQ_ENOMEM
ENODEV = ZMQ_ENODEV
EMSGSIZE = ZMQ_EMSGSIZE
EAFNOSUPPORT = ZMQ_EAFNOSUPPORT
ENETUNREACH = ZMQ_ENETUNREACH
ECONNABORTED = ZMQ_ECONNABORTED
ECONNRESET = ZMQ_ECONNRESET
ENOTCONN = ZMQ_ENOTCONN
ETIMEDOUT = ZMQ_ETIMEDOUT
EHOSTUNREACH = ZMQ_EHOSTUNREACH
ENETRESET = ZMQ_ENETRESET
HAUSNUMERO = ZMQ_HAUSNUMERO
ENOTSUP = ZMQ_ENOTSUP
EPROTONOSUPPORT = ZMQ_EPROTONOSUPPORT
ENOBUFS = ZMQ_ENOBUFS
ENETDOWN = ZMQ_ENETDOWN
EADDRINUSE = ZMQ_EADDRINUSE
EADDRNOTAVAIL = ZMQ_EADDRNOTAVAIL
ECONNREFUSED = ZMQ_ECONNREFUSED
EINPROGRESS = ZMQ_EINPROGRESS
ENOTSOCK = ZMQ_ENOTSOCK
EFSM = ZMQ_EFSM
ENOCOMPATPROTO = ZMQ_ENOCOMPATPROTO
ETERM = ZMQ_ETERM
EMTHREAD = ZMQ_EMTHREAD
IO_THREADS = ZMQ_IO_THREADS
MAX_SOCKETS = ZMQ_MAX_SOCKETS
SOCKET_LIMIT = ZMQ_SOCKET_LIMIT
THREAD_PRIORITY = ZMQ_THREAD_PRIORITY
THREAD_SCHED_POLICY = ZMQ_THREAD_SCHED_POLICY
BLOCKY = ZMQ_BLOCKY
MSG_T_SIZE = ZMQ_MSG_T_SIZE
THREAD_AFFINITY_CPU_ADD = ZMQ_THREAD_AFFINITY_CPU_ADD
THREAD_AFFINITY_CPU_REMOVE = ZMQ_THREAD_AFFINITY_CPU_REMOVE
THREAD_NAME_PREFIX = ZMQ_THREAD_NAME_PREFIX
IDENTITY = ZMQ_IDENTITY
SUBSCRIBE = ZMQ_SUBSCRIBE
UNSUBSCRIBE = ZMQ_UNSUBSCRIBE
LAST_ENDPOINT = ZMQ_LAST_ENDPOINT
TCP_ACCEPT_FILTER = ZMQ_TCP_ACCEPT_FILTER
PLAIN_USERNAME = ZMQ_PLAIN_USERNAME
PLAIN_PASSWORD = ZMQ_PLAIN_PASSWORD
CURVE_PUBLICKEY = ZMQ_CURVE_PUBLICKEY
CURVE_SECRETKEY = ZMQ_CURVE_SECRETKEY
CURVE_SERVERKEY = ZMQ_CURVE_SERVERKEY
ZAP_DOMAIN = ZMQ_ZAP_DOMAIN
CONNECT_RID = ZMQ_CONNECT_RID
GSSAPI_PRINCIPAL = ZMQ_GSSAPI_PRINCIPAL
GSSAPI_SERVICE_PRINCIPAL = ZMQ_GSSAPI_SERVICE_PRINCIPAL
SOCKS_PROXY = ZMQ_SOCKS_PROXY
XPUB_WELCOME_MSG = ZMQ_XPUB_WELCOME_MSG
ROUTING_ID = ZMQ_ROUTING_ID
CONNECT_ROUTING_ID = ZMQ_CONNECT_ROUTING_ID
BINDTODEVICE = ZMQ_BINDTODEVICE
FD = ZMQ_FD
RECONNECT_IVL_MAX = ZMQ_RECONNECT_IVL_MAX
SNDTIMEO = ZMQ_SNDTIMEO
RCVTIMEO = ZMQ_RCVTIMEO
SNDHWM = ZMQ_SNDHWM
RCVHWM = ZMQ_RCVHWM
MULTICAST_HOPS = ZMQ_MULTICAST_HOPS
IPV4ONLY = ZMQ_IPV4ONLY
ROUTER_BEHAVIOR = ZMQ_ROUTER_BEHAVIOR
TCP_KEEPALIVE = ZMQ_TCP_KEEPALIVE
TCP_KEEPALIVE_CNT = ZMQ_TCP_KEEPALIVE_CNT
TCP_KEEPALIVE_IDLE = ZMQ_TCP_KEEPALIVE_IDLE
TCP_KEEPALIVE_INTVL = ZMQ_TCP_KEEPALIVE_INTVL
DELAY_ATTACH_ON_CONNECT = ZMQ_DELAY_ATTACH_ON_CONNECT
XPUB_VERBOSE = ZMQ_XPUB_VERBOSE
EVENTS = ZMQ_EVENTS
TYPE = ZMQ_TYPE
LINGER = ZMQ_LINGER
RECONNECT_IVL = ZMQ_RECONNECT_IVL
BACKLOG = ZMQ_BACKLOG
ROUTER_MANDATORY = ZMQ_ROUTER_MANDATORY
FAIL_UNROUTABLE = ZMQ_FAIL_UNROUTABLE
ROUTER_RAW = ZMQ_ROUTER_RAW
IMMEDIATE = ZMQ_IMMEDIATE
IPV6 = ZMQ_IPV6
MECHANISM = ZMQ_MECHANISM
PLAIN_SERVER = ZMQ_PLAIN_SERVER
CURVE_SERVER = ZMQ_CURVE_SERVER
PROBE_ROUTER = ZMQ_PROBE_ROUTER
REQ_RELAXED = ZMQ_REQ_RELAXED
REQ_CORRELATE = ZMQ_REQ_CORRELATE
CONFLATE = ZMQ_CONFLATE
ROUTER_HANDOVER = ZMQ_ROUTER_HANDOVER
TOS = ZMQ_TOS
IPC_FILTER_PID = ZMQ_IPC_FILTER_PID
IPC_FILTER_UID = ZMQ_IPC_FILTER_UID
IPC_FILTER_GID = ZMQ_IPC_FILTER_GID
GSSAPI_SERVER = ZMQ_GSSAPI_SERVER
GSSAPI_PLAINTEXT = ZMQ_GSSAPI_PLAINTEXT
HANDSHAKE_IVL = ZMQ_HANDSHAKE_IVL
XPUB_NODROP = ZMQ_XPUB_NODROP
XPUB_MANUAL = ZMQ_XPUB_MANUAL
STREAM_NOTIFY = ZMQ_STREAM_NOTIFY
INVERT_MATCHING = ZMQ_INVERT_MATCHING
XPUB_VERBOSER = ZMQ_XPUB_VERBOSER
HEARTBEAT_IVL = ZMQ_HEARTBEAT_IVL
HEARTBEAT_TTL = ZMQ_HEARTBEAT_TTL
HEARTBEAT_TIMEOUT = ZMQ_HEARTBEAT_TIMEOUT
CONNECT_TIMEOUT = ZMQ_CONNECT_TIMEOUT
TCP_MAXRT = ZMQ_TCP_MAXRT
THREAD_SAFE = ZMQ_THREAD_SAFE
MULTICAST_MAXTPDU = ZMQ_MULTICAST_MAXTPDU
VMCI_CONNECT_TIMEOUT = ZMQ_VMCI_CONNECT_TIMEOUT
USE_FD = ZMQ_USE_FD
GSSAPI_PRINCIPAL_NAMETYPE = ZMQ_GSSAPI_PRINCIPAL_NAMETYPE
GSSAPI_SERVICE_PRINCIPAL_NAMETYPE = ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE
MULTICAST_LOOP = ZMQ_MULTICAST_LOOP
ROUTER_NOTIFY = ZMQ_ROUTER_NOTIFY
ZAP_ENFORCE_DOMAIN = ZMQ_ZAP_ENFORCE_DOMAIN
AFFINITY = ZMQ_AFFINITY
MAXMSGSIZE = ZMQ_MAXMSGSIZE
HWM = ZMQ_HWM
SWAP = ZMQ_SWAP
MCAST_LOOP = ZMQ_MCAST_LOOP
RECOVERY_IVL_MSEC = ZMQ_RECOVERY_IVL_MSEC
VMCI_BUFFER_SIZE = ZMQ_VMCI_BUFFER_SIZE
VMCI_BUFFER_MIN_SIZE = ZMQ_VMCI_BUFFER_MIN_SIZE
VMCI_BUFFER_MAX_SIZE = ZMQ_VMCI_BUFFER_MAX_SIZE
RATE = ZMQ_RATE
RECOVERY_IVL = ZMQ_RECOVERY_IVL
SNDBUF = ZMQ_SNDBUF
RCVBUF = ZMQ_RCVBUF
RCVMORE = ZMQ_RCVMORE
MORE = ZMQ_MORE
SRCFD = ZMQ_SRCFD
SHARED = ZMQ_SHARED
#-----------------------------------------------------------------------------
# Symbols to export
#-----------------------------------------------------------------------------
__all__ = [
"DRAFT_API",
"VERSION",
"VERSION_MAJOR",
"VERSION_MINOR",
"VERSION_PATCH",
"NOBLOCK",
"DONTWAIT",
"POLLIN",
"POLLOUT",
"POLLERR",
"POLLPRI",
"SNDMORE",
"STREAMER",
"FORWARDER",
"QUEUE",
"IO_THREADS_DFLT",
"MAX_SOCKETS_DFLT",
"POLLITEMS_DFLT",
"THREAD_PRIORITY_DFLT",
"THREAD_SCHED_POLICY_DFLT",
"PAIR",
"PUB",
"SUB",
"REQ",
"REP",
"DEALER",
"ROUTER",
"XREQ",
"XREP",
"PULL",
"PUSH",
"XPUB",
"XSUB",
"UPSTREAM",
"DOWNSTREAM",
"STREAM",
"SERVER",
"CLIENT",
"RADIO",
"DISH",
"GATHER",
"SCATTER",
"DGRAM",
"EVENT_CONNECTED",
"EVENT_CONNECT_DELAYED",
"EVENT_CONNECT_RETRIED",
"EVENT_LISTENING",
"EVENT_BIND_FAILED",
"EVENT_ACCEPTED",
"EVENT_ACCEPT_FAILED",
"EVENT_CLOSED",
"EVENT_CLOSE_FAILED",
"EVENT_DISCONNECTED",
"EVENT_ALL",
"EVENT_MONITOR_STOPPED",
"EVENT_HANDSHAKE_FAILED_NO_DETAIL",
"EVENT_HANDSHAKE_SUCCEEDED",
"EVENT_HANDSHAKE_FAILED_PROTOCOL",
"EVENT_HANDSHAKE_FAILED_AUTH",
"PROTOCOL_ERROR_ZMTP_UNSPECIFIED",
"PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND",
"PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE",
"PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE",
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED",
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE",
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO",
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE",
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR",
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY",
"PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME",
"PROTOCOL_ERROR_ZMTP_INVALID_METADATA",
"PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC",
"PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH",
"PROTOCOL_ERROR_ZAP_UNSPECIFIED",
"PROTOCOL_ERROR_ZAP_MALFORMED_REPLY",
"PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID",
"PROTOCOL_ERROR_ZAP_BAD_VERSION",
"PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE",
"PROTOCOL_ERROR_ZAP_INVALID_METADATA",
"NOTIFY_CONNECT",
"NOTIFY_DISCONNECT",
"NULL",
"PLAIN",
"CURVE",
"GSSAPI",
"GSSAPI_NT_HOSTBASED",
"GSSAPI_NT_USER_NAME",
"GSSAPI_NT_KRB5_PRINCIPAL",
"EAGAIN",
"EINVAL",
"EFAULT",
"ENOMEM",
"ENODEV",
"EMSGSIZE",
"EAFNOSUPPORT",
"ENETUNREACH",
"ECONNABORTED",
"ECONNRESET",
"ENOTCONN",
"ETIMEDOUT",
"EHOSTUNREACH",
"ENETRESET",
"HAUSNUMERO",
"ENOTSUP",
"EPROTONOSUPPORT",
"ENOBUFS",
"ENETDOWN",
"EADDRINUSE",
"EADDRNOTAVAIL",
"ECONNREFUSED",
"EINPROGRESS",
"ENOTSOCK",
"EFSM",
"ENOCOMPATPROTO",
"ETERM",
"EMTHREAD",
"IO_THREADS",
"MAX_SOCKETS",
"SOCKET_LIMIT",
"THREAD_PRIORITY",
"THREAD_SCHED_POLICY",
"BLOCKY",
"MSG_T_SIZE",
"THREAD_AFFINITY_CPU_ADD",
"THREAD_AFFINITY_CPU_REMOVE",
"THREAD_NAME_PREFIX",
"IDENTITY",
"SUBSCRIBE",
"UNSUBSCRIBE",
"LAST_ENDPOINT",
"TCP_ACCEPT_FILTER",
"PLAIN_USERNAME",
"PLAIN_PASSWORD",
"CURVE_PUBLICKEY",
"CURVE_SECRETKEY",
"CURVE_SERVERKEY",
"ZAP_DOMAIN",
"CONNECT_RID",
"GSSAPI_PRINCIPAL",
"GSSAPI_SERVICE_PRINCIPAL",
"SOCKS_PROXY",
"XPUB_WELCOME_MSG",
"ROUTING_ID",
"CONNECT_ROUTING_ID",
"BINDTODEVICE",
"FD",
"RECONNECT_IVL_MAX",
"SNDTIMEO",
"RCVTIMEO",
"SNDHWM",
"RCVHWM",
"MULTICAST_HOPS",
"IPV4ONLY",
"ROUTER_BEHAVIOR",
"TCP_KEEPALIVE",
"TCP_KEEPALIVE_CNT",
"TCP_KEEPALIVE_IDLE",
"TCP_KEEPALIVE_INTVL",
"DELAY_ATTACH_ON_CONNECT",
"XPUB_VERBOSE",
"EVENTS",
"TYPE",
"LINGER",
"RECONNECT_IVL",
"BACKLOG",
"ROUTER_MANDATORY",
"FAIL_UNROUTABLE",
"ROUTER_RAW",
"IMMEDIATE",
"IPV6",
"MECHANISM",
"PLAIN_SERVER",
"CURVE_SERVER",
"PROBE_ROUTER",
"REQ_RELAXED",
"REQ_CORRELATE",
"CONFLATE",
"ROUTER_HANDOVER",
"TOS",
"IPC_FILTER_PID",
"IPC_FILTER_UID",
"IPC_FILTER_GID",
"GSSAPI_SERVER",
"GSSAPI_PLAINTEXT",
"HANDSHAKE_IVL",
"XPUB_NODROP",
"XPUB_MANUAL",
"STREAM_NOTIFY",
"INVERT_MATCHING",
"XPUB_VERBOSER",
"HEARTBEAT_IVL",
"HEARTBEAT_TTL",
"HEARTBEAT_TIMEOUT",
"CONNECT_TIMEOUT",
"TCP_MAXRT",
"THREAD_SAFE",
"MULTICAST_MAXTPDU",
"VMCI_CONNECT_TIMEOUT",
"USE_FD",
"GSSAPI_PRINCIPAL_NAMETYPE",
"GSSAPI_SERVICE_PRINCIPAL_NAMETYPE",
"MULTICAST_LOOP",
"ROUTER_NOTIFY",
"ZAP_ENFORCE_DOMAIN",
"AFFINITY",
"MAXMSGSIZE",
"HWM",
"SWAP",
"MCAST_LOOP",
"RECOVERY_IVL_MSEC",
"VMCI_BUFFER_SIZE",
"VMCI_BUFFER_MIN_SIZE",
"VMCI_BUFFER_MAX_SIZE",
"RATE",
"RECOVERY_IVL",
"SNDBUF",
"RCVBUF",
"RCVMORE",
"MORE",
"SRCFD",
"SHARED",
]

View file

@ -0,0 +1,35 @@
"""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,117 @@
"""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
#-----------------------------------------------------------------------------
# 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
int 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,63 @@
"""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_t, zmq_msg_data, zmq_msg_size
#-----------------------------------------------------------------------------
# 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,49 @@
"""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.
public_api = [
'Context',
'Socket',
'Frame',
'Message',
'device',
'proxy',
'proxy_steerable',
'zmq_poll',
'strerror',
'zmq_errno',
'has',
'curve_keypair',
'curve_public',
'constants',
'zmq_version_info',
'IPC_PATH_MAX_LEN',
]
def select_backend(name):
"""Select the pyzmq backend"""
try:
mod = __import__(name, fromlist=public_api)
except ImportError:
raise
except Exception as e:
import sys
from zmq.utils.sixcerpt import reraise
exc_info = sys.exc_info()
reraise(ImportError, ImportError("Importing %s failed with %s" % (name, e)), exc_info[2])
ns = {}
for key in public_api:
ns[key] = getattr(mod, key)
return ns

Binary file not shown.

View file

@ -0,0 +1,188 @@
"""Decorators for running functions with context/sockets.
.. versionadded:: 15.3
Like using Contexts and Sockets as context managers, but with decorator syntax.
Context and sockets are closed at the end of the function.
For example::
from zmq.decorators import context, socket
@context()
@socket(zmq.PUSH)
def work(ctx, push):
...
"""
# Copyright (c) PyZMQ Developers.
# Distributed under the terms of the Modified BSD License.
__all__ = (
'context',
'socket',
)
from functools import wraps
import zmq
from zmq.utils.strtypes import basestring
class _Decorator(object):
'''The mini decorator factory'''
def __init__(self, target=None):
self._target = target
def __call__(self, *dec_args, **dec_kwargs):
'''
The main logic of decorator
Here is how those arguments works::
@out_decorator(*dec_args, *dec_kwargs)
def func(*wrap_args, **wrap_kwargs):
...
And in the ``wrapper``, we simply create ``self.target`` instance via
``with``::
target = self.get_target(*args, **kwargs)
with target(*dec_args, **dec_kwargs) as obj:
...
'''
kw_name, dec_args, dec_kwargs = self.process_decorator_args(*dec_args, **dec_kwargs)
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
target = self.get_target(*args, **kwargs)
with target(*dec_args, **dec_kwargs) as obj:
# insert our object into args
if kw_name and kw_name not in kwargs:
kwargs[kw_name] = obj
elif kw_name and kw_name in kwargs:
raise TypeError(
"{0}() got multiple values for"
" argument '{1}'".format(
func.__name__, kw_name))
else:
args = args + (obj,)
return func(*args, **kwargs)
return wrapper
return decorator
def get_target(self, *args, **kwargs):
"""Return the target function
Allows modifying args/kwargs to be passed.
"""
return self._target
def process_decorator_args(self, *args, **kwargs):
"""Process args passed to the decorator.
args not consumed by the decorator will be passed to the target factory
(Context/Socket constructor).
"""
kw_name = None
if isinstance(kwargs.get('name'), basestring):
kw_name = kwargs.pop('name')
elif len(args) >= 1 and isinstance(args[0], basestring):
kw_name = args[0]
args = args[1:]
return kw_name, args, kwargs
class _ContextDecorator(_Decorator):
"""Decorator subclass for Contexts"""
def __init__(self):
super(_ContextDecorator, self).__init__(zmq.Context)
class _SocketDecorator(_Decorator):
"""Decorator subclass for sockets
Gets the context from other args.
"""
def process_decorator_args(self, *args, **kwargs):
"""Also grab context_name out of kwargs"""
kw_name, args, kwargs = super(_SocketDecorator, self).process_decorator_args(*args, **kwargs)
self.context_name = kwargs.pop('context_name', 'context')
return kw_name, args, kwargs
def get_target(self, *args, **kwargs):
"""Get context, based on call-time args"""
context = self._get_context(*args, **kwargs)
return context.socket
def _get_context(self, *args, **kwargs):
'''
Find the ``zmq.Context`` from ``args`` and ``kwargs`` at call time.
First, if there is an keyword argument named ``context`` and it is a
``zmq.Context`` instance , we will take it.
Second, we check all the ``args``, take the first ``zmq.Context``
instance.
Finally, we will provide default Context -- ``zmq.Context.instance``
:return: a ``zmq.Context`` instance
'''
if self.context_name in kwargs:
ctx = kwargs[self.context_name]
if isinstance(ctx, zmq.Context):
return ctx
for arg in args:
if isinstance(arg, zmq.Context):
return arg
# not specified by any decorator
return zmq.Context.instance()
def context(*args, **kwargs):
'''Decorator for adding a Context to a function.
Usage::
@context()
def foo(ctx):
...
.. versionadded:: 15.3
:param str name: the keyword argument passed to decorated function
'''
return _ContextDecorator()(*args, **kwargs)
def socket(*args, **kwargs):
'''Decorator for adding a socket to a function.
Usage::
@socket(zmq.PUSH)
def foo(push):
...
.. versionadded:: 15.3
:param str name: the keyword argument passed to decorated function
:param str context_name: the keyword only argument to identify context
object
'''
return _SocketDecorator()(*args, **kwargs)

View file

@ -0,0 +1,29 @@
"""0MQ Device classes for running in background threads or processes."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from zmq import device
from zmq.devices import (
basedevice,
monitoredqueue,
monitoredqueuedevice,
proxydevice,
proxysteerabledevice,
)
from zmq.devices.basedevice import *
from zmq.devices.proxydevice import *
from zmq.devices.proxysteerabledevice import *
from zmq.devices.monitoredqueue import *
from zmq.devices.monitoredqueuedevice import *
__all__ = ['device']
for submod in (
basedevice,
proxydevice,
proxysteerabledevice,
monitoredqueue,
monitoredqueuedevice
):
__all__.extend(submod.__all__)

View file

@ -0,0 +1,281 @@
"""Classes for running 0MQ Devices in the background."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import time
from threading import Thread
from multiprocessing import Process
from zmq import device, QUEUE, REQ, Context, ETERM, ZMQBindError, ZMQError
class Device:
"""A 0MQ Device to be run in the background.
You do not pass Socket instances to this, but rather Socket types::
Device(device_type, in_socket_type, out_socket_type)
For instance::
dev = Device(zmq.QUEUE, zmq.DEALER, zmq.ROUTER)
Similar to zmq.device, but socket types instead of sockets themselves are
passed, and the sockets are created in the work thread, to avoid issues
with thread safety. As a result, additional bind_{in|out} and
connect_{in|out} methods and setsockopt_{in|out} allow users to specify
connections for the sockets.
Parameters
----------
device_type : int
The 0MQ Device type
{in|out}_type : int
zmq socket types, to be passed later to context.socket(). e.g.
zmq.PUB, zmq.SUB, zmq.REQ. If out_type is < 0, then in_socket is used
for both in_socket and out_socket.
Methods
-------
bind_{in_out}(iface)
passthrough for ``{in|out}_socket.bind(iface)``, to be called in the thread
connect_{in_out}(iface)
passthrough for ``{in|out}_socket.connect(iface)``, to be called in the
thread
setsockopt_{in_out}(opt,value)
passthrough for ``{in|out}_socket.setsockopt(opt, value)``, to be called in
the thread
Attributes
----------
daemon : int
sets whether the thread should be run as a daemon
Default is true, because if it is false, the thread will not
exit unless it is killed
context_factory : callable (class attribute)
Function for creating the Context. This will be Context.instance
in ThreadDevices, and Context in ProcessDevices. The only reason
it is not instance() in ProcessDevices is that there may be a stale
Context instance already initialized, and the forked environment
should *never* try to use it.
"""
context_factory = Context.instance
"""Callable that returns a context. Typically either Context.instance or Context,
depending on whether the device should share the global instance or not.
"""
def __init__(self, device_type=QUEUE, in_type=None, out_type=None):
self.device_type = device_type
if in_type is None:
raise TypeError("in_type must be specified")
if out_type is None:
raise TypeError("out_type must be specified")
self.in_type = in_type
self.out_type = out_type
self._in_binds = []
self._in_connects = []
self._in_sockopts = []
self._out_binds = []
self._out_connects = []
self._out_sockopts = []
self._random_addrs = []
self.daemon = True
self.done = False
def bind_in(self, addr):
"""Enqueue ZMQ address for binding on in_socket.
See zmq.Socket.bind for details.
"""
self._in_binds.append(addr)
def bind_in_to_random_port(self, addr, *args, **kwargs):
"""Enqueue a random port on the given interface for binding on
in_socket.
See zmq.Socket.bind_to_random_port for details.
.. versionadded:: 18.0
"""
port = self._reserve_random_port(addr, *args, **kwargs)
self.bind_in('%s:%i' % (addr, port))
return port
def connect_in(self, addr):
"""Enqueue ZMQ address for connecting on in_socket.
See zmq.Socket.connect for details.
"""
self._in_connects.append(addr)
def setsockopt_in(self, opt, value):
"""Enqueue setsockopt(opt, value) for in_socket
See zmq.Socket.setsockopt for details.
"""
self._in_sockopts.append((opt, value))
def bind_out(self, addr):
"""Enqueue ZMQ address for binding on out_socket.
See zmq.Socket.bind for details.
"""
self._out_binds.append(addr)
def bind_out_to_random_port(self, addr, *args, **kwargs):
"""Enqueue a random port on the given interface for binding on
out_socket.
See zmq.Socket.bind_to_random_port for details.
.. versionadded:: 18.0
"""
port = self._reserve_random_port(addr, *args, **kwargs)
self.bind_out('%s:%i' % (addr, port))
return port
def connect_out(self, addr):
"""Enqueue ZMQ address for connecting on out_socket.
See zmq.Socket.connect for details.
"""
self._out_connects.append(addr)
def setsockopt_out(self, opt, value):
"""Enqueue setsockopt(opt, value) for out_socket
See zmq.Socket.setsockopt for details.
"""
self._out_sockopts.append((opt, value))
def _reserve_random_port(self, addr, *args, **kwargs):
ctx = Context()
binder = ctx.socket(REQ)
for i in range(5):
port = binder.bind_to_random_port(addr, *args, **kwargs)
new_addr = '%s:%i' % (addr, port)
if new_addr in self._random_addrs:
continue
else:
break
else:
raise ZMQBindError("Could not reserve random port.")
self._random_addrs.append(new_addr)
binder.close()
return port
def _setup_sockets(self):
ctx = self.context_factory()
self._context = ctx
# create the sockets
ins = ctx.socket(self.in_type)
if self.out_type < 0:
outs = ins
else:
outs = ctx.socket(self.out_type)
# set sockopts (must be done first, in case of zmq.IDENTITY)
for opt,value in self._in_sockopts:
ins.setsockopt(opt, value)
for opt,value in self._out_sockopts:
outs.setsockopt(opt, value)
for iface in self._in_binds:
ins.bind(iface)
for iface in self._out_binds:
outs.bind(iface)
for iface in self._in_connects:
ins.connect(iface)
for iface in self._out_connects:
outs.connect(iface)
return ins,outs
def run_device(self):
"""The runner method.
Do not call me directly, instead call ``self.start()``, just like a Thread.
"""
ins,outs = self._setup_sockets()
device(self.device_type, ins, outs)
def run(self):
"""wrap run_device in try/catch ETERM"""
try:
self.run_device()
except ZMQError as e:
if e.errno == ETERM:
# silence TERM errors, because this should be a clean shutdown
pass
else:
raise
finally:
self.done = True
def start(self):
"""Start the device. Override me in subclass for other launchers."""
return self.run()
def join(self,timeout=None):
"""wait for me to finish, like Thread.join.
Reimplemented appropriately by subclasses."""
tic = time.time()
toc = tic
while not self.done and not (timeout is not None and toc-tic > timeout):
time.sleep(.001)
toc = time.time()
class BackgroundDevice(Device):
"""Base class for launching Devices in background processes and threads."""
launcher=None
_launch_class=None
def start(self):
self.launcher = self._launch_class(target=self.run)
self.launcher.daemon = self.daemon
return self.launcher.start()
def join(self, timeout=None):
return self.launcher.join(timeout=timeout)
class ThreadDevice(BackgroundDevice):
"""A Device that will be run in a background Thread.
See Device for details.
"""
_launch_class=Thread
class ProcessDevice(BackgroundDevice):
"""A Device that will be run in a background Process.
See Device for details.
"""
_launch_class=Process
context_factory = Context
"""Callable that returns a context. Typically either Context.instance or Context,
depending on whether the device should share the global instance or not.
"""
__all__ = ['Device', 'ThreadDevice', 'ProcessDevice']

View file

@ -0,0 +1,177 @@
"""MonitoredQueue class declarations.
Authors
-------
* MinRK
* Brian Granger
"""
#
# Copyright (c) 2010 Min Ragan-Kelley, Brian Granger
#
# This file is part of pyzmq, but is derived and adapted from zmq_queue.cpp
# originally from libzmq-2.1.6, used under LGPLv3
#
# 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 zmq.backend.cython.libzmq cimport *
#-----------------------------------------------------------------------------
# MonitoredQueue C functions
#-----------------------------------------------------------------------------
cdef inline int _relay(void *insocket_, void *outsocket_, void *sidesocket_,
zmq_msg_t msg, zmq_msg_t side_msg, zmq_msg_t id_msg,
bint swap_ids) nogil:
cdef int rc
cdef int64_t flag_2
cdef int flag_3
cdef int flags
cdef bint more
cdef size_t flagsz
cdef void * flag_ptr
if ZMQ_VERSION_MAJOR < 3:
flagsz = sizeof (int64_t)
flag_ptr = &flag_2
else:
flagsz = sizeof (int)
flag_ptr = &flag_3
if swap_ids:# both router, must send second identity first
# recv two ids into msg, id_msg
rc = zmq_msg_recv(&msg, insocket_, 0)
if rc < 0: return rc
rc = zmq_msg_recv(&id_msg, insocket_, 0)
if rc < 0: return rc
# send second id (id_msg) first
#!!!! always send a copy before the original !!!!
rc = zmq_msg_copy(&side_msg, &id_msg)
if rc < 0: return rc
rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
if rc < 0: return rc
rc = zmq_msg_send(&id_msg, sidesocket_, ZMQ_SNDMORE)
if rc < 0: return rc
# send first id (msg) second
rc = zmq_msg_copy(&side_msg, &msg)
if rc < 0: return rc
rc = zmq_msg_send(&side_msg, outsocket_, ZMQ_SNDMORE)
if rc < 0: return rc
rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
if rc < 0: return rc
while (True):
rc = zmq_msg_recv(&msg, insocket_, 0)
if rc < 0: return rc
# assert (rc == 0)
rc = zmq_getsockopt (insocket_, ZMQ_RCVMORE, flag_ptr, &flagsz)
if rc < 0: return rc
flags = 0
if ZMQ_VERSION_MAJOR < 3:
if flag_2:
flags |= ZMQ_SNDMORE
else:
if flag_3:
flags |= ZMQ_SNDMORE
# LABEL has been removed:
# rc = zmq_getsockopt (insocket_, ZMQ_RCVLABEL, flag_ptr, &flagsz)
# if flag_3:
# flags |= ZMQ_SNDLABEL
# assert (rc == 0)
rc = zmq_msg_copy(&side_msg, &msg)
if rc < 0: return rc
if flags:
rc = zmq_msg_send(&side_msg, outsocket_, flags)
if rc < 0: return rc
# only SNDMORE for side-socket
rc = zmq_msg_send(&msg, sidesocket_, ZMQ_SNDMORE)
if rc < 0: return rc
else:
rc = zmq_msg_send(&side_msg, outsocket_, 0)
if rc < 0: return rc
rc = zmq_msg_send(&msg, sidesocket_, 0)
if rc < 0: return rc
break
return rc
# the MonitoredQueue C function, adapted from zmq::queue.cpp :
cdef inline int c_monitored_queue (void *insocket_, void *outsocket_,
void *sidesocket_, zmq_msg_t *in_msg_ptr,
zmq_msg_t *out_msg_ptr, int swap_ids) nogil:
"""The actual C function for a monitored queue device.
See ``monitored_queue()`` for details.
"""
cdef zmq_msg_t msg
cdef int rc = zmq_msg_init (&msg)
cdef zmq_msg_t id_msg
rc = zmq_msg_init (&id_msg)
if rc < 0: return rc
cdef zmq_msg_t side_msg
rc = zmq_msg_init (&side_msg)
if rc < 0: return rc
cdef zmq_pollitem_t items [2]
items [0].socket = insocket_
items [0].fd = 0
items [0].events = ZMQ_POLLIN
items [0].revents = 0
items [1].socket = outsocket_
items [1].fd = 0
items [1].events = ZMQ_POLLIN
items [1].revents = 0
# I don't think sidesocket should be polled?
# items [2].socket = sidesocket_
# items [2].fd = 0
# items [2].events = ZMQ_POLLIN
# items [2].revents = 0
while (True):
# // Wait while there are either requests or replies to process.
rc = zmq_poll (&items [0], 2, -1)
if rc < 0: return rc
# // The algorithm below asumes ratio of request and replies processed
# // under full load to be 1:1. Although processing requests replies
# // first is tempting it is suspectible to DoS attacks (overloading
# // the system with unsolicited replies).
#
# // Process a request.
if (items [0].revents & ZMQ_POLLIN):
# send in_prefix to side socket
rc = zmq_msg_copy(&side_msg, in_msg_ptr)
if rc < 0: return rc
rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
if rc < 0: return rc
# relay the rest of the message
rc = _relay(insocket_, outsocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
if rc < 0: return rc
if (items [1].revents & ZMQ_POLLIN):
# send out_prefix to side socket
rc = zmq_msg_copy(&side_msg, out_msg_ptr)
if rc < 0: return rc
rc = zmq_msg_send(&side_msg, sidesocket_, ZMQ_SNDMORE)
if rc < 0: return rc
# relay the rest of the message
rc = _relay(outsocket_, insocket_, sidesocket_, msg, side_msg, id_msg, swap_ids)
if rc < 0: return rc
return rc

View file

@ -0,0 +1,37 @@
"""pure Python monitored_queue function
For use when Cython extension is unavailable (PyPy).
Authors
-------
* MinRK
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import zmq
def _relay(ins, outs, sides, prefix, swap_ids):
msg = ins.recv_multipart()
if swap_ids:
msg[:2] = msg[:2][::-1]
outs.send_multipart(msg)
sides.send_multipart([prefix] + msg)
def monitored_queue(in_socket, out_socket, mon_socket,
in_prefix=b'in', out_prefix=b'out'):
swap_ids = in_socket.type == zmq.ROUTER and out_socket.type == zmq.ROUTER
poller = zmq.Poller()
poller.register(in_socket, zmq.POLLIN)
poller.register(out_socket, zmq.POLLIN)
while True:
events = dict(poller.poll())
if in_socket in events:
_relay(in_socket, out_socket, mon_socket, in_prefix, swap_ids)
if out_socket in events:
_relay(out_socket, in_socket, mon_socket, out_prefix, swap_ids)
__all__ = ['monitored_queue']

View file

@ -0,0 +1,66 @@
"""MonitoredQueue classes and functions."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from zmq import ZMQError, PUB
from zmq.devices.proxydevice import ProxyBase, Proxy, ThreadProxy, ProcessProxy
from zmq.devices.monitoredqueue import monitored_queue
class MonitoredQueueBase(ProxyBase):
"""Base class for overriding methods."""
_in_prefix = b''
_out_prefix = b''
def __init__(self, in_type, out_type, mon_type=PUB, in_prefix=b'in', out_prefix=b'out'):
ProxyBase.__init__(self, in_type=in_type, out_type=out_type, mon_type=mon_type)
self._in_prefix = in_prefix
self._out_prefix = out_prefix
def run_device(self):
ins,outs,mons = self._setup_sockets()
monitored_queue(ins, outs, mons, self._in_prefix, self._out_prefix)
class MonitoredQueue(MonitoredQueueBase, Proxy):
"""Class for running monitored_queue in the background.
See zmq.devices.Device for most of the spec. MonitoredQueue differs from Proxy,
only in that it adds a ``prefix`` to messages sent on the monitor socket,
with a different prefix for each direction.
MQ also supports ROUTER on both sides, which zmq.proxy does not.
If a message arrives on `in_sock`, it will be prefixed with `in_prefix` on the monitor socket.
If it arrives on out_sock, it will be prefixed with `out_prefix`.
A PUB socket is the most logical choice for the mon_socket, but it is not required.
"""
pass
class ThreadMonitoredQueue(MonitoredQueueBase, ThreadProxy):
"""Run zmq.monitored_queue in a background thread.
See MonitoredQueue and Proxy for details.
"""
pass
class ProcessMonitoredQueue(MonitoredQueueBase, ProcessProxy):
"""Run zmq.monitored_queue in a background thread.
See MonitoredQueue and Proxy for details.
"""
__all__ = [
'MonitoredQueue',
'ThreadMonitoredQueue',
'ProcessMonitoredQueue'
]

View file

@ -0,0 +1,104 @@
"""Proxy classes and functions."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import zmq
from zmq.devices.basedevice import Device, ThreadDevice, ProcessDevice
class ProxyBase(object):
"""Base class for overriding methods."""
def __init__(self, in_type, out_type, mon_type=zmq.PUB):
Device.__init__(self, in_type=in_type, out_type=out_type)
self.mon_type = mon_type
self._mon_binds = []
self._mon_connects = []
self._mon_sockopts = []
def bind_mon(self, addr):
"""Enqueue ZMQ address for binding on mon_socket.
See zmq.Socket.bind for details.
"""
self._mon_binds.append(addr)
def bind_mon_to_random_port(self, addr, *args, **kwargs):
"""Enqueue a random port on the given interface for binding on
mon_socket.
See zmq.Socket.bind_to_random_port for details.
.. versionadded:: 18.0
"""
port = self._reserve_random_port(addr, *args, **kwargs)
self.bind_mon('%s:%i' % (addr, port))
return port
def connect_mon(self, addr):
"""Enqueue ZMQ address for connecting on mon_socket.
See zmq.Socket.connect for details.
"""
self._mon_connects.append(addr)
def setsockopt_mon(self, opt, value):
"""Enqueue setsockopt(opt, value) for mon_socket
See zmq.Socket.setsockopt for details.
"""
self._mon_sockopts.append((opt, value))
def _setup_sockets(self):
ins,outs = Device._setup_sockets(self)
ctx = self._context
mons = ctx.socket(self.mon_type)
# set sockopts (must be done first, in case of zmq.IDENTITY)
for opt,value in self._mon_sockopts:
mons.setsockopt(opt, value)
for iface in self._mon_binds:
mons.bind(iface)
for iface in self._mon_connects:
mons.connect(iface)
return ins,outs,mons
def run_device(self):
ins,outs,mons = self._setup_sockets()
zmq.proxy(ins, outs, mons)
class Proxy(ProxyBase, Device):
"""Threadsafe Proxy object.
See zmq.devices.Device for most of the spec. This subclass adds a
<method>_mon version of each <method>_{in|out} method, for configuring the
monitor socket.
A Proxy is a 3-socket ZMQ Device that functions just like a
QUEUE, except each message is also sent out on the monitor socket.
A PUB socket is the most logical choice for the mon_socket, but it is not required.
"""
pass
class ThreadProxy(ProxyBase, ThreadDevice):
"""Proxy in a Thread. See Proxy for more."""
pass
class ProcessProxy(ProxyBase, ProcessDevice):
"""Proxy in a Process. See Proxy for more."""
pass
__all__ = [
'Proxy',
'ThreadProxy',
'ProcessProxy',
]

View file

@ -0,0 +1,112 @@
"""Classes for running a steerable ZMQ proxy"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
import zmq
from zmq.devices.proxydevice import Proxy, ThreadProxy, ProcessProxy
class ProxySteerableBase(object):
"""Base class for overriding methods."""
def __init__(self, in_type, out_type, mon_type=zmq.PUB, ctrl_type=None):
super(ProxySteerableBase, self).__init__(
in_type=in_type,
out_type=out_type,
mon_type=mon_type
)
self.ctrl_type = ctrl_type
self._ctrl_binds = []
self._ctrl_connects = []
self._ctrl_sockopts = []
def bind_ctrl(self, addr):
"""Enqueue ZMQ address for binding on ctrl_socket.
See zmq.Socket.bind for details.
"""
self._ctrl_binds.append(addr)
def bind_ctrl_to_random_port(self, addr, *args, **kwargs):
"""Enqueue a random port on the given interface for binding on
ctrl_socket.
See zmq.Socket.bind_to_random_port for details.
"""
port = self._reserve_random_port(addr, *args, **kwargs)
self.bind_ctrl('%s:%i' % (addr, port))
return port
def connect_ctrl(self, addr):
"""Enqueue ZMQ address for connecting on ctrl_socket.
See zmq.Socket.connect for details.
"""
self._ctrl_connects.append(addr)
def setsockopt_ctrl(self, opt, value):
"""Enqueue setsockopt(opt, value) for ctrl_socket
See zmq.Socket.setsockopt for details.
"""
self._ctrl_sockopts.append((opt, value))
def _setup_sockets(self):
ins, outs, mons = super(ProxySteerableBase, self)._setup_sockets()
ctx = self._context
ctrls = ctx.socket(self.ctrl_type)
for opt, value in self._ctrl_sockopts:
ctrls.setsockopt(opt, value)
for iface in self._ctrl_binds:
ctrls.bind(iface)
for iface in self._ctrl_connects:
ctrls.connect(iface)
return ins, outs, mons, ctrls
def run_device(self):
ins, outs, mons, ctrls = self._setup_sockets()
zmq.proxy_steerable(ins, outs, mons, ctrls)
class ProxySteerable(ProxySteerableBase, Proxy):
"""Class for running a steerable proxy in the background.
See zmq.devices.Proxy for most of the spec. If the control socket is not
NULL, the proxy supports control flow, provided by the socket.
If PAUSE is received on this socket, the proxy suspends its activities. If
RESUME is received, it goes on. If TERMINATE is received, it terminates
smoothly. If the control socket is NULL, the proxy behave exactly as if
zmq.devices.Proxy had been used.
This subclass adds a <method>_ctrl version of each <method>_{in|out}
method, for configuring the control socket.
.. versionadded:: libzmq-4.1
.. versionadded:: 18.0
"""
pass
class ThreadProxySteerable(ProxySteerableBase, ThreadProxy):
"""ProxySteerable in a Thread. See ProxySteerable for details."""
pass
class ProcessProxySteerable(ProxySteerableBase, ProcessProxy):
"""ProxySteerable in a Process. See ProxySteerable for details."""
pass
__all__ = [
'ProxySteerable',
'ThreadProxySteerable',
'ProcessProxySteerable',
]

View file

@ -0,0 +1,196 @@
"""0MQ Error classes and functions."""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from errno import EINTR
class ZMQBaseError(Exception):
"""Base exception class for 0MQ errors in Python."""
pass
class ZMQError(ZMQBaseError):
"""Wrap an errno style error.
Parameters
----------
errno : int
The ZMQ errno or None. If None, then ``zmq_errno()`` is called and
used.
msg : string
Description of the error or None.
"""
errno = None
def __init__(self, errno=None, msg=None):
"""Wrap an errno style error.
Parameters
----------
errno : int
The ZMQ errno or None. If None, then ``zmq_errno()`` is called and
used.
msg : string
Description of the error or None.
"""
from zmq.backend import strerror, zmq_errno
if errno is None:
errno = zmq_errno()
if isinstance(errno, int):
self.errno = errno
if msg is None:
self.strerror = strerror(errno)
else:
self.strerror = msg
else:
if msg is None:
self.strerror = str(errno)
else:
self.strerror = msg
# flush signals, because there could be a SIGINT
# waiting to pounce, resulting in uncaught exceptions.
# Doing this here means getting SIGINT during a blocking
# libzmq call will raise a *catchable* KeyboardInterrupt
# PyErr_CheckSignals()
def __str__(self):
return self.strerror
def __repr__(self):
return "%s('%s')" % (self.__class__.__name__, str(self))
class ZMQBindError(ZMQBaseError):
"""An error for ``Socket.bind_to_random_port()``.
See Also
--------
.Socket.bind_to_random_port
"""
pass
class NotDone(ZMQBaseError):
"""Raised when timeout is reached while waiting for 0MQ to finish with a Message
See Also
--------
.MessageTracker.wait : object for tracking when ZeroMQ is done
"""
pass
class ContextTerminated(ZMQError):
"""Wrapper for zmq.ETERM
.. versionadded:: 13.0
"""
def __init__(self, errno='ignored', msg='ignored'):
from zmq import ETERM
super(ContextTerminated, self).__init__(ETERM)
class Again(ZMQError):
"""Wrapper for zmq.EAGAIN
.. versionadded:: 13.0
"""
def __init__(self, errno='ignored', msg='ignored'):
from zmq import EAGAIN
super(Again, self).__init__(EAGAIN)
try:
InterruptedError
except NameError:
InterruptedError = OSError
class InterruptedSystemCall(ZMQError, InterruptedError):
"""Wrapper for EINTR
This exception should be caught internally in pyzmq
to retry system calls, and not propagate to the user.
.. versionadded:: 14.7
"""
def __init__(self, errno='ignored', msg='ignored'):
super(InterruptedSystemCall, self).__init__(EINTR)
def __str__(self):
s = super(InterruptedSystemCall, self).__str__()
return s + ": This call should have been retried. Please report this to pyzmq."
def _check_rc(rc, errno=None):
"""internal utility for checking zmq return condition
and raising the appropriate Exception class
"""
if rc == -1:
if errno is None:
from zmq.backend import zmq_errno
errno = zmq_errno()
from zmq import EAGAIN, ETERM
if errno == EINTR:
raise InterruptedSystemCall(errno)
elif errno == EAGAIN:
raise Again(errno)
elif errno == ETERM:
raise ContextTerminated(errno)
else:
raise ZMQError(errno)
_zmq_version_info = None
_zmq_version = None
class ZMQVersionError(NotImplementedError):
"""Raised when a feature is not provided by the linked version of libzmq.
.. versionadded:: 14.2
"""
min_version = None
def __init__(self, min_version, msg='Feature'):
global _zmq_version
if _zmq_version is None:
from zmq import zmq_version
_zmq_version = zmq_version()
self.msg = msg
self.min_version = min_version
self.version = _zmq_version
def __repr__(self):
return "ZMQVersionError('%s')" % str(self)
def __str__(self):
return "%s requires libzmq >= %s, have %s" % (self.msg, self.min_version, self.version)
def _check_version(min_version_info, msg='Feature'):
"""Check for libzmq
raises ZMQVersionError if current zmq version is not at least min_version
min_version_info is a tuple of integers, and will be compared against zmq.zmq_version_info().
"""
global _zmq_version_info
if _zmq_version_info is None:
from zmq import zmq_version_info
_zmq_version_info = zmq_version_info()
if _zmq_version_info < min_version_info:
min_version = '.'.join(str(v) for v in min_version_info)
raise ZMQVersionError(min_version, msg)
__all__ = [
'ZMQBaseError',
'ZMQBindError',
'ZMQError',
'NotDone',
'ContextTerminated',
'InterruptedSystemCall',
'Again',
'ZMQVersionError',
]

View file

@ -0,0 +1,5 @@
"""Tornado eventloop integration for pyzmq"""
from zmq.eventloop.ioloop import IOLoop
__all__ = ['IOLoop']

View file

@ -0,0 +1,214 @@
# coding: utf-8
"""tornado IOLoop API with zmq compatibility
If you have tornado 3.0, this is a subclass of tornado's IOLoop,
otherwise we ship a minimal subset of tornado in zmq.eventloop.minitornado.
The minimal shipped version of tornado's IOLoop does not include
support for concurrent futures - this will only be available if you
have tornado 3.0.
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from __future__ import absolute_import, division, with_statement
import os
import time
import warnings
from zmq import (
Poller,
POLLIN, POLLOUT, POLLERR,
ZMQError, ETERM,
)
try:
import tornado
tornado_version = tornado.version_info
except (ImportError, AttributeError):
tornado_version = ()
from .minitornado.ioloop import PollIOLoop, PeriodicCallback
from .minitornado.log import gen_log
class DelayedCallback(PeriodicCallback):
"""Schedules the given callback to be called once.
The callback is called once, after callback_time milliseconds.
`start` must be called after the DelayedCallback is created.
The timeout is calculated from when `start` is called.
"""
def __init__(self, callback, callback_time, io_loop=None):
# PeriodicCallback require callback_time to be positive
warnings.warn("""DelayedCallback is deprecated.
Use loop.add_timeout instead.""", DeprecationWarning)
callback_time = max(callback_time, 1e-3)
super(DelayedCallback, self).__init__(callback, callback_time, io_loop)
def start(self):
"""Starts the timer."""
self._running = True
self._firstrun = True
self._next_timeout = time.time() + self.callback_time / 1000.0
self.io_loop.add_timeout(self._next_timeout, self._run)
def _run(self):
if not self._running: return
self._running = False
try:
self.callback()
except Exception:
gen_log.error("Error in delayed callback", exc_info=True)
class ZMQPoller(object):
"""A poller that can be used in the tornado IOLoop.
This simply wraps a regular zmq.Poller, scaling the timeout
by 1000, so that it is in seconds rather than milliseconds.
"""
def __init__(self):
self._poller = Poller()
@staticmethod
def _map_events(events):
"""translate IOLoop.READ/WRITE/ERROR event masks into zmq.POLLIN/OUT/ERR"""
z_events = 0
if events & IOLoop.READ:
z_events |= POLLIN
if events & IOLoop.WRITE:
z_events |= POLLOUT
if events & IOLoop.ERROR:
z_events |= POLLERR
return z_events
@staticmethod
def _remap_events(z_events):
"""translate zmq.POLLIN/OUT/ERR event masks into IOLoop.READ/WRITE/ERROR"""
events = 0
if z_events & POLLIN:
events |= IOLoop.READ
if z_events & POLLOUT:
events |= IOLoop.WRITE
if z_events & POLLERR:
events |= IOLoop.ERROR
return events
def register(self, fd, events):
return self._poller.register(fd, self._map_events(events))
def modify(self, fd, events):
return self._poller.modify(fd, self._map_events(events))
def unregister(self, fd):
return self._poller.unregister(fd)
def poll(self, timeout):
"""poll in seconds rather than milliseconds.
Event masks will be IOLoop.READ/WRITE/ERROR
"""
z_events = self._poller.poll(1000*timeout)
return [ (fd,self._remap_events(evt)) for (fd,evt) in z_events ]
def close(self):
pass
class ZMQIOLoop(PollIOLoop):
"""ZMQ subclass of tornado's IOLoop
Minor modifications, so that .current/.instance return self
"""
_zmq_impl = ZMQPoller
def initialize(self, impl=None, **kwargs):
impl = self._zmq_impl() if impl is None else impl
super(ZMQIOLoop, self).initialize(impl=impl, **kwargs)
@classmethod
def instance(cls, *args, **kwargs):
"""Returns a global `IOLoop` instance.
Most applications have a single, global `IOLoop` running on the
main thread. Use this method to get this instance from
another thread. To get the current thread's `IOLoop`, use `current()`.
"""
# install ZMQIOLoop as the active IOLoop implementation
# when using tornado 3
if tornado_version >= (3,):
PollIOLoop.configure(cls)
loop = PollIOLoop.instance(*args, **kwargs)
if not isinstance(loop, cls):
warnings.warn("IOLoop.current expected instance of %r, got %r" % (cls, loop),
RuntimeWarning, stacklevel=2,
)
return loop
@classmethod
def current(cls, *args, **kwargs):
"""Returns the current threads IOLoop.
"""
# install ZMQIOLoop as the active IOLoop implementation
# when using tornado 3
if tornado_version >= (3,):
PollIOLoop.configure(cls)
loop = PollIOLoop.current(*args, **kwargs)
if not isinstance(loop, cls):
warnings.warn("IOLoop.current expected instance of %r, got %r" % (cls, loop),
RuntimeWarning, stacklevel=2,
)
return loop
def start(self):
try:
super(ZMQIOLoop, self).start()
except ZMQError as e:
if e.errno == ETERM:
# quietly return on ETERM
pass
else:
raise
if (3, 0) <= tornado_version < (3, 1):
def backport_close(self, all_fds=False):
"""backport IOLoop.close to 3.0 from 3.1 (supports fd.close() method)"""
from zmq.eventloop.minitornado.ioloop import PollIOLoop as mini_loop
return mini_loop.close.__get__(self)(all_fds)
ZMQIOLoop.close = backport_close
# public API name
IOLoop = ZMQIOLoop
def install():
"""set the tornado IOLoop instance with the pyzmq IOLoop.
After calling this function, tornado's IOLoop.instance() and pyzmq's
IOLoop.instance() will return the same object.
An assertion error will be raised if tornado's IOLoop has been initialized
prior to calling this function.
"""
from tornado import ioloop
# check if tornado's IOLoop is already initialized to something other
# than the pyzmq IOLoop instance:
assert (not ioloop.IOLoop.initialized()) or \
ioloop.IOLoop.instance() is IOLoop.instance(), "tornado IOLoop already initialized"
if tornado_version >= (3,):
# tornado 3 has an official API for registering new defaults, yay!
ioloop.IOLoop.configure(ZMQIOLoop)
else:
# we have to set the global instance explicitly
ioloop.IOLoop._instance = IOLoop.instance()

View file

@ -0,0 +1,73 @@
"""Future-returning APIs for tornado coroutines.
.. seealso::
:mod:`zmq.asyncio`
"""
# Copyright (c) PyZMQ Developers.
# Distributed under the terms of the Modified BSD License.
import zmq as _zmq
from zmq._future import _AsyncPoller, _AsyncSocket
from tornado.concurrent import Future
from tornado.ioloop import IOLoop
class CancelledError(Exception):
pass
class _TornadoFuture(Future):
"""Subclass Tornado Future, reinstating cancellation."""
def cancel(self):
if self.done():
return False
self.set_exception(CancelledError())
return True
def cancelled(self):
return self.done() and isinstance(self.exception(), CancelledError)
# mixin for tornado/asyncio compatibility
class _AsyncTornado(object):
_Future = _TornadoFuture
_READ = IOLoop.READ
_WRITE = IOLoop.WRITE
def _default_loop(self):
return IOLoop.current()
class Poller(_AsyncTornado, _AsyncPoller):
def _watch_raw_socket(self, loop, socket, evt, f):
"""Schedule callback for a raw socket"""
loop.add_handler(socket, lambda *args: f(), evt)
def _unwatch_raw_sockets(self, loop, *sockets):
"""Unschedule callback for a raw socket"""
for socket in sockets:
loop.remove_handler(socket)
class Socket(_AsyncTornado, _AsyncSocket):
_poller_class = Poller
Poller._socket_class = Socket
class Context(_zmq.Context):
# avoid sharing instance with base Context class
_instance = None
io_loop = None
@staticmethod
def _socket_class(self, socket_type):
return Socket(self, socket_type, io_loop=self.io_loop)
def __init__(self, *args, **kwargs):
io_loop = kwargs.pop('io_loop', None)
super(Context, self).__init__(*args, **kwargs)
self.io_loop = io_loop or IOLoop.current()

View file

@ -0,0 +1,136 @@
# coding: utf-8
"""tornado IOLoop API with zmq compatibility
This module is deprecated in pyzmq 17.
To use zmq with tornado,
eventloop integration is no longer required
and tornado itself should be used.
"""
# Copyright (C) PyZMQ Developers
# Distributed under the terms of the Modified BSD License.
from __future__ import absolute_import, division, with_statement
import time
import warnings
try:
import tornado
from tornado.log import gen_log
from tornado import ioloop
if not hasattr(ioloop.IOLoop, 'configurable_default'):
raise ImportError("Tornado too old: %s" % getattr(tornado, 'version', 'unknown'))
except ImportError:
from .minitornado import ioloop
from .minitornado.log import gen_log
PeriodicCallback = ioloop.PeriodicCallback
class DelayedCallback(PeriodicCallback):
"""Schedules the given callback to be called once.
The callback is called once, after callback_time milliseconds.
`start` must be called after the DelayedCallback is created.
The timeout is calculated from when `start` is called.
"""
def __init__(self, callback, callback_time, io_loop=None):
# PeriodicCallback require callback_time to be positive
warnings.warn("""DelayedCallback is deprecated.
Use loop.add_timeout instead.""", DeprecationWarning)
callback_time = max(callback_time, 1e-3)
super(DelayedCallback, self).__init__(callback, callback_time, io_loop)
def start(self):
"""Starts the timer."""
self._running = True
self._firstrun = True
self._next_timeout = time.time() + self.callback_time / 1000.0
self.io_loop.add_timeout(self._next_timeout, self._run)
def _run(self):
if not self._running: return
self._running = False
try:
self.callback()
except Exception:
gen_log.error("Error in delayed callback", exc_info=True)
def _deprecated():
if _deprecated.called:
return
_deprecated.called = True
warnings.warn("zmq.eventloop.ioloop is deprecated in pyzmq 17."
" pyzmq now works with default tornado and asyncio eventloops.",
DeprecationWarning, stacklevel=3)
_deprecated.called = False
# resolve 'true' default loop
if '.minitornado.' in ioloop.__name__:
from ._deprecated import ZMQIOLoop as _IOLoop
else:
_IOLoop = ioloop.IOLoop
while _IOLoop.configurable_default() is not _IOLoop:
_IOLoop = _IOLoop.configurable_default()
class ZMQIOLoop(_IOLoop):
"""DEPRECATED: No longer needed as of pyzmq-17
PyZMQ tornado integration now works with the default :mod:`tornado.ioloop.IOLoop`.
"""
def __init__(self, *args, **kwargs):
_deprecated()
# super is object, which takes no args
return super(ZMQIOLoop, self).__init__()
@classmethod
def instance(cls, *args, **kwargs):
"""Returns a global `IOLoop` instance.
Most applications have a single, global `IOLoop` running on the
main thread. Use this method to get this instance from
another thread. To get the current thread's `IOLoop`, use `current()`.
"""
# install ZMQIOLoop as the active IOLoop implementation
# when using tornado 3
ioloop.IOLoop.configure(cls)
_deprecated()
loop = ioloop.IOLoop.instance(*args, **kwargs)
return loop
@classmethod
def current(cls, *args, **kwargs):
"""Returns the current threads IOLoop.
"""
# install ZMQIOLoop as the active IOLoop implementation
# when using tornado 3
ioloop.IOLoop.configure(cls)
_deprecated()
loop = ioloop.IOLoop.current(*args, **kwargs)
return loop
# public API name
IOLoop = ZMQIOLoop
def install():
"""DEPRECATED
pyzmq 17 no longer needs any special integration for tornado.
"""
_deprecated()
ioloop.IOLoop.configure(ZMQIOLoop)
# if minitornado is used, fallback on deprecated ZMQIOLoop, install implementations
if '.minitornado.' in ioloop.__name__:
from ._deprecated import ZMQIOLoop, install, IOLoop

View file

@ -0,0 +1,11 @@
import warnings
class VisibleDeprecationWarning(UserWarning):
"""A DeprecationWarning that users should see."""
pass
warnings.warn("""zmq.eventloop.minitornado is deprecated in pyzmq 14.0 and will be removed.
Install tornado itself to use zmq with the tornado IOLoop.
""",
VisibleDeprecationWarning,
stacklevel=4,
)

Some files were not shown because too many files have changed in this diff Show more