diff --git a/Thirdparty/zeromq/BUILD_INFO b/Thirdparty/zeromq/BUILD_INFO new file mode 100644 index 0000000..98d0817 --- /dev/null +++ b/Thirdparty/zeromq/BUILD_INFO @@ -0,0 +1,2 @@ +CRTLinkage: dynamic +LibraryLinkage: dynamic diff --git a/Thirdparty/zeromq/CONTROL b/Thirdparty/zeromq/CONTROL new file mode 100644 index 0000000..d538cc6 --- /dev/null +++ b/Thirdparty/zeromq/CONTROL @@ -0,0 +1,8 @@ +Package: zeromq +Version: 4.3.5 +Port-Version: 1 +Depends: vcpkg-cmake, vcpkg-cmake-config +Architecture: x64-windows +Multi-Arch: same +Abi: 48055f4994a97a653c3cbc44973eeba770ab272f83c012f810b1343e1b945c7a +Description: The ZeroMQ lightweight messaging kernel is a library which extends the standard socket interfaces with features traditionally provided by specialised messaging middleware products diff --git a/Thirdparty/zeromq/debug/lib/libzmq-mt-gd-4_3_5.lib b/Thirdparty/zeromq/debug/lib/libzmq-mt-gd-4_3_5.lib new file mode 100644 index 0000000..77a0ebb Binary files /dev/null and b/Thirdparty/zeromq/debug/lib/libzmq-mt-gd-4_3_5.lib differ diff --git a/Thirdparty/zeromq/debug/lib/pkgconfig/libzmq.pc b/Thirdparty/zeromq/debug/lib/pkgconfig/libzmq.pc new file mode 100644 index 0000000..8719006 --- /dev/null +++ b/Thirdparty/zeromq/debug/lib/pkgconfig/libzmq.pc @@ -0,0 +1,13 @@ +prefix=${pcfiledir}/../.. +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/../include + +Name: libzmq +Description: 0MQ c++ library +Version: 4.3.5 +Libs: "-L${libdir}" -lzmq +Libs.private: -lstdc++ +Requires.private: +Cflags: "-I${includedir}" + diff --git a/Thirdparty/zeromq/include/zmq.h b/Thirdparty/zeromq/include/zmq.h new file mode 100644 index 0000000..6520b07 --- /dev/null +++ b/Thirdparty/zeromq/include/zmq.h @@ -0,0 +1,787 @@ +/* SPDX-License-Identifier: MPL-2.0 */ +/* ************************************************************************* + NOTE to contributors. This file comprises the principal public contract + for ZeroMQ API users. Any change to this file supplied in a stable + release SHOULD not break existing applications. + In practice this means that the value of constants must not change, and + that old values may not be reused for new constants. + ************************************************************************* +*/ + +#ifndef __ZMQ_H_INCLUDED__ +#define __ZMQ_H_INCLUDED__ + +/* Version macros for compile-time API version detection */ +#define ZMQ_VERSION_MAJOR 4 +#define ZMQ_VERSION_MINOR 3 +#define ZMQ_VERSION_PATCH 5 + +#define ZMQ_MAKE_VERSION(major, minor, patch) \ + ((major) *10000 + (minor) *100 + (patch)) +#define ZMQ_VERSION \ + ZMQ_MAKE_VERSION (ZMQ_VERSION_MAJOR, ZMQ_VERSION_MINOR, ZMQ_VERSION_PATCH) + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined _WIN32_WCE +#include +#endif +#include +#include + +/* Handle DSO symbol visibility */ +#if defined ZMQ_NO_EXPORT +#define ZMQ_EXPORT +#else +#if defined _WIN32 +#if defined ZMQ_STATIC +#define ZMQ_EXPORT +#elif defined DLL_EXPORT +#define ZMQ_EXPORT __declspec(dllexport) +#else +#define ZMQ_EXPORT __declspec(dllimport) +#endif +#else +#if defined __SUNPRO_C || defined __SUNPRO_CC +#define ZMQ_EXPORT __global +#elif (defined __GNUC__ && __GNUC__ >= 4) || defined __INTEL_COMPILER +#define ZMQ_EXPORT __attribute__ ((visibility ("default"))) +#else +#define ZMQ_EXPORT +#endif +#endif +#endif + +/* Define integer types needed for event interface */ +#define ZMQ_DEFINED_STDINT 1 +#if defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_OPENVMS +#include +#elif defined _MSC_VER && _MSC_VER < 1600 +#ifndef uint64_t +typedef unsigned __int64 uint64_t; +#endif +#ifndef int32_t +typedef __int32 int32_t; +#endif +#ifndef uint32_t +typedef unsigned __int32 uint32_t; +#endif +#ifndef uint16_t +typedef unsigned __int16 uint16_t; +#endif +#ifndef uint8_t +typedef unsigned __int8 uint8_t; +#endif +#else +#include +#endif + +#if !defined _WIN32 +// needed for sigset_t definition in zmq_ppoll +#include +#endif + +// 32-bit AIX's pollfd struct members are called reqevents and rtnevents so it +// defines compatibility macros for them. Need to include that header first to +// stop build failures since zmq_pollset_t defines them as events and revents. +#ifdef ZMQ_HAVE_AIX +#include +#endif + + +/******************************************************************************/ +/* 0MQ errors. */ +/******************************************************************************/ + +/* A number random enough not to collide with different errno ranges on */ +/* different OSes. The assumption is that error_t is at least 32-bit type. */ +#define ZMQ_HAUSNUMERO 156384712 + +/* On Windows platform some of the standard POSIX errnos are not defined. */ +#ifndef ENOTSUP +#define ENOTSUP (ZMQ_HAUSNUMERO + 1) +#endif +#ifndef EPROTONOSUPPORT +#define EPROTONOSUPPORT (ZMQ_HAUSNUMERO + 2) +#endif +#ifndef ENOBUFS +#define ENOBUFS (ZMQ_HAUSNUMERO + 3) +#endif +#ifndef ENETDOWN +#define ENETDOWN (ZMQ_HAUSNUMERO + 4) +#endif +#ifndef EADDRINUSE +#define EADDRINUSE (ZMQ_HAUSNUMERO + 5) +#endif +#ifndef EADDRNOTAVAIL +#define EADDRNOTAVAIL (ZMQ_HAUSNUMERO + 6) +#endif +#ifndef ECONNREFUSED +#define ECONNREFUSED (ZMQ_HAUSNUMERO + 7) +#endif +#ifndef EINPROGRESS +#define EINPROGRESS (ZMQ_HAUSNUMERO + 8) +#endif +#ifndef ENOTSOCK +#define ENOTSOCK (ZMQ_HAUSNUMERO + 9) +#endif +#ifndef EMSGSIZE +#define EMSGSIZE (ZMQ_HAUSNUMERO + 10) +#endif +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT (ZMQ_HAUSNUMERO + 11) +#endif +#ifndef ENETUNREACH +#define ENETUNREACH (ZMQ_HAUSNUMERO + 12) +#endif +#ifndef ECONNABORTED +#define ECONNABORTED (ZMQ_HAUSNUMERO + 13) +#endif +#ifndef ECONNRESET +#define ECONNRESET (ZMQ_HAUSNUMERO + 14) +#endif +#ifndef ENOTCONN +#define ENOTCONN (ZMQ_HAUSNUMERO + 15) +#endif +#ifndef ETIMEDOUT +#define ETIMEDOUT (ZMQ_HAUSNUMERO + 16) +#endif +#ifndef EHOSTUNREACH +#define EHOSTUNREACH (ZMQ_HAUSNUMERO + 17) +#endif +#ifndef ENETRESET +#define ENETRESET (ZMQ_HAUSNUMERO + 18) +#endif + +/* Native 0MQ error codes. */ +#define EFSM (ZMQ_HAUSNUMERO + 51) +#define ENOCOMPATPROTO (ZMQ_HAUSNUMERO + 52) +#define ETERM (ZMQ_HAUSNUMERO + 53) +#define EMTHREAD (ZMQ_HAUSNUMERO + 54) + +/* This function retrieves the errno as it is known to 0MQ library. The goal */ +/* of this function is to make the code 100% portable, including where 0MQ */ +/* compiled with certain CRT library (on Windows) is linked to an */ +/* application that uses different CRT library. */ +ZMQ_EXPORT int zmq_errno (void); + +/* Resolves system errors and 0MQ errors to human-readable string. */ +ZMQ_EXPORT const char *zmq_strerror (int errnum_); + +/* Run-time API version detection */ +ZMQ_EXPORT void zmq_version (int *major_, int *minor_, int *patch_); + +/******************************************************************************/ +/* 0MQ infrastructure (a.k.a. context) initialisation & termination. */ +/******************************************************************************/ + +/* Context options */ +#define ZMQ_IO_THREADS 1 +#define ZMQ_MAX_SOCKETS 2 +#define ZMQ_SOCKET_LIMIT 3 +#define ZMQ_THREAD_PRIORITY 3 +#define ZMQ_THREAD_SCHED_POLICY 4 +#define ZMQ_MAX_MSGSZ 5 +#define ZMQ_MSG_T_SIZE 6 +#define ZMQ_THREAD_AFFINITY_CPU_ADD 7 +#define ZMQ_THREAD_AFFINITY_CPU_REMOVE 8 +#define ZMQ_THREAD_NAME_PREFIX 9 + +/* Default for new contexts */ +#define ZMQ_IO_THREADS_DFLT 1 +#define ZMQ_MAX_SOCKETS_DFLT 1023 +#define ZMQ_THREAD_PRIORITY_DFLT -1 +#define ZMQ_THREAD_SCHED_POLICY_DFLT -1 + +ZMQ_EXPORT void *zmq_ctx_new (void); +ZMQ_EXPORT int zmq_ctx_term (void *context_); +ZMQ_EXPORT int zmq_ctx_shutdown (void *context_); +ZMQ_EXPORT int zmq_ctx_set (void *context_, int option_, int optval_); +ZMQ_EXPORT int zmq_ctx_get (void *context_, int option_); + +/* Old (legacy) API */ +ZMQ_EXPORT void *zmq_init (int io_threads_); +ZMQ_EXPORT int zmq_term (void *context_); +ZMQ_EXPORT int zmq_ctx_destroy (void *context_); + + +/******************************************************************************/ +/* 0MQ message definition. */ +/******************************************************************************/ + +/* Some architectures, like sparc64 and some variants of aarch64, enforce pointer + * alignment and raise sigbus on violations. Make sure applications allocate + * zmq_msg_t on addresses aligned on a pointer-size boundary to avoid this issue. + */ +typedef struct zmq_msg_t +{ +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM64)) + __declspec(align (8)) unsigned char _[64]; +#elif defined(_MSC_VER) \ + && (defined(_M_IX86) || defined(_M_ARM_ARMV7VE) || defined(_M_ARM)) + __declspec(align (4)) unsigned char _[64]; +#elif defined(__GNUC__) || defined(__INTEL_COMPILER) \ + || (defined(__SUNPRO_C) && __SUNPRO_C >= 0x590) \ + || (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x590) + unsigned char _[64] __attribute__ ((aligned (sizeof (void *)))); +#else + unsigned char _[64]; +#endif +} zmq_msg_t; + +typedef void (zmq_free_fn) (void *data_, void *hint_); + +ZMQ_EXPORT int zmq_msg_init (zmq_msg_t *msg_); +ZMQ_EXPORT int zmq_msg_init_size (zmq_msg_t *msg_, size_t size_); +ZMQ_EXPORT int zmq_msg_init_data ( + zmq_msg_t *msg_, void *data_, size_t size_, zmq_free_fn *ffn_, void *hint_); +ZMQ_EXPORT int zmq_msg_send (zmq_msg_t *msg_, void *s_, int flags_); +ZMQ_EXPORT int zmq_msg_recv (zmq_msg_t *msg_, void *s_, int flags_); +ZMQ_EXPORT int zmq_msg_close (zmq_msg_t *msg_); +ZMQ_EXPORT int zmq_msg_move (zmq_msg_t *dest_, zmq_msg_t *src_); +ZMQ_EXPORT int zmq_msg_copy (zmq_msg_t *dest_, zmq_msg_t *src_); +ZMQ_EXPORT void *zmq_msg_data (zmq_msg_t *msg_); +ZMQ_EXPORT size_t zmq_msg_size (const zmq_msg_t *msg_); +ZMQ_EXPORT int zmq_msg_more (const zmq_msg_t *msg_); +ZMQ_EXPORT int zmq_msg_get (const zmq_msg_t *msg_, int property_); +ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg_, int property_, int optval_); +ZMQ_EXPORT const char *zmq_msg_gets (const zmq_msg_t *msg_, + const char *property_); + +/******************************************************************************/ +/* 0MQ socket definition. */ +/******************************************************************************/ + +/* Socket types. */ +#define ZMQ_PAIR 0 +#define ZMQ_PUB 1 +#define ZMQ_SUB 2 +#define ZMQ_REQ 3 +#define ZMQ_REP 4 +#define ZMQ_DEALER 5 +#define ZMQ_ROUTER 6 +#define ZMQ_PULL 7 +#define ZMQ_PUSH 8 +#define ZMQ_XPUB 9 +#define ZMQ_XSUB 10 +#define ZMQ_STREAM 11 + +/* Deprecated aliases */ +#define ZMQ_XREQ ZMQ_DEALER +#define ZMQ_XREP ZMQ_ROUTER + +/* Socket options. */ +#define ZMQ_AFFINITY 4 +#define ZMQ_ROUTING_ID 5 +#define ZMQ_SUBSCRIBE 6 +#define ZMQ_UNSUBSCRIBE 7 +#define ZMQ_RATE 8 +#define ZMQ_RECOVERY_IVL 9 +#define ZMQ_SNDBUF 11 +#define ZMQ_RCVBUF 12 +#define ZMQ_RCVMORE 13 +#define ZMQ_FD 14 +#define ZMQ_EVENTS 15 +#define ZMQ_TYPE 16 +#define ZMQ_LINGER 17 +#define ZMQ_RECONNECT_IVL 18 +#define ZMQ_BACKLOG 19 +#define ZMQ_RECONNECT_IVL_MAX 21 +#define ZMQ_MAXMSGSIZE 22 +#define ZMQ_SNDHWM 23 +#define ZMQ_RCVHWM 24 +#define ZMQ_MULTICAST_HOPS 25 +#define ZMQ_RCVTIMEO 27 +#define ZMQ_SNDTIMEO 28 +#define ZMQ_LAST_ENDPOINT 32 +#define ZMQ_ROUTER_MANDATORY 33 +#define ZMQ_TCP_KEEPALIVE 34 +#define ZMQ_TCP_KEEPALIVE_CNT 35 +#define ZMQ_TCP_KEEPALIVE_IDLE 36 +#define ZMQ_TCP_KEEPALIVE_INTVL 37 +#define ZMQ_IMMEDIATE 39 +#define ZMQ_XPUB_VERBOSE 40 +#define ZMQ_ROUTER_RAW 41 +#define ZMQ_IPV6 42 +#define ZMQ_MECHANISM 43 +#define ZMQ_PLAIN_SERVER 44 +#define ZMQ_PLAIN_USERNAME 45 +#define ZMQ_PLAIN_PASSWORD 46 +#define ZMQ_CURVE_SERVER 47 +#define ZMQ_CURVE_PUBLICKEY 48 +#define ZMQ_CURVE_SECRETKEY 49 +#define ZMQ_CURVE_SERVERKEY 50 +#define ZMQ_PROBE_ROUTER 51 +#define ZMQ_REQ_CORRELATE 52 +#define ZMQ_REQ_RELAXED 53 +#define ZMQ_CONFLATE 54 +#define ZMQ_ZAP_DOMAIN 55 +#define ZMQ_ROUTER_HANDOVER 56 +#define ZMQ_TOS 57 +#define ZMQ_CONNECT_ROUTING_ID 61 +#define ZMQ_GSSAPI_SERVER 62 +#define ZMQ_GSSAPI_PRINCIPAL 63 +#define ZMQ_GSSAPI_SERVICE_PRINCIPAL 64 +#define ZMQ_GSSAPI_PLAINTEXT 65 +#define ZMQ_HANDSHAKE_IVL 66 +#define ZMQ_SOCKS_PROXY 68 +#define ZMQ_XPUB_NODROP 69 +#define ZMQ_BLOCKY 70 +#define ZMQ_XPUB_MANUAL 71 +#define ZMQ_XPUB_WELCOME_MSG 72 +#define ZMQ_STREAM_NOTIFY 73 +#define ZMQ_INVERT_MATCHING 74 +#define ZMQ_HEARTBEAT_IVL 75 +#define ZMQ_HEARTBEAT_TTL 76 +#define ZMQ_HEARTBEAT_TIMEOUT 77 +#define ZMQ_XPUB_VERBOSER 78 +#define ZMQ_CONNECT_TIMEOUT 79 +#define ZMQ_TCP_MAXRT 80 +#define ZMQ_THREAD_SAFE 81 +#define ZMQ_MULTICAST_MAXTPDU 84 +#define ZMQ_VMCI_BUFFER_SIZE 85 +#define ZMQ_VMCI_BUFFER_MIN_SIZE 86 +#define ZMQ_VMCI_BUFFER_MAX_SIZE 87 +#define ZMQ_VMCI_CONNECT_TIMEOUT 88 +#define ZMQ_USE_FD 89 +#define ZMQ_GSSAPI_PRINCIPAL_NAMETYPE 90 +#define ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE 91 +#define ZMQ_BINDTODEVICE 92 + +/* Message options */ +#define ZMQ_MORE 1 +#define ZMQ_SHARED 3 + +/* Send/recv options. */ +#define ZMQ_DONTWAIT 1 +#define ZMQ_SNDMORE 2 + +/* Security mechanisms */ +#define ZMQ_NULL 0 +#define ZMQ_PLAIN 1 +#define ZMQ_CURVE 2 +#define ZMQ_GSSAPI 3 + +/* RADIO-DISH protocol */ +#define ZMQ_GROUP_MAX_LENGTH 255 + +/* Deprecated options and aliases */ +#define ZMQ_IDENTITY ZMQ_ROUTING_ID +#define ZMQ_CONNECT_RID ZMQ_CONNECT_ROUTING_ID +#define ZMQ_TCP_ACCEPT_FILTER 38 +#define ZMQ_IPC_FILTER_PID 58 +#define ZMQ_IPC_FILTER_UID 59 +#define ZMQ_IPC_FILTER_GID 60 +#define ZMQ_IPV4ONLY 31 +#define ZMQ_DELAY_ATTACH_ON_CONNECT ZMQ_IMMEDIATE +#define ZMQ_NOBLOCK ZMQ_DONTWAIT +#define ZMQ_FAIL_UNROUTABLE ZMQ_ROUTER_MANDATORY +#define ZMQ_ROUTER_BEHAVIOR ZMQ_ROUTER_MANDATORY + +/* Deprecated Message options */ +#define ZMQ_SRCFD 2 + +/******************************************************************************/ +/* GSSAPI definitions */ +/******************************************************************************/ + +/* GSSAPI principal name types */ +#define ZMQ_GSSAPI_NT_HOSTBASED 0 +#define ZMQ_GSSAPI_NT_USER_NAME 1 +#define ZMQ_GSSAPI_NT_KRB5_PRINCIPAL 2 + +/******************************************************************************/ +/* 0MQ socket events and monitoring */ +/******************************************************************************/ + +/* Socket transport events (TCP, IPC and TIPC only) */ + +#define ZMQ_EVENT_CONNECTED 0x0001 +#define ZMQ_EVENT_CONNECT_DELAYED 0x0002 +#define ZMQ_EVENT_CONNECT_RETRIED 0x0004 +#define ZMQ_EVENT_LISTENING 0x0008 +#define ZMQ_EVENT_BIND_FAILED 0x0010 +#define ZMQ_EVENT_ACCEPTED 0x0020 +#define ZMQ_EVENT_ACCEPT_FAILED 0x0040 +#define ZMQ_EVENT_CLOSED 0x0080 +#define ZMQ_EVENT_CLOSE_FAILED 0x0100 +#define ZMQ_EVENT_DISCONNECTED 0x0200 +#define ZMQ_EVENT_MONITOR_STOPPED 0x0400 +#define ZMQ_EVENT_ALL 0xFFFF +/* Unspecified system errors during handshake. Event value is an errno. */ +#define ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL 0x0800 +/* Handshake complete successfully with successful authentication (if * + * enabled). Event value is unused. */ +#define ZMQ_EVENT_HANDSHAKE_SUCCEEDED 0x1000 +/* Protocol errors between ZMTP peers or between server and ZAP handler. * + * Event value is one of ZMQ_PROTOCOL_ERROR_* */ +#define ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL 0x2000 +/* Failed authentication requests. Event value is the numeric ZAP status * + * code, i.e. 300, 400 or 500. */ +#define ZMQ_EVENT_HANDSHAKE_FAILED_AUTH 0x4000 +#define ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED 0x10000000 +#define ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND 0x10000001 +#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE 0x10000002 +#define ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE 0x10000003 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED 0x10000011 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE 0x10000012 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO 0x10000013 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE 0x10000014 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR 0x10000015 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY 0x10000016 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME 0x10000017 +#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA 0x10000018 +// the following two may be due to erroneous configuration of a peer +#define ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC 0x11000001 +#define ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH 0x11000002 +#define ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED 0x20000000 +#define ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY 0x20000001 +#define ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID 0x20000002 +#define ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION 0x20000003 +#define ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE 0x20000004 +#define ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA 0x20000005 +#define ZMQ_PROTOCOL_ERROR_WS_UNSPECIFIED 0x30000000 + +ZMQ_EXPORT void *zmq_socket (void *, int type_); +ZMQ_EXPORT int zmq_close (void *s_); +ZMQ_EXPORT int +zmq_setsockopt (void *s_, int option_, const void *optval_, size_t optvallen_); +ZMQ_EXPORT int +zmq_getsockopt (void *s_, int option_, void *optval_, size_t *optvallen_); +ZMQ_EXPORT int zmq_bind (void *s_, const char *addr_); +ZMQ_EXPORT int zmq_connect (void *s_, const char *addr_); +ZMQ_EXPORT int zmq_unbind (void *s_, const char *addr_); +ZMQ_EXPORT int zmq_disconnect (void *s_, const char *addr_); +ZMQ_EXPORT int zmq_send (void *s_, const void *buf_, size_t len_, int flags_); +ZMQ_EXPORT int +zmq_send_const (void *s_, const void *buf_, size_t len_, int flags_); +ZMQ_EXPORT int zmq_recv (void *s_, void *buf_, size_t len_, int flags_); +ZMQ_EXPORT int zmq_socket_monitor (void *s_, const char *addr_, int events_); + +/******************************************************************************/ +/* Hide socket fd type; this was before zmq_poller_event_t typedef below */ +/******************************************************************************/ + +#if defined _WIN32 +// Windows uses a pointer-sized unsigned integer to store the socket fd. +#if defined _WIN64 +typedef unsigned __int64 zmq_fd_t; +#else +typedef unsigned int zmq_fd_t; +#endif +#else +typedef int zmq_fd_t; +#endif + +/******************************************************************************/ +/* Deprecated I/O multiplexing. Prefer using zmq_poller API */ +/******************************************************************************/ + +#define ZMQ_POLLIN 1 +#define ZMQ_POLLOUT 2 +#define ZMQ_POLLERR 4 +#define ZMQ_POLLPRI 8 + +typedef struct zmq_pollitem_t +{ + void *socket; + zmq_fd_t fd; + short events; + short revents; +} zmq_pollitem_t; + +#define ZMQ_POLLITEMS_DFLT 16 + +ZMQ_EXPORT int zmq_poll (zmq_pollitem_t *items_, int nitems_, long timeout_); + +/******************************************************************************/ +/* Message proxying */ +/******************************************************************************/ + +ZMQ_EXPORT int zmq_proxy (void *frontend_, void *backend_, void *capture_); +ZMQ_EXPORT int zmq_proxy_steerable (void *frontend_, + void *backend_, + void *capture_, + void *control_); + +/******************************************************************************/ +/* Probe library capabilities */ +/******************************************************************************/ + +#define ZMQ_HAS_CAPABILITIES 1 +ZMQ_EXPORT int zmq_has (const char *capability_); + +/* Deprecated aliases */ +#define ZMQ_STREAMER 1 +#define ZMQ_FORWARDER 2 +#define ZMQ_QUEUE 3 + +/* Deprecated methods */ +ZMQ_EXPORT int zmq_device (int type_, void *frontend_, void *backend_); +ZMQ_EXPORT int zmq_sendmsg (void *s_, zmq_msg_t *msg_, int flags_); +ZMQ_EXPORT int zmq_recvmsg (void *s_, zmq_msg_t *msg_, int flags_); +struct iovec; +ZMQ_EXPORT int +zmq_sendiov (void *s_, struct iovec *iov_, size_t count_, int flags_); +ZMQ_EXPORT int +zmq_recviov (void *s_, struct iovec *iov_, size_t *count_, int flags_); + +/******************************************************************************/ +/* Encryption functions */ +/******************************************************************************/ + +/* Encode data with Z85 encoding. Returns encoded data */ +ZMQ_EXPORT char * +zmq_z85_encode (char *dest_, const uint8_t *data_, size_t size_); + +/* Decode data with Z85 encoding. Returns decoded data */ +ZMQ_EXPORT uint8_t *zmq_z85_decode (uint8_t *dest_, const char *string_); + +/* Generate z85-encoded public and private keypair with libsodium. */ +/* Returns 0 on success. */ +ZMQ_EXPORT int zmq_curve_keypair (char *z85_public_key_, char *z85_secret_key_); + +/* Derive the z85-encoded public key from the z85-encoded secret key. */ +/* Returns 0 on success. */ +ZMQ_EXPORT int zmq_curve_public (char *z85_public_key_, + const char *z85_secret_key_); + +/******************************************************************************/ +/* Atomic utility methods */ +/******************************************************************************/ + +ZMQ_EXPORT void *zmq_atomic_counter_new (void); +ZMQ_EXPORT void zmq_atomic_counter_set (void *counter_, int value_); +ZMQ_EXPORT int zmq_atomic_counter_inc (void *counter_); +ZMQ_EXPORT int zmq_atomic_counter_dec (void *counter_); +ZMQ_EXPORT int zmq_atomic_counter_value (void *counter_); +ZMQ_EXPORT void zmq_atomic_counter_destroy (void **counter_p_); + +/******************************************************************************/ +/* Scheduling timers */ +/******************************************************************************/ + +#define ZMQ_HAVE_TIMERS + +typedef void (zmq_timer_fn) (int timer_id, void *arg); + +ZMQ_EXPORT void *zmq_timers_new (void); +ZMQ_EXPORT int zmq_timers_destroy (void **timers_p); +ZMQ_EXPORT int +zmq_timers_add (void *timers, size_t interval, zmq_timer_fn handler, void *arg); +ZMQ_EXPORT int zmq_timers_cancel (void *timers, int timer_id); +ZMQ_EXPORT int +zmq_timers_set_interval (void *timers, int timer_id, size_t interval); +ZMQ_EXPORT int zmq_timers_reset (void *timers, int timer_id); +ZMQ_EXPORT long zmq_timers_timeout (void *timers); +ZMQ_EXPORT int zmq_timers_execute (void *timers); + + +/******************************************************************************/ +/* These functions are not documented by man pages -- use at your own risk. */ +/* If you need these to be part of the formal ZMQ API, then (a) write a man */ +/* page, and (b) write a test case in tests. */ +/******************************************************************************/ + +/* Helper functions are used by perf tests so that they don't have to care */ +/* about minutiae of time-related functions on different OS platforms. */ + +/* Starts the stopwatch. Returns the handle to the watch. */ +ZMQ_EXPORT void *zmq_stopwatch_start (void); + +/* Returns the number of microseconds elapsed since the stopwatch was */ +/* started, but does not stop or deallocate the stopwatch. */ +ZMQ_EXPORT unsigned long zmq_stopwatch_intermediate (void *watch_); + +/* Stops the stopwatch. Returns the number of microseconds elapsed since */ +/* the stopwatch was started, and deallocates that watch. */ +ZMQ_EXPORT unsigned long zmq_stopwatch_stop (void *watch_); + +/* Sleeps for specified number of seconds. */ +ZMQ_EXPORT void zmq_sleep (int seconds_); + +typedef void (zmq_thread_fn) (void *); + +/* Start a thread. Returns a handle to the thread. */ +ZMQ_EXPORT void *zmq_threadstart (zmq_thread_fn *func_, void *arg_); + +/* Wait for thread to complete then free up resources. */ +ZMQ_EXPORT void zmq_threadclose (void *thread_); + + +/******************************************************************************/ +/* These functions are DRAFT and disabled in stable releases, and subject to */ +/* change at ANY time until declared stable. */ +/******************************************************************************/ + +#ifdef ZMQ_BUILD_DRAFT_API + +/* DRAFT Socket types. */ +#define ZMQ_SERVER 12 +#define ZMQ_CLIENT 13 +#define ZMQ_RADIO 14 +#define ZMQ_DISH 15 +#define ZMQ_GATHER 16 +#define ZMQ_SCATTER 17 +#define ZMQ_DGRAM 18 +#define ZMQ_PEER 19 +#define ZMQ_CHANNEL 20 + +/* DRAFT Socket options. */ +#define ZMQ_ZAP_ENFORCE_DOMAIN 93 +#define ZMQ_LOOPBACK_FASTPATH 94 +#define ZMQ_METADATA 95 +#define ZMQ_MULTICAST_LOOP 96 +#define ZMQ_ROUTER_NOTIFY 97 +#define ZMQ_XPUB_MANUAL_LAST_VALUE 98 +#define ZMQ_SOCKS_USERNAME 99 +#define ZMQ_SOCKS_PASSWORD 100 +#define ZMQ_IN_BATCH_SIZE 101 +#define ZMQ_OUT_BATCH_SIZE 102 +#define ZMQ_WSS_KEY_PEM 103 +#define ZMQ_WSS_CERT_PEM 104 +#define ZMQ_WSS_TRUST_PEM 105 +#define ZMQ_WSS_HOSTNAME 106 +#define ZMQ_WSS_TRUST_SYSTEM 107 +#define ZMQ_ONLY_FIRST_SUBSCRIBE 108 +#define ZMQ_RECONNECT_STOP 109 +#define ZMQ_HELLO_MSG 110 +#define ZMQ_DISCONNECT_MSG 111 +#define ZMQ_PRIORITY 112 +#define ZMQ_BUSY_POLL 113 +#define ZMQ_HICCUP_MSG 114 +#define ZMQ_XSUB_VERBOSE_UNSUBSCRIBE 115 +#define ZMQ_TOPICS_COUNT 116 +#define ZMQ_NORM_MODE 117 +#define ZMQ_NORM_UNICAST_NACK 118 +#define ZMQ_NORM_BUFFER_SIZE 119 +#define ZMQ_NORM_SEGMENT_SIZE 120 +#define ZMQ_NORM_BLOCK_SIZE 121 +#define ZMQ_NORM_NUM_PARITY 122 +#define ZMQ_NORM_NUM_AUTOPARITY 123 +#define ZMQ_NORM_PUSH 124 + +/* DRAFT ZMQ_NORM_MODE options */ +#define ZMQ_NORM_FIXED 0 +#define ZMQ_NORM_CC 1 +#define ZMQ_NORM_CCL 2 +#define ZMQ_NORM_CCE 3 +#define ZMQ_NORM_CCE_ECNONLY 4 + +/* DRAFT ZMQ_RECONNECT_STOP options */ +#define ZMQ_RECONNECT_STOP_CONN_REFUSED 0x1 +#define ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED 0x2 +#define ZMQ_RECONNECT_STOP_AFTER_DISCONNECT 0x4 + +/* DRAFT Context options */ +#define ZMQ_ZERO_COPY_RECV 10 + +/* DRAFT Context methods. */ +ZMQ_EXPORT int zmq_ctx_set_ext (void *context_, + int option_, + const void *optval_, + size_t optvallen_); +ZMQ_EXPORT int zmq_ctx_get_ext (void *context_, + int option_, + void *optval_, + size_t *optvallen_); + +/* DRAFT Socket methods. */ +ZMQ_EXPORT int zmq_join (void *s, const char *group); +ZMQ_EXPORT int zmq_leave (void *s, const char *group); +ZMQ_EXPORT uint32_t zmq_connect_peer (void *s_, const char *addr_); + +/* DRAFT Msg methods. */ +ZMQ_EXPORT int zmq_msg_set_routing_id (zmq_msg_t *msg, uint32_t routing_id); +ZMQ_EXPORT uint32_t zmq_msg_routing_id (zmq_msg_t *msg); +ZMQ_EXPORT int zmq_msg_set_group (zmq_msg_t *msg, const char *group); +ZMQ_EXPORT const char *zmq_msg_group (zmq_msg_t *msg); +ZMQ_EXPORT int +zmq_msg_init_buffer (zmq_msg_t *msg_, const void *buf_, size_t size_); + +/* DRAFT Msg property names. */ +#define ZMQ_MSG_PROPERTY_ROUTING_ID "Routing-Id" +#define ZMQ_MSG_PROPERTY_SOCKET_TYPE "Socket-Type" +#define ZMQ_MSG_PROPERTY_USER_ID "User-Id" +#define ZMQ_MSG_PROPERTY_PEER_ADDRESS "Peer-Address" + +/* Router notify options */ +#define ZMQ_NOTIFY_CONNECT 1 +#define ZMQ_NOTIFY_DISCONNECT 2 + +/******************************************************************************/ +/* Poller polling on sockets,fd and thread-safe sockets */ +/******************************************************************************/ + +#define ZMQ_HAVE_POLLER + +typedef struct zmq_poller_event_t +{ + void *socket; + zmq_fd_t fd; + void *user_data; + short events; +} zmq_poller_event_t; + +ZMQ_EXPORT void *zmq_poller_new (void); +ZMQ_EXPORT int zmq_poller_destroy (void **poller_p); +ZMQ_EXPORT int zmq_poller_size (void *poller); +ZMQ_EXPORT int +zmq_poller_add (void *poller, void *socket, void *user_data, short events); +ZMQ_EXPORT int zmq_poller_modify (void *poller, void *socket, short events); +ZMQ_EXPORT int zmq_poller_remove (void *poller, void *socket); +ZMQ_EXPORT int +zmq_poller_wait (void *poller, zmq_poller_event_t *event, long timeout); +ZMQ_EXPORT int zmq_poller_wait_all (void *poller, + zmq_poller_event_t *events, + int n_events, + long timeout); +ZMQ_EXPORT int zmq_poller_fd (void *poller, zmq_fd_t *fd); + +ZMQ_EXPORT int +zmq_poller_add_fd (void *poller, zmq_fd_t fd, void *user_data, short events); +ZMQ_EXPORT int zmq_poller_modify_fd (void *poller, zmq_fd_t fd, short events); +ZMQ_EXPORT int zmq_poller_remove_fd (void *poller, zmq_fd_t fd); + +ZMQ_EXPORT int zmq_socket_get_peer_state (void *socket, + const void *routing_id, + size_t routing_id_size); + +/* DRAFT Socket monitoring events */ +#define ZMQ_EVENT_PIPES_STATS 0x10000 + +#define ZMQ_CURRENT_EVENT_VERSION 1 +#define ZMQ_CURRENT_EVENT_VERSION_DRAFT 2 + +#define ZMQ_EVENT_ALL_V1 ZMQ_EVENT_ALL +#define ZMQ_EVENT_ALL_V2 ZMQ_EVENT_ALL_V1 | ZMQ_EVENT_PIPES_STATS + +ZMQ_EXPORT int zmq_socket_monitor_versioned ( + void *s_, const char *addr_, uint64_t events_, int event_version_, int type_); +ZMQ_EXPORT int zmq_socket_monitor_pipes_stats (void *s); + +#if !defined _WIN32 +ZMQ_EXPORT int zmq_ppoll (zmq_pollitem_t *items_, + int nitems_, + long timeout_, + const sigset_t *sigmask_); +#else +// Windows has no sigset_t +ZMQ_EXPORT int zmq_ppoll (zmq_pollitem_t *items_, + int nitems_, + long timeout_, + const void *sigmask_); +#endif + +#endif // ZMQ_BUILD_DRAFT_API + + +#undef ZMQ_EXPORT + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Thirdparty/zeromq/include/zmq.hpp b/Thirdparty/zeromq/include/zmq.hpp new file mode 100644 index 0000000..3fa484c --- /dev/null +++ b/Thirdparty/zeromq/include/zmq.hpp @@ -0,0 +1,2762 @@ +/* + Copyright (c) 2016-2017 ZeroMQ community + Copyright (c) 2009-2011 250bpm s.r.o. + Copyright (c) 2011 Botond Ballo + Copyright (c) 2007-2009 iMatix Corporation + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef __ZMQ_HPP_INCLUDED__ +#define __ZMQ_HPP_INCLUDED__ + +#ifdef _WIN32 +#ifndef NOMINMAX +#define NOMINMAX +#endif +#endif + +// included here for _HAS_CXX* macros +#include + +#if defined(_MSVC_LANG) +#define CPPZMQ_LANG _MSVC_LANG +#else +#define CPPZMQ_LANG __cplusplus +#endif +// overwrite if specific language macros indicate higher version +#if defined(_HAS_CXX14) && _HAS_CXX14 && CPPZMQ_LANG < 201402L +#undef CPPZMQ_LANG +#define CPPZMQ_LANG 201402L +#endif +#if defined(_HAS_CXX17) && _HAS_CXX17 && CPPZMQ_LANG < 201703L +#undef CPPZMQ_LANG +#define CPPZMQ_LANG 201703L +#endif + +// macros defined if has a specific standard or greater +#if CPPZMQ_LANG >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900) +#define ZMQ_CPP11 +#endif +#if CPPZMQ_LANG >= 201402L +#define ZMQ_CPP14 +#endif +#if CPPZMQ_LANG >= 201703L +#define ZMQ_CPP17 +#endif + +#if defined(ZMQ_CPP14) && !defined(_MSC_VER) +#define ZMQ_DEPRECATED(msg) [[deprecated(msg)]] +#elif defined(_MSC_VER) +#define ZMQ_DEPRECATED(msg) __declspec(deprecated(msg)) +#elif defined(__GNUC__) +#define ZMQ_DEPRECATED(msg) __attribute__((deprecated(msg))) +#else +#define ZMQ_DEPRECATED(msg) +#endif + +#if defined(ZMQ_CPP17) +#define ZMQ_NODISCARD [[nodiscard]] +#else +#define ZMQ_NODISCARD +#endif + +#if defined(ZMQ_CPP11) +#define ZMQ_NOTHROW noexcept +#define ZMQ_EXPLICIT explicit +#define ZMQ_OVERRIDE override +#define ZMQ_NULLPTR nullptr +#define ZMQ_CONSTEXPR_FN constexpr +#define ZMQ_CONSTEXPR_VAR constexpr +#define ZMQ_CPP11_DEPRECATED(msg) ZMQ_DEPRECATED(msg) +#else +#define ZMQ_NOTHROW throw() +#define ZMQ_EXPLICIT +#define ZMQ_OVERRIDE +#define ZMQ_NULLPTR 0 +#define ZMQ_CONSTEXPR_FN +#define ZMQ_CONSTEXPR_VAR const +#define ZMQ_CPP11_DEPRECATED(msg) +#endif +#if defined(ZMQ_CPP14) && (!defined(_MSC_VER) || _MSC_VER > 1900) && (!defined(__GNUC__) || __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3)) +#define ZMQ_EXTENDED_CONSTEXPR +#endif +#if defined(ZMQ_CPP17) +#define ZMQ_INLINE_VAR inline +#define ZMQ_CONSTEXPR_IF constexpr +#else +#define ZMQ_INLINE_VAR +#define ZMQ_CONSTEXPR_IF +#endif + +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef ZMQ_CPP11 +#include +#include +#include +#include +#endif + +#if defined(__has_include) && defined(ZMQ_CPP17) +#define CPPZMQ_HAS_INCLUDE_CPP17(X) __has_include(X) +#else +#define CPPZMQ_HAS_INCLUDE_CPP17(X) 0 +#endif + +#if CPPZMQ_HAS_INCLUDE_CPP17() && !defined(CPPZMQ_HAS_OPTIONAL) +#define CPPZMQ_HAS_OPTIONAL 1 +#endif +#ifndef CPPZMQ_HAS_OPTIONAL +#define CPPZMQ_HAS_OPTIONAL 0 +#elif CPPZMQ_HAS_OPTIONAL +#include +#endif + +#if CPPZMQ_HAS_INCLUDE_CPP17() && !defined(CPPZMQ_HAS_STRING_VIEW) +#define CPPZMQ_HAS_STRING_VIEW 1 +#endif +#ifndef CPPZMQ_HAS_STRING_VIEW +#define CPPZMQ_HAS_STRING_VIEW 0 +#elif CPPZMQ_HAS_STRING_VIEW +#include +#endif + +/* Version macros for compile-time API version detection */ +#define CPPZMQ_VERSION_MAJOR 4 +#define CPPZMQ_VERSION_MINOR 10 +#define CPPZMQ_VERSION_PATCH 0 + +#define CPPZMQ_VERSION \ + ZMQ_MAKE_VERSION(CPPZMQ_VERSION_MAJOR, CPPZMQ_VERSION_MINOR, \ + CPPZMQ_VERSION_PATCH) + +// Detect whether the compiler supports C++11 rvalue references. +#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) \ + && defined(__GXX_EXPERIMENTAL_CXX0X__)) +#define ZMQ_HAS_RVALUE_REFS +#define ZMQ_DELETED_FUNCTION = delete +#elif defined(__clang__) +#if __has_feature(cxx_rvalue_references) +#define ZMQ_HAS_RVALUE_REFS +#endif + +#if __has_feature(cxx_deleted_functions) +#define ZMQ_DELETED_FUNCTION = delete +#else +#define ZMQ_DELETED_FUNCTION +#endif +#elif defined(_MSC_VER) && (_MSC_VER >= 1900) +#define ZMQ_HAS_RVALUE_REFS +#define ZMQ_DELETED_FUNCTION = delete +#elif defined(_MSC_VER) && (_MSC_VER >= 1600) +#define ZMQ_HAS_RVALUE_REFS +#define ZMQ_DELETED_FUNCTION +#else +#define ZMQ_DELETED_FUNCTION +#endif + +#if defined(ZMQ_CPP11) && !defined(__llvm__) && !defined(__INTEL_COMPILER) \ + && defined(__GNUC__) && __GNUC__ < 5 +#define ZMQ_CPP11_PARTIAL +#elif defined(__GLIBCXX__) && __GLIBCXX__ < 20160805 +//the date here is the last date of gcc 4.9.4, which +// effectively means libstdc++ from gcc 5.5 and higher won't trigger this branch +#define ZMQ_CPP11_PARTIAL +#endif + +#ifdef ZMQ_CPP11 +#ifdef ZMQ_CPP11_PARTIAL +#define ZMQ_IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T) +#else +#include +#define ZMQ_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable::value +#endif +#endif + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 3, 0) +#define ZMQ_NEW_MONITOR_EVENT_LAYOUT +#endif + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0) +#define ZMQ_HAS_PROXY_STEERABLE +/* Socket event data */ +typedef struct +{ + uint16_t event; // id of the event as bitfield + int32_t value; // value is either error code, fd or reconnect interval +} zmq_event_t; +#endif + +// Avoid using deprecated message receive function when possible +#if ZMQ_VERSION < ZMQ_MAKE_VERSION(3, 2, 0) +#define zmq_msg_recv(msg, socket, flags) zmq_recvmsg(socket, msg, flags) +#endif + + +// In order to prevent unused variable warnings when building in non-debug +// mode use this macro to make assertions. +#ifndef NDEBUG +#define ZMQ_ASSERT(expression) assert(expression) +#else +#define ZMQ_ASSERT(expression) (void) (expression) +#endif + +namespace zmq +{ +#ifdef ZMQ_CPP11 +namespace detail +{ +namespace ranges +{ +using std::begin; +using std::end; +template auto begin(T &&r) -> decltype(begin(std::forward(r))) +{ + return begin(std::forward(r)); +} +template auto end(T &&r) -> decltype(end(std::forward(r))) +{ + return end(std::forward(r)); +} +} // namespace ranges + +template using void_t = void; + +template +using iter_value_t = typename std::iterator_traits::value_type; + +template +using range_iter_t = decltype( + ranges::begin(std::declval::type &>())); + +template using range_value_t = iter_value_t>; + +template struct is_range : std::false_type +{ +}; + +template +struct is_range< + T, + void_t::type &>()) + == ranges::end(std::declval::type &>()))>> + : std::true_type +{ +}; + +} // namespace detail +#endif + +typedef zmq_free_fn free_fn; +typedef zmq_pollitem_t pollitem_t; + +// duplicate definition from libzmq 4.3.3 +#if defined _WIN32 +#if defined _WIN64 +typedef unsigned __int64 fd_t; +#else +typedef unsigned int fd_t; +#endif +#else +typedef int fd_t; +#endif + +class error_t : public std::exception +{ + public: + error_t() ZMQ_NOTHROW : errnum(zmq_errno()) {} + explicit error_t(int err) ZMQ_NOTHROW : errnum(err) {} + virtual const char *what() const ZMQ_NOTHROW ZMQ_OVERRIDE + { + return zmq_strerror(errnum); + } + int num() const ZMQ_NOTHROW { return errnum; } + + private: + int errnum; +}; + +namespace detail { +inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_) +{ + int rc = zmq_poll(items_, static_cast(nitems_), timeout_); + if (rc < 0) + throw error_t(); + return rc; +} +} + +#ifdef ZMQ_CPP11 +ZMQ_DEPRECATED("from 4.8.0, use poll taking std::chrono::duration instead of long") +inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_) +#else +inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_ = -1) +#endif +{ + return detail::poll(items_, nitems_, timeout_); +} + +ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items") +inline int poll(zmq_pollitem_t const *items_, size_t nitems_, long timeout_ = -1) +{ + return detail::poll(const_cast(items_), nitems_, timeout_); +} + +#ifdef ZMQ_CPP11 +ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items") +inline int +poll(zmq_pollitem_t const *items, size_t nitems, std::chrono::milliseconds timeout) +{ + return detail::poll(const_cast(items), nitems, + static_cast(timeout.count())); +} + +ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items") +inline int poll(std::vector const &items, + std::chrono::milliseconds timeout) +{ + return detail::poll(const_cast(items.data()), items.size(), + static_cast(timeout.count())); +} + +ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items") +inline int poll(std::vector const &items, long timeout_ = -1) +{ + return detail::poll(const_cast(items.data()), items.size(), timeout_); +} + +inline int +poll(zmq_pollitem_t *items, size_t nitems, std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}) +{ + return detail::poll(items, nitems, static_cast(timeout.count())); +} + +inline int poll(std::vector &items, + std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}) +{ + return detail::poll(items.data(), items.size(), static_cast(timeout.count())); +} + +ZMQ_DEPRECATED("from 4.3.1, use poll taking std::chrono::duration instead of long") +inline int poll(std::vector &items, long timeout_) +{ + return detail::poll(items.data(), items.size(), timeout_); +} + +template +inline int poll(std::array &items, + std::chrono::milliseconds timeout = std::chrono::milliseconds{-1}) +{ + return detail::poll(items.data(), items.size(), static_cast(timeout.count())); +} +#endif + + +inline void version(int *major_, int *minor_, int *patch_) +{ + zmq_version(major_, minor_, patch_); +} + +#ifdef ZMQ_CPP11 +inline std::tuple version() +{ + std::tuple v; + zmq_version(&std::get<0>(v), &std::get<1>(v), &std::get<2>(v)); + return v; +} + +#if !defined(ZMQ_CPP11_PARTIAL) +namespace detail +{ +template struct is_char_type +{ + // true if character type for string literals in C++11 + static constexpr bool value = + std::is_same::value || std::is_same::value + || std::is_same::value || std::is_same::value; +}; +} +#endif + +#endif + +class message_t +{ + public: + message_t() ZMQ_NOTHROW + { + int rc = zmq_msg_init(&msg); + ZMQ_ASSERT(rc == 0); + } + + explicit message_t(size_t size_) + { + int rc = zmq_msg_init_size(&msg, size_); + if (rc != 0) + throw error_t(); + } + + template message_t(ForwardIter first, ForwardIter last) + { + typedef typename std::iterator_traits::value_type value_t; + + assert(std::distance(first, last) >= 0); + size_t const size_ = + static_cast(std::distance(first, last)) * sizeof(value_t); + int const rc = zmq_msg_init_size(&msg, size_); + if (rc != 0) + throw error_t(); + std::copy(first, last, data()); + } + + message_t(const void *data_, size_t size_) + { + int rc = zmq_msg_init_size(&msg, size_); + if (rc != 0) + throw error_t(); + if (size_) { + // this constructor allows (nullptr, 0), + // memcpy with a null pointer is UB + memcpy(data(), data_, size_); + } + } + + message_t(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR) + { + int rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_); + if (rc != 0) + throw error_t(); + } + + // overload set of string-like types and generic containers +#if defined(ZMQ_CPP11) && !defined(ZMQ_CPP11_PARTIAL) + // NOTE this constructor will include the null terminator + // when called with a string literal. + // An overload taking const char* can not be added because + // it would be preferred over this function and break compatiblity. + template< + class Char, + size_t N, + typename = typename std::enable_if::value>::type> + ZMQ_DEPRECATED("from 4.7.0, use constructors taking iterators, (pointer, size) " + "or strings instead") + explicit message_t(const Char (&data)[N]) : + message_t(detail::ranges::begin(data), detail::ranges::end(data)) + { + } + + template::value + && ZMQ_IS_TRIVIALLY_COPYABLE(detail::range_value_t) + && !detail::is_char_type>::value + && !std::is_same::value>::type> + explicit message_t(const Range &rng) : + message_t(detail::ranges::begin(rng), detail::ranges::end(rng)) + { + } + + explicit message_t(const std::string &str) : message_t(str.data(), str.size()) {} + +#if CPPZMQ_HAS_STRING_VIEW + explicit message_t(std::string_view str) : message_t(str.data(), str.size()) {} +#endif + +#endif + +#ifdef ZMQ_HAS_RVALUE_REFS + message_t(message_t &&rhs) ZMQ_NOTHROW : msg(rhs.msg) + { + int rc = zmq_msg_init(&rhs.msg); + ZMQ_ASSERT(rc == 0); + } + + message_t &operator=(message_t &&rhs) ZMQ_NOTHROW + { + std::swap(msg, rhs.msg); + return *this; + } +#endif + + ~message_t() ZMQ_NOTHROW + { + int rc = zmq_msg_close(&msg); + ZMQ_ASSERT(rc == 0); + } + + void rebuild() + { + int rc = zmq_msg_close(&msg); + if (rc != 0) + throw error_t(); + rc = zmq_msg_init(&msg); + ZMQ_ASSERT(rc == 0); + } + + void rebuild(size_t size_) + { + int rc = zmq_msg_close(&msg); + if (rc != 0) + throw error_t(); + rc = zmq_msg_init_size(&msg, size_); + if (rc != 0) + throw error_t(); + } + + void rebuild(const void *data_, size_t size_) + { + int rc = zmq_msg_close(&msg); + if (rc != 0) + throw error_t(); + rc = zmq_msg_init_size(&msg, size_); + if (rc != 0) + throw error_t(); + memcpy(data(), data_, size_); + } + + void rebuild(const std::string &str) + { + rebuild(str.data(), str.size()); + } + + void rebuild(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR) + { + int rc = zmq_msg_close(&msg); + if (rc != 0) + throw error_t(); + rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_); + if (rc != 0) + throw error_t(); + } + + ZMQ_DEPRECATED("from 4.3.1, use move taking non-const reference instead") + void move(message_t const *msg_) + { + int rc = zmq_msg_move(&msg, const_cast(msg_->handle())); + if (rc != 0) + throw error_t(); + } + + void move(message_t &msg_) + { + int rc = zmq_msg_move(&msg, msg_.handle()); + if (rc != 0) + throw error_t(); + } + + ZMQ_DEPRECATED("from 4.3.1, use copy taking non-const reference instead") + void copy(message_t const *msg_) + { + int rc = zmq_msg_copy(&msg, const_cast(msg_->handle())); + if (rc != 0) + throw error_t(); + } + + void copy(message_t &msg_) + { + int rc = zmq_msg_copy(&msg, msg_.handle()); + if (rc != 0) + throw error_t(); + } + + bool more() const ZMQ_NOTHROW + { + int rc = zmq_msg_more(const_cast(&msg)); + return rc != 0; + } + + void *data() ZMQ_NOTHROW { return zmq_msg_data(&msg); } + + const void *data() const ZMQ_NOTHROW + { + return zmq_msg_data(const_cast(&msg)); + } + + size_t size() const ZMQ_NOTHROW + { + return zmq_msg_size(const_cast(&msg)); + } + + ZMQ_NODISCARD bool empty() const ZMQ_NOTHROW { return size() == 0u; } + + template T *data() ZMQ_NOTHROW { return static_cast(data()); } + + template T const *data() const ZMQ_NOTHROW + { + return static_cast(data()); + } + + ZMQ_DEPRECATED("from 4.3.0, use operator== instead") + bool equal(const message_t *other) const ZMQ_NOTHROW { return *this == *other; } + + bool operator==(const message_t &other) const ZMQ_NOTHROW + { + const size_t my_size = size(); + return my_size == other.size() && 0 == memcmp(data(), other.data(), my_size); + } + + bool operator!=(const message_t &other) const ZMQ_NOTHROW + { + return !(*this == other); + } + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 2, 0) + int get(int property_) + { + int value = zmq_msg_get(&msg, property_); + if (value == -1) + throw error_t(); + return value; + } +#endif + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0) + const char *gets(const char *property_) + { + const char *value = zmq_msg_gets(&msg, property_); + if (value == ZMQ_NULLPTR) + throw error_t(); + return value; + } +#endif + +#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) + uint32_t routing_id() const + { + return zmq_msg_routing_id(const_cast(&msg)); + } + + void set_routing_id(uint32_t routing_id) + { + int rc = zmq_msg_set_routing_id(&msg, routing_id); + if (rc != 0) + throw error_t(); + } + + const char *group() const + { + return zmq_msg_group(const_cast(&msg)); + } + + void set_group(const char *group) + { + int rc = zmq_msg_set_group(&msg, group); + if (rc != 0) + throw error_t(); + } +#endif + + // interpret message content as a string + std::string to_string() const + { + return std::string(static_cast(data()), size()); + } +#if CPPZMQ_HAS_STRING_VIEW + // interpret message content as a string + std::string_view to_string_view() const noexcept + { + return std::string_view(static_cast(data()), size()); + } +#endif + + /** Dump content to string for debugging. + * Ascii chars are readable, the rest is printed as hex. + * Probably ridiculously slow. + * Use to_string() or to_string_view() for + * interpreting the message as a string. + */ + std::string str() const + { + // Partly mutuated from the same method in zmq::multipart_t + std::stringstream os; + + const unsigned char *msg_data = this->data(); + unsigned char byte; + size_t size = this->size(); + int is_ascii[2] = {0, 0}; + + os << "zmq::message_t [size " << std::dec << std::setw(3) + << std::setfill('0') << size << "] ("; + // Totally arbitrary + if (size >= 1000) { + os << "... too big to print)"; + } else { + while (size--) { + byte = *msg_data++; + + is_ascii[1] = (byte >= 32 && byte < 127); + if (is_ascii[1] != is_ascii[0]) + os << " "; // Separate text/non text + + if (is_ascii[1]) { + os << byte; + } else { + os << std::hex << std::uppercase << std::setw(2) + << std::setfill('0') << static_cast(byte); + } + is_ascii[0] = is_ascii[1]; + } + os << ")"; + } + return os.str(); + } + + void swap(message_t &other) ZMQ_NOTHROW + { + // this assumes zmq::msg_t from libzmq is trivially relocatable + std::swap(msg, other.msg); + } + + ZMQ_NODISCARD zmq_msg_t *handle() ZMQ_NOTHROW { return &msg; } + ZMQ_NODISCARD const zmq_msg_t *handle() const ZMQ_NOTHROW { return &msg; } + + private: + // The underlying message + zmq_msg_t msg; + + // Disable implicit message copying, so that users won't use shared + // messages (less efficient) without being aware of the fact. + message_t(const message_t &) ZMQ_DELETED_FUNCTION; + void operator=(const message_t &) ZMQ_DELETED_FUNCTION; +}; + +inline void swap(message_t &a, message_t &b) ZMQ_NOTHROW +{ + a.swap(b); +} + +#ifdef ZMQ_CPP11 +enum class ctxopt +{ +#ifdef ZMQ_BLOCKY + blocky = ZMQ_BLOCKY, +#endif +#ifdef ZMQ_IO_THREADS + io_threads = ZMQ_IO_THREADS, +#endif +#ifdef ZMQ_THREAD_SCHED_POLICY + thread_sched_policy = ZMQ_THREAD_SCHED_POLICY, +#endif +#ifdef ZMQ_THREAD_PRIORITY + thread_priority = ZMQ_THREAD_PRIORITY, +#endif +#ifdef ZMQ_THREAD_AFFINITY_CPU_ADD + thread_affinity_cpu_add = ZMQ_THREAD_AFFINITY_CPU_ADD, +#endif +#ifdef ZMQ_THREAD_AFFINITY_CPU_REMOVE + thread_affinity_cpu_remove = ZMQ_THREAD_AFFINITY_CPU_REMOVE, +#endif +#ifdef ZMQ_THREAD_NAME_PREFIX + thread_name_prefix = ZMQ_THREAD_NAME_PREFIX, +#endif +#ifdef ZMQ_MAX_MSGSZ + max_msgsz = ZMQ_MAX_MSGSZ, +#endif +#ifdef ZMQ_ZERO_COPY_RECV + zero_copy_recv = ZMQ_ZERO_COPY_RECV, +#endif +#ifdef ZMQ_MAX_SOCKETS + max_sockets = ZMQ_MAX_SOCKETS, +#endif +#ifdef ZMQ_SOCKET_LIMIT + socket_limit = ZMQ_SOCKET_LIMIT, +#endif +#ifdef ZMQ_IPV6 + ipv6 = ZMQ_IPV6, +#endif +#ifdef ZMQ_MSG_T_SIZE + msg_t_size = ZMQ_MSG_T_SIZE +#endif +}; +#endif + +class context_t +{ + public: + context_t() + { + ptr = zmq_ctx_new(); + if (ptr == ZMQ_NULLPTR) + throw error_t(); + } + + + explicit context_t(int io_threads_, int max_sockets_ = ZMQ_MAX_SOCKETS_DFLT) + { + ptr = zmq_ctx_new(); + if (ptr == ZMQ_NULLPTR) + throw error_t(); + + int rc = zmq_ctx_set(ptr, ZMQ_IO_THREADS, io_threads_); + ZMQ_ASSERT(rc == 0); + + rc = zmq_ctx_set(ptr, ZMQ_MAX_SOCKETS, max_sockets_); + ZMQ_ASSERT(rc == 0); + } + +#ifdef ZMQ_HAS_RVALUE_REFS + context_t(context_t &&rhs) ZMQ_NOTHROW : ptr(rhs.ptr) { rhs.ptr = ZMQ_NULLPTR; } + context_t &operator=(context_t &&rhs) ZMQ_NOTHROW + { + close(); + std::swap(ptr, rhs.ptr); + return *this; + } +#endif + + ~context_t() ZMQ_NOTHROW { close(); } + + ZMQ_CPP11_DEPRECATED("from 4.7.0, use set taking zmq::ctxopt instead") + int setctxopt(int option_, int optval_) + { + int rc = zmq_ctx_set(ptr, option_, optval_); + ZMQ_ASSERT(rc == 0); + return rc; + } + + ZMQ_CPP11_DEPRECATED("from 4.7.0, use get taking zmq::ctxopt instead") + int getctxopt(int option_) { return zmq_ctx_get(ptr, option_); } + +#ifdef ZMQ_CPP11 + void set(ctxopt option, int optval) + { + int rc = zmq_ctx_set(ptr, static_cast(option), optval); + if (rc == -1) + throw error_t(); + } + + ZMQ_NODISCARD int get(ctxopt option) + { + int rc = zmq_ctx_get(ptr, static_cast(option)); + // some options have a default value of -1 + // which is unfortunate, and may result in errors + // that don't make sense + if (rc == -1) + throw error_t(); + return rc; + } +#endif + + // Terminates context (see also shutdown()). + void close() ZMQ_NOTHROW + { + if (ptr == ZMQ_NULLPTR) + return; + + int rc; + do { + rc = zmq_ctx_term(ptr); + } while (rc == -1 && errno == EINTR); + + ZMQ_ASSERT(rc == 0); + ptr = ZMQ_NULLPTR; + } + + // Shutdown context in preparation for termination (close()). + // Causes all blocking socket operations and any further + // socket operations to return with ETERM. + void shutdown() ZMQ_NOTHROW + { + if (ptr == ZMQ_NULLPTR) + return; + int rc = zmq_ctx_shutdown(ptr); + ZMQ_ASSERT(rc == 0); + } + + // Be careful with this, it's probably only useful for + // using the C api together with an existing C++ api. + // Normally you should never need to use this. + ZMQ_EXPLICIT operator void *() ZMQ_NOTHROW { return ptr; } + + ZMQ_EXPLICIT operator void const *() const ZMQ_NOTHROW { return ptr; } + + ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return ptr; } + + ZMQ_DEPRECATED("from 4.7.0, use handle() != nullptr instead") + operator bool() const ZMQ_NOTHROW { return ptr != ZMQ_NULLPTR; } + + void swap(context_t &other) ZMQ_NOTHROW { std::swap(ptr, other.ptr); } + + private: + void *ptr; + + context_t(const context_t &) ZMQ_DELETED_FUNCTION; + void operator=(const context_t &) ZMQ_DELETED_FUNCTION; +}; + +inline void swap(context_t &a, context_t &b) ZMQ_NOTHROW +{ + a.swap(b); +} + +#ifdef ZMQ_CPP11 + +struct recv_buffer_size +{ + size_t size; // number of bytes written to buffer + size_t untruncated_size; // untruncated message size in bytes + + ZMQ_NODISCARD bool truncated() const noexcept + { + return size != untruncated_size; + } +}; + +#if CPPZMQ_HAS_OPTIONAL + +using send_result_t = std::optional; +using recv_result_t = std::optional; +using recv_buffer_result_t = std::optional; + +#else + +namespace detail +{ +// A C++11 type emulating the most basic +// operations of std::optional for trivial types +template class trivial_optional +{ + public: + static_assert(std::is_trivial::value, "T must be trivial"); + using value_type = T; + + trivial_optional() = default; + trivial_optional(T value) noexcept : _value(value), _has_value(true) {} + + const T *operator->() const noexcept + { + assert(_has_value); + return &_value; + } + T *operator->() noexcept + { + assert(_has_value); + return &_value; + } + + const T &operator*() const noexcept + { + assert(_has_value); + return _value; + } + T &operator*() noexcept + { + assert(_has_value); + return _value; + } + + T &value() + { + if (!_has_value) + throw std::exception(); + return _value; + } + const T &value() const + { + if (!_has_value) + throw std::exception(); + return _value; + } + + explicit operator bool() const noexcept { return _has_value; } + bool has_value() const noexcept { return _has_value; } + + private: + T _value{}; + bool _has_value{false}; +}; +} // namespace detail + +using send_result_t = detail::trivial_optional; +using recv_result_t = detail::trivial_optional; +using recv_buffer_result_t = detail::trivial_optional; + +#endif + +namespace detail +{ +template constexpr T enum_bit_or(T a, T b) noexcept +{ + static_assert(std::is_enum::value, "must be enum"); + using U = typename std::underlying_type::type; + return static_cast(static_cast(a) | static_cast(b)); +} +template constexpr T enum_bit_and(T a, T b) noexcept +{ + static_assert(std::is_enum::value, "must be enum"); + using U = typename std::underlying_type::type; + return static_cast(static_cast(a) & static_cast(b)); +} +template constexpr T enum_bit_xor(T a, T b) noexcept +{ + static_assert(std::is_enum::value, "must be enum"); + using U = typename std::underlying_type::type; + return static_cast(static_cast(a) ^ static_cast(b)); +} +template constexpr T enum_bit_not(T a) noexcept +{ + static_assert(std::is_enum::value, "must be enum"); + using U = typename std::underlying_type::type; + return static_cast(~static_cast(a)); +} +} // namespace detail + +// partially satisfies named requirement BitmaskType +enum class send_flags : int +{ + none = 0, + dontwait = ZMQ_DONTWAIT, + sndmore = ZMQ_SNDMORE +}; + +constexpr send_flags operator|(send_flags a, send_flags b) noexcept +{ + return detail::enum_bit_or(a, b); +} +constexpr send_flags operator&(send_flags a, send_flags b) noexcept +{ + return detail::enum_bit_and(a, b); +} +constexpr send_flags operator^(send_flags a, send_flags b) noexcept +{ + return detail::enum_bit_xor(a, b); +} +constexpr send_flags operator~(send_flags a) noexcept +{ + return detail::enum_bit_not(a); +} + +// partially satisfies named requirement BitmaskType +enum class recv_flags : int +{ + none = 0, + dontwait = ZMQ_DONTWAIT +}; + +constexpr recv_flags operator|(recv_flags a, recv_flags b) noexcept +{ + return detail::enum_bit_or(a, b); +} +constexpr recv_flags operator&(recv_flags a, recv_flags b) noexcept +{ + return detail::enum_bit_and(a, b); +} +constexpr recv_flags operator^(recv_flags a, recv_flags b) noexcept +{ + return detail::enum_bit_xor(a, b); +} +constexpr recv_flags operator~(recv_flags a) noexcept +{ + return detail::enum_bit_not(a); +} + + +// mutable_buffer, const_buffer and buffer are based on +// the Networking TS specification, draft: +// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4771.pdf + +class mutable_buffer +{ + public: + constexpr mutable_buffer() noexcept : _data(nullptr), _size(0) {} + constexpr mutable_buffer(void *p, size_t n) noexcept : _data(p), _size(n) + { +#ifdef ZMQ_EXTENDED_CONSTEXPR + assert(p != nullptr || n == 0); +#endif + } + + constexpr void *data() const noexcept { return _data; } + constexpr size_t size() const noexcept { return _size; } + mutable_buffer &operator+=(size_t n) noexcept + { + // (std::min) is a workaround for when a min macro is defined + const auto shift = (std::min)(n, _size); + _data = static_cast(_data) + shift; + _size -= shift; + return *this; + } + + private: + void *_data; + size_t _size; +}; + +inline mutable_buffer operator+(const mutable_buffer &mb, size_t n) noexcept +{ + return mutable_buffer(static_cast(mb.data()) + (std::min)(n, mb.size()), + mb.size() - (std::min)(n, mb.size())); +} +inline mutable_buffer operator+(size_t n, const mutable_buffer &mb) noexcept +{ + return mb + n; +} + +class const_buffer +{ + public: + constexpr const_buffer() noexcept : _data(nullptr), _size(0) {} + constexpr const_buffer(const void *p, size_t n) noexcept : _data(p), _size(n) + { +#ifdef ZMQ_EXTENDED_CONSTEXPR + assert(p != nullptr || n == 0); +#endif + } + constexpr const_buffer(const mutable_buffer &mb) noexcept : + _data(mb.data()), _size(mb.size()) + { + } + + constexpr const void *data() const noexcept { return _data; } + constexpr size_t size() const noexcept { return _size; } + const_buffer &operator+=(size_t n) noexcept + { + const auto shift = (std::min)(n, _size); + _data = static_cast(_data) + shift; + _size -= shift; + return *this; + } + + private: + const void *_data; + size_t _size; +}; + +inline const_buffer operator+(const const_buffer &cb, size_t n) noexcept +{ + return const_buffer(static_cast(cb.data()) + + (std::min)(n, cb.size()), + cb.size() - (std::min)(n, cb.size())); +} +inline const_buffer operator+(size_t n, const const_buffer &cb) noexcept +{ + return cb + n; +} + +// buffer creation + +constexpr mutable_buffer buffer(void *p, size_t n) noexcept +{ + return mutable_buffer(p, n); +} +constexpr const_buffer buffer(const void *p, size_t n) noexcept +{ + return const_buffer(p, n); +} +constexpr mutable_buffer buffer(const mutable_buffer &mb) noexcept +{ + return mb; +} +inline mutable_buffer buffer(const mutable_buffer &mb, size_t n) noexcept +{ + return mutable_buffer(mb.data(), (std::min)(mb.size(), n)); +} +constexpr const_buffer buffer(const const_buffer &cb) noexcept +{ + return cb; +} +inline const_buffer buffer(const const_buffer &cb, size_t n) noexcept +{ + return const_buffer(cb.data(), (std::min)(cb.size(), n)); +} + +namespace detail +{ +template struct is_buffer +{ + static constexpr bool value = + std::is_same::value || std::is_same::value; +}; + +template struct is_pod_like +{ + // NOTE: The networking draft N4771 section 16.11 requires + // T in the buffer functions below to be + // trivially copyable OR standard layout. + // Here we decide to be conservative and require both. + static constexpr bool value = + ZMQ_IS_TRIVIALLY_COPYABLE(T) && std::is_standard_layout::value; +}; + +template constexpr auto seq_size(const C &c) noexcept -> decltype(c.size()) +{ + return c.size(); +} +template +constexpr size_t seq_size(const T (&/*array*/)[N]) noexcept +{ + return N; +} + +template +auto buffer_contiguous_sequence(Seq &&seq) noexcept + -> decltype(buffer(std::addressof(*std::begin(seq)), size_t{})) +{ + using T = typename std::remove_cv< + typename std::remove_reference::type>::type; + static_assert(detail::is_pod_like::value, "T must be POD"); + + const auto size = seq_size(seq); + return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr, + size * sizeof(T)); +} +template +auto buffer_contiguous_sequence(Seq &&seq, size_t n_bytes) noexcept + -> decltype(buffer_contiguous_sequence(seq)) +{ + using T = typename std::remove_cv< + typename std::remove_reference::type>::type; + static_assert(detail::is_pod_like::value, "T must be POD"); + + const auto size = seq_size(seq); + return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr, + (std::min)(size * sizeof(T), n_bytes)); +} + +} // namespace detail + +// C array +template mutable_buffer buffer(T (&data)[N]) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +mutable_buffer buffer(T (&data)[N], size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +template const_buffer buffer(const T (&data)[N]) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +const_buffer buffer(const T (&data)[N], size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +// std::array +template mutable_buffer buffer(std::array &data) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +mutable_buffer buffer(std::array &data, size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +template +const_buffer buffer(std::array &data) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +const_buffer buffer(std::array &data, size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +template +const_buffer buffer(const std::array &data) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +const_buffer buffer(const std::array &data, size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +// std::vector +template +mutable_buffer buffer(std::vector &data) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +mutable_buffer buffer(std::vector &data, size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +template +const_buffer buffer(const std::vector &data) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +const_buffer buffer(const std::vector &data, size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +// std::basic_string +template +mutable_buffer buffer(std::basic_string &data) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +mutable_buffer buffer(std::basic_string &data, + size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +template +const_buffer buffer(const std::basic_string &data) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +const_buffer buffer(const std::basic_string &data, + size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} + +#if CPPZMQ_HAS_STRING_VIEW +// std::basic_string_view +template +const_buffer buffer(std::basic_string_view data) noexcept +{ + return detail::buffer_contiguous_sequence(data); +} +template +const_buffer buffer(std::basic_string_view data, size_t n_bytes) noexcept +{ + return detail::buffer_contiguous_sequence(data, n_bytes); +} +#endif + +// Buffer for a string literal (null terminated) +// where the buffer size excludes the terminating character. +// Equivalent to zmq::buffer(std::string_view("...")). +template +constexpr const_buffer str_buffer(const Char (&data)[N]) noexcept +{ + static_assert(detail::is_pod_like::value, "Char must be POD"); +#ifdef ZMQ_EXTENDED_CONSTEXPR + assert(data[N - 1] == Char{0}); +#endif + return const_buffer(static_cast(data), (N - 1) * sizeof(Char)); +} + +namespace literals +{ +constexpr const_buffer operator"" _zbuf(const char *str, size_t len) noexcept +{ + return const_buffer(str, len * sizeof(char)); +} +constexpr const_buffer operator"" _zbuf(const wchar_t *str, size_t len) noexcept +{ + return const_buffer(str, len * sizeof(wchar_t)); +} +constexpr const_buffer operator"" _zbuf(const char16_t *str, size_t len) noexcept +{ + return const_buffer(str, len * sizeof(char16_t)); +} +constexpr const_buffer operator"" _zbuf(const char32_t *str, size_t len) noexcept +{ + return const_buffer(str, len * sizeof(char32_t)); +} +} + +#ifdef ZMQ_CPP11 +enum class socket_type : int +{ + req = ZMQ_REQ, + rep = ZMQ_REP, + dealer = ZMQ_DEALER, + router = ZMQ_ROUTER, + pub = ZMQ_PUB, + sub = ZMQ_SUB, + xpub = ZMQ_XPUB, + xsub = ZMQ_XSUB, + push = ZMQ_PUSH, + pull = ZMQ_PULL, +#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) + server = ZMQ_SERVER, + client = ZMQ_CLIENT, + radio = ZMQ_RADIO, + dish = ZMQ_DISH, + gather = ZMQ_GATHER, + scatter = ZMQ_SCATTER, + dgram = ZMQ_DGRAM, +#endif +#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3) + peer = ZMQ_PEER, + channel = ZMQ_CHANNEL, +#endif +#if ZMQ_VERSION_MAJOR >= 4 + stream = ZMQ_STREAM, +#endif + pair = ZMQ_PAIR +}; +#endif + +namespace sockopt +{ +// There are two types of options, +// integral type with known compiler time size (int, bool, int64_t, uint64_t) +// and arrays with dynamic size (strings, binary data). + +// BoolUnit: if true accepts values of type bool (but passed as T into libzmq) +template struct integral_option +{ +}; + +// NullTerm: +// 0: binary data +// 1: null-terminated string (`getsockopt` size includes null) +// 2: binary (size 32) or Z85 encoder string of size 41 (null included) +template struct array_option +{ +}; + +#define ZMQ_DEFINE_INTEGRAL_OPT(OPT, NAME, TYPE) \ + using NAME##_t = integral_option; \ + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} +#define ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(OPT, NAME, TYPE) \ + using NAME##_t = integral_option; \ + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} +#define ZMQ_DEFINE_ARRAY_OPT(OPT, NAME) \ + using NAME##_t = array_option; \ + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} +#define ZMQ_DEFINE_ARRAY_OPT_BINARY(OPT, NAME) \ + using NAME##_t = array_option; \ + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} +#define ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(OPT, NAME) \ + using NAME##_t = array_option; \ + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} + +// deprecated, use zmq::fd_t +using cppzmq_fd_t = ::zmq::fd_t; + +#ifdef ZMQ_AFFINITY +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_AFFINITY, affinity, uint64_t); +#endif +#ifdef ZMQ_BACKLOG +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_BACKLOG, backlog, int); +#endif +#ifdef ZMQ_BINDTODEVICE +ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_BINDTODEVICE, bindtodevice); +#endif +#ifdef ZMQ_CONFLATE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CONFLATE, conflate, int); +#endif +#ifdef ZMQ_CONNECT_ROUTING_ID +ZMQ_DEFINE_ARRAY_OPT(ZMQ_CONNECT_ROUTING_ID, connect_routing_id); +#endif +#ifdef ZMQ_CONNECT_TIMEOUT +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_CONNECT_TIMEOUT, connect_timeout, int); +#endif +#ifdef ZMQ_CURVE_PUBLICKEY +ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_PUBLICKEY, curve_publickey); +#endif +#ifdef ZMQ_CURVE_SECRETKEY +ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SECRETKEY, curve_secretkey); +#endif +#ifdef ZMQ_CURVE_SERVER +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CURVE_SERVER, curve_server, int); +#endif +#ifdef ZMQ_CURVE_SERVERKEY +ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SERVERKEY, curve_serverkey); +#endif +#ifdef ZMQ_DISCONNECT_MSG +ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_DISCONNECT_MSG, disconnect_msg); +#endif +#ifdef ZMQ_EVENTS +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_EVENTS, events, int); +#endif +#ifdef ZMQ_FD +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_FD, fd, ::zmq::fd_t); +#endif +#ifdef ZMQ_GSSAPI_PLAINTEXT +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_PLAINTEXT, gssapi_plaintext, int); +#endif +#ifdef ZMQ_GSSAPI_SERVER +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_SERVER, gssapi_server, int); +#endif +#ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL +ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL, gssapi_service_principal); +#endif +#ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE, + gssapi_service_principal_nametype, + int); +#endif +#ifdef ZMQ_GSSAPI_PRINCIPAL +ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_PRINCIPAL, gssapi_principal); +#endif +#ifdef ZMQ_GSSAPI_PRINCIPAL_NAMETYPE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, + gssapi_principal_nametype, + int); +#endif +#ifdef ZMQ_HANDSHAKE_IVL +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HANDSHAKE_IVL, handshake_ivl, int); +#endif +#ifdef ZMQ_HEARTBEAT_IVL +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_IVL, heartbeat_ivl, int); +#endif +#ifdef ZMQ_HEARTBEAT_TIMEOUT +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TIMEOUT, heartbeat_timeout, int); +#endif +#ifdef ZMQ_HEARTBEAT_TTL +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TTL, heartbeat_ttl, int); +#endif +#ifdef ZMQ_HELLO_MSG +ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_HELLO_MSG, hello_msg); +#endif +#ifdef ZMQ_IMMEDIATE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IMMEDIATE, immediate, int); +#endif +#ifdef ZMQ_INVERT_MATCHING +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_INVERT_MATCHING, invert_matching, int); +#endif +#ifdef ZMQ_IPV6 +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IPV6, ipv6, int); +#endif +#ifdef ZMQ_LAST_ENDPOINT +ZMQ_DEFINE_ARRAY_OPT(ZMQ_LAST_ENDPOINT, last_endpoint); +#endif +#ifdef ZMQ_LINGER +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_LINGER, linger, int); +#endif +#ifdef ZMQ_MAXMSGSIZE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MAXMSGSIZE, maxmsgsize, int64_t); +#endif +#ifdef ZMQ_MECHANISM +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MECHANISM, mechanism, int); +#endif +#ifdef ZMQ_METADATA +ZMQ_DEFINE_ARRAY_OPT(ZMQ_METADATA, metadata); +#endif +#ifdef ZMQ_MULTICAST_HOPS +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_HOPS, multicast_hops, int); +#endif +#ifdef ZMQ_MULTICAST_LOOP +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_MULTICAST_LOOP, multicast_loop, int); +#endif +#ifdef ZMQ_MULTICAST_MAXTPDU +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_MAXTPDU, multicast_maxtpdu, int); +#endif +#ifdef ZMQ_ONLY_FIRST_SUBSCRIBE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ONLY_FIRST_SUBSCRIBE, only_first_subscribe, int); +#endif +#ifdef ZMQ_PLAIN_SERVER +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PLAIN_SERVER, plain_server, int); +#endif +#ifdef ZMQ_PLAIN_PASSWORD +ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_PASSWORD, plain_password); +#endif +#ifdef ZMQ_PLAIN_USERNAME +ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_USERNAME, plain_username); +#endif +#ifdef ZMQ_PRIORITY +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_PRIORITY, priority, int); +#endif +#ifdef ZMQ_USE_FD +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_USE_FD, use_fd, int); +#endif +#ifdef ZMQ_PROBE_ROUTER +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PROBE_ROUTER, probe_router, int); +#endif +#ifdef ZMQ_RATE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RATE, rate, int); +#endif +#ifdef ZMQ_RCVBUF +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVBUF, rcvbuf, int); +#endif +#ifdef ZMQ_RCVHWM +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVHWM, rcvhwm, int); +#endif +#ifdef ZMQ_RCVMORE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_RCVMORE, rcvmore, int); +#endif +#ifdef ZMQ_RCVTIMEO +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVTIMEO, rcvtimeo, int); +#endif +#ifdef ZMQ_RECONNECT_IVL +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL, reconnect_ivl, int); +#endif +#ifdef ZMQ_RECONNECT_IVL_MAX +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL_MAX, reconnect_ivl_max, int); +#endif +#ifdef ZMQ_RECONNECT_STOP +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_STOP, reconnect_stop, int); +#endif +#ifdef ZMQ_RECOVERY_IVL +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECOVERY_IVL, recovery_ivl, int); +#endif +#ifdef ZMQ_REQ_CORRELATE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_CORRELATE, req_correlate, int); +#endif +#ifdef ZMQ_REQ_RELAXED +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_RELAXED, req_relaxed, int); +#endif +#ifdef ZMQ_ROUTER_HANDOVER +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_HANDOVER, router_handover, int); +#endif +#ifdef ZMQ_ROUTER_MANDATORY +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_MANDATORY, router_mandatory, int); +#endif +#ifdef ZMQ_ROUTER_NOTIFY +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_ROUTER_NOTIFY, router_notify, int); +#endif +#ifdef ZMQ_ROUTING_ID +ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_ROUTING_ID, routing_id); +#endif +#ifdef ZMQ_SNDBUF +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDBUF, sndbuf, int); +#endif +#ifdef ZMQ_SNDHWM +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDHWM, sndhwm, int); +#endif +#ifdef ZMQ_SNDTIMEO +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDTIMEO, sndtimeo, int); +#endif +#ifdef ZMQ_SOCKS_PASSWORD +ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PASSWORD, socks_password); +#endif +#ifdef ZMQ_SOCKS_PROXY +ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PROXY, socks_proxy); +#endif +#ifdef ZMQ_SOCKS_USERNAME +ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_USERNAME, socks_username); +#endif +#ifdef ZMQ_STREAM_NOTIFY +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_STREAM_NOTIFY, stream_notify, int); +#endif +#ifdef ZMQ_SUBSCRIBE +ZMQ_DEFINE_ARRAY_OPT(ZMQ_SUBSCRIBE, subscribe); +#endif +#ifdef ZMQ_TCP_KEEPALIVE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE, tcp_keepalive, int); +#endif +#ifdef ZMQ_TCP_KEEPALIVE_CNT +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_CNT, tcp_keepalive_cnt, int); +#endif +#ifdef ZMQ_TCP_KEEPALIVE_IDLE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_IDLE, tcp_keepalive_idle, int); +#endif +#ifdef ZMQ_TCP_KEEPALIVE_INTVL +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_INTVL, tcp_keepalive_intvl, int); +#endif +#ifdef ZMQ_TCP_MAXRT +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_MAXRT, tcp_maxrt, int); +#endif +#ifdef ZMQ_THREAD_SAFE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_THREAD_SAFE, thread_safe, int); +#endif +#ifdef ZMQ_TOS +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TOS, tos, int); +#endif +#ifdef ZMQ_TYPE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, type, int); +#ifdef ZMQ_CPP11 +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, socket_type, socket_type); +#endif // ZMQ_CPP11 +#endif // ZMQ_TYPE +#ifdef ZMQ_UNSUBSCRIBE +ZMQ_DEFINE_ARRAY_OPT(ZMQ_UNSUBSCRIBE, unsubscribe); +#endif +#ifdef ZMQ_VMCI_BUFFER_SIZE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_SIZE, vmci_buffer_size, uint64_t); +#endif +#ifdef ZMQ_VMCI_BUFFER_MIN_SIZE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MIN_SIZE, vmci_buffer_min_size, uint64_t); +#endif +#ifdef ZMQ_VMCI_BUFFER_MAX_SIZE +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MAX_SIZE, vmci_buffer_max_size, uint64_t); +#endif +#ifdef ZMQ_VMCI_CONNECT_TIMEOUT +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_CONNECT_TIMEOUT, vmci_connect_timeout, int); +#endif +#ifdef ZMQ_XPUB_VERBOSE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSE, xpub_verbose, int); +#endif +#ifdef ZMQ_XPUB_VERBOSER +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSER, xpub_verboser, int); +#endif +#ifdef ZMQ_XPUB_MANUAL +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL, xpub_manual, int); +#endif +#ifdef ZMQ_XPUB_MANUAL_LAST_VALUE +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL_LAST_VALUE, xpub_manual_last_value, int); +#endif +#ifdef ZMQ_XPUB_NODROP +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_NODROP, xpub_nodrop, int); +#endif +#ifdef ZMQ_XPUB_WELCOME_MSG +ZMQ_DEFINE_ARRAY_OPT(ZMQ_XPUB_WELCOME_MSG, xpub_welcome_msg); +#endif +#ifdef ZMQ_ZAP_ENFORCE_DOMAIN +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ZAP_ENFORCE_DOMAIN, zap_enforce_domain, int); +#endif +#ifdef ZMQ_ZAP_DOMAIN +ZMQ_DEFINE_ARRAY_OPT(ZMQ_ZAP_DOMAIN, zap_domain); +#endif + +} // namespace sockopt +#endif // ZMQ_CPP11 + + +namespace detail +{ +class socket_base +{ + public: + socket_base() ZMQ_NOTHROW : _handle(ZMQ_NULLPTR) {} + ZMQ_EXPLICIT socket_base(void *handle) ZMQ_NOTHROW : _handle(handle) {} + + template + ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt") + void setsockopt(int option_, T const &optval) + { + setsockopt(option_, &optval, sizeof(T)); + } + + ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt") + void setsockopt(int option_, const void *optval_, size_t optvallen_) + { + int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_); + if (rc != 0) + throw error_t(); + } + + ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt") + void getsockopt(int option_, void *optval_, size_t *optvallen_) const + { + int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_); + if (rc != 0) + throw error_t(); + } + + template + ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt") + T getsockopt(int option_) const + { + T optval; + size_t optlen = sizeof(T); + getsockopt(option_, &optval, &optlen); + return optval; + } + +#ifdef ZMQ_CPP11 + // Set integral socket option, e.g. + // `socket.set(zmq::sockopt::linger, 0)` + template + void set(sockopt::integral_option, const T &val) + { + static_assert(std::is_integral::value, "T must be integral"); + set_option(Opt, &val, sizeof val); + } + + // Set integral socket option from boolean, e.g. + // `socket.set(zmq::sockopt::immediate, false)` + template + void set(sockopt::integral_option, bool val) + { + static_assert(std::is_integral::value, "T must be integral"); + T rep_val = val; + set_option(Opt, &rep_val, sizeof rep_val); + } + + // Set array socket option, e.g. + // `socket.set(zmq::sockopt::plain_username, "foo123")` + template + void set(sockopt::array_option, const char *buf) + { + set_option(Opt, buf, std::strlen(buf)); + } + + // Set array socket option, e.g. + // `socket.set(zmq::sockopt::routing_id, zmq::buffer(id))` + template + void set(sockopt::array_option, const_buffer buf) + { + set_option(Opt, buf.data(), buf.size()); + } + + // Set array socket option, e.g. + // `socket.set(zmq::sockopt::routing_id, id_str)` + template + void set(sockopt::array_option, const std::string &buf) + { + set_option(Opt, buf.data(), buf.size()); + } + +#if CPPZMQ_HAS_STRING_VIEW + // Set array socket option, e.g. + // `socket.set(zmq::sockopt::routing_id, id_str)` + template + void set(sockopt::array_option, std::string_view buf) + { + set_option(Opt, buf.data(), buf.size()); + } +#endif + + // Get scalar socket option, e.g. + // `auto opt = socket.get(zmq::sockopt::linger)` + template + ZMQ_NODISCARD T get(sockopt::integral_option) const + { + static_assert(std::is_scalar::value, "T must be scalar"); + T val; + size_t size = sizeof val; + get_option(Opt, &val, &size); + assert(size == sizeof val); + return val; + } + + // Get array socket option, writes to buf, returns option size in bytes, e.g. + // `size_t optsize = socket.get(zmq::sockopt::routing_id, zmq::buffer(id))` + template + ZMQ_NODISCARD size_t get(sockopt::array_option, + mutable_buffer buf) const + { + size_t size = buf.size(); + get_option(Opt, buf.data(), &size); + return size; + } + + // Get array socket option as string (initializes the string buffer size to init_size) e.g. + // `auto s = socket.get(zmq::sockopt::routing_id)` + // Note: removes the null character from null-terminated string options, + // i.e. the string size excludes the null character. + template + ZMQ_NODISCARD std::string get(sockopt::array_option, + size_t init_size = 1024) const + { + if ZMQ_CONSTEXPR_IF (NullTerm == 2) { + if (init_size == 1024) { + init_size = 41; // get as Z85 string + } + } + std::string str(init_size, '\0'); + size_t size = get(sockopt::array_option{}, buffer(str)); + if ZMQ_CONSTEXPR_IF (NullTerm == 1) { + if (size > 0) { + assert(str[size - 1] == '\0'); + --size; + } + } else if ZMQ_CONSTEXPR_IF (NullTerm == 2) { + assert(size == 32 || size == 41); + if (size == 41) { + assert(str[size - 1] == '\0'); + --size; + } + } + str.resize(size); + return str; + } +#endif + + void bind(std::string const &addr) { bind(addr.c_str()); } + + void bind(const char *addr_) + { + int rc = zmq_bind(_handle, addr_); + if (rc != 0) + throw error_t(); + } + + void unbind(std::string const &addr) { unbind(addr.c_str()); } + + void unbind(const char *addr_) + { + int rc = zmq_unbind(_handle, addr_); + if (rc != 0) + throw error_t(); + } + + void connect(std::string const &addr) { connect(addr.c_str()); } + + void connect(const char *addr_) + { + int rc = zmq_connect(_handle, addr_); + if (rc != 0) + throw error_t(); + } + + void disconnect(std::string const &addr) { disconnect(addr.c_str()); } + + void disconnect(const char *addr_) + { + int rc = zmq_disconnect(_handle, addr_); + if (rc != 0) + throw error_t(); + } + + ZMQ_DEPRECATED("from 4.7.1, use handle() != nullptr or operator bool") + bool connected() const ZMQ_NOTHROW { return (_handle != ZMQ_NULLPTR); } + + ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking a const_buffer and send_flags") + size_t send(const void *buf_, size_t len_, int flags_ = 0) + { + int nbytes = zmq_send(_handle, buf_, len_, flags_); + if (nbytes >= 0) + return static_cast(nbytes); + if (zmq_errno() == EAGAIN) + return 0; + throw error_t(); + } + + ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags") + bool send(message_t &msg_, + int flags_ = 0) // default until removed + { + int nbytes = zmq_msg_send(msg_.handle(), _handle, flags_); + if (nbytes >= 0) + return true; + if (zmq_errno() == EAGAIN) + return false; + throw error_t(); + } + + template + ZMQ_CPP11_DEPRECATED( + "from 4.4.1, use send taking message_t or buffer (for contiguous " + "ranges), and send_flags") + bool send(T first, T last, int flags_ = 0) + { + zmq::message_t msg(first, last); + int nbytes = zmq_msg_send(msg.handle(), _handle, flags_); + if (nbytes >= 0) + return true; + if (zmq_errno() == EAGAIN) + return false; + throw error_t(); + } + +#ifdef ZMQ_HAS_RVALUE_REFS + ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags") + bool send(message_t &&msg_, + int flags_ = 0) // default until removed + { +#ifdef ZMQ_CPP11 + return send(msg_, static_cast(flags_)).has_value(); +#else + return send(msg_, flags_); +#endif + } +#endif + +#ifdef ZMQ_CPP11 + send_result_t send(const_buffer buf, send_flags flags = send_flags::none) + { + const int nbytes = + zmq_send(_handle, buf.data(), buf.size(), static_cast(flags)); + if (nbytes >= 0) + return static_cast(nbytes); + if (zmq_errno() == EAGAIN) + return {}; + throw error_t(); + } + + send_result_t send(message_t &msg, send_flags flags) + { + int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast(flags)); + if (nbytes >= 0) + return static_cast(nbytes); + if (zmq_errno() == EAGAIN) + return {}; + throw error_t(); + } + + send_result_t send(message_t &&msg, send_flags flags) + { + return send(msg, flags); + } +#endif + + ZMQ_CPP11_DEPRECATED( + "from 4.3.1, use recv taking a mutable_buffer and recv_flags") + size_t recv(void *buf_, size_t len_, int flags_ = 0) + { + int nbytes = zmq_recv(_handle, buf_, len_, flags_); + if (nbytes >= 0) + return static_cast(nbytes); + if (zmq_errno() == EAGAIN) + return 0; + throw error_t(); + } + + ZMQ_CPP11_DEPRECATED( + "from 4.3.1, use recv taking a reference to message_t and recv_flags") + bool recv(message_t *msg_, int flags_ = 0) + { + int nbytes = zmq_msg_recv(msg_->handle(), _handle, flags_); + if (nbytes >= 0) + return true; + if (zmq_errno() == EAGAIN) + return false; + throw error_t(); + } + +#ifdef ZMQ_CPP11 + ZMQ_NODISCARD + recv_buffer_result_t recv(mutable_buffer buf, + recv_flags flags = recv_flags::none) + { + const int nbytes = + zmq_recv(_handle, buf.data(), buf.size(), static_cast(flags)); + if (nbytes >= 0) { + return recv_buffer_size{ + (std::min)(static_cast(nbytes), buf.size()), + static_cast(nbytes)}; + } + if (zmq_errno() == EAGAIN) + return {}; + throw error_t(); + } + + ZMQ_NODISCARD + recv_result_t recv(message_t &msg, recv_flags flags = recv_flags::none) + { + const int nbytes = + zmq_msg_recv(msg.handle(), _handle, static_cast(flags)); + if (nbytes >= 0) { + assert(msg.size() == static_cast(nbytes)); + return static_cast(nbytes); + } + if (zmq_errno() == EAGAIN) + return {}; + throw error_t(); + } +#endif + +#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) + void join(const char *group) + { + int rc = zmq_join(_handle, group); + if (rc != 0) + throw error_t(); + } + + void leave(const char *group) + { + int rc = zmq_leave(_handle, group); + if (rc != 0) + throw error_t(); + } +#endif + + ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return _handle; } + ZMQ_NODISCARD const void *handle() const ZMQ_NOTHROW { return _handle; } + + ZMQ_EXPLICIT operator bool() const ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; } + // note: non-const operator bool can be removed once + // operator void* is removed from socket_t + ZMQ_EXPLICIT operator bool() ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; } + + protected: + void *_handle; + + private: + void set_option(int option_, const void *optval_, size_t optvallen_) + { + int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_); + if (rc != 0) + throw error_t(); + } + + void get_option(int option_, void *optval_, size_t *optvallen_) const + { + int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_); + if (rc != 0) + throw error_t(); + } +}; +} // namespace detail + +struct from_handle_t +{ + struct _private + { + }; // disabling use other than with from_handle + ZMQ_CONSTEXPR_FN ZMQ_EXPLICIT from_handle_t(_private /*p*/) ZMQ_NOTHROW {} +}; + +ZMQ_CONSTEXPR_VAR from_handle_t from_handle = + from_handle_t(from_handle_t::_private()); + +// A non-owning nullable reference to a socket. +// The reference is invalidated on socket close or destruction. +class socket_ref : public detail::socket_base +{ + public: + socket_ref() ZMQ_NOTHROW : detail::socket_base() {} +#ifdef ZMQ_CPP11 + socket_ref(std::nullptr_t) ZMQ_NOTHROW : detail::socket_base() {} +#endif + socket_ref(from_handle_t /*fh*/, void *handle) ZMQ_NOTHROW + : detail::socket_base(handle) + { + } +}; + +#ifdef ZMQ_CPP11 +inline bool operator==(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW +{ + return sr.handle() == nullptr; +} +inline bool operator==(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW +{ + return sr.handle() == nullptr; +} +inline bool operator!=(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW +{ + return !(sr == nullptr); +} +inline bool operator!=(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW +{ + return !(sr == nullptr); +} +#endif + +inline bool operator==(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW +{ + return std::equal_to()(a.handle(), b.handle()); +} +inline bool operator!=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW +{ + return !(a == b); +} +inline bool operator<(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW +{ + return std::less()(a.handle(), b.handle()); +} +inline bool operator>(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW +{ + return b < a; +} +inline bool operator<=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW +{ + return !(a > b); +} +inline bool operator>=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW +{ + return !(a < b); +} + +} // namespace zmq + +#ifdef ZMQ_CPP11 +namespace std +{ +template<> struct hash +{ + size_t operator()(zmq::socket_ref sr) const ZMQ_NOTHROW + { + return hash()(sr.handle()); + } +}; +} // namespace std +#endif + +namespace zmq +{ +class socket_t : public detail::socket_base +{ + friend class monitor_t; + + public: + socket_t() ZMQ_NOTHROW : detail::socket_base(ZMQ_NULLPTR), ctxptr(ZMQ_NULLPTR) {} + + socket_t(context_t &context_, int type_) : + detail::socket_base(zmq_socket(context_.handle(), type_)), + ctxptr(context_.handle()) + { + if (_handle == ZMQ_NULLPTR) + throw error_t(); + } + +#ifdef ZMQ_CPP11 + socket_t(context_t &context_, socket_type type_) : + socket_t(context_, static_cast(type_)) + { + } +#endif + +#ifdef ZMQ_HAS_RVALUE_REFS + socket_t(socket_t &&rhs) ZMQ_NOTHROW : detail::socket_base(rhs._handle), + ctxptr(rhs.ctxptr) + { + rhs._handle = ZMQ_NULLPTR; + rhs.ctxptr = ZMQ_NULLPTR; + } + socket_t &operator=(socket_t &&rhs) ZMQ_NOTHROW + { + close(); + std::swap(_handle, rhs._handle); + std::swap(ctxptr, rhs.ctxptr); + return *this; + } +#endif + + ~socket_t() ZMQ_NOTHROW { close(); } + + operator void *() ZMQ_NOTHROW { return _handle; } + + operator void const *() const ZMQ_NOTHROW { return _handle; } + + void close() ZMQ_NOTHROW + { + if (_handle == ZMQ_NULLPTR) + // already closed + return; + int rc = zmq_close(_handle); + ZMQ_ASSERT(rc == 0); + _handle = ZMQ_NULLPTR; + ctxptr = ZMQ_NULLPTR; + } + + void swap(socket_t &other) ZMQ_NOTHROW + { + std::swap(_handle, other._handle); + std::swap(ctxptr, other.ctxptr); + } + + operator socket_ref() ZMQ_NOTHROW { return socket_ref(from_handle, _handle); } + + private: + void *ctxptr; + + socket_t(const socket_t &) ZMQ_DELETED_FUNCTION; + void operator=(const socket_t &) ZMQ_DELETED_FUNCTION; + + // used by monitor_t + socket_t(void *context_, int type_) : + detail::socket_base(zmq_socket(context_, type_)), ctxptr(context_) + { + if (_handle == ZMQ_NULLPTR) + throw error_t(); + if (ctxptr == ZMQ_NULLPTR) + throw error_t(); + } +}; + +inline void swap(socket_t &a, socket_t &b) ZMQ_NOTHROW +{ + a.swap(b); +} + +ZMQ_DEPRECATED("from 4.3.1, use proxy taking socket_t objects") +inline void proxy(void *frontend, void *backend, void *capture) +{ + int rc = zmq_proxy(frontend, backend, capture); + if (rc != 0) + throw error_t(); +} + +inline void +proxy(socket_ref frontend, socket_ref backend, socket_ref capture = socket_ref()) +{ + int rc = zmq_proxy(frontend.handle(), backend.handle(), capture.handle()); + if (rc != 0) + throw error_t(); +} + +#ifdef ZMQ_HAS_PROXY_STEERABLE +ZMQ_DEPRECATED("from 4.3.1, use proxy_steerable taking socket_t objects") +inline void +proxy_steerable(void *frontend, void *backend, void *capture, void *control) +{ + int rc = zmq_proxy_steerable(frontend, backend, capture, control); + if (rc != 0) + throw error_t(); +} + +inline void proxy_steerable(socket_ref frontend, + socket_ref backend, + socket_ref capture, + socket_ref control) +{ + int rc = zmq_proxy_steerable(frontend.handle(), backend.handle(), + capture.handle(), control.handle()); + if (rc != 0) + throw error_t(); +} +#endif + +class monitor_t +{ + public: + monitor_t() : _socket(), _monitor_socket() {} + + virtual ~monitor_t() { close(); } + +#ifdef ZMQ_HAS_RVALUE_REFS + monitor_t(monitor_t &&rhs) ZMQ_NOTHROW : _socket(), _monitor_socket() + { + std::swap(_socket, rhs._socket); + std::swap(_monitor_socket, rhs._monitor_socket); + } + + monitor_t &operator=(monitor_t &&rhs) ZMQ_NOTHROW + { + close(); + _socket = socket_ref(); + std::swap(_socket, rhs._socket); + std::swap(_monitor_socket, rhs._monitor_socket); + return *this; + } +#endif + + + void + monitor(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL) + { + monitor(socket, addr.c_str(), events); + } + + void monitor(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL) + { + init(socket, addr_, events); + while (true) { + check_event(-1); + } + } + + void init(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL) + { + init(socket, addr.c_str(), events); + } + + void init(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL) + { + int rc = zmq_socket_monitor(socket.handle(), addr_, events); + if (rc != 0) + throw error_t(); + + _socket = socket; + _monitor_socket = socket_t(socket.ctxptr, ZMQ_PAIR); + _monitor_socket.connect(addr_); + + on_monitor_started(); + } + + bool check_event(int timeout = 0) + { + assert(_monitor_socket); + + zmq::message_t eventMsg; + + zmq::pollitem_t items[] = { + {_monitor_socket.handle(), 0, ZMQ_POLLIN, 0}, + }; + + #ifdef ZMQ_CPP11 + zmq::poll(&items[0], 1, std::chrono::milliseconds(timeout)); + #else + zmq::poll(&items[0], 1, timeout); + #endif + + if (items[0].revents & ZMQ_POLLIN) { + int rc = zmq_msg_recv(eventMsg.handle(), _monitor_socket.handle(), 0); + if (rc == -1 && zmq_errno() == ETERM) + return false; + assert(rc != -1); + + } else { + return false; + } + +#if ZMQ_VERSION_MAJOR >= 4 + const char *data = static_cast(eventMsg.data()); + zmq_event_t msgEvent; + memcpy(&msgEvent.event, data, sizeof(uint16_t)); + data += sizeof(uint16_t); + memcpy(&msgEvent.value, data, sizeof(int32_t)); + zmq_event_t *event = &msgEvent; +#else + zmq_event_t *event = static_cast(eventMsg.data()); +#endif + +#ifdef ZMQ_NEW_MONITOR_EVENT_LAYOUT + zmq::message_t addrMsg; + int rc = zmq_msg_recv(addrMsg.handle(), _monitor_socket.handle(), 0); + if (rc == -1 && zmq_errno() == ETERM) { + return false; + } + + assert(rc != -1); + std::string address = addrMsg.to_string(); +#else + // Bit of a hack, but all events in the zmq_event_t union have the same layout so this will work for all event types. + std::string address = event->data.connected.addr; +#endif + +#ifdef ZMQ_EVENT_MONITOR_STOPPED + if (event->event == ZMQ_EVENT_MONITOR_STOPPED) { + return false; + } + +#endif + + switch (event->event) { + case ZMQ_EVENT_CONNECTED: + on_event_connected(*event, address.c_str()); + break; + case ZMQ_EVENT_CONNECT_DELAYED: + on_event_connect_delayed(*event, address.c_str()); + break; + case ZMQ_EVENT_CONNECT_RETRIED: + on_event_connect_retried(*event, address.c_str()); + break; + case ZMQ_EVENT_LISTENING: + on_event_listening(*event, address.c_str()); + break; + case ZMQ_EVENT_BIND_FAILED: + on_event_bind_failed(*event, address.c_str()); + break; + case ZMQ_EVENT_ACCEPTED: + on_event_accepted(*event, address.c_str()); + break; + case ZMQ_EVENT_ACCEPT_FAILED: + on_event_accept_failed(*event, address.c_str()); + break; + case ZMQ_EVENT_CLOSED: + on_event_closed(*event, address.c_str()); + break; + case ZMQ_EVENT_CLOSE_FAILED: + on_event_close_failed(*event, address.c_str()); + break; + case ZMQ_EVENT_DISCONNECTED: + on_event_disconnected(*event, address.c_str()); + break; +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 0) || (defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)) + case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL: + on_event_handshake_failed_no_detail(*event, address.c_str()); + break; + case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL: + on_event_handshake_failed_protocol(*event, address.c_str()); + break; + case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH: + on_event_handshake_failed_auth(*event, address.c_str()); + break; + case ZMQ_EVENT_HANDSHAKE_SUCCEEDED: + on_event_handshake_succeeded(*event, address.c_str()); + break; +#elif defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1) + case ZMQ_EVENT_HANDSHAKE_FAILED: + on_event_handshake_failed(*event, address.c_str()); + break; + case ZMQ_EVENT_HANDSHAKE_SUCCEED: + on_event_handshake_succeed(*event, address.c_str()); + break; +#endif + default: + on_event_unknown(*event, address.c_str()); + break; + } + + return true; + } + +#ifdef ZMQ_EVENT_MONITOR_STOPPED + void abort() + { + if (_socket) + zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0); + + _socket = socket_ref(); + } +#endif + virtual void on_monitor_started() {} + virtual void on_event_connected(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_connect_delayed(const zmq_event_t &event_, + const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_connect_retried(const zmq_event_t &event_, + const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_listening(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_bind_failed(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_accepted(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_accept_failed(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_closed(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_close_failed(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_disconnected(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3) + virtual void on_event_handshake_failed_no_detail(const zmq_event_t &event_, + const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_handshake_failed_protocol(const zmq_event_t &event_, + const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_handshake_failed_auth(const zmq_event_t &event_, + const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_handshake_succeeded(const zmq_event_t &event_, + const char *addr_) + { + (void) event_; + (void) addr_; + } +#elif ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1) + virtual void on_event_handshake_failed(const zmq_event_t &event_, + const char *addr_) + { + (void) event_; + (void) addr_; + } + virtual void on_event_handshake_succeed(const zmq_event_t &event_, + const char *addr_) + { + (void) event_; + (void) addr_; + } +#endif + virtual void on_event_unknown(const zmq_event_t &event_, const char *addr_) + { + (void) event_; + (void) addr_; + } + + private: + monitor_t(const monitor_t &) ZMQ_DELETED_FUNCTION; + void operator=(const monitor_t &) ZMQ_DELETED_FUNCTION; + + socket_ref _socket; + socket_t _monitor_socket; + + void close() ZMQ_NOTHROW + { + if (_socket) + zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0); + _monitor_socket.close(); + } +}; + +#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) + +// polling events +enum class event_flags : short +{ + none = 0, + pollin = ZMQ_POLLIN, + pollout = ZMQ_POLLOUT, + pollerr = ZMQ_POLLERR, + pollpri = ZMQ_POLLPRI +}; + +constexpr event_flags operator|(event_flags a, event_flags b) noexcept +{ + return detail::enum_bit_or(a, b); +} +constexpr event_flags operator&(event_flags a, event_flags b) noexcept +{ + return detail::enum_bit_and(a, b); +} +constexpr event_flags operator^(event_flags a, event_flags b) noexcept +{ + return detail::enum_bit_xor(a, b); +} +constexpr event_flags operator~(event_flags a) noexcept +{ + return detail::enum_bit_not(a); +} + +struct no_user_data; + +// layout compatible with zmq_poller_event_t +template struct poller_event +{ + socket_ref socket; + ::zmq::fd_t fd; + T *user_data; + event_flags events; +}; + +template class poller_t +{ + public: + using event_type = poller_event; + + poller_t() : poller_ptr(zmq_poller_new()) + { + if (!poller_ptr) + throw error_t(); + } + + template< + typename Dummy = void, + typename = + typename std::enable_if::value, Dummy>::type> + void add(zmq::socket_ref socket, event_flags events, T *user_data) + { + add_impl(socket, events, user_data); + } + + void add(zmq::socket_ref socket, event_flags events) + { + add_impl(socket, events, nullptr); + } + + template< + typename Dummy = void, + typename = + typename std::enable_if::value, Dummy>::type> + void add(fd_t fd, event_flags events, T *user_data) + { + add_impl(fd, events, user_data); + } + + void add(fd_t fd, event_flags events) { add_impl(fd, events, nullptr); } + + void remove(zmq::socket_ref socket) + { + if (0 != zmq_poller_remove(poller_ptr.get(), socket.handle())) { + throw error_t(); + } + } + + void modify(zmq::socket_ref socket, event_flags events) + { + if (0 + != zmq_poller_modify(poller_ptr.get(), socket.handle(), + static_cast(events))) { + throw error_t(); + } + } + + size_t wait_all(std::vector &poller_events, + const std::chrono::milliseconds timeout) + { + int rc = zmq_poller_wait_all( + poller_ptr.get(), + reinterpret_cast(poller_events.data()), + static_cast(poller_events.size()), + static_cast(timeout.count())); + if (rc > 0) + return static_cast(rc); + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3) + if (zmq_errno() == EAGAIN) +#else + if (zmq_errno() == ETIMEDOUT) +#endif + return 0; + + throw error_t(); + } + +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3) + size_t size() const noexcept + { + int rc = zmq_poller_size(const_cast(poller_ptr.get())); + ZMQ_ASSERT(rc >= 0); + return static_cast(std::max(rc, 0)); + } +#endif + + private: + struct destroy_poller_t + { + void operator()(void *ptr) noexcept + { + int rc = zmq_poller_destroy(&ptr); + ZMQ_ASSERT(rc == 0); + } + }; + + std::unique_ptr poller_ptr; + + void add_impl(zmq::socket_ref socket, event_flags events, T *user_data) + { + if (0 + != zmq_poller_add(poller_ptr.get(), socket.handle(), user_data, + static_cast(events))) { + throw error_t(); + } + } + + void add_impl(fd_t fd, event_flags events, T *user_data) + { + if (0 + != zmq_poller_add_fd(poller_ptr.get(), fd, user_data, + static_cast(events))) { + throw error_t(); + } + } +}; +#endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) + +inline std::ostream &operator<<(std::ostream &os, const message_t &msg) +{ + return os << msg.str(); +} + +} // namespace zmq + +#endif // __ZMQ_HPP_INCLUDED__ diff --git a/Thirdparty/zeromq/include/zmq_addon.hpp b/Thirdparty/zeromq/include/zmq_addon.hpp new file mode 100644 index 0000000..958eec5 --- /dev/null +++ b/Thirdparty/zeromq/include/zmq_addon.hpp @@ -0,0 +1,753 @@ +/* + Copyright (c) 2016-2017 ZeroMQ community + Copyright (c) 2016 VOCA AS / Harald N酶kland + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. +*/ + +#ifndef __ZMQ_ADDON_HPP_INCLUDED__ +#define __ZMQ_ADDON_HPP_INCLUDED__ + +#include "zmq.hpp" + +#include +#include +#include +#include +#ifdef ZMQ_CPP11 +#include +#include +#include +#endif + +namespace zmq +{ +#ifdef ZMQ_CPP11 + +namespace detail +{ +template +recv_result_t +recv_multipart_n(socket_ref s, OutputIt out, size_t n, recv_flags flags) +{ + size_t msg_count = 0; + message_t msg; + while (true) { + if ZMQ_CONSTEXPR_IF (CheckN) { + if (msg_count >= n) + throw std::runtime_error( + "Too many message parts in recv_multipart_n"); + } + if (!s.recv(msg, flags)) { + // zmq ensures atomic delivery of messages + assert(msg_count == 0); + return {}; + } + ++msg_count; + const bool more = msg.more(); + *out++ = std::move(msg); + if (!more) + break; + } + return msg_count; +} + +inline bool is_little_endian() +{ + const uint16_t i = 0x01; + return *reinterpret_cast(&i) == 0x01; +} + +inline void write_network_order(unsigned char *buf, const uint32_t value) +{ + if (is_little_endian()) { + ZMQ_CONSTEXPR_VAR uint32_t mask = (std::numeric_limits::max)(); + *buf++ = static_cast((value >> 24) & mask); + *buf++ = static_cast((value >> 16) & mask); + *buf++ = static_cast((value >> 8) & mask); + *buf++ = static_cast(value & mask); + } else { + std::memcpy(buf, &value, sizeof(value)); + } +} + +inline uint32_t read_u32_network_order(const unsigned char *buf) +{ + if (is_little_endian()) { + return (static_cast(buf[0]) << 24) + + (static_cast(buf[1]) << 16) + + (static_cast(buf[2]) << 8) + + static_cast(buf[3]); + } else { + uint32_t value; + std::memcpy(&value, buf, sizeof(value)); + return value; + } +} +} // namespace detail + +/* Receive a multipart message. + + Writes the zmq::message_t objects to OutputIterator out. + The out iterator must handle an unspecified number of writes, + e.g. by using std::back_inserter. + + Returns: the number of messages received or nullopt (on EAGAIN). + Throws: if recv throws. Any exceptions thrown + by the out iterator will be propagated and the message + may have been only partially received with pending + message parts. It is adviced to close this socket in that event. +*/ +template +ZMQ_NODISCARD recv_result_t recv_multipart(socket_ref s, + OutputIt out, + recv_flags flags = recv_flags::none) +{ + return detail::recv_multipart_n(s, std::move(out), 0, flags); +} + +/* Receive a multipart message. + + Writes at most n zmq::message_t objects to OutputIterator out. + If the number of message parts of the incoming message exceeds n + then an exception will be thrown. + + Returns: the number of messages received or nullopt (on EAGAIN). + Throws: if recv throws. Throws std::runtime_error if the number + of message parts exceeds n (exactly n messages will have been written + to out). Any exceptions thrown + by the out iterator will be propagated and the message + may have been only partially received with pending + message parts. It is adviced to close this socket in that event. +*/ +template +ZMQ_NODISCARD recv_result_t recv_multipart_n(socket_ref s, + OutputIt out, + size_t n, + recv_flags flags = recv_flags::none) +{ + return detail::recv_multipart_n(s, std::move(out), n, flags); +} + +/* Send a multipart message. + + The range must be a ForwardRange of zmq::message_t, + zmq::const_buffer or zmq::mutable_buffer. + The flags may be zmq::send_flags::sndmore if there are + more message parts to be sent after the call to this function. + + Returns: the number of messages sent (exactly msgs.size()) or nullopt (on EAGAIN). + Throws: if send throws. Any exceptions thrown + by the msgs range will be propagated and the message + may have been only partially sent. It is adviced to close this socket in that event. +*/ +template::value + && (std::is_same, message_t>::value + || detail::is_buffer>::value)>::type +#endif + > +send_result_t +send_multipart(socket_ref s, Range &&msgs, send_flags flags = send_flags::none) +{ + using std::begin; + using std::end; + auto it = begin(msgs); + const auto end_it = end(msgs); + size_t msg_count = 0; + while (it != end_it) { + const auto next = std::next(it); + const auto msg_flags = + flags | (next == end_it ? send_flags::none : send_flags::sndmore); + if (!s.send(*it, msg_flags)) { + // zmq ensures atomic delivery of messages + assert(it == begin(msgs)); + return {}; + } + ++msg_count; + it = next; + } + return msg_count; +} + +/* Encode a multipart message. + + The range must be a ForwardRange of zmq::message_t. A + zmq::multipart_t or STL container may be passed for encoding. + + Returns: a zmq::message_t holding the encoded multipart data. + + Throws: std::range_error is thrown if the size of any single part + can not fit in an unsigned 32 bit integer. + + The encoding is compatible with that used by the CZMQ function + zmsg_encode(), see https://rfc.zeromq.org/spec/50/. + Each part consists of a size followed by the data. + These are placed contiguously into the output message. A part of + size less than 255 bytes will have a single byte size value. + Larger parts will have a five byte size value with the first byte + set to 0xFF and the remaining four bytes holding the size of the + part's data. +*/ +template::value + && (std::is_same, message_t>::value + || detail::is_buffer>::value)>::type +#endif + > +message_t encode(const Range &parts) +{ + size_t mmsg_size = 0; + + // First pass check sizes + for (const auto &part : parts) { + const size_t part_size = part.size(); + if (part_size > (std::numeric_limits::max)()) { + // Size value must fit into uint32_t. + throw std::range_error("Invalid size, message part too large"); + } + const size_t count_size = + part_size < (std::numeric_limits::max)() ? 1 : 5; + mmsg_size += part_size + count_size; + } + + message_t encoded(mmsg_size); + unsigned char *buf = encoded.data(); + for (const auto &part : parts) { + const uint32_t part_size = static_cast(part.size()); + const unsigned char *part_data = + static_cast(part.data()); + + if (part_size < (std::numeric_limits::max)()) { + // small part + *buf++ = (unsigned char) part_size; + } else { + // big part + *buf++ = (std::numeric_limits::max)(); + detail::write_network_order(buf, part_size); + buf += sizeof(part_size); + } + std::memcpy(buf, part_data, part_size); + buf += part_size; + } + + assert(static_cast(buf - encoded.data()) == mmsg_size); + return encoded; +} + +/* Decode an encoded message to multiple parts. + + The given output iterator must be a ForwardIterator to a container + holding zmq::message_t such as a zmq::multipart_t or various STL + containers. + + Returns the ForwardIterator advanced once past the last decoded + part. + + Throws: a std::out_of_range is thrown if the encoded part sizes + lead to exceeding the message data bounds. + + The decoding assumes the message is encoded in the manner + performed by zmq::encode(), see https://rfc.zeromq.org/spec/50/. + */ +template OutputIt decode(const message_t &encoded, OutputIt out) +{ + const unsigned char *source = encoded.data(); + const unsigned char *const limit = source + encoded.size(); + + while (source < limit) { + size_t part_size = *source++; + if (part_size == (std::numeric_limits::max)()) { + if (static_cast(limit - source) < sizeof(uint32_t)) { + throw std::out_of_range( + "Malformed encoding, overflow in reading size"); + } + part_size = detail::read_u32_network_order(source); + // the part size is allowed to be less than 0xFF + source += sizeof(uint32_t); + } + + if (static_cast(limit - source) < part_size) { + throw std::out_of_range("Malformed encoding, overflow in reading part"); + } + *out = message_t(source, part_size); + ++out; + source += part_size; + } + + assert(source == limit); + return out; +} + +#endif + + +#ifdef ZMQ_HAS_RVALUE_REFS + +/* + This class handles multipart messaging. It is the C++ equivalent of zmsg.h, + which is part of CZMQ (the high-level C binding). Furthermore, it is a major + improvement compared to zmsg.hpp, which is part of the examples in the 脴MQ + Guide. Unnecessary copying is avoided by using move semantics to efficiently + add/remove parts. +*/ +class multipart_t +{ + private: + std::deque m_parts; + + public: + typedef std::deque::value_type value_type; + + typedef std::deque::iterator iterator; + typedef std::deque::const_iterator const_iterator; + + typedef std::deque::reverse_iterator reverse_iterator; + typedef std::deque::const_reverse_iterator const_reverse_iterator; + + // Default constructor + multipart_t() {} + + // Construct from socket receive + multipart_t(socket_ref socket) { recv(socket); } + + // Construct from memory block + multipart_t(const void *src, size_t size) { addmem(src, size); } + + // Construct from string + multipart_t(const std::string &string) { addstr(string); } + + // Construct from message part + multipart_t(message_t &&message) { add(std::move(message)); } + + // Move constructor + multipart_t(multipart_t &&other) ZMQ_NOTHROW { m_parts = std::move(other.m_parts); } + + // Move assignment operator + multipart_t &operator=(multipart_t &&other) ZMQ_NOTHROW + { + m_parts = std::move(other.m_parts); + return *this; + } + + // Destructor + virtual ~multipart_t() { clear(); } + + message_t &operator[](size_t n) { return m_parts[n]; } + + const message_t &operator[](size_t n) const { return m_parts[n]; } + + message_t &at(size_t n) { return m_parts.at(n); } + + const message_t &at(size_t n) const { return m_parts.at(n); } + + iterator begin() { return m_parts.begin(); } + + const_iterator begin() const { return m_parts.begin(); } + + const_iterator cbegin() const { return m_parts.cbegin(); } + + reverse_iterator rbegin() { return m_parts.rbegin(); } + + const_reverse_iterator rbegin() const { return m_parts.rbegin(); } + + iterator end() { return m_parts.end(); } + + const_iterator end() const { return m_parts.end(); } + + const_iterator cend() const { return m_parts.cend(); } + + reverse_iterator rend() { return m_parts.rend(); } + + const_reverse_iterator rend() const { return m_parts.rend(); } + + // Delete all parts + void clear() { m_parts.clear(); } + + // Get number of parts + size_t size() const { return m_parts.size(); } + + // Check if number of parts is zero + bool empty() const { return m_parts.empty(); } + + // Receive multipart message from socket + bool recv(socket_ref socket, int flags = 0) + { + clear(); + bool more = true; + while (more) { + message_t message; +#ifdef ZMQ_CPP11 + if (!socket.recv(message, static_cast(flags))) + return false; +#else + if (!socket.recv(&message, flags)) + return false; +#endif + more = message.more(); + add(std::move(message)); + } + return true; + } + + // Send multipart message to socket + bool send(socket_ref socket, int flags = 0) + { + flags &= ~(ZMQ_SNDMORE); + bool more = size() > 0; + while (more) { + message_t message = pop(); + more = size() > 0; +#ifdef ZMQ_CPP11 + if (!socket.send(message, static_cast( + (more ? ZMQ_SNDMORE : 0) | flags))) + return false; +#else + if (!socket.send(message, (more ? ZMQ_SNDMORE : 0) | flags)) + return false; +#endif + } + clear(); + return true; + } + + // Concatenate other multipart to front + void prepend(multipart_t &&other) + { + while (!other.empty()) + push(other.remove()); + } + + // Concatenate other multipart to back + void append(multipart_t &&other) + { + while (!other.empty()) + add(other.pop()); + } + + // Push memory block to front + void pushmem(const void *src, size_t size) + { + m_parts.push_front(message_t(src, size)); + } + + // Push memory block to back + void addmem(const void *src, size_t size) + { + m_parts.push_back(message_t(src, size)); + } + + // Push string to front + void pushstr(const std::string &string) + { + m_parts.push_front(message_t(string.data(), string.size())); + } + + // Push string to back + void addstr(const std::string &string) + { + m_parts.push_back(message_t(string.data(), string.size())); + } + + // Push type (fixed-size) to front + template void pushtyp(const T &type) + { + static_assert(!std::is_same::value, + "Use pushstr() instead of pushtyp()"); + m_parts.push_front(message_t(&type, sizeof(type))); + } + + // Push type (fixed-size) to back + template void addtyp(const T &type) + { + static_assert(!std::is_same::value, + "Use addstr() instead of addtyp()"); + m_parts.push_back(message_t(&type, sizeof(type))); + } + + // Push message part to front + void push(message_t &&message) { m_parts.push_front(std::move(message)); } + + // Push message part to back + void add(message_t &&message) { m_parts.push_back(std::move(message)); } + + // Alias to allow std::back_inserter() + void push_back(message_t &&message) { m_parts.push_back(std::move(message)); } + + // Pop string from front + std::string popstr() + { + std::string string(m_parts.front().data(), m_parts.front().size()); + m_parts.pop_front(); + return string; + } + + // Pop type (fixed-size) from front + template T poptyp() + { + static_assert(!std::is_same::value, + "Use popstr() instead of poptyp()"); + if (sizeof(T) != m_parts.front().size()) + throw std::runtime_error( + "Invalid type, size does not match the message size"); + T type = *m_parts.front().data(); + m_parts.pop_front(); + return type; + } + + // Pop message part from front + message_t pop() + { + message_t message = std::move(m_parts.front()); + m_parts.pop_front(); + return message; + } + + // Pop message part from back + message_t remove() + { + message_t message = std::move(m_parts.back()); + m_parts.pop_back(); + return message; + } + + // get message part from front + const message_t &front() { return m_parts.front(); } + + // get message part from back + const message_t &back() { return m_parts.back(); } + + // Get pointer to a specific message part + const message_t *peek(size_t index) const { return &m_parts[index]; } + + // Get a string copy of a specific message part + std::string peekstr(size_t index) const + { + std::string string(m_parts[index].data(), m_parts[index].size()); + return string; + } + + // Peek type (fixed-size) from front + template T peektyp(size_t index) const + { + static_assert(!std::is_same::value, + "Use peekstr() instead of peektyp()"); + if (sizeof(T) != m_parts[index].size()) + throw std::runtime_error( + "Invalid type, size does not match the message size"); + T type = *m_parts[index].data(); + return type; + } + + // Create multipart from type (fixed-size) + template static multipart_t create(const T &type) + { + multipart_t multipart; + multipart.addtyp(type); + return multipart; + } + + // Copy multipart + multipart_t clone() const + { + multipart_t multipart; + for (size_t i = 0; i < size(); i++) + multipart.addmem(m_parts[i].data(), m_parts[i].size()); + return multipart; + } + + // Dump content to string + std::string str() const + { + std::stringstream ss; + for (size_t i = 0; i < m_parts.size(); i++) { + const unsigned char *data = m_parts[i].data(); + size_t size = m_parts[i].size(); + + // Dump the message as text or binary + bool isText = true; + for (size_t j = 0; j < size; j++) { + if (data[j] < 32 || data[j] > 127) { + isText = false; + break; + } + } + ss << "\n[" << std::dec << std::setw(3) << std::setfill('0') << size + << "] "; + if (size >= 1000) { + ss << "... (too big to print)"; + continue; + } + for (size_t j = 0; j < size; j++) { + if (isText) + ss << static_cast(data[j]); + else + ss << std::hex << std::setw(2) << std::setfill('0') + << static_cast(data[j]); + } + } + return ss.str(); + } + + // Check if equal to other multipart + bool equal(const multipart_t *other) const ZMQ_NOTHROW + { + return *this == *other; + } + + bool operator==(const multipart_t &other) const ZMQ_NOTHROW + { + if (size() != other.size()) + return false; + for (size_t i = 0; i < size(); i++) + if (at(i) != other.at(i)) + return false; + return true; + } + + bool operator!=(const multipart_t &other) const ZMQ_NOTHROW + { + return !(*this == other); + } + +#ifdef ZMQ_CPP11 + + // Return single part message_t encoded from this multipart_t. + message_t encode() const { return zmq::encode(*this); } + + // Decode encoded message into multiple parts and append to self. + void decode_append(const message_t &encoded) + { + zmq::decode(encoded, std::back_inserter(*this)); + } + + // Return a new multipart_t containing the decoded message_t. + static multipart_t decode(const message_t &encoded) + { + multipart_t tmp; + zmq::decode(encoded, std::back_inserter(tmp)); + return tmp; + } + +#endif + + private: + // Disable implicit copying (moving is more efficient) + multipart_t(const multipart_t &other) ZMQ_DELETED_FUNCTION; + void operator=(const multipart_t &other) ZMQ_DELETED_FUNCTION; +}; // class multipart_t + +inline std::ostream &operator<<(std::ostream &os, const multipart_t &msg) +{ + return os << msg.str(); +} + +#endif // ZMQ_HAS_RVALUE_REFS + +#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) +class active_poller_t +{ + public: + active_poller_t() = default; + ~active_poller_t() = default; + + active_poller_t(const active_poller_t &) = delete; + active_poller_t &operator=(const active_poller_t &) = delete; + + active_poller_t(active_poller_t &&src) = default; + active_poller_t &operator=(active_poller_t &&src) = default; + + using handler_type = std::function; + + void add(zmq::socket_ref socket, event_flags events, handler_type handler) + { + if (!handler) + throw std::invalid_argument("null handler in active_poller_t::add"); + auto ret = handlers.emplace( + socket, std::make_shared(std::move(handler))); + if (!ret.second) + throw error_t(EINVAL); // already added + try { + base_poller.add(socket, events, ret.first->second.get()); + need_rebuild = true; + } + catch (...) { + // rollback + handlers.erase(socket); + throw; + } + } + + void remove(zmq::socket_ref socket) + { + base_poller.remove(socket); + handlers.erase(socket); + need_rebuild = true; + } + + void modify(zmq::socket_ref socket, event_flags events) + { + base_poller.modify(socket, events); + } + + size_t wait(std::chrono::milliseconds timeout) + { + if (need_rebuild) { + poller_events.resize(handlers.size()); + poller_handlers.clear(); + poller_handlers.reserve(handlers.size()); + for (const auto &handler : handlers) { + poller_handlers.push_back(handler.second); + } + need_rebuild = false; + } + const auto count = base_poller.wait_all(poller_events, timeout); + std::for_each(poller_events.begin(), + poller_events.begin() + static_cast(count), + [](decltype(base_poller)::event_type &event) { + assert(event.user_data != nullptr); + (*event.user_data)(event.events); + }); + return count; + } + + ZMQ_NODISCARD bool empty() const noexcept { return handlers.empty(); } + + size_t size() const noexcept { return handlers.size(); } + + private: + bool need_rebuild{false}; + + poller_t base_poller{}; + std::unordered_map> handlers{}; + std::vector poller_events{}; + std::vector> poller_handlers{}; +}; // class active_poller_t +#endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) + + +} // namespace zmq + +#endif // __ZMQ_ADDON_HPP_INCLUDED__ diff --git a/Thirdparty/zeromq/include/zmq_utils.h b/Thirdparty/zeromq/include/zmq_utils.h new file mode 100644 index 0000000..c409406 --- /dev/null +++ b/Thirdparty/zeromq/include/zmq_utils.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: MPL-2.0 */ + +/* This file is deprecated, and all its functionality provided by zmq.h */ +/* Note that -Wpedantic compilation requires GCC to avoid using its custom + extensions such as #warning, hence the trick below. Also, pragmas for + warnings or other messages are not standard, not portable, and not all + compilers even have an equivalent concept. + So in the worst case, this include file is treated as silently empty. */ + +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) \ + || defined(_MSC_VER) +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic push +#pragma GCC diagnostic warning "-Wcpp" +#pragma GCC diagnostic ignored "-Werror" +#pragma GCC diagnostic ignored "-Wall" +#endif +#pragma message( \ + "Warning: zmq_utils.h is deprecated. All its functionality is provided by zmq.h.") +#if defined(__GNUC__) || defined(__GNUG__) +#pragma GCC diagnostic pop +#endif +#endif diff --git a/Thirdparty/zeromq/lib/libzmq-mt-4_3_5.lib b/Thirdparty/zeromq/lib/libzmq-mt-4_3_5.lib new file mode 100644 index 0000000..b124802 Binary files /dev/null and b/Thirdparty/zeromq/lib/libzmq-mt-4_3_5.lib differ diff --git a/Thirdparty/zeromq/lib/pkgconfig/libzmq.pc b/Thirdparty/zeromq/lib/pkgconfig/libzmq.pc new file mode 100644 index 0000000..37837d1 --- /dev/null +++ b/Thirdparty/zeromq/lib/pkgconfig/libzmq.pc @@ -0,0 +1,13 @@ +prefix=${pcfiledir}/../.. +exec_prefix=${prefix} +libdir=${prefix}/lib +includedir=${prefix}/include + +Name: libzmq +Description: 0MQ c++ library +Version: 4.3.5 +Libs: "-L${libdir}" -lzmq +Libs.private: -lstdc++ +Requires.private: +Cflags: "-I${includedir}" + diff --git a/Thirdparty/zeromq/share/zeromq/ZeroMQConfig.cmake b/Thirdparty/zeromq/share/zeromq/ZeroMQConfig.cmake new file mode 100644 index 0000000..b7e82b0 --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/ZeroMQConfig.cmake @@ -0,0 +1,58 @@ +# ZeroMQ cmake module +# +# The following import targets are created +# +# :: +# +# libzmq-static +# libzmq +# +# This module sets the following variables in your project:: +# +# ZeroMQ_FOUND - true if ZeroMQ found on the system +# ZeroMQ_INCLUDE_DIR - the directory containing ZeroMQ headers +# ZeroMQ_LIBRARY - +# ZeroMQ_STATIC_LIBRARY + + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was ZeroMQConfig.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +macro(check_required_components _NAME) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(NOT ${_NAME}_${comp}_FOUND) + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + endif() + endif() + endforeach() +endmacro() + +#################################################################################### + +if(NOT TARGET libzmq AND NOT TARGET libzmq-static) + include("${CMAKE_CURRENT_LIST_DIR}/ZeroMQTargets.cmake") + + if (TARGET libzmq) + get_target_property(ZeroMQ_INCLUDE_DIR libzmq INTERFACE_INCLUDE_DIRECTORIES) + else () + get_target_property(ZeroMQ_INCLUDE_DIR libzmq-static INTERFACE_INCLUDE_DIRECTORIES) + endif() + + if (TARGET libzmq) + get_target_property(ZeroMQ_LIBRARY libzmq LOCATION) + endif() + if (TARGET libzmq-static) + get_target_property(ZeroMQ_STATIC_LIBRARY libzmq-static LOCATION) + endif() +endif() diff --git a/Thirdparty/zeromq/share/zeromq/ZeroMQConfigVersion.cmake b/Thirdparty/zeromq/share/zeromq/ZeroMQConfigVersion.cmake new file mode 100644 index 0000000..32be624 --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/ZeroMQConfigVersion.cmake @@ -0,0 +1,43 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version. +# The variable CVF_VERSION must be set before calling configure_file(). + +set(PACKAGE_VERSION "4.3.5") + +if (PACKAGE_FIND_VERSION_RANGE) + # Package version must be in the requested version range + if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN) + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + endif() +else() + if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() + + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/Thirdparty/zeromq/share/zeromq/ZeroMQTargets-debug.cmake b/Thirdparty/zeromq/share/zeromq/ZeroMQTargets-debug.cmake new file mode 100644 index 0000000..b2795c0 --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/ZeroMQTargets-debug.cmake @@ -0,0 +1,20 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Debug". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "libzmq" for configuration "Debug" +set_property(TARGET libzmq APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) +set_target_properties(libzmq PROPERTIES + IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/debug/lib/libzmq-mt-gd-4_3_5.lib" + IMPORTED_LINK_INTERFACE_LIBRARIES_DEBUG "ws2_32;advapi32;rpcrt4;iphlpapi" + IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/debug/bin/libzmq-mt-gd-4_3_5.dll" + ) + +list(APPEND _cmake_import_check_targets libzmq ) +list(APPEND _cmake_import_check_files_for_libzmq "${_IMPORT_PREFIX}/debug/lib/libzmq-mt-gd-4_3_5.lib" "${_IMPORT_PREFIX}/debug/bin/libzmq-mt-gd-4_3_5.dll" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/Thirdparty/zeromq/share/zeromq/ZeroMQTargets-release.cmake b/Thirdparty/zeromq/share/zeromq/ZeroMQTargets-release.cmake new file mode 100644 index 0000000..5072738 --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/ZeroMQTargets-release.cmake @@ -0,0 +1,20 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "libzmq" for configuration "Release" +set_property(TARGET libzmq APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(libzmq PROPERTIES + IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/libzmq-mt-4_3_5.lib" + IMPORTED_LINK_INTERFACE_LIBRARIES_RELEASE "ws2_32;advapi32;rpcrt4;iphlpapi" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/libzmq-mt-4_3_5.dll" + ) + +list(APPEND _cmake_import_check_targets libzmq ) +list(APPEND _cmake_import_check_files_for_libzmq "${_IMPORT_PREFIX}/lib/libzmq-mt-4_3_5.lib" "${_IMPORT_PREFIX}/bin/libzmq-mt-4_3_5.dll" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/Thirdparty/zeromq/share/zeromq/ZeroMQTargets.cmake b/Thirdparty/zeromq/share/zeromq/ZeroMQTargets.cmake new file mode 100644 index 0000000..93374e4 --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/ZeroMQTargets.cmake @@ -0,0 +1,105 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.27) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS libzmq) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target libzmq +add_library(libzmq SHARED IMPORTED) + +set_target_properties(libzmq PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" +) + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/ZeroMQTargets-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + if(CMAKE_VERSION VERSION_LESS "3.28" + OR NOT DEFINED _cmake_import_check_xcframework_for_${_cmake_target} + OR NOT IS_DIRECTORY "${_cmake_import_check_xcframework_for_${_cmake_target}}") + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + endif() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/Thirdparty/zeromq/share/zeromq/copyright b/Thirdparty/zeromq/share/zeromq/copyright new file mode 100644 index 0000000..a612ad9 --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/copyright @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/Thirdparty/zeromq/share/zeromq/vcpkg-cmake-wrapper.cmake b/Thirdparty/zeromq/share/zeromq/vcpkg-cmake-wrapper.cmake new file mode 100644 index 0000000..5e4f46b --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/vcpkg-cmake-wrapper.cmake @@ -0,0 +1,9 @@ +_find_package(${ARGS}) + +if(TARGET libzmq AND NOT TARGET libzmq-static) + add_library(libzmq-static INTERFACE IMPORTED) + set_target_properties(libzmq-static PROPERTIES INTERFACE_LINK_LIBRARIES libzmq) +elseif(TARGET libzmq-static AND NOT TARGET libzmq) + add_library(libzmq INTERFACE IMPORTED) + set_target_properties(libzmq PROPERTIES INTERFACE_LINK_LIBRARIES libzmq-static) +endif() diff --git a/Thirdparty/zeromq/share/zeromq/vcpkg.spdx.json b/Thirdparty/zeromq/share/zeromq/vcpkg.spdx.json new file mode 100644 index 0000000..cc157c0 --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/vcpkg.spdx.json @@ -0,0 +1,154 @@ +{ + "$schema": "https://raw.githubusercontent.com/spdx/spdx-spec/v2.2.1/schemas/spdx-schema.json", + "spdxVersion": "SPDX-2.2", + "dataLicense": "CC0-1.0", + "SPDXID": "SPDXRef-DOCUMENT", + "documentNamespace": "https://spdx.org/spdxdocs/zeromq-x64-windows-4.3.5#1-349127b2-9538-443a-9e20-551b46fc22e0", + "name": "zeromq:x64-windows@4.3.5#1 48055f4994a97a653c3cbc44973eeba770ab272f83c012f810b1343e1b945c7a", + "creationInfo": { + "creators": [ + "Tool: vcpkg-d6945642ee5c3076addd1a42c331bbf4cfc97457" + ], + "created": "2024-12-08T08:19:21Z" + }, + "relationships": [ + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "GENERATES", + "relatedSpdxElement": "SPDXRef-binary" + }, + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-file-0" + }, + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-file-1" + }, + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-file-2" + }, + { + "spdxElementId": "SPDXRef-port", + "relationshipType": "CONTAINS", + "relatedSpdxElement": "SPDXRef-file-3" + }, + { + "spdxElementId": "SPDXRef-binary", + "relationshipType": "GENERATED_FROM", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-0", + "relationshipType": "CONTAINED_BY", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-1", + "relationshipType": "CONTAINED_BY", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-2", + "relationshipType": "CONTAINED_BY", + "relatedSpdxElement": "SPDXRef-port" + }, + { + "spdxElementId": "SPDXRef-file-3", + "relationshipType": "CONTAINED_BY", + "relatedSpdxElement": "SPDXRef-port" + } + ], + "packages": [ + { + "name": "zeromq", + "SPDXID": "SPDXRef-port", + "versionInfo": "4.3.5#1", + "downloadLocation": "git+https://github.com/Microsoft/vcpkg#ports/zeromq", + "homepage": "https://github.com/zeromq/libzmq", + "licenseConcluded": "MPL-2.0", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "description": "The ZeroMQ lightweight messaging kernel is a library which extends the standard socket interfaces with features traditionally provided by specialised messaging middleware products", + "comment": "This is the port (recipe) consumed by vcpkg." + }, + { + "name": "zeromq:x64-windows", + "SPDXID": "SPDXRef-binary", + "versionInfo": "48055f4994a97a653c3cbc44973eeba770ab272f83c012f810b1343e1b945c7a", + "downloadLocation": "NONE", + "licenseConcluded": "MPL-2.0", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "comment": "This is a binary package built by vcpkg." + }, + { + "SPDXID": "SPDXRef-resource-1", + "name": "zeromq/libzmq", + "downloadLocation": "git+https://github.com/zeromq/libzmq@v4.3.5", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "copyrightText": "NOASSERTION", + "checksums": [ + { + "algorithm": "SHA512", + "checksumValue": "108d9c5fa761c111585c30f9c651ed92942dda0ac661155bca52cc7b6dbeb3d27b0dd994abde206eacfc3bc88d19ed24e45b291050c38469e34dca5f8c9a037d" + } + ] + } + ], + "files": [ + { + "fileName": "./D:/vcpkg/ports/zeromq/fix-arm.patch", + "SPDXID": "SPDXRef-file-0", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "4d231802a3981e3beb343818314826e58813732bfd70851c31b76682b88f0b97" + } + ], + "licenseConcluded": "NOASSERTION", + "copyrightText": "NOASSERTION" + }, + { + "fileName": "./D:/vcpkg/ports/zeromq/portfile.cmake", + "SPDXID": "SPDXRef-file-1", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "f25d59456e32ea7fb294369bda6db00d9d7d1d786d611bbebdb90e55422d1fa2" + } + ], + "licenseConcluded": "NOASSERTION", + "copyrightText": "NOASSERTION" + }, + { + "fileName": "./D:/vcpkg/ports/zeromq/vcpkg-cmake-wrapper.cmake", + "SPDXID": "SPDXRef-file-2", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "19043ac8e3a04cce2d94c59de9909704fa130cf2a340ea164d2a484bc7ce66dc" + } + ], + "licenseConcluded": "NOASSERTION", + "copyrightText": "NOASSERTION" + }, + { + "fileName": "./D:/vcpkg/ports/zeromq/vcpkg.json", + "SPDXID": "SPDXRef-file-3", + "checksums": [ + { + "algorithm": "SHA256", + "checksumValue": "431f307cadda8a3a6b52a407534180e066ca51830708d3b5843fcb39f4ffe559" + } + ], + "licenseConcluded": "NOASSERTION", + "copyrightText": "NOASSERTION" + } + ] +} diff --git a/Thirdparty/zeromq/share/zeromq/vcpkg_abi_info.txt b/Thirdparty/zeromq/share/zeromq/vcpkg_abi_info.txt new file mode 100644 index 0000000..c84b46a --- /dev/null +++ b/Thirdparty/zeromq/share/zeromq/vcpkg_abi_info.txt @@ -0,0 +1,19 @@ +cmake 3.29.2 +features core +fix-arm.patch 4d231802a3981e3beb343818314826e58813732bfd70851c31b76682b88f0b97 +portfile.cmake f25d59456e32ea7fb294369bda6db00d9d7d1d786d611bbebdb90e55422d1fa2 +ports.cmake 0500e9e2422fe0084c99bdd0c9de4c7069b76da14c8b58228a7e95ebac43058a +post_build_checks 2 +powershell 7.2.16 +triplet x64-windows +triplet_abi 4556164a2cd3dd6f4742101eabb46def7e71b6e5856faa88e5d005aac12a803c-e36df1c7f50ab25f9c182fa927d06c19ae082e0d599f132b3f655784b49e4b33-c543948ecd5e4a5a4e61ec771337c095046b3106 +vcpkg-cmake 72c5fcc62d00fc527722f20df38cecd04017a2536592f15d130686fee7f84fae +vcpkg-cmake-config 78775ea32d130eefb88a2359faa43f7a017f907f38b1ed404424fe22953155ff +vcpkg-cmake-wrapper.cmake 19043ac8e3a04cce2d94c59de9909704fa130cf2a340ea164d2a484bc7ce66dc +vcpkg.json 431f307cadda8a3a6b52a407534180e066ca51830708d3b5843fcb39f4ffe559 +vcpkg_check_features 943b217e0968d64cf2cb9c272608e6a0b497377e792034f819809a79e1502c2b +vcpkg_copy_pdbs d57e4f196c82dc562a9968c6155073094513c31e2de475694143d3aa47954b1c +vcpkg_fixup_pkgconfig 904e67c46ecbb67379911bc1d7222855c0cbfcf1129bf47783858bcf0cc44970 +vcpkg_from_git 96ed81968f76354c00096dd8cd4e63c6a235fa969334a11ab18d11c0c512ff58 +vcpkg_from_github b743742296a114ea1b18ae99672e02f142c4eb2bef7f57d36c038bedbfb0502f +vcpkg_install_copyright ba6c169ab4e59fa05682e530cdeb883767de22c8391f023d4e6844a7ec5dd3d2 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b6bed94..85f610f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -25,6 +25,7 @@ INCLUDE_DIRECTORIES( ${Thirdparty} ${Thirdparty}/spdlog/include ${Thirdparty}/libipc/include + ${Thirdparty}/zeromq/include ) link_directories( @@ -32,6 +33,7 @@ link_directories( ${Thirdparty}/glew/lib ${Thirdparty}/spdlog/lib ${Thirdparty}/libipc/lib + ${Thirdparty}/zeromq/debug/lib ) # IF(CMAKE_SIZEOF_VOID_P EQUAL 8) @@ -60,15 +62,17 @@ add_executable(${PROJECT_NAME} IF(WIN32) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES COMPILE_FLAGS "/MP") ENDIF(WIN32) - + target_link_libraries( ${PROJECT_NAME} PRIVATE + Winmm opengl32 glew32s glfw3 debug spdlogd optimized spdlog + libzmq-mt-gd-4_3_5 ) diff --git a/src/ImageBuffer.cpp b/src/ImageBuffer.cpp index 4b84b1a..e8d4f8d 100644 --- a/src/ImageBuffer.cpp +++ b/src/ImageBuffer.cpp @@ -2,6 +2,8 @@ #include "Texture2D.h" #include "Core/Thread/ScopeLock.h" +#include "VHI/VHI.h" +#include "Ipc/IpcMoudle.h" ImageBuffer* Singleton::instance_ = nullptr; @@ -19,12 +21,6 @@ void ImageBuffer::PushImage(ImageBuffer::IBType type, std::vector case ImageBuffer::IBType::Human: PushHumanImage(std::move(data), width, height, comp); break; - case ImageBuffer::IBType::Face: - PushFaceImage(std::move(data), width, height, comp); - break; - case ImageBuffer::IBType::FaceMask: - PushFaceMaskImage(std::move(data), width, height, comp); - break; default: break; } @@ -35,39 +31,56 @@ void ImageBuffer::Update(IBType type, Texture2D* texture) { case ImageBuffer::IBType::Human: UpdateHuman(texture); break; - - case IBType::Face: - UpdateFace(texture); - - case IBType::FaceMask: - UpdateFaceMask(texture); - default: break; } } void ImageBuffer::PushHumanImage(std::vector data, uint32 width, uint32 height, uint32 comp) { - ScopeLock lock(&human_cs_); - - human_.data = std::move(data); - human_.width = width; - human_.height = height; - human_.comp = comp; - human_.updated = true; + Image image{ std::move(data), width, height, comp, false }; + + { + ScopeLock lock(&human_cs_); + human_.emplace(std::move(image)); + + } } void ImageBuffer::UpdateHuman(Texture2D* texture) { - if (human_.data.empty()) { + int count = 0; + { + ScopeLock lock(&human_cs_); + if (human_.empty()) { + return; + } + count = human_.size(); + } + + if (playedIndex_ > VHI::Get()->GetAudioRender()->GetClock()+2) { return; } - ScopeLock lock(&human_cs_); - if (!human_.updated) { - return; + if (count > 10) { + constexpr char full[] = "full"; + IpcMoudle::Get()->Send(full, sizeof(full) / sizeof(full[0])); + } else if (count < 3) { + constexpr char empty[] = "empty"; + IpcMoudle::Get()->Send(empty, sizeof(empty) / sizeof(empty[0])); + } else { + constexpr char normal[] = "normal"; + IpcMoudle::Get()->Send(normal, sizeof(normal) / sizeof(normal[0])); } - human_.updated = false; - texture->Update(human_.width, human_.height, human_.comp, human_.data.data()); + + ++playedIndex_; + Image image; + { + ScopeLock lock(&human_cs_); + image = std::move(human_.front()); + human_.pop(); + } + + + texture->Update(image.width, image.height, image.comp, image.data.data()); } void ImageBuffer::PushFaceImage(std::vector data, uint32 width, uint32 height, uint32 comp) { diff --git a/src/ImageBuffer.h b/src/ImageBuffer.h index 7edbac6..0cbeeba 100644 --- a/src/ImageBuffer.h +++ b/src/ImageBuffer.h @@ -10,8 +10,6 @@ class ImageBuffer : public Singleton { public: enum class IBType { Human, - Face, - FaceMask, }; public: explicit ImageBuffer() noexcept = default; @@ -44,7 +42,8 @@ private: bool updated{false}; }; CriticalSection human_cs_; - Image human_; + std::queue human_; + uint64 playedIndex_{ 0 }; CriticalSection face_cs_; Image face_; diff --git a/src/Ipc/IpcMoudle.cpp b/src/Ipc/IpcMoudle.cpp index 0ca7bd8..4841830 100644 --- a/src/Ipc/IpcMoudle.cpp +++ b/src/Ipc/IpcMoudle.cpp @@ -8,6 +8,7 @@ #include "Core/Core.h" #include "Ipc/ipclib.h" #include "ImageBuffer.h" +#include "VHI/VHI.h" IpcMoudle* Singleton::instance_ = nullptr; @@ -19,32 +20,14 @@ void OnParseImageData(const char* data, size_t size) { // Extract identifier char identifier = data[0]; - - // Extract width - int width; - std::memcpy(&width, data + 1, sizeof(int)); - - // Extract height - int height; - std::memcpy(&height, data + 5, sizeof(int)); - - // Extract bit depth - int bit_depth; - std::memcpy(&bit_depth, data + 9, sizeof(int)); - - // Extract image bytes - const char* img_bytes = data + 13; - size_t img_size = size - 13; - std::vector img_data(img_size); - memcpy(img_data.data(), img_bytes, img_size); - + const char* buffer = data + 1; if (0x01 == identifier) { - ImageBuffer::Get()->PushImage(ImageBuffer::IBType::Human, std::move(img_data), width, height, bit_depth); + IpcMoudle::Get()->PushImage(buffer, size - 1); } else if (0x02 == identifier) { - ImageBuffer::Get()->PushImage(ImageBuffer::IBType::Face, std::move(img_data), width, height, bit_depth); - } else if (0x03 == identifier) { - ImageBuffer::Get()->PushImage(ImageBuffer::IBType::FaceMask, std::move(img_data), width, height, bit_depth); + IpcMoudle::Get()->PushVoice(buffer, size - 1); } + + INFOLOG("identifier {}", static_cast(identifier)); } bool IpcMoudle::Initialize() { @@ -63,16 +46,25 @@ bool IpcMoudle::Initialize() { ERRORLOG("ipc listen failed"); return false; } + + //auto callback = [](const char* data, unsigned int size) { + // //INFOLOG("ipc recive data:{}", size); + // OnParseImageData(data, size); + //}; + //zmqMoudle_ = std::make_unique(callback); + //zmqMoudle_->Start(); lastHeartbeatTime_ = std::chrono::steady_clock::now(); return true; } void IpcMoudle::Uninitialize() { + //zmqMoudle_->Stop(); uninitialize(); } bool IpcMoudle::Send(const char* data, unsigned int size) { return send(data, size); + return false; } void IpcMoudle::OnFrame() { @@ -80,11 +72,42 @@ void IpcMoudle::OnFrame() { auto duration = std::chrono::duration_cast(now - lastHeartbeatTime_); if (duration.count() >= 2) { - constexpr char heartbeat[] = "heartbeat"; - if (!send("heartbeat", sizeof(heartbeat) / sizeof(heartbeat[0]))) { - ERRORLOG("send heartbeat failed"); - reConnect(); - } + /* constexpr char heartbeat[] = "heartbeat"; + if (!send("heartbeat", sizeof(heartbeat) / sizeof(heartbeat[0]))) { + ERRORLOG("send heartbeat failed"); + reConnect(); + }*/ lastHeartbeatTime_ = now; } } + +void IpcMoudle::PushImage(const char* data, uint32 size) { + // Extract width + int width; + std::memcpy(&width, data, sizeof(int)); + + // Extract height + int height; + std::memcpy(&height, data + 4, sizeof(int)); + + // Extract bit depth + int bit_depth; + std::memcpy(&bit_depth, data + 8, sizeof(int)); + + // Extract image bytes + const char* img_bytes = data + 12; + size_t img_size = size - 12; + std::vector img_data(img_size); + memcpy(img_data.data(), img_bytes, img_size); + + ImageBuffer::Get()->PushImage(ImageBuffer::IBType::Human, std::move(img_data), width, height, bit_depth); +} + +void IpcMoudle::PushVoice(const char* data, uint32 size) { + IAudioRender* audioRender = VHI::Get()->GetAudioRender(); + if (nullptr == audioRender) { + return; + } + + audioRender->Write(data, size); +} diff --git a/src/Ipc/IpcMoudle.h b/src/Ipc/IpcMoudle.h index 2e3a61b..78569a7 100644 --- a/src/Ipc/IpcMoudle.h +++ b/src/Ipc/IpcMoudle.h @@ -5,6 +5,8 @@ #include "Core/Singleton.h" #include "Core/Constant.h" +#include "Ipc/ZmqMoudle.h" + class IpcMoudle : public Singleton { NON_COPYABLE(IpcMoudle) @@ -14,12 +16,16 @@ public: bool Initialize() override; void Uninitialize() override; - bool Send(const char* data, unsigned int size); + bool Send(const char* data, uint32 size); void OnFrame(); + void PushImage(const char* data, uint32 size); + void PushVoice(const char* data, uint32 size); + private: std::chrono::time_point lastHeartbeatTime_; + std::unique_ptr zmqMoudle_; }; diff --git a/src/Ipc/ZmqMoudle.cpp b/src/Ipc/ZmqMoudle.cpp new file mode 100644 index 0000000..15949cc --- /dev/null +++ b/src/Ipc/ZmqMoudle.cpp @@ -0,0 +1,60 @@ +#include "Ipc/ZmqMoudle.h" + +#include +#include + +#include + + ZmqMoudle::ZmqMoudle(ZmqMoudleCallback callback) + : callback_(callback){ + + } + + void ZmqMoudle::Start() { + if (work_) { + return; + } + + shouldExit_.store(false); + auto run = [this]() { + zmq::context_t context(1); + zmq::socket_t subscriber(context, ZMQ_SUB); + subscriber.connect("tcp://127.0.0.1:55661"); + subscriber.setsockopt(ZMQ_SUBSCRIBE, "", 0); + + bool isFirst = true; + while (!shouldExit_.load()) { + zmq::message_t message; + if (subscriber.recv(message, zmq::recv_flags::none)) { + if (isFirst) { + auto start = std::chrono::high_resolution_clock::now(); + + // 打印自 Epoch 以来的时间(以秒为单位) + auto duration = std::chrono::duration(start.time_since_epoch()); + int64_t time = duration.count(); + time = 0; + isFirst = true; + } + const char* data = static_cast(message.data()); + if (nullptr != callback_) { + callback_(data, message.size()); + } + } else { + ::_sleep(1); + } + } + }; + + work_.reset(new std::thread(run)); + } + + void ZmqMoudle::Stop() { + if (!work_) { + return; + } + + shouldExit_.store(true); + if (work_->joinable()) { + work_->join(); + } + } diff --git a/src/Ipc/ZmqMoudle.h b/src/Ipc/ZmqMoudle.h new file mode 100644 index 0000000..8c0db28 --- /dev/null +++ b/src/Ipc/ZmqMoudle.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include +#include + +using ZmqMoudleCallback = std::function; +class ZmqMoudle { +public: + ZmqMoudle(ZmqMoudleCallback callback); + + void Start(); + void Stop(); + +private: + ZmqMoudleCallback callback_; + std::unique_ptr work_; + void* context_{ nullptr }; + std::atomic shouldExit_; +}; diff --git a/src/Main.cpp b/src/Main.cpp index 2bdc0fb..ed1a1cd 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -10,6 +10,7 @@ #include "Core/Logger.h" #include "Ipc/IpcMoudle.h" +#include "VHI/VHI.h" #include "ImageBuffer.h" #include "shader_s.h" #include "Texture2D.h" @@ -17,8 +18,10 @@ static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow) { Logger::Init(); - IpcMoudle::Init(); ImageBuffer::Init(); + VHI::Init(); + IpcMoudle::Init(); + auto glfwErrorCallback = [](int error, const char* description) { ERRORLOG("code={}, description={}", error, description); }; @@ -172,14 +175,15 @@ static int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevI //glDrawArrays(GL_TRIANGLES, 0, 6); //glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - constexpr char quit[] = "quit"; - IpcMoudle::Get()->Send(quit, sizeof(quit)/ sizeof(quit[0])); + /*constexpr char quit[] = "quit"; + IpcMoudle::Get()->Send(quit, sizeof(quit)/ sizeof(quit[0]));*/ glfwDestroyWindow(window); glfwTerminate(); - ImageBuffer::Shotdown(); IpcMoudle::Shotdown(); + VHI::Shotdown(); + ImageBuffer::Shotdown(); Logger::Shotdown(); return 0; } diff --git a/src/VHI/AudioRenderStd.cpp b/src/VHI/AudioRenderStd.cpp new file mode 100644 index 0000000..0bfe104 --- /dev/null +++ b/src/VHI/AudioRenderStd.cpp @@ -0,0 +1,18 @@ +#include "AudioRenderStd.h" + +#include + +#include "Core/Core.h" +#include "VHI/Windows/WavAudioRender.h" + +IAudioRender* IAudioRender::Create() { + return new WavAudioRender(); +} + +AudioRenderStd::AudioRenderStd() noexcept { + +} + +void AudioRenderStd::WirteLog(int32 level, const std::string& log) { + INFOLOG(log); +} diff --git a/src/VHI/AudioRenderStd.h b/src/VHI/AudioRenderStd.h new file mode 100644 index 0000000..efab4b2 --- /dev/null +++ b/src/VHI/AudioRenderStd.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +#include "IAudioRender.h" + +class AudioRenderStd : public IAudioRender { +public: + enum LOG_LEVEL { + DEBUG, + LOG + }; +public: + explicit AudioRenderStd() noexcept; + ~AudioRenderStd() override = default; + uint64 GetClock() override { + return 0; + } + + void WirteLog(int32 level, const std::string& log); +}; + diff --git a/src/VHI/IAudioRender.h b/src/VHI/IAudioRender.h new file mode 100644 index 0000000..0b858b5 --- /dev/null +++ b/src/VHI/IAudioRender.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "Core/Core.h" + + +struct AudioFrame { + std::vector data_; +}; + + +class IAudioRender { +public: + using LogCallback = std::function; + static IAudioRender* Create(); + +public: + virtual ~IAudioRender() = default; + virtual uint64 GetClock() = 0; + virtual bool Write(const char* data, uint32 size) = 0; +}; diff --git a/src/VHI/VHI.cpp b/src/VHI/VHI.cpp new file mode 100644 index 0000000..c479a10 --- /dev/null +++ b/src/VHI/VHI.cpp @@ -0,0 +1,28 @@ +#include "VHI/VHI.h" + +#include +#include + +#include "Core/Core.h" + +#include "IAudioRender.h" + +VHI* Singleton::instance_ = nullptr; + +VHI::VHI() noexcept { + +} + +VHI::~VHI() { + +} + +bool VHI::Initialize() { + audioRender_.reset(IAudioRender::Create()); + return true; +} + +void VHI::Uninitialize() { + audioRender_.reset(); +} + diff --git a/src/VHI/VHI.h b/src/VHI/VHI.h new file mode 100644 index 0000000..f8e1e37 --- /dev/null +++ b/src/VHI/VHI.h @@ -0,0 +1,21 @@ +#pragma once + +#include "Core/Singleton.h" + +#include "VHI/IAudioRender.h" + +class VHI : public Singleton { +public: + explicit VHI() noexcept; + ~VHI() override; + + bool Initialize() override; + void Uninitialize() override; + + IAudioRender* GetAudioRender() const noexcept { + return audioRender_.get(); + } + +private: + std::unique_ptr audioRender_; +}; diff --git a/src/VHI/Windows/CoreAudioRender.cpp b/src/VHI/Windows/CoreAudioRender.cpp new file mode 100644 index 0000000..1c6ef2d --- /dev/null +++ b/src/VHI/Windows/CoreAudioRender.cpp @@ -0,0 +1 @@ +#include "CoreAudioRender.h" diff --git a/src/VHI/Windows/CoreAudioRender.h b/src/VHI/Windows/CoreAudioRender.h new file mode 100644 index 0000000..d6db50d --- /dev/null +++ b/src/VHI/Windows/CoreAudioRender.h @@ -0,0 +1,7 @@ +#pragma once + +#include "VHI/IAudioRender.h" + +class CoreAudioRender : public IAudioRender { +}; + diff --git a/src/VHI/Windows/WavAudioRender.cpp b/src/VHI/Windows/WavAudioRender.cpp new file mode 100644 index 0000000..40499f7 --- /dev/null +++ b/src/VHI/Windows/WavAudioRender.cpp @@ -0,0 +1,222 @@ +#include "VHI/Windows/WavAudioRender.h" + +#include +#include + + +static WAVEHDR* AllocateBlocks(uint32 size, int32 count) { + uint32 totalBufferSize = (size + sizeof(WAVEHDR)) * count; + + uint8* buffer{ nullptr }; + if ((buffer = reinterpret_cast(HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + totalBufferSize + ))) == NULL) { + ExitProcess(1); + } + + WAVEHDR* blocks = reinterpret_cast(buffer); + buffer += sizeof(WAVEHDR) * count; + for (int32 index = 0; index < count; ++index) { + blocks[index].dwBufferLength = size; + blocks[index].lpData = (LPSTR)buffer; + blocks[index].dwFlags = 0; + buffer += size; + } + return blocks; +} + +static void FreeBlocks(WAVEHDR* blockArray) { + HeapFree(GetProcessHeap(), 0, blockArray); +} + + +class WavAudioRenderImpl { +public: + using UtilComplateCallback = std::function; +public: + explicit WavAudioRenderImpl(UtilComplateCallback callback) noexcept; + ~WavAudioRenderImpl(); + + bool Write(const char* data, uint32 size); + static void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2); + void FreeBlock(); + +private: + static constexpr int BlockSize_{ 1280 }; + static constexpr int BlockCount_{ 10 }; + + uint32 freeBlockCounter_{ BlockCount_ }; + uint32 waveCurrentBlock_{ 0 }; + + WAVEHDR* waveBlocks_{ nullptr }; + HWAVEOUT hWavout_{ nullptr }; + bool initialized_{ false }; + UtilComplateCallback callback_; +}; + +WavAudioRenderImpl::WavAudioRenderImpl(UtilComplateCallback callback) noexcept + : callback_(callback){ + HWAVEOUT hWaveOut = nullptr; + + waveBlocks_ = AllocateBlocks(BlockSize_, BlockCount_); + + constexpr int32 rate = 16000; + constexpr int32 channel = 1; + constexpr int32 bitePerSample = 16; + + WAVEFORMATEX waveform; + waveform.wFormatTag = WAVE_FORMAT_PCM; + waveform.nChannels = channel; + waveform.nSamplesPerSec = rate; + waveform.nAvgBytesPerSec = rate * channel * 2; + waveform.nBlockAlign = channel * 2; + waveform.wBitsPerSample = bitePerSample; + waveform.cbSize = 0; + + + MMRESULT hr = waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveform, + reinterpret_cast(WavAudioRenderImpl::waveOutProc), + reinterpret_cast(this), CALLBACK_FUNCTION); + if (MMSYSERR_NOERROR != hr) { + return; + } + + hWavout_ = std::move(hWaveOut); + initialized_ = true; +} + +WavAudioRenderImpl::~WavAudioRenderImpl() { + initialized_ = false; + if (nullptr == hWavout_) { + return; + } + waveOutReset(hWavout_); + for (int i = 0; i < BlockCount_; i++) { + if (waveBlocks_[i].dwFlags & WHDR_PREPARED) { + waveOutUnprepareHeader(hWavout_, &waveBlocks_[i], sizeof(WAVEHDR)); + } + } + + do { + MMRESULT ret = waveOutClose(hWavout_); + if (MMSYSERR_NOERROR == ret) { + break; + } else if (WAVERR_STILLPLAYING == ret) { + ::Sleep(1); + } else if (MMSYSERR_NOMEM == ret) { + break; + } else { + break; + } + } while (true); + FreeBlocks(waveBlocks_); +} + +bool WavAudioRenderImpl::Write(const char* data, uint32 size) { + if (nullptr == hWavout_) { + return false; + } + + WAVEHDR* current; + int32 remain; + current = &waveBlocks_[waveCurrentBlock_]; + while (size > 0) { + if (current->dwFlags & WHDR_PREPARED) { + waveOutUnprepareHeader(hWavout_, current, sizeof(WAVEHDR)); + } + if (size < (int)(BlockSize_ - current->dwUser)) { + memcpy(current->lpData + current->dwUser, data, size); + current->dwUser += size; + break; + } + remain = BlockSize_ - static_cast(current->dwUser); + memcpy(current->lpData + current->dwUser, data, remain); + size -= remain; + data += remain; + current->dwBufferLength = BlockSize_; + waveOutPrepareHeader(hWavout_, current, sizeof(WAVEHDR)); + waveOutWrite(hWavout_, current, sizeof(WAVEHDR)); + --freeBlockCounter_; + + while (!freeBlockCounter_ && initialized_) { + Sleep(1); + } + if (!initialized_) { + break; + } + + ++waveCurrentBlock_; + waveCurrentBlock_ %= BlockCount_; + current = &waveBlocks_[waveCurrentBlock_]; + current->dwUser = 0; + } + return true; +} + +void CALLBACK WavAudioRenderImpl::waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance, + DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + WavAudioRenderImpl* self = reinterpret_cast(dwInstance); + + if (uMsg != WOM_DONE) + return; + + self->FreeBlock(); +} + +void WavAudioRenderImpl::FreeBlock() { + ++freeBlockCounter_; + if (nullptr != callback_) { + callback_(); + } +} + + + +WavAudioRender::WavAudioRender() noexcept { + auto utilComplatedCallback = [this]() { + ++playedIndex_; + }; + + auto run = [this, utilComplatedCallback]() { + WavAudioRenderImpl impl(utilComplatedCallback); + std::vector temp; + while (!showExit_.load()) { + { + std::unique_lock lock(mutex_); + cv_.wait(lock, [&]() {return !audioQueue_.empty() || showExit_.load(); }); + if (showExit_.load()) { + break; + } + temp = std::move(audioQueue_.front()); + audioQueue_.pop(); + } + impl.Write(temp.data(), temp.size()); + } + }; + + work_.reset(new std::thread(run)); +} + +WavAudioRender::~WavAudioRender() { + showExit_.store(true); + cv_.notify_one(); + if (work_->joinable()) { + work_->join(); + } +} + +bool WavAudioRender::Write(const char* data, uint32 size) { + WirteLog(DEBUG, "WavAudioRender::Write"); + + std::vector frame(size, 0); + memcpy(&frame[0], data, size); + + std::unique_lock lock(mutex_); + audioQueue_.emplace(std::move(frame)); + cv_.notify_one(); + return true; +} + diff --git a/src/VHI/Windows/WavAudioRender.h b/src/VHI/Windows/WavAudioRender.h new file mode 100644 index 0000000..dc80db8 --- /dev/null +++ b/src/VHI/Windows/WavAudioRender.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include +#include +#include + +#include "VHI/AudioRenderStd.h" + +class WavAudioRender : public AudioRenderStd { +public: + explicit WavAudioRender() noexcept; + ~WavAudioRender() override; + + bool Write(const char* data, uint32 size) override; + uint64 GetClock() override { + return playedIndex_; + } + +private: + std::atomic showExit_{ false }; + std::mutex mutex_; + std::condition_variable cv_; + std::queue> audioQueue_; + std::unique_ptr work_; + uint64 playedIndex_{ 0 }; +};