Compile zmq locally

This commit is contained in:
ariel- committed 2018-03-28 03:20:25 -03:00
1 parent e02dbdb176
commit 7fff6c424f
206 files changed
+40112 -116

No files matched your search

-1
View File
@@ -61,7 +61,6 @@ include(GroupSources)
include(AutoCollect)
find_package(PCHSupport)
find_package(ZMQ REQUIRED)
find_package(MySQL)
if(NOT WITHOUT_GIT)
-88
View File
@@ -1,88 +0,0 @@
#
# Find the ZMQ includes and library
#
# This module defines
# ZMQ_INCLUDE_DIR, where to find zmq.h
# ZMQ_LIBRARY, the library needed to use ZMQ
# ZMQ_FOUND, if false, you cannot build anything that requires ZMQ.
set(ZMQ_FOUND 0)
if (PLATFORM EQUAL 64)
set(ZMQ_REGISTRY_PATH
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ (x64);DisplayIcon]"
)
else()
set(ZMQ_REGISTRY_PATH
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ;DisplayIcon]"
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ;DisplayIcon]"
)
endif()
find_path(ZMQ_ROOT_DIR
NAMES
include/zmq.h
HINTS
${ZMQ_REGISTRY_PATH}
PATHS
/usr
/usr/local
)
find_path(ZMQ_INCLUDE_DIR zmq.h ${ZMQ_ROOT_DIR}/include)
if (MSVC)
# Read registry key holding version
if (PLATFORM EQUAL 64)
get_filename_component(ZMQ_NAME "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ (x64);DisplayVersion]" NAME)
else()
get_filename_component(ZMQ_NAME "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ;DisplayVersion]" NAME)
if (${ZMQ_NAME} MATCHES "registry") # if key was not found, the string "registry" is returned
get_filename_component(ZMQ_NAME "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\ZeroMQ;DisplayVersion]" NAME)
endif()
endif()
# Replace dots with underscores
string(REGEX REPLACE "\\." "_" ZMQ_NAME ${ZMQ_NAME})
# Get Visual studio version number
set(_VS_VERSIONS "140" "120")
if (${ZMQ_NAME} MATCHES "registry") # if key was not found, the string "registry" is returned
set(_ZMQ_VERSIONS "4_0_4" "4_0_3" "4_0_2" "4_0_1" "4_0_0" "3_2_5" "3_2_4" "3_2_3" "3_2_2" "3_2_1" "3_2_0" "3_1_0")
set(ZMQ_LIBRARY_NAME)
foreach(ver ${_ZMQ_VERSIONS})
foreach(vs ${_VS_VERSIONS})
list(APPEND ZMQ_LIBRARY_NAME "libzmq-v${vs}-mt-${ver}")
endforeach()
endforeach()
else()
# Format ZMQ library file name
foreach(vs ${_VS_VERSIONS})
set(ZMQ_LIBRARY_NAME "libzmq-v${vs}-mt-${ZMQ_NAME}")
endforeach()
endif()
endif()
find_library(ZMQ_LIBRARY
NAMES
zmq
${ZMQ_LIBRARY_NAME}
PATHS
/lib
/usr/lib
/usr/local/lib
"${ZMQ_ROOT_DIR}/lib"
)
if (ZMQ_INCLUDE_DIR AND ZMQ_LIBRARY AND NOT ZMQ_LIBRARY-NOTFOUND)
set(ZMQ_FOUND 1)
message(STATUS "Found ZMQ library: ${ZMQ_LIBRARY}")
message(STATUS "Found ZMQ headers: ${ZMQ_INCLUDE_DIR}")
else()
message(FATAL_ERROR "Could not find ZMQ libraries/headers! Please install ZMQ with libraries and headers, read README.md for more info")
endif()
# show the ZMQ_INCLUDE_DIR and ZMQ_LIBRARY variables only in the advanced view
mark_as_advanced(ZMQ_ROOT_DIR ZMQ_INCLUDE_DIR ZMQ_LIBRARY ZMQ_FOUND)
+1 -1
View File
@@ -39,7 +39,7 @@ if(SERVERS)
add_subdirectory(mysql)
add_subdirectory(readline)
add_subdirectory(gsoap)
add_subdirectory(zmq)
add_subdirectory(libzmq)
add_subdirectory(zmqpp)
add_subdirectory(efsw)
endif()
+4
View File
@@ -59,6 +59,10 @@ recastnavigation (Recast is state of the art navigation mesh construction toolse
StormLib (a pack of modules, written in C++, which are able to read and also to write files from/to the MPQ archives)
http://www.zezula.net/en/mpq/stormlib.html
Version: 8.04
libzmq (ZeroMQ core engine in C++, implements ZMTP/3.1)
https://github.com/zeromq/libzmq
Version: 4.2.3 stable
zmqpp (C++ binding for 0mq/zmq is a 'high-level' library that hides most of the c-style interface core 0mq provides.)
https://github.com/zeromq/zmqpp
+102
View File
@@ -0,0 +1,102 @@
# Use the bundled source on windows
set (libzmq_STAT_SRCS
src/address.cpp
src/client.cpp
src/clock.cpp
src/ctx.cpp
src/dealer.cpp
src/dgram.cpp
src/dist.cpp
src/err.cpp
src/fq.cpp
src/io_object.cpp
src/io_thread.cpp
src/ip.cpp
src/lb.cpp
src/mailbox.cpp
src/mailbox_safe.cpp
src/mechanism.cpp
src/mechanism_base.cpp
src/metadata.cpp
src/msg.cpp
src/mtrie.cpp
src/object.cpp
src/options.cpp
src/own.cpp
src/null_mechanism.cpp
src/pair.cpp
src/pipe.cpp
src/plain_client.cpp
src/plain_server.cpp
src/poller_base.cpp
src/proxy.cpp
src/pub.cpp
src/pull.cpp
src/push.cpp
src/random.cpp
src/raw_encoder.cpp
src/raw_decoder.cpp
src/reaper.cpp
src/rep.cpp
src/req.cpp
src/router.cpp
src/select.cpp
src/server.cpp
src/session_base.cpp
src/signaler.cpp
src/socket_base.cpp
src/socks.cpp
src/socks_connecter.cpp
src/stream.cpp
src/stream_engine.cpp
src/sub.cpp
src/tcp.cpp
src/tcp_address.cpp
src/tcp_connecter.cpp
src/tcp_listener.cpp
src/thread.cpp
src/trie.cpp
src/v1_decoder.cpp
src/v1_encoder.cpp
src/v2_decoder.cpp
src/v2_encoder.cpp
src/xpub.cpp
src/xsub.cpp
src/zmq.cpp
src/zmq_utils.cpp
src/decoder_allocators.cpp
src/socket_poller.cpp
src/timers.cpp
src/config.hpp
src/radio.cpp
src/dish.cpp
src/udp_engine.cpp
src/udp_address.cpp
src/scatter.cpp
src/gather.cpp
src/zap_client.cpp
)
add_definitions(-DZMQ_USE_SELECT)
add_definitions(-DZMQ_STATIC)
if (WIN32)
add_definitions(-DZMQ_HAVE_WINDOWS)
elseif (APPLE)
add_definitions(-DZMQ_HAVE_OSX)
elseif (UNIX)
add_definitions(-DZMQ_HAVE_LINUX)
endif()
add_library(libzmq STATIC ${libzmq_STAT_SRCS})
target_include_directories(libzmq
PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src)
set_target_properties(libzmq
PROPERTIES
FOLDER
"dep")
+708
View File
@@ -0,0 +1,708 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*************************************************************************
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 2
#define ZMQ_VERSION_PATCH 3
#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 <errno.h>
#endif
#include <stddef.h>
#include <stdio.h>
#if defined _WIN32
// Set target version to Windows Server 2008, Windows Vista or higher.
// Windows XP (0x0501) is supported but without client & server socket types.
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#ifdef __MINGW32__
// Require Windows XP or higher with MinGW for getaddrinfo().
#if(_WIN32_WINNT >= 0x0501)
#else
#error You need at least Windows XP target
#endif
#endif
#include <winsock2.h>
#endif
/* Handle DSO symbol visibility */
#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
/* Define integer types needed for event interface */
#define ZMQ_DEFINED_STDINT 1
#if defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_OPENVMS
# include <inttypes.h>
#elif defined _MSC_VER && _MSC_VER < 1600
# 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 <stdint.h>
#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 <poll.h>
#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
/* 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 (__GNUC__) || defined ( __INTEL_COMPILER) || \
(defined (__SUNPRO_C) && __SUNPRO_C >= 0x590) || \
(defined (__SUNPRO_CC) && __SUNPRO_CC >= 0x590)
unsigned char _ [64] __attribute__ ((aligned (sizeof (void *))));
#elif 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))
__declspec (align (4)) unsigned char _ [64];
#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
/* 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 15
/* 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
/******************************************************************************/
/* 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
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);
/******************************************************************************/
/* 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;
#if defined _WIN32
SOCKET fd;
#else
int fd;
#endif
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 tweetnacl/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);
/******************************************************************************/
/* 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);
/* Stops the stopwatch. Returns the number of microseconds elapsed since */
/* the stopwatch was started. */
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
/* DRAFT Socket options. */
#define ZMQ_GSSAPI_PRINCIPAL_NAMETYPE 90
#define ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE 91
#define ZMQ_BINDTODEVICE 92
#define ZMQ_ZAP_ENFORCE_DOMAIN 93
/* DRAFT 0MQ socket events and monitoring */
/* 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
/* DRAFT Context options */
#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
/* DRAFT Socket methods. */
ZMQ_EXPORT int zmq_join (void *s, const char *group);
ZMQ_EXPORT int zmq_leave (void *s, const char *group);
/* 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);
/* 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"
/******************************************************************************/
/* Poller polling on sockets,fd and thread-safe sockets */
/******************************************************************************/
#define ZMQ_HAVE_POLLER
typedef struct zmq_poller_event_t
{
void *socket;
#if defined _WIN32
SOCKET fd;
#else
int fd;
#endif
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_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);
#if defined _WIN32
ZMQ_EXPORT int zmq_poller_add_fd (void *poller, SOCKET fd, void *user_data, short events);
ZMQ_EXPORT int zmq_poller_modify_fd (void *poller, SOCKET fd, short events);
ZMQ_EXPORT int zmq_poller_remove_fd (void *poller, SOCKET fd);
#else
ZMQ_EXPORT int zmq_poller_add_fd (void *poller, int fd, void *user_data, short events);
ZMQ_EXPORT int zmq_poller_modify_fd (void *poller, int fd, short events);
ZMQ_EXPORT int zmq_poller_remove_fd (void *poller, int fd);
#endif
ZMQ_EXPORT int zmq_socket_get_peer_state (void *socket,
const void *routing_id,
size_t routing_id_size);
/******************************************************************************/
/* 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);
/******************************************************************************/
/* 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
#endif // ZMQ_BUILD_DRAFT_API
#undef ZMQ_EXPORT
#ifdef __cplusplus
}
#endif
#endif
+48
View File
@@ -0,0 +1,48 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* 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
+134
View File
@@ -0,0 +1,134 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "address.hpp"
#include "ctx.hpp"
#include "err.hpp"
#include "tcp_address.hpp"
#include "udp_address.hpp"
#include "ipc_address.hpp"
#include "tipc_address.hpp"
#if defined ZMQ_HAVE_VMCI
#include "vmci_address.hpp"
#endif
#include <string>
#include <sstream>
zmq::address_t::address_t (
const std::string &protocol_, const std::string &address_, ctx_t *parent_)
: protocol (protocol_),
address (address_),
parent (parent_)
{
memset (&resolved, 0, sizeof resolved);
}
zmq::address_t::~address_t ()
{
if (protocol == "tcp") {
if (resolved.tcp_addr) {
LIBZMQ_DELETE(resolved.tcp_addr);
}
}
if (protocol == "udp") {
if (resolved.udp_addr) {
LIBZMQ_DELETE(resolved.udp_addr);
}
}
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
else
if (protocol == "ipc") {
if (resolved.ipc_addr) {
LIBZMQ_DELETE(resolved.ipc_addr);
}
}
#endif
#if defined ZMQ_HAVE_TIPC
else
if (protocol == "tipc") {
if (resolved.tipc_addr) {
LIBZMQ_DELETE(resolved.tipc_addr);
}
}
#endif
#if defined ZMQ_HAVE_VMCI
else
if (protocol == "vmci") {
if (resolved.vmci_addr) {
LIBZMQ_DELETE(resolved.vmci_addr);
}
}
#endif
}
int zmq::address_t::to_string (std::string &addr_) const
{
if (protocol == "tcp") {
if (resolved.tcp_addr)
return resolved.tcp_addr->to_string (addr_);
}
if (protocol == "udp") {
if (resolved.udp_addr)
return resolved.udp_addr->to_string (addr_);
}
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
else
if (protocol == "ipc") {
if (resolved.ipc_addr)
return resolved.ipc_addr->to_string (addr_);
}
#endif
#if defined ZMQ_HAVE_TIPC
else
if (protocol == "tipc") {
if (resolved.tipc_addr)
return resolved.tipc_addr->to_string (addr_);
}
#endif
#if defined ZMQ_HAVE_VMCI
else
if (protocol == "vmci") {
if (resolved.vmci_addr)
return resolved.vmci_addr->to_string (addr_);
}
#endif
if (!protocol.empty () && !address.empty ()) {
std::stringstream s;
s << protocol << "://" << address;
addr_ = s.str ();
return 0;
}
addr_.clear ();
return -1;
}
+77
View File
@@ -0,0 +1,77 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ADDRESS_HPP_INCLUDED__
#define __ZMQ_ADDRESS_HPP_INCLUDED__
#include <string>
namespace zmq
{
class ctx_t;
class tcp_address_t;
class udp_address_t;
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
class ipc_address_t;
#endif
#if defined ZMQ_HAVE_LINUX
class tipc_address_t;
#endif
#if defined ZMQ_HAVE_VMCI
class vmci_address_t;
#endif
struct address_t {
address_t (const std::string &protocol_, const std::string &address_, ctx_t *parent_);
~address_t ();
const std::string protocol;
const std::string address;
ctx_t *parent;
// Protocol specific resolved address
union {
tcp_address_t *tcp_addr;
udp_address_t *udp_addr;
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
ipc_address_t *ipc_addr;
#endif
#if defined ZMQ_HAVE_LINUX
tipc_address_t *tipc_addr;
#endif
#if defined ZMQ_HAVE_VMCI
vmci_address_t *vmci_addr;
#endif
} resolved;
int to_string (std::string &addr_) const;
};
}
#endif
+167
View File
@@ -0,0 +1,167 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ARRAY_INCLUDED__
#define __ZMQ_ARRAY_INCLUDED__
#include <vector>
#include <algorithm>
namespace zmq
{
// Implementation of fast arrays with O(1) access, insertion and
// removal. The array stores pointers rather than objects.
// O(1) is achieved by making items inheriting from
// array_item_t<ID> class which internally stores the position
// in the array.
// The ID template argument is used to differentiate among arrays
// and thus let an object be stored in different arrays.
// Base class for objects stored in the array. If you want to store
// same object in multiple arrays, each of those arrays has to have
// different ID. The item itself has to be derived from instantiations of
// array_item_t template for all relevant IDs.
template <int ID = 0> class array_item_t
{
public:
inline array_item_t () :
array_index (-1)
{
}
// The destructor doesn't have to be virtual. It is made virtual
// just to keep ICC and code checking tools from complaining.
inline virtual ~array_item_t ()
{
}
inline void set_array_index (int index_)
{
array_index = index_;
}
inline int get_array_index ()
{
return array_index;
}
private:
int array_index;
array_item_t (const array_item_t&);
const array_item_t &operator = (const array_item_t&);
};
template <typename T, int ID = 0> class array_t
{
private:
typedef array_item_t <ID> item_t;
public:
typedef typename std::vector <T*>::size_type size_type;
inline array_t ()
{
}
inline ~array_t ()
{
}
inline size_type size ()
{
return items.size ();
}
inline bool empty ()
{
return items.empty ();
}
inline T *&operator [] (size_type index_)
{
return items [index_];
}
inline void push_back (T *item_)
{
if (item_)
((item_t*) item_)->set_array_index ((int) items.size ());
items.push_back (item_);
}
inline void erase (T *item_) {
erase (((item_t*) item_)->get_array_index ());
}
inline void erase (size_type index_) {
if (items.back ())
((item_t*) items.back ())->set_array_index ((int) index_);
items [index_] = items.back ();
items.pop_back ();
}
inline void swap (size_type index1_, size_type index2_)
{
if (items [index1_])
((item_t*) items [index1_])->set_array_index ((int) index2_);
if (items [index2_])
((item_t*) items [index2_])->set_array_index ((int) index1_);
std::swap (items [index1_], items [index2_]);
}
inline void clear ()
{
items.clear ();
}
inline size_type index (T *item_)
{
return (size_type) ((item_t*) item_)->get_array_index ();
}
private:
typedef std::vector <T*> items_t;
items_t items;
array_t (const array_t&);
const array_t &operator = (const array_t&);
};
}
#endif
+249
View File
@@ -0,0 +1,249 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__
#define __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__
#include "stdint.hpp"
#if defined ZMQ_FORCE_MUTEXES
#define ZMQ_ATOMIC_COUNTER_MUTEX
#elif defined ZMQ_HAVE_ATOMIC_INTRINSICS
#define ZMQ_ATOMIC_COUNTER_INTRINSIC
#elif (defined __cplusplus && __cplusplus >= 201103L)
#define ZMQ_ATOMIC_COUNTER_CXX11
#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
#define ZMQ_ATOMIC_COUNTER_X86
#elif defined __ARM_ARCH_7A__ && defined __GNUC__
#define ZMQ_ATOMIC_COUNTER_ARM
#elif defined ZMQ_HAVE_WINDOWS
#define ZMQ_ATOMIC_COUNTER_WINDOWS
#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD || defined ZMQ_HAVE_GNU)
#define ZMQ_ATOMIC_COUNTER_ATOMIC_H
#elif defined __tile__
#define ZMQ_ATOMIC_COUNTER_TILE
#else
#define ZMQ_ATOMIC_COUNTER_MUTEX
#endif
#if defined ZMQ_ATOMIC_COUNTER_MUTEX
#include "mutex.hpp"
#elif defined ZMQ_ATOMIC_COUNTER_CXX11
#include <atomic>
#elif defined ZMQ_ATOMIC_COUNTER_WINDOWS
#include "windows.hpp"
#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
#include <atomic.h>
#elif defined ZMQ_ATOMIC_COUNTER_TILE
#include <arch/atomic.h>
#endif
namespace zmq
{
// This class represents an integer that can be incremented/decremented
// in atomic fashion.
//
// In zmq::shared_message_memory_allocator a buffer with an atomic_counter_t
// at the start is allocated. If the class does not align to pointer size,
// access to pointers in structures in the buffer will cause SIGBUS on
// architectures that do not allow mis-aligned pointers (eg: SPARC).
// Force the compiler to align to pointer size, which will cause the object
// to grow from 4 bytes to 8 bytes on 64 bit architectures (when not using
// mutexes).
#if defined (_MSC_VER) && (defined (_M_X64) || defined (_M_ARM64))
class __declspec (align (8)) atomic_counter_t
#elif defined (_MSC_VER) && (defined (_M_IX86) || defined (_M_ARM_ARMV7VE))
class __declspec (align (4)) atomic_counter_t
#else
class atomic_counter_t
#endif
{
public:
typedef uint32_t integer_t;
inline atomic_counter_t (integer_t value_ = 0) :
value (value_)
{
}
inline ~atomic_counter_t ()
{
}
// Set counter value (not thread-safe).
inline void set (integer_t value_)
{
value = value_;
}
// Atomic addition. Returns the old value.
inline integer_t add (integer_t increment_)
{
integer_t old_value;
#if defined ZMQ_ATOMIC_COUNTER_WINDOWS
old_value = InterlockedExchangeAdd ((LONG*) &value, increment_);
#elif defined ZMQ_ATOMIC_COUNTER_INTRINSIC
old_value = __atomic_fetch_add(&value, increment_, __ATOMIC_ACQ_REL);
#elif defined ZMQ_ATOMIC_COUNTER_CXX11
old_value = value.fetch_add(increment_, std::memory_order_acq_rel);
#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
integer_t new_value = atomic_add_32_nv (&value, increment_);
old_value = new_value - increment_;
#elif defined ZMQ_ATOMIC_COUNTER_TILE
old_value = arch_atomic_add (&value, increment_);
#elif defined ZMQ_ATOMIC_COUNTER_X86
__asm__ volatile (
"lock; xadd %0, %1 \n\t"
: "=r" (old_value), "=m" (value)
: "0" (increment_), "m" (value)
: "cc", "memory");
#elif defined ZMQ_ATOMIC_COUNTER_ARM
integer_t flag, tmp;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %0, [%5]\n\t"
" add %2, %0, %4\n\t"
" strex %1, %2, [%5]\n\t"
" teq %1, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(old_value), "=&r"(flag), "=&r"(tmp), "+Qo"(value)
: "Ir"(increment_), "r"(&value)
: "cc");
#elif defined ZMQ_ATOMIC_COUNTER_MUTEX
sync.lock ();
old_value = value;
value += increment_;
sync.unlock ();
#else
#error atomic_counter is not implemented for this platform
#endif
return old_value;
}
// Atomic subtraction. Returns false if the counter drops to zero.
inline bool sub (integer_t decrement)
{
#if defined ZMQ_ATOMIC_COUNTER_WINDOWS
LONG delta = - ((LONG) decrement);
integer_t old = InterlockedExchangeAdd ((LONG*) &value, delta);
return old - decrement != 0;
#elif defined ZMQ_ATOMIC_COUNTER_INTRINSIC
integer_t nv = __atomic_sub_fetch(&value, decrement, __ATOMIC_ACQ_REL);
return nv != 0;
#elif defined ZMQ_ATOMIC_COUNTER_CXX11
integer_t old = value.fetch_sub(decrement, std::memory_order_acq_rel);
return old - decrement != 0;
#elif defined ZMQ_ATOMIC_COUNTER_ATOMIC_H
int32_t delta = - ((int32_t) decrement);
integer_t nv = atomic_add_32_nv (&value, delta);
return nv != 0;
#elif defined ZMQ_ATOMIC_COUNTER_TILE
int32_t delta = - ((int32_t) decrement);
integer_t nv = arch_atomic_add (&value, delta);
return nv != 0;
#elif defined ZMQ_ATOMIC_COUNTER_X86
integer_t oldval = -decrement;
volatile integer_t *val = &value;
__asm__ volatile ("lock; xaddl %0,%1"
: "=r" (oldval), "=m" (*val)
: "0" (oldval), "m" (*val)
: "cc", "memory");
return oldval != decrement;
#elif defined ZMQ_ATOMIC_COUNTER_ARM
integer_t old_value, flag, tmp;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %0, [%5]\n\t"
" sub %2, %0, %4\n\t"
" strex %1, %2, [%5]\n\t"
" teq %1, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(old_value), "=&r"(flag), "=&r"(tmp), "+Qo"(value)
: "Ir"(decrement), "r"(&value)
: "cc");
return old_value - decrement != 0;
#elif defined ZMQ_ATOMIC_COUNTER_MUTEX
sync.lock ();
value -= decrement;
bool result = value ? true : false;
sync.unlock ();
return result;
#else
#error atomic_counter is not implemented for this platform
#endif
}
inline integer_t get () const
{
return value;
}
private:
#if defined ZMQ_ATOMIC_COUNTER_CXX11
std::atomic<integer_t> value;
#else
volatile integer_t value;
#endif
#if defined ZMQ_ATOMIC_COUNTER_MUTEX
mutex_t sync;
#endif
#if ! defined ZMQ_ATOMIC_COUNTER_CXX11
atomic_counter_t (const atomic_counter_t&);
const atomic_counter_t& operator = (const atomic_counter_t&);
#endif
#if defined (__GNUC__) || defined ( __INTEL_COMPILER) || \
(defined (__SUNPRO_C) && __SUNPRO_C >= 0x590) || \
(defined (__SUNPRO_CC) && __SUNPRO_CC >= 0x590)
} __attribute__ ((aligned (sizeof (void *))));
#else
};
#endif
}
// Remove macros local to this file.
#undef ZMQ_ATOMIC_COUNTER_MUTEX
#undef ZMQ_ATOMIC_COUNTER_INTRINSIC
#undef ZMQ_ATOMIC_COUNTER_CXX11
#undef ZMQ_ATOMIC_COUNTER_X86
#undef ZMQ_ATOMIC_COUNTER_ARM
#undef ZMQ_ATOMIC_COUNTER_WINDOWS
#undef ZMQ_ATOMIC_COUNTER_ATOMIC_H
#undef ZMQ_ATOMIC_COUNTER_TILE
#endif
+227
View File
@@ -0,0 +1,227 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
#define __ZMQ_ATOMIC_PTR_HPP_INCLUDED__
#if defined ZMQ_FORCE_MUTEXES
#define ZMQ_ATOMIC_PTR_MUTEX
#elif defined ZMQ_HAVE_ATOMIC_INTRINSICS
#define ZMQ_ATOMIC_PTR_INTRINSIC
#elif (defined __cplusplus && __cplusplus >= 201103L)
#define ZMQ_ATOMIC_PTR_CXX11
#elif (defined __i386__ || defined __x86_64__) && defined __GNUC__
#define ZMQ_ATOMIC_PTR_X86
#elif defined __ARM_ARCH_7A__ && defined __GNUC__
#define ZMQ_ATOMIC_PTR_ARM
#elif defined __tile__
#define ZMQ_ATOMIC_PTR_TILE
#elif defined ZMQ_HAVE_WINDOWS
#define ZMQ_ATOMIC_PTR_WINDOWS
#elif (defined ZMQ_HAVE_SOLARIS || defined ZMQ_HAVE_NETBSD || defined ZMQ_HAVE_GNU)
#define ZMQ_ATOMIC_PTR_ATOMIC_H
#else
#define ZMQ_ATOMIC_PTR_MUTEX
#endif
#if defined ZMQ_ATOMIC_PTR_MUTEX
#include "mutex.hpp"
#elif defined ZMQ_ATOMIC_PTR_CXX11
#include <atomic>
#elif defined ZMQ_ATOMIC_PTR_WINDOWS
#include "windows.hpp"
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
#include <atomic.h>
#elif defined ZMQ_ATOMIC_PTR_TILE
#include <arch/atomic.h>
#endif
namespace zmq
{
// This class encapsulates several atomic operations on pointers.
template <typename T> class atomic_ptr_t
{
public:
// Initialise atomic pointer
inline atomic_ptr_t ()
{
ptr = NULL;
}
// Destroy atomic pointer
inline ~atomic_ptr_t ()
{
}
// Set value of atomic pointer in a non-threadsafe way
// Use this function only when you are sure that at most one
// thread is accessing the pointer at the moment.
inline void set (T *ptr_)
{
this->ptr = ptr_;
}
// Perform atomic 'exchange pointers' operation. Pointer is set
// to the 'val' value. Old value is returned.
inline T *xchg (T *val_)
{
#if defined ZMQ_ATOMIC_PTR_WINDOWS
return (T*) InterlockedExchangePointer ((PVOID*) &ptr, val_);
#elif defined ZMQ_ATOMIC_PTR_INTRINSIC
return (T*) __atomic_exchange_n (&ptr, val_, __ATOMIC_ACQ_REL);
#elif defined ZMQ_ATOMIC_PTR_CXX11
return ptr.exchange(val_, std::memory_order_acq_rel);
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
return (T*) atomic_swap_ptr (&ptr, val_);
#elif defined ZMQ_ATOMIC_PTR_TILE
return (T*) arch_atomic_exchange (&ptr, val_);
#elif defined ZMQ_ATOMIC_PTR_X86
T *old;
__asm__ volatile (
"lock; xchg %0, %2"
: "=r" (old), "=m" (ptr)
: "m" (ptr), "0" (val_));
return old;
#elif defined ZMQ_ATOMIC_PTR_ARM
T* old;
unsigned int flag;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %1, [%3]\n\t"
" strex %0, %4, [%3]\n\t"
" teq %0, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(flag), "=&r"(old), "+Qo"(ptr)
: "r"(&ptr), "r"(val_)
: "cc");
return old;
#elif defined ZMQ_ATOMIC_PTR_MUTEX
sync.lock ();
T *old = (T*) ptr;
ptr = val_;
sync.unlock ();
return old;
#else
#error atomic_ptr is not implemented for this platform
#endif
}
// Perform atomic 'compare and swap' operation on the pointer.
// The pointer is compared to 'cmp' argument and if they are
// equal, its value is set to 'val'. Old value of the pointer
// is returned.
inline T *cas (T *cmp_, T *val_)
{
#if defined ZMQ_ATOMIC_PTR_WINDOWS
return (T*) InterlockedCompareExchangePointer (
(volatile PVOID*) &ptr, val_, cmp_);
#elif defined ZMQ_ATOMIC_PTR_INTRINSIC
T *old = cmp_;
__atomic_compare_exchange_n (&ptr, (volatile T**) &old, val_, false,
__ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
return old;
#elif defined ZMQ_ATOMIC_PTR_CXX11
ptr.compare_exchange_strong(cmp_, val_, std::memory_order_acq_rel);
return cmp_;
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
return (T*) atomic_cas_ptr (&ptr, cmp_, val_);
#elif defined ZMQ_ATOMIC_PTR_TILE
return (T*) arch_atomic_val_compare_and_exchange (&ptr, cmp_, val_);
#elif defined ZMQ_ATOMIC_PTR_X86
T *old;
__asm__ volatile (
"lock; cmpxchg %2, %3"
: "=a" (old), "=m" (ptr)
: "r" (val_), "m" (ptr), "0" (cmp_)
: "cc");
return old;
#elif defined ZMQ_ATOMIC_PTR_ARM
T *old;
unsigned int flag;
__asm__ volatile (
" dmb sy\n\t"
"1: ldrex %1, [%3]\n\t"
" mov %0, #0\n\t"
" teq %1, %4\n\t"
" it eq\n\t"
" strexeq %0, %5, [%3]\n\t"
" teq %0, #0\n\t"
" bne 1b\n\t"
" dmb sy\n\t"
: "=&r"(flag), "=&r"(old), "+Qo"(ptr)
: "r"(&ptr), "r"(cmp_), "r"(val_)
: "cc");
return old;
#elif defined ZMQ_ATOMIC_PTR_MUTEX
sync.lock ();
T *old = (T*) ptr;
if (ptr == cmp_)
ptr = val_;
sync.unlock ();
return old;
#else
#error atomic_ptr is not implemented for this platform
#endif
}
private:
#if defined ZMQ_ATOMIC_PTR_CXX11
std::atomic<T*> ptr;
#else
volatile T *ptr;
#endif
#if defined ZMQ_ATOMIC_PTR_MUTEX
mutex_t sync;
#endif
#if ! defined ZMQ_ATOMIC_PTR_CXX11
atomic_ptr_t (const atomic_ptr_t&);
const atomic_ptr_t &operator = (const atomic_ptr_t&);
#endif
};
}
// Remove macros local to this file.
#undef ZMQ_ATOMIC_PTR_MUTEX
#undef ZMQ_ATOMIC_PTR_INTRINSIC
#undef ZMQ_ATOMIC_PTR_CXX11
#undef ZMQ_ATOMIC_PTR_X86
#undef ZMQ_ATOMIC_PTR_ARM
#undef ZMQ_ATOMIC_PTR_TILE
#undef ZMQ_ATOMIC_PTR_WINDOWS
#undef ZMQ_ATOMIC_PTR_ATOMIC_H
#endif
+186
View File
@@ -0,0 +1,186 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_BLOB_HPP_INCLUDED__
#define __ZMQ_BLOB_HPP_INCLUDED__
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#if __cplusplus >= 201103L || defined(_MSC_VER) && _MSC_VER >= 1700
#define ZMQ_HAS_MOVE_SEMANTICS
#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) emplace (k,v)
#define ZMQ_PUSH_OR_EMPLACE_BACK emplace_back
#define ZMQ_MOVE(x) std::move (x)
#else
#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) insert (std::make_pair (k, v))
#define ZMQ_PUSH_OR_EMPLACE_BACK push_back
#define ZMQ_MOVE(x) (x)
#endif
namespace zmq
{
struct reference_tag_t {};
// Object to hold dynamically allocated opaque binary data.
// On modern compilers, it will be movable but not copyable. Copies
// must be explicitly created by set_deep_copy.
// On older compilers, it is copyable for syntactical reasons.
struct blob_t
{
// Creates an empty blob_t.
blob_t () : data_ (0), size_ (0), owned_ (true) {}
// Creates a blob_t of a given size, with uninitialized content.
blob_t (const size_t size)
: data_ ((unsigned char*)malloc (size))
, size_ (size)
, owned_ (true)
{
}
// Creates a blob_t of a given size, an initializes content by copying
// from another buffer.
blob_t(const unsigned char * const data, const size_t size)
: data_ ((unsigned char*)malloc (size))
, size_ (size)
, owned_ (true)
{
memcpy(data_, data, size_);
}
// Creates a blob_t for temporary use that only references a
// pre-allocated block of data.
// Use with caution and ensure that the blob_t will not outlive
// the referenced data.
blob_t (unsigned char * const data, const size_t size, reference_tag_t)
: data_ (data)
, size_ (size)
, owned_ (false)
{
}
// Returns the size of the blob_t.
size_t size () const { return size_; }
// Returns a pointer to the data of the blob_t.
const unsigned char *data() const {
return data_;
}
// Returns a pointer to the data of the blob_t.
unsigned char *data() {
return data_;
}
// Defines an order relationship on blob_t.
bool operator< (blob_t const &other) const {
int cmpres = memcmp (data_, other.data_, std::min (size_, other.size_));
return cmpres < 0 || (cmpres == 0 && size_ < other.size_);
}
// Sets a blob_t to a deep copy of another blob_t.
void set_deep_copy (blob_t const &other)
{
clear ();
data_ = (unsigned char*)malloc (other.size_);
size_ = other.size_;
owned_ = true;
memcpy (data_, other.data_, size_);
}
// Sets a blob_t to a copy of a given buffer.
void set (const unsigned char * const data, const size_t size)
{
clear ();
data_ = (unsigned char*)malloc (size);
size_ = size;
owned_ = true;
memcpy (data_, data, size_);
}
// Empties a blob_t.
void clear () {
if (owned_) { free (data_); }
data_ = 0; size_ = 0;
}
~blob_t () {
if (owned_) { free (data_); }
}
#ifdef ZMQ_HAS_MOVE_SEMANTICS
blob_t (const blob_t &) = delete;
blob_t &operator= (const blob_t &) = delete;
blob_t (blob_t&& other)
: data_ (other.data_)
, size_ (other.size_)
, owned_ (other.owned_)
{
other.owned_ = false;
}
blob_t &operator= (blob_t&& other) {
if (this != &other)
{
clear ();
data_ = other.data_;
size_ = other.size_;
owned_ = other.owned_;
other.owned_ = false;
}
return *this;
}
#else
blob_t (const blob_t &other)
: owned_(false)
{
set_deep_copy (other);
}
blob_t &operator= (const blob_t &other) {
if (this != &other)
{
clear ();
set_deep_copy (other);
}
return *this;
}
#endif
private:
unsigned char *data_;
size_t size_;
bool owned_;
};
}
#endif
+116
View File
@@ -0,0 +1,116 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "client.hpp"
#include "err.hpp"
#include "msg.hpp"
zmq::client_t::client_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_, true)
{
options.type = ZMQ_CLIENT;
}
zmq::client_t::~client_t ()
{
}
void zmq::client_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_);
fq.attach (pipe_);
lb.attach (pipe_);
}
int zmq::client_t::xsend (msg_t *msg_)
{
// CLIENT sockets do not allow multipart data (ZMQ_SNDMORE)
if (msg_->flags () & msg_t::more) {
errno = EINVAL;
return -1;
}
return lb.sendpipe (msg_, NULL);
}
int zmq::client_t::xrecv (msg_t *msg_)
{
int rc = fq.recvpipe (msg_, NULL);
// Drop any messages with more flag
while (rc == 0 && msg_->flags () & msg_t::more) {
// drop all frames of the current multi-frame message
rc = fq.recvpipe (msg_, NULL);
while (rc == 0 && msg_->flags () & msg_t::more)
rc = fq.recvpipe (msg_, NULL);
// get the new message
if (rc == 0)
rc = fq.recvpipe (msg_, NULL);
}
return rc;
}
bool zmq::client_t::xhas_in ()
{
return fq.has_in ();
}
bool zmq::client_t::xhas_out ()
{
return lb.has_out ();
}
const zmq::blob_t &zmq::client_t::get_credential () const
{
return fq.get_credential ();
}
void zmq::client_t::xread_activated (pipe_t *pipe_)
{
fq.activated (pipe_);
}
void zmq::client_t::xwrite_activated (pipe_t *pipe_)
{
lb.activated (pipe_);
}
void zmq::client_t::xpipe_terminated (pipe_t *pipe_)
{
fq.pipe_terminated (pipe_);
lb.pipe_terminated (pipe_);
}
+81
View File
@@ -0,0 +1,81 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CLIENT_HPP_INCLUDED__
#define __ZMQ_CLIENT_HPP_INCLUDED__
#include "socket_base.hpp"
#include "session_base.hpp"
#include "fq.hpp"
#include "lb.hpp"
namespace zmq
{
class ctx_t;
class msg_t;
class pipe_t;
class io_thread_t;
class socket_base_t;
class client_t :
public socket_base_t
{
public:
client_t (zmq::ctx_t *parent_, uint32_t tid_, int sid);
~client_t ();
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
private:
// Messages are fair-queued from inbound pipes. And load-balanced to
// the outbound pipes.
fq_t fq;
lb_t lb;
client_t (const client_t &);
const client_t &operator = (const client_t&);
};
}
#endif
+253
View File
@@ -0,0 +1,253 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "clock.hpp"
#include "likely.hpp"
#include "config.hpp"
#include "err.hpp"
#include "mutex.hpp"
#include <stddef.h>
#if defined _MSC_VER
#if defined _WIN32_WCE
#include <cmnintrin.h>
#else
#include <intrin.h>
#endif
#endif
#if !defined ZMQ_HAVE_WINDOWS
#include <sys/time.h>
#endif
#if defined HAVE_CLOCK_GETTIME || defined HAVE_GETHRTIME
#include <time.h>
#endif
#if defined ZMQ_HAVE_OSX
#include <mach/clock.h>
#include <mach/mach.h>
#include <time.h>
#include <sys/time.h>
int alt_clock_gettime (int clock_id, timespec *ts)
{
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service (mach_host_self (), clock_id, &cclock);
clock_get_time (cclock, &mts);
mach_port_deallocate (mach_task_self (), cclock);
ts->tv_sec = mts.tv_sec;
ts->tv_nsec = mts.tv_nsec;
return 0;
}
#endif
#ifdef ZMQ_HAVE_WINDOWS
typedef ULONGLONG (*f_compatible_get_tick_count64)();
static zmq::mutex_t compatible_get_tick_count64_mutex;
ULONGLONG compatible_get_tick_count64()
{
#ifdef ZMQ_HAVE_WINDOWS_UWP
const ULONGLONG result = ::GetTickCount64();
return result;
#else
zmq::scoped_lock_t locker(compatible_get_tick_count64_mutex);
static DWORD s_wrap = 0;
static DWORD s_last_tick = 0;
const DWORD current_tick = ::GetTickCount();
if (current_tick < s_last_tick)
++s_wrap;
s_last_tick = current_tick;
const ULONGLONG result = (static_cast<ULONGLONG>(s_wrap) << 32) + static_cast<ULONGLONG>(current_tick);
return result;
#endif
}
f_compatible_get_tick_count64 init_compatible_get_tick_count64()
{
f_compatible_get_tick_count64 func = NULL;
#if !defined ZMQ_HAVE_WINDOWS_UWP
HMODULE module = ::LoadLibraryA("Kernel32.dll");
if (module != NULL)
func = reinterpret_cast<f_compatible_get_tick_count64>(::GetProcAddress(module, "GetTickCount64"));
#endif
if (func == NULL)
func = compatible_get_tick_count64;
#if !defined ZMQ_HAVE_WINDOWS_UWP
::FreeLibrary(module);
#endif
return func;
}
static f_compatible_get_tick_count64 my_get_tick_count64 = init_compatible_get_tick_count64();
#endif
zmq::clock_t::clock_t () :
last_tsc (rdtsc ()),
#ifdef ZMQ_HAVE_WINDOWS
last_time (static_cast<uint64_t>((*my_get_tick_count64)()))
#else
last_time (now_us () / 1000)
#endif
{
}
zmq::clock_t::~clock_t ()
{
}
uint64_t zmq::clock_t::now_us ()
{
#if defined ZMQ_HAVE_WINDOWS
// Get the high resolution counter's accuracy.
LARGE_INTEGER ticksPerSecond;
QueryPerformanceFrequency (&ticksPerSecond);
// What time is it?
LARGE_INTEGER tick;
QueryPerformanceCounter (&tick);
// Convert the tick number into the number of seconds
// since the system was started.
double ticks_div = ticksPerSecond.QuadPart / 1000000.0;
return (uint64_t) (tick.QuadPart / ticks_div);
#elif defined HAVE_CLOCK_GETTIME && defined CLOCK_MONOTONIC
// Use POSIX clock_gettime function to get precise monotonic time.
struct timespec tv;
#if defined ZMQ_HAVE_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12
int rc = alt_clock_gettime (SYSTEM_CLOCK, &tv);
#else
int rc = clock_gettime (CLOCK_MONOTONIC, &tv);
#endif
// Fix case where system has clock_gettime but CLOCK_MONOTONIC is not supported.
// This should be a configuration check, but I looked into it and writing an
// AC_FUNC_CLOCK_MONOTONIC seems beyond my powers.
if( rc != 0) {
// Use POSIX gettimeofday function to get precise time.
struct timeval tv;
int rc = gettimeofday (&tv, NULL);
errno_assert (rc == 0);
return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec);
}
return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_nsec / 1000);
#elif defined HAVE_GETHRTIME
return (gethrtime () / 1000);
#else
// Use POSIX gettimeofday function to get precise time.
struct timeval tv;
int rc = gettimeofday (&tv, NULL);
errno_assert (rc == 0);
return (tv.tv_sec * (uint64_t) 1000000 + tv.tv_usec);
#endif
}
uint64_t zmq::clock_t::now_ms ()
{
uint64_t tsc = rdtsc ();
// If TSC is not supported, get precise time and chop off the microseconds.
if (!tsc)
{
#ifdef ZMQ_HAVE_WINDOWS
// Under Windows, now_us is not so reliable since QueryPerformanceCounter
// does not guarantee that it will use a hardware that offers a monotonic timer.
// So, lets use GetTickCount when GetTickCount64 is not available with an workaround
// to its 32 bit limitation.
return static_cast<uint64_t>((*my_get_tick_count64)());
#else
return now_us () / 1000;
#endif
}
// If TSC haven't jumped back (in case of migration to a different
// CPU core) and if not too much time elapsed since last measurement,
// we can return cached time value.
if (likely (tsc - last_tsc <= (clock_precision / 2) && tsc >= last_tsc))
return last_time;
last_tsc = tsc;
#ifdef ZMQ_HAVE_WINDOWS
last_time = static_cast<uint64_t>((*my_get_tick_count64)());
#else
last_time = now_us () / 1000;
#endif
return last_time;
}
uint64_t zmq::clock_t::rdtsc ()
{
#if (defined _MSC_VER && (defined _M_IX86 || defined _M_X64))
return __rdtsc ();
#elif (defined __GNUC__ && (defined __i386__ || defined __x86_64__))
uint32_t low, high;
__asm__ volatile ("rdtsc" : "=a" (low), "=d" (high));
return (uint64_t) high << 32 | low;
#elif (defined __SUNPRO_CC && (__SUNPRO_CC >= 0x5100) && (defined __i386 || \
defined __amd64 || defined __x86_64))
union {
uint64_t u64val;
uint32_t u32val [2];
} tsc;
asm("rdtsc" : "=a" (tsc.u32val [0]), "=d" (tsc.u32val [1]));
return tsc.u64val;
#elif defined(__s390__)
uint64_t tsc;
asm("\tstck\t%0\n" : "=Q" (tsc) : : "cc");
return(tsc);
#else
struct timespec ts;
#if defined ZMQ_HAVE_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12
alt_clock_gettime (SYSTEM_CLOCK, &ts);
#else
clock_gettime (CLOCK_MONOTONIC, &ts);
#endif
return (uint64_t)(ts.tv_sec) * 1000000000 + ts.tv_nsec;
#endif
}
+83
View File
@@ -0,0 +1,83 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CLOCK_HPP_INCLUDED__
#define __ZMQ_CLOCK_HPP_INCLUDED__
#include "stdint.hpp"
#if defined ZMQ_HAVE_OSX
#include <mach/clock.h>
#include <mach/mach.h>
#include <time.h>
#include <sys/time.h>
int alt_clock_gettime (int clock_id, timespec *ts);
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef HAVE_CLOCK_GETTIME
#define HAVE_CLOCK_GETTIME
#endif
#endif
namespace zmq
{
class clock_t
{
public:
clock_t ();
~clock_t ();
// CPU's timestamp counter. Returns 0 if it's not available.
static uint64_t rdtsc ();
// High precision timestamp.
static uint64_t now_us ();
// Low precision timestamp. In tight loops generating it can be
// 10 to 100 times faster than the high precision timestamp.
uint64_t now_ms ();
private:
// TSC timestamp of when last time measurement was made.
uint64_t last_tsc;
// Physical time corresponding to the TSC above (in milliseconds).
uint64_t last_time;
clock_t (const clock_t&);
const clock_t &operator = (const clock_t&);
};
}
#endif
+188
View File
@@ -0,0 +1,188 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_COMMAND_HPP_INCLUDED__
#define __ZMQ_COMMAND_HPP_INCLUDED__
#include <string>
#include "stdint.hpp"
namespace zmq
{
class object_t;
class own_t;
struct i_engine;
class pipe_t;
class socket_base_t;
// This structure defines the commands that can be sent between threads.
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4324) // C4324: alignment padding warnings
__declspec(align(64))
#endif
struct command_t
{
// Object to process the command.
zmq::object_t *destination;
enum type_t
{
stop,
plug,
own,
attach,
bind,
activate_read,
activate_write,
hiccup,
pipe_term,
pipe_term_ack,
pipe_hwm,
term_req,
term,
term_ack,
term_endpoint,
reap,
reaped,
inproc_connected,
done
} type;
union args_t
{
// Sent to I/O thread to let it know that it should
// terminate itself.
struct {
} stop;
// Sent to I/O object to make it register with its I/O thread.
struct {
} plug;
// Sent to socket to let it know about the newly created object.
struct {
zmq::own_t *object;
} own;
// Attach the engine to the session. If engine is NULL, it informs
// session that the connection have failed.
struct {
struct i_engine *engine;
} attach;
// Sent from session to socket to establish pipe(s) between them.
// Caller have used inc_seqnum beforehand sending the command.
struct {
zmq::pipe_t *pipe;
} bind;
// Sent by pipe writer to inform dormant pipe reader that there
// are messages in the pipe.
struct {
} activate_read;
// Sent by pipe reader to inform pipe writer about how many
// messages it has read so far.
struct {
uint64_t msgs_read;
} activate_write;
// Sent by pipe reader to writer after creating a new inpipe.
// The parameter is actually of type pipe_t::upipe_t, however,
// its definition is private so we'll have to do with void*.
struct {
void *pipe;
} hiccup;
// Sent by pipe reader to pipe writer to ask it to terminate
// its end of the pipe.
struct {
} pipe_term;
// Pipe writer acknowledges pipe_term command.
struct {
} pipe_term_ack;
// Sent by one of pipe to another part for modify hwm
struct {
int inhwm;
int outhwm;
} pipe_hwm;
// Sent by I/O object ot the socket to request the shutdown of
// the I/O object.
struct {
zmq::own_t *object;
} term_req;
// Sent by socket to I/O object to start its shutdown.
struct {
int linger;
} term;
// Sent by I/O object to the socket to acknowledge it has
// shut down.
struct {
} term_ack;
// Sent by session_base (I/O thread) to socket (application thread)
// to ask to disconnect the endpoint.
struct {
std::string *endpoint;
} term_endpoint;
// Transfers the ownership of the closed socket
// to the reaper thread.
struct {
zmq::socket_base_t *socket;
} reap;
// Closed socket notifies the reaper that it's already deallocated.
struct {
} reaped;
// Sent by reaper thread to the term thread when all the sockets
// are successfully deallocated.
struct {
} done;
} args;
#ifdef _MSC_VER
};
#pragma warning(pop)
#else
} __attribute__((aligned(64)));
#endif
}
#endif
+279
View File
@@ -0,0 +1,279 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CONDITON_VARIABLE_HPP_INCLUDED__
#define __ZMQ_CONDITON_VARIABLE_HPP_INCLUDED__
#include "clock.hpp"
#include "err.hpp"
#include "mutex.hpp"
// Condition variable class encapsulates OS mutex in a platform-independent way.
#ifdef ZMQ_HAVE_WINDOWS
#include "windows.hpp"
#if defined(_MSC_VER)
#if _MSC_VER >= 1800
#define _SUPPORT_CONDITION_VARIABLE 1
#else
#define _SUPPORT_CONDITION_VARIABLE 0
#endif
#else
#if _cplusplus >= 201103L
#define _SUPPORT_CONDITION_VARIABLE 1
#else
#define _SUPPORT_CONDITION_VARIABLE 0
#endif
#endif
// Condition variable is supported from Windows Vista only, to use condition variable define _WIN32_WINNT to 0x0600
#if _WIN32_WINNT < 0x0600 && !_SUPPORT_CONDITION_VARIABLE
namespace zmq
{
class condition_variable_t
{
public:
inline condition_variable_t ()
{
zmq_assert(false);
}
inline ~condition_variable_t ()
{
}
inline int wait (mutex_t* mutex_, int timeout_ )
{
zmq_assert(false);
return -1;
}
inline void broadcast ()
{
zmq_assert(false);
}
private:
// Disable copy construction and assignment.
condition_variable_t (const condition_variable_t&);
void operator = (const condition_variable_t&);
};
}
#else
#if _SUPPORT_CONDITION_VARIABLE || defined(ZMQ_HAVE_WINDOWS_TARGET_XP)
#include <condition_variable>
#include <mutex>
#endif
namespace zmq
{
#if !defined(ZMQ_HAVE_WINDOWS_TARGET_XP) && _WIN32_WINNT >= 0x0600
class condition_variable_t
{
public:
inline condition_variable_t ()
{
InitializeConditionVariable (&cv);
}
inline ~condition_variable_t ()
{
}
inline int wait (mutex_t* mutex_, int timeout_ )
{
int rc = SleepConditionVariableCS(&cv, mutex_->get_cs (), timeout_);
if (rc != 0)
return 0;
rc = GetLastError();
if (rc != ERROR_TIMEOUT)
win_assert(rc);
errno = EAGAIN;
return -1;
}
inline void broadcast ()
{
WakeAllConditionVariable(&cv);
}
private:
CONDITION_VARIABLE cv;
// Disable copy construction and assignment.
condition_variable_t (const condition_variable_t&);
void operator = (const condition_variable_t&);
};
#else
class condition_variable_t
{
public:
inline condition_variable_t()
{
}
inline ~condition_variable_t()
{
}
inline int wait(mutex_t* mutex_, int timeout_)
{
std::unique_lock<std::mutex> lck(mtx); // lock mtx
mutex_->unlock(); // unlock mutex_
int res = 0;
if(timeout_ == -1) {
cv.wait(lck); // unlock mtx and wait cv.notify_all(), lock mtx after cv.notify_all()
} else if (cv.wait_for(lck, std::chrono::milliseconds(timeout_)) == std::cv_status::timeout) {
// time expired
errno = EAGAIN;
res = -1;
}
lck.unlock(); // unlock mtx
mutex_->lock(); // lock mutex_
return res;
}
inline void broadcast()
{
std::unique_lock<std::mutex> lck(mtx); // lock mtx
cv.notify_all();
}
private:
std::condition_variable cv;
std::mutex mtx;
// Disable copy construction and assignment.
condition_variable_t(const condition_variable_t&);
void operator = (const condition_variable_t&);
};
#endif
}
#endif
#else
#include <pthread.h>
namespace zmq
{
class condition_variable_t
{
public:
inline condition_variable_t ()
{
int rc = pthread_cond_init (&cond, NULL);
posix_assert (rc);
}
inline ~condition_variable_t ()
{
int rc = pthread_cond_destroy (&cond);
posix_assert (rc);
}
inline int wait (mutex_t* mutex_, int timeout_)
{
int rc;
if (timeout_ != -1) {
struct timespec timeout;
#if defined ZMQ_HAVE_OSX && __MAC_OS_X_VERSION_MIN_REQUIRED < 101200 // less than macOS 10.12
alt_clock_gettime(SYSTEM_CLOCK, &timeout);
#else
clock_gettime(CLOCK_MONOTONIC, &timeout);
#endif
timeout.tv_sec += timeout_ / 1000;
timeout.tv_nsec += (timeout_ % 1000) * 1000000;
if (timeout.tv_nsec > 1000000000) {
timeout.tv_sec++;
timeout.tv_nsec -= 1000000000;
}
rc = pthread_cond_timedwait (&cond, mutex_->get_mutex (), &timeout);
}
else
rc = pthread_cond_wait(&cond, mutex_->get_mutex());
if (rc == 0)
return 0;
if (rc == ETIMEDOUT){
errno= EAGAIN;
return -1;
}
posix_assert (rc);
return -1;
}
inline void broadcast ()
{
int rc = pthread_cond_broadcast (&cond);
posix_assert (rc);
}
private:
pthread_cond_t cond;
// Disable copy construction and assignment.
condition_variable_t (const condition_variable_t&);
const condition_variable_t &operator = (const condition_variable_t&);
};
}
#endif
#endif
+98
View File
@@ -0,0 +1,98 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CONFIG_HPP_INCLUDED__
#define __ZMQ_CONFIG_HPP_INCLUDED__
namespace zmq
{
// Compile-time settings.
enum
{
// Number of new messages in message pipe needed to trigger new memory
// allocation. Setting this parameter to 256 decreases the impact of
// memory allocation by approximately 99.6%
message_pipe_granularity = 256,
// Commands in pipe per allocation event.
command_pipe_granularity = 16,
// Determines how often does socket poll for new commands when it
// still has unprocessed messages to handle. Thus, if it is set to 100,
// socket will process 100 inbound messages before doing the poll.
// If there are no unprocessed messages available, poll is done
// immediately. Decreasing the value trades overall latency for more
// real-time behaviour (less latency peaks).
inbound_poll_rate = 100,
// Maximal batching size for engines with receiving functionality.
// So, if there are 10 messages that fit into the batch size, all of
// them may be read by a single 'recv' system call, thus avoiding
// unnecessary network stack traversals.
in_batch_size = 8192,
// Maximal batching size for engines with sending functionality.
// So, if there are 10 messages that fit into the batch size, all of
// them may be written by a single 'send' system call, thus avoiding
// unnecessary network stack traversals.
out_batch_size = 8192,
// Maximal delta between high and low watermark.
max_wm_delta = 1024,
// Maximum number of events the I/O thread can process in one go.
max_io_events = 256,
// Maximal delay to process command in API thread (in CPU ticks).
// 3,000,000 ticks equals to 1 - 2 milliseconds on current CPUs.
// Note that delay is only applied when there is continuous stream of
// messages to process. If not so, commands are processed immediately.
max_command_delay = 3000000,
// Low-precision clock precision in CPU ticks. 1ms. Value of 1000000
// should be OK for CPU frequencies above 1GHz. If should work
// reasonably well for CPU frequencies above 500MHz. For lower CPU
// frequencies you may consider lowering this value to get best
// possible latencies.
clock_precision = 1000000,
// On some OSes the signaler has to be emulated using a TCP
// connection. In such cases following port is used.
// If 0, it lets the OS choose a free port without requiring use of a
// global mutex. The original implementation of a Windows signaler
// socket used port 5905 instead of letting the OS choose a free port.
// https://github.com/zeromq/libzmq/issues/1542
signaler_port = 0
};
}
#endif
+644
View File
@@ -0,0 +1,644 @@
/*
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#ifndef ZMQ_HAVE_WINDOWS
#include <unistd.h>
#endif
#include <limits>
#include <climits>
#include <new>
#include <sstream>
#include <string.h>
#include "ctx.hpp"
#include "socket_base.hpp"
#include "io_thread.hpp"
#include "reaper.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
#include "random.hpp"
#ifdef ZMQ_HAVE_VMCI
#include <vmci_sockets.h>
#endif
#define ZMQ_CTX_TAG_VALUE_GOOD 0xabadcafe
#define ZMQ_CTX_TAG_VALUE_BAD 0xdeadbeef
int clipped_maxsocket (int max_requested)
{
if (max_requested >= zmq::poller_t::max_fds () && zmq::poller_t::max_fds () != -1)
// -1 because we need room for the reaper mailbox.
max_requested = zmq::poller_t::max_fds () - 1;
return max_requested;
}
zmq::ctx_t::ctx_t () :
tag (ZMQ_CTX_TAG_VALUE_GOOD),
starting (true),
terminating (false),
reaper (NULL),
slot_count (0),
slots (NULL),
max_sockets (clipped_maxsocket (ZMQ_MAX_SOCKETS_DFLT)),
max_msgsz (INT_MAX),
io_thread_count (ZMQ_IO_THREADS_DFLT),
blocky (true),
ipv6 (false),
thread_priority (ZMQ_THREAD_PRIORITY_DFLT),
thread_sched_policy (ZMQ_THREAD_SCHED_POLICY_DFLT)
{
#ifdef HAVE_FORK
pid = getpid();
#endif
#ifdef ZMQ_HAVE_VMCI
vmci_fd = -1;
vmci_family = -1;
#endif
// Initialise crypto library, if needed.
zmq::random_open ();
}
bool zmq::ctx_t::check_tag ()
{
return tag == ZMQ_CTX_TAG_VALUE_GOOD;
}
zmq::ctx_t::~ctx_t ()
{
// Check that there are no remaining sockets.
zmq_assert (sockets.empty ());
// Ask I/O threads to terminate. If stop signal wasn't sent to I/O
// thread subsequent invocation of destructor would hang-up.
for (io_threads_t::size_type i = 0; i != io_threads.size (); i++) {
io_threads [i]->stop ();
}
// Wait till I/O threads actually terminate.
for (io_threads_t::size_type i = 0; i != io_threads.size (); i++) {
LIBZMQ_DELETE(io_threads [i]);
}
// Deallocate the reaper thread object.
LIBZMQ_DELETE(reaper);
// Deallocate the array of mailboxes. No special work is
// needed as mailboxes themselves were deallocated with their
// corresponding io_thread/socket objects.
free (slots);
// De-initialise crypto library, if needed.
zmq::random_close ();
// Remove the tag, so that the object is considered dead.
tag = ZMQ_CTX_TAG_VALUE_BAD;
}
int zmq::ctx_t::terminate ()
{
slot_sync.lock();
bool saveTerminating = terminating;
terminating = false;
// Connect up any pending inproc connections, otherwise we will hang
pending_connections_t copy = pending_connections;
for (pending_connections_t::iterator p = copy.begin (); p != copy.end (); ++p) {
zmq::socket_base_t *s = create_socket (ZMQ_PAIR);
// create_socket might fail eg: out of memory/sockets limit reached
zmq_assert (s);
s->bind (p->first.c_str ());
s->close ();
}
terminating = saveTerminating;
if (!starting) {
#ifdef HAVE_FORK
if (pid != getpid ()) {
// we are a forked child process. Close all file descriptors
// inherited from the parent.
for (sockets_t::size_type i = 0; i != sockets.size (); i++)
sockets [i]->get_mailbox ()->forked ();
term_mailbox.forked ();
}
#endif
// Check whether termination was already underway, but interrupted and now
// restarted.
bool restarted = terminating;
terminating = true;
// First attempt to terminate the context.
if (!restarted) {
// First send stop command to sockets so that any blocking calls
// can be interrupted. If there are no sockets we can ask reaper
// thread to stop.
for (sockets_t::size_type i = 0; i != sockets.size (); i++)
sockets [i]->stop ();
if (sockets.empty ())
reaper->stop ();
}
slot_sync.unlock();
// Wait till reaper thread closes all the sockets.
command_t cmd;
int rc = term_mailbox.recv (&cmd, -1);
if (rc == -1 && errno == EINTR)
return -1;
errno_assert (rc == 0);
zmq_assert (cmd.type == command_t::done);
slot_sync.lock ();
zmq_assert (sockets.empty ());
}
slot_sync.unlock ();
#ifdef ZMQ_HAVE_VMCI
vmci_sync.lock ();
VMCISock_ReleaseAFValueFd (vmci_fd);
vmci_family = -1;
vmci_fd = -1;
vmci_sync.unlock ();
#endif
// Deallocate the resources.
delete this;
return 0;
}
int zmq::ctx_t::shutdown ()
{
scoped_lock_t locker(slot_sync);
if (!starting && !terminating) {
terminating = true;
// Send stop command to sockets so that any blocking calls
// can be interrupted. If there are no sockets we can ask reaper
// thread to stop.
for (sockets_t::size_type i = 0; i != sockets.size (); i++)
sockets [i]->stop ();
if (sockets.empty ())
reaper->stop ();
}
return 0;
}
int zmq::ctx_t::set (int option_, int optval_)
{
int rc = 0;
if (option_ == ZMQ_MAX_SOCKETS
&& optval_ >= 1 && optval_ == clipped_maxsocket (optval_)) {
scoped_lock_t locker(opt_sync);
max_sockets = optval_;
}
else
if (option_ == ZMQ_IO_THREADS && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
io_thread_count = optval_;
}
else
if (option_ == ZMQ_IPV6 && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
ipv6 = (optval_ != 0);
}
else
if (option_ == ZMQ_THREAD_PRIORITY && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
thread_priority = optval_;
}
else
if (option_ == ZMQ_THREAD_SCHED_POLICY && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
thread_sched_policy = optval_;
}
else
if (option_ == ZMQ_THREAD_AFFINITY_CPU_ADD && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
thread_affinity_cpus.insert( optval_ );
}
else
if (option_ == ZMQ_THREAD_AFFINITY_CPU_REMOVE && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
std::set<int>::iterator it = thread_affinity_cpus.find( optval_ );
if (it != thread_affinity_cpus.end()) {
thread_affinity_cpus.erase( it );
} else {
errno = EINVAL;
rc = -1;
}
}
else
if (option_ == ZMQ_THREAD_NAME_PREFIX && optval_ >= 0) {
std::ostringstream s;
s << optval_;
scoped_lock_t locker(opt_sync);
thread_name_prefix = s.str();
}
else
if (option_ == ZMQ_BLOCKY && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
blocky = (optval_ != 0);
}
else
if (option_ == ZMQ_MAX_MSGSZ && optval_ >= 0) {
scoped_lock_t locker(opt_sync);
max_msgsz = optval_ < INT_MAX? optval_: INT_MAX;
}
else {
errno = EINVAL;
rc = -1;
}
return rc;
}
int zmq::ctx_t::get (int option_)
{
int rc = 0;
if (option_ == ZMQ_MAX_SOCKETS)
rc = max_sockets;
else
if (option_ == ZMQ_SOCKET_LIMIT)
rc = clipped_maxsocket (65535);
else
if (option_ == ZMQ_IO_THREADS)
rc = io_thread_count;
else
if (option_ == ZMQ_IPV6)
rc = ipv6;
else
if (option_ == ZMQ_BLOCKY)
rc = blocky;
else
if (option_ == ZMQ_MAX_MSGSZ)
rc = max_msgsz;
else
if (option_ == ZMQ_MSG_T_SIZE)
rc = sizeof (zmq_msg_t);
else {
errno = EINVAL;
rc = -1;
}
return rc;
}
zmq::socket_base_t *zmq::ctx_t::create_socket (int type_)
{
scoped_lock_t locker(slot_sync);
if (unlikely (starting)) {
starting = false;
// Initialise the array of mailboxes. Additional three slots are for
// zmq_ctx_term thread and reaper thread.
opt_sync.lock ();
int mazmq = max_sockets;
int ios = io_thread_count;
opt_sync.unlock ();
slot_count = mazmq + ios + 2;
slots = (i_mailbox **) malloc (sizeof (i_mailbox*) * slot_count);
alloc_assert (slots);
// Initialise the infrastructure for zmq_ctx_term thread.
slots [term_tid] = &term_mailbox;
// Create the reaper thread.
reaper = new (std::nothrow) reaper_t (this, reaper_tid);
alloc_assert (reaper);
slots [reaper_tid] = reaper->get_mailbox ();
reaper->start ();
// Create I/O thread objects and launch them.
for (int i = 2; i != ios + 2; i++) {
io_thread_t *io_thread = new (std::nothrow) io_thread_t (this, i);
alloc_assert (io_thread);
io_threads.push_back (io_thread);
slots [i] = io_thread->get_mailbox ();
io_thread->start ();
}
// In the unused part of the slot array, create a list of empty slots.
for (int32_t i = (int32_t) slot_count - 1;
i >= (int32_t) ios + 2; i--) {
empty_slots.push_back (i);
slots [i] = NULL;
}
}
// Once zmq_ctx_term() was called, we can't create new sockets.
if (terminating) {
errno = ETERM;
return NULL;
}
// If max_sockets limit was reached, return error.
if (empty_slots.empty ()) {
errno = EMFILE;
return NULL;
}
// Choose a slot for the socket.
uint32_t slot = empty_slots.back ();
empty_slots.pop_back ();
// Generate new unique socket ID.
int sid = ((int) max_socket_id.add (1)) + 1;
// Create the socket and register its mailbox.
socket_base_t *s = socket_base_t::create (type_, this, slot, sid);
if (!s) {
empty_slots.push_back (slot);
return NULL;
}
sockets.push_back (s);
slots [slot] = s->get_mailbox ();
return s;
}
void zmq::ctx_t::destroy_socket (class socket_base_t *socket_)
{
scoped_lock_t locker(slot_sync);
// Free the associated thread slot.
uint32_t tid = socket_->get_tid ();
empty_slots.push_back (tid);
slots [tid] = NULL;
// Remove the socket from the list of sockets.
sockets.erase (socket_);
// If zmq_ctx_term() was already called and there are no more socket
// we can ask reaper thread to terminate.
if (terminating && sockets.empty ())
reaper->stop ();
}
zmq::object_t *zmq::ctx_t::get_reaper ()
{
return reaper;
}
void zmq::ctx_t::start_thread (thread_t &thread_, thread_fn *tfn_, void *arg_) const
{
static unsigned int nthreads_started = 0;
thread_.setSchedulingParameters(thread_priority, thread_sched_policy, thread_affinity_cpus);
thread_.start(tfn_, arg_);
#ifndef ZMQ_HAVE_ANDROID
std::ostringstream s;
if (!thread_name_prefix.empty())
s << thread_name_prefix << "/";
s << "ZMQbg/" << nthreads_started;
thread_.setThreadName (s.str().c_str());
#endif
nthreads_started++;
}
void zmq::ctx_t::send_command (uint32_t tid_, const command_t &command_)
{
slots [tid_]->send (command_);
}
zmq::io_thread_t *zmq::ctx_t::choose_io_thread (uint64_t affinity_)
{
if (io_threads.empty ())
return NULL;
// Find the I/O thread with minimum load.
int min_load = -1;
io_thread_t *selected_io_thread = NULL;
for (io_threads_t::size_type i = 0; i != io_threads.size (); i++) {
if (!affinity_ || (affinity_ & (uint64_t (1) << i))) {
int load = io_threads [i]->get_load ();
if (selected_io_thread == NULL || load < min_load) {
min_load = load;
selected_io_thread = io_threads [i];
}
}
}
return selected_io_thread;
}
int zmq::ctx_t::register_endpoint (const char *addr_,
const endpoint_t &endpoint_)
{
scoped_lock_t locker(endpoints_sync);
const bool inserted = endpoints.ZMQ_MAP_INSERT_OR_EMPLACE (addr_,
endpoint_).second;
if (!inserted) {
errno = EADDRINUSE;
return -1;
}
return 0;
}
int zmq::ctx_t::unregister_endpoint (
const std::string &addr_, socket_base_t *socket_)
{
scoped_lock_t locker(endpoints_sync);
const endpoints_t::iterator it = endpoints.find (addr_);
if (it == endpoints.end () || it->second.socket != socket_) {
errno = ENOENT;
return -1;
}
// Remove endpoint.
endpoints.erase (it);
return 0;
}
void zmq::ctx_t::unregister_endpoints (socket_base_t *socket_)
{
scoped_lock_t locker(endpoints_sync);
endpoints_t::iterator it = endpoints.begin ();
while (it != endpoints.end ()) {
if (it->second.socket == socket_) {
endpoints_t::iterator to_erase = it;
++it;
endpoints.erase (to_erase);
continue;
}
++it;
}
}
zmq::endpoint_t zmq::ctx_t::find_endpoint (const char *addr_)
{
scoped_lock_t locker(endpoints_sync);
endpoints_t::iterator it = endpoints.find (addr_);
if (it == endpoints.end ()) {
errno = ECONNREFUSED;
endpoint_t empty = {NULL, options_t()};
return empty;
}
endpoint_t endpoint = it->second;
// Increment the command sequence number of the peer so that it won't
// get deallocated until "bind" command is issued by the caller.
// The subsequent 'bind' has to be called with inc_seqnum parameter
// set to false, so that the seqnum isn't incremented twice.
endpoint.socket->inc_seqnum ();
return endpoint;
}
void zmq::ctx_t::pend_connection (const std::string &addr_,
const endpoint_t &endpoint_, pipe_t **pipes_)
{
scoped_lock_t locker(endpoints_sync);
const pending_connection_t pending_connection = {endpoint_, pipes_ [0], pipes_ [1]};
endpoints_t::iterator it = endpoints.find (addr_);
if (it == endpoints.end ()) {
// Still no bind.
endpoint_.socket->inc_seqnum ();
pending_connections.ZMQ_MAP_INSERT_OR_EMPLACE (addr_, pending_connection);
} else {
// Bind has happened in the mean time, connect directly
connect_inproc_sockets(it->second.socket, it->second.options, pending_connection, connect_side);
}
}
void zmq::ctx_t::connect_pending (const char *addr_, zmq::socket_base_t *bind_socket_)
{
scoped_lock_t locker(endpoints_sync);
std::pair<pending_connections_t::iterator, pending_connections_t::iterator> pending = pending_connections.equal_range(addr_);
for (pending_connections_t::iterator p = pending.first; p != pending.second; ++p)
connect_inproc_sockets(bind_socket_, endpoints[addr_].options, p->second, bind_side);
pending_connections.erase(pending.first, pending.second);
}
void zmq::ctx_t::connect_inproc_sockets (zmq::socket_base_t *bind_socket_,
options_t& bind_options, const pending_connection_t &pending_connection_, side side_)
{
bind_socket_->inc_seqnum();
pending_connection_.bind_pipe->set_tid (bind_socket_->get_tid ());
if (!bind_options.recv_routing_id) {
msg_t msg;
const bool ok = pending_connection_.bind_pipe->read (&msg);
zmq_assert (ok);
const int rc = msg.close ();
errno_assert (rc == 0);
}
bool conflate = pending_connection_.endpoint.options.conflate &&
(pending_connection_.endpoint.options.type == ZMQ_DEALER ||
pending_connection_.endpoint.options.type == ZMQ_PULL ||
pending_connection_.endpoint.options.type == ZMQ_PUSH ||
pending_connection_.endpoint.options.type == ZMQ_PUB ||
pending_connection_.endpoint.options.type == ZMQ_SUB);
if (!conflate) {
pending_connection_.connect_pipe->set_hwms_boost(bind_options.sndhwm, bind_options.rcvhwm);
pending_connection_.bind_pipe->set_hwms_boost(pending_connection_.endpoint.options.sndhwm, pending_connection_.endpoint.options.rcvhwm);
pending_connection_.connect_pipe->set_hwms(pending_connection_.endpoint.options.rcvhwm, pending_connection_.endpoint.options.sndhwm);
pending_connection_.bind_pipe->set_hwms(bind_options.rcvhwm, bind_options.sndhwm);
}
else {
pending_connection_.connect_pipe->set_hwms(-1, -1);
pending_connection_.bind_pipe->set_hwms(-1, -1);
}
if (side_ == bind_side) {
command_t cmd;
cmd.type = command_t::bind;
cmd.args.bind.pipe = pending_connection_.bind_pipe;
bind_socket_->process_command (cmd);
bind_socket_->send_inproc_connected (pending_connection_.endpoint.socket);
}
else
pending_connection_.connect_pipe->send_bind (bind_socket_, pending_connection_.bind_pipe, false);
// When a ctx is terminated all pending inproc connection will be
// connected, but the socket will already be closed and the pipe will be
// in waiting_for_delimiter state, which means no more writes can be done
// and the routing id write fails and causes an assert. Check if the socket
// is open before sending.
if (pending_connection_.endpoint.options.recv_routing_id &&
pending_connection_.endpoint.socket->check_tag ()) {
msg_t routing_id;
const int rc = routing_id.init_size (bind_options.routing_id_size);
errno_assert (rc == 0);
memcpy (routing_id.data (), bind_options.routing_id, bind_options.routing_id_size);
routing_id.set_flags (msg_t::routing_id);
const bool written = pending_connection_.bind_pipe->write (&routing_id);
zmq_assert (written);
pending_connection_.bind_pipe->flush ();
}
}
#ifdef ZMQ_HAVE_VMCI
int zmq::ctx_t::get_vmci_socket_family ()
{
zmq::scoped_lock_t locker(vmci_sync);
if (vmci_fd == -1) {
vmci_family = VMCISock_GetAFValueFd (&vmci_fd);
if (vmci_fd != -1) {
#ifdef FD_CLOEXEC
int rc = fcntl (vmci_fd, F_SETFD, FD_CLOEXEC);
errno_assert (rc != -1);
#endif
}
}
return vmci_family;
}
#endif
// The last used socket ID, or 0 if no socket was used so far. Note that this
// is a global variable. Thus, even sockets created in different contexts have
// unique IDs.
zmq::atomic_counter_t zmq::ctx_t::max_socket_id;
+242
View File
@@ -0,0 +1,242 @@
/*
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CTX_HPP_INCLUDED__
#define __ZMQ_CTX_HPP_INCLUDED__
#include <map>
#include <vector>
#include <string>
#include <stdarg.h>
#include "mailbox.hpp"
#include "array.hpp"
#include "config.hpp"
#include "mutex.hpp"
#include "stdint.hpp"
#include "options.hpp"
#include "atomic_counter.hpp"
#include "thread.hpp"
namespace zmq
{
class object_t;
class io_thread_t;
class socket_base_t;
class reaper_t;
class pipe_t;
// Information associated with inproc endpoint. Note that endpoint options
// are registered as well so that the peer can access them without a need
// for synchronisation, handshaking or similar.
struct endpoint_t
{
socket_base_t *socket;
options_t options;
};
// Context object encapsulates all the global state associated with
// the library.
class ctx_t
{
public:
// Create the context object.
ctx_t ();
// Returns false if object is not a context.
bool check_tag ();
// This function is called when user invokes zmq_ctx_term. If there are
// no more sockets open it'll cause all the infrastructure to be shut
// down. If there are open sockets still, the deallocation happens
// after the last one is closed.
int terminate ();
// This function starts the terminate process by unblocking any blocking
// operations currently in progress and stopping any more socket activity
// (except zmq_close).
// This function is non-blocking.
// terminate must still be called afterwards.
// This function is optional, terminate will unblock any current
// operations as well.
int shutdown();
// Set and get context properties.
int set (int option_, int optval_);
int get (int option_);
// Create and destroy a socket.
zmq::socket_base_t *create_socket (int type_);
void destroy_socket (zmq::socket_base_t *socket_);
// Start a new thread with proper scheduling parameters.
void start_thread (thread_t &thread_, thread_fn *tfn_, void *arg_) const;
// Send command to the destination thread.
void send_command (uint32_t tid_, const command_t &command_);
// Returns the I/O thread that is the least busy at the moment.
// Affinity specifies which I/O threads are eligible (0 = all).
// Returns NULL if no I/O thread is available.
zmq::io_thread_t *choose_io_thread (uint64_t affinity_);
// Returns reaper thread object.
zmq::object_t *get_reaper ();
// Management of inproc endpoints.
int register_endpoint (const char *addr_, const endpoint_t &endpoint_);
int unregister_endpoint (const std::string &addr_, socket_base_t *socket_);
void unregister_endpoints (zmq::socket_base_t *socket_);
endpoint_t find_endpoint (const char *addr_);
void pend_connection (const std::string &addr_,
const endpoint_t &endpoint_, pipe_t **pipes_);
void connect_pending (const char *addr_, zmq::socket_base_t *bind_socket_);
#ifdef ZMQ_HAVE_VMCI
// Return family for the VMCI socket or -1 if it's not available.
int get_vmci_socket_family ();
#endif
enum {
term_tid = 0,
reaper_tid = 1
};
~ctx_t ();
private:
struct pending_connection_t
{
endpoint_t endpoint;
pipe_t* connect_pipe;
pipe_t* bind_pipe;
};
// Used to check whether the object is a context.
uint32_t tag;
// Sockets belonging to this context. We need the list so that
// we can notify the sockets when zmq_ctx_term() is called.
// The sockets will return ETERM then.
typedef array_t <socket_base_t> sockets_t;
sockets_t sockets;
// List of unused thread slots.
typedef std::vector <uint32_t> empty_slots_t;
empty_slots_t empty_slots;
// If true, zmq_init has been called but no socket has been created
// yet. Launching of I/O threads is delayed.
bool starting;
// If true, zmq_ctx_term was already called.
bool terminating;
// Synchronisation of accesses to global slot-related data:
// sockets, empty_slots, terminating. It also synchronises
// access to zombie sockets as such (as opposed to slots) and provides
// a memory barrier to ensure that all CPU cores see the same data.
mutex_t slot_sync;
// The reaper thread.
zmq::reaper_t *reaper;
// I/O threads.
typedef std::vector <zmq::io_thread_t*> io_threads_t;
io_threads_t io_threads;
// Array of pointers to mailboxes for both application and I/O threads.
uint32_t slot_count;
i_mailbox **slots;
// Mailbox for zmq_ctx_term thread.
mailbox_t term_mailbox;
// List of inproc endpoints within this context.
typedef std::map <std::string, endpoint_t> endpoints_t;
endpoints_t endpoints;
// List of inproc connection endpoints pending a bind
typedef std::multimap <std::string, pending_connection_t> pending_connections_t;
pending_connections_t pending_connections;
// Synchronisation of access to the list of inproc endpoints.
mutex_t endpoints_sync;
// Maximum socket ID.
static atomic_counter_t max_socket_id;
// Maximum number of sockets that can be opened at the same time.
int max_sockets;
// Maximum allowed message size
int max_msgsz;
// Number of I/O threads to launch.
int io_thread_count;
// Does context wait (possibly forever) on termination?
bool blocky;
// Is IPv6 enabled on this context?
bool ipv6;
// Thread parameters.
int thread_priority;
int thread_sched_policy;
std::set<int> thread_affinity_cpus;
std::string thread_name_prefix;
// Synchronisation of access to context options.
mutex_t opt_sync;
ctx_t (const ctx_t&);
const ctx_t &operator = (const ctx_t&);
#ifdef HAVE_FORK
// the process that created this context. Used to detect forking.
pid_t pid;
#endif
enum side { connect_side, bind_side };
void connect_inproc_sockets(zmq::socket_base_t *bind_socket_, options_t& bind_options, const pending_connection_t &pending_connection_, side side_);
#ifdef ZMQ_HAVE_VMCI
int vmci_fd;
int vmci_family;
mutex_t vmci_sync;
#endif
};
}
#endif
+87
View File
@@ -0,0 +1,87 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CURVE_CLIENT_HPP_INCLUDED__
#define __ZMQ_CURVE_CLIENT_HPP_INCLUDED__
#ifdef ZMQ_HAVE_CURVE
#include "curve_mechanism_base.hpp"
#include "options.hpp"
#include "curve_client_tools.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
class curve_client_t : public curve_mechanism_base_t
{
public:
curve_client_t (session_base_t *session_, const options_t &options_);
virtual ~curve_client_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int encode (msg_t *msg_);
virtual int decode (msg_t *msg_);
virtual status_t status () const;
private:
enum state_t {
send_hello,
expect_welcome,
send_initiate,
expect_ready,
error_received,
connected
};
// Current FSM state
state_t state;
// CURVE protocol tools
curve_client_tools_t tools;
int produce_hello (msg_t *msg_);
int process_welcome (const uint8_t *cmd_data, size_t data_size);
int produce_initiate (msg_t *msg_);
int process_ready (const uint8_t *cmd_data, size_t data_size);
int process_error (const uint8_t *cmd_data, size_t data_size);
};
}
#endif
#endif
+94
View File
@@ -0,0 +1,94 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_CURVE_SERVER_HPP_INCLUDED__
#define __ZMQ_CURVE_SERVER_HPP_INCLUDED__
#ifdef ZMQ_HAVE_CURVE
#include "curve_mechanism_base.hpp"
#include "options.hpp"
#include "zap_client.hpp"
namespace zmq
{
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4250)
#endif
class curve_server_t : public zap_client_common_handshake_t,
public curve_mechanism_base_t
{
public:
curve_server_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_);
virtual ~curve_server_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int encode (msg_t *msg_);
virtual int decode (msg_t *msg_);
private:
// Our secret key (s)
uint8_t secret_key [crypto_box_SECRETKEYBYTES];
// Our short-term public key (S')
uint8_t cn_public [crypto_box_PUBLICKEYBYTES];
// Our short-term secret key (s')
uint8_t cn_secret [crypto_box_SECRETKEYBYTES];
// Client's short-term public key (C')
uint8_t cn_client [crypto_box_PUBLICKEYBYTES];
// Key used to produce cookie
uint8_t cookie_key [crypto_secretbox_KEYBYTES];
int process_hello (msg_t *msg_);
int produce_welcome (msg_t *msg_);
int process_initiate (msg_t *msg_);
int produce_ready (msg_t *msg_);
int produce_error (msg_t *msg_) const;
void send_zap_request (const uint8_t *key);
};
#ifdef _MSC_VER
#pragma warning (pop)
#endif
}
#endif
#endif
+144
View File
@@ -0,0 +1,144 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DBUFFER_HPP_INCLUDED__
#define __ZMQ_DBUFFER_HPP_INCLUDED__
#include <stdlib.h>
#include <stddef.h>
#include <algorithm>
#include "mutex.hpp"
#include "msg.hpp"
namespace zmq
{
// dbuffer is a single-producer single-consumer double-buffer
// implementation.
//
// The producer writes to a back buffer and then tries to swap
// pointers between the back and front buffers. If it fails,
// due to the consumer reading from the front buffer, it just
// gives up, which is ok since writes are many and redundant.
//
// The reader simply reads from the front buffer.
//
// has_msg keeps track of whether there has been a not yet read
// value written, it is used by ypipe_conflate to mimic ypipe
// functionality regarding a reader being asleep
template <typename T> class dbuffer_t;
template <> class dbuffer_t<msg_t>
{
public:
inline dbuffer_t ()
: back (&storage[0])
, front (&storage[1])
, has_msg (false)
{
back->init ();
front->init ();
}
inline ~dbuffer_t()
{
back->close ();
front->close ();
}
inline void write (const msg_t &value_)
{
msg_t& xvalue = const_cast<msg_t&>(value_);
zmq_assert (xvalue.check ());
back->move (xvalue); // cannot just overwrite, might leak
zmq_assert (back->check ());
if (sync.try_lock ())
{
std::swap (back, front);
has_msg = true;
sync.unlock ();
}
}
inline bool read (msg_t *value_)
{
if (!value_)
return false;
{
scoped_lock_t lock (sync);
if (!has_msg)
return false;
zmq_assert (front->check ());
*value_ = *front;
front->init (); // avoid double free
has_msg = false;
return true;
}
}
inline bool check_read ()
{
scoped_lock_t lock (sync);
return has_msg;
}
inline bool probe (bool (*fn)(const msg_t &))
{
scoped_lock_t lock (sync);
return (*fn) (*front);
}
private:
msg_t storage[2];
msg_t *back, *front;
mutex_t sync;
bool has_msg;
// Disable copying of dbuffer.
dbuffer_t (const dbuffer_t&);
const dbuffer_t &operator = (const dbuffer_t&);
};
}
#endif
+143
View File
@@ -0,0 +1,143 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "dealer.hpp"
#include "err.hpp"
#include "msg.hpp"
zmq::dealer_t::dealer_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_),
probe_router (false)
{
options.type = ZMQ_DEALER;
}
zmq::dealer_t::~dealer_t ()
{
}
void zmq::dealer_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_);
if (probe_router) {
msg_t probe_msg_;
int rc = probe_msg_.init ();
errno_assert (rc == 0);
rc = pipe_->write (&probe_msg_);
// zmq_assert (rc) is not applicable here, since it is not a bug.
pipe_->flush ();
rc = probe_msg_.close ();
errno_assert (rc == 0);
}
fq.attach (pipe_);
lb.attach (pipe_);
}
int zmq::dealer_t::xsetsockopt (int option_, const void *optval_,
size_t optvallen_)
{
bool is_int = (optvallen_ == sizeof (int));
int value = 0;
if (is_int) memcpy(&value, optval_, sizeof (int));
switch (option_) {
case ZMQ_PROBE_ROUTER:
if (is_int && value >= 0) {
probe_router = (value != 0);
return 0;
}
break;
default:
break;
}
errno = EINVAL;
return -1;
}
int zmq::dealer_t::xsend (msg_t *msg_)
{
return sendpipe (msg_, NULL);
}
int zmq::dealer_t::xrecv (msg_t *msg_)
{
return recvpipe (msg_, NULL);
}
bool zmq::dealer_t::xhas_in ()
{
return fq.has_in ();
}
bool zmq::dealer_t::xhas_out ()
{
return lb.has_out ();
}
const zmq::blob_t &zmq::dealer_t::get_credential () const
{
return fq.get_credential ();
}
void zmq::dealer_t::xread_activated (pipe_t *pipe_)
{
fq.activated (pipe_);
}
void zmq::dealer_t::xwrite_activated (pipe_t *pipe_)
{
lb.activated (pipe_);
}
void zmq::dealer_t::xpipe_terminated (pipe_t *pipe_)
{
fq.pipe_terminated (pipe_);
lb.pipe_terminated (pipe_);
}
int zmq::dealer_t::sendpipe (msg_t *msg_, pipe_t **pipe_)
{
return lb.sendpipe (msg_, pipe_);
}
int zmq::dealer_t::recvpipe (msg_t *msg_, pipe_t **pipe_)
{
return fq.recvpipe (msg_, pipe_);
}
+89
View File
@@ -0,0 +1,89 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DEALER_HPP_INCLUDED__
#define __ZMQ_DEALER_HPP_INCLUDED__
#include "socket_base.hpp"
#include "session_base.hpp"
#include "fq.hpp"
#include "lb.hpp"
namespace zmq
{
class ctx_t;
class msg_t;
class pipe_t;
class io_thread_t;
class socket_base_t;
class dealer_t :
public socket_base_t
{
public:
dealer_t (zmq::ctx_t *parent_, uint32_t tid_, int sid);
~dealer_t ();
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsetsockopt (int option_, const void *optval_, size_t optvallen_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
// Send and recv - knowing which pipe was used.
int sendpipe (zmq::msg_t *msg_, zmq::pipe_t **pipe_);
int recvpipe (zmq::msg_t *msg_, zmq::pipe_t **pipe_);
private:
// Messages are fair-queued from inbound pipes. And load-balanced to
// the outbound pipes.
fq_t fq;
lb_t lb;
// if true, send an empty message to every connected router peer
bool probe_router;
dealer_t (const dealer_t&);
const dealer_t &operator = (const dealer_t&);
};
}
#endif
+198
View File
@@ -0,0 +1,198 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DECODER_HPP_INCLUDED__
#define __ZMQ_DECODER_HPP_INCLUDED__
#include <algorithm>
#include <cstddef>
#include <cstring>
#include "decoder_allocators.hpp"
#include "err.hpp"
#include "i_decoder.hpp"
#include "msg.hpp"
#include "stdint.hpp"
namespace zmq
{
// Helper base class for decoders that know the amount of data to read
// in advance at any moment. Knowing the amount in advance is a property
// of the protocol used. 0MQ framing protocol is based size-prefixed
// paradigm, which qualifies it to be parsed by this class.
// On the other hand, XML-based transports (like XMPP or SOAP) don't allow
// for knowing the size of data to read in advance and should use different
// decoding algorithms.
//
// This class implements the state machine that parses the incoming buffer.
// Derived class should implement individual state machine actions.
//
// Buffer management is done by an allocator policy.
template <typename T, typename A = c_single_allocator>
class decoder_base_t : public i_decoder
{
public:
explicit decoder_base_t (A *allocator_) :
next (NULL),
read_pos (NULL),
to_read (0),
allocator(allocator_)
{
buf = allocator->allocate ();
}
// The destructor doesn't have to be virtual. It is made virtual
// just to keep ICC and code checking tools from complaining.
virtual ~decoder_base_t ()
{
allocator->deallocate ();
}
// Returns a buffer to be filled with binary data.
void get_buffer (unsigned char **data_, std::size_t *size_)
{
buf = allocator->allocate ();
// If we are expected to read large message, we'll opt for zero-
// copy, i.e. we'll ask caller to fill the data directly to the
// message. Note that subsequent read(s) are non-blocking, thus
// each single read reads at most SO_RCVBUF bytes at once not
// depending on how large is the chunk returned from here.
// As a consequence, large messages being received won't block
// other engines running in the same I/O thread for excessive
// amounts of time.
if (to_read >= allocator->size ()) {
*data_ = read_pos;
*size_ = to_read;
return;
}
*data_ = buf;
*size_ = allocator->size ();
}
// Processes the data in the buffer previously allocated using
// get_buffer function. size_ argument specifies number of bytes
// actually filled into the buffer. Function returns 1 when the
// whole message was decoded or 0 when more data is required.
// On error, -1 is returned and errno set accordingly.
// Number of bytes processed is returned in bytes_used_.
int decode (const unsigned char *data_, std::size_t size_,
std::size_t &bytes_used_)
{
bytes_used_ = 0;
// In case of zero-copy simply adjust the pointers, no copying
// is required. Also, run the state machine in case all the data
// were processed.
if (data_ == read_pos) {
zmq_assert (size_ <= to_read);
read_pos += size_;
to_read -= size_;
bytes_used_ = size_;
while (!to_read) {
const int rc =
(static_cast <T *> (this)->*next) (data_ + bytes_used_);
if (rc != 0)
return rc;
}
return 0;
}
while (bytes_used_ < size_) {
// Copy the data from buffer to the message.
const size_t to_copy = std::min (to_read, size_ - bytes_used_);
// Only copy when destination address is different from the
// current address in the buffer.
if (read_pos != data_ + bytes_used_) {
memcpy (read_pos, data_ + bytes_used_, to_copy);
}
read_pos += to_copy;
to_read -= to_copy;
bytes_used_ += to_copy;
// Try to get more space in the message to fill in.
// If none is available, return.
while (to_read == 0) {
// pass current address in the buffer
const int rc =
(static_cast <T *> (this)->*next) (data_ + bytes_used_);
if (rc != 0)
return rc;
}
}
return 0;
}
virtual void resize_buffer (std::size_t new_size)
{
allocator->resize (new_size);
}
protected:
// Prototype of state machine action. Action should return false if
// it is unable to push the data to the system.
typedef int (T:: *step_t) (unsigned char const *);
// This function should be called from derived class to read data
// from the buffer and schedule next state machine action.
void next_step (void *read_pos_, std::size_t to_read_, step_t next_)
{
read_pos = static_cast <unsigned char*> (read_pos_);
to_read = to_read_;
next = next_;
}
private:
// Next step. If set to NULL, it means that associated data stream
// is dead. Note that there can be still data in the process in such
// case.
step_t next;
// Where to store the read data.
unsigned char *read_pos;
// How much data to read before taking next step.
std::size_t to_read;
// The duffer for data to decode.
A *allocator;
unsigned char *buf;
decoder_base_t (const decoder_base_t &);
const decoder_base_t &operator = (const decoder_base_t &);
};
}
#endif
+144
View File
@@ -0,0 +1,144 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "decoder_allocators.hpp"
#include <cmath>
#include "msg.hpp"
zmq::shared_message_memory_allocator::shared_message_memory_allocator (std::size_t bufsize_) :
buf(NULL),
bufsize(0),
max_size(bufsize_),
msg_content(NULL),
maxCounters (static_cast <size_t> (std::ceil (static_cast <double> (max_size) / static_cast <double> (msg_t::max_vsm_size))))
{
}
zmq::shared_message_memory_allocator::shared_message_memory_allocator (std::size_t bufsize_, std::size_t maxMessages) :
buf(NULL),
bufsize(0),
max_size(bufsize_),
msg_content(NULL),
maxCounters(maxMessages)
{
}
zmq::shared_message_memory_allocator::~shared_message_memory_allocator ()
{
deallocate();
}
unsigned char* zmq::shared_message_memory_allocator::allocate ()
{
if (buf) {
// release reference count to couple lifetime to messages
zmq::atomic_counter_t* c = reinterpret_cast<zmq::atomic_counter_t* >(buf);
// if refcnt drops to 0, there are no message using the buffer
// because either all messages have been closed or only vsm-messages
// were created
if (c->sub (1)) {
// buffer is still in use as message data. "Release" it and create a new one
// release pointer because we are going to create a new buffer
release ();
}
}
// if buf != NULL it is not used by any message so we can re-use it for the next run
if (!buf) {
// allocate memory for reference counters together with reception buffer
std::size_t const allocationsize =
max_size + sizeof (zmq::atomic_counter_t) +
maxCounters * sizeof (zmq::msg_t::content_t);
buf = static_cast <unsigned char *> (std::malloc (allocationsize));
alloc_assert (buf);
new (buf) atomic_counter_t (1);
} else {
// release reference count to couple lifetime to messages
zmq::atomic_counter_t *c = reinterpret_cast <zmq::atomic_counter_t *> (buf);
c->set (1);
}
bufsize = max_size;
msg_content = reinterpret_cast <zmq::msg_t::content_t*> (buf + sizeof (atomic_counter_t) + max_size);
return buf + sizeof (zmq::atomic_counter_t);
}
void zmq::shared_message_memory_allocator::deallocate ()
{
zmq::atomic_counter_t* c = reinterpret_cast<zmq::atomic_counter_t* >(buf);
if (buf && !c->sub(1)) {
std::free(buf);
}
release();
}
unsigned char* zmq::shared_message_memory_allocator::release ()
{
unsigned char* b = buf;
buf = NULL;
bufsize = 0;
msg_content = NULL;
return b;
}
void zmq::shared_message_memory_allocator::inc_ref ()
{
(reinterpret_cast <zmq::atomic_counter_t*> (buf))->add (1);
}
void zmq::shared_message_memory_allocator::call_dec_ref(void*, void* hint)
{
zmq_assert (hint);
unsigned char* buf = static_cast <unsigned char*> (hint);
zmq::atomic_counter_t* c = reinterpret_cast <zmq::atomic_counter_t*> (buf);
if (!c->sub (1)) {
c->~atomic_counter_t ();
std::free (buf);
buf = NULL;
}
}
std::size_t zmq::shared_message_memory_allocator::size () const
{
return bufsize;
}
unsigned char* zmq::shared_message_memory_allocator::data ()
{
return buf + sizeof (zmq::atomic_counter_t);
}
+155
View File
@@ -0,0 +1,155 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DECODER_ALLOCATORS_HPP_INCLUDED__
#define __ZMQ_DECODER_ALLOCATORS_HPP_INCLUDED__
#include <cstddef>
#include <cstdlib>
#include "atomic_counter.hpp"
#include "msg.hpp"
#include "err.hpp"
namespace zmq
{
// Static buffer policy.
class c_single_allocator
{
public:
explicit c_single_allocator (std::size_t bufsize_) :
bufsize(bufsize_),
buf(static_cast <unsigned char*> (std::malloc (bufsize)))
{
alloc_assert (buf);
}
~c_single_allocator ()
{
std::free (buf);
}
unsigned char* allocate ()
{
return buf;
}
void deallocate ()
{
}
std::size_t size () const
{
return bufsize;
}
void resize (std::size_t new_size)
{
bufsize = new_size;
}
private:
std::size_t bufsize;
unsigned char* buf;
c_single_allocator (c_single_allocator const&);
c_single_allocator& operator = (c_single_allocator const&);
};
// This allocator allocates a reference counted buffer which is used by v2_decoder_t
// to use zero-copy msg::init_data to create messages with memory from this buffer as
// data storage.
//
// The buffer is allocated with a reference count of 1 to make sure that is is alive while
// decoding messages. Otherwise, it is possible that e.g. the first message increases the count
// from zero to one, gets passed to the user application, processed in the user thread and deleted
// which would then deallocate the buffer. The drawback is that the buffer may be allocated longer
// than necessary because it is only deleted when allocate is called the next time.
class shared_message_memory_allocator
{
public:
explicit shared_message_memory_allocator (std::size_t bufsize_);
// Create an allocator for a maximum number of messages
shared_message_memory_allocator (std::size_t bufsize_, std::size_t maxMessages);
~shared_message_memory_allocator ();
// Allocate a new buffer
//
// This releases the current buffer to be bound to the lifetime of the messages
// created on this buffer.
unsigned char* allocate ();
// force deallocation of buffer.
void deallocate ();
// Give up ownership of the buffer. The buffer's lifetime is now coupled to
// the messages constructed on top of it.
unsigned char* release ();
void inc_ref ();
static void call_dec_ref (void*, void* buffer);
std::size_t size () const;
// Return pointer to the first message data byte.
unsigned char* data ();
// Return pointer to the first byte of the buffer.
unsigned char* buffer ()
{
return buf;
}
void resize (std::size_t new_size)
{
bufsize = new_size;
}
zmq::msg_t::content_t* provide_content ()
{
return msg_content;
}
void advance_content ()
{
msg_content++;
}
private:
unsigned char* buf;
std::size_t bufsize;
std::size_t max_size;
zmq::msg_t::content_t* msg_content;
std::size_t maxCounters;
};
}
#endif
+177
View File
@@ -0,0 +1,177 @@
/*
Copyright (c) 2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "dgram.hpp"
#include "pipe.hpp"
#include "wire.hpp"
#include "random.hpp"
#include "likely.hpp"
#include "err.hpp"
zmq::dgram_t::dgram_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_),
pipe (NULL),
last_in (NULL),
more_out (false)
{
options.type = ZMQ_DGRAM;
options.raw_socket = true;
}
zmq::dgram_t::~dgram_t ()
{
zmq_assert (!pipe);
}
void zmq::dgram_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED(subscribe_to_all_);
zmq_assert (pipe_);
// ZMQ_DGRAM socket can only be connected to a single peer.
// The socket rejects any further connection requests.
if (pipe == NULL)
pipe = pipe_;
else
pipe_->terminate (false);
}
void zmq::dgram_t::xpipe_terminated (pipe_t *pipe_)
{
if (pipe_ == pipe) {
if (last_in == pipe) {
saved_credential.set_deep_copy (last_in->get_credential ());
last_in = NULL;
}
pipe = NULL;
}
}
void zmq::dgram_t::xread_activated (pipe_t *)
{
// There's just one pipe. No lists of active and inactive pipes.
// There's nothing to do here.
}
void zmq::dgram_t::xwrite_activated (pipe_t *)
{
// There's just one pipe. No lists of active and inactive pipes.
// There's nothing to do here.
}
int zmq::dgram_t::xsend (msg_t *msg_)
{
// If there's no out pipe, just drop it.
if (!pipe) {
int rc = msg_->close ();
errno_assert (rc == 0);
return -1;
}
// If this is the first part of the message it's the ID of the
// peer to send the message to.
if (!more_out) {
if (!(msg_->flags () & msg_t::more)) {
errno = EINVAL;
return -1;
}
// Expect one more message frame.
more_out = true;
}
else {
// dgram messages are two part only, reject part if more is set
if (msg_->flags () & msg_t::more) {
errno = EINVAL;
return -1;
}
// This is the last part of the message.
more_out = false;
}
// Push the message into the pipe.
if (!pipe->write (msg_)) {
errno = EAGAIN;
return -1;
}
if (!(msg_->flags () & msg_t::more))
pipe->flush ();
// Detach the message from the data buffer.
int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
int zmq::dgram_t::xrecv (msg_t *msg_)
{
// Deallocate old content of the message.
int rc = msg_->close ();
errno_assert (rc == 0);
if (!pipe || !pipe->read (msg_)) {
// Initialise the output parameter to be a 0-byte message.
rc = msg_->init ();
errno_assert (rc == 0);
errno = EAGAIN;
return -1;
}
last_in = pipe;
return 0;
}
bool zmq::dgram_t::xhas_in ()
{
if (!pipe)
return false;
return pipe->check_read ();
}
bool zmq::dgram_t::xhas_out ()
{
if (!pipe)
return false;
return pipe->check_write ();
}
const zmq::blob_t &zmq::dgram_t::get_credential () const
{
return last_in? last_in->get_credential (): saved_credential;
}
+81
View File
@@ -0,0 +1,81 @@
/*
Copyright (c) 2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DGRAM_HPP_INCLUDED__
#define __ZMQ_DGRAM_HPP_INCLUDED__
#include "blob.hpp"
#include "socket_base.hpp"
#include "session_base.hpp"
namespace zmq
{
class ctx_t;
class msg_t;
class pipe_t;
class io_thread_t;
class dgram_t :
public socket_base_t
{
public:
dgram_t (zmq::ctx_t *parent_, uint32_t tid_, int sid);
~dgram_t ();
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
private:
zmq::pipe_t *pipe;
zmq::pipe_t *last_in;
blob_t saved_credential;
// If true, more outgoing message parts are expected.
bool more_out;
dgram_t (const dgram_t&);
const dgram_t &operator = (const dgram_t&);
};
}
#endif
+360
View File
@@ -0,0 +1,360 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <string.h>
#include "macros.hpp"
#include "dish.hpp"
#include "err.hpp"
zmq::dish_t::dish_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_, true),
has_message (false)
{
options.type = ZMQ_DISH;
// When socket is being closed down we don't want to wait till pending
// subscription commands are sent to the wire.
options.linger = 0;
int rc = message.init ();
errno_assert (rc == 0);
}
zmq::dish_t::~dish_t ()
{
int rc = message.close ();
errno_assert (rc == 0);
}
void zmq::dish_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_);
fq.attach (pipe_);
dist.attach (pipe_);
// Send all the cached subscriptions to the new upstream peer.
send_subscriptions (pipe_);
}
void zmq::dish_t::xread_activated (pipe_t *pipe_)
{
fq.activated (pipe_);
}
void zmq::dish_t::xwrite_activated (pipe_t *pipe_)
{
dist.activated (pipe_);
}
void zmq::dish_t::xpipe_terminated (pipe_t *pipe_)
{
fq.pipe_terminated (pipe_);
dist.pipe_terminated (pipe_);
}
void zmq::dish_t::xhiccuped (pipe_t *pipe_)
{
// Send all the cached subscriptions to the hiccuped pipe.
send_subscriptions (pipe_);
}
int zmq::dish_t::xjoin (const char* group_)
{
std::string group = std::string (group_);
if (group.length () > ZMQ_GROUP_MAX_LENGTH) {
errno = EINVAL;
return -1;
}
subscriptions_t::iterator it = subscriptions.find (group);
// User cannot join same group twice
if (it != subscriptions.end ()) {
errno = EINVAL;
return -1;
}
subscriptions.insert (group);
msg_t msg;
int rc = msg.init_join ();
errno_assert (rc == 0);
rc = msg.set_group (group_);
errno_assert (rc == 0);
int err = 0;
rc = dist.send_to_all (&msg);
if (rc != 0)
err = errno;
int rc2 = msg.close ();
errno_assert (rc2 == 0);
if (rc != 0)
errno = err;
return rc;
}
int zmq::dish_t::xleave (const char* group_)
{
std::string group = std::string (group_);
if (group.length () > ZMQ_GROUP_MAX_LENGTH) {
errno = EINVAL;
return -1;
}
subscriptions_t::iterator it = std::find (subscriptions.begin (), subscriptions.end (), group);
if (it == subscriptions.end ()) {
errno = EINVAL;
return -1;
}
subscriptions.erase (it);
msg_t msg;
int rc = msg.init_leave ();
errno_assert (rc == 0);
rc = msg.set_group (group_);
errno_assert (rc == 0);
int err = 0;
rc = dist.send_to_all (&msg);
if (rc != 0)
err = errno;
int rc2 = msg.close ();
errno_assert (rc2 == 0);
if (rc != 0)
errno = err;
return rc;
}
int zmq::dish_t::xsend (msg_t *msg_)
{
LIBZMQ_UNUSED (msg_);
errno = ENOTSUP;
return -1;
}
bool zmq::dish_t::xhas_out ()
{
// Subscription can be added/removed anytime.
return true;
}
int zmq::dish_t::xrecv (msg_t *msg_)
{
// If there's already a message prepared by a previous call to zmq_poll,
// return it straight ahead.
if (has_message) {
int rc = msg_->move (message);
errno_assert (rc == 0);
has_message = false;
return 0;
}
while (true) {
// Get a message using fair queueing algorithm.
int rc = fq.recv (msg_);
// If there's no message available, return immediately.
// The same when error occurs.
if (rc != 0)
return -1;
// Filtering non matching messages
subscriptions_t::iterator it = subscriptions.find (std::string(msg_->group ()));
if (it != subscriptions.end ())
return 0;
}
}
bool zmq::dish_t::xhas_in ()
{
// If there's already a message prepared by a previous call to zmq_poll,
// return straight ahead.
if (has_message)
return true;
while (true) {
// Get a message using fair queueing algorithm.
int rc = fq.recv (&message);
// If there's no message available, return immediately.
// The same when error occurs.
if (rc != 0) {
errno_assert (errno == EAGAIN);
return false;
}
// Filtering non matching messages
subscriptions_t::iterator it = subscriptions.find (std::string(message.group ()));
if (it != subscriptions.end ()) {
has_message = true;
return true;
}
}
}
const zmq::blob_t &zmq::dish_t::get_credential () const
{
return fq.get_credential ();
}
void zmq::dish_t::send_subscriptions (pipe_t *pipe_)
{
for (subscriptions_t::iterator it = subscriptions.begin (); it != subscriptions.end (); ++it) {
msg_t msg;
int rc = msg.init_join ();
errno_assert (rc == 0);
rc = msg.set_group (it->c_str());
errno_assert (rc == 0);
// Send it to the pipe.
pipe_->write (&msg);
msg.close ();
}
pipe_->flush ();
}
zmq::dish_session_t::dish_session_t (io_thread_t *io_thread_, bool connect_,
socket_base_t *socket_, const options_t &options_,
address_t *addr_) :
session_base_t (io_thread_, connect_, socket_, options_, addr_),
state (group)
{
}
zmq::dish_session_t::~dish_session_t ()
{
}
int zmq::dish_session_t::push_msg (msg_t *msg_)
{
if (state == group) {
if ((msg_->flags() & msg_t::more) != msg_t::more) {
errno = EFAULT;
return -1;
}
if (msg_->size() > ZMQ_GROUP_MAX_LENGTH) {
errno = EFAULT;
return -1;
}
group_msg = *msg_;
state = body;
int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
else {
// Set the message group
int rc = msg_->set_group ((char*)group_msg.data (), group_msg. size());
errno_assert (rc == 0);
// We set the group, so we don't need the group_msg anymore
rc = group_msg.close ();
errno_assert (rc == 0);
// Thread safe socket doesn't support multipart messages
if ((msg_->flags() & msg_t::more) == msg_t::more) {
errno = EFAULT;
return -1;
}
// Push message to dish socket
rc = session_base_t::push_msg (msg_);
if (rc == 0)
state = group;
return rc;
}
}
int zmq::dish_session_t::pull_msg (msg_t *msg_)
{
int rc = session_base_t::pull_msg (msg_);
if (rc != 0)
return rc;
if (!msg_->is_join () && !msg_->is_leave ())
return rc;
else {
int group_length = (int) strlen (msg_->group ());
msg_t command;
int offset;
if (msg_->is_join ()) {
rc = command.init_size (group_length + 5);
errno_assert(rc == 0);
offset = 5;
memcpy (command.data (), "\4JOIN", 5);
}
else {
rc = command.init_size (group_length + 6);
errno_assert(rc == 0);
offset = 6;
memcpy (command.data (), "\5LEAVE", 6);
}
command.set_flags (msg_t::command);
char* command_data = (char*)command.data ();
// Copy the group
memcpy (command_data + offset, msg_->group (), group_length);
// Close the join message
rc = msg_->close ();
errno_assert (rc == 0);
*msg_ = command;
return 0;
}
}
void zmq::dish_session_t::reset ()
{
session_base_t::reset ();
state = group;
}
+125
View File
@@ -0,0 +1,125 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DISH_HPP_INCLUDED__
#define __ZMQ_DISH_HPP_INCLUDED__
#include <string>
#include <vector>
#include "socket_base.hpp"
#include "session_base.hpp"
#include "dist.hpp"
#include "fq.hpp"
#include "trie.hpp"
namespace zmq
{
class ctx_t;
class pipe_t;
class io_thread_t;
class dish_t :
public socket_base_t
{
public:
dish_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);
~dish_t ();
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsend (zmq::msg_t *msg_);
bool xhas_out ();
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xhiccuped (pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
int xjoin (const char *group_);
int xleave (const char *group_);
private:
// Send subscriptions to a pipe
void send_subscriptions (pipe_t *pipe_);
// Fair queueing object for inbound pipes.
fq_t fq;
// Object for distributing the subscriptions upstream.
dist_t dist;
// The repository of subscriptions.
typedef std::set<std::string> subscriptions_t;
subscriptions_t subscriptions;
// If true, 'message' contains a matching message to return on the
// next recv call.
bool has_message;
msg_t message;
dish_t (const dish_t&);
const dish_t &operator = (const dish_t&);
};
class dish_session_t : public session_base_t
{
public:
dish_session_t (zmq::io_thread_t *io_thread_, bool connect_,
zmq::socket_base_t *socket_, const options_t &options_,
address_t *addr_);
~dish_session_t ();
// Overrides of the functions from session_base_t.
int push_msg (msg_t *msg_);
int pull_msg (msg_t *msg_);
void reset ();
private:
enum {
group,
body
} state;
msg_t group_msg;
dish_session_t (const dish_session_t&);
const dish_session_t &operator = (const dish_session_t&);
};
}
#endif
+235
View File
@@ -0,0 +1,235 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "dist.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
#include "likely.hpp"
zmq::dist_t::dist_t () :
matching (0),
active (0),
eligible (0),
more (false)
{
}
zmq::dist_t::~dist_t ()
{
zmq_assert (pipes.empty ());
}
void zmq::dist_t::attach (pipe_t *pipe_)
{
// If we are in the middle of sending a message, we'll add new pipe
// into the list of eligible pipes. Otherwise we add it to the list
// of active pipes.
if (more) {
pipes.push_back (pipe_);
pipes.swap (eligible, pipes.size () - 1);
eligible++;
}
else {
pipes.push_back (pipe_);
pipes.swap (active, pipes.size () - 1);
active++;
eligible++;
}
}
void zmq::dist_t::match (pipe_t *pipe_)
{
// If pipe is already matching do nothing.
if (pipes.index (pipe_) < matching)
return;
// If the pipe isn't eligible, ignore it.
if (pipes.index (pipe_) >= eligible)
return;
// Mark the pipe as matching.
pipes.swap (pipes.index (pipe_), matching);
matching++;
}
void zmq::dist_t::reverse_match ()
{
pipes_t::size_type prev_matching = matching;
// Reset matching to 0
unmatch();
// Mark all matching pipes as not matching and vice-versa.
// To do this, push all pipes that are eligible but not
// matched - i.e. between "matching" and "eligible" -
// to the beginning of the queue.
for (pipes_t::size_type i = prev_matching; i < eligible; ++i) {
pipes.swap(i, matching++);
}
}
void zmq::dist_t::unmatch ()
{
matching = 0;
}
void zmq::dist_t::pipe_terminated (pipe_t *pipe_)
{
// Remove the pipe from the list; adjust number of matching, active and/or
// eligible pipes accordingly.
if (pipes.index (pipe_) < matching) {
pipes.swap (pipes.index (pipe_), matching - 1);
matching--;
}
if (pipes.index (pipe_) < active) {
pipes.swap (pipes.index (pipe_), active - 1);
active--;
}
if (pipes.index (pipe_) < eligible) {
pipes.swap (pipes.index (pipe_), eligible - 1);
eligible--;
}
pipes.erase (pipe_);
}
void zmq::dist_t::activated (pipe_t *pipe_)
{
// Move the pipe from passive to eligible state.
if (eligible < pipes.size ()) {
pipes.swap (pipes.index (pipe_), eligible);
eligible++;
}
// If there's no message being sent at the moment, move it to
// the active state.
if (!more && active < pipes.size ()) {
pipes.swap (eligible - 1, active);
active++;
}
}
int zmq::dist_t::send_to_all (msg_t *msg_)
{
matching = active;
return send_to_matching (msg_);
}
int zmq::dist_t::send_to_matching (msg_t *msg_)
{
// Is this end of a multipart message?
bool msg_more = msg_->flags () & msg_t::more ? true : false;
// Push the message to matching pipes.
distribute (msg_);
// If multipart message is fully sent, activate all the eligible pipes.
if (!msg_more)
active = eligible;
more = msg_more;
return 0;
}
void zmq::dist_t::distribute (msg_t *msg_)
{
// If there are no matching pipes available, simply drop the message.
if (matching == 0) {
int rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
return;
}
if (msg_->is_vsm ()) {
for (pipes_t::size_type i = 0; i < matching; ++i)
if(!write (pipes [i], msg_))
--i; // Retry last write because index will have been swapped
int rc = msg_->close();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
return;
}
// Add matching-1 references to the message. We already hold one reference,
// that's why -1.
msg_->add_refs ((int) matching - 1);
// Push copy of the message to each matching pipe.
int failed = 0;
for (pipes_t::size_type i = 0; i < matching; ++i)
if (!write (pipes [i], msg_)) {
++failed;
--i; // Retry last write because index will have been swapped
}
if (unlikely (failed))
msg_->rm_refs (failed);
// Detach the original message from the data buffer. Note that we don't
// close the message. That's because we've already used all the references.
int rc = msg_->init ();
errno_assert (rc == 0);
}
bool zmq::dist_t::has_out ()
{
return true;
}
bool zmq::dist_t::write (pipe_t *pipe_, msg_t *msg_)
{
if (!pipe_->write (msg_)) {
pipes.swap (pipes.index (pipe_), matching - 1);
matching--;
pipes.swap (pipes.index (pipe_), active - 1);
active--;
pipes.swap (active, eligible - 1);
eligible--;
return false;
}
if (!(msg_->flags () & msg_t::more))
pipe_->flush ();
return true;
}
bool zmq::dist_t::check_hwm ()
{
for (pipes_t::size_type i = 0; i < matching; ++i)
if (!pipes [i]->check_hwm ())
return false;
return true;
}
+120
View File
@@ -0,0 +1,120 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DIST_HPP_INCLUDED__
#define __ZMQ_DIST_HPP_INCLUDED__
#include <vector>
#include "array.hpp"
#include "pipe.hpp"
namespace zmq
{
class pipe_t;
class msg_t;
// Class manages a set of outbound pipes. It sends each messages to
// each of them.
class dist_t
{
public:
dist_t ();
~dist_t ();
// Adds the pipe to the distributor object.
void attach (zmq::pipe_t *pipe_);
// Activates pipe that have previously reached high watermark.
void activated (zmq::pipe_t *pipe_);
// Mark the pipe as matching. Subsequent call to send_to_matching
// will send message also to this pipe.
void match (zmq::pipe_t *pipe_);
// Marks all pipes that are not matched as matched and vice-versa.
void reverse_match();
// Mark all pipes as non-matching.
void unmatch ();
// Removes the pipe from the distributor object.
void pipe_terminated (zmq::pipe_t *pipe_);
// Send the message to the matching outbound pipes.
int send_to_matching (zmq::msg_t *msg_);
// Send the message to all the outbound pipes.
int send_to_all (zmq::msg_t *msg_);
bool has_out ();
// check HWM of all pipes matching
bool check_hwm ();
private:
// Write the message to the pipe. Make the pipe inactive if writing
// fails. In such a case false is returned.
bool write (zmq::pipe_t *pipe_, zmq::msg_t *msg_);
// Put the message to all active pipes.
void distribute (zmq::msg_t *msg_);
// List of outbound pipes.
typedef array_t <zmq::pipe_t, 2> pipes_t;
pipes_t pipes;
// Number of all the pipes to send the next message to.
pipes_t::size_type matching;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array. These are the pipes the messages
// can be sent to at the moment.
pipes_t::size_type active;
// Number of pipes eligible for sending messages to. This includes all
// the active pipes plus all the pipes that we can in theory send
// messages to (the HWM is not yet reached), but sending a message
// to them would result in partial message being delivered, ie. message
// with initial parts missing.
pipes_t::size_type eligible;
// True if last we are in the middle of a multipart message.
bool more;
dist_t (const dist_t&);
const dist_t &operator = (const dist_t&);
};
}
#endif
+189
View File
@@ -0,0 +1,189 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ENCODER_HPP_INCLUDED__
#define __ZMQ_ENCODER_HPP_INCLUDED__
#if defined(_MSC_VER)
#ifndef NOMINMAX
#define NOMINMAX
#endif
#endif
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
#include "err.hpp"
#include "msg.hpp"
#include "i_encoder.hpp"
namespace zmq
{
// Helper base class for encoders. It implements the state machine that
// fills the outgoing buffer. Derived classes should implement individual
// state machine actions.
template <typename T> class encoder_base_t : public i_encoder
{
public:
inline encoder_base_t (size_t bufsize_) :
write_pos(0),
to_write(0),
next(NULL),
new_msg_flag(false),
bufsize (bufsize_),
in_progress (NULL)
{
buf = (unsigned char*) malloc (bufsize_);
alloc_assert (buf);
}
// The destructor doesn't have to be virtual. It is made virtual
// just to keep ICC and code checking tools from complaining.
inline virtual ~encoder_base_t ()
{
free (buf);
}
// The function returns a batch of binary data. The data
// are filled to a supplied buffer. If no buffer is supplied (data_
// points to NULL) decoder object will provide buffer of its own.
inline size_t encode (unsigned char **data_, size_t size_)
{
unsigned char *buffer = !*data_ ? buf : *data_;
size_t buffersize = !*data_ ? bufsize : size_;
if (in_progress == NULL)
return 0;
size_t pos = 0;
while (pos < buffersize) {
// If there are no more data to return, run the state machine.
// If there are still no data, return what we already have
// in the buffer.
if (!to_write) {
if (new_msg_flag) {
int rc = in_progress->close ();
errno_assert (rc == 0);
rc = in_progress->init ();
errno_assert (rc == 0);
in_progress = NULL;
break;
}
(static_cast <T*> (this)->*next) ();
}
// If there are no data in the buffer yet and we are able to
// fill whole buffer in a single go, let's use zero-copy.
// There's no disadvantage to it as we cannot stuck multiple
// messages into the buffer anyway. Note that subsequent
// write(s) are non-blocking, thus each single write writes
// at most SO_SNDBUF bytes at once not depending on how large
// is the chunk returned from here.
// As a consequence, large messages being sent won't block
// other engines running in the same I/O thread for excessive
// amounts of time.
if (!pos && !*data_ && to_write >= buffersize) {
*data_ = write_pos;
pos = to_write;
write_pos = NULL;
to_write = 0;
return pos;
}
// Copy data to the buffer. If the buffer is full, return.
size_t to_copy = std::min (to_write, buffersize - pos);
memcpy (buffer + pos, write_pos, to_copy);
pos += to_copy;
write_pos += to_copy;
to_write -= to_copy;
}
*data_ = buffer;
return pos;
}
void load_msg (msg_t *msg_)
{
zmq_assert (in_progress == NULL);
in_progress = msg_;
(static_cast <T*> (this)->*next) ();
}
protected:
// Prototype of state machine action.
typedef void (T::*step_t) ();
// This function should be called from derived class to write the data
// to the buffer and schedule next state machine action.
inline void next_step (void *write_pos_, size_t to_write_,
step_t next_, bool new_msg_flag_)
{
write_pos = (unsigned char*) write_pos_;
to_write = to_write_;
next = next_;
new_msg_flag = new_msg_flag_;
}
private:
// Where to get the data to write from.
unsigned char *write_pos;
// How much data to write before next step should be executed.
size_t to_write;
// Next step. If set to NULL, it means that associated data stream
// is dead.
step_t next;
bool new_msg_flag;
// The buffer for encoded data.
size_t bufsize;
unsigned char *buf;
encoder_base_t (const encoder_base_t&);
void operator = (const encoder_base_t&);
protected:
msg_t *in_progress;
};
}
#endif
+447
View File
@@ -0,0 +1,447 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "err.hpp"
const char *zmq::errno_to_string (int errno_)
{
switch (errno_) {
#if defined ZMQ_HAVE_WINDOWS
case ENOTSUP:
return "Not supported";
case EPROTONOSUPPORT:
return "Protocol not supported";
case ENOBUFS:
return "No buffer space available";
case ENETDOWN:
return "Network is down";
case EADDRINUSE:
return "Address in use";
case EADDRNOTAVAIL:
return "Address not available";
case ECONNREFUSED:
return "Connection refused";
case EINPROGRESS:
return "Operation in progress";
#endif
case EFSM:
return "Operation cannot be accomplished in current state";
case ENOCOMPATPROTO:
return "The protocol is not compatible with the socket type";
case ETERM:
return "Context was terminated";
case EMTHREAD:
return "No thread available";
case EHOSTUNREACH:
return "Host unreachable";
default:
#if defined _MSC_VER
#pragma warning (push)
#pragma warning (disable:4996)
#endif
return strerror (errno_);
#if defined _MSC_VER
#pragma warning (pop)
#endif
}
}
void zmq::zmq_abort(const char *errmsg_)
{
#if defined ZMQ_HAVE_WINDOWS
// Raise STATUS_FATAL_APP_EXIT.
ULONG_PTR extra_info [1];
extra_info [0] = (ULONG_PTR) errmsg_;
RaiseException (0x40000015, EXCEPTION_NONCONTINUABLE, 1, extra_info);
#else
(void)errmsg_;
print_backtrace();
abort ();
#endif
}
#ifdef ZMQ_HAVE_WINDOWS
const char *zmq::wsa_error()
{
return wsa_error_no (WSAGetLastError(), NULL);
}
const char *zmq::wsa_error_no (int no_, const char * wsae_wouldblock_string)
{
// TODO: It seems that list of Windows socket errors is longer than this.
// Investigate whether there's a way to convert it into the string
// automatically (wsaError->HRESULT->string?).
return
(no_ == WSABASEERR) ?
"No Error" :
(no_ == WSAEINTR) ?
"Interrupted system call" :
(no_ == WSAEBADF) ?
"Bad file number" :
(no_ == WSAEACCES) ?
"Permission denied" :
(no_ == WSAEFAULT) ?
"Bad address" :
(no_ == WSAEINVAL) ?
"Invalid argument" :
(no_ == WSAEMFILE) ?
"Too many open files" :
(no_ == WSAEWOULDBLOCK) ?
wsae_wouldblock_string :
(no_ == WSAEINPROGRESS) ?
"Operation now in progress" :
(no_ == WSAEALREADY) ?
"Operation already in progress" :
(no_ == WSAENOTSOCK) ?
"Socket operation on non-socket" :
(no_ == WSAEDESTADDRREQ) ?
"Destination address required" :
(no_ == WSAEMSGSIZE) ?
"Message too long" :
(no_ == WSAEPROTOTYPE) ?
"Protocol wrong type for socket" :
(no_ == WSAENOPROTOOPT) ?
"Bad protocol option" :
(no_ == WSAEPROTONOSUPPORT) ?
"Protocol not supported" :
(no_ == WSAESOCKTNOSUPPORT) ?
"Socket type not supported" :
(no_ == WSAEOPNOTSUPP) ?
"Operation not supported on socket" :
(no_ == WSAEPFNOSUPPORT) ?
"Protocol family not supported" :
(no_ == WSAEAFNOSUPPORT) ?
"Address family not supported by protocol family" :
(no_ == WSAEADDRINUSE) ?
"Address already in use" :
(no_ == WSAEADDRNOTAVAIL) ?
"Can't assign requested address" :
(no_ == WSAENETDOWN) ?
"Network is down" :
(no_ == WSAENETUNREACH) ?
"Network is unreachable" :
(no_ == WSAENETRESET) ?
"Net dropped connection or reset" :
(no_ == WSAECONNABORTED) ?
"Software caused connection abort" :
(no_ == WSAECONNRESET) ?
"Connection reset by peer" :
(no_ == WSAENOBUFS) ?
"No buffer space available" :
(no_ == WSAEISCONN) ?
"Socket is already connected" :
(no_ == WSAENOTCONN) ?
"Socket is not connected" :
(no_ == WSAESHUTDOWN) ?
"Can't send after socket shutdown" :
(no_ == WSAETOOMANYREFS) ?
"Too many references can't splice" :
(no_ == WSAETIMEDOUT) ?
"Connection timed out" :
(no_ == WSAECONNREFUSED) ?
"Connection refused" :
(no_ == WSAELOOP) ?
"Too many levels of symbolic links" :
(no_ == WSAENAMETOOLONG) ?
"File name too long" :
(no_ == WSAEHOSTDOWN) ?
"Host is down" :
(no_ == WSAEHOSTUNREACH) ?
"No Route to Host" :
(no_ == WSAENOTEMPTY) ?
"Directory not empty" :
(no_ == WSAEPROCLIM) ?
"Too many processes" :
(no_ == WSAEUSERS) ?
"Too many users" :
(no_ == WSAEDQUOT) ?
"Disc Quota Exceeded" :
(no_ == WSAESTALE) ?
"Stale NFS file handle" :
(no_ == WSAEREMOTE) ?
"Too many levels of remote in path" :
(no_ == WSASYSNOTREADY) ?
"Network SubSystem is unavailable" :
(no_ == WSAVERNOTSUPPORTED) ?
"WINSOCK DLL Version out of range" :
(no_ == WSANOTINITIALISED) ?
"Successful WSASTARTUP not yet performed" :
(no_ == WSAHOST_NOT_FOUND) ?
"Host not found" :
(no_ == WSATRY_AGAIN) ?
"Non-Authoritative Host not found" :
(no_ == WSANO_RECOVERY) ?
"Non-Recoverable errors: FORMERR REFUSED NOTIMP" :
(no_ == WSANO_DATA) ?
"Valid name no data record of requested" :
"error not defined";
}
void zmq::win_error (char *buffer_, size_t buffer_size_)
{
DWORD errcode = GetLastError ();
#if defined _WIN32_WCE
DWORD rc = FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode, MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT), (LPWSTR)buffer_, buffer_size_ / sizeof(wchar_t), NULL);
#else
DWORD rc = FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode, MAKELANGID(LANG_NEUTRAL,
SUBLANG_DEFAULT), buffer_, (DWORD) buffer_size_, NULL);
#endif
zmq_assert (rc);
}
int zmq::wsa_error_to_errno (int errcode)
{
switch (errcode) {
// 10004 - Interrupted system call.
case WSAEINTR:
return EINTR;
// 10009 - File handle is not valid.
case WSAEBADF:
return EBADF;
// 10013 - Permission denied.
case WSAEACCES:
return EACCES;
// 10014 - Bad address.
case WSAEFAULT:
return EFAULT;
// 10022 - Invalid argument.
case WSAEINVAL:
return EINVAL;
// 10024 - Too many open files.
case WSAEMFILE:
return EMFILE;
// 10035 - Operation would block.
case WSAEWOULDBLOCK:
return EBUSY;
// 10036 - Operation now in progress.
case WSAEINPROGRESS:
return EAGAIN;
// 10037 - Operation already in progress.
case WSAEALREADY:
return EAGAIN;
// 10038 - Socket operation on non-socket.
case WSAENOTSOCK:
return ENOTSOCK;
// 10039 - Destination address required.
case WSAEDESTADDRREQ:
return EFAULT;
// 10040 - Message too long.
case WSAEMSGSIZE:
return EMSGSIZE;
// 10041 - Protocol wrong type for socket.
case WSAEPROTOTYPE:
return EFAULT;
// 10042 - Bad protocol option.
case WSAENOPROTOOPT:
return EINVAL;
// 10043 - Protocol not supported.
case WSAEPROTONOSUPPORT:
return EPROTONOSUPPORT;
// 10044 - Socket type not supported.
case WSAESOCKTNOSUPPORT:
return EFAULT;
// 10045 - Operation not supported on socket.
case WSAEOPNOTSUPP:
return EFAULT;
// 10046 - Protocol family not supported.
case WSAEPFNOSUPPORT:
return EPROTONOSUPPORT;
// 10047 - Address family not supported by protocol family.
case WSAEAFNOSUPPORT:
return EAFNOSUPPORT;
// 10048 - Address already in use.
case WSAEADDRINUSE:
return EADDRINUSE;
// 10049 - Cannot assign requested address.
case WSAEADDRNOTAVAIL:
return EADDRNOTAVAIL;
// 10050 - Network is down.
case WSAENETDOWN:
return ENETDOWN;
// 10051 - Network is unreachable.
case WSAENETUNREACH:
return ENETUNREACH;
// 10052 - Network dropped connection on reset.
case WSAENETRESET:
return ENETRESET;
// 10053 - Software caused connection abort.
case WSAECONNABORTED:
return ECONNABORTED;
// 10054 - Connection reset by peer.
case WSAECONNRESET:
return ECONNRESET;
// 10055 - No buffer space available.
case WSAENOBUFS:
return ENOBUFS;
// 10056 - Socket is already connected.
case WSAEISCONN:
return EFAULT;
// 10057 - Socket is not connected.
case WSAENOTCONN:
return ENOTCONN;
// 10058 - Can't send after socket shutdown.
case WSAESHUTDOWN:
return EFAULT;
// 10059 - Too many references can't splice.
case WSAETOOMANYREFS:
return EFAULT;
// 10060 - Connection timed out.
case WSAETIMEDOUT:
return ETIMEDOUT;
// 10061 - Connection refused.
case WSAECONNREFUSED:
return ECONNREFUSED;
// 10062 - Too many levels of symbolic links.
case WSAELOOP:
return EFAULT;
// 10063 - File name too long.
case WSAENAMETOOLONG:
return EFAULT;
// 10064 - Host is down.
case WSAEHOSTDOWN:
return EAGAIN;
// 10065 - No route to host.
case WSAEHOSTUNREACH:
return EHOSTUNREACH;
// 10066 - Directory not empty.
case WSAENOTEMPTY:
return EFAULT;
// 10067 - Too many processes.
case WSAEPROCLIM:
return EFAULT;
// 10068 - Too many users.
case WSAEUSERS:
return EFAULT;
// 10069 - Disc Quota Exceeded.
case WSAEDQUOT:
return EFAULT;
// 10070 - Stale NFS file handle.
case WSAESTALE:
return EFAULT;
// 10071 - Too many levels of remote in path.
case WSAEREMOTE:
return EFAULT;
// 10091 - Network SubSystem is unavailable.
case WSASYSNOTREADY:
return EFAULT;
// 10092 - WINSOCK DLL Version out of range.
case WSAVERNOTSUPPORTED:
return EFAULT;
// 10093 - Successful WSASTARTUP not yet performed.
case WSANOTINITIALISED:
return EFAULT;
// 11001 - Host not found.
case WSAHOST_NOT_FOUND:
return EFAULT;
// 11002 - Non-Authoritative Host not found.
case WSATRY_AGAIN:
return EFAULT;
// 11003 - Non-Recoverable errors: FORMERR REFUSED NOTIMP.
case WSANO_RECOVERY:
return EFAULT;
// 11004 - Valid name no data record of requested.
case WSANO_DATA:
return EFAULT;
default:
wsa_assert (false);
}
// Not reachable
return 0;
}
#endif
#ifdef HAVE_LIBUNWIND
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#include <dlfcn.h>
#include <cxxabi.h>
#include "mutex.hpp"
void zmq::print_backtrace (void)
{
static zmq::mutex_t mtx;
mtx.lock ();
Dl_info dl_info;
unw_cursor_t cursor;
unw_context_t ctx;
unsigned frame_n = 0;
unw_getcontext (&ctx);
unw_init_local (&cursor, &ctx);
while (unw_step (&cursor) > 0) {
unw_word_t offset;
unw_proc_info_t p_info;
const char *file_name;
char *demangled_name;
char func_name[256] = "";
void *addr;
int rc;
if (unw_get_proc_info (&cursor, &p_info))
break;
rc = unw_get_proc_name (&cursor, func_name, 256, &offset);
if (rc == -UNW_ENOINFO)
strcpy(func_name, "?");
addr = (void *)(p_info.start_ip + offset);
if (dladdr (addr, &dl_info) && dl_info.dli_fname)
file_name = dl_info.dli_fname;
else
file_name = "?";
demangled_name = abi::__cxa_demangle (func_name, NULL, NULL, &rc);
printf ("#%u %p in %s (%s+0x%lx)\n", frame_n++, addr, file_name,
rc ? func_name : demangled_name, (unsigned long) offset);
free (demangled_name);
}
puts ("");
fflush (stdout);
mtx.unlock ();
}
#else
void zmq::print_backtrace (void)
{
}
#endif
+173
View File
@@ -0,0 +1,173 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ERR_HPP_INCLUDED__
#define __ZMQ_ERR_HPP_INCLUDED__
#include <assert.h>
#if defined _WIN32_WCE
#include "..\builds\msvc\errno.hpp"
#else
#include <errno.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef ZMQ_HAVE_WINDOWS
#include <netdb.h>
#endif
#include "likely.hpp"
// 0MQ-specific error codes are defined in zmq.h
// EPROTO is not used by OpenBSD and maybe other platforms.
#ifndef EPROTO
#define EPROTO 0
#endif
namespace zmq
{
const char *errno_to_string (int errno_);
void zmq_abort (const char *errmsg_);
void print_backtrace (void);
}
#ifdef ZMQ_HAVE_WINDOWS
namespace zmq
{
const char *wsa_error ();
const char *wsa_error_no (int no_, const char * wsae_wouldblock_string = "Operation would block");
void win_error (char *buffer_, size_t buffer_size_);
int wsa_error_to_errno (int errcode);
}
// Provides convenient way to check WSA-style errors on Windows.
#define wsa_assert(x) \
do {\
if (unlikely (!(x))) {\
const char *errstr = zmq::wsa_error ();\
if (errstr != NULL) {\
fprintf (stderr, "Assertion failed: %s (%s:%d)\n", errstr, \
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
}\
} while (false)
// Provides convenient way to assert on WSA-style errors on Windows.
#define wsa_assert_no(no) \
do {\
const char *errstr = zmq::wsa_error_no (no);\
if (errstr != NULL) {\
fprintf (stderr, "Assertion failed: %s (%s:%d)\n", errstr, \
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
// Provides convenient way to check GetLastError-style errors on Windows.
#define win_assert(x) \
do {\
if (unlikely (!(x))) {\
char errstr [256];\
zmq::win_error (errstr, 256);\
fprintf (stderr, "Assertion failed: %s (%s:%d)\n", errstr, \
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
#endif
// This macro works in exactly the same way as the normal assert. It is used
// in its stead because standard assert on Win32 in broken - it prints nothing
// when used within the scope of JNI library.
#define zmq_assert(x) \
do {\
if (unlikely (!(x))) {\
fprintf (stderr, "Assertion failed: %s (%s:%d)\n", #x, \
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (#x);\
}\
} while (false)
// Provides convenient way to check for errno-style errors.
#define errno_assert(x) \
do {\
if (unlikely (!(x))) {\
const char *errstr = strerror (errno);\
fprintf (stderr, "%s (%s:%d)\n", errstr, __FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
// Provides convenient way to check for POSIX errors.
#define posix_assert(x) \
do {\
if (unlikely (x)) {\
const char *errstr = strerror (x);\
fprintf (stderr, "%s (%s:%d)\n", errstr, __FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
// Provides convenient way to check for errors from getaddrinfo.
#define gai_assert(x) \
do {\
if (unlikely (x)) {\
const char *errstr = gai_strerror (x);\
fprintf (stderr, "%s (%s:%d)\n", errstr, __FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort (errstr);\
}\
} while (false)
// Provides convenient way to check whether memory allocation have succeeded.
#define alloc_assert(x) \
do {\
if (unlikely (!x)) {\
fprintf (stderr, "FATAL ERROR: OUT OF MEMORY (%s:%d)\n",\
__FILE__, __LINE__);\
fflush (stderr);\
zmq::zmq_abort ("FATAL ERROR: OUT OF MEMORY");\
}\
} while (false)
#endif
+52
View File
@@ -0,0 +1,52 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_FD_HPP_INCLUDED__
#define __ZMQ_FD_HPP_INCLUDED__
#if defined _WIN32
#include "windows.hpp"
#endif
namespace zmq
{
#ifdef ZMQ_HAVE_WINDOWS
#if defined _MSC_VER &&_MSC_VER <= 1400
typedef UINT_PTR fd_t;
enum {retired_fd = (fd_t)(~0)};
#else
typedef SOCKET fd_t;
enum {retired_fd = (fd_t)INVALID_SOCKET};
#endif
#else
typedef int fd_t;
enum {retired_fd = -1};
#endif
}
#endif
+163
View File
@@ -0,0 +1,163 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "fq.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
zmq::fq_t::fq_t () :
active (0),
last_in (NULL),
current (0),
more (false)
{
}
zmq::fq_t::~fq_t ()
{
zmq_assert (pipes.empty ());
}
void zmq::fq_t::attach (pipe_t *pipe_)
{
pipes.push_back (pipe_);
pipes.swap (active, pipes.size () - 1);
active++;
}
void zmq::fq_t::pipe_terminated (pipe_t *pipe_)
{
const pipes_t::size_type index = pipes.index (pipe_);
// Remove the pipe from the list; adjust number of active pipes
// accordingly.
if (index < active) {
active--;
pipes.swap (index, active);
if (current == active)
current = 0;
}
pipes.erase (pipe_);
if (last_in == pipe_) {
saved_credential.set_deep_copy (last_in->get_credential ());
last_in = NULL;
}
}
void zmq::fq_t::activated (pipe_t *pipe_)
{
// Move the pipe to the list of active pipes.
pipes.swap (pipes.index (pipe_), active);
active++;
}
int zmq::fq_t::recv (msg_t *msg_)
{
return recvpipe (msg_, NULL);
}
int zmq::fq_t::recvpipe (msg_t *msg_, pipe_t **pipe_)
{
// Deallocate old content of the message.
int rc = msg_->close ();
errno_assert (rc == 0);
// Round-robin over the pipes to get the next message.
while (active > 0) {
// Try to fetch new message. If we've already read part of the message
// subsequent part should be immediately available.
bool fetched = pipes [current]->read (msg_);
// Note that when message is not fetched, current pipe is deactivated
// and replaced by another active pipe. Thus we don't have to increase
// the 'current' pointer.
if (fetched) {
if (pipe_)
*pipe_ = pipes [current];
more = msg_->flags () & msg_t::more? true: false;
if (!more) {
last_in = pipes [current];
current = (current + 1) % active;
}
return 0;
}
// Check the atomicity of the message.
// If we've already received the first part of the message
// we should get the remaining parts without blocking.
zmq_assert (!more);
active--;
pipes.swap (current, active);
if (current == active)
current = 0;
}
// No message is available. Initialise the output parameter
// to be a 0-byte message.
rc = msg_->init ();
errno_assert (rc == 0);
errno = EAGAIN;
return -1;
}
bool zmq::fq_t::has_in ()
{
// There are subsequent parts of the partly-read message available.
if (more)
return true;
// Note that messing with current doesn't break the fairness of fair
// queueing algorithm. If there are no messages available current will
// get back to its original value. Otherwise it'll point to the first
// pipe holding messages, skipping only pipes with no messages available.
while (active > 0) {
if (pipes [current]->check_read ())
return true;
// Deactivate the pipe.
active--;
pipes.swap (current, active);
if (current == active)
current = 0;
}
return false;
}
const zmq::blob_t &zmq::fq_t::get_credential () const
{
return last_in?
last_in->get_credential (): saved_credential;
}
+92
View File
@@ -0,0 +1,92 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_FQ_HPP_INCLUDED__
#define __ZMQ_FQ_HPP_INCLUDED__
#include "array.hpp"
#include "blob.hpp"
#include "pipe.hpp"
#include "msg.hpp"
namespace zmq
{
// Class manages a set of inbound pipes. On receive it performs fair
// queueing so that senders gone berserk won't cause denial of
// service for decent senders.
class fq_t
{
public:
fq_t ();
~fq_t ();
void attach (pipe_t *pipe_);
void activated (pipe_t *pipe_);
void pipe_terminated (pipe_t *pipe_);
int recv (msg_t *msg_);
int recvpipe (msg_t *msg_, pipe_t **pipe_);
bool has_in ();
const blob_t &get_credential () const;
private:
// Inbound pipes.
typedef array_t <pipe_t, 1> pipes_t;
pipes_t pipes;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array.
pipes_t::size_type active;
// Pointer to the last pipe we received message from.
// NULL when no message has been received or the pipe
// has terminated.
pipe_t *last_in;
// Index of the next bound pipe to read a message from.
pipes_t::size_type current;
// If true, part of a multipart message was already received, but
// there are following parts still waiting in the current pipe.
bool more;
// Holds credential after the last_active_pipe has terminated.
blob_t saved_credential;
fq_t (const fq_t&);
const fq_t &operator = (const fq_t&);
};
}
#endif
+94
View File
@@ -0,0 +1,94 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "gather.hpp"
#include "err.hpp"
#include "msg.hpp"
#include "pipe.hpp"
zmq::gather_t::gather_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_, true)
{
options.type = ZMQ_GATHER;
}
zmq::gather_t::~gather_t ()
{
}
void zmq::gather_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_);
fq.attach (pipe_);
}
void zmq::gather_t::xread_activated (pipe_t *pipe_)
{
fq.activated (pipe_);
}
void zmq::gather_t::xpipe_terminated (pipe_t *pipe_)
{
fq.pipe_terminated (pipe_);
}
int zmq::gather_t::xrecv (msg_t *msg_)
{
int rc = fq.recvpipe (msg_, NULL);
// Drop any messages with more flag
while (rc == 0 && msg_->flags () & msg_t::more) {
// drop all frames of the current multi-frame message
rc = fq.recvpipe (msg_, NULL);
while (rc == 0 && msg_->flags () & msg_t::more)
rc = fq.recvpipe (msg_, NULL);
// get the new message
if (rc == 0)
rc = fq.recvpipe (msg_, NULL);
}
return rc;
}
bool zmq::gather_t::xhas_in ()
{
return fq.has_in ();
}
const zmq::blob_t &zmq::gather_t::get_credential () const
{
return fq.get_credential ();
}
+75
View File
@@ -0,0 +1,75 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_GATHER_HPP_INCLUDED__
#define __ZMQ_GATHER_HPP_INCLUDED__
#include "socket_base.hpp"
#include "session_base.hpp"
#include "fq.hpp"
namespace zmq
{
class ctx_t;
class pipe_t;
class msg_t;
class io_thread_t;
class gather_t :
public socket_base_t
{
public:
gather_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);
~gather_t ();
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
private:
// Fair queueing object for inbound pipes.
fq_t fq;
gather_t (const gather_t&);
const gather_t &operator = (const gather_t&);
};
}
#endif
+94
View File
@@ -0,0 +1,94 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_GSSAPI_CLIENT_HPP_INCLUDED__
#define __ZMQ_GSSAPI_CLIENT_HPP_INCLUDED__
#ifdef HAVE_LIBGSSAPI_KRB5
#include "gssapi_mechanism_base.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
class gssapi_client_t : public gssapi_mechanism_base_t
{
public:
gssapi_client_t (session_base_t *session_, const options_t &options_);
virtual ~gssapi_client_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int encode (msg_t *msg_);
virtual int decode (msg_t *msg_);
virtual status_t status () const;
private:
enum state_t {
call_next_init,
send_next_token,
recv_next_token,
send_ready,
recv_ready,
connected
};
// Human-readable principal name of the service we are connecting to
char * service_name;
gss_OID service_name_type;
// Current FSM state
state_t state;
// Points to either send_tok or recv_tok
// during context initialization
gss_buffer_desc *token_ptr;
// The desired underlying mechanism
gss_OID_set_desc mechs;
// True iff client considers the server authenticated
bool security_context_established;
int initialize_context ();
int produce_next_token (msg_t *msg_);
int process_next_token (msg_t *msg_);
};
}
#endif
#endif
+95
View File
@@ -0,0 +1,95 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_GSSAPI_SERVER_HPP_INCLUDED__
#define __ZMQ_GSSAPI_SERVER_HPP_INCLUDED__
#ifdef HAVE_LIBGSSAPI_KRB5
#include "gssapi_mechanism_base.hpp"
#include "zap_client.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
class gssapi_server_t
: public gssapi_mechanism_base_t, public zap_client_t
{
public:
gssapi_server_t (session_base_t *session_,
const std::string &peer_address,
const options_t &options_);
virtual ~gssapi_server_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int encode (msg_t *msg_);
virtual int decode (msg_t *msg_);
virtual int zap_msg_available ();
virtual status_t status () const;
private:
enum state_t {
send_next_token,
recv_next_token,
expect_zap_reply,
send_ready,
recv_ready,
connected
};
session_base_t * const session;
const std::string peer_address;
// Current FSM state
state_t state;
// True iff server considers the client authenticated
bool security_context_established;
// The underlying mechanism type (ignored)
gss_OID doid;
void accept_context ();
int produce_next_token (msg_t *msg_);
int process_next_token (msg_t *msg_);
void send_zap_request ();
};
}
#endif
#endif
+64
View File
@@ -0,0 +1,64 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_DECODER_HPP_INCLUDED__
#define __ZMQ_I_DECODER_HPP_INCLUDED__
#include "stdint.hpp"
namespace zmq
{
class msg_t;
// Interface to be implemented by message decoder.
class i_decoder
{
public:
virtual ~i_decoder () {}
virtual void get_buffer (unsigned char **data_, size_t *size_) = 0;
virtual void resize_buffer(size_t) = 0;
// Decodes data pointed to by data_.
// When a message is decoded, 1 is returned.
// When the decoder needs more data, 0 is returned.
// On error, -1 is returned and errno is set accordingly.
virtual int decode (const unsigned char *data_, size_t size_,
size_t &processed) = 0;
virtual msg_t *msg () = 0;
};
}
#endif
+60
View File
@@ -0,0 +1,60 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_ENCODER_HPP_INCLUDED__
#define __ZMQ_I_ENCODER_HPP_INCLUDED__
#include "stdint.hpp"
namespace zmq
{
// Forward declaration
class msg_t;
// Interface to be implemented by message encoder.
struct i_encoder
{
virtual ~i_encoder () {}
// The function returns a batch of binary data. The data
// are filled to a supplied buffer. If no buffer is supplied (data_
// is NULL) encoder will provide buffer of its own.
// Function returns 0 when a new message is required.
virtual size_t encode (unsigned char **data_, size_t size) = 0;
// Load a new message into encoder.
virtual void load_msg (msg_t *msg_) = 0;
};
}
#endif
+68
View File
@@ -0,0 +1,68 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_ENGINE_HPP_INCLUDED__
#define __ZMQ_I_ENGINE_HPP_INCLUDED__
namespace zmq
{
class io_thread_t;
// Abstract interface to be implemented by various engines.
struct i_engine
{
virtual ~i_engine () {}
// Plug the engine to the session.
virtual void plug (zmq::io_thread_t *io_thread_,
class session_base_t *session_) = 0;
// Terminate and deallocate the engine. Note that 'detached'
// events are not fired on termination.
virtual void terminate () = 0;
// This method is called by the session to signalise that more
// messages can be written to the pipe.
virtual void restart_input () = 0;
// This method is called by the session to signalise that there
// are messages to send available.
virtual void restart_output () = 0;
virtual void zap_msg_available () = 0;
virtual const char * get_endpoint() const = 0;
};
}
#endif
+60
View File
@@ -0,0 +1,60 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_MAILBOX_HPP_INCLUDED__
#define __ZMQ_I_MAILBOX_HPP_INCLUDED__
#include "stdint.hpp"
namespace zmq
{
// Interface to be implemented by mailbox.
class i_mailbox
{
public:
virtual ~i_mailbox () {}
virtual void send (const command_t &cmd_) = 0;
virtual int recv (command_t *cmd_, int timeout_) = 0;
#ifdef HAVE_FORK
// close the file descriptors in the signaller. This is used in a forked
// child process to close the file descriptors so that they do not interfere
// with the context in the parent process.
virtual void forked () = 0;
#endif
};
}
#endif
+55
View File
@@ -0,0 +1,55 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__
#define __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__
namespace zmq
{
// Virtual interface to be exposed by object that want to be notified
// about events on file descriptors.
struct i_poll_events
{
virtual ~i_poll_events () {}
// Called by I/O thread when file descriptor is ready for reading.
virtual void in_event () = 0;
// Called by I/O thread when file descriptor is ready for writing.
virtual void out_event () = 0;
// Called when timer expires.
virtual void timer_event (int id_) = 0;
};
}
#endif
+117
View File
@@ -0,0 +1,117 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "io_object.hpp"
#include "io_thread.hpp"
#include "err.hpp"
zmq::io_object_t::io_object_t (io_thread_t *io_thread_) :
poller (NULL)
{
if (io_thread_)
plug (io_thread_);
}
zmq::io_object_t::~io_object_t ()
{
}
void zmq::io_object_t::plug (io_thread_t *io_thread_)
{
zmq_assert (io_thread_);
zmq_assert (!poller);
// Retrieve the poller from the thread we are running in.
poller = io_thread_->get_poller ();
}
void zmq::io_object_t::unplug ()
{
zmq_assert (poller);
// Forget about old poller in preparation to be migrated
// to a different I/O thread.
poller = NULL;
}
zmq::io_object_t::handle_t zmq::io_object_t::add_fd (fd_t fd_)
{
return poller->add_fd (fd_, this);
}
void zmq::io_object_t::rm_fd (handle_t handle_)
{
poller->rm_fd (handle_);
}
void zmq::io_object_t::set_pollin (handle_t handle_)
{
poller->set_pollin (handle_);
}
void zmq::io_object_t::reset_pollin (handle_t handle_)
{
poller->reset_pollin (handle_);
}
void zmq::io_object_t::set_pollout (handle_t handle_)
{
poller->set_pollout (handle_);
}
void zmq::io_object_t::reset_pollout (handle_t handle_)
{
poller->reset_pollout (handle_);
}
void zmq::io_object_t::add_timer (int timeout_, int id_)
{
poller->add_timer (timeout_, this, id_);
}
void zmq::io_object_t::cancel_timer (int id_)
{
poller->cancel_timer (this, id_);
}
void zmq::io_object_t::in_event ()
{
zmq_assert (false);
}
void zmq::io_object_t::out_event ()
{
zmq_assert (false);
}
void zmq::io_object_t::timer_event (int)
{
zmq_assert (false);
}
+89
View File
@@ -0,0 +1,89 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IO_OBJECT_HPP_INCLUDED__
#define __ZMQ_IO_OBJECT_HPP_INCLUDED__
#include <stddef.h>
#include "stdint.hpp"
#include "poller.hpp"
#include "i_poll_events.hpp"
namespace zmq
{
class io_thread_t;
// Simple base class for objects that live in I/O threads.
// It makes communication with the poller object easier and
// makes defining unneeded event handlers unnecessary.
class io_object_t : public i_poll_events
{
public:
io_object_t (zmq::io_thread_t *io_thread_ = NULL);
~io_object_t ();
// When migrating an object from one I/O thread to another, first
// unplug it, then migrate it, then plug it to the new thread.
void plug (zmq::io_thread_t *io_thread_);
void unplug ();
protected:
typedef poller_t::handle_t handle_t;
// Methods to access underlying poller object.
handle_t add_fd (fd_t fd_);
void rm_fd (handle_t handle_);
void set_pollin (handle_t handle_);
void reset_pollin (handle_t handle_);
void set_pollout (handle_t handle_);
void reset_pollout (handle_t handle_);
void add_timer (int timout_, int id_);
void cancel_timer (int id_);
// i_poll_events interface implementation.
void in_event ();
void out_event ();
void timer_event (int id_);
private:
poller_t *poller;
io_object_t (const io_object_t&);
const io_object_t &operator = (const io_object_t&);
};
}
#endif
+114
View File
@@ -0,0 +1,114 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <new>
#include "macros.hpp"
#include "io_thread.hpp"
#include "err.hpp"
#include "ctx.hpp"
zmq::io_thread_t::io_thread_t (ctx_t *ctx_, uint32_t tid_) :
object_t (ctx_, tid_)
{
poller = new (std::nothrow) poller_t (*ctx_);
alloc_assert (poller);
mailbox_handle = poller->add_fd (mailbox.get_fd (), this);
poller->set_pollin (mailbox_handle);
}
zmq::io_thread_t::~io_thread_t ()
{
LIBZMQ_DELETE(poller);
}
void zmq::io_thread_t::start ()
{
// Start the underlying I/O thread.
poller->start ();
}
void zmq::io_thread_t::stop ()
{
send_stop ();
}
zmq::mailbox_t *zmq::io_thread_t::get_mailbox ()
{
return &mailbox;
}
int zmq::io_thread_t::get_load ()
{
return poller->get_load ();
}
void zmq::io_thread_t::in_event ()
{
// TODO: Do we want to limit number of commands I/O thread can
// process in a single go?
command_t cmd;
int rc = mailbox.recv (&cmd, 0);
while (rc == 0 || errno == EINTR) {
if (rc == 0)
cmd.destination->process_command (cmd);
rc = mailbox.recv (&cmd, 0);
}
errno_assert (rc != 0 && errno == EAGAIN);
}
void zmq::io_thread_t::out_event ()
{
// We are never polling for POLLOUT here. This function is never called.
zmq_assert (false);
}
void zmq::io_thread_t::timer_event (int)
{
// No timers here. This function is never called.
zmq_assert (false);
}
zmq::poller_t *zmq::io_thread_t::get_poller ()
{
zmq_assert (poller);
return poller;
}
void zmq::io_thread_t::process_stop ()
{
poller->rm_fd (mailbox_handle);
poller->stop ();
}
+99
View File
@@ -0,0 +1,99 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IO_THREAD_HPP_INCLUDED__
#define __ZMQ_IO_THREAD_HPP_INCLUDED__
#include <vector>
#include "stdint.hpp"
#include "object.hpp"
#include "poller.hpp"
#include "i_poll_events.hpp"
#include "mailbox.hpp"
namespace zmq
{
class ctx_t;
// Generic part of the I/O thread. Polling-mechanism-specific features
// are implemented in separate "polling objects".
class io_thread_t : public object_t, public i_poll_events
{
public:
io_thread_t (zmq::ctx_t *ctx_, uint32_t tid_);
// Clean-up. If the thread was started, it's necessary to call 'stop'
// before invoking destructor. Otherwise the destructor would hang up.
~io_thread_t ();
// Launch the physical thread.
void start ();
// Ask underlying thread to stop.
void stop ();
// Returns mailbox associated with this I/O thread.
mailbox_t *get_mailbox ();
// i_poll_events implementation.
void in_event ();
void out_event ();
void timer_event (int id_);
// Used by io_objects to retrieve the associated poller object.
poller_t *get_poller ();
// Command handlers.
void process_stop ();
// Returns load experienced by the I/O thread.
int get_load ();
private:
// I/O thread accesses incoming commands via this mailbox.
mailbox_t mailbox;
// Handle associated with mailbox' file descriptor.
poller_t::handle_t mailbox_handle;
// I/O multiplexing is performed using a poller object.
poller_t *poller;
io_thread_t (const io_thread_t&);
const io_thread_t &operator = (const io_thread_t&);
};
}
#endif
+235
View File
@@ -0,0 +1,235 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "ip.hpp"
#include "err.hpp"
#include "macros.hpp"
#if !defined ZMQ_HAVE_WINDOWS
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#endif
#if defined ZMQ_HAVE_OPENVMS
#include <ioctl.h>
#endif
zmq::fd_t zmq::open_socket (int domain_, int type_, int protocol_)
{
int rc;
// Setting this option result in sane behaviour when exec() functions
// are used. Old sockets are closed and don't block TCP ports etc.
#if defined ZMQ_HAVE_SOCK_CLOEXEC
type_ |= SOCK_CLOEXEC;
#endif
fd_t s = socket (domain_, type_, protocol_);
#ifdef ZMQ_HAVE_WINDOWS
if (s == INVALID_SOCKET)
return INVALID_SOCKET;
#else
if (s == -1)
return -1;
#endif
// If there's no SOCK_CLOEXEC, let's try the second best option. Note that
// race condition can cause socket not to be closed (if fork happens
// between socket creation and this point).
#if !defined ZMQ_HAVE_SOCK_CLOEXEC && defined FD_CLOEXEC
rc = fcntl (s, F_SETFD, FD_CLOEXEC);
errno_assert (rc != -1);
#endif
// On Windows, preventing sockets to be inherited by child processes.
#if defined ZMQ_HAVE_WINDOWS && defined HANDLE_FLAG_INHERIT
BOOL brc = SetHandleInformation ((HANDLE) s, HANDLE_FLAG_INHERIT, 0);
win_assert (brc);
#endif
// Socket is not yet connected so EINVAL is not a valid networking error
rc = zmq::set_nosigpipe (s);
errno_assert (rc == 0);
return s;
}
void zmq::unblock_socket (fd_t s_)
{
#if defined ZMQ_HAVE_WINDOWS
u_long nonblock = 1;
int rc = ioctlsocket (s_, FIONBIO, &nonblock);
wsa_assert (rc != SOCKET_ERROR);
#elif defined ZMQ_HAVE_OPENVMS
int nonblock = 1;
int rc = ioctl (s_, FIONBIO, &nonblock);
errno_assert (rc != -1);
#else
int flags = fcntl (s_, F_GETFL, 0);
if (flags == -1)
flags = 0;
int rc = fcntl (s_, F_SETFL, flags | O_NONBLOCK);
errno_assert (rc != -1);
#endif
}
void zmq::enable_ipv4_mapping (fd_t s_)
{
(void) s_;
#if defined IPV6_V6ONLY && !defined ZMQ_HAVE_OPENBSD
#ifdef ZMQ_HAVE_WINDOWS
DWORD flag = 0;
#else
int flag = 0;
#endif
int rc = setsockopt (s_, IPPROTO_IPV6, IPV6_V6ONLY, (const char*) &flag,
sizeof (flag));
#ifdef ZMQ_HAVE_WINDOWS
wsa_assert (rc != SOCKET_ERROR);
#else
errno_assert (rc == 0);
#endif
#endif
}
int zmq::get_peer_ip_address (fd_t sockfd_, std::string &ip_addr_)
{
int rc;
struct sockaddr_storage ss;
#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_WINDOWS
int addrlen = static_cast <int> (sizeof ss);
#else
socklen_t addrlen = sizeof ss;
#endif
rc = getpeername (sockfd_, (struct sockaddr*) &ss, &addrlen);
#ifdef ZMQ_HAVE_WINDOWS
if (rc == SOCKET_ERROR) {
const int last_error = WSAGetLastError();
wsa_assert (last_error != WSANOTINITIALISED &&
last_error != WSAEFAULT &&
last_error != WSAEINPROGRESS &&
last_error != WSAENOTSOCK);
return 0;
}
#else
if (rc == -1) {
errno_assert (errno != EBADF &&
errno != EFAULT &&
errno != ENOTSOCK);
return 0;
}
#endif
char host [NI_MAXHOST];
rc = getnameinfo ((struct sockaddr*) &ss, addrlen, host, sizeof host,
NULL, 0, NI_NUMERICHOST);
if (rc != 0)
return 0;
ip_addr_ = host;
union {
struct sockaddr sa;
struct sockaddr_storage sa_stor;
} u;
u.sa_stor = ss;
return (int) u.sa.sa_family;
}
void zmq::set_ip_type_of_service (fd_t s_, int iptos)
{
int rc = setsockopt(s_, IPPROTO_IP, IP_TOS, reinterpret_cast<const char*>(&iptos), sizeof(iptos));
#ifdef ZMQ_HAVE_WINDOWS
wsa_assert (rc != SOCKET_ERROR);
#else
errno_assert (rc == 0);
#endif
// Windows and Hurd do not support IPV6_TCLASS
#if !defined (ZMQ_HAVE_WINDOWS) && defined (IPV6_TCLASS)
rc = setsockopt(
s_,
IPPROTO_IPV6,
IPV6_TCLASS,
reinterpret_cast<const char*>(&iptos),
sizeof(iptos));
// If IPv6 is not enabled ENOPROTOOPT will be returned on Linux and
// EINVAL on OSX
if (rc == -1) {
errno_assert (errno == ENOPROTOOPT ||
errno == EINVAL);
}
#endif
}
int zmq::set_nosigpipe (fd_t s_)
{
#ifdef SO_NOSIGPIPE
// Make sure that SIGPIPE signal is not generated when writing to a
// connection that was already closed by the peer.
// As per POSIX spec, EINVAL will be returned if the socket was valid but
// the connection has been reset by the peer. Return an error so that the
// socket can be closed and the connection retried if necessary.
int set = 1;
int rc = setsockopt (s_, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof (int));
if (rc != 0 && errno == EINVAL)
return -1;
errno_assert (rc == 0);
#else
LIBZMQ_UNUSED (s_);
#endif
return 0;
}
void zmq::bind_to_device (fd_t s_, std::string &bound_device_)
{
#ifdef ZMQ_HAVE_SO_BINDTODEVICE
int rc = setsockopt(s_, SOL_SOCKET, SO_BINDTODEVICE, bound_device_.c_str (), bound_device_.length ());
#ifdef ZMQ_HAVE_WINDOWS
wsa_assert (rc != SOCKET_ERROR);
#else
errno_assert (rc == 0);
#endif
#else
LIBZMQ_UNUSED (s_);
LIBZMQ_UNUSED (bound_device_);
#endif
}
+64
View File
@@ -0,0 +1,64 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IP_HPP_INCLUDED__
#define __ZMQ_IP_HPP_INCLUDED__
#include <string>
#include "fd.hpp"
namespace zmq
{
// Same as socket(2), but allows for transparent tweaking the options.
fd_t open_socket (int domain_, int type_, int protocol_);
// Sets the socket into non-blocking mode.
void unblock_socket (fd_t s_);
// Enable IPv4-mapping of addresses in case it is disabled by default.
void enable_ipv4_mapping (fd_t s_);
// Returns string representation of peer's address.
// Socket sockfd_ must be connected. Returns true iff successful.
int get_peer_ip_address (fd_t sockfd_, std::string &ip_addr_);
// Sets the IP Type-Of-Service for the underlying socket
void set_ip_type_of_service (fd_t s_, int iptos);
// Sets the SO_NOSIGPIPE option for the underlying socket.
// Return 0 on success, -1 if the connection has been closed by the peer
int set_nosigpipe (fd_t s_);
// Binds the underlying socket to the given device, eg. VRF or interface
void bind_to_device (fd_t s_, std::string &bound_device_);
}
#endif
+74
View File
@@ -0,0 +1,74 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IPC_ADDRESS_HPP_INCLUDED__
#define __ZMQ_IPC_ADDRESS_HPP_INCLUDED__
#include <string>
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include <sys/socket.h>
#include <sys/un.h>
namespace zmq
{
class ipc_address_t
{
public:
ipc_address_t ();
ipc_address_t (const sockaddr *sa, socklen_t sa_len);
~ipc_address_t ();
// This function sets up the address for UNIX domain transport.
int resolve (const char *path_);
// The opposite to resolve()
int to_string (std::string &addr_);
const sockaddr *addr () const;
socklen_t addrlen () const;
private:
struct sockaddr_un address;
ipc_address_t (const ipc_address_t&);
const ipc_address_t &operator = (const ipc_address_t&);
};
}
#endif
#endif
+135
View File
@@ -0,0 +1,135 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __IPC_CONNECTER_HPP_INCLUDED__
#define __IPC_CONNECTER_HPP_INCLUDED__
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include "fd.hpp"
#include "own.hpp"
#include "stdint.hpp"
#include "io_object.hpp"
namespace zmq
{
class io_thread_t;
class session_base_t;
struct address_t;
class ipc_connecter_t : public own_t, public io_object_t
{
public:
// If 'delayed_start' is true connecter first waits for a while,
// then starts connection process.
ipc_connecter_t (zmq::io_thread_t *io_thread_,
zmq::session_base_t *session_, const options_t &options_,
const address_t *addr_, bool delayed_start_);
~ipc_connecter_t ();
private:
// ID of the timer used to delay the reconnection.
enum {reconnect_timer_id = 1};
// Handlers for incoming commands.
void process_plug ();
void process_term (int linger_);
// Handlers for I/O events.
void in_event ();
void out_event ();
void timer_event (int id_);
// Internal function to start the actual connection establishment.
void start_connecting ();
// Internal function to add a reconnect timer
void add_reconnect_timer();
// Internal function to return a reconnect backoff delay.
// Will modify the current_reconnect_ivl used for next call
// Returns the currently used interval
int get_new_reconnect_ivl ();
// Open IPC connecting socket. Returns -1 in case of error,
// 0 if connect was successful immediately. Returns -1 with
// EAGAIN errno if async connect was launched.
int open ();
// Close the connecting socket.
int close ();
// Get the file descriptor of newly created connection. Returns
// retired_fd if the connection was unsuccessful.
fd_t connect ();
// Address to connect to. Owned by session_base_t.
const address_t *addr;
// Underlying socket.
fd_t s;
// Handle corresponding to the listening socket.
handle_t handle;
// If true file descriptor is registered with the poller and 'handle'
// contains valid value.
bool handle_valid;
// If true, connecter is waiting a while before trying to connect.
const bool delayed_start;
// True iff a timer has been started.
bool timer_started;
// Reference to the session we belong to.
zmq::session_base_t *session;
// Current reconnect ivl, updated for backoff strategy
int current_reconnect_ivl;
// String representation of endpoint to connect to
std::string endpoint;
// Socket
zmq::socket_base_t *socket;
ipc_connecter_t (const ipc_connecter_t&);
const ipc_connecter_t &operator = (const ipc_connecter_t&);
};
}
#endif
#endif
+123
View File
@@ -0,0 +1,123 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IPC_LISTENER_HPP_INCLUDED__
#define __ZMQ_IPC_LISTENER_HPP_INCLUDED__
#if !defined ZMQ_HAVE_WINDOWS && !defined ZMQ_HAVE_OPENVMS
#include <string>
#include "fd.hpp"
#include "own.hpp"
#include "stdint.hpp"
#include "io_object.hpp"
namespace zmq
{
class io_thread_t;
class socket_base_t;
class ipc_listener_t : public own_t, public io_object_t
{
public:
ipc_listener_t (zmq::io_thread_t *io_thread_,
zmq::socket_base_t *socket_, const options_t &options_);
~ipc_listener_t ();
// Set address to listen on.
int set_address (const char *addr_);
// Get the bound address for use with wildcards
int get_address (std::string &addr_);
private:
// Handlers for incoming commands.
void process_plug ();
void process_term (int linger_);
// Handlers for I/O events.
void in_event ();
// Close the listening socket.
int close ();
// Create wildcard path address
static int create_wildcard_address(std::string& path_,
std::string& file_);
// Filter new connections if the OS provides a mechanism to get
// the credentials of the peer process. Called from accept().
# if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
bool filter (fd_t sock);
# endif
// Accept the new connection. Returns the file descriptor of the
// newly created connection. The function may return retired_fd
// if the connection was dropped while waiting in the listen backlog.
fd_t accept ();
// True, if the underlying file for UNIX domain socket exists.
bool has_file;
// Name of the temporary directory (if any) that has the
// the UNIX domain socket
std::string tmp_socket_dirname;
// Name of the file associated with the UNIX domain address.
std::string filename;
// Underlying socket.
fd_t s;
// Handle corresponding to the listening socket.
handle_t handle;
// Socket the listener belongs to.
zmq::socket_base_t *socket;
// String representation of endpoint to bind to
std::string endpoint;
// Acceptable temporary directory environment variables
static const char *tmp_env_vars[];
ipc_listener_t (const ipc_listener_t&);
const ipc_listener_t &operator = (const ipc_listener_t&);
};
}
#endif
#endif
+173
View File
@@ -0,0 +1,173 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "lb.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "msg.hpp"
zmq::lb_t::lb_t () :
active (0),
current (0),
more (false),
dropping (false)
{
}
zmq::lb_t::~lb_t ()
{
zmq_assert (pipes.empty ());
}
void zmq::lb_t::attach (pipe_t *pipe_)
{
pipes.push_back (pipe_);
activated (pipe_);
}
void zmq::lb_t::pipe_terminated (pipe_t *pipe_)
{
pipes_t::size_type index = pipes.index (pipe_);
// If we are in the middle of multipart message and current pipe
// have disconnected, we have to drop the remainder of the message.
if (index == current && more)
dropping = true;
// Remove the pipe from the list; adjust number of active pipes
// accordingly.
if (index < active) {
active--;
pipes.swap (index, active);
if (current == active)
current = 0;
}
pipes.erase (pipe_);
}
void zmq::lb_t::activated (pipe_t *pipe_)
{
// Move the pipe to the list of active pipes.
pipes.swap (pipes.index (pipe_), active);
active++;
}
int zmq::lb_t::send (msg_t *msg_)
{
return sendpipe (msg_, NULL);
}
int zmq::lb_t::sendpipe (msg_t *msg_, pipe_t **pipe_)
{
// Drop the message if required. If we are at the end of the message
// switch back to non-dropping mode.
if (dropping) {
more = msg_->flags () & msg_t::more ? true : false;
dropping = more;
int rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
while (active > 0) {
if (pipes [current]->write (msg_))
{
if (pipe_)
*pipe_ = pipes [current];
break;
}
// If send fails for multi-part msg rollback other
// parts sent earlier and return EAGAIN.
// Application should handle this as suitable
if (more)
{
pipes [current]->rollback ();
more = 0;
errno = EAGAIN;
return -1;
}
active--;
if (current < active)
pipes.swap (current, active);
else
current = 0;
}
// If there are no pipes we cannot send the message.
if (active == 0) {
errno = EAGAIN;
return -1;
}
// If it's final part of the message we can flush it downstream and
// continue round-robining (load balance).
more = msg_->flags () & msg_t::more? true: false;
if (!more) {
pipes [current]->flush ();
if (++current >= active)
current = 0;
}
// Detach the message from the data buffer.
int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
bool zmq::lb_t::has_out ()
{
// If one part of the message was already written we can definitely
// write the rest of the message.
if (more)
return true;
while (active > 0) {
// Check whether a pipe has room for another message.
if (pipes [current]->check_write ())
return true;
// Deactivate the pipe.
active--;
pipes.swap (current, active);
if (current == active)
current = 0;
}
return false;
}
+88
View File
@@ -0,0 +1,88 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_LB_HPP_INCLUDED__
#define __ZMQ_LB_HPP_INCLUDED__
#include "array.hpp"
#include "pipe.hpp"
namespace zmq
{
// This class manages a set of outbound pipes. On send it load balances
// messages fairly among the pipes.
class lb_t
{
public:
lb_t ();
~lb_t ();
void attach (pipe_t *pipe_);
void activated (pipe_t *pipe_);
void pipe_terminated (pipe_t *pipe_);
int send (msg_t *msg_);
// Sends a message and stores the pipe that was used in pipe_.
// It is possible for this function to return success but keep pipe_
// unset if the rest of a multipart message to a terminated pipe is
// being dropped. For the first frame, this will never happen.
int sendpipe (msg_t *msg_, pipe_t **pipe_);
bool has_out ();
private:
// List of outbound pipes.
typedef array_t <pipe_t, 2> pipes_t;
pipes_t pipes;
// Number of active pipes. All the active pipes are located at the
// beginning of the pipes array.
pipes_t::size_type active;
// Points to the last pipe that the most recent message was sent to.
pipes_t::size_type current;
// True if last we are in the middle of a multipart message.
bool more;
// True if we are dropping current message.
bool dropping;
lb_t (const lb_t&);
const lb_t &operator = (const lb_t&);
};
}
#endif
+42
View File
@@ -0,0 +1,42 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_LIKELY_HPP_INCLUDED__
#define __ZMQ_LIKELY_HPP_INCLUDED__
#if defined __GNUC__
#define likely(x) __builtin_expect ((x), 1)
#define unlikely(x) __builtin_expect ((x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
#endif
+12
View File
@@ -0,0 +1,12 @@
/******************************************************************************/
/* 0MQ Internal Use */
/******************************************************************************/
#define LIBZMQ_UNUSED(object) (void)object
#define LIBZMQ_DELETE(p_object) {\
delete p_object; \
p_object = 0; \
}
/******************************************************************************/
+101
View File
@@ -0,0 +1,101 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "mailbox.hpp"
#include "err.hpp"
zmq::mailbox_t::mailbox_t ()
{
// Get the pipe into passive state. That way, if the users starts by
// polling on the associated file descriptor it will get woken up when
// new command is posted.
const bool ok = cpipe.read (NULL);
zmq_assert (!ok);
active = false;
}
zmq::mailbox_t::~mailbox_t ()
{
// TODO: Retrieve and deallocate commands inside the cpipe.
// Work around problem that other threads might still be in our
// send() method, by waiting on the mutex before disappearing.
sync.lock ();
sync.unlock ();
}
zmq::fd_t zmq::mailbox_t::get_fd () const
{
return signaler.get_fd ();
}
void zmq::mailbox_t::send (const command_t &cmd_)
{
sync.lock ();
cpipe.write (cmd_, false);
const bool ok = cpipe.flush ();
sync.unlock ();
if (!ok)
signaler.send ();
}
int zmq::mailbox_t::recv (command_t *cmd_, int timeout_)
{
// Try to get the command straight away.
if (active) {
if (cpipe.read (cmd_))
return 0;
// If there are no more commands available, switch into passive state.
active = false;
}
// Wait for signal from the command sender.
int rc = signaler.wait (timeout_);
if (rc == -1) {
errno_assert (errno == EAGAIN || errno == EINTR);
return -1;
}
// Receive the signal.
rc = signaler.recv_failable ();
if (rc == -1) {
errno_assert (errno == EAGAIN);
return -1;
}
// Switch into active state.
active = true;
// Get a command.
const bool ok = cpipe.read (cmd_);
zmq_assert (ok);
return 0;
}
+90
View File
@@ -0,0 +1,90 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MAILBOX_HPP_INCLUDED__
#define __ZMQ_MAILBOX_HPP_INCLUDED__
#include <stddef.h>
#include "signaler.hpp"
#include "fd.hpp"
#include "config.hpp"
#include "command.hpp"
#include "ypipe.hpp"
#include "mutex.hpp"
#include "i_mailbox.hpp"
namespace zmq
{
class mailbox_t : public i_mailbox
{
public:
mailbox_t ();
~mailbox_t ();
fd_t get_fd () const;
void send (const command_t &cmd_);
int recv (command_t *cmd_, int timeout_);
#ifdef HAVE_FORK
// close the file descriptors in the signaller. This is used in a forked
// child process to close the file descriptors so that they do not interfere
// with the context in the parent process.
void forked () { signaler.forked (); }
#endif
private:
// The pipe to store actual commands.
typedef ypipe_t <command_t, command_pipe_granularity> cpipe_t;
cpipe_t cpipe;
// Signaler to pass signals from writer thread to reader thread.
signaler_t signaler;
// There's only one thread receiving from the mailbox, but there
// is arbitrary number of threads sending. Given that ypipe requires
// synchronised access on both of its endpoints, we have to synchronise
// the sending side.
mutex_t sync;
// True if the underlying pipe is active, ie. when we are allowed to
// read commands from it.
bool active;
// Disable copying of mailbox_t object.
mailbox_t (const mailbox_t&);
const mailbox_t &operator = (const mailbox_t&);
};
}
#endif
+117
View File
@@ -0,0 +1,117 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "mailbox_safe.hpp"
#include "clock.hpp"
#include "err.hpp"
zmq::mailbox_safe_t::mailbox_safe_t (mutex_t* sync_) :
sync (sync_)
{
// Get the pipe into passive state. That way, if the users starts by
// polling on the associated file descriptor it will get woken up when
// new command is posted.
const bool ok = cpipe.read (NULL);
zmq_assert (!ok);
}
zmq::mailbox_safe_t::~mailbox_safe_t ()
{
// TODO: Retrieve and deallocate commands inside the cpipe.
// Work around problem that other threads might still be in our
// send() method, by waiting on the mutex before disappearing.
sync->lock ();
sync->unlock ();
}
void zmq::mailbox_safe_t::add_signaler (signaler_t* signaler)
{
signalers.push_back(signaler);
}
void zmq::mailbox_safe_t::remove_signaler (signaler_t* signaler)
{
std::vector<signaler_t*>::iterator it = signalers.begin();
// TODO: make a copy of array and signal outside the lock
for (; it != signalers.end(); ++it){
if (*it == signaler)
break;
}
if (it != signalers.end())
signalers.erase(it);
}
void zmq::mailbox_safe_t::clear_signalers ()
{
signalers.clear ();
}
void zmq::mailbox_safe_t::send (const command_t &cmd_)
{
sync->lock ();
cpipe.write (cmd_, false);
const bool ok = cpipe.flush ();
if (!ok) {
cond_var.broadcast ();
for (std::vector<signaler_t*>::iterator it = signalers.begin(); it != signalers.end(); ++it){
(*it)->send();
}
}
sync->unlock ();
}
int zmq::mailbox_safe_t::recv (command_t *cmd_, int timeout_)
{
// Try to get the command straight away.
if (cpipe.read (cmd_))
return 0;
// Wait for signal from the command sender.
int rc = cond_var.wait (sync, timeout_);
if (rc == -1) {
errno_assert (errno == EAGAIN || errno == EINTR);
return -1;
}
// Another thread may already fetch the command
const bool ok = cpipe.read (cmd_);
if (!ok) {
errno = EAGAIN;
return -1;
}
return 0;
}
+94
View File
@@ -0,0 +1,94 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MAILBOX_SAFE_HPP_INCLUDED__
#define __ZMQ_MAILBOX_SAFE_HPP_INCLUDED__
#include <vector>
#include <stddef.h>
#include "signaler.hpp"
#include "fd.hpp"
#include "config.hpp"
#include "command.hpp"
#include "ypipe.hpp"
#include "mutex.hpp"
#include "i_mailbox.hpp"
#include "condition_variable.hpp"
namespace zmq
{
class mailbox_safe_t : public i_mailbox
{
public:
mailbox_safe_t (mutex_t* sync_);
~mailbox_safe_t ();
void send (const command_t &cmd_);
int recv (command_t *cmd_, int timeout_);
// Add signaler to mailbox which will be called when a message is ready
void add_signaler (signaler_t* signaler);
void remove_signaler (signaler_t* signaler);
void clear_signalers ();
#ifdef HAVE_FORK
// close the file descriptors in the signaller. This is used in a forked
// child process to close the file descriptors so that they do not interfere
// with the context in the parent process.
void forked ()
{
// TODO: call fork on the condition variable
}
#endif
private:
// The pipe to store actual commands.
typedef ypipe_t <command_t, command_pipe_granularity> cpipe_t;
cpipe_t cpipe;
// Condition variable to pass signals from writer thread to reader thread.
condition_variable_t cond_var;
// Synchronize access to the mailbox from receivers and senders
mutex_t* sync;
std::vector <zmq::signaler_t* > signalers;
// Disable copying of mailbox_t object.
mailbox_safe_t (const mailbox_safe_t&);
const mailbox_safe_t &operator = (const mailbox_safe_t&);
};
}
#endif
+285
View File
@@ -0,0 +1,285 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <string.h>
#include "mechanism.hpp"
#include "options.hpp"
#include "msg.hpp"
#include "err.hpp"
#include "wire.hpp"
#include "session_base.hpp"
zmq::mechanism_t::mechanism_t (const options_t &options_) :
options (options_)
{
}
zmq::mechanism_t::~mechanism_t ()
{
}
void zmq::mechanism_t::set_peer_routing_id (const void *id_ptr, size_t id_size)
{
routing_id.set (static_cast <const unsigned char*> (id_ptr), id_size);
}
void zmq::mechanism_t::peer_routing_id (msg_t *msg_)
{
const int rc = msg_->init_size (routing_id.size ());
errno_assert (rc == 0);
memcpy (msg_->data (), routing_id.data (), routing_id.size ());
msg_->set_flags (msg_t::routing_id);
}
void zmq::mechanism_t::set_user_id (const void *data_, size_t size_)
{
user_id.set (static_cast <const unsigned char*> (data_), size_);
zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE (
ZMQ_MSG_PROPERTY_USER_ID, std::string ((char *) data_, size_));
}
const zmq::blob_t &zmq::mechanism_t::get_user_id () const
{
return user_id;
}
const char *zmq::mechanism_t::socket_type_string (int socket_type) const
{
static const char *names [] = {"PAIR", "PUB", "SUB", "REQ", "REP",
"DEALER", "ROUTER", "PULL", "PUSH",
"XPUB", "XSUB", "STREAM",
"SERVER", "CLIENT",
"RADIO", "DISH",
"GATHER", "SCATTER", "DGRAM"};
zmq_assert (socket_type >= 0 && socket_type <= 18);
return names [socket_type];
}
static size_t property_len (size_t name_len, size_t value_len)
{
return 1 + name_len + 4 + value_len;
}
static size_t name_len (const char *name)
{
const size_t name_len = strlen (name);
zmq_assert (name_len <= 255);
return name_len;
}
size_t zmq::mechanism_t::add_property (unsigned char *ptr,
size_t ptr_capacity,
const char *name,
const void *value,
size_t value_len)
{
const size_t name_len = ::name_len (name);
const size_t total_len = ::property_len (name_len, value_len);
zmq_assert (total_len <= ptr_capacity);
*ptr++ = static_cast <unsigned char> (name_len);
memcpy (ptr, name, name_len);
ptr += name_len;
zmq_assert (value_len <= 0x7FFFFFFF);
put_uint32 (ptr, static_cast <uint32_t> (value_len));
ptr += 4;
memcpy (ptr, value, value_len);
return total_len;
}
size_t zmq::mechanism_t::property_len (const char *name, size_t value_len)
{
return ::property_len (name_len (name), value_len);
}
#define ZMTP_PROPERTY_SOCKET_TYPE "Socket-Type"
#define ZMTP_PROPERTY_IDENTITY "Identity"
size_t zmq::mechanism_t::add_basic_properties (unsigned char *buf,
size_t buf_capacity) const
{
unsigned char *ptr = buf;
// Add socket type property
const char *socket_type = socket_type_string (options.type);
ptr += add_property (ptr, buf_capacity,
ZMTP_PROPERTY_SOCKET_TYPE, socket_type,
strlen (socket_type));
// Add identity (aka routing id) property
if (options.type == ZMQ_REQ || options.type == ZMQ_DEALER
|| options.type == ZMQ_ROUTER)
ptr += add_property (ptr, buf_capacity - (ptr - buf),
ZMTP_PROPERTY_IDENTITY, options.routing_id,
options.routing_id_size);
return ptr - buf;
}
size_t zmq::mechanism_t::basic_properties_len() const
{
const char *socket_type = socket_type_string (options.type);
return property_len (ZMTP_PROPERTY_SOCKET_TYPE, strlen (socket_type))
+ ((options.type == ZMQ_REQ || options.type == ZMQ_DEALER
|| options.type == ZMQ_ROUTER)
? property_len (ZMTP_PROPERTY_IDENTITY,
options.routing_id_size)
: 0);
}
void zmq::mechanism_t::make_command_with_basic_properties (
msg_t *msg_, const char *prefix, size_t prefix_len) const
{
const size_t command_size = prefix_len + basic_properties_len ();
const int rc = msg_->init_size (command_size);
errno_assert (rc == 0);
unsigned char *ptr = (unsigned char *) msg_->data ();
// Add prefix
memcpy (ptr, prefix, prefix_len);
ptr += prefix_len;
add_basic_properties (
ptr, command_size - (ptr - (unsigned char *) msg_->data ()));
}
int zmq::mechanism_t::parse_metadata (const unsigned char *ptr_,
size_t length_,
bool zap_flag)
{
size_t bytes_left = length_;
while (bytes_left > 1) {
const size_t name_length = static_cast <size_t> (*ptr_);
ptr_ += 1;
bytes_left -= 1;
if (bytes_left < name_length)
break;
const std::string name = std::string ((char *) ptr_, name_length);
ptr_ += name_length;
bytes_left -= name_length;
if (bytes_left < 4)
break;
const size_t value_length = static_cast <size_t> (get_uint32 (ptr_));
ptr_ += 4;
bytes_left -= 4;
if (bytes_left < value_length)
break;
const uint8_t *value = ptr_;
ptr_ += value_length;
bytes_left -= value_length;
if (name == ZMTP_PROPERTY_IDENTITY && options.recv_routing_id)
set_peer_routing_id (value, value_length);
else
if (name == ZMTP_PROPERTY_SOCKET_TYPE) {
const std::string socket_type ((char *) value, value_length);
if (!check_socket_type (socket_type)) {
errno = EINVAL;
return -1;
}
}
else {
const int rc = property (name, value, value_length);
if (rc == -1)
return -1;
}
if (zap_flag)
zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE (
name, std::string ((char *) value, value_length));
else
zmtp_properties.ZMQ_MAP_INSERT_OR_EMPLACE (
name, std::string ((char *) value, value_length));
}
if (bytes_left > 0) {
errno = EPROTO;
return -1;
}
return 0;
}
int zmq::mechanism_t::property (const std::string& /* name_ */,
const void * /* value_ */, size_t /* length_ */)
{
// Default implementation does not check
// property values and returns 0 to signal success.
return 0;
}
bool zmq::mechanism_t::check_socket_type (const std::string& type_) const
{
switch (options.type) {
case ZMQ_REQ:
return type_ == "REP" || type_ == "ROUTER";
case ZMQ_REP:
return type_ == "REQ" || type_ == "DEALER";
case ZMQ_DEALER:
return type_ == "REP" || type_ == "DEALER" || type_ == "ROUTER";
case ZMQ_ROUTER:
return type_ == "REQ" || type_ == "DEALER" || type_ == "ROUTER";
case ZMQ_PUSH:
return type_ == "PULL";
case ZMQ_PULL:
return type_ == "PUSH";
case ZMQ_PUB:
return type_ == "SUB" || type_ == "XSUB";
case ZMQ_SUB:
return type_ == "PUB" || type_ == "XPUB";
case ZMQ_XPUB:
return type_ == "SUB" || type_ == "XSUB";
case ZMQ_XSUB:
return type_ == "PUB" || type_ == "XPUB";
case ZMQ_PAIR:
return type_ == "PAIR";
case ZMQ_SERVER:
return type_ == "CLIENT";
case ZMQ_CLIENT:
return type_ == "SERVER";
case ZMQ_RADIO:
return type_ == "DISH";
case ZMQ_DISH:
return type_ == "RADIO";
case ZMQ_GATHER:
return type_ == "SCATTER";
case ZMQ_SCATTER:
return type_ == "GATHER";
case ZMQ_DGRAM:
return type_ == "DGRAM";
default:
break;
}
return false;
}
+152
View File
@@ -0,0 +1,152 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MECHANISM_HPP_INCLUDED__
#define __ZMQ_MECHANISM_HPP_INCLUDED__
#include "stdint.hpp"
#include "options.hpp"
#include "blob.hpp"
#include "metadata.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
// Abstract class representing security mechanism.
// Different mechanism extends this class.
class mechanism_t
{
public:
enum status_t {
handshaking,
ready,
error
};
mechanism_t (const options_t &options_);
virtual ~mechanism_t ();
// Prepare next handshake command that is to be sent to the peer.
virtual int next_handshake_command (msg_t *msg_) = 0;
// Process the handshake command received from the peer.
virtual int process_handshake_command (msg_t *msg_) = 0;
virtual int encode (msg_t *) { return 0; }
virtual int decode (msg_t *) { return 0; }
// Notifies mechanism about availability of ZAP message.
virtual int zap_msg_available () { return 0; }
// Returns the status of this mechanism.
virtual status_t status () const = 0;
void set_peer_routing_id (const void *id_ptr, size_t id_size);
void peer_routing_id (msg_t *msg_);
void set_user_id (const void *user_id, size_t size);
const blob_t &get_user_id () const;
const metadata_t::dict_t& get_zmtp_properties () {
return zmtp_properties;
}
const metadata_t::dict_t& get_zap_properties () {
return zap_properties;
}
protected:
// Only used to identify the socket for the Socket-Type
// property in the wire protocol.
const char *socket_type_string (int socket_type) const;
static size_t add_property (unsigned char *ptr,
size_t ptr_capacity,
const char *name,
const void *value,
size_t value_len);
static size_t property_len (const char *name,
size_t value_len);
size_t add_basic_properties (unsigned char *ptr, size_t ptr_capacity) const;
size_t basic_properties_len () const;
void make_command_with_basic_properties (msg_t *msg_,
const char *prefix,
size_t prefix_len) const;
// Parses a metadata.
// Metadata consists of a list of properties consisting of
// name and value as size-specified strings.
// Returns 0 on success and -1 on error, in which case errno is set.
int parse_metadata (
const unsigned char *ptr_, size_t length, bool zap_flag = false);
// This is called by parse_property method whenever it
// parses a new property. The function should return 0
// on success and -1 on error, in which case it should
// set errno. Signaling error prevents parser from
// parsing remaining data.
// Derived classes are supposed to override this
// method to handle custom processing.
virtual int property (const std::string& name_,
const void *value_, size_t length_);
// Properties received from ZMTP peer.
metadata_t::dict_t zmtp_properties;
// Properties received from ZAP server.
metadata_t::dict_t zap_properties;
options_t options;
private:
blob_t routing_id;
blob_t user_id;
// Returns true iff socket associated with the mechanism
// is compatible with a given socket type 'type_'.
bool check_socket_type (const std::string& type_) const;
};
}
#endif
+70
View File
@@ -0,0 +1,70 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "mechanism_base.hpp"
#include "session_base.hpp"
zmq::mechanism_base_t::mechanism_base_t (session_base_t *const session_,
const options_t &options_) :
mechanism_t (options_),
session (session_)
{
}
int zmq::mechanism_base_t::check_basic_command_structure (msg_t *msg_)
{
if (msg_->size () <= 1 || msg_->size () <= ((uint8_t *) msg_->data ())[0]) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_UNSPECIFIED);
errno = EPROTO;
return -1;
}
return 0;
}
void zmq::mechanism_base_t::handle_error_reason (const char *error_reason,
size_t error_reason_len)
{
if (error_reason_len == 3 && error_reason[1] == '0'
&& error_reason[2] == '0' && error_reason[0] >= '3'
&& error_reason[0] <= '5') {
// it is a ZAP status code, so emit an authentication failure event
session->get_socket ()->event_handshake_failed_auth (
session->get_endpoint (), (error_reason[0] - '0') * 100);
}
}
bool zmq::mechanism_base_t::zap_required() const
{
return !options.zap_domain.empty ();
}
+53
View File
@@ -0,0 +1,53 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MECHANISM_BASE_HPP_INCLUDED__
#define __ZMQ_MECHANISM_BASE_HPP_INCLUDED__
#include "mechanism.hpp"
namespace zmq
{
class mechanism_base_t : public mechanism_t
{
protected:
mechanism_base_t (session_base_t *const session_,
const options_t &options_);
session_base_t *const session;
int check_basic_command_structure (msg_t *msg_);
void handle_error_reason (const char *error_reason, size_t error_reason_len);
bool zap_required() const;
};
}
#endif
+62
View File
@@ -0,0 +1,62 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "metadata.hpp"
zmq::metadata_t::metadata_t (const dict_t &dict) :
ref_cnt (1),
dict (dict)
{
}
const char *zmq::metadata_t::get (const std::string &property) const
{
dict_t::const_iterator it = dict.find (property);
if (it == dict.end())
{
/** \todo remove this when support for the deprecated name "Identity" is dropped */
if (property == "Identity")
return get (ZMQ_MSG_PROPERTY_ROUTING_ID);
return NULL;
}
else
return it->second.c_str ();
}
void zmq::metadata_t::add_ref ()
{
ref_cnt.add (1);
}
bool zmq::metadata_t::drop_ref ()
{
return !ref_cnt.sub (1);
}
+70
View File
@@ -0,0 +1,70 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_METADATA_HPP_INCLUDED__
#define __ZMQ_METADATA_HPP_INCLUDED__
#include <map>
#include <string>
#include "atomic_counter.hpp"
namespace zmq
{
class metadata_t
{
public:
typedef std::map <std::string, std::string> dict_t;
metadata_t (const dict_t &dict);
// Returns pointer to property value or NULL if
// property is not found.
const char *get (const std::string &property) const;
void add_ref ();
// Drop reference. Returns true iff the reference
// counter drops to zero.
bool drop_ref ();
private:
metadata_t(const metadata_t&);
metadata_t & operator=(const metadata_t&);
// Reference counter.
atomic_counter_t ref_cnt;
// Dictionary holding metadata.
dict_t dict;
};
}
#endif
+578
View File
@@ -0,0 +1,578 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "msg.hpp"
#include <string.h>
#include <stdlib.h>
#include <new>
#include "stdint.hpp"
#include "likely.hpp"
#include "metadata.hpp"
#include "err.hpp"
// Check whether the sizes of public representation of the message (zmq_msg_t)
// and private representation of the message (zmq::msg_t) match.
typedef char zmq_msg_size_check
[2 * ((sizeof (zmq::msg_t) == sizeof (zmq_msg_t)) != 0) - 1];
bool zmq::msg_t::check () const
{
return u.base.type >= type_min && u.base.type <= type_max;
}
int zmq::msg_t::init (void* data_, size_t size_,
msg_free_fn* ffn_, void* hint,
content_t* content_)
{
if (size_ < max_vsm_size) {
int const rc = init_size(size_);
if (rc != -1)
{
memcpy(data(), data_, size_);
return 0;
}
else
{
return -1;
}
}
else if(content_)
{
return init_external_storage(content_, data_, size_, ffn_, hint);
}
else
{
return init_data(data_, size_, ffn_, hint);
}
}
int zmq::msg_t::init ()
{
u.vsm.metadata = NULL;
u.vsm.type = type_vsm;
u.vsm.flags = 0;
u.vsm.size = 0;
u.vsm.group[0] = '\0';
u.vsm.routing_id = 0;
return 0;
}
int zmq::msg_t::init_size (size_t size_)
{
if (size_ <= max_vsm_size) {
u.vsm.metadata = NULL;
u.vsm.type = type_vsm;
u.vsm.flags = 0;
u.vsm.size = (unsigned char) size_;
u.vsm.group[0] = '\0';
u.vsm.routing_id = 0;
}
else {
u.lmsg.metadata = NULL;
u.lmsg.type = type_lmsg;
u.lmsg.flags = 0;
u.lmsg.group[0] = '\0';
u.lmsg.routing_id = 0;
u.lmsg.content = NULL;
if (sizeof (content_t) + size_ > size_)
u.lmsg.content = (content_t*) malloc (sizeof (content_t) + size_);
if (unlikely (!u.lmsg.content)) {
errno = ENOMEM;
return -1;
}
u.lmsg.content->data = u.lmsg.content + 1;
u.lmsg.content->size = size_;
u.lmsg.content->ffn = NULL;
u.lmsg.content->hint = NULL;
new (&u.lmsg.content->refcnt) zmq::atomic_counter_t ();
}
return 0;
}
int zmq::msg_t::init_external_storage(content_t* content_, void* data_, size_t size_,
msg_free_fn *ffn_, void* hint_)
{
zmq_assert(NULL != data_);
zmq_assert(NULL != content_);
u.zclmsg.metadata = NULL;
u.zclmsg.type = type_zclmsg;
u.zclmsg.flags = 0;
u.zclmsg.group[0] = '\0';
u.zclmsg.routing_id = 0;
u.zclmsg.content = content_;
u.zclmsg.content->data = data_;
u.zclmsg.content->size = size_;
u.zclmsg.content->ffn = ffn_;
u.zclmsg.content->hint = hint_;
new (&u.zclmsg.content->refcnt) zmq::atomic_counter_t();
return 0;
}
int zmq::msg_t::init_data (void *data_, size_t size_,
msg_free_fn *ffn_, void *hint_)
{
// If data is NULL and size is not 0, a segfault
// would occur once the data is accessed
zmq_assert (data_ != NULL || size_ == 0);
// Initialize constant message if there's no need to deallocate
if (ffn_ == NULL) {
u.cmsg.metadata = NULL;
u.cmsg.type = type_cmsg;
u.cmsg.flags = 0;
u.cmsg.data = data_;
u.cmsg.size = size_;
u.cmsg.group[0] = '\0';
u.cmsg.routing_id = 0;
}
else {
u.lmsg.metadata = NULL;
u.lmsg.type = type_lmsg;
u.lmsg.flags = 0;
u.lmsg.group[0] = '\0';
u.lmsg.routing_id = 0;
u.lmsg.content = (content_t*) malloc (sizeof (content_t));
if (!u.lmsg.content) {
errno = ENOMEM;
return -1;
}
u.lmsg.content->data = data_;
u.lmsg.content->size = size_;
u.lmsg.content->ffn = ffn_;
u.lmsg.content->hint = hint_;
new (&u.lmsg.content->refcnt) zmq::atomic_counter_t ();
}
return 0;
}
int zmq::msg_t::init_delimiter ()
{
u.delimiter.metadata = NULL;
u.delimiter.type = type_delimiter;
u.delimiter.flags = 0;
u.delimiter.group[0] = '\0';
u.delimiter.routing_id = 0;
return 0;
}
int zmq::msg_t::init_join ()
{
u.base.metadata = NULL;
u.base.type = type_join;
u.base.flags = 0;
u.base.group[0] = '\0';
u.base.routing_id = 0;
return 0;
}
int zmq::msg_t::init_leave ()
{
u.base.metadata = NULL;
u.base.type = type_leave;
u.base.flags = 0;
u.base.group[0] = '\0';
u.base.routing_id = 0;
return 0;
}
int zmq::msg_t::close ()
{
// Check the validity of the message.
if (unlikely (!check ())) {
errno = EFAULT;
return -1;
}
if (u.base.type == type_lmsg) {
// If the content is not shared, or if it is shared and the reference
// count has dropped to zero, deallocate it.
if (!(u.lmsg.flags & msg_t::shared) ||
!u.lmsg.content->refcnt.sub (1)) {
// We used "placement new" operator to initialize the reference
// counter so we call the destructor explicitly now.
u.lmsg.content->refcnt.~atomic_counter_t ();
if (u.lmsg.content->ffn)
u.lmsg.content->ffn (u.lmsg.content->data,
u.lmsg.content->hint);
free (u.lmsg.content);
}
}
if (is_zcmsg())
{
zmq_assert(u.zclmsg.content->ffn);
// If the content is not shared, or if it is shared and the reference
// count has dropped to zero, deallocate it.
if (!(u.zclmsg.flags & msg_t::shared) ||
!u.zclmsg.content->refcnt.sub (1)) {
// We used "placement new" operator to initialize the reference
// counter so we call the destructor explicitly now.
u.zclmsg.content->refcnt.~atomic_counter_t ();
u.zclmsg.content->ffn (u.zclmsg.content->data,
u.zclmsg.content->hint);
}
}
if (u.base.metadata != NULL) {
if (u.base.metadata->drop_ref ()) {
LIBZMQ_DELETE(u.base.metadata);
}
u.base.metadata = NULL;
}
// Make the message invalid.
u.base.type = 0;
return 0;
}
int zmq::msg_t::move (msg_t &src_)
{
// Check the validity of the source.
if (unlikely (!src_.check ())) {
errno = EFAULT;
return -1;
}
int rc = close ();
if (unlikely (rc < 0))
return rc;
*this = src_;
rc = src_.init ();
if (unlikely (rc < 0))
return rc;
return 0;
}
int zmq::msg_t::copy (msg_t &src_)
{
// Check the validity of the source.
if (unlikely (!src_.check ())) {
errno = EFAULT;
return -1;
}
int rc = close ();
if (unlikely (rc < 0))
return rc;
if (src_.u.base.type == type_lmsg ) {
// One reference is added to shared messages. Non-shared messages
// are turned into shared messages and reference count is set to 2.
if (src_.u.lmsg.flags & msg_t::shared)
src_.u.lmsg.content->refcnt.add (1);
else {
src_.u.lmsg.flags |= msg_t::shared;
src_.u.lmsg.content->refcnt.set (2);
}
}
if (src_.is_zcmsg()) {
// One reference is added to shared messages. Non-shared messages
// are turned into shared messages and reference count is set to 2.
if (src_.u.zclmsg.flags & msg_t::shared)
src_.refcnt()->add (1);
else {
src_.u.zclmsg.flags |= msg_t::shared;
src_.refcnt()->set (2);
}
}
if (src_.u.base.metadata != NULL)
src_.u.base.metadata->add_ref ();
*this = src_;
return 0;
}
void *zmq::msg_t::data ()
{
// Check the validity of the message.
zmq_assert (check ());
switch (u.base.type) {
case type_vsm:
return u.vsm.data;
case type_lmsg:
return u.lmsg.content->data;
case type_cmsg:
return u.cmsg.data;
case type_zclmsg:
return u.zclmsg.content->data;
default:
zmq_assert (false);
return NULL;
}
}
size_t zmq::msg_t::size () const
{
// Check the validity of the message.
zmq_assert (check ());
switch (u.base.type) {
case type_vsm:
return u.vsm.size;
case type_lmsg:
return u.lmsg.content->size;
case type_zclmsg:
return u.zclmsg.content->size;
case type_cmsg:
return u.cmsg.size;
default:
zmq_assert (false);
return 0;
}
}
unsigned char zmq::msg_t::flags () const
{
return u.base.flags;
}
void zmq::msg_t::set_flags (unsigned char flags_)
{
u.base.flags |= flags_;
}
void zmq::msg_t::reset_flags (unsigned char flags_)
{
u.base.flags &= ~flags_;
}
zmq::metadata_t *zmq::msg_t::metadata () const
{
return u.base.metadata;
}
void zmq::msg_t::set_metadata (zmq::metadata_t *metadata_)
{
assert (metadata_ != NULL);
assert (u.base.metadata == NULL);
metadata_->add_ref ();
u.base.metadata = metadata_;
}
void zmq::msg_t::reset_metadata ()
{
if (u.base.metadata) {
if (u.base.metadata->drop_ref ()) {
LIBZMQ_DELETE(u.base.metadata);
}
u.base.metadata = NULL;
}
}
bool zmq::msg_t::is_routing_id () const
{
return (u.base.flags & routing_id) == routing_id;
}
bool zmq::msg_t::is_credential () const
{
return (u.base.flags & credential) == credential;
}
bool zmq::msg_t::is_delimiter () const
{
return u.base.type == type_delimiter;
}
bool zmq::msg_t::is_vsm () const
{
return u.base.type == type_vsm;
}
bool zmq::msg_t::is_cmsg () const
{
return u.base.type == type_cmsg;
}
bool zmq::msg_t::is_zcmsg() const
{
return u.base.type == type_zclmsg;
}
bool zmq::msg_t::is_join() const
{
return u.base.type == type_join;
}
bool zmq::msg_t::is_leave() const
{
return u.base.type == type_leave;
}
void zmq::msg_t::add_refs (int refs_)
{
zmq_assert (refs_ >= 0);
// Operation not supported for messages with metadata.
zmq_assert (u.base.metadata == NULL);
// No copies required.
if (!refs_)
return;
// VSMs, CMSGS and delimiters can be copied straight away. The only
// message type that needs special care are long messages.
if (u.base.type == type_lmsg || is_zcmsg() ) {
if (u.base.flags & msg_t::shared)
refcnt()->add (refs_);
else {
refcnt()->set (refs_ + 1);
u.base.flags |= msg_t::shared;
}
}
}
bool zmq::msg_t::rm_refs (int refs_)
{
zmq_assert (refs_ >= 0);
// Operation not supported for messages with metadata.
zmq_assert (u.base.metadata == NULL);
// No copies required.
if (!refs_)
return true;
// If there's only one reference close the message.
if ( (u.base.type != type_zclmsg && u.base.type != type_lmsg) || !(u.base.flags & msg_t::shared)) {
close ();
return false;
}
// The only message type that needs special care are long and zcopy messages.
if (u.base.type == type_lmsg && !u.lmsg.content->refcnt.sub(refs_)) {
// We used "placement new" operator to initialize the reference
// counter so we call the destructor explicitly now.
u.lmsg.content->refcnt.~atomic_counter_t ();
if (u.lmsg.content->ffn)
u.lmsg.content->ffn (u.lmsg.content->data, u.lmsg.content->hint);
free (u.lmsg.content);
return false;
}
if (is_zcmsg() && !u.zclmsg.content->refcnt.sub(refs_)) {
// storage for rfcnt is provided externally
if (u.zclmsg.content->ffn) {
u.zclmsg.content->ffn(u.zclmsg.content->data, u.zclmsg.content->hint);
}
return false;
}
return true;
}
uint32_t zmq::msg_t::get_routing_id ()
{
return u.base.routing_id;
}
int zmq::msg_t::set_routing_id (uint32_t routing_id_)
{
if (routing_id_) {
u.base.routing_id = routing_id_;
return 0;
}
errno = EINVAL;
return -1;
}
int zmq::msg_t::reset_routing_id ()
{
u.base.routing_id = 0;
return 0;
}
const char * zmq::msg_t::group ()
{
return u.base.group;
}
int zmq::msg_t::set_group (const char * group_)
{
return set_group (group_, strlen (group_));
}
int zmq::msg_t::set_group (const char * group_, size_t length_)
{
if (length_> ZMQ_GROUP_MAX_LENGTH)
{
errno = EINVAL;
return -1;
}
strncpy (u.base.group, group_, length_);
u.base.group[length_] = '\0';
return 0;
}
zmq::atomic_counter_t *zmq::msg_t::refcnt()
{
switch(u.base.type)
{
case type_lmsg:
return &u.lmsg.content->refcnt;
case type_zclmsg:
return &u.zclmsg.content->refcnt;
default:
zmq_assert(false);
return NULL;
}
}
+268
View File
@@ -0,0 +1,268 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MSG_HPP_INCLUDE__
#define __ZMQ_MSG_HPP_INCLUDE__
#include <stddef.h>
#include <stdio.h>
#include "config.hpp"
#include "err.hpp"
#include "fd.hpp"
#include "atomic_counter.hpp"
#include "metadata.hpp"
// Signature for free function to deallocate the message content.
// Note that it has to be declared as "C" so that it is the same as
// zmq_free_fn defined in zmq.h.
extern "C"
{
typedef void (msg_free_fn) (void *data, void *hint);
}
namespace zmq
{
// Note that this structure needs to be explicitly constructed
// (init functions) and destructed (close function).
class msg_t
{
public:
// Shared message buffer. Message data are either allocated in one
// continuous block along with this structure - thus avoiding one
// malloc/free pair or they are stored in user-supplied memory.
// In the latter case, ffn member stores pointer to the function to be
// used to deallocate the data. If the buffer is actually shared (there
// are at least 2 references to it) refcount member contains number of
// references.
struct content_t
{
void *data;
size_t size;
msg_free_fn *ffn;
void *hint;
zmq::atomic_counter_t refcnt;
};
// Message flags.
enum
{
more = 1, // Followed by more parts
command = 2, // Command frame (see ZMTP spec)
credential = 32,
routing_id = 64,
shared = 128
};
bool check () const;
int init();
int init (void* data, size_t size_,
msg_free_fn* ffn_, void* hint,
content_t* content_ = NULL);
int init_size (size_t size_);
int init_data (void *data_, size_t size_, msg_free_fn *ffn_,
void *hint_);
int init_external_storage(content_t* content_, void *data_, size_t size_,
msg_free_fn *ffn_, void *hint_);
int init_delimiter ();
int init_join ();
int init_leave ();
int close ();
int move (msg_t &src_);
int copy (msg_t &src_);
void *data ();
size_t size () const;
unsigned char flags () const;
void set_flags (unsigned char flags_);
void reset_flags (unsigned char flags_);
metadata_t *metadata () const;
void set_metadata (metadata_t *metadata_);
void reset_metadata ();
bool is_routing_id () const;
bool is_credential () const;
bool is_delimiter () const;
bool is_join () const;
bool is_leave () const;
bool is_vsm () const;
bool is_cmsg () const;
bool is_zcmsg() const;
uint32_t get_routing_id ();
int set_routing_id (uint32_t routing_id_);
int reset_routing_id ();
const char * group ();
int set_group (const char* group_);
int set_group (const char*, size_t length);
// After calling this function you can copy the message in POD-style
// refs_ times. No need to call copy.
void add_refs (int refs_);
// Removes references previously added by add_refs. If the number of
// references drops to 0, the message is closed and false is returned.
bool rm_refs (int refs_);
// Size in bytes of the largest message that is still copied around
// rather than being reference-counted.
enum { msg_t_size = 64 };
enum { max_vsm_size = msg_t_size - (sizeof (metadata_t *) +
3 +
16 +
sizeof (uint32_t))};
private:
zmq::atomic_counter_t* refcnt();
// Different message types.
enum type_t
{
type_min = 101,
// VSM messages store the content in the message itself
type_vsm = 101,
// LMSG messages store the content in malloc-ed memory
type_lmsg = 102,
// Delimiter messages are used in envelopes
type_delimiter = 103,
// CMSG messages point to constant data
type_cmsg = 104,
// zero-copy LMSG message for v2_decoder
type_zclmsg = 105,
// Join message for radio_dish
type_join = 106,
// Leave message for radio_dish
type_leave = 107,
type_max = 107
};
// Note that fields shared between different message types are not
// moved to the parent class (msg_t). This way we get tighter packing
// of the data. Shared fields can be accessed via 'base' member of
// the union.
union {
struct {
metadata_t *metadata;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} base;
struct {
metadata_t *metadata;
unsigned char data [max_vsm_size];
unsigned char size;
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} vsm;
struct {
metadata_t *metadata;
content_t *content;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
sizeof (content_t*) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} lmsg;
struct {
metadata_t *metadata;
content_t *content;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
sizeof (content_t*) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} zclmsg;
struct {
metadata_t *metadata;
void* data;
size_t size;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
sizeof (void*) +
sizeof (size_t) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} cmsg;
struct {
metadata_t *metadata;
unsigned char unused [msg_t_size - (sizeof (metadata_t *) +
2 +
16 +
sizeof (uint32_t))];
unsigned char type;
unsigned char flags;
char group [16];
uint32_t routing_id;
} delimiter;
} u;
};
inline int close_and_return (zmq::msg_t *msg, int echo)
{
// Since we abort on close failure we preserve errno for success case.
int err = errno;
const int rc = msg->close ();
errno_assert (rc == 0);
errno = err;
return echo;
}
inline int close_and_return (zmq::msg_t msg [], int count, int echo)
{
for (int i = 0; i < count; i++)
close_and_return (&msg [i], 0);
return echo;
}
}
#endif
+434
View File
@@ -0,0 +1,434 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <stdlib.h>
#include <new>
#include <algorithm>
#include "err.hpp"
#include "pipe.hpp"
#include "macros.hpp"
#include "mtrie.hpp"
zmq::mtrie_t::mtrie_t () :
pipes (0),
min (0),
count (0),
live_nodes (0)
{
}
zmq::mtrie_t::~mtrie_t ()
{
LIBZMQ_DELETE(pipes);
if (count == 1) {
zmq_assert (next.node);
LIBZMQ_DELETE(next.node);
}
else if (count > 1) {
for (unsigned short i = 0; i != count; ++i) {
LIBZMQ_DELETE(next.table[i]);
}
free (next.table);
}
}
bool zmq::mtrie_t::add (unsigned char *prefix_, size_t size_, pipe_t *pipe_)
{
return add_helper (prefix_, size_, pipe_);
}
bool zmq::mtrie_t::add_helper (unsigned char *prefix_, size_t size_,
pipe_t *pipe_)
{
// We are at the node corresponding to the prefix. We are done.
if (!size_) {
bool result = !pipes;
if (!pipes) {
pipes = new (std::nothrow) pipes_t;
alloc_assert (pipes);
}
pipes->insert (pipe_);
return result;
}
unsigned char c = *prefix_;
if (c < min || c >= min + count) {
// The character is out of range of currently handled
// characters. We have to extend the table.
if (!count) {
min = c;
count = 1;
next.node = NULL;
}
else
if (count == 1) {
unsigned char oldc = min;
mtrie_t *oldp = next.node;
count = (min < c ? c - min : min - c) + 1;
next.table = (mtrie_t**)
malloc (sizeof (mtrie_t*) * count);
alloc_assert (next.table);
for (unsigned short i = 0; i != count; ++i)
next.table [i] = 0;
min = std::min (min, c);
next.table [oldc - min] = oldp;
}
else
if (min < c) {
// The new character is above the current character range.
unsigned short old_count = count;
count = c - min + 1;
next.table = (mtrie_t**) realloc (next.table,
sizeof (mtrie_t*) * count);
alloc_assert (next.table);
for (unsigned short i = old_count; i != count; i++)
next.table [i] = NULL;
}
else {
// The new character is below the current character range.
unsigned short old_count = count;
count = (min + old_count) - c;
next.table = (mtrie_t**) realloc (next.table,
sizeof (mtrie_t*) * count);
alloc_assert (next.table);
memmove (next.table + min - c, next.table,
old_count * sizeof (mtrie_t*));
for (unsigned short i = 0; i != min - c; i++)
next.table [i] = NULL;
min = c;
}
}
// If next node does not exist, create one.
if (count == 1) {
if (!next.node) {
next.node = new (std::nothrow) mtrie_t;
alloc_assert (next.node);
++live_nodes;
}
return next.node->add_helper (prefix_ + 1, size_ - 1, pipe_);
}
else {
if (!next.table [c - min]) {
next.table [c - min] = new (std::nothrow) mtrie_t;
alloc_assert (next.table [c - min]);
++live_nodes;
}
return next.table [c - min]->add_helper (prefix_ + 1, size_ - 1, pipe_);
}
}
void zmq::mtrie_t::rm (pipe_t *pipe_,
void (*func_) (unsigned char *data_, size_t size_, void *arg_),
void *arg_, bool call_on_uniq_)
{
unsigned char *buff = NULL;
rm_helper (pipe_, &buff, 0, 0, func_, arg_, call_on_uniq_);
free (buff);
}
void zmq::mtrie_t::rm_helper (pipe_t *pipe_, unsigned char **buff_,
size_t buffsize_, size_t maxbuffsize_,
void (*func_) (unsigned char *data_, size_t size_, void *arg_),
void *arg_, bool call_on_uniq_)
{
// Remove the subscription from this node.
if (pipes && pipes->erase (pipe_)) {
if (!call_on_uniq_ || pipes->empty ()) {
func_ (*buff_, buffsize_, arg_);
}
if (pipes->empty ()) {
LIBZMQ_DELETE(pipes);
}
}
// Adjust the buffer.
if (buffsize_ >= maxbuffsize_) {
maxbuffsize_ = buffsize_ + 256;
*buff_ = (unsigned char*) realloc (*buff_, maxbuffsize_);
alloc_assert (*buff_);
}
// If there are no subnodes in the trie, return.
if (count == 0)
return;
// If there's one subnode (optimisation).
if (count == 1) {
(*buff_) [buffsize_] = min;
buffsize_++;
next.node->rm_helper (pipe_, buff_, buffsize_, maxbuffsize_,
func_, arg_, call_on_uniq_);
// Prune the node if it was made redundant by the removal
if (next.node->is_redundant ()) {
LIBZMQ_DELETE(next.node);
count = 0;
--live_nodes;
zmq_assert (live_nodes == 0);
}
return;
}
// If there are multiple subnodes.
//
// New min non-null character in the node table after the removal
unsigned char new_min = min + count - 1;
// New max non-null character in the node table after the removal
unsigned char new_max = min;
for (unsigned short c = 0; c != count; c++) {
(*buff_) [buffsize_] = min + c;
if (next.table [c]) {
next.table [c]->rm_helper (pipe_, buff_, buffsize_ + 1,
maxbuffsize_, func_, arg_, call_on_uniq_);
// Prune redundant nodes from the mtrie
if (next.table [c]->is_redundant ()) {
LIBZMQ_DELETE(next.table[c]);
zmq_assert (live_nodes > 0);
--live_nodes;
}
else {
// The node is not redundant, so it's a candidate for being
// the new min/max node.
//
// We loop through the node array from left to right, so the
// first non-null, non-redundant node encountered is the new
// minimum index. Conversely, the last non-redundant, non-null
// node encountered is the new maximum index.
if (c + min < new_min)
new_min = c + min;
if (c + min > new_max)
new_max = c + min;
}
}
}
zmq_assert (count > 1);
// Free the node table if it's no longer used.
if (live_nodes == 0) {
free (next.table);
next.table = NULL;
count = 0;
}
// Compact the node table if possible
else
if (live_nodes == 1) {
// If there's only one live node in the table we can
// switch to using the more compact single-node
// representation
zmq_assert (new_min == new_max);
zmq_assert (new_min >= min && new_min < min + count);
mtrie_t *node = next.table [new_min - min];
zmq_assert (node);
free (next.table);
next.node = node;
count = 1;
min = new_min;
}
else
if (new_min > min || new_max < min + count - 1) {
zmq_assert (new_max - new_min + 1 > 1);
mtrie_t **old_table = next.table;
zmq_assert (new_min > min || new_max < min + count - 1);
zmq_assert (new_min >= min);
zmq_assert (new_max <= min + count - 1);
zmq_assert (new_max - new_min + 1 < count);
count = new_max - new_min + 1;
next.table = (mtrie_t**) malloc (sizeof (mtrie_t*) * count);
alloc_assert (next.table);
memmove (next.table, old_table + (new_min - min),
sizeof (mtrie_t*) * count);
free (old_table);
min = new_min;
}
}
bool zmq::mtrie_t::rm (unsigned char *prefix_, size_t size_, pipe_t *pipe_)
{
return rm_helper (prefix_, size_, pipe_);
}
bool zmq::mtrie_t::rm_helper (unsigned char *prefix_, size_t size_,
pipe_t *pipe_)
{
if (!size_) {
if (pipes) {
pipes_t::size_type erased = pipes->erase (pipe_);
zmq_assert (erased == 1);
if (pipes->empty ()) {
LIBZMQ_DELETE(pipes);
}
}
return !pipes;
}
unsigned char c = *prefix_;
if (!count || c < min || c >= min + count)
return false;
mtrie_t *next_node =
count == 1 ? next.node : next.table [c - min];
if (!next_node)
return false;
bool ret = next_node->rm_helper (prefix_ + 1, size_ - 1, pipe_);
if (next_node->is_redundant ()) {
LIBZMQ_DELETE(next_node);
zmq_assert (count > 0);
if (count == 1) {
next.node = 0;
count = 0;
--live_nodes;
zmq_assert (live_nodes == 0);
}
else {
next.table [c - min] = 0;
zmq_assert (live_nodes > 1);
--live_nodes;
// Compact the table if possible
if (live_nodes == 1) {
// If there's only one live node in the table we can
// switch to using the more compact single-node
// representation
unsigned short i;
for (i = 0; i < count; ++i)
if (next.table [i])
break;
zmq_assert (i < count);
min += i;
count = 1;
mtrie_t *oldp = next.table [i];
free (next.table);
next.node = oldp;
}
else
if (c == min) {
// We can compact the table "from the left"
unsigned short i;
for (i = 1; i < count; ++i)
if (next.table [i])
break;
zmq_assert (i < count);
min += i;
count -= i;
mtrie_t **old_table = next.table;
next.table = (mtrie_t**) malloc (sizeof (mtrie_t*) * count);
alloc_assert (next.table);
memmove (next.table, old_table + i, sizeof (mtrie_t*) * count);
free (old_table);
}
else
if (c == min + count - 1) {
// We can compact the table "from the right"
unsigned short i;
for (i = 1; i < count; ++i)
if (next.table [count - 1 - i])
break;
zmq_assert (i < count);
count -= i;
mtrie_t **old_table = next.table;
next.table = (mtrie_t**) malloc (sizeof (mtrie_t*) * count);
alloc_assert (next.table);
memmove (next.table, old_table, sizeof (mtrie_t*) * count);
free (old_table);
}
}
}
return ret;
}
void zmq::mtrie_t::match (unsigned char *data_, size_t size_,
void (*func_) (pipe_t *pipe_, void *arg_), void *arg_)
{
mtrie_t *current = this;
while (true) {
// Signal the pipes attached to this node.
if (current->pipes) {
for (pipes_t::iterator it = current->pipes->begin ();
it != current->pipes->end (); ++it)
func_ (*it, arg_);
}
// If we are at the end of the message, there's nothing more to match.
if (!size_)
break;
// If there are no subnodes in the trie, return.
if (current->count == 0)
break;
// If there's one subnode (optimisation).
if (current->count == 1) {
if (data_ [0] != current->min)
break;
current = current->next.node;
data_++;
size_--;
continue;
}
// If there are multiple subnodes.
if (data_ [0] < current->min || data_ [0] >=
current->min + current->count)
break;
if (!current->next.table [data_ [0] - current->min])
break;
current = current->next.table [data_ [0] - current->min];
data_++;
size_--;
}
}
bool zmq::mtrie_t::is_redundant () const
{
return !pipes && live_nodes == 0;
}
+102
View File
@@ -0,0 +1,102 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MTRIE_HPP_INCLUDED__
#define __ZMQ_MTRIE_HPP_INCLUDED__
#include <stddef.h>
#include <set>
#include "stdint.hpp"
namespace zmq
{
class pipe_t;
// Multi-trie. Each node in the trie is a set of pointers to pipes.
class mtrie_t
{
public:
mtrie_t ();
~mtrie_t ();
// Add key to the trie. Returns true if it's a new subscription
// rather than a duplicate.
bool add (unsigned char *prefix_, size_t size_, zmq::pipe_t *pipe_);
// Remove all subscriptions for a specific peer from the trie.
// The call_on_uniq_ flag controls if the callback is invoked
// when there are no subscriptions left on some topics or on
// every removal.
void rm (zmq::pipe_t *pipe_,
void (*func_) (unsigned char *data_, size_t size_, void *arg_),
void *arg_, bool call_on_uniq_);
// Remove specific subscription from the trie. Return true is it was
// actually removed rather than de-duplicated.
bool rm (unsigned char *prefix_, size_t size_, zmq::pipe_t *pipe_);
// Signal all the matching pipes.
void match (unsigned char *data_, size_t size_,
void (*func_) (zmq::pipe_t *pipe_, void *arg_), void *arg_);
private:
bool add_helper (unsigned char *prefix_, size_t size_,
zmq::pipe_t *pipe_);
void rm_helper (zmq::pipe_t *pipe_, unsigned char **buff_,
size_t buffsize_, size_t maxbuffsize_,
void (*func_) (unsigned char *data_, size_t size_, void *arg_),
void *arg_, bool call_on_uniq_);
bool rm_helper (unsigned char *prefix_, size_t size_,
zmq::pipe_t *pipe_);
bool is_redundant () const;
typedef std::set <zmq::pipe_t*> pipes_t;
pipes_t *pipes;
unsigned char min;
unsigned short count;
unsigned short live_nodes;
union {
class mtrie_t *node;
class mtrie_t **table;
} next;
mtrie_t (const mtrie_t&);
const mtrie_t &operator = (const mtrie_t&);
};
}
#endif
+213
View File
@@ -0,0 +1,213 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MUTEX_HPP_INCLUDED__
#define __ZMQ_MUTEX_HPP_INCLUDED__
#include "err.hpp"
// Mutex class encapsulates OS mutex in a platform-independent way.
#ifdef ZMQ_HAVE_WINDOWS
#include "windows.hpp"
namespace zmq
{
class mutex_t
{
public:
inline mutex_t ()
{
InitializeCriticalSection (&cs);
}
inline ~mutex_t ()
{
DeleteCriticalSection (&cs);
}
inline void lock ()
{
EnterCriticalSection (&cs);
}
inline bool try_lock ()
{
return (TryEnterCriticalSection (&cs)) ? true : false;
}
inline void unlock ()
{
LeaveCriticalSection (&cs);
}
inline CRITICAL_SECTION* get_cs()
{
return &cs;
}
private:
CRITICAL_SECTION cs;
// Disable copy construction and assignment.
mutex_t (const mutex_t&);
void operator = (const mutex_t&);
};
}
#else
#include <pthread.h>
namespace zmq
{
class mutex_t
{
public:
inline mutex_t ()
{
int rc = pthread_mutexattr_init(&attr);
posix_assert (rc);
rc = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
posix_assert (rc);
rc = pthread_mutex_init (&mutex, &attr);
posix_assert (rc);
}
inline ~mutex_t ()
{
int rc = pthread_mutex_destroy (&mutex);
posix_assert (rc);
rc = pthread_mutexattr_destroy (&attr);
posix_assert (rc);
}
inline void lock ()
{
int rc = pthread_mutex_lock (&mutex);
posix_assert (rc);
}
inline bool try_lock ()
{
int rc = pthread_mutex_trylock (&mutex);
if (rc == EBUSY)
return false;
posix_assert (rc);
return true;
}
inline void unlock ()
{
int rc = pthread_mutex_unlock (&mutex);
posix_assert (rc);
}
inline pthread_mutex_t* get_mutex()
{
return &mutex;
}
private:
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
// Disable copy construction and assignment.
mutex_t (const mutex_t&);
const mutex_t &operator = (const mutex_t&);
};
}
#endif
namespace zmq
{
struct scoped_lock_t
{
scoped_lock_t (mutex_t& mutex_)
: mutex (mutex_)
{
mutex.lock ();
}
~scoped_lock_t ()
{
mutex.unlock ();
}
private:
mutex_t& mutex;
// Disable copy construction and assignment.
scoped_lock_t (const scoped_lock_t&);
const scoped_lock_t &operator = (const scoped_lock_t&);
};
struct scoped_optional_lock_t
{
scoped_optional_lock_t (mutex_t* mutex_)
: mutex (mutex_)
{
if(mutex != NULL)
mutex->lock ();
}
~scoped_optional_lock_t ()
{
if(mutex != NULL)
mutex->unlock ();
}
private:
mutex_t* mutex;
// Disable copy construction and assignment.
scoped_optional_lock_t (const scoped_lock_t&);
const scoped_optional_lock_t &operator = (const scoped_lock_t&);
};
}
#endif
+190
View File
@@ -0,0 +1,190 @@
#ifndef __ZMQ_NORM_ENGINE_HPP_INCLUDED__
#define __ZMQ_NORM_ENGINE_HPP_INCLUDED__
#if defined ZMQ_HAVE_NORM
#include "io_object.hpp"
#include "i_engine.hpp"
#include "options.hpp"
#include "v2_decoder.hpp"
#include "v2_encoder.hpp"
#include <normApi.h>
namespace zmq
{
class io_thread_t;
class session_base_t;
class norm_engine_t : public io_object_t, public i_engine
{
public:
norm_engine_t (zmq::io_thread_t *parent_, const options_t &options_);
~norm_engine_t ();
// create NORM instance, session, etc
int init(const char* network_, bool send, bool recv);
void shutdown();
// i_engine interface implementation.
// Plug the engine to the session.
virtual void plug (zmq::io_thread_t *io_thread_,
class session_base_t *session_);
// Terminate and deallocate the engine. Note that 'detached'
// events are not fired on termination.
virtual void terminate ();
// This method is called by the session to signalise that more
// messages can be written to the pipe.
virtual void restart_input ();
// This method is called by the session to signalise that there
// are messages to send available.
virtual void restart_output ();
virtual void zap_msg_available () {};
virtual const char *get_endpoint () const;
// i_poll_events interface implementation.
// (we only need in_event() for NormEvent notification)
// (i.e., don't have any output events or timers (yet))
void in_event ();
private:
void unplug();
void send_data();
void recv_data(NormObjectHandle stream);
enum {BUFFER_SIZE = 2048};
// Used to keep track of streams from multiple senders
class NormRxStreamState
{
public:
NormRxStreamState(NormObjectHandle normStream,
int64_t maxMsgSize);
~NormRxStreamState();
NormObjectHandle GetStreamHandle() const
{return norm_stream;}
bool Init();
void SetRxReady(bool state)
{rx_ready = state;}
bool IsRxReady() const
{return rx_ready;}
void SetSync(bool state)
{in_sync = state;}
bool InSync() const
{return in_sync;}
// These are used to feed data to decoder
// and its underlying "msg" buffer
char* AccessBuffer()
{return (char*)(buffer_ptr + buffer_count);}
size_t GetBytesNeeded() const
{return (buffer_size - buffer_count);}
void IncrementBufferCount(size_t count)
{buffer_count += count;}
msg_t* AccessMsg()
{return zmq_decoder->msg();}
// This invokes the decoder "decode" method
// returning 0 if more data is needed,
// 1 if the message is complete, If an error
// occurs the 'sync' is dropped and the
// decoder re-initialized
int Decode();
class List
{
public:
List();
~List();
void Append(NormRxStreamState& item);
void Remove(NormRxStreamState& item);
bool IsEmpty() const
{return (NULL == head);}
void Destroy();
class Iterator
{
public:
Iterator(const List& list);
NormRxStreamState* GetNextItem();
private:
NormRxStreamState* next_item;
};
friend class Iterator;
private:
NormRxStreamState* head;
NormRxStreamState* tail;
}; // end class zmq::norm_engine_t::NormRxStreamState::List
friend class List;
List* AccessList()
{return list;}
private:
NormObjectHandle norm_stream;
int64_t max_msg_size;
bool in_sync;
bool rx_ready;
v2_decoder_t* zmq_decoder;
bool skip_norm_sync;
unsigned char* buffer_ptr;
size_t buffer_size;
size_t buffer_count;
NormRxStreamState* prev;
NormRxStreamState* next;
NormRxStreamState::List* list;
}; // end class zmq::norm_engine_t::NormRxStreamState
session_base_t* zmq_session;
options_t options;
NormInstanceHandle norm_instance;
handle_t norm_descriptor_handle;
NormSessionHandle norm_session;
bool is_sender;
bool is_receiver;
// Sender state
msg_t tx_msg;
v2_encoder_t zmq_encoder; // for tx messages (we use v2 for now)
NormObjectHandle norm_tx_stream;
bool tx_first_msg;
bool tx_more_bit;
bool zmq_output_ready; // zmq has msg(s) to send
bool norm_tx_ready; // norm has tx queue vacancy
// TBD - maybe don't need buffer if can access zmq message buffer directly?
char tx_buffer[BUFFER_SIZE];
unsigned int tx_index;
unsigned int tx_len;
// Receiver state
// Lists of norm rx streams from remote senders
bool zmq_input_ready; // zmq ready to receive msg(s)
NormRxStreamState::List rx_pending_list; // rx streams waiting for data reception
NormRxStreamState::List rx_ready_list; // rx streams ready for NormStreamRead()
NormRxStreamState::List msg_ready_list; // rx streams w/ msg ready for push to zmq
}; // end class norm_engine_t
}
#endif // ZMQ_HAVE_NORM
#endif // !__ZMQ_NORM_ENGINE_HPP_INCLUDED__
+220
View File
@@ -0,0 +1,220 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include "err.hpp"
#include "msg.hpp"
#include "session_base.hpp"
#include "wire.hpp"
#include "null_mechanism.hpp"
zmq::null_mechanism_t::null_mechanism_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_) :
mechanism_base_t (session_, options_),
zap_client_t (session_, peer_address_, options_),
ready_command_sent (false),
error_command_sent (false),
ready_command_received (false),
error_command_received (false),
zap_request_sent (false),
zap_reply_received (false)
{
}
zmq::null_mechanism_t::~null_mechanism_t ()
{
}
int zmq::null_mechanism_t::next_handshake_command (msg_t *msg_)
{
if (ready_command_sent || error_command_sent) {
errno = EAGAIN;
return -1;
}
if (zap_required() && !zap_reply_received) {
if (zap_request_sent) {
errno = EAGAIN;
return -1;
}
int rc = session->zap_connect();
if (rc == -1)
{
session->get_socket()->event_handshake_failed_no_detail (
session->get_endpoint(),
EFAULT);
return -1;
}
send_zap_request ();
zap_request_sent = true;
// TODO actually, it is quite unlikely that we can read the ZAP
// reply already, but removing this has some strange side-effect
// (probably because the pipe's in_active flag is true until a read
// is attempted)
rc = receive_and_process_zap_reply ();
if (rc != 0)
return -1;
zap_reply_received = true;
}
if (zap_reply_received && status_code != "200") {
error_command_sent = true;
if (status_code != "300") {
const size_t status_code_len = 3;
const int rc = msg_->init_size (6 + 1 + status_code_len);
zmq_assert (rc == 0);
unsigned char *msg_data =
static_cast<unsigned char *> (msg_->data ());
memcpy (msg_data, "\5ERROR", 6);
msg_data[6] = status_code_len;
memcpy (msg_data + 7, status_code.c_str (), status_code_len);
return 0;
} else {
errno = EAGAIN;
return -1;
}
}
make_command_with_basic_properties (msg_, "\5READY", 6);
ready_command_sent = true;
return 0;
}
int zmq::null_mechanism_t::process_handshake_command (msg_t *msg_)
{
if (ready_command_received || error_command_received) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
const unsigned char *cmd_data =
static_cast <unsigned char *> (msg_->data ());
const size_t data_size = msg_->size ();
int rc = 0;
if (data_size >= 6 && !memcmp (cmd_data, "\5READY", 6))
rc = process_ready_command (cmd_data, data_size);
else
if (data_size >= 6 && !memcmp (cmd_data, "\5ERROR", 6))
rc = process_error_command (cmd_data, data_size);
else {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
rc = -1;
}
if (rc == 0) {
rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
}
return rc;
}
int zmq::null_mechanism_t::process_ready_command (
const unsigned char *cmd_data, size_t data_size)
{
ready_command_received = true;
return parse_metadata (cmd_data + 6, data_size - 6);
}
int zmq::null_mechanism_t::process_error_command (
const unsigned char *cmd_data, size_t data_size)
{
if (data_size < 7) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);
errno = EPROTO;
return -1;
}
const size_t error_reason_len = static_cast <size_t> (cmd_data [6]);
if (error_reason_len > data_size - 7) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);
errno = EPROTO;
return -1;
}
const char *error_reason = reinterpret_cast<const char *> (cmd_data) + 7;
handle_error_reason (error_reason, error_reason_len);
error_command_received = true;
return 0;
}
int zmq::null_mechanism_t::zap_msg_available ()
{
if (zap_reply_received) {
errno = EFSM;
return -1;
}
const int rc = receive_and_process_zap_reply ();
if (rc == 0)
zap_reply_received = true;
return rc == -1 ? -1 : 0;
}
zmq::mechanism_t::status_t zmq::null_mechanism_t::status () const
{
const bool command_sent =
ready_command_sent || error_command_sent;
const bool command_received =
ready_command_received || error_command_received;
if (ready_command_sent && ready_command_received)
return mechanism_t::ready;
else
if (command_sent && command_received)
return error;
else
return handshaking;
}
void zmq::null_mechanism_t::send_zap_request ()
{
zap_client_t::send_zap_request ("NULL", 4, NULL, NULL, 0);
}
+77
View File
@@ -0,0 +1,77 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_NULL_MECHANISM_HPP_INCLUDED__
#define __ZMQ_NULL_MECHANISM_HPP_INCLUDED__
#include "mechanism.hpp"
#include "options.hpp"
#include "zap_client.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
class null_mechanism_t : public zap_client_t
{
public:
null_mechanism_t (session_base_t *session_,
const std::string &peer_address,
const options_t &options_);
virtual ~null_mechanism_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual int zap_msg_available ();
virtual status_t status () const;
private:
bool ready_command_sent;
bool error_command_sent;
bool ready_command_received;
bool error_command_received;
bool zap_request_sent;
bool zap_reply_received;
int process_ready_command (
const unsigned char *cmd_data, size_t data_size);
int process_error_command (
const unsigned char *cmd_data, size_t data_size);
void send_zap_request ();
};
}
#endif
+476
View File
@@ -0,0 +1,476 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <string.h>
#include <stdarg.h>
#include "object.hpp"
#include "ctx.hpp"
#include "err.hpp"
#include "pipe.hpp"
#include "io_thread.hpp"
#include "session_base.hpp"
#include "socket_base.hpp"
zmq::object_t::object_t (ctx_t *ctx_, uint32_t tid_) :
ctx (ctx_),
tid (tid_)
{
}
zmq::object_t::object_t (object_t *parent_) :
ctx (parent_->ctx),
tid (parent_->tid)
{
}
zmq::object_t::~object_t ()
{
}
uint32_t zmq::object_t::get_tid ()
{
return tid;
}
void zmq::object_t::set_tid(uint32_t id)
{
tid = id;
}
zmq::ctx_t *zmq::object_t::get_ctx ()
{
return ctx;
}
void zmq::object_t::process_command (command_t &cmd_)
{
switch (cmd_.type) {
case command_t::activate_read:
process_activate_read ();
break;
case command_t::activate_write:
process_activate_write (cmd_.args.activate_write.msgs_read);
break;
case command_t::stop:
process_stop ();
break;
case command_t::plug:
process_plug ();
process_seqnum ();
break;
case command_t::own:
process_own (cmd_.args.own.object);
process_seqnum ();
break;
case command_t::attach:
process_attach (cmd_.args.attach.engine);
process_seqnum ();
break;
case command_t::bind:
process_bind (cmd_.args.bind.pipe);
process_seqnum ();
break;
case command_t::hiccup:
process_hiccup (cmd_.args.hiccup.pipe);
break;
case command_t::pipe_term:
process_pipe_term ();
break;
case command_t::pipe_term_ack:
process_pipe_term_ack ();
break;
case command_t::pipe_hwm:
process_pipe_hwm (cmd_.args.pipe_hwm.inhwm, cmd_.args.pipe_hwm.outhwm);
break;
case command_t::term_req:
process_term_req (cmd_.args.term_req.object);
break;
case command_t::term:
process_term (cmd_.args.term.linger);
break;
case command_t::term_ack:
process_term_ack ();
break;
case command_t::term_endpoint:
process_term_endpoint (cmd_.args.term_endpoint.endpoint);
break;
case command_t::reap:
process_reap (cmd_.args.reap.socket);
break;
case command_t::reaped:
process_reaped ();
break;
case command_t::inproc_connected:
process_seqnum ();
break;
case command_t::done:
default:
zmq_assert (false);
}
}
int zmq::object_t::register_endpoint (const char *addr_,
const endpoint_t &endpoint_)
{
return ctx->register_endpoint (addr_, endpoint_);
}
int zmq::object_t::unregister_endpoint (
const std::string &addr_, socket_base_t *socket_)
{
return ctx->unregister_endpoint (addr_, socket_);
}
void zmq::object_t::unregister_endpoints (socket_base_t *socket_)
{
return ctx->unregister_endpoints (socket_);
}
zmq::endpoint_t zmq::object_t::find_endpoint (const char *addr_)
{
return ctx->find_endpoint (addr_);
}
void zmq::object_t::pend_connection (const std::string &addr_,
const endpoint_t &endpoint_, pipe_t **pipes_)
{
ctx->pend_connection (addr_, endpoint_, pipes_);
}
void zmq::object_t::connect_pending (const char *addr_, zmq::socket_base_t *bind_socket_)
{
return ctx->connect_pending(addr_, bind_socket_);
}
void zmq::object_t::destroy_socket (socket_base_t *socket_)
{
ctx->destroy_socket (socket_);
}
zmq::io_thread_t *zmq::object_t::choose_io_thread (uint64_t affinity_)
{
return ctx->choose_io_thread (affinity_);
}
void zmq::object_t::send_stop ()
{
// 'stop' command goes always from administrative thread to
// the current object.
command_t cmd;
cmd.destination = this;
cmd.type = command_t::stop;
ctx->send_command (tid, cmd);
}
void zmq::object_t::send_plug (own_t *destination_, bool inc_seqnum_)
{
if (inc_seqnum_)
destination_->inc_seqnum ();
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::plug;
send_command (cmd);
}
void zmq::object_t::send_own (own_t *destination_, own_t *object_)
{
destination_->inc_seqnum ();
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::own;
cmd.args.own.object = object_;
send_command (cmd);
}
void zmq::object_t::send_attach (session_base_t *destination_,
i_engine *engine_, bool inc_seqnum_)
{
if (inc_seqnum_)
destination_->inc_seqnum ();
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::attach;
cmd.args.attach.engine = engine_;
send_command (cmd);
}
void zmq::object_t::send_bind (own_t *destination_, pipe_t *pipe_,
bool inc_seqnum_)
{
if (inc_seqnum_)
destination_->inc_seqnum ();
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::bind;
cmd.args.bind.pipe = pipe_;
send_command (cmd);
}
void zmq::object_t::send_activate_read (pipe_t *destination_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::activate_read;
send_command (cmd);
}
void zmq::object_t::send_activate_write (pipe_t *destination_,
uint64_t msgs_read_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::activate_write;
cmd.args.activate_write.msgs_read = msgs_read_;
send_command (cmd);
}
void zmq::object_t::send_hiccup (pipe_t *destination_, void *pipe_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::hiccup;
cmd.args.hiccup.pipe = pipe_;
send_command (cmd);
}
void zmq::object_t::send_pipe_term (pipe_t *destination_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::pipe_term;
send_command (cmd);
}
void zmq::object_t::send_pipe_term_ack (pipe_t *destination_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::pipe_term_ack;
send_command (cmd);
}
void zmq::object_t::send_pipe_hwm (pipe_t *destination_, int inhwm_, int outhwm_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::pipe_hwm;
cmd.args.pipe_hwm.inhwm = inhwm_;
cmd.args.pipe_hwm.outhwm = outhwm_;
send_command (cmd);
}
void zmq::object_t::send_term_req (own_t *destination_,
own_t *object_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::term_req;
cmd.args.term_req.object = object_;
send_command (cmd);
}
void zmq::object_t::send_term (own_t *destination_, int linger_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::term;
cmd.args.term.linger = linger_;
send_command (cmd);
}
void zmq::object_t::send_term_ack (own_t *destination_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::term_ack;
send_command (cmd);
}
void zmq::object_t::send_term_endpoint (own_t *destination_,
std::string *endpoint_)
{
command_t cmd;
cmd.destination = destination_;
cmd.type = command_t::term_endpoint;
cmd.args.term_endpoint.endpoint = endpoint_;
send_command (cmd);
}
void zmq::object_t::send_reap (class socket_base_t *socket_)
{
command_t cmd;
cmd.destination = ctx->get_reaper ();
cmd.type = command_t::reap;
cmd.args.reap.socket = socket_;
send_command (cmd);
}
void zmq::object_t::send_reaped ()
{
command_t cmd;
cmd.destination = ctx->get_reaper ();
cmd.type = command_t::reaped;
send_command (cmd);
}
void zmq::object_t::send_inproc_connected (zmq::socket_base_t *socket_)
{
command_t cmd;
cmd.destination = socket_;
cmd.type = command_t::inproc_connected;
send_command (cmd);
}
void zmq::object_t::send_done ()
{
command_t cmd;
cmd.destination = NULL;
cmd.type = command_t::done;
ctx->send_command (ctx_t::term_tid, cmd);
}
void zmq::object_t::process_stop ()
{
zmq_assert (false);
}
void zmq::object_t::process_plug ()
{
zmq_assert (false);
}
void zmq::object_t::process_own (own_t *)
{
zmq_assert (false);
}
void zmq::object_t::process_attach (i_engine *)
{
zmq_assert (false);
}
void zmq::object_t::process_bind (pipe_t *)
{
zmq_assert (false);
}
void zmq::object_t::process_activate_read ()
{
zmq_assert (false);
}
void zmq::object_t::process_activate_write (uint64_t)
{
zmq_assert (false);
}
void zmq::object_t::process_hiccup (void *)
{
zmq_assert (false);
}
void zmq::object_t::process_pipe_term ()
{
zmq_assert (false);
}
void zmq::object_t::process_pipe_term_ack ()
{
zmq_assert (false);
}
void zmq::object_t::process_pipe_hwm (int, int)
{
zmq_assert (false);
}
void zmq::object_t::process_term_req (own_t *)
{
zmq_assert (false);
}
void zmq::object_t::process_term (int)
{
zmq_assert (false);
}
void zmq::object_t::process_term_ack ()
{
zmq_assert (false);
}
void zmq::object_t::process_term_endpoint (std::string *)
{
zmq_assert (false);
}
void zmq::object_t::process_reap (class socket_base_t *)
{
zmq_assert (false);
}
void zmq::object_t::process_reaped ()
{
zmq_assert (false);
}
void zmq::object_t::process_seqnum ()
{
zmq_assert (false);
}
void zmq::object_t::send_command (command_t &cmd_)
{
ctx->send_command (cmd_.destination->get_tid (), cmd_);
}
+156
View File
@@ -0,0 +1,156 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_OBJECT_HPP_INCLUDED__
#define __ZMQ_OBJECT_HPP_INCLUDED__
#include <string>
#include "stdint.hpp"
namespace zmq
{
struct i_engine;
struct endpoint_t;
struct pending_connection_t;
struct command_t;
class ctx_t;
class pipe_t;
class socket_base_t;
class session_base_t;
class io_thread_t;
class own_t;
// Base class for all objects that participate in inter-thread
// communication.
class object_t
{
public:
object_t (zmq::ctx_t *ctx_, uint32_t tid_);
object_t (object_t *parent_);
virtual ~object_t ();
uint32_t get_tid ();
void set_tid(uint32_t id);
ctx_t *get_ctx ();
void process_command (zmq::command_t &cmd_);
void send_inproc_connected (zmq::socket_base_t *socket_);
void send_bind (zmq::own_t *destination_, zmq::pipe_t *pipe_, bool inc_seqnum_ = true);
protected:
// Using following function, socket is able to access global
// repository of inproc endpoints.
int register_endpoint (const char *addr_,
const zmq::endpoint_t &endpoint_);
int unregister_endpoint (
const std::string &addr_, socket_base_t *socket_);
void unregister_endpoints (zmq::socket_base_t *socket_);
zmq::endpoint_t find_endpoint (const char *addr_);
void pend_connection (const std::string &addr_,
const endpoint_t &endpoint, pipe_t **pipes_);
void connect_pending (const char *addr_, zmq::socket_base_t *bind_socket_);
void destroy_socket (zmq::socket_base_t *socket_);
// Logs an message.
void log (const char *format_, ...);
// Chooses least loaded I/O thread.
zmq::io_thread_t *choose_io_thread (uint64_t affinity_);
// Derived object can use these functions to send commands
// to other objects.
void send_stop ();
void send_plug (zmq::own_t *destination_,
bool inc_seqnum_ = true);
void send_own (zmq::own_t *destination_,
zmq::own_t *object_);
void send_attach (zmq::session_base_t *destination_,
zmq::i_engine *engine_, bool inc_seqnum_ = true);
void send_activate_read (zmq::pipe_t *destination_);
void send_activate_write (zmq::pipe_t *destination_,
uint64_t msgs_read_);
void send_hiccup (zmq::pipe_t *destination_, void *pipe_);
void send_pipe_term (zmq::pipe_t *destination_);
void send_pipe_term_ack (zmq::pipe_t *destination_);
void send_pipe_hwm (zmq::pipe_t *destination_, int inhwm_, int outhwm_);
void send_term_req (zmq::own_t *destination_,
zmq::own_t *object_);
void send_term (zmq::own_t *destination_, int linger_);
void send_term_ack (zmq::own_t *destination_);
void send_term_endpoint (own_t *destination_, std::string *endpoint_);
void send_reap (zmq::socket_base_t *socket_);
void send_reaped ();
void send_done ();
// These handlers can be overridden by the derived objects. They are
// called when command arrives from another thread.
virtual void process_stop ();
virtual void process_plug ();
virtual void process_own (zmq::own_t *object_);
virtual void process_attach (zmq::i_engine *engine_);
virtual void process_bind (zmq::pipe_t *pipe_);
virtual void process_activate_read ();
virtual void process_activate_write (uint64_t msgs_read_);
virtual void process_hiccup (void *pipe_);
virtual void process_pipe_term ();
virtual void process_pipe_term_ack ();
virtual void process_pipe_hwm (int inhwm_, int outhwm_);
virtual void process_term_req (zmq::own_t *object_);
virtual void process_term (int linger_);
virtual void process_term_ack ();
virtual void process_term_endpoint (std::string *endpoint_);
virtual void process_reap (zmq::socket_base_t *socket_);
virtual void process_reaped ();
// Special handler called after a command that requires a seqnum
// was processed. The implementation should catch up with its counter
// of processed commands here.
virtual void process_seqnum ();
private:
// Context provides access to the global state.
zmq::ctx_t *ctx;
// Thread ID of the thread the object belongs to.
uint32_t tid;
void send_command (command_t &cmd_);
object_t (const object_t&);
const object_t &operator = (const object_t&);
};
}
#endif
File diff suppressed because it is too large. Load diff
+251
View File
@@ -0,0 +1,251 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_OPTIONS_HPP_INCLUDED__
#define __ZMQ_OPTIONS_HPP_INCLUDED__
#include <string>
#include <vector>
#include <set>
#include "stddef.h"
#include "stdint.hpp"
#include "tcp_address.hpp"
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
#include <sys/types.h>
#endif
#ifdef ZMQ_HAVE_LOCAL_PEERCRED
#include <sys/ucred.h>
#endif
// Normal base 256 key is 32 bytes
#define CURVE_KEYSIZE 32
// Key encoded using Z85 is 40 bytes
#define CURVE_KEYSIZE_Z85 40
namespace zmq
{
struct options_t
{
options_t ();
int set_curve_key(uint8_t * destination, const void * optval_, size_t optvallen_);
int setsockopt (int option_, const void *optval_, size_t optvallen_);
int getsockopt (int option_, void *optval_, size_t *optvallen_) const;
bool is_valid (int option_) const;
// High-water marks for message pipes.
int sndhwm;
int rcvhwm;
// I/O thread affinity.
uint64_t affinity;
// Socket routing id.
unsigned char routing_id_size;
unsigned char routing_id [256];
// Maximum transfer rate [kb/s]. Default 100kb/s.
int rate;
// Reliability time interval [ms]. Default 10 seconds.
int recovery_ivl;
// Sets the time-to-live field in every multicast packet sent.
int multicast_hops;
// Sets the maximum transport data unit size in every multicast
// packet sent.
int multicast_maxtpdu;
// SO_SNDBUF and SO_RCVBUF to be passed to underlying transport sockets.
int sndbuf;
int rcvbuf;
// Type of service (containing DSCP and ECN socket options)
int tos;
// Socket type.
int type;
// Linger time, in milliseconds.
int linger;
// Maximum interval in milliseconds beyond which userspace will
// timeout connect().
// Default 0 (unused)
int connect_timeout;
// Maximum interval in milliseconds beyond which TCP will timeout
// retransmitted packets.
// Default 0 (unused)
int tcp_maxrt;
// Minimum interval between attempts to reconnect, in milliseconds.
// Default 100ms
int reconnect_ivl;
// Maximum interval between attempts to reconnect, in milliseconds.
// Default 0 (unused)
int reconnect_ivl_max;
// Maximum backlog for pending connections.
int backlog;
// Maximal size of message to handle.
int64_t maxmsgsize;
// The timeout for send/recv operations for this socket, in milliseconds.
int rcvtimeo;
int sndtimeo;
// If true, IPv6 is enabled (as well as IPv4)
bool ipv6;
// If 1, connecting pipes are not attached immediately, meaning a send()
// on a socket with only connecting pipes would block
int immediate;
// If 1, (X)SUB socket should filter the messages. If 0, it should not.
bool filter;
// If true, the subscription matching on (X)PUB and (X)SUB sockets
// is reversed. Messages are sent to and received by non-matching
// sockets.
bool invert_matching;
// If true, the routing id message is forwarded to the socket.
bool recv_routing_id;
// if true, router socket accepts non-zmq tcp connections
bool raw_socket;
bool raw_notify; // Provide connect notifications
// Address of SOCKS proxy
std::string socks_proxy_address;
// TCP keep-alive settings.
// Defaults to -1 = do not change socket options
int tcp_keepalive;
int tcp_keepalive_cnt;
int tcp_keepalive_idle;
int tcp_keepalive_intvl;
// TCP accept() filters
typedef std::vector <tcp_address_mask_t> tcp_accept_filters_t;
tcp_accept_filters_t tcp_accept_filters;
// IPC accept() filters
# if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
typedef std::set <uid_t> ipc_uid_accept_filters_t;
ipc_uid_accept_filters_t ipc_uid_accept_filters;
typedef std::set <gid_t> ipc_gid_accept_filters_t;
ipc_gid_accept_filters_t ipc_gid_accept_filters;
# endif
# if defined ZMQ_HAVE_SO_PEERCRED
typedef std::set <pid_t> ipc_pid_accept_filters_t;
ipc_pid_accept_filters_t ipc_pid_accept_filters;
# endif
// Security mechanism for all connections on this socket
int mechanism;
// If peer is acting as server for PLAIN or CURVE mechanisms
int as_server;
// ZAP authentication domain
std::string zap_domain;
// Security credentials for PLAIN mechanism
std::string plain_username;
std::string plain_password;
// Security credentials for CURVE mechanism
uint8_t curve_public_key [CURVE_KEYSIZE];
uint8_t curve_secret_key [CURVE_KEYSIZE];
uint8_t curve_server_key [CURVE_KEYSIZE];
// Principals for GSSAPI mechanism
std::string gss_principal;
std::string gss_service_principal;
// Name types GSSAPI principals
int gss_principal_nt;
int gss_service_principal_nt;
// If true, gss encryption will be disabled
bool gss_plaintext;
// ID of the socket.
int socket_id;
// If true, socket conflates outgoing/incoming messages.
// Applicable to dealer, push/pull, pub/sub socket types.
// Cannot receive multi-part messages.
// Ignores hwm
bool conflate;
// If connection handshake is not done after this many milliseconds,
// close socket. Default is 30 secs. 0 means no handshake timeout.
int handshake_ivl;
bool connected;
// If remote peer receives a PING message and doesn't receive another
// message within the ttl value, it should close the connection
// (measured in tenths of a second)
uint16_t heartbeat_ttl;
// Time in milliseconds between sending heartbeat PING messages.
int heartbeat_interval;
// Time in milliseconds to wait for a PING response before disconnecting
int heartbeat_timeout;
# if defined ZMQ_HAVE_VMCI
uint64_t vmci_buffer_size;
uint64_t vmci_buffer_min_size;
uint64_t vmci_buffer_max_size;
int vmci_connect_timeout;
# endif
// When creating a new ZMQ socket, if this option is set the value
// will be used as the File Descriptor instead of allocating a new
// one via the socket () system call.
int use_fd;
// Device to bind the underlying socket to, eg. VRF or interface
std::string bound_device;
// Enforce a non-empty ZAP domain requirement for PLAIN auth
bool zap_enforce_domain;
};
}
#endif
+216
View File
@@ -0,0 +1,216 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "own.hpp"
#include "err.hpp"
#include "io_thread.hpp"
zmq::own_t::own_t (class ctx_t *parent_, uint32_t tid_) :
object_t (parent_, tid_),
terminating (false),
sent_seqnum (0),
processed_seqnum (0),
owner (NULL),
term_acks (0)
{
}
zmq::own_t::own_t (io_thread_t *io_thread_, const options_t &options_) :
object_t (io_thread_),
options (options_),
terminating (false),
sent_seqnum (0),
processed_seqnum (0),
owner (NULL),
term_acks (0)
{
}
zmq::own_t::~own_t ()
{
}
void zmq::own_t::set_owner (own_t *owner_)
{
zmq_assert (!owner);
owner = owner_;
}
void zmq::own_t::inc_seqnum ()
{
// This function may be called from a different thread!
sent_seqnum.add (1);
}
void zmq::own_t::process_seqnum ()
{
// Catch up with counter of processed commands.
processed_seqnum++;
// We may have catched up and still have pending terms acks.
check_term_acks ();
}
void zmq::own_t::launch_child (own_t *object_)
{
// Specify the owner of the object.
object_->set_owner (this);
// Plug the object into the I/O thread.
send_plug (object_);
// Take ownership of the object.
send_own (this, object_);
}
void zmq::own_t::term_child (own_t *object_)
{
process_term_req (object_);
}
void zmq::own_t::process_term_req (own_t *object_)
{
// When shutting down we can ignore termination requests from owned
// objects. The termination request was already sent to the object.
if (terminating)
return;
// If I/O object is well and alive let's ask it to terminate.
owned_t::iterator it = std::find (owned.begin (), owned.end (), object_);
// If not found, we assume that termination request was already sent to
// the object so we can safely ignore the request.
if (it == owned.end ())
return;
owned.erase (it);
register_term_acks (1);
// Note that this object is the root of the (partial shutdown) thus, its
// value of linger is used, rather than the value stored by the children.
send_term (object_, options.linger);
}
void zmq::own_t::process_own (own_t *object_)
{
// If the object is already being shut down, new owned objects are
// immediately asked to terminate. Note that linger is set to zero.
if (terminating) {
register_term_acks (1);
send_term (object_, 0);
return;
}
// Store the reference to the owned object.
owned.insert (object_);
}
void zmq::own_t::terminate ()
{
// If termination is already underway, there's no point
// in starting it anew.
if (terminating)
return;
// As for the root of the ownership tree, there's no one to terminate it,
// so it has to terminate itself.
if (!owner) {
process_term (options.linger);
return;
}
// If I am an owned object, I'll ask my owner to terminate me.
send_term_req (owner, this);
}
bool zmq::own_t::is_terminating ()
{
return terminating;
}
void zmq::own_t::process_term (int linger_)
{
// Double termination should never happen.
zmq_assert (!terminating);
// Send termination request to all owned objects.
for (owned_t::iterator it = owned.begin (); it != owned.end (); ++it)
send_term (*it, linger_);
register_term_acks ((int) owned.size ());
owned.clear ();
// Start termination process and check whether by chance we cannot
// terminate immediately.
terminating = true;
check_term_acks ();
}
void zmq::own_t::register_term_acks (int count_)
{
term_acks += count_;
}
void zmq::own_t::unregister_term_ack ()
{
zmq_assert (term_acks > 0);
term_acks--;
// This may be a last ack we are waiting for before termination...
check_term_acks ();
}
void zmq::own_t::process_term_ack ()
{
unregister_term_ack ();
}
void zmq::own_t::check_term_acks ()
{
if (terminating && processed_seqnum == sent_seqnum.get () &&
term_acks == 0) {
// Sanity check. There should be no active children at this point.
zmq_assert (owned.empty ());
// The root object has nobody to confirm the termination to.
// Other nodes will confirm the termination to the owner.
if (owner)
send_term_ack (owner);
// Deallocate the resources.
process_destroy ();
}
}
void zmq::own_t::process_destroy ()
{
delete this;
}
+154
View File
@@ -0,0 +1,154 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_OWN_HPP_INCLUDED__
#define __ZMQ_OWN_HPP_INCLUDED__
#include <set>
#include <algorithm>
#include "object.hpp"
#include "options.hpp"
#include "atomic_counter.hpp"
#include "stdint.hpp"
namespace zmq
{
class ctx_t;
class io_thread_t;
// Base class for objects forming a part of ownership hierarchy.
// It handles initialisation and destruction of such objects.
class own_t : public object_t
{
public:
// Note that the owner is unspecified in the constructor.
// It'll be supplied later on when the object is plugged in.
// The object is not living within an I/O thread. It has it's own
// thread outside of 0MQ infrastructure.
own_t (zmq::ctx_t *parent_, uint32_t tid_);
// The object is living within I/O thread.
own_t (zmq::io_thread_t *io_thread_, const options_t &options_);
// When another owned object wants to send command to this object
// it calls this function to let it know it should not shut down
// before the command is delivered.
void inc_seqnum ();
// Use following two functions to wait for arbitrary events before
// terminating. Just add number of events to wait for using
// register_tem_acks functions. When event occurs, call
// remove_term_ack. When number of pending acks reaches zero
// object will be deallocated.
void register_term_acks (int count_);
void unregister_term_ack ();
protected:
// Launch the supplied object and become its owner.
void launch_child (own_t *object_);
// Terminate owned object
void term_child (own_t *object_);
// Ask owner object to terminate this object. It may take a while
// while actual termination is started. This function should not be
// called more than once.
void terminate ();
// Returns true if the object is in process of termination.
bool is_terminating ();
// Derived object destroys own_t. There's no point in allowing
// others to invoke the destructor. At the same time, it has to be
// virtual so that generic own_t deallocation mechanism destroys
// specific type of the owned object correctly.
virtual ~own_t ();
// Term handler is protected rather than private so that it can
// be intercepted by the derived class. This is useful to add custom
// steps to the beginning of the termination process.
void process_term (int linger_);
// A place to hook in when physical destruction of the object
// is to be delayed.
virtual void process_destroy ();
// Socket options associated with this object.
options_t options;
private:
// Set owner of the object
void set_owner (own_t *owner_);
// Handlers for incoming commands.
void process_own (own_t *object_);
void process_term_req (own_t *object_);
void process_term_ack ();
void process_seqnum ();
// Check whether all the pending term acks were delivered.
// If so, deallocate this object.
void check_term_acks ();
// True if termination was already initiated. If so, we can destroy
// the object if there are no more child objects or pending term acks.
bool terminating;
// Sequence number of the last command sent to this object.
atomic_counter_t sent_seqnum;
// Sequence number of the last command processed by this object.
uint64_t processed_seqnum;
// Socket owning this object. It's responsible for shutting down
// this object.
own_t *owner;
// List of all objects owned by this socket. We are responsible
// for deallocating them before we quit.
typedef std::set <own_t*> owned_t;
owned_t owned;
// Number of events we have to get before we can destroy the object.
int term_acks;
own_t (const own_t&);
const own_t &operator = (const own_t&);
};
}
#endif
+142
View File
@@ -0,0 +1,142 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "pair.hpp"
#include "err.hpp"
#include "pipe.hpp"
#include "msg.hpp"
zmq::pair_t::pair_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_),
pipe (NULL),
last_in (NULL)
{
options.type = ZMQ_PAIR;
}
zmq::pair_t::~pair_t ()
{
zmq_assert (!pipe);
}
void zmq::pair_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
zmq_assert (pipe_ != NULL);
// ZMQ_PAIR socket can only be connected to a single peer.
// The socket rejects any further connection requests.
if (pipe == NULL)
pipe = pipe_;
else
pipe_->terminate (false);
}
void zmq::pair_t::xpipe_terminated (pipe_t *pipe_)
{
if (pipe_ == pipe) {
if (last_in == pipe) {
saved_credential.set_deep_copy (last_in->get_credential ());
last_in = NULL;
}
pipe = NULL;
}
}
void zmq::pair_t::xread_activated (pipe_t *)
{
// There's just one pipe. No lists of active and inactive pipes.
// There's nothing to do here.
}
void zmq::pair_t::xwrite_activated (pipe_t *)
{
// There's just one pipe. No lists of active and inactive pipes.
// There's nothing to do here.
}
int zmq::pair_t::xsend (msg_t *msg_)
{
if (!pipe || !pipe->write (msg_)) {
errno = EAGAIN;
return -1;
}
if (!(msg_->flags () & msg_t::more))
pipe->flush ();
// Detach the original message from the data buffer.
int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
int zmq::pair_t::xrecv (msg_t *msg_)
{
// Deallocate old content of the message.
int rc = msg_->close ();
errno_assert (rc == 0);
if (!pipe || !pipe->read (msg_)) {
// Initialise the output parameter to be a 0-byte message.
rc = msg_->init ();
errno_assert (rc == 0);
errno = EAGAIN;
return -1;
}
last_in = pipe;
return 0;
}
bool zmq::pair_t::xhas_in ()
{
if (!pipe)
return false;
return pipe->check_read ();
}
bool zmq::pair_t::xhas_out ()
{
if (!pipe)
return false;
return pipe->check_write ();
}
const zmq::blob_t &zmq::pair_t::get_credential () const
{
return last_in? last_in->get_credential (): saved_credential;
}
+78
View File
@@ -0,0 +1,78 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_PAIR_HPP_INCLUDED__
#define __ZMQ_PAIR_HPP_INCLUDED__
#include "blob.hpp"
#include "socket_base.hpp"
#include "session_base.hpp"
namespace zmq
{
class ctx_t;
class msg_t;
class pipe_t;
class io_thread_t;
class pair_t :
public socket_base_t
{
public:
pair_t (zmq::ctx_t *parent_, uint32_t tid_, int sid);
~pair_t ();
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_, bool subscribe_to_all_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
const blob_t &get_credential () const;
void xread_activated (zmq::pipe_t *pipe_);
void xwrite_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
private:
zmq::pipe_t *pipe;
zmq::pipe_t *last_in;
blob_t saved_credential;
pair_t (const pair_t&);
const pair_t &operator = (const pair_t&);
};
}
#endif
+147
View File
@@ -0,0 +1,147 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_PGM_RECEIVER_HPP_INCLUDED__
#define __ZMQ_PGM_RECEIVER_HPP_INCLUDED__
#if defined ZMQ_HAVE_OPENPGM
#include <map>
#include <algorithm>
#include "io_object.hpp"
#include "i_engine.hpp"
#include "options.hpp"
#include "v1_decoder.hpp"
#include "pgm_socket.hpp"
namespace zmq
{
class io_thread_t;
class session_base_t;
class pgm_receiver_t : public io_object_t, public i_engine
{
public:
pgm_receiver_t (zmq::io_thread_t *parent_, const options_t &options_);
~pgm_receiver_t ();
int init (bool udp_encapsulation_, const char *network_);
// i_engine interface implementation.
void plug (zmq::io_thread_t *io_thread_,
zmq::session_base_t *session_);
void terminate ();
void restart_input ();
void restart_output ();
void zap_msg_available () {}
const char *get_endpoint () const;
// i_poll_events interface implementation.
void in_event ();
void timer_event (int token);
private:
// Unplug the engine from the session.
void unplug ();
// Decode received data (inpos, insize) and forward decoded
// messages to the session.
int process_input (v1_decoder_t *decoder);
// PGM is not able to move subscriptions upstream. Thus, drop all
// the pending subscriptions.
void drop_subscriptions ();
// RX timeout timer ID.
enum {rx_timer_id = 0xa1};
// RX timer is running.
bool has_rx_timer;
// If joined is true we are already getting messages from the peer.
// It it's false, we are getting data but still we haven't seen
// beginning of a message.
struct peer_info_t
{
bool joined;
v1_decoder_t *decoder;
};
struct tsi_comp
{
bool operator () (const pgm_tsi_t &ltsi,
const pgm_tsi_t &rtsi) const
{
uint32_t ll[2], rl[2];
memcpy (ll, &ltsi, sizeof (ll));
memcpy (rl, &rtsi, sizeof (rl));
return (ll[0] < rl[0]) || (ll[0] == rl[0] && ll[1] < rl[1]);
}
};
typedef std::map <pgm_tsi_t, peer_info_t, tsi_comp> peers_t;
peers_t peers;
// PGM socket.
pgm_socket_t pgm_socket;
// Socket options.
options_t options;
// Associated session.
zmq::session_base_t *session;
const pgm_tsi_t *active_tsi;
// Number of bytes not consumed by the decoder due to pipe overflow.
size_t insize;
// Pointer to data still waiting to be processed by the decoder.
const unsigned char *inpos;
// Poll handle associated with PGM socket.
handle_t socket_handle;
// Poll handle associated with engine PGM waiting pipe.
handle_t pipe_handle;
pgm_receiver_t (const pgm_receiver_t&);
const pgm_receiver_t &operator = (const pgm_receiver_t&);
};
}
#endif
#endif
+124
View File
@@ -0,0 +1,124 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_PGM_SENDER_HPP_INCLUDED__
#define __ZMQ_PGM_SENDER_HPP_INCLUDED__
#if defined ZMQ_HAVE_OPENPGM
#include "stdint.hpp"
#include "io_object.hpp"
#include "i_engine.hpp"
#include "options.hpp"
#include "pgm_socket.hpp"
#include "v1_encoder.hpp"
#include "msg.hpp"
namespace zmq
{
class io_thread_t;
class session_base_t;
class pgm_sender_t : public io_object_t, public i_engine
{
public:
pgm_sender_t (zmq::io_thread_t *parent_, const options_t &options_);
~pgm_sender_t ();
int init (bool udp_encapsulation_, const char *network_);
// i_engine interface implementation.
void plug (zmq::io_thread_t *io_thread_,
zmq::session_base_t *session_);
void terminate ();
void restart_input ();
void restart_output ();
void zap_msg_available () {}
const char *get_endpoint () const;
// i_poll_events interface implementation.
void in_event ();
void out_event ();
void timer_event (int token);
private:
// Unplug the engine from the session.
void unplug ();
// TX and RX timeout timer ID's.
enum {tx_timer_id = 0xa0, rx_timer_id = 0xa1};
// Timers are running.
bool has_tx_timer;
bool has_rx_timer;
session_base_t *session;
// Message encoder.
v1_encoder_t encoder;
msg_t msg;
// Keeps track of message boundaries.
bool more_flag;
// PGM socket.
pgm_socket_t pgm_socket;
// Socket options.
options_t options;
// Poll handle associated with PGM socket.
handle_t handle;
handle_t uplink_handle;
handle_t rdata_notify_handle;
handle_t pending_notify_handle;
// Output buffer from pgm_socket.
unsigned char *out_buffer;
// Output buffer size.
size_t out_buffer_size;
// Number of bytes in the buffer to be written to the socket.
// If zero, there are no data to be sent.
size_t write_size;
pgm_sender_t (const pgm_sender_t&);
const pgm_sender_t &operator = (const pgm_sender_t&);
};
}
#endif
#endif
+547
View File
@@ -0,0 +1,547 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <new>
#include <stddef.h>
#include "macros.hpp"
#include "pipe.hpp"
#include "err.hpp"
#include "ypipe.hpp"
#include "ypipe_conflate.hpp"
int zmq::pipepair (class object_t *parents_ [2], class pipe_t* pipes_ [2],
int hwms_ [2], bool conflate_ [2])
{
// Creates two pipe objects. These objects are connected by two ypipes,
// each to pass messages in one direction.
typedef ypipe_t <msg_t, message_pipe_granularity> upipe_normal_t;
typedef ypipe_conflate_t <msg_t> upipe_conflate_t;
pipe_t::upipe_t *upipe1;
if(conflate_ [0])
upipe1 = new (std::nothrow) upipe_conflate_t ();
else
upipe1 = new (std::nothrow) upipe_normal_t ();
alloc_assert (upipe1);
pipe_t::upipe_t *upipe2;
if(conflate_ [1])
upipe2 = new (std::nothrow) upipe_conflate_t ();
else
upipe2 = new (std::nothrow) upipe_normal_t ();
alloc_assert (upipe2);
pipes_ [0] = new (std::nothrow) pipe_t (parents_ [0], upipe1, upipe2,
hwms_ [1], hwms_ [0], conflate_ [0]);
alloc_assert (pipes_ [0]);
pipes_ [1] = new (std::nothrow) pipe_t (parents_ [1], upipe2, upipe1,
hwms_ [0], hwms_ [1], conflate_ [1]);
alloc_assert (pipes_ [1]);
pipes_ [0]->set_peer (pipes_ [1]);
pipes_ [1]->set_peer (pipes_ [0]);
return 0;
}
zmq::pipe_t::pipe_t (object_t *parent_, upipe_t *inpipe_, upipe_t *outpipe_,
int inhwm_, int outhwm_, bool conflate_) :
object_t (parent_),
inpipe (inpipe_),
outpipe (outpipe_),
in_active (true),
out_active (true),
hwm (outhwm_),
lwm (compute_lwm (inhwm_)),
inhwmboost(-1),
outhwmboost(-1),
msgs_read (0),
msgs_written (0),
peers_msgs_read (0),
peer (NULL),
sink (NULL),
state (active),
delay (true),
server_socket_routing_id (0),
conflate (conflate_)
{
}
zmq::pipe_t::~pipe_t ()
{
}
void zmq::pipe_t::set_peer (pipe_t *peer_)
{
// Peer can be set once only.
zmq_assert (!peer);
peer = peer_;
}
void zmq::pipe_t::set_event_sink (i_pipe_events *sink_)
{
// Sink can be set once only.
zmq_assert (!sink);
sink = sink_;
}
void zmq::pipe_t::set_server_socket_routing_id (uint32_t server_socket_routing_id_)
{
server_socket_routing_id = server_socket_routing_id_;
}
uint32_t zmq::pipe_t::get_server_socket_routing_id ()
{
return server_socket_routing_id;
}
void zmq::pipe_t::set_router_socket_routing_id (const blob_t &router_socket_routing_id_)
{
router_socket_routing_id.set_deep_copy (router_socket_routing_id_);
}
const zmq::blob_t &zmq::pipe_t::get_routing_id ()
{
return router_socket_routing_id;
}
const zmq::blob_t &zmq::pipe_t::get_credential () const
{
return credential;
}
bool zmq::pipe_t::check_read ()
{
if (unlikely (!in_active))
return false;
if (unlikely (state != active && state != waiting_for_delimiter))
return false;
// Check if there's an item in the pipe.
if (!inpipe->check_read ()) {
in_active = false;
return false;
}
// If the next item in the pipe is message delimiter,
// initiate termination process.
if (inpipe->probe (is_delimiter)) {
msg_t msg;
bool ok = inpipe->read (&msg);
zmq_assert (ok);
process_delimiter ();
return false;
}
return true;
}
bool zmq::pipe_t::read (msg_t *msg_)
{
if (unlikely (!in_active))
return false;
if (unlikely (state != active && state != waiting_for_delimiter))
return false;
read_message:
if (!inpipe->read (msg_)) {
in_active = false;
return false;
}
// If this is a credential, save a copy and receive next message.
if (unlikely (msg_->is_credential ())) {
const unsigned char *data = static_cast <const unsigned char *> (msg_->data ());
credential.set (data, msg_->size ());
const int rc = msg_->close ();
zmq_assert (rc == 0);
goto read_message;
}
// If delimiter was read, start termination process of the pipe.
if (msg_->is_delimiter ()) {
process_delimiter ();
return false;
}
if (!(msg_->flags () & msg_t::more) && !msg_->is_routing_id ())
msgs_read++;
if (lwm > 0 && msgs_read % lwm == 0)
send_activate_write (peer, msgs_read);
return true;
}
bool zmq::pipe_t::check_write ()
{
if (unlikely (!out_active || state != active))
return false;
bool full = !check_hwm();
if (unlikely (full)) {
out_active = false;
return false;
}
return true;
}
bool zmq::pipe_t::write (msg_t *msg_)
{
if (unlikely (!check_write ()))
return false;
bool more = msg_->flags () & msg_t::more ? true : false;
const bool is_routing_id = msg_->is_routing_id ();
outpipe->write (*msg_, more);
if (!more && !is_routing_id)
msgs_written++;
return true;
}
void zmq::pipe_t::rollback ()
{
// Remove incomplete message from the outbound pipe.
msg_t msg;
if (outpipe) {
while (outpipe->unwrite (&msg)) {
zmq_assert (msg.flags () & msg_t::more);
int rc = msg.close ();
errno_assert (rc == 0);
}
}
}
void zmq::pipe_t::flush ()
{
// The peer does not exist anymore at this point.
if (state == term_ack_sent)
return;
if (outpipe && !outpipe->flush ())
send_activate_read (peer);
}
void zmq::pipe_t::process_activate_read ()
{
if (!in_active && (state == active || state == waiting_for_delimiter)) {
in_active = true;
sink->read_activated (this);
}
}
void zmq::pipe_t::process_activate_write (uint64_t msgs_read_)
{
// Remember the peer's message sequence number.
peers_msgs_read = msgs_read_;
if (!out_active && state == active) {
out_active = true;
sink->write_activated (this);
}
}
void zmq::pipe_t::process_hiccup (void *pipe_)
{
// Destroy old outpipe. Note that the read end of the pipe was already
// migrated to this thread.
zmq_assert (outpipe);
outpipe->flush ();
msg_t msg;
while (outpipe->read (&msg)) {
if (!(msg.flags () & msg_t::more))
msgs_written--;
int rc = msg.close ();
errno_assert (rc == 0);
}
LIBZMQ_DELETE(outpipe);
// Plug in the new outpipe.
zmq_assert (pipe_);
outpipe = (upipe_t*) pipe_;
out_active = true;
// If appropriate, notify the user about the hiccup.
if (state == active)
sink->hiccuped (this);
}
void zmq::pipe_t::process_pipe_term ()
{
zmq_assert (state == active
|| state == delimiter_received
|| state == term_req_sent1);
// This is the simple case of peer-induced termination. If there are no
// more pending messages to read, or if the pipe was configured to drop
// pending messages, we can move directly to the term_ack_sent state.
// Otherwise we'll hang up in waiting_for_delimiter state till all
// pending messages are read.
if (state == active) {
if (delay)
state = waiting_for_delimiter;
else {
state = term_ack_sent;
outpipe = NULL;
send_pipe_term_ack (peer);
}
}
// Delimiter happened to arrive before the term command. Now we have the
// term command as well, so we can move straight to term_ack_sent state.
else
if (state == delimiter_received) {
state = term_ack_sent;
outpipe = NULL;
send_pipe_term_ack (peer);
}
// This is the case where both ends of the pipe are closed in parallel.
// We simply reply to the request by ack and continue waiting for our
// own ack.
else
if (state == term_req_sent1) {
state = term_req_sent2;
outpipe = NULL;
send_pipe_term_ack (peer);
}
}
void zmq::pipe_t::process_pipe_term_ack ()
{
// Notify the user that all the references to the pipe should be dropped.
zmq_assert (sink);
sink->pipe_terminated (this);
// In term_ack_sent and term_req_sent2 states there's nothing to do.
// Simply deallocate the pipe. In term_req_sent1 state we have to ack
// the peer before deallocating this side of the pipe.
// All the other states are invalid.
if (state == term_req_sent1) {
outpipe = NULL;
send_pipe_term_ack (peer);
}
else
zmq_assert (state == term_ack_sent || state == term_req_sent2);
// We'll deallocate the inbound pipe, the peer will deallocate the outbound
// pipe (which is an inbound pipe from its point of view).
// First, delete all the unread messages in the pipe. We have to do it by
// hand because msg_t doesn't have automatic destructor. Then deallocate
// the ypipe itself.
if (!conflate) {
msg_t msg;
while (inpipe->read (&msg)) {
int rc = msg.close ();
errno_assert (rc == 0);
}
}
LIBZMQ_DELETE(inpipe);
// Deallocate the pipe object
delete this;
}
void zmq::pipe_t::process_pipe_hwm (int inhwm_, int outhwm_)
{
set_hwms(inhwm_, outhwm_);
}
void zmq::pipe_t::set_nodelay ()
{
this->delay = false;
}
void zmq::pipe_t::terminate (bool delay_)
{
// Overload the value specified at pipe creation.
delay = delay_;
// If terminate was already called, we can ignore the duplicate invocation.
if (state == term_req_sent1 || state == term_req_sent2) {
return;
}
// If the pipe is in the final phase of async termination, it's going to
// closed anyway. No need to do anything special here.
else if (state == term_ack_sent) {
return;
}
// The simple sync termination case. Ask the peer to terminate and wait
// for the ack.
else if (state == active) {
send_pipe_term (peer);
state = term_req_sent1;
}
// There are still pending messages available, but the user calls
// 'terminate'. We can act as if all the pending messages were read.
else if (state == waiting_for_delimiter && !delay) {
// Drop any unfinished outbound messages.
rollback ();
outpipe = NULL;
send_pipe_term_ack (peer);
state = term_ack_sent;
}
// If there are pending messages still available, do nothing.
else if (state == waiting_for_delimiter) {
}
// We've already got delimiter, but not term command yet. We can ignore
// the delimiter and ack synchronously terminate as if we were in
// active state.
else if (state == delimiter_received) {
send_pipe_term (peer);
state = term_req_sent1;
}
// There are no other states.
else {
zmq_assert (false);
}
// Stop outbound flow of messages.
out_active = false;
if (outpipe) {
// Drop any unfinished outbound messages.
rollback ();
// Write the delimiter into the pipe. Note that watermarks are not
// checked; thus the delimiter can be written even when the pipe is full.
msg_t msg;
msg.init_delimiter ();
outpipe->write (msg, false);
flush ();
}
}
bool zmq::pipe_t::is_delimiter (const msg_t &msg_)
{
return msg_.is_delimiter ();
}
int zmq::pipe_t::compute_lwm (int hwm_)
{
// Compute the low water mark. Following point should be taken
// into consideration:
//
// 1. LWM has to be less than HWM.
// 2. LWM cannot be set to very low value (such as zero) as after filling
// the queue it would start to refill only after all the messages are
// read from it and thus unnecessarily hold the progress back.
// 3. LWM cannot be set to very high value (such as HWM-1) as it would
// result in lock-step filling of the queue - if a single message is
// read from a full queue, writer thread is resumed to write exactly one
// message to the queue and go back to sleep immediately. This would
// result in low performance.
//
// Given the 3. it would be good to keep HWM and LWM as far apart as
// possible to reduce the thread switching overhead to almost zero.
// Let's make LWM 1/2 of HWM.
int result = (hwm_ + 1) / 2;
return result;
}
void zmq::pipe_t::process_delimiter ()
{
zmq_assert (state == active
|| state == waiting_for_delimiter);
if (state == active)
state = delimiter_received;
else {
outpipe = NULL;
send_pipe_term_ack (peer);
state = term_ack_sent;
}
}
void zmq::pipe_t::hiccup ()
{
// If termination is already under way do nothing.
if (state != active)
return;
// We'll drop the pointer to the inpipe. From now on, the peer is
// responsible for deallocating it.
inpipe = NULL;
// Create new inpipe.
if (conflate)
inpipe = new (std::nothrow)ypipe_conflate_t <msg_t>();
else
inpipe = new (std::nothrow)ypipe_t <msg_t, message_pipe_granularity>();
alloc_assert (inpipe);
in_active = true;
// Notify the peer about the hiccup.
send_hiccup (peer, (void*) inpipe);
}
void zmq::pipe_t::set_hwms (int inhwm_, int outhwm_)
{
int in = inhwm_ + (inhwmboost > 0 ? inhwmboost : 0);
int out = outhwm_ + (outhwmboost > 0 ? outhwmboost : 0);
// if either send or recv side has hwm <= 0 it means infinite so we should set hwms infinite
if (inhwm_ <= 0 || inhwmboost == 0)
in = 0;
if (outhwm_ <= 0 || outhwmboost == 0)
out = 0;
lwm = compute_lwm(in);
hwm = out;
}
void zmq::pipe_t::set_hwms_boost(int inhwmboost_, int outhwmboost_)
{
inhwmboost = inhwmboost_;
outhwmboost = outhwmboost_;
}
bool zmq::pipe_t::check_hwm () const
{
bool full = hwm > 0 && msgs_written - peers_msgs_read >= uint64_t (hwm);
return( !full );
}
void zmq::pipe_t::send_hwms_to_peer(int inhwm_, int outhwm_)
{
send_pipe_hwm(peer, inhwm_, outhwm_);
}
+253
View File
@@ -0,0 +1,253 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_PIPE_HPP_INCLUDED__
#define __ZMQ_PIPE_HPP_INCLUDED__
#include "msg.hpp"
#include "ypipe_base.hpp"
#include "config.hpp"
#include "object.hpp"
#include "stdint.hpp"
#include "array.hpp"
#include "blob.hpp"
namespace zmq
{
class object_t;
class pipe_t;
// Create a pipepair for bi-directional transfer of messages.
// First HWM is for messages passed from first pipe to the second pipe.
// Second HWM is for messages passed from second pipe to the first pipe.
// Delay specifies how the pipe behaves when the peer terminates. If true
// pipe receives all the pending messages before terminating, otherwise it
// terminates straight away.
// If conflate is true, only the most recently arrived message could be
// read (older messages are discarded)
int pipepair (zmq::object_t *parents_ [2], zmq::pipe_t* pipes_ [2],
int hwms_ [2], bool conflate_ [2]);
struct i_pipe_events
{
virtual ~i_pipe_events () {}
virtual void read_activated (zmq::pipe_t *pipe_) = 0;
virtual void write_activated (zmq::pipe_t *pipe_) = 0;
virtual void hiccuped (zmq::pipe_t *pipe_) = 0;
virtual void pipe_terminated (zmq::pipe_t *pipe_) = 0;
};
// Note that pipe can be stored in three different arrays.
// The array of inbound pipes (1), the array of outbound pipes (2) and
// the generic array of pipes to be deallocated (3).
class pipe_t :
public object_t,
public array_item_t <1>,
public array_item_t <2>,
public array_item_t <3>
{
// This allows pipepair to create pipe objects.
friend int pipepair (zmq::object_t *parents_ [2], zmq::pipe_t* pipes_ [2],
int hwms_ [2], bool conflate_ [2]);
public:
// Specifies the object to send events to.
void set_event_sink (i_pipe_events *sink_);
// Pipe endpoint can store an routing ID to be used by its clients.
void set_server_socket_routing_id (uint32_t routing_id_);
uint32_t get_server_socket_routing_id ();
// Pipe endpoint can store an opaque ID to be used by its clients.
void set_router_socket_routing_id (const blob_t &identity_);
const blob_t &get_routing_id ();
const blob_t &get_credential () const;
// Returns true if there is at least one message to read in the pipe.
bool check_read ();
// Reads a message to the underlying pipe.
bool read (msg_t *msg_);
// Checks whether messages can be written to the pipe. If the pipe is
// closed or if writing the message would cause high watermark the
// function returns false.
bool check_write ();
// Writes a message to the underlying pipe. Returns false if the
// message does not pass check_write. If false, the message object
// retains ownership of its message buffer.
bool write (msg_t *msg_);
// Remove unfinished parts of the outbound message from the pipe.
void rollback ();
// Flush the messages downstream.
void flush ();
// Temporarily disconnects the inbound message stream and drops
// all the messages on the fly. Causes 'hiccuped' event to be generated
// in the peer.
void hiccup ();
// Ensure the pipe won't block on receiving pipe_term.
void set_nodelay ();
// Ask pipe to terminate. The termination will happen asynchronously
// and user will be notified about actual deallocation by 'terminated'
// event. If delay is true, the pending messages will be processed
// before actual shutdown.
void terminate (bool delay_);
// Set the high water marks.
void set_hwms (int inhwm_, int outhwm_);
// Set the boost to high water marks, used by inproc sockets so total hwm are sum of connect and bind sockets watermarks
void set_hwms_boost(int inhwmboost_, int outhwmboost_);
// send command to peer for notify the change of hwm
void send_hwms_to_peer(int inhwm_, int outhwm_);
// Returns true if HWM is not reached
bool check_hwm () const;
private:
// Type of the underlying lock-free pipe.
typedef ypipe_base_t <msg_t> upipe_t;
// Command handlers.
void process_activate_read ();
void process_activate_write (uint64_t msgs_read_);
void process_hiccup (void *pipe_);
void process_pipe_term ();
void process_pipe_term_ack ();
void process_pipe_hwm (int inhwm_, int outhwm_);
// Handler for delimiter read from the pipe.
void process_delimiter ();
// Constructor is private. Pipe can only be created using
// pipepair function.
pipe_t (object_t *parent_, upipe_t *inpipe_, upipe_t *outpipe_,
int inhwm_, int outhwm_, bool conflate_);
// Pipepair uses this function to let us know about
// the peer pipe object.
void set_peer (pipe_t *pipe_);
// Destructor is private. Pipe objects destroy themselves.
~pipe_t ();
// Underlying pipes for both directions.
upipe_t *inpipe;
upipe_t *outpipe;
// Can the pipe be read from / written to?
bool in_active;
bool out_active;
// High watermark for the outbound pipe.
int hwm;
// Low watermark for the inbound pipe.
int lwm;
// boosts for high and low watermarks, used with inproc sockets so hwm are sum of send and recv hmws on each side of pipe
int inhwmboost;
int outhwmboost;
// Number of messages read and written so far.
uint64_t msgs_read;
uint64_t msgs_written;
// Last received peer's msgs_read. The actual number in the peer
// can be higher at the moment.
uint64_t peers_msgs_read;
// The pipe object on the other side of the pipepair.
pipe_t *peer;
// Sink to send events to.
i_pipe_events *sink;
// States of the pipe endpoint:
// active: common state before any termination begins,
// delimiter_received: delimiter was read from pipe before
// term command was received,
// waiting_for_delimiter: term command was already received
// from the peer but there are still pending messages to read,
// term_ack_sent: all pending messages were already read and
// all we are waiting for is ack from the peer,
// term_req_sent1: 'terminate' was explicitly called by the user,
// term_req_sent2: user called 'terminate' and then we've got
// term command from the peer as well.
enum {
active,
delimiter_received,
waiting_for_delimiter,
term_ack_sent,
term_req_sent1,
term_req_sent2
} state;
// If true, we receive all the pending inbound messages before
// terminating. If false, we terminate immediately when the peer
// asks us to.
bool delay;
// Routing id of the writer. Used uniquely by the reader side.
blob_t router_socket_routing_id;
// Routing id of the writer. Used uniquely by the reader side.
int server_socket_routing_id;
// Pipe's credential.
blob_t credential;
// Returns true if the message is delimiter; false otherwise.
static bool is_delimiter (const msg_t &msg_);
// Computes appropriate low watermark from the given high watermark.
static int compute_lwm (int hwm_);
const bool conflate;
// Disable copying.
pipe_t (const pipe_t&);
const pipe_t &operator = (const pipe_t&);
};
}
#endif
+220
View File
@@ -0,0 +1,220 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include <string>
#include "msg.hpp"
#include "err.hpp"
#include "plain_client.hpp"
#include "session_base.hpp"
zmq::plain_client_t::plain_client_t (session_base_t *const session_,
const options_t &options_) :
mechanism_base_t (session_, options_),
state (sending_hello)
{
}
zmq::plain_client_t::~plain_client_t ()
{
}
int zmq::plain_client_t::next_handshake_command (msg_t *msg_)
{
int rc = 0;
switch (state) {
case sending_hello:
rc = produce_hello (msg_);
if (rc == 0)
state = waiting_for_welcome;
break;
case sending_initiate:
rc = produce_initiate (msg_);
if (rc == 0)
state = waiting_for_ready;
break;
default:
errno = EAGAIN;
rc = -1;
}
return rc;
}
int zmq::plain_client_t::process_handshake_command (msg_t *msg_)
{
const unsigned char *cmd_data =
static_cast <unsigned char *> (msg_->data ());
const size_t data_size = msg_->size ();
int rc = 0;
if (data_size >= 8 && !memcmp (cmd_data, "\7WELCOME", 8))
rc = process_welcome (cmd_data, data_size);
else
if (data_size >= 6 && !memcmp (cmd_data, "\5READY", 6))
rc = process_ready (cmd_data, data_size);
else
if (data_size >= 6 && !memcmp (cmd_data, "\5ERROR", 6))
rc = process_error (cmd_data, data_size);
else {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
rc = -1;
}
if (rc == 0) {
rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
}
return rc;
}
zmq::mechanism_t::status_t zmq::plain_client_t::status () const
{
if (state == ready)
return mechanism_t::ready;
else
if (state == error_command_received)
return mechanism_t::error;
else
return mechanism_t::handshaking;
}
int zmq::plain_client_t::produce_hello (msg_t *msg_) const
{
const std::string username = options.plain_username;
zmq_assert (username.length () < 256);
const std::string password = options.plain_password;
zmq_assert (password.length () < 256);
const size_t command_size = 6 + 1 + username.length ()
+ 1 + password.length ();
const int rc = msg_->init_size (command_size);
errno_assert (rc == 0);
unsigned char *ptr = static_cast <unsigned char *> (msg_->data ());
memcpy (ptr, "\x05HELLO", 6);
ptr += 6;
*ptr++ = static_cast <unsigned char> (username.length ());
memcpy (ptr, username.c_str (), username.length ());
ptr += username.length ();
*ptr++ = static_cast <unsigned char> (password.length ());
memcpy (ptr, password.c_str (), password.length ());
return 0;
}
int zmq::plain_client_t::process_welcome (
const unsigned char *cmd_data, size_t data_size)
{
LIBZMQ_UNUSED (cmd_data);
if (state != waiting_for_welcome) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
if (data_size != 8) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_WELCOME);
errno = EPROTO;
return -1;
}
state = sending_initiate;
return 0;
}
int zmq::plain_client_t::produce_initiate (msg_t *msg_) const
{
make_command_with_basic_properties (msg_, "\x08INITIATE", 9);
return 0;
}
int zmq::plain_client_t::process_ready (
const unsigned char *cmd_data, size_t data_size)
{
if (state != waiting_for_ready) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
const int rc = parse_metadata (cmd_data + 6, data_size - 6);
if (rc == 0)
state = ready;
else
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);
return rc;
}
int zmq::plain_client_t::process_error (
const unsigned char *cmd_data, size_t data_size)
{
if (state != waiting_for_welcome && state != waiting_for_ready) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
if (data_size < 7) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);
errno = EPROTO;
return -1;
}
const size_t error_reason_len = static_cast <size_t> (cmd_data [6]);
if (error_reason_len > data_size - 7) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_ERROR);
errno = EPROTO;
return -1;
}
const char *error_reason = reinterpret_cast<const char *> (cmd_data) + 7;
handle_error_reason (error_reason, error_reason_len);
state = error_command_received;
return 0;
}
+79
View File
@@ -0,0 +1,79 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_PLAIN_CLIENT_HPP_INCLUDED__
#define __ZMQ_PLAIN_CLIENT_HPP_INCLUDED__
#include "mechanism_base.hpp"
#include "options.hpp"
namespace zmq
{
class msg_t;
class plain_client_t : public mechanism_base_t
{
public:
plain_client_t (session_base_t *const session_,
const options_t &options_);
virtual ~plain_client_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
virtual status_t status () const;
private:
enum state_t {
sending_hello,
waiting_for_welcome,
sending_initiate,
waiting_for_ready,
error_command_received,
ready
};
state_t state;
int produce_hello (msg_t *msg_) const;
int produce_initiate (msg_t *msg_) const;
int process_welcome (
const unsigned char *cmd_data, size_t data_size);
int process_ready (
const unsigned char *cmd_data, size_t data_size);
int process_error (
const unsigned char *cmd_data, size_t data_size);
};
}
#endif
+253
View File
@@ -0,0 +1,253 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include <string>
#include "msg.hpp"
#include "session_base.hpp"
#include "err.hpp"
#include "plain_server.hpp"
#include "wire.hpp"
zmq::plain_server_t::plain_server_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_) :
mechanism_base_t (session_, options_),
zap_client_common_handshake_t (
session_, peer_address_, options_, sending_welcome)
{
// Note that there is no point to PLAIN if ZAP is not set up to handle the
// username and password, so if ZAP is not configured it is considered a
// failure.
// Given this is a backward-incompatible change, it's behind a socket
// option disabled by default.
if (options.zap_enforce_domain)
zmq_assert (zap_required());
}
zmq::plain_server_t::~plain_server_t ()
{
}
int zmq::plain_server_t::next_handshake_command (msg_t *msg_)
{
int rc = 0;
switch (state) {
case sending_welcome:
rc = produce_welcome (msg_);
if (rc == 0)
state = waiting_for_initiate;
break;
case sending_ready:
rc = produce_ready (msg_);
if (rc == 0)
state = ready;
break;
case sending_error:
rc = produce_error (msg_);
if (rc == 0)
state = error_sent;
break;
default:
errno = EAGAIN;
rc = -1;
}
return rc;
}
int zmq::plain_server_t::process_handshake_command (msg_t *msg_)
{
int rc = 0;
switch (state) {
case waiting_for_hello:
rc = process_hello (msg_);
break;
case waiting_for_initiate:
rc = process_initiate (msg_);
break;
default:
// TODO see comment in curve_server_t::process_handshake_command
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED);
errno = EPROTO;
rc = -1;
break;
}
if (rc == 0) {
rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
}
return rc;
}
int zmq::plain_server_t::process_hello (msg_t *msg_)
{
int rc = check_basic_command_structure (msg_);
if (rc == -1)
return -1;
const unsigned char *ptr = static_cast <unsigned char *> (msg_->data ());
size_t bytes_left = msg_->size ();
if (bytes_left < 6 || memcmp (ptr, "\x05HELLO", 6)) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
ptr += 6;
bytes_left -= 6;
if (bytes_left < 1) {
// PLAIN I: invalid PLAIN client, did not send username
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
errno = EPROTO;
return -1;
}
const uint8_t username_length = *ptr++;
bytes_left -= 1;
if (bytes_left < username_length) {
// PLAIN I: invalid PLAIN client, sent malformed username
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
errno = EPROTO;
return -1;
}
const std::string username = std::string ((char *) ptr, username_length);
ptr += username_length;
bytes_left -= username_length;
if (bytes_left < 1) {
// PLAIN I: invalid PLAIN client, did not send password
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
errno = EPROTO;
return -1;
}
const uint8_t password_length = *ptr++;
bytes_left -= 1;
if (bytes_left < password_length) {
// PLAIN I: invalid PLAIN client, sent malformed password
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
errno = EPROTO;
return -1;
}
const std::string password = std::string ((char *) ptr, password_length);
ptr += password_length;
bytes_left -= password_length;
if (bytes_left > 0) {
// PLAIN I: invalid PLAIN client, sent extraneous data
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
errno = EPROTO;
return -1;
}
// Use ZAP protocol (RFC 27) to authenticate the user.
rc = session->zap_connect ();
if (rc != 0) {
session->get_socket ()->event_handshake_failed_no_detail (
session->get_endpoint (), EFAULT);
return -1;
}
send_zap_request (username, password);
state = waiting_for_zap_reply;
// TODO actually, it is quite unlikely that we can read the ZAP
// reply already, but removing this has some strange side-effect
// (probably because the pipe's in_active flag is true until a read
// is attempted)
return receive_and_process_zap_reply () == -1 ? -1 : 0;
}
int zmq::plain_server_t::produce_welcome (msg_t *msg_) const
{
const int rc = msg_->init_size (8);
errno_assert (rc == 0);
memcpy (msg_->data (), "\x07WELCOME", 8);
return 0;
}
int zmq::plain_server_t::process_initiate (msg_t *msg_)
{
const unsigned char *ptr = static_cast <unsigned char *> (msg_->data ());
const size_t bytes_left = msg_->size ();
if (bytes_left < 9 || memcmp (ptr, "\x08INITIATE", 9)) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
const int rc = parse_metadata (ptr + 9, bytes_left - 9);
if (rc == 0)
state = sending_ready;
return rc;
}
int zmq::plain_server_t::produce_ready (msg_t *msg_) const
{
make_command_with_basic_properties (msg_, "\5READY", 6);
return 0;
}
int zmq::plain_server_t::produce_error (msg_t *msg_) const
{
zmq_assert (status_code.length () == 3);
const int rc = msg_->init_size (6 + 1 + status_code.length ());
zmq_assert (rc == 0);
char *msg_data = static_cast <char *> (msg_->data ());
memcpy (msg_data, "\5ERROR", 6);
msg_data [6] = (char) status_code.length ();
memcpy (msg_data + 7, status_code.c_str (), status_code.length ());
return 0;
}
void zmq::plain_server_t::send_zap_request (const std::string &username,
const std::string &password)
{
const uint8_t *credentials[] = {
reinterpret_cast<const uint8_t *> (username.c_str ()),
reinterpret_cast<const uint8_t *> (password.c_str ())};
size_t credentials_sizes[] = {username.size (), password.size ()};
zap_client_t::send_zap_request ("PLAIN", 5, credentials, credentials_sizes,
2);
}
+71
View File
@@ -0,0 +1,71 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_PLAIN_SERVER_HPP_INCLUDED__
#define __ZMQ_PLAIN_SERVER_HPP_INCLUDED__
#include "mechanism.hpp"
#include "options.hpp"
#include "zap_client.hpp"
namespace zmq
{
class msg_t;
class session_base_t;
class plain_server_t : public zap_client_common_handshake_t
{
public:
plain_server_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_);
virtual ~plain_server_t ();
// mechanism implementation
virtual int next_handshake_command (msg_t *msg_);
virtual int process_handshake_command (msg_t *msg_);
private:
int produce_welcome (msg_t *msg_) const;
int produce_ready (msg_t *msg_) const;
int produce_error (msg_t *msg_) const;
int process_hello (msg_t *msg_);
int process_initiate (msg_t *msg_);
void send_zap_request (const std::string &username,
const std::string &password);
};
}
#endif
+14
View File
@@ -0,0 +1,14 @@
#ifndef __PLATFORM_HPP_INCLUDED__
#define __PLATFORM_HPP_INCLUDED__
#define ZMQ_HAVE_WINDOWS
// MSVC build configuration is controlled via options exposed in the Visual
// Studio user interface. The option to use libsodium is not exposed in the
// user interface unless a sibling `libsodium` directory to that of this
// repository exists and contains the following files:
//
// \builds\msvc\vs2015\libsodium.import.props
// \builds\msvc\vs2015\libsodium.import.xml
#endif
+64
View File
@@ -0,0 +1,64 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_POLLER_HPP_INCLUDED__
#define __ZMQ_POLLER_HPP_INCLUDED__
#if defined ZMQ_USE_KQUEUE + defined ZMQ_USE_EPOLL \
+ defined ZMQ_USE_DEVPOLL + defined ZMQ_USE_POLLSET \
+ defined ZMQ_USE_POLL + defined ZMQ_USE_SELECT > 1
#error More than one of the ZMQ_USE_* macros defined
#endif
#if defined ZMQ_USE_KQUEUE
# include "kqueue.hpp"
#elif defined ZMQ_USE_EPOLL
# include "epoll.hpp"
#elif defined ZMQ_USE_DEVPOLL
# include "devpoll.hpp"
#elif defined ZMQ_USE_POLLSET
# include "pollset.hpp"
#elif defined ZMQ_USE_POLL
# include "poll.hpp"
#elif defined ZMQ_USE_SELECT
# include "select.hpp"
#elif defined ZMQ_HAVE_GNU
# define ZMQ_USE_POLL
# include "poll.hpp"
#else
# error None of the ZMQ_USE_* macros defined
#endif
#if defined ZMQ_USE_SELECT
#define ZMQ_POLL_BASED_ON_SELECT
#else
#define ZMQ_POLL_BASED_ON_POLL
#endif
#endif
Loaded 100 of 206 files, more files were not shown because too many files have changed in this diff. Show more