Compile zmq locally
This commit is contained in:
1 parent
e02dbdb176
commit
7fff6c424f
206 files changed
+40112
-116
No files matched your search
@@ -61,7 +61,6 @@ include(GroupSources)
|
||||
include(AutoCollect)
|
||||
|
||||
find_package(PCHSupport)
|
||||
find_package(ZMQ REQUIRED)
|
||||
find_package(MySQL)
|
||||
|
||||
if(NOT WITHOUT_GIT)
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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_);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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_);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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 ();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 ();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,12 @@
|
||||
|
||||
/******************************************************************************/
|
||||
/* 0MQ Internal Use */
|
||||
/******************************************************************************/
|
||||
|
||||
#define LIBZMQ_UNUSED(object) (void)object
|
||||
#define LIBZMQ_DELETE(p_object) {\
|
||||
delete p_object; \
|
||||
p_object = 0; \
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 ();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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_);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 <si,
|
||||
const pgm_tsi_t &rtsi) const
|
||||
{
|
||||
uint32_t ll[2], rl[2];
|
||||
memcpy (ll, <si, 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
|
||||
@@ -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
|
||||
@@ -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_);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
Reference in new issue
Block a user