1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-22 18:17:11 +02:00

Initial ZMQ bindings.

This commit is contained in:
Sandu Liviu Catalin
2021-02-02 19:07:02 +02:00
parent 82b7f75b80
commit fc9419677f
1092 changed files with 147348 additions and 92 deletions

143
vendor/ZMQ/src/address.cpp vendored Normal file
View File

@ -0,0 +1,143 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "macros.hpp"
#include "address.hpp"
#include "ctx.hpp"
#include "err.hpp"
#include "tcp_address.hpp"
#include "udp_address.hpp"
#include "ipc_address.hpp"
#include "tipc_address.hpp"
#include "ws_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_)
{
resolved.dummy = NULL;
}
zmq::address_t::~address_t ()
{
if (protocol == protocol_name::tcp) {
LIBZMQ_DELETE (resolved.tcp_addr);
} else if (protocol == protocol_name::udp) {
LIBZMQ_DELETE (resolved.udp_addr);
}
#ifdef ZMQ_HAVE_WS
else if (protocol == protocol_name::ws) {
LIBZMQ_DELETE (resolved.ws_addr);
}
#endif
#ifdef ZMQ_HAVE_WSS
else if (protocol == protocol_name::wss) {
LIBZMQ_DELETE (resolved.ws_addr);
}
#endif
#if defined ZMQ_HAVE_IPC
else if (protocol == protocol_name::ipc) {
LIBZMQ_DELETE (resolved.ipc_addr);
}
#endif
#if defined ZMQ_HAVE_TIPC
else if (protocol == protocol_name::tipc) {
LIBZMQ_DELETE (resolved.tipc_addr);
}
#endif
#if defined ZMQ_HAVE_VMCI
else if (protocol == protocol_name::vmci) {
LIBZMQ_DELETE (resolved.vmci_addr);
}
#endif
}
int zmq::address_t::to_string (std::string &addr_) const
{
if (protocol == protocol_name::tcp && resolved.tcp_addr)
return resolved.tcp_addr->to_string (addr_);
if (protocol == protocol_name::udp && resolved.udp_addr)
return resolved.udp_addr->to_string (addr_);
#ifdef ZMQ_HAVE_WS
if (protocol == protocol_name::ws && resolved.ws_addr)
return resolved.ws_addr->to_string (addr_);
#endif
#ifdef ZMQ_HAVE_WSS
if (protocol == protocol_name::wss && resolved.ws_addr)
return resolved.ws_addr->to_string (addr_);
#endif
#if defined ZMQ_HAVE_IPC
if (protocol == protocol_name::ipc && resolved.ipc_addr)
return resolved.ipc_addr->to_string (addr_);
#endif
#if defined ZMQ_HAVE_TIPC
if (protocol == protocol_name::tipc && resolved.tipc_addr)
return resolved.tipc_addr->to_string (addr_);
#endif
#if defined ZMQ_HAVE_VMCI
if (protocol == protocol_name::vmci && 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;
}
zmq::zmq_socklen_t zmq::get_socket_address (fd_t fd_,
socket_end_t socket_end_,
sockaddr_storage *ss_)
{
zmq_socklen_t sl = static_cast<zmq_socklen_t> (sizeof (*ss_));
const int rc =
socket_end_ == socket_end_local
? getsockname (fd_, reinterpret_cast<struct sockaddr *> (ss_), &sl)
: getpeername (fd_, reinterpret_cast<struct sockaddr *> (ss_), &sl);
return rc != 0 ? 0 : sl;
}

162
vendor/ZMQ/src/address.hpp vendored Normal file
View File

@ -0,0 +1,162 @@
/*
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 "fd.hpp"
#include <string>
#ifndef ZMQ_HAVE_WINDOWS
#include <sys/socket.h>
#else
#include <ws2tcpip.h>
#endif
namespace zmq
{
class ctx_t;
class tcp_address_t;
class udp_address_t;
class ws_address_t;
#ifdef ZMQ_HAVE_WSS
class wss_address_t;
#endif
#if defined ZMQ_HAVE_IPC
class ipc_address_t;
#endif
#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_VXWORKS
class tipc_address_t;
#endif
#if defined ZMQ_HAVE_VMCI
class vmci_address_t;
#endif
namespace protocol_name
{
static const char inproc[] = "inproc";
static const char tcp[] = "tcp";
static const char udp[] = "udp";
#ifdef ZMQ_HAVE_OPENPGM
static const char pgm[] = "pgm";
static const char epgm[] = "epgm";
#endif
#ifdef ZMQ_HAVE_NORM
static const char norm[] = "norm";
#endif
#ifdef ZMQ_HAVE_WS
static const char ws[] = "ws";
#endif
#ifdef ZMQ_HAVE_WSS
static const char wss[] = "wss";
#endif
#if defined ZMQ_HAVE_IPC
static const char ipc[] = "ipc";
#endif
#if defined ZMQ_HAVE_TIPC
static const char tipc[] = "tipc";
#endif
#if defined ZMQ_HAVE_VMCI
static const char vmci[] = "vmci";
#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 *const parent;
// Protocol specific resolved address
// All members must be pointers to allow for consistent initialization
union
{
void *dummy;
tcp_address_t *tcp_addr;
udp_address_t *udp_addr;
#ifdef ZMQ_HAVE_WS
ws_address_t *ws_addr;
#endif
#ifdef ZMQ_HAVE_WSS
wss_address_t *wss_addr;
#endif
#if defined ZMQ_HAVE_IPC
ipc_address_t *ipc_addr;
#endif
#if defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_VXWORKS
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;
};
#if defined(ZMQ_HAVE_HPUX) || defined(ZMQ_HAVE_VXWORKS) \
|| defined(ZMQ_HAVE_WINDOWS)
typedef int zmq_socklen_t;
#else
typedef socklen_t zmq_socklen_t;
#endif
enum socket_end_t
{
socket_end_local,
socket_end_remote
};
zmq_socklen_t
get_socket_address (fd_t fd_, socket_end_t socket_end_, sockaddr_storage *ss_);
template <typename T>
std::string get_socket_name (fd_t fd_, socket_end_t socket_end_)
{
struct sockaddr_storage ss;
const zmq_socklen_t sl = get_socket_address (fd_, socket_end_, &ss);
if (sl == 0) {
return std::string ();
}
const T addr (reinterpret_cast<struct sockaddr *> (&ss), sl);
std::string address_string;
addr.to_string (address_string);
return address_string;
}
}
#endif

140
vendor/ZMQ/src/array.hpp vendored Normal file
View File

@ -0,0 +1,140 @@
/*
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>
#include "macros.hpp"
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:
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.
virtual ~array_item_t () ZMQ_DEFAULT;
void set_array_index (int index_) { _array_index = index_; }
int get_array_index () const { return _array_index; }
private:
int _array_index;
ZMQ_NON_COPYABLE_NOR_MOVABLE (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;
array_t () ZMQ_DEFAULT;
size_type size () { return _items.size (); }
bool empty () { return _items.empty (); }
T *&operator[] (size_type index_) { return _items[index_]; }
void push_back (T *item_)
{
if (item_)
static_cast<item_t *> (item_)->set_array_index (
static_cast<int> (_items.size ()));
_items.push_back (item_);
}
void erase (T *item_)
{
erase (static_cast<item_t *> (item_)->get_array_index ());
}
void erase (size_type index_)
{
if (_items.empty ())
return;
static_cast<item_t *> (_items.back ())
->set_array_index (static_cast<int> (index_));
_items[index_] = _items.back ();
_items.pop_back ();
}
void swap (size_type index1_, size_type index2_)
{
if (_items[index1_])
static_cast<item_t *> (_items[index1_])
->set_array_index (static_cast<int> (index2_));
if (_items[index2_])
static_cast<item_t *> (_items[index2_])
->set_array_index (static_cast<int> (index1_));
std::swap (_items[index1_], _items[index2_]);
}
void clear () { _items.clear (); }
static size_type index (T *item_)
{
return static_cast<size_type> (
static_cast<item_t *> (item_)->get_array_index ());
}
private:
typedef std::vector<T *> items_t;
items_t _items;
ZMQ_NON_COPYABLE_NOR_MOVABLE (array_t)
};
}
#endif

235
vendor/ZMQ/src/atomic_counter.hpp vendored Normal file
View File

@ -0,0 +1,235 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__
#define __ZMQ_ATOMIC_COUNTER_HPP_INCLUDED__
#include "stdint.hpp"
#include "macros.hpp"
#if defined ZMQ_FORCE_MUTEXES
#define ZMQ_ATOMIC_COUNTER_MUTEX
#elif (defined __cplusplus && __cplusplus >= 201103L) \
|| (defined _MSC_VER && _MSC_VER >= 1900)
#define ZMQ_ATOMIC_COUNTER_CXX11
#elif defined ZMQ_HAVE_ATOMIC_INTRINSICS
#define ZMQ_ATOMIC_COUNTER_INTRINSIC
#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;
atomic_counter_t (integer_t value_ = 0) ZMQ_NOEXCEPT : _value (value_) {}
// Set counter _value (not thread-safe).
void set (integer_t value_) ZMQ_NOEXCEPT { _value = value_; }
// Atomic addition. Returns the old _value.
integer_t add (integer_t increment_) ZMQ_NOEXCEPT
{
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.
bool sub (integer_t decrement_) ZMQ_NOEXCEPT
{
#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
const 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
}
integer_t get () const ZMQ_NOEXCEPT { 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
ZMQ_NON_COPYABLE_NOR_MOVABLE (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

306
vendor/ZMQ/src/atomic_ptr.hpp vendored Normal file
View File

@ -0,0 +1,306 @@
/*
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__
#include "macros.hpp"
#if defined ZMQ_FORCE_MUTEXES
#define ZMQ_ATOMIC_PTR_MUTEX
#elif (defined __cplusplus && __cplusplus >= 201103L) \
|| (defined _MSC_VER && _MSC_VER >= 1900)
#define ZMQ_ATOMIC_PTR_CXX11
#elif defined ZMQ_HAVE_ATOMIC_INTRINSICS
#define ZMQ_ATOMIC_PTR_INTRINSIC
#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
{
#if !defined ZMQ_ATOMIC_PTR_CXX11
inline void *atomic_xchg_ptr (void **ptr_,
void *const val_
#if defined ZMQ_ATOMIC_PTR_MUTEX
,
mutex_t &_sync
#endif
) ZMQ_NOEXCEPT
{
#if defined ZMQ_ATOMIC_PTR_WINDOWS
return InterlockedExchangePointer ((PVOID *) ptr_, val_);
#elif defined ZMQ_ATOMIC_PTR_INTRINSIC
return __atomic_exchange_n (ptr_, val_, __ATOMIC_ACQ_REL);
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
return atomic_swap_ptr (ptr_, val_);
#elif defined ZMQ_ATOMIC_PTR_TILE
return arch_atomic_exchange (ptr_, val_);
#elif defined ZMQ_ATOMIC_PTR_X86
void *old;
__asm__ volatile("lock; xchg %0, %2"
: "=r"(old), "=m"(*ptr_)
: "m"(*ptr_), "0"(val_));
return old;
#elif defined ZMQ_ATOMIC_PTR_ARM
void *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 ();
void *old = *ptr_;
*ptr_ = val_;
_sync.unlock ();
return old;
#else
#error atomic_ptr is not implemented for this platform
#endif
}
inline void *atomic_cas (void *volatile *ptr_,
void *cmp_,
void *val_
#if defined ZMQ_ATOMIC_PTR_MUTEX
,
mutex_t &_sync
#endif
) ZMQ_NOEXCEPT
{
#if defined ZMQ_ATOMIC_PTR_WINDOWS
return InterlockedCompareExchangePointer ((volatile PVOID *) ptr_, val_,
cmp_);
#elif defined ZMQ_ATOMIC_PTR_INTRINSIC
void *old = cmp_;
__atomic_compare_exchange_n (ptr_, &old, val_, false, __ATOMIC_RELEASE,
__ATOMIC_ACQUIRE);
return old;
#elif defined ZMQ_ATOMIC_PTR_ATOMIC_H
return atomic_cas_ptr (ptr_, cmp_, val_);
#elif defined ZMQ_ATOMIC_PTR_TILE
return arch_atomic_val_compare_and_exchange (ptr_, cmp_, val_);
#elif defined ZMQ_ATOMIC_PTR_X86
void *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
void *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 ();
void *old = *ptr_;
if (*ptr_ == cmp_)
*ptr_ = val_;
_sync.unlock ();
return old;
#else
#error atomic_ptr is not implemented for this platform
#endif
}
#endif
// This class encapsulates several atomic operations on pointers.
template <typename T> class atomic_ptr_t
{
public:
// Initialise atomic pointer
atomic_ptr_t () ZMQ_NOEXCEPT { _ptr = NULL; }
// 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.
void set (T *ptr_) ZMQ_NOEXCEPT { _ptr = ptr_; }
// Perform atomic 'exchange pointers' operation. Pointer is set
// to the 'val_' value. Old value is returned.
T *xchg (T *val_) ZMQ_NOEXCEPT
{
#if defined ZMQ_ATOMIC_PTR_CXX11
return _ptr.exchange (val_, std::memory_order_acq_rel);
#else
return (T *) atomic_xchg_ptr ((void **) &_ptr, val_
#if defined ZMQ_ATOMIC_PTR_MUTEX
,
_sync
#endif
);
#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.
T *cas (T *cmp_, T *val_) ZMQ_NOEXCEPT
{
#if defined ZMQ_ATOMIC_PTR_CXX11
_ptr.compare_exchange_strong (cmp_, val_, std::memory_order_acq_rel);
return cmp_;
#else
return (T *) atomic_cas ((void **) &_ptr, cmp_, val_
#if defined ZMQ_ATOMIC_PTR_MUTEX
,
_sync
#endif
);
#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
ZMQ_NON_COPYABLE_NOR_MOVABLE (atomic_ptr_t)
#endif
};
struct atomic_value_t
{
atomic_value_t (const int value_) ZMQ_NOEXCEPT : _value (value_) {}
atomic_value_t (const atomic_value_t &src_) ZMQ_NOEXCEPT
: _value (src_.load ())
{
}
void store (const int value_) ZMQ_NOEXCEPT
{
#if defined ZMQ_ATOMIC_PTR_CXX11
_value.store (value_, std::memory_order_release);
#else
atomic_xchg_ptr ((void **) &_value, (void *) (ptrdiff_t) value_
#if defined ZMQ_ATOMIC_PTR_MUTEX
,
_sync
#endif
);
#endif
}
int load () const ZMQ_NOEXCEPT
{
#if defined ZMQ_ATOMIC_PTR_CXX11
return _value.load (std::memory_order_acquire);
#else
return (int) (ptrdiff_t) atomic_cas ((void **) &_value, 0, 0
#if defined ZMQ_ATOMIC_PTR_MUTEX
,
#if defined __SUNPRO_CC
const_cast<mutex_t &> (_sync)
#else
_sync
#endif
#endif
);
#endif
}
private:
#if defined ZMQ_ATOMIC_PTR_CXX11
std::atomic<int> _value;
#else
volatile ptrdiff_t _value;
#endif
#if defined ZMQ_ATOMIC_PTR_MUTEX
mutable mutex_t _sync;
#endif
private:
atomic_value_t &operator= (const atomic_value_t &src_);
};
}
// 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

205
vendor/ZMQ/src/blob.hpp vendored Normal file
View File

@ -0,0 +1,205 @@
/*
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 "macros.hpp"
#include "err.hpp"
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <ios>
#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
#if defined __SUNPRO_CC
template <typename K, typename V>
std::pair<const K, V> make_pair_fix_const (const K &k, const V &v)
{
return std::pair<const K, V> (k, v);
}
#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) insert (make_pair_fix_const (k, v))
#else
#define ZMQ_MAP_INSERT_OR_EMPLACE(k, v) insert (std::make_pair (k, v))
#endif
#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.
explicit blob_t (const size_t size_) :
_data (static_cast<unsigned char *> (malloc (size_))),
_size (size_),
_owned (true)
{
alloc_assert (_data);
}
// 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 (static_cast<unsigned char *> (malloc (size_))),
_size (size_),
_owned (true)
{
alloc_assert (_data);
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
{
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 = static_cast<unsigned char *> (malloc (other_._size));
alloc_assert (_data);
_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 = static_cast<unsigned char *> (malloc (size_));
alloc_assert (_data);
_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_) ZMQ_NOEXCEPT : _data (other_._data),
_size (other_._size),
_owned (other_._owned)
{
other_._owned = false;
}
blob_t &operator= (blob_t &&other_) ZMQ_NOEXCEPT
{
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

160
vendor/ZMQ/src/channel.cpp vendored Normal file
View File

@ -0,0 +1,160 @@
/*
Copyright (c) 2007-2020 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 "channel.hpp"
#include "err.hpp"
#include "pipe.hpp"
#include "msg.hpp"
zmq::channel_t::channel_t (class ctx_t *parent_, uint32_t tid_, int sid_) :
socket_base_t (parent_, tid_, sid_, true),
_pipe (NULL)
{
options.type = ZMQ_CHANNEL;
}
zmq::channel_t::~channel_t ()
{
zmq_assert (!_pipe);
}
void zmq::channel_t::xattach_pipe (pipe_t *pipe_,
bool subscribe_to_all_,
bool locally_initiated_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
LIBZMQ_UNUSED (locally_initiated_);
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::channel_t::xpipe_terminated (pipe_t *pipe_)
{
if (pipe_ == _pipe)
_pipe = NULL;
}
void zmq::channel_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::channel_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::channel_t::xsend (msg_t *msg_)
{
// CHANNEL sockets do not allow multipart data (ZMQ_SNDMORE)
if (msg_->flags () & msg_t::more) {
errno = EINVAL;
return -1;
}
if (!_pipe || !_pipe->write (msg_)) {
errno = EAGAIN;
return -1;
}
_pipe->flush ();
// Detach the original message from the data buffer.
const int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
int zmq::channel_t::xrecv (msg_t *msg_)
{
// Deallocate old content of the message.
int rc = msg_->close ();
errno_assert (rc == 0);
if (!_pipe) {
// Initialise the output parameter to be a 0-byte message.
rc = msg_->init ();
errno_assert (rc == 0);
errno = EAGAIN;
return -1;
}
// Drop any messages with more flag
bool read = _pipe->read (msg_);
while (read && msg_->flags () & msg_t::more) {
// drop all frames of the current multi-frame message
read = _pipe->read (msg_);
while (read && msg_->flags () & msg_t::more)
read = _pipe->read (msg_);
// get the new message
if (read)
read = _pipe->read (msg_);
}
if (!read) {
// Initialise the output parameter to be a 0-byte message.
rc = msg_->init ();
errno_assert (rc == 0);
errno = EAGAIN;
return -1;
}
return 0;
}
bool zmq::channel_t::xhas_in ()
{
if (!_pipe)
return false;
return _pipe->check_read ();
}
bool zmq::channel_t::xhas_out ()
{
if (!_pipe)
return false;
return _pipe->check_write ();
}

69
vendor/ZMQ/src/channel.hpp vendored Normal file
View File

@ -0,0 +1,69 @@
/*
Copyright (c) 2007-2020 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_CHANNEL_HPP_INCLUDED__
#define __ZMQ_CHANNEL_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 channel_t ZMQ_FINAL : public socket_base_t
{
public:
channel_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_);
~channel_t ();
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_,
bool subscribe_to_all_,
bool locally_initiated_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
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_NON_COPYABLE_NOR_MOVABLE (channel_t)
};
}
#endif

114
vendor/ZMQ/src/client.cpp vendored Normal file
View File

@ -0,0 +1,114 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "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;
options.can_send_hello_msg = true;
}
zmq::client_t::~client_t ()
{
}
void zmq::client_t::xattach_pipe (pipe_t *pipe_,
bool subscribe_to_all_,
bool locally_initiated_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
LIBZMQ_UNUSED (locally_initiated_);
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 ();
}
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_);
}

73
vendor/ZMQ/src/client.hpp vendored Normal file
View File

@ -0,0 +1,73 @@
/*
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 "fq.hpp"
#include "lb.hpp"
namespace zmq
{
class ctx_t;
class msg_t;
class pipe_t;
class io_thread_t;
class client_t ZMQ_FINAL : 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_,
bool locally_initiated_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (client_t)
};
}
#endif

277
vendor/ZMQ/src/clock.cpp vendored Normal file
View File

@ -0,0 +1,277 @@
/*
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>
#if defined(_M_ARM) || defined(_M_ARM64)
#include <arm_neon.h>
#endif
#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_VXWORKS
#include "timers.h"
#endif
#if defined ZMQ_HAVE_OSX
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
const 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
if (module != NULL)
::FreeLibrary (module);
#endif
return func;
}
static f_compatible_get_tick_count64 my_get_tick_count64 =
init_compatible_get_tick_count64 ();
#endif
const uint64_t usecs_per_msec = 1000;
const uint64_t usecs_per_sec = 1000000;
const uint64_t nsecs_per_usec = 1000;
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 () / usecs_per_msec)
#endif
{
}
uint64_t zmq::clock_t::now_us ()
{
#if defined ZMQ_HAVE_WINDOWS
// Get the high resolution counter's accuracy.
// While QueryPerformanceFrequency only needs to be called once, since its
// value does not change during runtime, we query it here since this is a
// static function. It might make sense to cache it, though.
LARGE_INTEGER ticks_per_second;
QueryPerformanceFrequency (&ticks_per_second);
// What time is it?
LARGE_INTEGER tick;
QueryPerformanceCounter (&tick);
// Convert the tick number into the number of seconds
// since the system was started.
const double ticks_div =
static_cast<double> (ticks_per_second.QuadPart) / usecs_per_sec;
return static_cast<uint64_t> (tick.QuadPart / ticks_div);
#elif defined HAVE_CLOCK_GETTIME \
&& (defined CLOCK_MONOTONIC || defined ZMQ_HAVE_VXWORKS)
// 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) {
#ifndef ZMQ_HAVE_VXWORKS
// Use POSIX gettimeofday function to get precise time.
struct timeval tv;
int rc = gettimeofday (&tv, NULL);
errno_assert (rc == 0);
return tv.tv_sec * usecs_per_sec + tv.tv_usec;
#endif
}
return tv.tv_sec * usecs_per_sec + tv.tv_nsec / nsecs_per_usec;
#elif defined HAVE_GETHRTIME
return gethrtime () / nsecs_per_usec;
#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 * usecs_per_sec + tv.tv_usec;
#endif
}
uint64_t zmq::clock_t::now_ms ()
{
const 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 () / usecs_per_msec;
#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 () / usecs_per_msec;
#endif
return _last_time;
}
uint64_t zmq::clock_t::rdtsc ()
{
#if (defined _MSC_VER && (defined _M_IX86 || defined _M_X64))
return __rdtsc ();
#elif defined(_MSC_VER) && defined(_M_ARM) // NC => added for windows ARM
return __rdpmccntr64 ();
#elif defined(_MSC_VER) && defined(_M_ARM64) // NC => added for windows ARM64
//return __rdpmccntr64 ();
//return __rdtscp (nullptr);
// todo: find proper implementation for ARM64
static uint64_t snCounter = 0;
return ++snCounter;
#elif (defined __GNUC__ && (defined __i386__ || defined __x86_64__))
uint32_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return static_cast<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 static_cast<uint64_t> (ts.tv_sec) * nsecs_per_usec * usecs_per_sec
+ ts.tv_nsec;
#endif
}

80
vendor/ZMQ/src/clock.hpp vendored Normal file
View File

@ -0,0 +1,80 @@
/*
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 "macros.hpp"
#include "stdint.hpp"
#if defined ZMQ_HAVE_OSX
// TODO this is not required in this file, but condition_variable.hpp includes
// clock.hpp to get these definitions
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef HAVE_CLOCK_GETTIME
#define HAVE_CLOCK_GETTIME
#endif
#include <mach/clock.h>
#include <mach/mach.h>
#include <time.h>
#include <sys/time.h>
#endif
namespace zmq
{
class clock_t
{
public:
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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (clock_t)
};
}
#endif

225
vendor/ZMQ/src/command.hpp vendored Normal file
View File

@ -0,0 +1,225 @@
/*
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"
#include "endpoint.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,
conn_failed,
pipe_peer_stats,
pipe_stats_publish,
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;
// Send application-side pipe count and ask to send monitor event
struct
{
uint64_t queue_count;
zmq::own_t *socket_base;
endpoint_uri_pair_t *endpoint_pair;
} pipe_peer_stats;
// Collate application thread and I/O thread pipe counts and endpoints
// and send as event
struct
{
uint64_t outbound_queue_count;
uint64_t inbound_queue_count;
endpoint_uri_pair_t *endpoint_pair;
} pipe_stats_publish;
// 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

75
vendor/ZMQ/src/compat.hpp vendored Normal file
View File

@ -0,0 +1,75 @@
/*
Copyright (c) 2020 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_COMPAT_HPP_INCLUDED__
#define __ZMQ_COMPAT_HPP_INCLUDED__
#include "precompiled.hpp"
#include <string.h>
#ifdef ZMQ_HAVE_WINDOWS
#define strcasecmp _stricmp
#define strtok_r strtok_s
#else
#ifndef ZMQ_HAVE_STRLCPY
#ifdef ZMQ_HAVE_LIBBSD
#include <bsd/string.h>
#else
static inline size_t
strlcpy (char *dest_, const char *src_, const size_t dest_size_)
{
size_t remain = dest_size_;
for (; remain && *src_; --remain, ++src_, ++dest_) {
*dest_ = *src_;
}
return dest_size_ - remain;
}
#endif
#endif
template <size_t size>
static inline int strcpy_s (char (&dest_)[size], const char *const src_)
{
const size_t res = strlcpy (dest_, src_, size);
return res >= size ? ERANGE : 0;
}
#endif
#ifndef HAVE_STRNLEN
static inline size_t strnlen (const char *s, size_t len)
{
for (size_t i = 0; i < len; i++) {
if (s[i] == '\0')
return i + 1;
}
return len;
}
#endif
#endif

313
vendor/ZMQ/src/condition_variable.hpp vendored Normal file
View File

@ -0,0 +1,313 @@
/*
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 "err.hpp"
#include "mutex.hpp"
// Condition variable class encapsulates OS mutex in a platform-independent way.
#if defined(ZMQ_USE_CV_IMPL_NONE)
namespace zmq
{
class condition_variable_t
{
public:
inline condition_variable_t () { zmq_assert (false); }
inline int wait (mutex_t *mutex_, int timeout_)
{
zmq_assert (false);
return -1;
}
inline void broadcast () { zmq_assert (false); }
ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)
};
}
#elif defined(ZMQ_USE_CV_IMPL_WIN32API)
#include "windows.hpp"
namespace zmq
{
class condition_variable_t
{
public:
inline condition_variable_t () { InitializeConditionVariable (&_cv); }
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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)
};
}
#elif defined(ZMQ_USE_CV_IMPL_STL11)
#include <condition_variable>
namespace zmq
{
class condition_variable_t
{
public:
condition_variable_t () ZMQ_DEFAULT;
int wait (mutex_t *mutex_, int timeout_)
{
// this assumes that the mutex mutex_ has been locked by the caller
int res = 0;
if (timeout_ == -1) {
_cv.wait (
*mutex_); // unlock mtx and wait cv.notify_all(), lock mtx after cv.notify_all()
} else if (_cv.wait_for (*mutex_, std::chrono::milliseconds (timeout_))
== std::cv_status::timeout) {
// time expired
errno = EAGAIN;
res = -1;
}
return res;
}
void broadcast ()
{
// this assumes that the mutex associated with _cv has been locked by the caller
_cv.notify_all ();
}
private:
std::condition_variable_any _cv;
ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)
};
}
#elif defined(ZMQ_USE_CV_IMPL_VXWORKS)
#include <sysLib.h>
namespace zmq
{
class condition_variable_t
{
public:
inline condition_variable_t () ZMQ_DEFAULT;
inline ~condition_variable_t ()
{
scoped_lock_t l (_listenersMutex);
for (size_t i = 0; i < _listeners.size (); i++) {
semDelete (_listeners[i]);
}
}
inline int wait (mutex_t *mutex_, int timeout_)
{
//Atomically releases lock, blocks the current executing thread,
//and adds it to the list of threads waiting on *this. The thread
//will be unblocked when broadcast() is executed.
//It may also be unblocked spuriously. When unblocked, regardless
//of the reason, lock is reacquired and wait exits.
SEM_ID sem = semBCreate (SEM_Q_PRIORITY, SEM_EMPTY);
{
scoped_lock_t l (_listenersMutex);
_listeners.push_back (sem);
}
mutex_->unlock ();
int rc;
if (timeout_ < 0)
rc = semTake (sem, WAIT_FOREVER);
else {
int ticksPerSec = sysClkRateGet ();
int timeoutTicks = (timeout_ * ticksPerSec) / 1000 + 1;
rc = semTake (sem, timeoutTicks);
}
{
scoped_lock_t l (_listenersMutex);
// remove sem from listeners
for (size_t i = 0; i < _listeners.size (); i++) {
if (_listeners[i] == sem) {
_listeners.erase (_listeners.begin () + i);
break;
}
}
semDelete (sem);
}
mutex_->lock ();
if (rc == 0)
return 0;
if (rc == S_objLib_OBJ_TIMEOUT) {
errno = EAGAIN;
return -1;
}
return -1;
}
inline void broadcast ()
{
scoped_lock_t l (_listenersMutex);
for (size_t i = 0; i < _listeners.size (); i++) {
semGive (_listeners[i]);
}
}
private:
mutex_t _listenersMutex;
std::vector<SEM_ID> _listeners;
ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)
};
}
#elif defined(ZMQ_USE_CV_IMPL_PTHREADS)
#include <pthread.h>
#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
#define ANDROID_LEGACY
extern "C" int pthread_cond_timedwait_monotonic_np (pthread_cond_t *,
pthread_mutex_t *,
const struct timespec *);
#endif
namespace zmq
{
class condition_variable_t
{
public:
inline condition_variable_t ()
{
pthread_condattr_t attr;
pthread_condattr_init (&attr);
#if !defined(ZMQ_HAVE_OSX) && !defined(ANDROID_LEGACY)
pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
#endif
int rc = pthread_cond_init (&_cond, &attr);
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;
#ifdef ZMQ_HAVE_OSX
timeout.tv_sec = 0;
timeout.tv_nsec = 0;
#else
rc = clock_gettime (CLOCK_MONOTONIC, &timeout);
posix_assert (rc);
#endif
timeout.tv_sec += timeout_ / 1000;
timeout.tv_nsec += (timeout_ % 1000) * 1000000;
if (timeout.tv_nsec >= 1000000000) {
timeout.tv_sec++;
timeout.tv_nsec -= 1000000000;
}
#ifdef ZMQ_HAVE_OSX
rc = pthread_cond_timedwait_relative_np (
&_cond, mutex_->get_mutex (), &timeout);
#elif defined(ANDROID_LEGACY)
rc = pthread_cond_timedwait_monotonic_np (
&_cond, mutex_->get_mutex (), &timeout);
#else
rc =
pthread_cond_timedwait (&_cond, mutex_->get_mutex (), &timeout);
#endif
} 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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (condition_variable_t)
};
}
#endif
#endif

89
vendor/ZMQ/src/config.hpp vendored Normal file
View File

@ -0,0 +1,89 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_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 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 batch size of packets forwarded by a ZMQ proxy.
// Increasing this value improves throughput at the expense of
// latency and fairness.
proxy_burst_size = 1000,
// 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

893
vendor/ZMQ/src/ctx.cpp vendored Normal file
View File

@ -0,0 +1,893 @@
/*
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
#ifdef ZMQ_USE_NSS
#include <nss.h>
#endif
#ifdef ZMQ_USE_GNUTLS
#include <gnutls/gnutls.h>
#endif
#define ZMQ_CTX_TAG_VALUE_GOOD 0xabadcafe
#define ZMQ_CTX_TAG_VALUE_BAD 0xdeadbeef
static 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),
_max_sockets (clipped_maxsocket (ZMQ_MAX_SOCKETS_DFLT)),
_max_msgsz (INT_MAX),
_io_thread_count (ZMQ_IO_THREADS_DFLT),
_blocky (true),
_ipv6 (false),
_zero_copy (true)
{
#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 ();
#ifdef ZMQ_USE_NSS
NSS_NoDB_Init (NULL);
#endif
#ifdef ZMQ_USE_GNUTLS
gnutls_global_init ();
#endif
}
bool zmq::ctx_t::check_tag () const
{
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.
const io_threads_t::size_type io_threads_size = _io_threads.size ();
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);
// The mailboxes in _slots themselves were deallocated with their
// corresponding io_thread/socket objects.
// De-initialise crypto library, if needed.
zmq::random_close ();
#ifdef ZMQ_USE_NSS
NSS_Shutdown ();
#endif
#ifdef ZMQ_USE_GNUTLS
gnutls_global_deinit ();
#endif
// Remove the tag, so that the object is considered dead.
_tag = ZMQ_CTX_TAG_VALUE_BAD;
}
bool zmq::ctx_t::valid () const
{
return _term_mailbox.valid ();
}
int zmq::ctx_t::terminate ()
{
_slot_sync.lock ();
const bool save_terminating = _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 (), end = copy.end ();
p != 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 = save_terminating;
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, size = _sockets.size (); i != size;
i++) {
_sockets[i]->get_mailbox ()->forked ();
}
_term_mailbox.forked ();
}
#endif
// Check whether termination was already underway, but interrupted and now
// restarted.
const 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, size = _sockets.size (); i != size;
i++) {
_sockets[i]->stop ();
}
if (_sockets.empty ())
_reaper->stop ();
}
_slot_sync.unlock ();
// Wait till reaper thread closes all the sockets.
command_t cmd;
const 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 (!_terminating) {
_terminating = true;
if (!_starting) {
// 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, size = _sockets.size (); i != size;
i++) {
_sockets[i]->stop ();
}
if (_sockets.empty ())
_reaper->stop ();
}
}
return 0;
}
int zmq::ctx_t::set (int option_, const void *optval_, size_t optvallen_)
{
const bool is_int = (optvallen_ == sizeof (int));
int value = 0;
if (is_int)
memcpy (&value, optval_, sizeof (int));
switch (option_) {
case ZMQ_MAX_SOCKETS:
if (is_int && value >= 1 && value == clipped_maxsocket (value)) {
scoped_lock_t locker (_opt_sync);
_max_sockets = value;
return 0;
}
break;
case ZMQ_IO_THREADS:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
_io_thread_count = value;
return 0;
}
break;
case ZMQ_IPV6:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
_ipv6 = (value != 0);
return 0;
}
break;
case ZMQ_BLOCKY:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
_blocky = (value != 0);
return 0;
}
break;
case ZMQ_MAX_MSGSZ:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
_max_msgsz = value < INT_MAX ? value : INT_MAX;
return 0;
}
break;
case ZMQ_ZERO_COPY_RECV:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
_zero_copy = (value != 0);
return 0;
}
break;
default: {
return thread_ctx_t::set (option_, optval_, optvallen_);
}
}
errno = EINVAL;
return -1;
}
int zmq::ctx_t::get (int option_, void *optval_, const size_t *optvallen_)
{
const bool is_int = (*optvallen_ == sizeof (int));
int *value = static_cast<int *> (optval_);
switch (option_) {
case ZMQ_MAX_SOCKETS:
if (is_int) {
*value = _max_sockets;
return 0;
}
break;
case ZMQ_SOCKET_LIMIT:
if (is_int) {
*value = clipped_maxsocket (65535);
return 0;
}
break;
case ZMQ_IO_THREADS:
if (is_int) {
*value = _io_thread_count;
return 0;
}
break;
case ZMQ_IPV6:
if (is_int) {
*value = _ipv6;
return 0;
}
break;
case ZMQ_BLOCKY:
if (is_int) {
*value = _blocky;
return 0;
}
break;
case ZMQ_MAX_MSGSZ:
if (is_int) {
*value = _max_msgsz;
return 0;
}
break;
case ZMQ_MSG_T_SIZE:
if (is_int) {
*value = sizeof (zmq_msg_t);
return 0;
}
break;
case ZMQ_ZERO_COPY_RECV:
if (is_int) {
*value = _zero_copy;
return 0;
}
break;
default: {
return thread_ctx_t::get (option_, optval_, optvallen_);
}
}
errno = EINVAL;
return -1;
}
int zmq::ctx_t::get (int option_)
{
int optval = 0;
size_t optvallen = sizeof (int);
if (get (option_, &optval, &optvallen) == 0)
return optval;
errno = EINVAL;
return -1;
}
bool zmq::ctx_t::start ()
{
// Initialise the array of mailboxes. Additional two slots are for
// zmq_ctx_term thread and reaper thread.
_opt_sync.lock ();
const int term_and_reaper_threads_count = 2;
const int mazmq = _max_sockets;
const int ios = _io_thread_count;
_opt_sync.unlock ();
const int slot_count = mazmq + ios + term_and_reaper_threads_count;
try {
_slots.reserve (slot_count);
_empty_slots.reserve (slot_count - term_and_reaper_threads_count);
}
catch (const std::bad_alloc &) {
errno = ENOMEM;
return false;
}
_slots.resize (term_and_reaper_threads_count);
// 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);
if (!_reaper) {
errno = ENOMEM;
goto fail_cleanup_slots;
}
if (!_reaper->get_mailbox ()->valid ())
goto fail_cleanup_reaper;
_slots[reaper_tid] = _reaper->get_mailbox ();
_reaper->start ();
// Create I/O thread objects and launch them.
_slots.resize (slot_count, NULL);
for (int i = term_and_reaper_threads_count;
i != ios + term_and_reaper_threads_count; i++) {
io_thread_t *io_thread = new (std::nothrow) io_thread_t (this, i);
if (!io_thread) {
errno = ENOMEM;
goto fail_cleanup_reaper;
}
if (!io_thread->get_mailbox ()->valid ()) {
delete io_thread;
goto fail_cleanup_reaper;
}
_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 = static_cast<int32_t> (_slots.size ()) - 1;
i >= static_cast<int32_t> (ios) + term_and_reaper_threads_count; i--) {
_empty_slots.push_back (i);
}
_starting = false;
return true;
fail_cleanup_reaper:
_reaper->stop ();
delete _reaper;
_reaper = NULL;
fail_cleanup_slots:
_slots.clear ();
return false;
}
zmq::socket_base_t *zmq::ctx_t::create_socket (int type_)
{
scoped_lock_t locker (_slot_sync);
// Once zmq_ctx_term() or zmq_ctx_shutdown() was called, we can't create
// new sockets.
if (_terminating) {
errno = ETERM;
return NULL;
}
if (unlikely (_starting)) {
if (!start ())
return NULL;
}
// If max_sockets limit was reached, return error.
if (_empty_slots.empty ()) {
errno = EMFILE;
return NULL;
}
// Choose a slot for the socket.
const uint32_t slot = _empty_slots.back ();
_empty_slots.pop_back ();
// Generate new unique socket ID.
const int sid = (static_cast<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.
const 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 () const
{
return _reaper;
}
zmq::thread_ctx_t::thread_ctx_t () :
_thread_priority (ZMQ_THREAD_PRIORITY_DFLT),
_thread_sched_policy (ZMQ_THREAD_SCHED_POLICY_DFLT)
{
}
void zmq::thread_ctx_t::start_thread (thread_t &thread_,
thread_fn *tfn_,
void *arg_,
const char *name_) const
{
thread_.setSchedulingParameters (_thread_priority, _thread_sched_policy,
_thread_affinity_cpus);
char namebuf[16] = "";
snprintf (namebuf, sizeof (namebuf), "%s%sZMQbg%s%s",
_thread_name_prefix.empty () ? "" : _thread_name_prefix.c_str (),
_thread_name_prefix.empty () ? "" : "/", name_ ? "/" : "",
name_ ? name_ : "");
thread_.start (tfn_, arg_, namebuf);
}
int zmq::thread_ctx_t::set (int option_, const void *optval_, size_t optvallen_)
{
const bool is_int = (optvallen_ == sizeof (int));
int value = 0;
if (is_int)
memcpy (&value, optval_, sizeof (int));
switch (option_) {
case ZMQ_THREAD_SCHED_POLICY:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
_thread_sched_policy = value;
return 0;
}
break;
case ZMQ_THREAD_AFFINITY_CPU_ADD:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
_thread_affinity_cpus.insert (value);
return 0;
}
break;
case ZMQ_THREAD_AFFINITY_CPU_REMOVE:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
if (0 == _thread_affinity_cpus.erase (value)) {
errno = EINVAL;
return -1;
}
return 0;
}
break;
case ZMQ_THREAD_PRIORITY:
if (is_int && value >= 0) {
scoped_lock_t locker (_opt_sync);
_thread_priority = value;
return 0;
}
break;
case ZMQ_THREAD_NAME_PREFIX:
// start_thread() allows max 16 chars for thread name
if (is_int) {
std::ostringstream s;
s << value;
scoped_lock_t locker (_opt_sync);
_thread_name_prefix = s.str ();
return 0;
} else if (optvallen_ > 0 && optvallen_ <= 16) {
scoped_lock_t locker (_opt_sync);
_thread_name_prefix.assign (static_cast<const char *> (optval_),
optvallen_);
return 0;
}
break;
}
errno = EINVAL;
return -1;
}
int zmq::thread_ctx_t::get (int option_,
void *optval_,
const size_t *optvallen_)
{
const bool is_int = (*optvallen_ == sizeof (int));
int *value = static_cast<int *> (optval_);
switch (option_) {
case ZMQ_THREAD_SCHED_POLICY:
if (is_int) {
scoped_lock_t locker (_opt_sync);
*value = _thread_sched_policy;
return 0;
}
break;
case ZMQ_THREAD_NAME_PREFIX:
if (is_int) {
scoped_lock_t locker (_opt_sync);
*value = atoi (_thread_name_prefix.c_str ());
return 0;
} else if (*optvallen_ >= _thread_name_prefix.size ()) {
scoped_lock_t locker (_opt_sync);
memcpy (optval_, _thread_name_prefix.data (),
_thread_name_prefix.size ());
return 0;
}
break;
}
errno = EINVAL;
return -1;
}
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, size = _io_threads.size (); i != size;
i++) {
if (!affinity_ || (affinity_ & (uint64_t (1) << i))) {
const 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 (std::string (addr_), endpoint_)
.second;
if (!inserted) {
errno = EADDRINUSE;
return -1;
}
return 0;
}
int zmq::ctx_t::unregister_endpoint (const std::string &addr_,
const socket_base_t *const 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 (const socket_base_t *const socket_)
{
scoped_lock_t locker (_endpoints_sync);
for (endpoints_t::iterator it = _endpoints.begin (),
end = _endpoints.end ();
it != end;) {
if (it->second.socket == socket_)
#if __cplusplus >= 201103L || (defined _MSC_VER && _MSC_VER >= 1700)
it = _endpoints.erase (it);
#else
_endpoints.erase (it++);
#endif
else
++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]};
const 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);
const 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_,
const 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);
}
if (!get_effective_conflate_option (pending_connection_.endpoint.options)) {
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);
}
#ifdef ZMQ_BUILD_DRAFT_API
if (bind_options_.can_recv_disconnect_msg
&& !bind_options_.disconnect_msg.empty ())
pending_connection_.connect_pipe->set_disconnect_msg (
bind_options_.disconnect_msg);
#endif
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 ()) {
send_routing_id (pending_connection_.bind_pipe, bind_options_);
}
#ifdef ZMQ_BUILD_DRAFT_API
// If set, send the hello msg of the bind socket to the pending connection.
if (bind_options_.can_send_hello_msg
&& bind_options_.hello_msg.size () > 0) {
send_hello_msg (pending_connection_.bind_pipe, bind_options_);
}
#endif
}
#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;

271
vendor/ZMQ/src/ctx.hpp vendored Normal file
View File

@ -0,0 +1,271 @@
/*
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;
};
class thread_ctx_t
{
public:
thread_ctx_t ();
// Start a new thread with proper scheduling parameters.
void start_thread (thread_t &thread_,
thread_fn *tfn_,
void *arg_,
const char *name_ = NULL) const;
int set (int option_, const void *optval_, size_t optvallen_);
int get (int option_, void *optval_, const size_t *optvallen_);
protected:
// Synchronisation of access to context options.
mutex_t _opt_sync;
private:
// Thread parameters.
int _thread_priority;
int _thread_sched_policy;
std::set<int> _thread_affinity_cpus;
std::string _thread_name_prefix;
};
// Context object encapsulates all the global state associated with
// the library.
class ctx_t ZMQ_FINAL : public thread_ctx_t
{
public:
// Create the context object.
ctx_t ();
// Returns false if object is not a context.
bool check_tag () const;
// 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_, const void *optval_, size_t optvallen_);
int get (int option_, void *optval_, const size_t *optvallen_);
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_);
// 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 () const;
// Management of inproc endpoints.
int register_endpoint (const char *addr_, const endpoint_t &endpoint_);
int unregister_endpoint (const std::string &addr_,
const socket_base_t *socket_);
void unregister_endpoints (const 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 ();
bool valid () const;
private:
bool start ();
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.
std::vector<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;
// Should we use zero copy message decoding in this context?
bool _zero_copy;
ZMQ_NON_COPYABLE_NOR_MOVABLE (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
};
static void
connect_inproc_sockets (zmq::socket_base_t *bind_socket_,
const 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

287
vendor/ZMQ/src/curve_client.cpp vendored Normal file
View File

@ -0,0 +1,287 @@
/*
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"
#ifdef ZMQ_HAVE_CURVE
#include "msg.hpp"
#include "session_base.hpp"
#include "err.hpp"
#include "curve_client.hpp"
#include "wire.hpp"
#include "curve_client_tools.hpp"
#include "secure_allocator.hpp"
zmq::curve_client_t::curve_client_t (session_base_t *session_,
const options_t &options_,
const bool downgrade_sub_) :
mechanism_base_t (session_, options_),
curve_mechanism_base_t (session_,
options_,
"CurveZMQMESSAGEC",
"CurveZMQMESSAGES",
downgrade_sub_),
_state (send_hello),
_tools (options_.curve_public_key,
options_.curve_secret_key,
options_.curve_server_key)
{
}
zmq::curve_client_t::~curve_client_t ()
{
}
int zmq::curve_client_t::next_handshake_command (msg_t *msg_)
{
int rc = 0;
switch (_state) {
case send_hello:
rc = produce_hello (msg_);
if (rc == 0)
_state = expect_welcome;
break;
case send_initiate:
rc = produce_initiate (msg_);
if (rc == 0)
_state = expect_ready;
break;
default:
errno = EAGAIN;
rc = -1;
}
return rc;
}
int zmq::curve_client_t::process_handshake_command (msg_t *msg_)
{
const unsigned char *msg_data =
static_cast<unsigned char *> (msg_->data ());
const size_t msg_size = msg_->size ();
int rc = 0;
if (curve_client_tools_t::is_handshake_command_welcome (msg_data, msg_size))
rc = process_welcome (msg_data, msg_size);
else if (curve_client_tools_t::is_handshake_command_ready (msg_data,
msg_size))
rc = process_ready (msg_data, msg_size);
else if (curve_client_tools_t::is_handshake_command_error (msg_data,
msg_size))
rc = process_error (msg_data, msg_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::curve_client_t::encode (msg_t *msg_)
{
zmq_assert (_state == connected);
return curve_mechanism_base_t::encode (msg_);
}
int zmq::curve_client_t::decode (msg_t *msg_)
{
zmq_assert (_state == connected);
return curve_mechanism_base_t::decode (msg_);
}
zmq::mechanism_t::status_t zmq::curve_client_t::status () const
{
if (_state == connected)
return mechanism_t::ready;
if (_state == error_received)
return mechanism_t::error;
return mechanism_t::handshaking;
}
int zmq::curve_client_t::produce_hello (msg_t *msg_)
{
int rc = msg_->init_size (200);
errno_assert (rc == 0);
rc = _tools.produce_hello (msg_->data (), get_and_inc_nonce ());
if (rc == -1) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
// TODO this is somewhat inconsistent: we call init_size, but we may
// not close msg_; i.e. we assume that msg_ is initialized but empty
// (if it were non-empty, calling init_size might cause a leak!)
// msg_->close ();
return -1;
}
return 0;
}
int zmq::curve_client_t::process_welcome (const uint8_t *msg_data_,
size_t msg_size_)
{
const int rc = _tools.process_welcome (msg_data_, msg_size_,
get_writable_precom_buffer ());
if (rc == -1) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
errno = EPROTO;
return -1;
}
_state = send_initiate;
return 0;
}
int zmq::curve_client_t::produce_initiate (msg_t *msg_)
{
const size_t metadata_length = basic_properties_len ();
std::vector<unsigned char, secure_allocator_t<unsigned char> >
metadata_plaintext (metadata_length);
add_basic_properties (&metadata_plaintext[0], metadata_length);
const size_t msg_size =
113 + 128 + crypto_box_BOXZEROBYTES + metadata_length;
int rc = msg_->init_size (msg_size);
errno_assert (rc == 0);
rc = _tools.produce_initiate (msg_->data (), msg_size, get_and_inc_nonce (),
&metadata_plaintext[0], metadata_length);
if (-1 == rc) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
// TODO see comment in produce_hello
return -1;
}
return 0;
}
int zmq::curve_client_t::process_ready (const uint8_t *msg_data_,
size_t msg_size_)
{
if (msg_size_ < 30) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_READY);
errno = EPROTO;
return -1;
}
const size_t clen = (msg_size_ - 14) + crypto_box_BOXZEROBYTES;
uint8_t ready_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > ready_plaintext (
crypto_box_ZEROBYTES + clen);
std::vector<uint8_t> ready_box (crypto_box_BOXZEROBYTES + 16 + clen);
std::fill (ready_box.begin (), ready_box.begin () + crypto_box_BOXZEROBYTES,
0);
memcpy (&ready_box[crypto_box_BOXZEROBYTES], msg_data_ + 14,
clen - crypto_box_BOXZEROBYTES);
memcpy (ready_nonce, "CurveZMQREADY---", 16);
memcpy (ready_nonce + 16, msg_data_ + 6, 8);
set_peer_nonce (get_uint64 (msg_data_ + 6));
int rc = crypto_box_open_afternm (&ready_plaintext[0], &ready_box[0], clen,
ready_nonce, get_precom_buffer ());
if (rc != 0) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
errno = EPROTO;
return -1;
}
rc = parse_metadata (&ready_plaintext[crypto_box_ZEROBYTES],
clen - crypto_box_ZEROBYTES);
if (rc == 0)
_state = connected;
else {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);
errno = EPROTO;
}
return rc;
}
int zmq::curve_client_t::process_error (const uint8_t *msg_data_,
size_t msg_size_)
{
if (_state != expect_welcome && _state != expect_ready) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
if (msg_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> (msg_data_[6]);
if (error_reason_len > msg_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 *> (msg_data_) + 7;
handle_error_reason (error_reason, error_reason_len);
_state = error_received;
return 0;
}
#endif

86
vendor/ZMQ/src/curve_client.hpp vendored Normal file
View File

@ -0,0 +1,86 @@
/*
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 ZMQ_FINAL : public curve_mechanism_base_t
{
public:
curve_client_t (session_base_t *session_,
const options_t &options_,
const bool downgrade_sub_);
~curve_client_t () ZMQ_FINAL;
// mechanism implementation
int next_handshake_command (msg_t *msg_) ZMQ_FINAL;
int process_handshake_command (msg_t *msg_) ZMQ_FINAL;
int encode (msg_t *msg_) ZMQ_FINAL;
int decode (msg_t *msg_) ZMQ_FINAL;
status_t status () const ZMQ_FINAL;
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 *msg_data_, size_t msg_size_);
int produce_initiate (msg_t *msg_);
int process_ready (const uint8_t *msg_data_, size_t msg_size_);
int process_error (const uint8_t *msg_data_, size_t msg_size_);
};
}
#endif
#endif

316
vendor/ZMQ/src/curve_client_tools.hpp vendored Normal file
View File

@ -0,0 +1,316 @@
/*
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_TOOLS_HPP_INCLUDED__
#define __ZMQ_CURVE_CLIENT_TOOLS_HPP_INCLUDED__
#ifdef ZMQ_HAVE_CURVE
#if defined(ZMQ_USE_TWEETNACL)
#include "tweetnacl.h"
#elif defined(ZMQ_USE_LIBSODIUM)
#include "sodium.h"
#endif
#if crypto_box_NONCEBYTES != 24 || crypto_box_PUBLICKEYBYTES != 32 \
|| crypto_box_SECRETKEYBYTES != 32 || crypto_box_ZEROBYTES != 32 \
|| crypto_box_BOXZEROBYTES != 16
#error "CURVE library not built properly"
#endif
#include "wire.hpp"
#include "err.hpp"
#include "secure_allocator.hpp"
#include <vector>
namespace zmq
{
struct curve_client_tools_t
{
static int produce_hello (void *data_,
const uint8_t *server_key_,
const uint64_t cn_nonce_,
const uint8_t *cn_public_,
const uint8_t *cn_secret_)
{
uint8_t hello_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > hello_plaintext (
crypto_box_ZEROBYTES + 64, 0);
uint8_t hello_box[crypto_box_BOXZEROBYTES + 80];
// Prepare the full nonce
memcpy (hello_nonce, "CurveZMQHELLO---", 16);
put_uint64 (hello_nonce + 16, cn_nonce_);
// Create Box [64 * %x0](C'->S)
const int rc =
crypto_box (hello_box, &hello_plaintext[0], hello_plaintext.size (),
hello_nonce, server_key_, cn_secret_);
if (rc == -1)
return -1;
uint8_t *hello = static_cast<uint8_t *> (data_);
memcpy (hello, "\x05HELLO", 6);
// CurveZMQ major and minor version numbers
memcpy (hello + 6, "\1\0", 2);
// Anti-amplification padding
memset (hello + 8, 0, 72);
// Client public connection key
memcpy (hello + 80, cn_public_, crypto_box_PUBLICKEYBYTES);
// Short nonce, prefixed by "CurveZMQHELLO---"
memcpy (hello + 112, hello_nonce + 16, 8);
// Signature, Box [64 * %x0](C'->S)
memcpy (hello + 120, hello_box + crypto_box_BOXZEROBYTES, 80);
return 0;
}
static int process_welcome (const uint8_t *msg_data_,
size_t msg_size_,
const uint8_t *server_key_,
const uint8_t *cn_secret_,
uint8_t *cn_server_,
uint8_t *cn_cookie_,
uint8_t *cn_precom_)
{
if (msg_size_ != 168) {
errno = EPROTO;
return -1;
}
uint8_t welcome_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > welcome_plaintext (
crypto_box_ZEROBYTES + 128);
uint8_t welcome_box[crypto_box_BOXZEROBYTES + 144];
// Open Box [S' + cookie](C'->S)
memset (welcome_box, 0, crypto_box_BOXZEROBYTES);
memcpy (welcome_box + crypto_box_BOXZEROBYTES, msg_data_ + 24, 144);
memcpy (welcome_nonce, "WELCOME-", 8);
memcpy (welcome_nonce + 8, msg_data_ + 8, 16);
int rc = crypto_box_open (&welcome_plaintext[0], welcome_box,
sizeof welcome_box, welcome_nonce,
server_key_, cn_secret_);
if (rc != 0) {
errno = EPROTO;
return -1;
}
memcpy (cn_server_, &welcome_plaintext[crypto_box_ZEROBYTES], 32);
memcpy (cn_cookie_, &welcome_plaintext[crypto_box_ZEROBYTES + 32],
16 + 80);
// Message independent precomputation
rc = crypto_box_beforenm (cn_precom_, cn_server_, cn_secret_);
zmq_assert (rc == 0);
return 0;
}
static int produce_initiate (void *data_,
size_t size_,
const uint64_t cn_nonce_,
const uint8_t *server_key_,
const uint8_t *public_key_,
const uint8_t *secret_key_,
const uint8_t *cn_public_,
const uint8_t *cn_secret_,
const uint8_t *cn_server_,
const uint8_t *cn_cookie_,
const uint8_t *metadata_plaintext_,
const size_t metadata_length_)
{
uint8_t vouch_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > vouch_plaintext (
crypto_box_ZEROBYTES + 64);
uint8_t vouch_box[crypto_box_BOXZEROBYTES + 80];
// Create vouch = Box [C',S](C->S')
std::fill (vouch_plaintext.begin (),
vouch_plaintext.begin () + crypto_box_ZEROBYTES, 0);
memcpy (&vouch_plaintext[crypto_box_ZEROBYTES], cn_public_, 32);
memcpy (&vouch_plaintext[crypto_box_ZEROBYTES + 32], server_key_, 32);
memset (vouch_nonce, 0, crypto_box_NONCEBYTES);
memcpy (vouch_nonce, "VOUCH---", 8);
randombytes (vouch_nonce + 8, 16);
int rc =
crypto_box (vouch_box, &vouch_plaintext[0], vouch_plaintext.size (),
vouch_nonce, cn_server_, secret_key_);
if (rc == -1)
return -1;
uint8_t initiate_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t> initiate_box (crypto_box_BOXZEROBYTES + 144
+ metadata_length_);
std::vector<uint8_t, secure_allocator_t<uint8_t> > initiate_plaintext (
crypto_box_ZEROBYTES + 128 + metadata_length_);
// Create Box [C + vouch + metadata](C'->S')
std::fill (initiate_plaintext.begin (),
initiate_plaintext.begin () + crypto_box_ZEROBYTES, 0);
memcpy (&initiate_plaintext[crypto_box_ZEROBYTES], public_key_, 32);
memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 32], vouch_nonce + 8,
16);
memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 48],
vouch_box + crypto_box_BOXZEROBYTES, 80);
if (metadata_length_) {
memcpy (&initiate_plaintext[crypto_box_ZEROBYTES + 48 + 80],
metadata_plaintext_, metadata_length_);
}
memcpy (initiate_nonce, "CurveZMQINITIATE", 16);
put_uint64 (initiate_nonce + 16, cn_nonce_);
rc = crypto_box (&initiate_box[0], &initiate_plaintext[0],
crypto_box_ZEROBYTES + 128 + metadata_length_,
initiate_nonce, cn_server_, cn_secret_);
if (rc == -1)
return -1;
uint8_t *initiate = static_cast<uint8_t *> (data_);
zmq_assert (size_
== 113 + 128 + crypto_box_BOXZEROBYTES + metadata_length_);
memcpy (initiate, "\x08INITIATE", 9);
// Cookie provided by the server in the WELCOME command
memcpy (initiate + 9, cn_cookie_, 96);
// Short nonce, prefixed by "CurveZMQINITIATE"
memcpy (initiate + 105, initiate_nonce + 16, 8);
// Box [C + vouch + metadata](C'->S')
memcpy (initiate + 113, &initiate_box[crypto_box_BOXZEROBYTES],
128 + metadata_length_ + crypto_box_BOXZEROBYTES);
return 0;
}
static bool is_handshake_command_welcome (const uint8_t *msg_data_,
const size_t msg_size_)
{
return is_handshake_command (msg_data_, msg_size_, "\7WELCOME");
}
static bool is_handshake_command_ready (const uint8_t *msg_data_,
const size_t msg_size_)
{
return is_handshake_command (msg_data_, msg_size_, "\5READY");
}
static bool is_handshake_command_error (const uint8_t *msg_data_,
const size_t msg_size_)
{
return is_handshake_command (msg_data_, msg_size_, "\5ERROR");
}
// non-static functions
curve_client_tools_t (
const uint8_t (&curve_public_key_)[crypto_box_PUBLICKEYBYTES],
const uint8_t (&curve_secret_key_)[crypto_box_SECRETKEYBYTES],
const uint8_t (&curve_server_key_)[crypto_box_PUBLICKEYBYTES])
{
int rc;
memcpy (public_key, curve_public_key_, crypto_box_PUBLICKEYBYTES);
memcpy (secret_key, curve_secret_key_, crypto_box_SECRETKEYBYTES);
memcpy (server_key, curve_server_key_, crypto_box_PUBLICKEYBYTES);
// Generate short-term key pair
memset (cn_secret, 0, crypto_box_SECRETKEYBYTES);
memset (cn_public, 0, crypto_box_PUBLICKEYBYTES);
rc = crypto_box_keypair (cn_public, cn_secret);
zmq_assert (rc == 0);
}
int produce_hello (void *data_, const uint64_t cn_nonce_) const
{
return produce_hello (data_, server_key, cn_nonce_, cn_public,
cn_secret);
}
int process_welcome (const uint8_t *msg_data_,
size_t msg_size_,
uint8_t *cn_precom_)
{
return process_welcome (msg_data_, msg_size_, server_key, cn_secret,
cn_server, cn_cookie, cn_precom_);
}
int produce_initiate (void *data_,
size_t size_,
const uint64_t cn_nonce_,
const uint8_t *metadata_plaintext_,
const size_t metadata_length_) const
{
return produce_initiate (data_, size_, cn_nonce_, server_key,
public_key, secret_key, cn_public, cn_secret,
cn_server, cn_cookie, metadata_plaintext_,
metadata_length_);
}
// Our public key (C)
uint8_t public_key[crypto_box_PUBLICKEYBYTES];
// Our secret key (c)
uint8_t secret_key[crypto_box_SECRETKEYBYTES];
// Our short-term public key (C')
uint8_t cn_public[crypto_box_PUBLICKEYBYTES];
// Our short-term secret key (c')
uint8_t cn_secret[crypto_box_SECRETKEYBYTES];
// Server's public key (S)
uint8_t server_key[crypto_box_PUBLICKEYBYTES];
// Server's short-term public key (S')
uint8_t cn_server[crypto_box_PUBLICKEYBYTES];
// Cookie received from server
uint8_t cn_cookie[16 + 80];
private:
template <size_t N>
static bool is_handshake_command (const uint8_t *msg_data_,
const size_t msg_size_,
const char (&prefix_)[N])
{
return msg_size_ >= (N - 1) && !memcmp (msg_data_, prefix_, N - 1);
}
};
}
#endif
#endif

313
vendor/ZMQ/src/curve_mechanism_base.cpp vendored Normal file
View File

@ -0,0 +1,313 @@
/*
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 "curve_mechanism_base.hpp"
#include "msg.hpp"
#include "wire.hpp"
#include "session_base.hpp"
#ifdef ZMQ_HAVE_CURVE
#ifdef ZMQ_USE_LIBSODIUM
// libsodium added crypto_box_easy_afternm and crypto_box_open_easy_afternm with
// https: //github.com/jedisct1/libsodium/commit/aaf5fbf2e53a33b18d8ea9bdf2c6f73d7acc8c3e
#if SODIUM_LIBRARY_VERSION_MAJOR > 7 \
|| (SODIUM_LIBRARY_VERSION_MAJOR == 7 && SODIUM_LIBRARY_VERSION_MINOR >= 4)
#define ZMQ_HAVE_CRYPTO_BOX_EASY_FNS 1
#endif
#endif
zmq::curve_mechanism_base_t::curve_mechanism_base_t (
session_base_t *session_,
const options_t &options_,
const char *encode_nonce_prefix_,
const char *decode_nonce_prefix_,
const bool downgrade_sub_) :
mechanism_base_t (session_, options_),
curve_encoding_t (
encode_nonce_prefix_, decode_nonce_prefix_, downgrade_sub_)
{
}
int zmq::curve_mechanism_base_t::encode (msg_t *msg_)
{
return curve_encoding_t::encode (msg_);
}
int zmq::curve_mechanism_base_t::decode (msg_t *msg_)
{
int rc = check_basic_command_structure (msg_);
if (rc == -1)
return -1;
int error_event_code;
rc = curve_encoding_t::decode (msg_, &error_event_code);
if (-1 == rc) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), error_event_code);
}
return rc;
}
zmq::curve_encoding_t::curve_encoding_t (const char *encode_nonce_prefix_,
const char *decode_nonce_prefix_,
const bool downgrade_sub_) :
_encode_nonce_prefix (encode_nonce_prefix_),
_decode_nonce_prefix (decode_nonce_prefix_),
_cn_nonce (1),
_cn_peer_nonce (1),
_downgrade_sub (downgrade_sub_)
{
}
// Right now, we only transport the lower two bit flags of zmq::msg_t, so they
// are binary identical, and we can just use a bitmask to select them. If we
// happened to add more flags, this might change.
static const uint8_t flag_mask = zmq::msg_t::more | zmq::msg_t::command;
static const size_t flags_len = 1;
static const size_t nonce_prefix_len = 16;
static const char message_command[] = "\x07MESSAGE";
static const size_t message_command_len = sizeof (message_command) - 1;
static const size_t message_header_len =
message_command_len + sizeof (zmq::curve_encoding_t::nonce_t);
#ifndef ZMQ_USE_LIBSODIUM
static const size_t crypto_box_MACBYTES = 16;
#endif
int zmq::curve_encoding_t::check_validity (msg_t *msg_, int *error_event_code_)
{
const size_t size = msg_->size ();
const uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
if (size < message_command_len
|| 0 != memcmp (message, message_command, message_command_len)) {
*error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND;
errno = EPROTO;
return -1;
}
if (size < message_header_len + crypto_box_MACBYTES + flags_len) {
*error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE;
errno = EPROTO;
return -1;
}
{
const uint64_t nonce = get_uint64 (message + message_command_len);
if (nonce <= _cn_peer_nonce) {
*error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_SEQUENCE;
errno = EPROTO;
return -1;
}
set_peer_nonce (nonce);
}
return 0;
}
int zmq::curve_encoding_t::encode (msg_t *msg_)
{
size_t sub_cancel_len = 0;
uint8_t message_nonce[crypto_box_NONCEBYTES];
memcpy (message_nonce, _encode_nonce_prefix, nonce_prefix_len);
put_uint64 (message_nonce + nonce_prefix_len, get_and_inc_nonce ());
if (msg_->is_subscribe () || msg_->is_cancel ()) {
if (_downgrade_sub)
sub_cancel_len = 1;
else
sub_cancel_len = msg_->is_cancel ()
? zmq::msg_t::cancel_cmd_name_size
: zmq::msg_t::sub_cmd_name_size;
}
#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
const size_t mlen = flags_len + sub_cancel_len + msg_->size ();
std::vector<uint8_t> message_plaintext (mlen);
#else
const size_t mlen =
crypto_box_ZEROBYTES + flags_len + sub_cancel_len + msg_->size ();
std::vector<uint8_t> message_plaintext_with_zerobytes (mlen);
uint8_t *const message_plaintext =
&message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];
std::fill (message_plaintext_with_zerobytes.begin (),
message_plaintext_with_zerobytes.begin () + crypto_box_ZEROBYTES,
0);
#endif
const uint8_t flags = msg_->flags () & flag_mask;
message_plaintext[0] = flags;
// For backward compatibility subscribe/cancel command messages are not stored with
// the message flags, and are encoded in the encoder, so that messages for < 3.0 peers
// can be encoded in the "old" 0/1 way rather than as commands.
if (sub_cancel_len == 1)
message_plaintext[flags_len] = msg_->is_subscribe () ? 1 : 0;
else if (sub_cancel_len == zmq::msg_t::sub_cmd_name_size) {
message_plaintext[0] |= zmq::msg_t::command;
memcpy (&message_plaintext[flags_len], zmq::sub_cmd_name,
zmq::msg_t::sub_cmd_name_size);
} else if (sub_cancel_len == zmq::msg_t::cancel_cmd_name_size) {
message_plaintext[0] |= zmq::msg_t::command;
memcpy (&message_plaintext[flags_len], zmq::cancel_cmd_name,
zmq::msg_t::cancel_cmd_name_size);
}
// this is copying the data from insecure memory, so there is no point in
// using secure_allocator_t for message_plaintext
if (msg_->size () > 0)
memcpy (&message_plaintext[flags_len + sub_cancel_len], msg_->data (),
msg_->size ());
#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
msg_t msg_box;
int rc =
msg_box.init_size (message_header_len + mlen + crypto_box_MACBYTES);
zmq_assert (rc == 0);
rc = crypto_box_easy_afternm (
static_cast<uint8_t *> (msg_box.data ()) + message_header_len,
&message_plaintext[0], mlen, message_nonce, _cn_precom);
zmq_assert (rc == 0);
msg_->move (msg_box);
uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
#else
std::vector<uint8_t> message_box (mlen);
int rc =
crypto_box_afternm (&message_box[0], &message_plaintext_with_zerobytes[0],
mlen, message_nonce, _cn_precom);
zmq_assert (rc == 0);
rc = msg_->close ();
zmq_assert (rc == 0);
rc = msg_->init_size (16 + mlen - crypto_box_BOXZEROBYTES);
zmq_assert (rc == 0);
uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
memcpy (message + message_header_len, &message_box[crypto_box_BOXZEROBYTES],
mlen - crypto_box_BOXZEROBYTES);
#endif
memcpy (message, message_command, message_command_len);
memcpy (message + message_command_len, message_nonce + nonce_prefix_len,
sizeof (nonce_t));
return 0;
}
int zmq::curve_encoding_t::decode (msg_t *msg_, int *error_event_code_)
{
int rc = check_validity (msg_, error_event_code_);
if (0 != rc) {
return rc;
}
uint8_t *const message = static_cast<uint8_t *> (msg_->data ());
uint8_t message_nonce[crypto_box_NONCEBYTES];
memcpy (message_nonce, _decode_nonce_prefix, nonce_prefix_len);
memcpy (message_nonce + nonce_prefix_len, message + message_command_len,
sizeof (nonce_t));
#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
const size_t clen = msg_->size () - message_header_len;
uint8_t *const message_plaintext = message + message_header_len;
rc = crypto_box_open_easy_afternm (message_plaintext,
message + message_header_len, clen,
message_nonce, _cn_precom);
#else
const size_t clen =
crypto_box_BOXZEROBYTES + msg_->size () - message_header_len;
std::vector<uint8_t> message_plaintext_with_zerobytes (clen);
std::vector<uint8_t> message_box (clen);
std::fill (message_box.begin (),
message_box.begin () + crypto_box_BOXZEROBYTES, 0);
memcpy (&message_box[crypto_box_BOXZEROBYTES], message + message_header_len,
msg_->size () - message_header_len);
rc = crypto_box_open_afternm (&message_plaintext_with_zerobytes[0],
&message_box[0], clen, message_nonce,
_cn_precom);
const uint8_t *const message_plaintext =
&message_plaintext_with_zerobytes[crypto_box_ZEROBYTES];
#endif
if (rc == 0) {
const uint8_t flags = message_plaintext[0];
#ifdef ZMQ_HAVE_CRYPTO_BOX_EASY_FNS
const size_t plaintext_size = clen - flags_len - crypto_box_MACBYTES;
if (plaintext_size > 0) {
memmove (msg_->data (), &message_plaintext[flags_len],
plaintext_size);
}
msg_->shrink (plaintext_size);
#else
rc = msg_->close ();
zmq_assert (rc == 0);
rc = msg_->init_size (clen - flags_len - crypto_box_ZEROBYTES);
zmq_assert (rc == 0);
// this is copying the data to insecure memory, so there is no point in
// using secure_allocator_t for message_plaintext
if (msg_->size () > 0) {
memcpy (msg_->data (), &message_plaintext[flags_len],
msg_->size ());
}
#endif
msg_->set_flags (flags & flag_mask);
} else {
// CURVE I : connection key used for MESSAGE is wrong
*error_event_code_ = ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC;
errno = EPROTO;
}
return rc;
}
#endif

108
vendor/ZMQ/src/curve_mechanism_base.hpp vendored Normal file
View File

@ -0,0 +1,108 @@
/*
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_MECHANISM_BASE_HPP_INCLUDED__
#define __ZMQ_CURVE_MECHANISM_BASE_HPP_INCLUDED__
#ifdef ZMQ_HAVE_CURVE
#if defined(ZMQ_USE_TWEETNACL)
#include "tweetnacl.h"
#elif defined(ZMQ_USE_LIBSODIUM)
#include "sodium.h"
#endif
#if crypto_box_NONCEBYTES != 24 || crypto_box_PUBLICKEYBYTES != 32 \
|| crypto_box_SECRETKEYBYTES != 32 || crypto_box_ZEROBYTES != 32 \
|| crypto_box_BOXZEROBYTES != 16 || crypto_secretbox_NONCEBYTES != 24 \
|| crypto_secretbox_ZEROBYTES != 32 || crypto_secretbox_BOXZEROBYTES != 16
#error "CURVE library not built properly"
#endif
#include "mechanism_base.hpp"
#include "options.hpp"
#include <memory>
namespace zmq
{
class curve_encoding_t
{
public:
curve_encoding_t (const char *encode_nonce_prefix_,
const char *decode_nonce_prefix_,
const bool downgrade_sub_);
int encode (msg_t *msg_);
int decode (msg_t *msg_, int *error_event_code_);
uint8_t *get_writable_precom_buffer () { return _cn_precom; }
const uint8_t *get_precom_buffer () const { return _cn_precom; }
typedef uint64_t nonce_t;
nonce_t get_and_inc_nonce () { return _cn_nonce++; }
void set_peer_nonce (nonce_t peer_nonce_) { _cn_peer_nonce = peer_nonce_; };
private:
int check_validity (msg_t *msg_, int *error_event_code_);
const char *_encode_nonce_prefix;
const char *_decode_nonce_prefix;
nonce_t _cn_nonce;
nonce_t _cn_peer_nonce;
// Intermediary buffer used to speed up boxing and unboxing.
uint8_t _cn_precom[crypto_box_BEFORENMBYTES];
const bool _downgrade_sub;
ZMQ_NON_COPYABLE_NOR_MOVABLE (curve_encoding_t)
};
class curve_mechanism_base_t : public virtual mechanism_base_t,
public curve_encoding_t
{
public:
curve_mechanism_base_t (session_base_t *session_,
const options_t &options_,
const char *encode_nonce_prefix_,
const char *decode_nonce_prefix_,
const bool downgrade_sub_);
// mechanism implementation
int encode (msg_t *msg_) ZMQ_OVERRIDE;
int decode (msg_t *msg_) ZMQ_OVERRIDE;
};
}
#endif
#endif

506
vendor/ZMQ/src/curve_server.cpp vendored Normal file
View File

@ -0,0 +1,506 @@
/*
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"
#ifdef ZMQ_HAVE_CURVE
#include "msg.hpp"
#include "session_base.hpp"
#include "err.hpp"
#include "curve_server.hpp"
#include "wire.hpp"
#include "secure_allocator.hpp"
zmq::curve_server_t::curve_server_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_,
const bool downgrade_sub_) :
mechanism_base_t (session_, options_),
zap_client_common_handshake_t (
session_, peer_address_, options_, sending_ready),
curve_mechanism_base_t (session_,
options_,
"CurveZMQMESSAGES",
"CurveZMQMESSAGEC",
downgrade_sub_)
{
int rc;
// Fetch our secret key from socket options
memcpy (_secret_key, options_.curve_secret_key, crypto_box_SECRETKEYBYTES);
// Generate short-term key pair
memset (_cn_secret, 0, crypto_box_SECRETKEYBYTES);
memset (_cn_public, 0, crypto_box_PUBLICKEYBYTES);
rc = crypto_box_keypair (_cn_public, _cn_secret);
zmq_assert (rc == 0);
}
zmq::curve_server_t::~curve_server_t ()
{
}
int zmq::curve_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;
break;
}
return rc;
}
int zmq::curve_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 I think this is not a case reachable with a misbehaving
// client. It is not an "invalid handshake command", but would be
// trying to process a handshake command in an invalid state,
// which is purely under control of this peer.
// Therefore, it should be changed to zmq_assert (false);
// CURVE I: invalid 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::curve_server_t::encode (msg_t *msg_)
{
zmq_assert (state == ready);
return curve_mechanism_base_t::encode (msg_);
}
int zmq::curve_server_t::decode (msg_t *msg_)
{
zmq_assert (state == ready);
return curve_mechanism_base_t::decode (msg_);
}
int zmq::curve_server_t::process_hello (msg_t *msg_)
{
int rc = check_basic_command_structure (msg_);
if (rc == -1)
return -1;
const size_t size = msg_->size ();
const uint8_t *const hello = static_cast<uint8_t *> (msg_->data ());
if (size < 6 || memcmp (hello, "\x05HELLO", 6)) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
if (size != 200) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
errno = EPROTO;
return -1;
}
const uint8_t major = hello[6];
const uint8_t minor = hello[7];
if (major != 1 || minor != 0) {
// CURVE I: client HELLO has unknown version number
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
errno = EPROTO;
return -1;
}
// Save client's short-term public key (C')
memcpy (_cn_client, hello + 80, 32);
uint8_t hello_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > hello_plaintext (
crypto_box_ZEROBYTES + 64);
uint8_t hello_box[crypto_box_BOXZEROBYTES + 80];
memcpy (hello_nonce, "CurveZMQHELLO---", 16);
memcpy (hello_nonce + 16, hello + 112, 8);
set_peer_nonce (get_uint64 (hello + 112));
memset (hello_box, 0, crypto_box_BOXZEROBYTES);
memcpy (hello_box + crypto_box_BOXZEROBYTES, hello + 120, 80);
// Open Box [64 * %x0](C'->S)
rc = crypto_box_open (&hello_plaintext[0], hello_box, sizeof hello_box,
hello_nonce, _cn_client, _secret_key);
if (rc != 0) {
// CURVE I: cannot open client HELLO -- wrong server key?
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
errno = EPROTO;
return -1;
}
state = sending_welcome;
return rc;
}
int zmq::curve_server_t::produce_welcome (msg_t *msg_)
{
uint8_t cookie_nonce[crypto_secretbox_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > cookie_plaintext (
crypto_secretbox_ZEROBYTES + 64);
uint8_t cookie_ciphertext[crypto_secretbox_BOXZEROBYTES + 80];
// Create full nonce for encryption
// 8-byte prefix plus 16-byte random nonce
memset (cookie_nonce, 0, crypto_secretbox_NONCEBYTES);
memcpy (cookie_nonce, "COOKIE--", 8);
randombytes (cookie_nonce + 8, 16);
// Generate cookie = Box [C' + s'](t)
std::fill (cookie_plaintext.begin (),
cookie_plaintext.begin () + crypto_secretbox_ZEROBYTES, 0);
memcpy (&cookie_plaintext[crypto_secretbox_ZEROBYTES], _cn_client, 32);
memcpy (&cookie_plaintext[crypto_secretbox_ZEROBYTES + 32], _cn_secret, 32);
// Generate fresh cookie key
memset (_cookie_key, 0, crypto_secretbox_KEYBYTES);
randombytes (_cookie_key, crypto_secretbox_KEYBYTES);
// Encrypt using symmetric cookie key
int rc =
crypto_secretbox (cookie_ciphertext, &cookie_plaintext[0],
cookie_plaintext.size (), cookie_nonce, _cookie_key);
zmq_assert (rc == 0);
uint8_t welcome_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > welcome_plaintext (
crypto_box_ZEROBYTES + 128);
uint8_t welcome_ciphertext[crypto_box_BOXZEROBYTES + 144];
// Create full nonce for encryption
// 8-byte prefix plus 16-byte random nonce
memset (welcome_nonce, 0, crypto_box_NONCEBYTES);
memcpy (welcome_nonce, "WELCOME-", 8);
randombytes (welcome_nonce + 8, crypto_box_NONCEBYTES - 8);
// Create 144-byte Box [S' + cookie](S->C')
std::fill (welcome_plaintext.begin (),
welcome_plaintext.begin () + crypto_box_ZEROBYTES, 0);
memcpy (&welcome_plaintext[crypto_box_ZEROBYTES], _cn_public, 32);
memcpy (&welcome_plaintext[crypto_box_ZEROBYTES + 32], cookie_nonce + 8,
16);
memcpy (&welcome_plaintext[crypto_box_ZEROBYTES + 48],
cookie_ciphertext + crypto_secretbox_BOXZEROBYTES, 80);
rc = crypto_box (welcome_ciphertext, &welcome_plaintext[0],
welcome_plaintext.size (), welcome_nonce, _cn_client,
_secret_key);
// TODO I think we should change this back to zmq_assert (rc == 0);
// as it was before https://github.com/zeromq/libzmq/pull/1832
// The reason given there was that secret_key might be 0ed.
// But if it were, we would never get this far, since we could
// not have opened the client's hello box with a 0ed key.
if (rc == -1)
return -1;
rc = msg_->init_size (168);
errno_assert (rc == 0);
uint8_t *const welcome = static_cast<uint8_t *> (msg_->data ());
memcpy (welcome, "\x07WELCOME", 8);
memcpy (welcome + 8, welcome_nonce + 8, 16);
memcpy (welcome + 24, welcome_ciphertext + crypto_box_BOXZEROBYTES, 144);
return 0;
}
int zmq::curve_server_t::process_initiate (msg_t *msg_)
{
int rc = check_basic_command_structure (msg_);
if (rc == -1)
return -1;
const size_t size = msg_->size ();
const uint8_t *initiate = static_cast<uint8_t *> (msg_->data ());
if (size < 9 || memcmp (initiate, "\x08INITIATE", 9)) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
if (size < 257) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);
errno = EPROTO;
return -1;
}
uint8_t cookie_nonce[crypto_secretbox_NONCEBYTES];
uint8_t cookie_plaintext[crypto_secretbox_ZEROBYTES + 64];
uint8_t cookie_box[crypto_secretbox_BOXZEROBYTES + 80];
// Open Box [C' + s'](t)
memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES);
memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80);
memcpy (cookie_nonce, "COOKIE--", 8);
memcpy (cookie_nonce + 8, initiate + 9, 16);
rc = crypto_secretbox_open (cookie_plaintext, cookie_box, sizeof cookie_box,
cookie_nonce, _cookie_key);
if (rc != 0) {
// CURVE I: cannot open client INITIATE cookie
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
errno = EPROTO;
return -1;
}
// Check cookie plain text is as expected [C' + s']
if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, _cn_client, 32)
|| memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32,
_cn_secret, 32)) {
// TODO this case is very hard to test, as it would require a modified
// client that knows the server's secret temporary cookie key
// CURVE I: client INITIATE cookie is not valid
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
errno = EPROTO;
return -1;
}
const size_t clen = (size - 113) + crypto_box_BOXZEROBYTES;
uint8_t initiate_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > initiate_plaintext (
crypto_box_ZEROBYTES + clen);
std::vector<uint8_t> initiate_box (crypto_box_BOXZEROBYTES + clen);
// Open Box [C + vouch + metadata](C'->S')
std::fill (initiate_box.begin (),
initiate_box.begin () + crypto_box_BOXZEROBYTES, 0);
memcpy (&initiate_box[crypto_box_BOXZEROBYTES], initiate + 113,
clen - crypto_box_BOXZEROBYTES);
memcpy (initiate_nonce, "CurveZMQINITIATE", 16);
memcpy (initiate_nonce + 16, initiate + 105, 8);
set_peer_nonce (get_uint64 (initiate + 105));
const uint8_t *client_key = &initiate_plaintext[crypto_box_ZEROBYTES];
rc = crypto_box_open (&initiate_plaintext[0], &initiate_box[0], clen,
initiate_nonce, _cn_client, _cn_secret);
if (rc != 0) {
// CURVE I: cannot open client INITIATE
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
errno = EPROTO;
return -1;
}
uint8_t vouch_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > vouch_plaintext (
crypto_box_ZEROBYTES + 64);
uint8_t vouch_box[crypto_box_BOXZEROBYTES + 80];
// Open Box Box [C',S](C->S') and check contents
memset (vouch_box, 0, crypto_box_BOXZEROBYTES);
memcpy (vouch_box + crypto_box_BOXZEROBYTES,
&initiate_plaintext[crypto_box_ZEROBYTES + 48], 80);
memset (vouch_nonce, 0, crypto_box_NONCEBYTES);
memcpy (vouch_nonce, "VOUCH---", 8);
memcpy (vouch_nonce + 8, &initiate_plaintext[crypto_box_ZEROBYTES + 32],
16);
rc = crypto_box_open (&vouch_plaintext[0], vouch_box, sizeof vouch_box,
vouch_nonce, client_key, _cn_secret);
if (rc != 0) {
// CURVE I: cannot open client INITIATE vouch
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
errno = EPROTO;
return -1;
}
// What we decrypted must be the client's short-term public key
if (memcmp (&vouch_plaintext[crypto_box_ZEROBYTES], _cn_client, 32)) {
// TODO this case is very hard to test, as it would require a modified
// client that knows the server's secret short-term key
// CURVE I: invalid handshake from client (public key)
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE);
errno = EPROTO;
return -1;
}
// Precompute connection secret from client key
rc = crypto_box_beforenm (get_writable_precom_buffer (), _cn_client,
_cn_secret);
zmq_assert (rc == 0);
// Given this is a backward-incompatible change, it's behind a socket
// option disabled by default.
if (zap_required () || !options.zap_enforce_domain) {
// Use ZAP protocol (RFC 27) to authenticate the user.
rc = session->zap_connect ();
if (rc == 0) {
send_zap_request (client_key);
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)
if (-1 == receive_and_process_zap_reply ())
return -1;
} else if (!options.zap_enforce_domain) {
// This supports the Stonehouse pattern (encryption without
// authentication) in legacy mode (domain set but no handler).
state = sending_ready;
} else {
session->get_socket ()->event_handshake_failed_no_detail (
session->get_endpoint (), EFAULT);
return -1;
}
} else {
// This supports the Stonehouse pattern (encryption without authentication).
state = sending_ready;
}
return parse_metadata (&initiate_plaintext[crypto_box_ZEROBYTES + 128],
clen - crypto_box_ZEROBYTES - 128);
}
int zmq::curve_server_t::produce_ready (msg_t *msg_)
{
const size_t metadata_length = basic_properties_len ();
uint8_t ready_nonce[crypto_box_NONCEBYTES];
std::vector<uint8_t, secure_allocator_t<uint8_t> > ready_plaintext (
crypto_box_ZEROBYTES + metadata_length);
// Create Box [metadata](S'->C')
std::fill (ready_plaintext.begin (),
ready_plaintext.begin () + crypto_box_ZEROBYTES, 0);
uint8_t *ptr = &ready_plaintext[crypto_box_ZEROBYTES];
ptr += add_basic_properties (ptr, metadata_length);
const size_t mlen = ptr - &ready_plaintext[0];
memcpy (ready_nonce, "CurveZMQREADY---", 16);
put_uint64 (ready_nonce + 16, get_and_inc_nonce ());
std::vector<uint8_t> ready_box (crypto_box_BOXZEROBYTES + 16
+ metadata_length);
int rc = crypto_box_afternm (&ready_box[0], &ready_plaintext[0], mlen,
ready_nonce, get_precom_buffer ());
zmq_assert (rc == 0);
rc = msg_->init_size (14 + mlen - crypto_box_BOXZEROBYTES);
errno_assert (rc == 0);
uint8_t *ready = static_cast<uint8_t *> (msg_->data ());
memcpy (ready, "\x05READY", 6);
// Short nonce, prefixed by "CurveZMQREADY---"
memcpy (ready + 6, ready_nonce + 16, 8);
// Box [metadata](S'->C')
memcpy (ready + 14, &ready_box[crypto_box_BOXZEROBYTES],
mlen - crypto_box_BOXZEROBYTES);
return 0;
}
int zmq::curve_server_t::produce_error (msg_t *msg_) const
{
const size_t expected_status_code_length = 3;
zmq_assert (status_code.length () == 3);
const int rc = msg_->init_size (6 + 1 + expected_status_code_length);
zmq_assert (rc == 0);
char *msg_data = static_cast<char *> (msg_->data ());
memcpy (msg_data, "\5ERROR", 6);
msg_data[6] = expected_status_code_length;
memcpy (msg_data + 7, status_code.c_str (), expected_status_code_length);
return 0;
}
void zmq::curve_server_t::send_zap_request (const uint8_t *key_)
{
zap_client_t::send_zap_request ("CURVE", 5, key_,
crypto_box_PUBLICKEYBYTES);
}
#endif

92
vendor/ZMQ/src/curve_server.hpp vendored Normal file
View File

@ -0,0 +1,92 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_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 ZMQ_FINAL : 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_,
const bool downgrade_sub_);
~curve_server_t ();
// mechanism implementation
int next_handshake_command (msg_t *msg_);
int process_handshake_command (msg_t *msg_);
int encode (msg_t *msg_);
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

134
vendor/ZMQ/src/dbuffer.hpp vendored Normal file
View File

@ -0,0 +1,134 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#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:
dbuffer_t () : _back (&_storage[0]), _front (&_storage[1]), _has_msg (false)
{
_back->init ();
_front->init ();
}
~dbuffer_t ()
{
_back->close ();
_front->close ();
}
void write (const msg_t &value_)
{
zmq_assert (value_.check ());
*_back = value_;
zmq_assert (_back->check ());
if (_sync.try_lock ()) {
_front->move (*_back);
_has_msg = true;
_sync.unlock ();
}
}
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;
}
}
bool check_read ()
{
scoped_lock_t lock (_sync);
return _has_msg;
}
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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (dbuffer_t)
};
}
#endif

145
vendor/ZMQ/src/dealer.cpp vendored Normal file
View File

@ -0,0 +1,145 @@
/*
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;
options.can_send_hello_msg = true;
}
zmq::dealer_t::~dealer_t ()
{
}
void zmq::dealer_t::xattach_pipe (pipe_t *pipe_,
bool subscribe_to_all_,
bool locally_initiated_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
LIBZMQ_UNUSED (locally_initiated_);
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.
LIBZMQ_UNUSED (rc);
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_)
{
const 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 ();
}
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_);
}

85
vendor/ZMQ/src/dealer.hpp vendored Normal file
View File

@ -0,0 +1,85 @@
/*
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 () ZMQ_OVERRIDE;
protected:
// Overrides of functions from socket_base_t.
void xattach_pipe (zmq::pipe_t *pipe_,
bool subscribe_to_all_,
bool locally_initiated_) ZMQ_FINAL;
int xsetsockopt (int option_,
const void *optval_,
size_t optvallen_) ZMQ_OVERRIDE;
int xsend (zmq::msg_t *msg_) ZMQ_OVERRIDE;
int xrecv (zmq::msg_t *msg_) ZMQ_OVERRIDE;
bool xhas_in () ZMQ_OVERRIDE;
bool xhas_out () ZMQ_OVERRIDE;
void xread_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;
void xwrite_activated (zmq::pipe_t *pipe_) ZMQ_FINAL;
void xpipe_terminated (zmq::pipe_t *pipe_) ZMQ_OVERRIDE;
// 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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (dealer_t)
};
}
#endif

191
vendor/ZMQ/src/decoder.hpp vendored Normal file
View File

@ -0,0 +1,191 @@
/*
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 "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 (const size_t buf_size_) :
_next (NULL),
_read_pos (NULL),
_to_read (0),
_allocator (buf_size_)
{
_buf = _allocator.allocate ();
}
~decoder_base_t () ZMQ_OVERRIDE { _allocator.deallocate (); }
// Returns a buffer to be filled with binary data.
void get_buffer (unsigned char **data_, std::size_t *size_) ZMQ_FINAL
{
_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_) ZMQ_FINAL
{
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;
}
void resize_buffer (std::size_t new_size_) ZMQ_FINAL
{
_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_;
}
A &get_allocator () { return _allocator; }
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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (decoder_base_t)
};
}
#endif

151
vendor/ZMQ/src/decoder_allocators.cpp vendored Normal file
View File

@ -0,0 +1,151 @@
/*
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 "msg.hpp"
zmq::shared_message_memory_allocator::shared_message_memory_allocator (
std::size_t bufsize_) :
_buf (NULL),
_buf_size (0),
_max_size (bufsize_),
_msg_content (NULL),
_max_counters ((_max_size + msg_t::max_vsm_size - 1) / msg_t::max_vsm_size)
{
}
zmq::shared_message_memory_allocator::shared_message_memory_allocator (
std::size_t bufsize_, std::size_t max_messages_) :
_buf (NULL),
_buf_size (0),
_max_size (bufsize_),
_msg_content (NULL),
_max_counters (max_messages_)
{
}
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)
+ _max_counters * 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);
}
_buf_size = _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);
}
clear ();
}
unsigned char *zmq::shared_message_memory_allocator::release ()
{
unsigned char *b = _buf;
clear ();
return b;
}
void zmq::shared_message_memory_allocator::clear ()
{
_buf = NULL;
_buf_size = 0;
_msg_content = NULL;
}
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 _buf_size;
}
unsigned char *zmq::shared_message_memory_allocator::data ()
{
return _buf + sizeof (zmq::atomic_counter_t);
}

133
vendor/ZMQ/src/decoder_allocators.hpp vendored Normal file
View File

@ -0,0 +1,133 @@
/*
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_) :
_buf_size (bufsize_),
_buf (static_cast<unsigned char *> (std::malloc (_buf_size)))
{
alloc_assert (_buf);
}
~c_single_allocator () { std::free (_buf); }
unsigned char *allocate () { return _buf; }
void deallocate () {}
std::size_t size () const { return _buf_size; }
// This buffer is fixed, size must not be changed
void resize (std::size_t new_size_) { LIBZMQ_UNUSED (new_size_); }
private:
std::size_t _buf_size;
unsigned char *_buf;
ZMQ_NON_COPYABLE_NOR_MOVABLE (c_single_allocator)
};
// 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 max_messages_);
~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 *hint_);
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_) { _buf_size = new_size_; }
zmq::msg_t::content_t *provide_content () { return _msg_content; }
void advance_content () { _msg_content++; }
private:
void clear ();
unsigned char *_buf;
std::size_t _buf_size;
const std::size_t _max_size;
zmq::msg_t::content_t *_msg_content;
std::size_t _max_counters;
};
}
#endif

208
vendor/ZMQ/src/devpoll.cpp vendored Normal file
View File

@ -0,0 +1,208 @@
/*
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 "devpoll.hpp"
#if defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL
#include <sys/devpoll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <limits.h>
#include <algorithm>
#include "devpoll.hpp"
#include "err.hpp"
#include "config.hpp"
#include "i_poll_events.hpp"
zmq::devpoll_t::devpoll_t (const zmq::thread_ctx_t &ctx_) :
worker_poller_base_t (ctx_)
{
devpoll_fd = open ("/dev/poll", O_RDWR);
errno_assert (devpoll_fd != -1);
}
zmq::devpoll_t::~devpoll_t ()
{
// Wait till the worker thread exits.
stop_worker ();
close (devpoll_fd);
}
void zmq::devpoll_t::devpoll_ctl (fd_t fd_, short events_)
{
struct pollfd pfd = {fd_, events_, 0};
ssize_t rc = write (devpoll_fd, &pfd, sizeof pfd);
zmq_assert (rc == sizeof pfd);
}
zmq::devpoll_t::handle_t zmq::devpoll_t::add_fd (fd_t fd_,
i_poll_events *reactor_)
{
check_thread ();
// If the file descriptor table is too small expand it.
fd_table_t::size_type sz = fd_table.size ();
if (sz <= (fd_table_t::size_type) fd_) {
fd_table.resize (fd_ + 1);
while (sz != (fd_table_t::size_type) (fd_ + 1)) {
fd_table[sz].valid = false;
++sz;
}
}
zmq_assert (!fd_table[fd_].valid);
fd_table[fd_].events = 0;
fd_table[fd_].reactor = reactor_;
fd_table[fd_].valid = true;
fd_table[fd_].accepted = false;
devpoll_ctl (fd_, 0);
pending_list.push_back (fd_);
// Increase the load metric of the thread.
adjust_load (1);
return fd_;
}
void zmq::devpoll_t::rm_fd (handle_t handle_)
{
check_thread ();
zmq_assert (fd_table[handle_].valid);
devpoll_ctl (handle_, POLLREMOVE);
fd_table[handle_].valid = false;
// Decrease the load metric of the thread.
adjust_load (-1);
}
void zmq::devpoll_t::set_pollin (handle_t handle_)
{
check_thread ();
devpoll_ctl (handle_, POLLREMOVE);
fd_table[handle_].events |= POLLIN;
devpoll_ctl (handle_, fd_table[handle_].events);
}
void zmq::devpoll_t::reset_pollin (handle_t handle_)
{
check_thread ();
devpoll_ctl (handle_, POLLREMOVE);
fd_table[handle_].events &= ~((short) POLLIN);
devpoll_ctl (handle_, fd_table[handle_].events);
}
void zmq::devpoll_t::set_pollout (handle_t handle_)
{
check_thread ();
devpoll_ctl (handle_, POLLREMOVE);
fd_table[handle_].events |= POLLOUT;
devpoll_ctl (handle_, fd_table[handle_].events);
}
void zmq::devpoll_t::reset_pollout (handle_t handle_)
{
check_thread ();
devpoll_ctl (handle_, POLLREMOVE);
fd_table[handle_].events &= ~((short) POLLOUT);
devpoll_ctl (handle_, fd_table[handle_].events);
}
void zmq::devpoll_t::stop ()
{
check_thread ();
}
int zmq::devpoll_t::max_fds ()
{
return -1;
}
void zmq::devpoll_t::loop ()
{
while (true) {
struct pollfd ev_buf[max_io_events];
struct dvpoll poll_req;
for (pending_list_t::size_type i = 0; i < pending_list.size (); i++)
fd_table[pending_list[i]].accepted = true;
pending_list.clear ();
// Execute any due timers.
int timeout = (int) execute_timers ();
if (get_load () == 0) {
if (timeout == 0)
break;
// TODO sleep for timeout
continue;
}
// Wait for events.
// On Solaris, we can retrieve no more then (OPEN_MAX - 1) events.
poll_req.dp_fds = &ev_buf[0];
#if defined ZMQ_HAVE_SOLARIS
poll_req.dp_nfds = std::min ((int) max_io_events, OPEN_MAX - 1);
#else
poll_req.dp_nfds = max_io_events;
#endif
poll_req.dp_timeout = timeout ? timeout : -1;
int n = ioctl (devpoll_fd, DP_POLL, &poll_req);
if (n == -1 && errno == EINTR)
continue;
errno_assert (n != -1);
for (int i = 0; i < n; i++) {
fd_entry_t *fd_ptr = &fd_table[ev_buf[i].fd];
if (!fd_ptr->valid || !fd_ptr->accepted)
continue;
if (ev_buf[i].revents & (POLLERR | POLLHUP))
fd_ptr->reactor->in_event ();
if (!fd_ptr->valid || !fd_ptr->accepted)
continue;
if (ev_buf[i].revents & POLLOUT)
fd_ptr->reactor->out_event ();
if (!fd_ptr->valid || !fd_ptr->accepted)
continue;
if (ev_buf[i].revents & POLLIN)
fd_ptr->reactor->in_event ();
}
}
}
#endif

101
vendor/ZMQ/src/devpoll.hpp vendored Normal file
View File

@ -0,0 +1,101 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_DEVPOLL_HPP_INCLUDED__
#define __ZMQ_DEVPOLL_HPP_INCLUDED__
// poller.hpp decides which polling mechanism to use.
#include "poller.hpp"
#if defined ZMQ_IOTHREAD_POLLER_USE_DEVPOLL
#include <vector>
#include "ctx.hpp"
#include "fd.hpp"
#include "thread.hpp"
#include "poller_base.hpp"
namespace zmq
{
struct i_poll_events;
// Implements socket polling mechanism using the "/dev/poll" interface.
class devpoll_t ZMQ_FINAL : public worker_poller_base_t
{
public:
typedef fd_t handle_t;
devpoll_t (const thread_ctx_t &ctx_);
~devpoll_t () ZMQ_FINAL;
// "poller" concept.
handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);
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 stop ();
static int max_fds ();
private:
// Main event loop.
void loop () ZMQ_FINAL;
// File descriptor referring to "/dev/poll" pseudo-device.
fd_t devpoll_fd;
struct fd_entry_t
{
short events;
zmq::i_poll_events *reactor;
bool valid;
bool accepted;
};
typedef std::vector<fd_entry_t> fd_table_t;
fd_table_t fd_table;
typedef std::vector<fd_t> pending_list_t;
pending_list_t pending_list;
// Pollset manipulation function.
void devpoll_ctl (fd_t fd_, short events_);
ZMQ_NON_COPYABLE_NOR_MOVABLE (devpoll_t)
};
typedef devpoll_t poller_t;
}
#endif
#endif

169
vendor/ZMQ/src/dgram.cpp vendored Normal file
View File

@ -0,0 +1,169 @@
/*
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_,
bool locally_initiated_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
LIBZMQ_UNUSED (locally_initiated_);
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) {
_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) {
const 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;
}
} else {
// dgram messages are two part only, reject part if more is set
if (msg_->flags () & msg_t::more) {
errno = EINVAL;
return -1;
}
}
// Push the message into the pipe.
if (!_pipe->write (msg_)) {
errno = EAGAIN;
return -1;
}
if (!(msg_->flags () & msg_t::more))
_pipe->flush ();
// flip the more flag
_more_out = !_more_out;
// Detach the message from the data buffer.
const 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 ();
}

74
vendor/ZMQ/src/dgram.hpp vendored Normal file
View File

@ -0,0 +1,74 @@
/*
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 ZMQ_FINAL : 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_,
bool locally_initiated_);
int xsend (zmq::msg_t *msg_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
bool xhas_out ();
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;
// If true, more outgoing message parts are expected.
bool _more_out;
ZMQ_NON_COPYABLE_NOR_MOVABLE (dgram_t)
};
}
#endif

350
vendor/ZMQ/src/dish.cpp vendored Normal file
View File

@ -0,0 +1,350 @@
/*
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.store (0);
const int rc = _message.init ();
errno_assert (rc == 0);
}
zmq::dish_t::~dish_t ()
{
const int rc = _message.close ();
errno_assert (rc == 0);
}
void zmq::dish_t::xattach_pipe (pipe_t *pipe_,
bool subscribe_to_all_,
bool locally_initiated_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
LIBZMQ_UNUSED (locally_initiated_);
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_)
{
const std::string group = std::string (group_);
if (group.length () > ZMQ_GROUP_MAX_LENGTH) {
errno = EINVAL;
return -1;
}
// User cannot join same group twice
if (!_subscriptions.insert (group).second) {
errno = EINVAL;
return -1;
}
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;
const int rc2 = msg.close ();
errno_assert (rc2 == 0);
if (rc != 0)
errno = err;
return rc;
}
int zmq::dish_t::xleave (const char *group_)
{
const std::string group = std::string (group_);
if (group.length () > ZMQ_GROUP_MAX_LENGTH) {
errno = EINVAL;
return -1;
}
if (0 == _subscriptions.erase (group)) {
errno = EINVAL;
return -1;
}
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;
const 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) {
const int rc = msg_->move (_message);
errno_assert (rc == 0);
_has_message = false;
return 0;
}
return xxrecv (msg_);
}
int zmq::dish_t::xxrecv (msg_t *msg_)
{
do {
// Get a message using fair queueing algorithm.
const int rc = _fq.recv (msg_);
// If there's no message available, return immediately.
// The same when error occurs.
if (rc != 0)
return -1;
// Skip non matching messages
} while (0 == _subscriptions.count (std::string (msg_->group ())));
// Found a matching message
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;
const int rc = xxrecv (&_message);
if (rc != 0) {
errno_assert (errno == EAGAIN);
return false;
}
// Matching message found
_has_message = true;
return true;
}
void zmq::dish_t::send_subscriptions (pipe_t *pipe_)
{
for (subscriptions_t::iterator it = _subscriptions.begin (),
end = _subscriptions.end ();
it != 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);
}
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;
const int rc = msg_->init ();
errno_assert (rc == 0);
return 0;
}
const char *group_setting = msg_->group ();
int rc;
if (group_setting[0] != 0)
goto has_group;
// Set the message group
rc = msg_->set_group (static_cast<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);
has_group:
// 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;
const int group_length = static_cast<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 = static_cast<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;
}

121
vendor/ZMQ/src/dish.hpp vendored Normal file
View File

@ -0,0 +1,121 @@
/*
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 "socket_base.hpp"
#include "session_base.hpp"
#include "dist.hpp"
#include "fq.hpp"
#include "msg.hpp"
namespace zmq
{
class ctx_t;
class pipe_t;
class io_thread_t;
class dish_t ZMQ_FINAL : 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_,
bool locally_initiated_);
int xsend (zmq::msg_t *msg_);
bool xhas_out ();
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
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:
int xxrecv (zmq::msg_t *msg_);
// 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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (dish_t)
};
class dish_session_t ZMQ_FINAL : 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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (dish_session_t)
};
}
#endif

237
vendor/ZMQ/src/dist.cpp vendored Normal file
View File

@ -0,0 +1,237 @@
/*
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 ()
{
const 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?
const bool msg_more = (msg_->flags () & msg_t::more) != 0;
// 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;) {
if (!write (_pipes[i], msg_)) {
// Use same index again because entry will have been removed.
} else {
++i;
}
}
int 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 (static_cast<int> (_matching) - 1);
// Push copy of the message to each matching pipe.
int failed = 0;
for (pipes_t::size_type i = 0; i < _matching;) {
if (!write (_pipes[i], msg_)) {
++failed;
// Use same index again because entry will have been removed.
} else {
++i;
}
}
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.
const 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;
}

115
vendor/ZMQ/src/dist.hpp vendored Normal file
View File

@ -0,0 +1,115 @@
/*
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 "macros.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_);
static 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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (dist_t)
};
}
#endif

178
vendor/ZMQ/src/encoder.hpp vendored Normal file
View File

@ -0,0 +1,178 @@
/*
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 "i_encoder.hpp"
#include "msg.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:
explicit encoder_base_t (size_t bufsize_) :
_write_pos (0),
_to_write (0),
_next (NULL),
_new_msg_flag (false),
_buf_size (bufsize_),
_buf (static_cast<unsigned char *> (malloc (bufsize_))),
_in_progress (NULL)
{
alloc_assert (_buf);
}
~encoder_base_t () ZMQ_OVERRIDE { 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.
size_t encode (unsigned char **data_, size_t size_) ZMQ_FINAL
{
unsigned char *buffer = !*data_ ? _buf : *data_;
const size_t buffersize = !*data_ ? _buf_size : 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.
const 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_FINAL
{
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.
void next_step (void *write_pos_,
size_t to_write_,
step_t next_,
bool new_msg_flag_)
{
_write_pos = static_cast<unsigned char *> (write_pos_);
_to_write = to_write_;
_next = next_;
_new_msg_flag = new_msg_flag_;
}
msg_t *in_progress () { return _in_progress; }
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.
const size_t _buf_size;
unsigned char *const _buf;
msg_t *_in_progress;
ZMQ_NON_COPYABLE_NOR_MOVABLE (encoder_base_t)
};
}
#endif

44
vendor/ZMQ/src/endpoint.cpp vendored Normal file
View File

@ -0,0 +1,44 @@
/*
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 "endpoint.hpp"
zmq::endpoint_uri_pair_t
zmq::make_unconnected_connect_endpoint_pair (const std::string &endpoint_)
{
return endpoint_uri_pair_t (std::string (), endpoint_,
endpoint_type_connect);
}
zmq::endpoint_uri_pair_t
zmq::make_unconnected_bind_endpoint_pair (const std::string &endpoint_)
{
return endpoint_uri_pair_t (endpoint_, std::string (), endpoint_type_bind);
}

72
vendor/ZMQ/src/endpoint.hpp vendored Normal file
View File

@ -0,0 +1,72 @@
/*
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_ENDPOINT_HPP_INCLUDED__
#define __ZMQ_ENDPOINT_HPP_INCLUDED__
#include <string>
namespace zmq
{
enum endpoint_type_t
{
endpoint_type_none, // a connection-less endpoint
endpoint_type_bind, // a connection-oriented bind endpoint
endpoint_type_connect // a connection-oriented connect endpoint
};
struct endpoint_uri_pair_t
{
endpoint_uri_pair_t () : local_type (endpoint_type_none) {}
endpoint_uri_pair_t (const std::string &local,
const std::string &remote,
endpoint_type_t local_type) :
local (local),
remote (remote),
local_type (local_type)
{
}
const std::string &identifier () const
{
return local_type == endpoint_type_bind ? local : remote;
}
std::string local, remote;
endpoint_type_t local_type;
};
endpoint_uri_pair_t
make_unconnected_connect_endpoint_pair (const std::string &endpoint_);
endpoint_uri_pair_t
make_unconnected_bind_endpoint_pair (const std::string &endpoint_);
}
#endif

218
vendor/ZMQ/src/epoll.cpp vendored Normal file
View File

@ -0,0 +1,218 @@
/*
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"
#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL
#include "epoll.hpp"
#if !defined ZMQ_HAVE_WINDOWS
#include <unistd.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <algorithm>
#include <new>
#include "macros.hpp"
#include "err.hpp"
#include "config.hpp"
#include "i_poll_events.hpp"
#ifdef ZMQ_HAVE_WINDOWS
const zmq::epoll_t::epoll_fd_t zmq::epoll_t::epoll_retired_fd =
INVALID_HANDLE_VALUE;
#endif
zmq::epoll_t::epoll_t (const zmq::thread_ctx_t &ctx_) :
worker_poller_base_t (ctx_)
{
#ifdef ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC
// Setting this option result in sane behaviour when exec() functions
// are used. Old sockets are closed and don't block TCP ports, avoid
// leaks, etc.
_epoll_fd = epoll_create1 (EPOLL_CLOEXEC);
#else
_epoll_fd = epoll_create (1);
#endif
errno_assert (_epoll_fd != epoll_retired_fd);
}
zmq::epoll_t::~epoll_t ()
{
// Wait till the worker thread exits.
stop_worker ();
#ifdef ZMQ_HAVE_WINDOWS
epoll_close (_epoll_fd);
#else
close (_epoll_fd);
#endif
for (retired_t::iterator it = _retired.begin (), end = _retired.end ();
it != end; ++it) {
LIBZMQ_DELETE (*it);
}
}
zmq::epoll_t::handle_t zmq::epoll_t::add_fd (fd_t fd_, i_poll_events *events_)
{
check_thread ();
poll_entry_t *pe = new (std::nothrow) poll_entry_t;
alloc_assert (pe);
// The memset is not actually needed. It's here to prevent debugging
// tools to complain about using uninitialised memory.
memset (pe, 0, sizeof (poll_entry_t));
pe->fd = fd_;
pe->ev.events = 0;
pe->ev.data.ptr = pe;
pe->events = events_;
const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_ADD, fd_, &pe->ev);
errno_assert (rc != -1);
// Increase the load metric of the thread.
adjust_load (1);
return pe;
}
void zmq::epoll_t::rm_fd (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_DEL, pe->fd, &pe->ev);
errno_assert (rc != -1);
pe->fd = retired_fd;
_retired.push_back (pe);
// Decrease the load metric of the thread.
adjust_load (-1);
}
void zmq::epoll_t::set_pollin (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
pe->ev.events |= EPOLLIN;
const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
errno_assert (rc != -1);
}
void zmq::epoll_t::reset_pollin (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
pe->ev.events &= ~(static_cast<short> (EPOLLIN));
const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
errno_assert (rc != -1);
}
void zmq::epoll_t::set_pollout (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
pe->ev.events |= EPOLLOUT;
const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
errno_assert (rc != -1);
}
void zmq::epoll_t::reset_pollout (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
pe->ev.events &= ~(static_cast<short> (EPOLLOUT));
const int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
errno_assert (rc != -1);
}
void zmq::epoll_t::stop ()
{
check_thread ();
}
int zmq::epoll_t::max_fds ()
{
return -1;
}
void zmq::epoll_t::loop ()
{
epoll_event ev_buf[max_io_events];
while (true) {
// Execute any due timers.
const int timeout = static_cast<int> (execute_timers ());
if (get_load () == 0) {
if (timeout == 0)
break;
// TODO sleep for timeout
continue;
}
// Wait for events.
const int n = epoll_wait (_epoll_fd, &ev_buf[0], max_io_events,
timeout ? timeout : -1);
if (n == -1) {
errno_assert (errno == EINTR);
continue;
}
for (int i = 0; i < n; i++) {
const poll_entry_t *const pe =
static_cast<const poll_entry_t *> (ev_buf[i].data.ptr);
if (pe->fd == retired_fd)
continue;
if (ev_buf[i].events & (EPOLLERR | EPOLLHUP))
pe->events->in_event ();
if (pe->fd == retired_fd)
continue;
if (ev_buf[i].events & EPOLLOUT)
pe->events->out_event ();
if (pe->fd == retired_fd)
continue;
if (ev_buf[i].events & EPOLLIN)
pe->events->in_event ();
}
// Destroy retired event sources.
for (retired_t::iterator it = _retired.begin (), end = _retired.end ();
it != end; ++it) {
LIBZMQ_DELETE (*it);
}
_retired.clear ();
}
}
#endif

114
vendor/ZMQ/src/epoll.hpp vendored Normal file
View File

@ -0,0 +1,114 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_EPOLL_HPP_INCLUDED__
#define __ZMQ_EPOLL_HPP_INCLUDED__
// poller.hpp decides which polling mechanism to use.
#include "poller.hpp"
#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL
#include <vector>
#if defined ZMQ_HAVE_WINDOWS
#include "../external/wepoll/wepoll.h"
#else
#include <sys/epoll.h>
#endif
#include "ctx.hpp"
#include "fd.hpp"
#include "thread.hpp"
#include "poller_base.hpp"
#include "mutex.hpp"
namespace zmq
{
struct i_poll_events;
// This class implements socket polling mechanism using the Linux-specific
// epoll mechanism.
class epoll_t ZMQ_FINAL : public worker_poller_base_t
{
public:
typedef void *handle_t;
epoll_t (const thread_ctx_t &ctx_);
~epoll_t () ZMQ_OVERRIDE;
// "poller" concept.
handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);
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 stop ();
static int max_fds ();
private:
#if defined ZMQ_HAVE_WINDOWS
typedef HANDLE epoll_fd_t;
static const epoll_fd_t epoll_retired_fd;
#else
typedef fd_t epoll_fd_t;
enum
{
epoll_retired_fd = retired_fd
};
#endif
// Main event loop.
void loop ();
// Main epoll file descriptor
epoll_fd_t _epoll_fd;
struct poll_entry_t
{
fd_t fd;
epoll_event ev;
zmq::i_poll_events *events;
};
// List of retired event sources.
typedef std::vector<poll_entry_t *> retired_t;
retired_t _retired;
ZMQ_NON_COPYABLE_NOR_MOVABLE (epoll_t)
};
typedef epoll_t poller_t;
}
#endif
#endif

453
vendor/ZMQ/src/err.cpp vendored Normal file
View File

@ -0,0 +1,453 @@
/*
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"
#include "macros.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
LIBZMQ_UNUSED (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?).
switch (no_) {
case WSABASEERR:
return "No Error";
case WSAEINTR:
return "Interrupted system call";
case WSAEBADF:
return "Bad file number";
case WSAEACCES:
return "Permission denied";
case WSAEFAULT:
return "Bad address";
case WSAEINVAL:
return "Invalid argument";
case WSAEMFILE:
return "Too many open files";
case WSAEWOULDBLOCK:
return wsae_wouldblock_string_;
case WSAEINPROGRESS:
return "Operation now in progress";
case WSAEALREADY:
return "Operation already in progress";
case WSAENOTSOCK:
return "Socket operation on non-socket";
case WSAEDESTADDRREQ:
return "Destination address required";
case WSAEMSGSIZE:
return "Message too long";
case WSAEPROTOTYPE:
return "Protocol wrong type for socket";
case WSAENOPROTOOPT:
return "Bas protocol option";
case WSAEPROTONOSUPPORT:
return "Protocol not supported";
case WSAESOCKTNOSUPPORT:
return "Socket type not supported";
case WSAEOPNOTSUPP:
return "Operation not supported on socket";
case WSAEPFNOSUPPORT:
return "Protocol family not supported";
case WSAEAFNOSUPPORT:
return "Address family not supported by protocol family";
case WSAEADDRINUSE:
return "Address already in use";
case WSAEADDRNOTAVAIL:
return "Can't assign requested address";
case WSAENETDOWN:
return "Network is down";
case WSAENETUNREACH:
return "Network is unreachable";
case WSAENETRESET:
return "Net dropped connection or reset";
case WSAECONNABORTED:
return "Software caused connection abort";
case WSAECONNRESET:
return "Connection reset by peer";
case WSAENOBUFS:
return "No buffer space available";
case WSAEISCONN:
return "Socket is already connected";
case WSAENOTCONN:
return "Socket is not connected";
case WSAESHUTDOWN:
return "Can't send after socket shutdown";
case WSAETOOMANYREFS:
return "Too many references can't splice";
case WSAETIMEDOUT:
return "Connection timed out";
case WSAECONNREFUSED:
return "Connection refused";
case WSAELOOP:
return "Too many levels of symbolic links";
case WSAENAMETOOLONG:
return "File name too long";
case WSAEHOSTDOWN:
return "Host is down";
case WSAEHOSTUNREACH:
return "No Route to Host";
case WSAENOTEMPTY:
return "Directory not empty";
case WSAEPROCLIM:
return "Too many processes";
case WSAEUSERS:
return "Too many users";
case WSAEDQUOT:
return "Disc Quota Exceeded";
case WSAESTALE:
return "Stale NFS file handle";
case WSAEREMOTE:
return "Too many levels of remote in path";
case WSASYSNOTREADY:
return "Network SubSystem is unavailable";
case WSAVERNOTSUPPORTED:
return "WINSOCK DLL Version out of range";
case WSANOTINITIALISED:
return "Successful WSASTARTUP not yet performed";
case WSAHOST_NOT_FOUND:
return "Host not found";
case WSATRY_AGAIN:
return "Non-Authoritative Host not found";
case WSANO_RECOVERY:
return "Non-Recoverable errors: FORMERR REFUSED NOTIMP";
case WSANO_DATA:
return "Valid name no data record of requested";
default:
return "error not defined";
}
}
void zmq::win_error (char *buffer_, size_t buffer_size_)
{
const 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
const DWORD rc = FormatMessageA (
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errcode,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), buffer_,
static_cast<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
#if defined(HAVE_LIBUNWIND) && !defined(__SUNPRO_CC)
#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;
static const char unknown[] = "?";
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)
memcpy (func_name, unknown, sizeof unknown);
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 = unknown;
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 ()
{
}
#endif

183
vendor/ZMQ/src/err.hpp vendored Normal file
View File

@ -0,0 +1,183 @@
/*
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_);
#if defined __clang__
#if __has_feature(attribute_analyzer_noreturn)
void zmq_abort (const char *errmsg_) __attribute__ ((analyzer_noreturn));
#else
void zmq_abort (const char *errmsg_);
#endif
#elif defined __MSCVER__
__declspec(noreturn) void zmq_abort (const char *errmsg_);
#else
void zmq_abort (const char *errmsg_);
#endif
void print_backtrace ();
}
#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 [%i] (%s:%d)\n", \
errstr, WSAGetLastError (), __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

63
vendor/ZMQ/src/fd.hpp vendored Normal file
View File

@ -0,0 +1,63 @@
/*
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
{
typedef zmq_fd_t fd_t;
#ifdef ZMQ_HAVE_WINDOWS
#if defined _MSC_VER && _MSC_VER <= 1400
enum
{
retired_fd = (fd_t) (~0)
};
#else
enum
#if _MSC_VER >= 1800
: fd_t
#endif
{
retired_fd = INVALID_SOCKET
};
#endif
#else
enum
{
retired_fd = -1
};
#endif
}
#endif

150
vendor/ZMQ/src/fq.cpp vendored Normal file
View File

@ -0,0 +1,150 @@
/*
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_) {
_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.
const 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) != 0;
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;
}

84
vendor/ZMQ/src/fq.hpp vendored Normal file
View File

@ -0,0 +1,84 @@
/*
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"
namespace zmq
{
class msg_t;
class pipe_t;
// 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 ();
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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (fq_t)
};
}
#endif

91
vendor/ZMQ/src/gather.cpp vendored Normal file
View File

@ -0,0 +1,91 @@
/*
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_,
bool locally_initiated_)
{
LIBZMQ_UNUSED (subscribe_to_all_);
LIBZMQ_UNUSED (locally_initiated_);
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 ();
}

66
vendor/ZMQ/src/gather.hpp vendored Normal file
View File

@ -0,0 +1,66 @@
/*
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 "fq.hpp"
namespace zmq
{
class ctx_t;
class pipe_t;
class msg_t;
class gather_t ZMQ_FINAL : 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_,
bool locally_initiated_);
int xrecv (zmq::msg_t *msg_);
bool xhas_in ();
void xread_activated (zmq::pipe_t *pipe_);
void xpipe_terminated (zmq::pipe_t *pipe_);
private:
// Fair queueing object for inbound pipes.
fq_t _fq;
ZMQ_NON_COPYABLE_NOR_MOVABLE (gather_t)
};
}
#endif

117
vendor/ZMQ/src/generic_mtrie.hpp vendored Normal file
View File

@ -0,0 +1,117 @@
/*
Copyright (c) 2018 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_GENERIC_MTRIE_HPP_INCLUDED__
#define __ZMQ_GENERIC_MTRIE_HPP_INCLUDED__
#include <stddef.h>
#include <set>
#include "macros.hpp"
#include "stdint.hpp"
namespace zmq
{
// Multi-trie (prefix tree). Each node in the trie is a set of pointers.
template <typename T> class generic_mtrie_t
{
public:
typedef T value_t;
typedef const unsigned char *prefix_t;
enum rm_result
{
not_found,
last_value_removed,
values_remain
};
generic_mtrie_t ();
~generic_mtrie_t ();
// Add key to the trie. Returns true iff no entry with the same prefix_
// and size_ existed before.
bool add (prefix_t prefix_, size_t size_, value_t *value_);
// Remove all entries with a specific value from the trie.
// The call_on_uniq_ flag controls if the callback is invoked
// when there are no entries left on a prefix only (true)
// or on every removal (false). The arg_ argument is passed
// through to the callback function.
template <typename Arg>
void rm (value_t *value_,
void (*func_) (const unsigned char *data_, size_t size_, Arg arg_),
Arg arg_,
bool call_on_uniq_);
// Removes a specific entry from the trie.
// Returns the result of the operation.
rm_result rm (prefix_t prefix_, size_t size_, value_t *value_);
// Calls a callback function for all matching entries, i.e. any node
// corresponding to data_ or a prefix of it. The arg_ argument
// is passed through to the callback function.
template <typename Arg>
void match (prefix_t data_,
size_t size_,
void (*func_) (value_t *value_, Arg arg_),
Arg arg_);
private:
bool is_redundant () const;
typedef std::set<value_t *> pipes_t;
pipes_t *_pipes;
unsigned char _min;
unsigned short _count;
unsigned short _live_nodes;
union _next_t
{
class generic_mtrie_t<value_t> *node;
class generic_mtrie_t<value_t> **table;
} _next;
struct iter
{
generic_mtrie_t<value_t> *node;
generic_mtrie_t<value_t> *next_node;
prefix_t prefix;
size_t size;
unsigned short current_child;
unsigned char new_min;
unsigned char new_max;
bool processed_for_removal;
};
ZMQ_NON_COPYABLE_NOR_MOVABLE (generic_mtrie_t)
};
}
#endif

593
vendor/ZMQ/src/generic_mtrie_impl.hpp vendored Normal file
View File

@ -0,0 +1,593 @@
/*
Copyright (c) 2018 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_GENERIC_MTRIE_IMPL_HPP_INCLUDED__
#define __ZMQ_GENERIC_MTRIE_IMPL_HPP_INCLUDED__
#include <stdlib.h>
#include <new>
#include <algorithm>
#include <list>
#include "err.hpp"
#include "macros.hpp"
#include "generic_mtrie.hpp"
namespace zmq
{
template <typename T>
generic_mtrie_t<T>::generic_mtrie_t () :
_pipes (0),
_min (0),
_count (0),
_live_nodes (0)
{
}
template <typename T> generic_mtrie_t<T>::~generic_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);
}
}
template <typename T>
bool generic_mtrie_t<T>::add (prefix_t prefix_, size_t size_, value_t *pipe_)
{
generic_mtrie_t<value_t> *it = this;
while (size_) {
const unsigned char c = *prefix_;
if (c < it->_min || c >= it->_min + it->_count) {
// The character is out of range of currently handled
// characters. We have to extend the table.
if (!it->_count) {
it->_min = c;
it->_count = 1;
it->_next.node = NULL;
} else if (it->_count == 1) {
const unsigned char oldc = it->_min;
generic_mtrie_t *oldp = it->_next.node;
it->_count = (it->_min < c ? c - it->_min : it->_min - c) + 1;
it->_next.table = static_cast<generic_mtrie_t **> (
malloc (sizeof (generic_mtrie_t *) * it->_count));
alloc_assert (it->_next.table);
for (unsigned short i = 0; i != it->_count; ++i)
it->_next.table[i] = 0;
it->_min = std::min (it->_min, c);
it->_next.table[oldc - it->_min] = oldp;
} else if (it->_min < c) {
// The new character is above the current character range.
const unsigned short old_count = it->_count;
it->_count = c - it->_min + 1;
it->_next.table = static_cast<generic_mtrie_t **> (realloc (
it->_next.table, sizeof (generic_mtrie_t *) * it->_count));
alloc_assert (it->_next.table);
for (unsigned short i = old_count; i != it->_count; i++)
it->_next.table[i] = NULL;
} else {
// The new character is below the current character range.
const unsigned short old_count = it->_count;
it->_count = (it->_min + old_count) - c;
it->_next.table = static_cast<generic_mtrie_t **> (realloc (
it->_next.table, sizeof (generic_mtrie_t *) * it->_count));
alloc_assert (it->_next.table);
memmove (it->_next.table + it->_min - c, it->_next.table,
old_count * sizeof (generic_mtrie_t *));
for (unsigned short i = 0; i != it->_min - c; i++)
it->_next.table[i] = NULL;
it->_min = c;
}
}
// If next node does not exist, create one.
if (it->_count == 1) {
if (!it->_next.node) {
it->_next.node = new (std::nothrow) generic_mtrie_t;
alloc_assert (it->_next.node);
++(it->_live_nodes);
}
++prefix_;
--size_;
it = it->_next.node;
} else {
if (!it->_next.table[c - it->_min]) {
it->_next.table[c - it->_min] =
new (std::nothrow) generic_mtrie_t;
alloc_assert (it->_next.table[c - it->_min]);
++(it->_live_nodes);
}
++prefix_;
--size_;
it = it->_next.table[c - it->_min];
}
}
// We are at the node corresponding to the prefix. We are done.
const bool result = !it->_pipes;
if (!it->_pipes) {
it->_pipes = new (std::nothrow) pipes_t;
alloc_assert (it->_pipes);
}
it->_pipes->insert (pipe_);
return result;
}
template <typename T>
template <typename Arg>
void generic_mtrie_t<T>::rm (value_t *pipe_,
void (*func_) (prefix_t data_,
size_t size_,
Arg arg_),
Arg arg_,
bool call_on_uniq_)
{
// This used to be implemented as a non-tail recursive travesal of the trie,
// which means remote clients controlled the depth of the recursion and the
// stack size.
// To simulate the non-tail recursion, with post-recursion changes depending on
// the result of the recursive call, a stack is used to re-visit the same node
// and operate on it again after children have been visisted.
// A boolean is used to record whether the node had already been visited and to
// determine if the pre- or post- children visit actions have to be taken.
// In the case of a node with (N > 1) children, the node has to be re-visited
// N times, in the correct order after each child visit.
std::list<struct iter> stack;
unsigned char *buff = NULL;
size_t maxbuffsize = 0;
struct iter it = {this, NULL, NULL, 0, 0, 0, 0, false};
stack.push_back (it);
while (!stack.empty ()) {
it = stack.back ();
stack.pop_back ();
if (!it.processed_for_removal) {
// Remove the subscription from this node.
if (it.node->_pipes && it.node->_pipes->erase (pipe_)) {
if (!call_on_uniq_ || it.node->_pipes->empty ()) {
func_ (buff, it.size, arg_);
}
if (it.node->_pipes->empty ()) {
LIBZMQ_DELETE (it.node->_pipes);
}
}
// Adjust the buffer.
if (it.size >= maxbuffsize) {
maxbuffsize = it.size + 256;
buff =
static_cast<unsigned char *> (realloc (buff, maxbuffsize));
alloc_assert (buff);
}
switch (it.node->_count) {
case 0:
// If there are no subnodes in the trie, we are done with this node
// pre-processing.
break;
case 1: {
// If there's one subnode (optimisation).
buff[it.size] = it.node->_min;
// Mark this node as pre-processed and push it, so that the next
// visit after the operation on the child can do the removals.
it.processed_for_removal = true;
stack.push_back (it);
struct iter next = {it.node->_next.node,
NULL,
NULL,
++it.size,
0,
0,
0,
false};
stack.push_back (next);
break;
}
default: {
// If there are multiple subnodes.
// When first visiting this node, initialize the new_min/max parameters
// which will then be used after each child has been processed, on the
// post-children iterations.
if (it.current_child == 0) {
// New min non-null character in the node table after the removal
it.new_min = it.node->_min + it.node->_count - 1;
// New max non-null character in the node table after the removal
it.new_max = it.node->_min;
}
// Mark this node as pre-processed and push it, so that the next
// visit after the operation on the child can do the removals.
buff[it.size] = it.node->_min + it.current_child;
it.processed_for_removal = true;
stack.push_back (it);
if (it.node->_next.table[it.current_child]) {
struct iter next = {
it.node->_next.table[it.current_child],
NULL,
NULL,
it.size + 1,
0,
0,
0,
false};
stack.push_back (next);
}
}
}
} else {
// Reset back for the next time, in case this node doesn't get deleted.
// This is done unconditionally, unlike when setting this variable to true.
it.processed_for_removal = false;
switch (it.node->_count) {
case 0:
// If there are no subnodes in the trie, we are done with this node
// post-processing.
break;
case 1:
// If there's one subnode (optimisation).
// Prune the node if it was made redundant by the removal
if (it.node->_next.node->is_redundant ()) {
LIBZMQ_DELETE (it.node->_next.node);
it.node->_count = 0;
--it.node->_live_nodes;
zmq_assert (it.node->_live_nodes == 0);
}
break;
default:
// If there are multiple subnodes.
{
if (it.node->_next.table[it.current_child]) {
// Prune redundant nodes from the mtrie
if (it.node->_next.table[it.current_child]
->is_redundant ()) {
LIBZMQ_DELETE (
it.node->_next.table[it.current_child]);
zmq_assert (it.node->_live_nodes > 0);
--it.node->_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 (it.current_child + it.node->_min
< it.new_min)
it.new_min =
it.current_child + it.node->_min;
if (it.current_child + it.node->_min
> it.new_max)
it.new_max =
it.current_child + it.node->_min;
}
}
// If there are more children to visit, push again the current
// node, so that pre-processing can happen on the next child.
// If we are done, reset the child index so that the ::rm is
// fully idempotent.
++it.current_child;
if (it.current_child >= it.node->_count)
it.current_child = 0;
else {
stack.push_back (it);
continue;
}
// All children have been visited and removed if needed, and
// all pre- and post-visit operations have been carried.
// Resize/free the node table if needed.
zmq_assert (it.node->_count > 1);
// Free the node table if it's no longer used.
switch (it.node->_live_nodes) {
case 0:
free (it.node->_next.table);
it.node->_next.table = NULL;
it.node->_count = 0;
break;
case 1:
// Compact the node table if possible
// If there's only one live node in the table we can
// switch to using the more compact single-node
// representation
zmq_assert (it.new_min == it.new_max);
zmq_assert (it.new_min >= it.node->_min);
zmq_assert (it.new_min
< it.node->_min + it.node->_count);
{
generic_mtrie_t *node =
it.node->_next
.table[it.new_min - it.node->_min];
zmq_assert (node);
free (it.node->_next.table);
it.node->_next.node = node;
}
it.node->_count = 1;
it.node->_min = it.new_min;
break;
default:
if (it.new_min > it.node->_min
|| it.new_max < it.node->_min
+ it.node->_count - 1) {
zmq_assert (it.new_max - it.new_min + 1
> 1);
generic_mtrie_t **old_table =
it.node->_next.table;
zmq_assert (it.new_min > it.node->_min
|| it.new_max
< it.node->_min
+ it.node->_count - 1);
zmq_assert (it.new_min >= it.node->_min);
zmq_assert (it.new_max
<= it.node->_min
+ it.node->_count - 1);
zmq_assert (it.new_max - it.new_min + 1
< it.node->_count);
it.node->_count =
it.new_max - it.new_min + 1;
it.node->_next.table =
static_cast<generic_mtrie_t **> (
malloc (sizeof (generic_mtrie_t *)
* it.node->_count));
alloc_assert (it.node->_next.table);
memmove (it.node->_next.table,
old_table
+ (it.new_min - it.node->_min),
sizeof (generic_mtrie_t *)
* it.node->_count);
free (old_table);
it.node->_min = it.new_min;
}
}
}
}
}
}
free (buff);
}
template <typename T>
typename generic_mtrie_t<T>::rm_result
generic_mtrie_t<T>::rm (prefix_t prefix_, size_t size_, value_t *pipe_)
{
// This used to be implemented as a non-tail recursive travesal of the trie,
// which means remote clients controlled the depth of the recursion and the
// stack size.
// To simulate the non-tail recursion, with post-recursion changes depending on
// the result of the recursive call, a stack is used to re-visit the same node
// and operate on it again after children have been visisted.
// A boolean is used to record whether the node had already been visited and to
// determine if the pre- or post- children visit actions have to be taken.
rm_result ret = not_found;
std::list<struct iter> stack;
struct iter it = {this, NULL, prefix_, size_, 0, 0, 0, false};
stack.push_back (it);
while (!stack.empty ()) {
it = stack.back ();
stack.pop_back ();
if (!it.processed_for_removal) {
if (!it.size) {
if (!it.node->_pipes) {
ret = not_found;
continue;
}
typename pipes_t::size_type erased =
it.node->_pipes->erase (pipe_);
if (it.node->_pipes->empty ()) {
zmq_assert (erased == 1);
LIBZMQ_DELETE (it.node->_pipes);
ret = last_value_removed;
continue;
}
ret = (erased == 1) ? values_remain : not_found;
continue;
}
it.current_child = *it.prefix;
if (!it.node->_count || it.current_child < it.node->_min
|| it.current_child >= it.node->_min + it.node->_count) {
ret = not_found;
continue;
}
it.next_node =
it.node->_count == 1
? it.node->_next.node
: it.node->_next.table[it.current_child - it.node->_min];
if (!it.next_node) {
ret = not_found;
continue;
}
it.processed_for_removal = true;
stack.push_back (it);
struct iter next = {
it.next_node, NULL, it.prefix + 1, it.size - 1, 0, 0, 0, false};
stack.push_back (next);
} else {
it.processed_for_removal = false;
if (it.next_node->is_redundant ()) {
LIBZMQ_DELETE (it.next_node);
zmq_assert (it.node->_count > 0);
if (it.node->_count == 1) {
it.node->_next.node = NULL;
it.node->_count = 0;
--it.node->_live_nodes;
zmq_assert (it.node->_live_nodes == 0);
} else {
it.node->_next.table[it.current_child - it.node->_min] = 0;
zmq_assert (it.node->_live_nodes > 1);
--it.node->_live_nodes;
// Compact the table if possible
if (it.node->_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 < it.node->_count; ++i)
if (it.node->_next.table[i])
break;
zmq_assert (i < it.node->_count);
it.node->_min += i;
it.node->_count = 1;
generic_mtrie_t *oldp = it.node->_next.table[i];
free (it.node->_next.table);
it.node->_next.table = NULL;
it.node->_next.node = oldp;
} else if (it.current_child == it.node->_min) {
// We can compact the table "from the left"
unsigned short i;
for (i = 1; i < it.node->_count; ++i)
if (it.node->_next.table[i])
break;
zmq_assert (i < it.node->_count);
it.node->_min += i;
it.node->_count -= i;
generic_mtrie_t **old_table = it.node->_next.table;
it.node->_next.table =
static_cast<generic_mtrie_t **> (malloc (
sizeof (generic_mtrie_t *) * it.node->_count));
alloc_assert (it.node->_next.table);
memmove (it.node->_next.table, old_table + i,
sizeof (generic_mtrie_t *) * it.node->_count);
free (old_table);
} else if (it.current_child
== it.node->_min + it.node->_count - 1) {
// We can compact the table "from the right"
unsigned short i;
for (i = 1; i < it.node->_count; ++i)
if (it.node->_next.table[it.node->_count - 1 - i])
break;
zmq_assert (i < it.node->_count);
it.node->_count -= i;
generic_mtrie_t **old_table = it.node->_next.table;
it.node->_next.table =
static_cast<generic_mtrie_t **> (malloc (
sizeof (generic_mtrie_t *) * it.node->_count));
alloc_assert (it.node->_next.table);
memmove (it.node->_next.table, old_table,
sizeof (generic_mtrie_t *) * it.node->_count);
free (old_table);
}
}
}
}
}
return ret;
}
template <typename T>
template <typename Arg>
void generic_mtrie_t<T>::match (prefix_t data_,
size_t size_,
void (*func_) (value_t *pipe_, Arg arg_),
Arg arg_)
{
for (generic_mtrie_t *current = this; current; data_++, size_--) {
// Signal the pipes attached to this node.
if (current->_pipes) {
for (typename pipes_t::iterator it = current->_pipes->begin (),
end = current->_pipes->end ();
it != 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 (current->_count == 1) {
// If there's one subnode (optimisation).
if (data_[0] != current->_min) {
break;
}
current = current->_next.node;
} else {
// If there are multiple subnodes.
if (data_[0] < current->_min
|| data_[0] >= current->_min + current->_count) {
break;
}
current = current->_next.table[data_[0] - current->_min];
}
}
}
template <typename T> bool generic_mtrie_t<T>::is_redundant () const
{
return !_pipes && _live_nodes == 0;
}
}
#endif

236
vendor/ZMQ/src/gssapi_client.cpp vendored Normal file
View File

@ -0,0 +1,236 @@
/*
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"
#ifdef HAVE_LIBGSSAPI_KRB5
#include <string.h>
#include <string>
#include "msg.hpp"
#include "session_base.hpp"
#include "err.hpp"
#include "gssapi_client.hpp"
#include "wire.hpp"
zmq::gssapi_client_t::gssapi_client_t (session_base_t *session_,
const options_t &options_) :
mechanism_base_t (session_, options_),
gssapi_mechanism_base_t (session_, options_),
state (call_next_init),
token_ptr (GSS_C_NO_BUFFER),
mechs (),
security_context_established (false)
{
const std::string::size_type service_size =
options_.gss_service_principal.size ();
service_name = static_cast<char *> (malloc (service_size + 1));
assert (service_name);
memcpy (service_name, options_.gss_service_principal.c_str (),
service_size + 1);
service_name_type = convert_nametype (options_.gss_service_principal_nt);
maj_stat = GSS_S_COMPLETE;
if (!options_.gss_principal.empty ()) {
const std::string::size_type principal_size =
options_.gss_principal.size ();
principal_name = static_cast<char *> (malloc (principal_size + 1));
assert (principal_name);
memcpy (principal_name, options_.gss_principal.c_str (),
principal_size + 1);
gss_OID name_type = convert_nametype (options_.gss_principal_nt);
if (acquire_credentials (principal_name, &cred, name_type) != 0)
maj_stat = GSS_S_FAILURE;
}
mechs.elements = NULL;
mechs.count = 0;
}
zmq::gssapi_client_t::~gssapi_client_t ()
{
if (service_name)
free (service_name);
if (cred)
gss_release_cred (&min_stat, &cred);
}
int zmq::gssapi_client_t::next_handshake_command (msg_t *msg_)
{
if (state == send_ready) {
int rc = produce_ready (msg_);
if (rc == 0)
state = connected;
return rc;
}
if (state != call_next_init) {
errno = EAGAIN;
return -1;
}
if (initialize_context () < 0)
return -1;
if (produce_next_token (msg_) < 0)
return -1;
if (maj_stat != GSS_S_CONTINUE_NEEDED && maj_stat != GSS_S_COMPLETE)
return -1;
if (maj_stat == GSS_S_COMPLETE) {
security_context_established = true;
state = recv_ready;
} else
state = recv_next_token;
return 0;
}
int zmq::gssapi_client_t::process_handshake_command (msg_t *msg_)
{
if (state == recv_ready) {
int rc = process_ready (msg_);
if (rc == 0)
state = send_ready;
return rc;
}
if (state != recv_next_token) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
if (process_next_token (msg_) < 0)
return -1;
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
return -1;
state = call_next_init;
errno_assert (msg_->close () == 0);
errno_assert (msg_->init () == 0);
return 0;
}
int zmq::gssapi_client_t::encode (msg_t *msg_)
{
zmq_assert (state == connected);
if (do_encryption)
return encode_message (msg_);
return 0;
}
int zmq::gssapi_client_t::decode (msg_t *msg_)
{
zmq_assert (state == connected);
if (do_encryption)
return decode_message (msg_);
return 0;
}
zmq::mechanism_t::status_t zmq::gssapi_client_t::status () const
{
return state == connected ? mechanism_t::ready : mechanism_t::handshaking;
}
int zmq::gssapi_client_t::initialize_context ()
{
// principal was specified but credentials could not be acquired
if (principal_name != NULL && cred == NULL)
return -1;
// First time through, import service_name into target_name
if (target_name == GSS_C_NO_NAME) {
send_tok.value = service_name;
send_tok.length = strlen (service_name) + 1;
OM_uint32 maj = gss_import_name (&min_stat, &send_tok,
service_name_type, &target_name);
if (maj != GSS_S_COMPLETE)
return -1;
}
maj_stat = gss_init_sec_context (
&init_sec_min_stat, cred, &context, target_name, mechs.elements,
gss_flags, 0, NULL, token_ptr, NULL, &send_tok, &ret_flags, NULL);
if (token_ptr != GSS_C_NO_BUFFER)
free (recv_tok.value);
return 0;
}
int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
{
if (send_tok.length != 0) { // Server expects another token
if (produce_initiate (msg_, send_tok.value, send_tok.length) < 0) {
gss_release_buffer (&min_stat, &send_tok);
gss_release_name (&min_stat, &target_name);
return -1;
}
}
gss_release_buffer (&min_stat, &send_tok);
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
gss_release_name (&min_stat, &target_name);
if (context != GSS_C_NO_CONTEXT)
gss_delete_sec_context (&min_stat, &context, GSS_C_NO_BUFFER);
return -1;
}
return 0;
}
int zmq::gssapi_client_t::process_next_token (msg_t *msg_)
{
if (maj_stat == GSS_S_CONTINUE_NEEDED) {
if (process_initiate (msg_, &recv_tok.value, recv_tok.length) < 0) {
gss_release_name (&min_stat, &target_name);
return -1;
}
token_ptr = &recv_tok;
}
return 0;
}
#endif

92
vendor/ZMQ/src/gssapi_client.hpp vendored Normal file
View File

@ -0,0 +1,92 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_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 ZMQ_FINAL : public gssapi_mechanism_base_t
{
public:
gssapi_client_t (session_base_t *session_, const options_t &options_);
~gssapi_client_t () ZMQ_FINAL;
// mechanism implementation
int next_handshake_command (msg_t *msg_) ZMQ_FINAL;
int process_handshake_command (msg_t *msg_) ZMQ_FINAL;
int encode (msg_t *msg_) ZMQ_FINAL;
int decode (msg_t *msg_) ZMQ_FINAL;
status_t status () const ZMQ_FINAL;
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

402
vendor/ZMQ/src/gssapi_mechanism_base.cpp vendored Normal file
View File

@ -0,0 +1,402 @@
/*
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"
#ifdef HAVE_LIBGSSAPI_KRB5
#include <string.h>
#include <string>
#include "msg.hpp"
#include "session_base.hpp"
#include "err.hpp"
#include "gssapi_mechanism_base.hpp"
#include "wire.hpp"
zmq::gssapi_mechanism_base_t::gssapi_mechanism_base_t (
session_base_t *session_, const options_t &options_) :
mechanism_base_t (session_, options_),
send_tok (),
recv_tok (),
/// FIXME remove? in_buf (),
target_name (GSS_C_NO_NAME),
principal_name (NULL),
maj_stat (GSS_S_COMPLETE),
min_stat (0),
init_sec_min_stat (0),
ret_flags (0),
gss_flags (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG),
cred (GSS_C_NO_CREDENTIAL),
context (GSS_C_NO_CONTEXT),
do_encryption (!options_.gss_plaintext)
{
}
zmq::gssapi_mechanism_base_t::~gssapi_mechanism_base_t ()
{
if (target_name)
gss_release_name (&min_stat, &target_name);
if (context)
gss_delete_sec_context (&min_stat, &context, GSS_C_NO_BUFFER);
}
int zmq::gssapi_mechanism_base_t::encode_message (msg_t *msg_)
{
// Wrap the token value
int state;
gss_buffer_desc plaintext;
gss_buffer_desc wrapped;
uint8_t flags = 0;
if (msg_->flags () & msg_t::more)
flags |= 0x01;
if (msg_->flags () & msg_t::command)
flags |= 0x02;
uint8_t *plaintext_buffer =
static_cast<uint8_t *> (malloc (msg_->size () + 1));
alloc_assert (plaintext_buffer);
plaintext_buffer[0] = flags;
memcpy (plaintext_buffer + 1, msg_->data (), msg_->size ());
plaintext.value = plaintext_buffer;
plaintext.length = msg_->size () + 1;
maj_stat = gss_wrap (&min_stat, context, 1, GSS_C_QOP_DEFAULT, &plaintext,
&state, &wrapped);
zmq_assert (maj_stat == GSS_S_COMPLETE);
zmq_assert (state);
// Re-initialize msg_ for wrapped text
int rc = msg_->close ();
zmq_assert (rc == 0);
rc = msg_->init_size (8 + 4 + wrapped.length);
zmq_assert (rc == 0);
uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());
// Add command string
memcpy (ptr, "\x07MESSAGE", 8);
ptr += 8;
// Add token length
put_uint32 (ptr, static_cast<uint32_t> (wrapped.length));
ptr += 4;
// Add wrapped token value
memcpy (ptr, wrapped.value, wrapped.length);
ptr += wrapped.length;
gss_release_buffer (&min_stat, &wrapped);
return 0;
}
int zmq::gssapi_mechanism_base_t::decode_message (msg_t *msg_)
{
const uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());
size_t bytes_left = msg_->size ();
int rc = check_basic_command_structure (msg_);
if (rc == -1)
return rc;
// Get command string
if (bytes_left < 8 || memcmp (ptr, "\x07MESSAGE", 8)) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
ptr += 8;
bytes_left -= 8;
// Get token length
if (bytes_left < 4) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE);
errno = EPROTO;
return -1;
}
gss_buffer_desc wrapped;
wrapped.length = get_uint32 (ptr);
ptr += 4;
bytes_left -= 4;
// Get token value
if (bytes_left < wrapped.length) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE);
errno = EPROTO;
return -1;
}
// TODO: instead of malloc/memcpy, can we just do: wrapped.value = ptr;
const size_t alloc_length = wrapped.length ? wrapped.length : 1;
wrapped.value = static_cast<char *> (malloc (alloc_length));
alloc_assert (wrapped.value);
if (wrapped.length) {
memcpy (wrapped.value, ptr, wrapped.length);
ptr += wrapped.length;
bytes_left -= wrapped.length;
}
// Unwrap the token value
int state;
gss_buffer_desc plaintext;
maj_stat = gss_unwrap (&min_stat, context, &wrapped, &plaintext, &state,
(gss_qop_t *) NULL);
if (maj_stat != GSS_S_COMPLETE) {
gss_release_buffer (&min_stat, &plaintext);
free (wrapped.value);
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
errno = EPROTO;
return -1;
}
zmq_assert (state);
// Re-initialize msg_ for plaintext
rc = msg_->close ();
zmq_assert (rc == 0);
rc = msg_->init_size (plaintext.length - 1);
zmq_assert (rc == 0);
const uint8_t flags = static_cast<char *> (plaintext.value)[0];
if (flags & 0x01)
msg_->set_flags (msg_t::more);
if (flags & 0x02)
msg_->set_flags (msg_t::command);
memcpy (msg_->data (), static_cast<char *> (plaintext.value) + 1,
plaintext.length - 1);
gss_release_buffer (&min_stat, &plaintext);
free (wrapped.value);
if (bytes_left > 0) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE);
errno = EPROTO;
return -1;
}
return 0;
}
int zmq::gssapi_mechanism_base_t::produce_initiate (msg_t *msg_,
void *token_value_,
size_t token_length_)
{
zmq_assert (token_value_);
zmq_assert (token_length_ <= 0xFFFFFFFFUL);
const size_t command_size = 9 + 4 + token_length_;
const int rc = msg_->init_size (command_size);
errno_assert (rc == 0);
uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());
// Add command string
memcpy (ptr, "\x08INITIATE", 9);
ptr += 9;
// Add token length
put_uint32 (ptr, static_cast<uint32_t> (token_length_));
ptr += 4;
// Add token value
memcpy (ptr, token_value_, token_length_);
ptr += token_length_;
return 0;
}
int zmq::gssapi_mechanism_base_t::process_initiate (msg_t *msg_,
void **token_value_,
size_t &token_length_)
{
zmq_assert (token_value_);
const uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());
size_t bytes_left = msg_->size ();
int rc = check_basic_command_structure (msg_);
if (rc == -1)
return rc;
// Get command string
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;
}
ptr += 9;
bytes_left -= 9;
// Get token length
if (bytes_left < 4) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);
errno = EPROTO;
return -1;
}
token_length_ = get_uint32 (ptr);
ptr += 4;
bytes_left -= 4;
// Get token value
if (bytes_left < token_length_) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);
errno = EPROTO;
return -1;
}
*token_value_ =
static_cast<char *> (malloc (token_length_ ? token_length_ : 1));
alloc_assert (*token_value_);
if (token_length_) {
memcpy (*token_value_, ptr, token_length_);
ptr += token_length_;
bytes_left -= token_length_;
}
if (bytes_left > 0) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (),
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);
errno = EPROTO;
return -1;
}
return 0;
}
int zmq::gssapi_mechanism_base_t::produce_ready (msg_t *msg_)
{
make_command_with_basic_properties (msg_, "\5READY", 6);
if (do_encryption)
return encode_message (msg_);
return 0;
}
int zmq::gssapi_mechanism_base_t::process_ready (msg_t *msg_)
{
if (do_encryption) {
const int rc = decode_message (msg_);
if (rc != 0)
return rc;
}
const unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());
size_t bytes_left = msg_->size ();
int rc = check_basic_command_structure (msg_);
if (rc == -1)
return rc;
if (bytes_left < 6 || memcmp (ptr, "\x05READY", 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;
rc = parse_metadata (ptr, bytes_left);
if (rc == -1)
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);
return rc;
}
const gss_OID zmq::gssapi_mechanism_base_t::convert_nametype (int zmq_nametype)
{
switch (zmq_nametype) {
case ZMQ_GSSAPI_NT_HOSTBASED:
return GSS_C_NT_HOSTBASED_SERVICE;
case ZMQ_GSSAPI_NT_USER_NAME:
return GSS_C_NT_USER_NAME;
case ZMQ_GSSAPI_NT_KRB5_PRINCIPAL:
#ifdef GSS_KRB5_NT_PRINCIPAL_NAME
return (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME;
#else
return GSS_C_NT_USER_NAME;
#endif
}
return NULL;
}
int zmq::gssapi_mechanism_base_t::acquire_credentials (char *service_name_,
gss_cred_id_t *cred_,
gss_OID name_type_)
{
OM_uint32 maj_stat;
OM_uint32 min_stat;
gss_name_t server_name;
gss_buffer_desc name_buf;
name_buf.value = service_name_;
name_buf.length = strlen ((char *) name_buf.value) + 1;
maj_stat = gss_import_name (&min_stat, &name_buf, name_type_, &server_name);
if (maj_stat != GSS_S_COMPLETE)
return -1;
maj_stat = gss_acquire_cred (&min_stat, server_name, 0, GSS_C_NO_OID_SET,
GSS_C_BOTH, cred_, NULL, NULL);
if (maj_stat != GSS_S_COMPLETE)
return -1;
gss_release_name (&min_stat, &server_name);
return 0;
}
#endif

132
vendor/ZMQ/src/gssapi_mechanism_base.hpp vendored Normal file
View File

@ -0,0 +1,132 @@
/*
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_MECHANISM_BASE_HPP_INCLUDED__
#define __ZMQ_GSSAPI_MECHANISM_BASE_HPP_INCLUDED__
#ifdef HAVE_LIBGSSAPI_KRB5
#if HAVE_GSSAPI_GSSAPI_GENERIC_H
#include <gssapi/gssapi_generic.h>
#endif
#include <gssapi/gssapi_krb5.h>
#include "mechanism_base.hpp"
#include "options.hpp"
namespace zmq
{
class msg_t;
/// Commonalities between clients and servers are captured here.
/// For example, clients and servers both need to produce and
/// process context-level GSSAPI tokens (via INITIATE commands)
/// and per-message GSSAPI tokens (via MESSAGE commands).
class gssapi_mechanism_base_t : public virtual mechanism_base_t
{
public:
gssapi_mechanism_base_t (session_base_t *session_,
const options_t &options_);
~gssapi_mechanism_base_t () ZMQ_OVERRIDE = 0;
protected:
// Produce a context-level GSSAPI token (INITIATE command)
// during security context initialization.
int produce_initiate (msg_t *msg_, void *data_, size_t data_len_);
// Process a context-level GSSAPI token (INITIATE command)
// during security context initialization.
int process_initiate (msg_t *msg_, void **data_, size_t &data_len_);
// Produce a metadata ready msg (READY) to conclude handshake
int produce_ready (msg_t *msg_);
// Process a metadata ready msg (READY)
int process_ready (msg_t *msg_);
// Encode a per-message GSSAPI token (MESSAGE command) using
// the established security context.
int encode_message (msg_t *msg_);
// Decode a per-message GSSAPI token (MESSAGE command) using
// the established security context.
int decode_message (msg_t *msg_);
// Convert ZMQ_GSSAPI_NT values to GSSAPI name_type
static const gss_OID convert_nametype (int zmq_name_type_);
// Acquire security context credentials from the
// underlying mechanism.
static int acquire_credentials (char *principal_name_,
gss_cred_id_t *cred_,
gss_OID name_type_);
protected:
// Opaque GSSAPI token for outgoing data
gss_buffer_desc send_tok;
// Opaque GSSAPI token for incoming data
gss_buffer_desc recv_tok;
// Opaque GSSAPI representation of principal
gss_name_t target_name;
// Human-readable principal name
char *principal_name;
// Status code returned by GSSAPI functions
OM_uint32 maj_stat;
// Status code returned by the underlying mechanism
OM_uint32 min_stat;
// Status code returned by the underlying mechanism
// during context initialization
OM_uint32 init_sec_min_stat;
// Flags returned by GSSAPI (ignored)
OM_uint32 ret_flags;
// Flags returned by GSSAPI (ignored)
OM_uint32 gss_flags;
// Credentials used to establish security context
gss_cred_id_t cred;
// Opaque GSSAPI representation of the security context
gss_ctx_id_t context;
// If true, use gss to encrypt messages. If false, only utilize gss for auth.
bool do_encryption;
};
}
#endif
#endif

248
vendor/ZMQ/src/gssapi_server.cpp vendored Normal file
View File

@ -0,0 +1,248 @@
/*
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"
#ifdef HAVE_LIBGSSAPI_KRB5
#include <string.h>
#include <string>
#include "msg.hpp"
#include "session_base.hpp"
#include "err.hpp"
#include "gssapi_server.hpp"
#include "wire.hpp"
#include <gssapi/gssapi.h>
zmq::gssapi_server_t::gssapi_server_t (session_base_t *session_,
const std::string &peer_address_,
const options_t &options_) :
mechanism_base_t (session_, options_),
gssapi_mechanism_base_t (session_, options_),
zap_client_t (session_, peer_address_, options_),
session (session_),
peer_address (peer_address_),
state (recv_next_token),
security_context_established (false)
{
maj_stat = GSS_S_CONTINUE_NEEDED;
if (!options_.gss_principal.empty ()) {
const std::string::size_type principal_size =
options_.gss_principal.size ();
principal_name = static_cast<char *> (malloc (principal_size + 1));
assert (principal_name);
memcpy (principal_name, options_.gss_principal.c_str (),
principal_size + 1);
gss_OID name_type = convert_nametype (options_.gss_principal_nt);
if (acquire_credentials (principal_name, &cred, name_type) != 0)
maj_stat = GSS_S_FAILURE;
}
}
zmq::gssapi_server_t::~gssapi_server_t ()
{
if (cred)
gss_release_cred (&min_stat, &cred);
if (target_name)
gss_release_name (&min_stat, &target_name);
}
int zmq::gssapi_server_t::next_handshake_command (msg_t *msg_)
{
if (state == send_ready) {
int rc = produce_ready (msg_);
if (rc == 0)
state = recv_ready;
return rc;
}
if (state != send_next_token) {
errno = EAGAIN;
return -1;
}
if (produce_next_token (msg_) < 0)
return -1;
if (maj_stat != GSS_S_CONTINUE_NEEDED && maj_stat != GSS_S_COMPLETE)
return -1;
if (maj_stat == GSS_S_COMPLETE) {
security_context_established = true;
}
state = recv_next_token;
return 0;
}
int zmq::gssapi_server_t::process_handshake_command (msg_t *msg_)
{
if (state == recv_ready) {
int rc = process_ready (msg_);
if (rc == 0)
state = connected;
return rc;
}
if (state != recv_next_token) {
session->get_socket ()->event_handshake_failed_protocol (
session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
errno = EPROTO;
return -1;
}
if (security_context_established) {
// Use ZAP protocol (RFC 27) to authenticate the user.
// Note that rc will be -1 only if ZAP is not set up, but if it was
// requested and it does not work properly the program will abort.
bool expecting_zap_reply = false;
int rc = session->zap_connect ();
if (rc == 0) {
send_zap_request ();
rc = receive_and_process_zap_reply ();
if (rc != 0) {
if (rc == -1)
return -1;
expecting_zap_reply = true;
}
}
state = expecting_zap_reply ? expect_zap_reply : send_ready;
return 0;
}
if (process_next_token (msg_) < 0)
return -1;
accept_context ();
state = send_next_token;
errno_assert (msg_->close () == 0);
errno_assert (msg_->init () == 0);
return 0;
}
void zmq::gssapi_server_t::send_zap_request ()
{
gss_buffer_desc principal;
gss_display_name (&min_stat, target_name, &principal, NULL);
zap_client_t::send_zap_request (
"GSSAPI", 6, reinterpret_cast<const uint8_t *> (principal.value),
principal.length);
gss_release_buffer (&min_stat, &principal);
}
int zmq::gssapi_server_t::encode (msg_t *msg_)
{
zmq_assert (state == connected);
if (do_encryption)
return encode_message (msg_);
return 0;
}
int zmq::gssapi_server_t::decode (msg_t *msg_)
{
zmq_assert (state == connected);
if (do_encryption)
return decode_message (msg_);
return 0;
}
int zmq::gssapi_server_t::zap_msg_available ()
{
if (state != expect_zap_reply) {
errno = EFSM;
return -1;
}
const int rc = receive_and_process_zap_reply ();
if (rc == 0)
state = send_ready;
return rc == -1 ? -1 : 0;
}
zmq::mechanism_t::status_t zmq::gssapi_server_t::status () const
{
return state == connected ? mechanism_t::ready : mechanism_t::handshaking;
}
int zmq::gssapi_server_t::produce_next_token (msg_t *msg_)
{
if (send_tok.length != 0) { // Client expects another token
if (produce_initiate (msg_, send_tok.value, send_tok.length) < 0)
return -1;
gss_release_buffer (&min_stat, &send_tok);
}
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
gss_release_name (&min_stat, &target_name);
if (context != GSS_C_NO_CONTEXT)
gss_delete_sec_context (&min_stat, &context, GSS_C_NO_BUFFER);
return -1;
}
return 0;
}
int zmq::gssapi_server_t::process_next_token (msg_t *msg_)
{
if (maj_stat == GSS_S_CONTINUE_NEEDED) {
if (process_initiate (msg_, &recv_tok.value, recv_tok.length) < 0) {
if (target_name != GSS_C_NO_NAME)
gss_release_name (&min_stat, &target_name);
return -1;
}
}
return 0;
}
void zmq::gssapi_server_t::accept_context ()
{
maj_stat = gss_accept_sec_context (
&init_sec_min_stat, &context, cred, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
&target_name, &doid, &send_tok, &ret_flags, NULL, NULL);
if (recv_tok.value) {
free (recv_tok.value);
recv_tok.value = NULL;
}
}
#endif

93
vendor/ZMQ/src/gssapi_server.hpp vendored Normal file
View File

@ -0,0 +1,93 @@
/*
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 ZMQ_FINAL : 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_);
~gssapi_server_t () ZMQ_FINAL;
// mechanism implementation
int next_handshake_command (msg_t *msg_) ZMQ_FINAL;
int process_handshake_command (msg_t *msg_) ZMQ_FINAL;
int encode (msg_t *msg_) ZMQ_FINAL;
int decode (msg_t *msg_) ZMQ_FINAL;
int zap_msg_available () ZMQ_FINAL;
status_t status () const ZMQ_FINAL;
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

61
vendor/ZMQ/src/i_decoder.hpp vendored Normal file
View File

@ -0,0 +1,61 @@
/*
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 "macros.hpp"
#include "stdint.hpp"
namespace zmq
{
class msg_t;
// Interface to be implemented by message decoder.
class i_decoder
{
public:
virtual ~i_decoder () ZMQ_DEFAULT;
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

58
vendor/ZMQ/src/i_encoder.hpp vendored Normal file
View File

@ -0,0 +1,58 @@
/*
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 "macros.hpp"
#include "stdint.hpp"
namespace zmq
{
// Forward declaration
class msg_t;
// Interface to be implemented by message encoder.
struct i_encoder
{
virtual ~i_encoder () ZMQ_DEFAULT;
// 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

82
vendor/ZMQ/src/i_engine.hpp vendored Normal file
View File

@ -0,0 +1,82 @@
/*
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__
#include "endpoint.hpp"
#include "macros.hpp"
namespace zmq
{
class io_thread_t;
// Abstract interface to be implemented by various engines.
struct i_engine
{
enum error_reason_t
{
protocol_error,
connection_error,
timeout_error
};
virtual ~i_engine () ZMQ_DEFAULT;
// Indicate if the engine has an handshake stage.
// If engine has handshake stage, engine must call session.engine_ready when the handshake is complete.
virtual bool has_handshake_stage () = 0;
// 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.
// Returns false if the engine was deleted due to an error.
// TODO it is probably better to change the design such that the engine
// does not delete itself
virtual bool 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 endpoint_uri_pair_t &get_endpoint () const = 0;
};
}
#endif

58
vendor/ZMQ/src/i_mailbox.hpp vendored Normal file
View File

@ -0,0 +1,58 @@
/*
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 "macros.hpp"
#include "stdint.hpp"
namespace zmq
{
// Interface to be implemented by mailbox.
class i_mailbox
{
public:
virtual ~i_mailbox () ZMQ_DEFAULT;
virtual void send (const command_t &cmd_) = 0;
virtual int recv (command_t *cmd_, int timeout_) = 0;
#ifdef HAVE_FORK
// close the file descriptors in the signaller. This is used in a forked
// child process to close the file descriptors so that they do not interfere
// with the context in the parent process.
virtual void forked () = 0;
#endif
};
}
#endif

55
vendor/ZMQ/src/i_poll_events.hpp vendored Normal file
View File

@ -0,0 +1,55 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__
#define __ZMQ_I_POLL_EVENTS_HPP_INCLUDED__
#include "macros.hpp"
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 () ZMQ_DEFAULT;
// 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

116
vendor/ZMQ/src/io_object.cpp vendored Normal file
View File

@ -0,0 +1,116 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "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);
}

83
vendor/ZMQ/src/io_object.hpp vendored Normal file
View File

@ -0,0 +1,83 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_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 () ZMQ_OVERRIDE;
// 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 timeout_, int id_);
void cancel_timer (int id_);
// i_poll_events interface implementation.
void in_event () ZMQ_OVERRIDE;
void out_event () ZMQ_OVERRIDE;
void timer_event (int id_) ZMQ_OVERRIDE;
private:
poller_t *_poller;
ZMQ_NON_COPYABLE_NOR_MOVABLE (io_object_t)
};
}
#endif

121
vendor/ZMQ/src/io_thread.cpp vendored Normal file
View File

@ -0,0 +1,121 @@
/*
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_),
_mailbox_handle (static_cast<poller_t::handle_t> (NULL))
{
_poller = new (std::nothrow) poller_t (*ctx_);
alloc_assert (_poller);
if (_mailbox.get_fd () != retired_fd) {
_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 ()
{
char name[16] = "";
snprintf (name, sizeof (name), "IO/%u",
get_tid () - zmq::ctx_t::reaper_tid - 1);
// Start the underlying I/O thread.
_poller->start (name);
}
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 () const
{
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 () const
{
zmq_assert (_poller);
return _poller;
}
void zmq::io_thread_t::process_stop ()
{
zmq_assert (_mailbox_handle);
_poller->rm_fd (_mailbox_handle);
_poller->stop ();
}

92
vendor/ZMQ/src/io_thread.hpp vendored Normal file
View File

@ -0,0 +1,92 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IO_THREAD_HPP_INCLUDED__
#define __ZMQ_IO_THREAD_HPP_INCLUDED__
#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 ZMQ_FINAL : 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 () const;
// Command handlers.
void process_stop ();
// Returns load experienced by the I/O thread.
int get_load () const;
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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (io_thread_t)
};
}
#endif

945
vendor/ZMQ/src/ip.cpp vendored Normal file
View File

@ -0,0 +1,945 @@
/*
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"
#include "config.hpp"
#include "address.hpp"
#if !defined ZMQ_HAVE_WINDOWS
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdlib.h>
#include <unistd.h>
#include <vector>
#else
#include "tcp.hpp"
#ifdef ZMQ_HAVE_IPC
#include "ipc_address.hpp"
#endif
#include <direct.h>
#define rmdir _rmdir
#define unlink _unlink
#endif
#if defined ZMQ_HAVE_OPENVMS || defined ZMQ_HAVE_VXWORKS
#include <ioctl.h>
#endif
#if defined ZMQ_HAVE_VXWORKS
#include <unistd.h>
#include <sockLib.h>
#include <ioLib.h>
#endif
#if defined ZMQ_HAVE_EVENTFD
#include <sys/eventfd.h>
#endif
#if defined ZMQ_HAVE_OPENPGM
#ifdef ZMQ_HAVE_WINDOWS
#define __PGM_WININT_H__
#endif
#include <pgm/pgm.h>
#endif
#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
#ifndef ZMQ_HAVE_WINDOWS
// Acceptable temporary directory environment variables
static const char *tmp_env_vars[] = {
"TMPDIR", "TEMPDIR", "TMP",
0 // Sentinel
};
#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
#if defined ZMQ_HAVE_WINDOWS && defined WSA_FLAG_NO_HANDLE_INHERIT
// if supported, create socket with WSA_FLAG_NO_HANDLE_INHERIT, such that
// the race condition in making it non-inheritable later is avoided
const fd_t s = WSASocket (domain_, type_, protocol_, NULL, 0,
WSA_FLAG_OVERLAPPED | WSA_FLAG_NO_HANDLE_INHERIT);
#else
const fd_t s = socket (domain_, type_, protocol_);
#endif
if (s == retired_fd) {
#ifdef ZMQ_HAVE_WINDOWS
errno = wsa_error_to_errno (WSAGetLastError ());
#endif
return retired_fd;
}
make_socket_noninheritable (s);
// 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;
const int rc = ioctlsocket (s_, FIONBIO, &nonblock);
wsa_assert (rc != SOCKET_ERROR);
#elif defined ZMQ_HAVE_OPENVMS || defined ZMQ_HAVE_VXWORKS
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_)
{
LIBZMQ_UNUSED (s_);
#if defined IPV6_V6ONLY && !defined ZMQ_HAVE_OPENBSD \
&& !defined ZMQ_HAVE_DRAGONFLY
#ifdef ZMQ_HAVE_WINDOWS
DWORD flag = 0;
#else
int flag = 0;
#endif
const int rc = setsockopt (s_, IPPROTO_IPV6, IPV6_V6ONLY,
reinterpret_cast<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_)
{
struct sockaddr_storage ss;
const zmq_socklen_t addrlen =
get_socket_address (sockfd_, socket_end_remote, &ss);
if (addrlen == 0) {
#ifdef ZMQ_HAVE_WINDOWS
const int last_error = WSAGetLastError ();
wsa_assert (last_error != WSANOTINITIALISED && last_error != WSAEFAULT
&& last_error != WSAEINPROGRESS
&& last_error != WSAENOTSOCK);
#elif !defined(TARGET_OS_IPHONE) || !TARGET_OS_IPHONE
errno_assert (errno != EBADF && errno != EFAULT && errno != ENOTSOCK);
#else
errno_assert (errno != EFAULT && errno != ENOTSOCK);
#endif
return 0;
}
char host[NI_MAXHOST];
const int rc =
getnameinfo (reinterpret_cast<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 static_cast<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<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<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
}
void zmq::set_socket_priority (fd_t s_, int priority_)
{
#ifdef ZMQ_HAVE_SO_PRIORITY
int rc =
setsockopt (s_, SOL_SOCKET, SO_PRIORITY,
reinterpret_cast<char *> (&priority_), sizeof (priority_));
errno_assert (rc == 0);
#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;
}
int zmq::bind_to_device (fd_t s_, const std::string &bound_device_)
{
#ifdef ZMQ_HAVE_SO_BINDTODEVICE
int rc = setsockopt (s_, SOL_SOCKET, SO_BINDTODEVICE,
bound_device_.c_str (), bound_device_.length ());
if (rc != 0) {
assert_success_or_recoverable (s_, rc);
return -1;
}
return 0;
#else
LIBZMQ_UNUSED (s_);
LIBZMQ_UNUSED (bound_device_);
errno = ENOTSUP;
return -1;
#endif
}
bool zmq::initialize_network ()
{
#if defined ZMQ_HAVE_OPENPGM
// Init PGM transport. Ensure threading and timer are enabled. Find PGM
// protocol ID. Note that if you want to use gettimeofday and sleep for
// openPGM timing, set environment variables PGM_TIMER to "GTOD" and
// PGM_SLEEP to "USLEEP".
pgm_error_t *pgm_error = NULL;
const bool ok = pgm_init (&pgm_error);
if (ok != TRUE) {
// Invalid parameters don't set pgm_error_t
zmq_assert (pgm_error != NULL);
if (pgm_error->domain == PGM_ERROR_DOMAIN_TIME
&& (pgm_error->code == PGM_ERROR_FAILED)) {
// Failed to access RTC or HPET device.
pgm_error_free (pgm_error);
errno = EINVAL;
return false;
}
// PGM_ERROR_DOMAIN_ENGINE: WSAStartup errors or missing WSARecvMsg.
zmq_assert (false);
}
#endif
#ifdef ZMQ_HAVE_WINDOWS
// Intialise Windows sockets. Note that WSAStartup can be called multiple
// times given that WSACleanup will be called for each WSAStartup.
const WORD version_requested = MAKEWORD (2, 2);
WSADATA wsa_data;
const int rc = WSAStartup (version_requested, &wsa_data);
zmq_assert (rc == 0);
zmq_assert (LOBYTE (wsa_data.wVersion) == 2
&& HIBYTE (wsa_data.wVersion) == 2);
#endif
return true;
}
void zmq::shutdown_network ()
{
#ifdef ZMQ_HAVE_WINDOWS
// On Windows, uninitialise socket layer.
const int rc = WSACleanup ();
wsa_assert (rc != SOCKET_ERROR);
#endif
#if defined ZMQ_HAVE_OPENPGM
// Shut down the OpenPGM library.
if (pgm_shutdown () != TRUE)
zmq_assert (false);
#endif
}
#if defined ZMQ_HAVE_WINDOWS
static void tune_socket (const SOCKET socket_)
{
BOOL tcp_nodelay = 1;
const int rc =
setsockopt (socket_, IPPROTO_TCP, TCP_NODELAY,
reinterpret_cast<char *> (&tcp_nodelay), sizeof tcp_nodelay);
wsa_assert (rc != SOCKET_ERROR);
zmq::tcp_tune_loopback_fast_path (socket_);
}
static int make_fdpair_tcpip (zmq::fd_t *r_, zmq::fd_t *w_)
{
#if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP
// Windows CE does not manage security attributes
SECURITY_DESCRIPTOR sd;
SECURITY_ATTRIBUTES sa;
memset (&sd, 0, sizeof sd);
memset (&sa, 0, sizeof sa);
InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
SetSecurityDescriptorDacl (&sd, TRUE, 0, FALSE);
sa.nLength = sizeof (SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = &sd;
#endif
// This function has to be in a system-wide critical section so that
// two instances of the library don't accidentally create signaler
// crossing the process boundary.
// We'll use named event object to implement the critical section.
// Note that if the event object already exists, the CreateEvent requests
// EVENT_ALL_ACCESS access right. If this fails, we try to open
// the event object asking for SYNCHRONIZE access only.
HANDLE sync = NULL;
// Create critical section only if using fixed signaler port
// Use problematic Event implementation for compatibility if using old port 5905.
// Otherwise use Mutex implementation.
const int event_signaler_port = 5905;
if (zmq::signaler_port == event_signaler_port) {
#if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP
sync =
CreateEventW (&sa, FALSE, TRUE, L"Global\\zmq-signaler-port-sync");
#else
sync =
CreateEventW (NULL, FALSE, TRUE, L"Global\\zmq-signaler-port-sync");
#endif
if (sync == NULL && GetLastError () == ERROR_ACCESS_DENIED)
sync = OpenEventW (SYNCHRONIZE | EVENT_MODIFY_STATE, FALSE,
L"Global\\zmq-signaler-port-sync");
win_assert (sync != NULL);
} else if (zmq::signaler_port != 0) {
wchar_t mutex_name[MAX_PATH];
#ifdef __MINGW32__
_snwprintf (mutex_name, MAX_PATH, L"Global\\zmq-signaler-port-%d",
zmq::signaler_port);
#else
swprintf (mutex_name, MAX_PATH, L"Global\\zmq-signaler-port-%d",
zmq::signaler_port);
#endif
#if !defined _WIN32_WCE && !defined ZMQ_HAVE_WINDOWS_UWP
sync = CreateMutexW (&sa, FALSE, mutex_name);
#else
sync = CreateMutexW (NULL, FALSE, mutex_name);
#endif
if (sync == NULL && GetLastError () == ERROR_ACCESS_DENIED)
sync = OpenMutexW (SYNCHRONIZE, FALSE, mutex_name);
win_assert (sync != NULL);
}
// Windows has no 'socketpair' function. CreatePipe is no good as pipe
// handles cannot be polled on. Here we create the socketpair by hand.
*w_ = INVALID_SOCKET;
*r_ = INVALID_SOCKET;
// Create listening socket.
SOCKET listener;
listener = zmq::open_socket (AF_INET, SOCK_STREAM, 0);
wsa_assert (listener != INVALID_SOCKET);
// Set SO_REUSEADDR and TCP_NODELAY on listening socket.
BOOL so_reuseaddr = 1;
int rc = setsockopt (listener, SOL_SOCKET, SO_REUSEADDR,
reinterpret_cast<char *> (&so_reuseaddr),
sizeof so_reuseaddr);
wsa_assert (rc != SOCKET_ERROR);
tune_socket (listener);
// Init sockaddr to signaler port.
struct sockaddr_in addr;
memset (&addr, 0, sizeof addr);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
addr.sin_port = htons (zmq::signaler_port);
// Create the writer socket.
*w_ = zmq::open_socket (AF_INET, SOCK_STREAM, 0);
wsa_assert (*w_ != INVALID_SOCKET);
if (sync != NULL) {
// Enter the critical section.
const DWORD dwrc = WaitForSingleObject (sync, INFINITE);
zmq_assert (dwrc == WAIT_OBJECT_0 || dwrc == WAIT_ABANDONED);
}
// Bind listening socket to signaler port.
rc = bind (listener, reinterpret_cast<const struct sockaddr *> (&addr),
sizeof addr);
if (rc != SOCKET_ERROR && zmq::signaler_port == 0) {
// Retrieve ephemeral port number
int addrlen = sizeof addr;
rc = getsockname (listener, reinterpret_cast<struct sockaddr *> (&addr),
&addrlen);
}
// Listen for incoming connections.
if (rc != SOCKET_ERROR) {
rc = listen (listener, 1);
}
// Connect writer to the listener.
if (rc != SOCKET_ERROR) {
rc = connect (*w_, reinterpret_cast<struct sockaddr *> (&addr),
sizeof addr);
}
// Accept connection from writer.
if (rc != SOCKET_ERROR) {
// Set TCP_NODELAY on writer socket.
tune_socket (*w_);
*r_ = accept (listener, NULL, NULL);
}
// Send/receive large chunk to work around TCP slow start
// This code is a workaround for #1608
if (*r_ != INVALID_SOCKET) {
const size_t dummy_size =
1024 * 1024; // 1M to overload default receive buffer
unsigned char *dummy =
static_cast<unsigned char *> (malloc (dummy_size));
wsa_assert (dummy);
int still_to_send = static_cast<int> (dummy_size);
int still_to_recv = static_cast<int> (dummy_size);
while (still_to_send || still_to_recv) {
int nbytes;
if (still_to_send > 0) {
nbytes = ::send (
*w_,
reinterpret_cast<char *> (dummy + dummy_size - still_to_send),
still_to_send, 0);
wsa_assert (nbytes != SOCKET_ERROR);
still_to_send -= nbytes;
}
nbytes = ::recv (
*r_,
reinterpret_cast<char *> (dummy + dummy_size - still_to_recv),
still_to_recv, 0);
wsa_assert (nbytes != SOCKET_ERROR);
still_to_recv -= nbytes;
}
free (dummy);
}
// Save errno if error occurred in bind/listen/connect/accept.
int saved_errno = 0;
if (*r_ == INVALID_SOCKET)
saved_errno = WSAGetLastError ();
// We don't need the listening socket anymore. Close it.
rc = closesocket (listener);
wsa_assert (rc != SOCKET_ERROR);
if (sync != NULL) {
// Exit the critical section.
BOOL brc;
if (zmq::signaler_port == event_signaler_port)
brc = SetEvent (sync);
else
brc = ReleaseMutex (sync);
win_assert (brc != 0);
// Release the kernel object
brc = CloseHandle (sync);
win_assert (brc != 0);
}
if (*r_ != INVALID_SOCKET) {
zmq::make_socket_noninheritable (*r_);
return 0;
}
// Cleanup writer if connection failed
if (*w_ != INVALID_SOCKET) {
rc = closesocket (*w_);
wsa_assert (rc != SOCKET_ERROR);
*w_ = INVALID_SOCKET;
}
// Set errno from saved value
errno = zmq::wsa_error_to_errno (saved_errno);
return -1;
}
#endif
int zmq::make_fdpair (fd_t *r_, fd_t *w_)
{
#if defined ZMQ_HAVE_EVENTFD
int flags = 0;
#if defined ZMQ_HAVE_EVENTFD_CLOEXEC
// Setting this option result in sane behaviour when exec() functions
// are used. Old sockets are closed and don't block TCP ports, avoid
// leaks, etc.
flags |= EFD_CLOEXEC;
#endif
fd_t fd = eventfd (0, flags);
if (fd == -1) {
errno_assert (errno == ENFILE || errno == EMFILE);
*w_ = *r_ = -1;
return -1;
}
*w_ = *r_ = fd;
return 0;
#elif defined ZMQ_HAVE_WINDOWS
#ifdef ZMQ_HAVE_IPC
ipc_address_t address;
std::string dirname, filename;
sockaddr_un lcladdr;
socklen_t lcladdr_len = sizeof lcladdr;
int rc = 0;
int saved_errno = 0;
// Create a listening socket.
const SOCKET listener = open_socket (AF_UNIX, SOCK_STREAM, 0);
if (listener == retired_fd) {
// This may happen if the library was built on a system supporting AF_UNIX, but the system running doesn't support it.
goto try_tcpip;
}
create_ipc_wildcard_address (dirname, filename);
// Initialise the address structure.
rc = address.resolve (filename.c_str ());
if (rc != 0) {
goto error_closelistener;
}
// Bind the socket to the file path.
rc = bind (listener, const_cast<sockaddr *> (address.addr ()),
address.addrlen ());
if (rc != 0) {
errno = wsa_error_to_errno (WSAGetLastError ());
goto error_closelistener;
}
// Listen for incoming connections.
rc = listen (listener, 1);
if (rc != 0) {
errno = wsa_error_to_errno (WSAGetLastError ());
goto error_closelistener;
}
rc = getsockname (listener, reinterpret_cast<struct sockaddr *> (&lcladdr),
&lcladdr_len);
wsa_assert (rc != -1);
// Create the client socket.
*w_ = open_socket (AF_UNIX, SOCK_STREAM, 0);
if (*w_ == -1) {
errno = wsa_error_to_errno (WSAGetLastError ());
goto error_closelistener;
}
// Connect to the remote peer.
rc = ::connect (*w_, reinterpret_cast<const struct sockaddr *> (&lcladdr),
lcladdr_len);
if (rc == -1) {
goto error_closeclient;
}
*r_ = accept (listener, NULL, NULL);
errno_assert (*r_ != -1);
// Close the listener socket, we don't need it anymore.
rc = closesocket (listener);
wsa_assert (rc == 0);
// Cleanup temporary socket file descriptor
if (!filename.empty ()) {
rc = ::unlink (filename.c_str ());
if ((rc == 0) && !dirname.empty ()) {
rc = ::rmdir (dirname.c_str ());
dirname.clear ();
}
filename.clear ();
}
return 0;
error_closeclient:
saved_errno = errno;
rc = closesocket (*w_);
wsa_assert (rc == 0);
errno = saved_errno;
error_closelistener:
saved_errno = errno;
rc = closesocket (listener);
wsa_assert (rc == 0);
// Cleanup temporary socket file descriptor
if (!filename.empty ()) {
rc = ::unlink (filename.c_str ());
if ((rc == 0) && !dirname.empty ()) {
rc = ::rmdir (dirname.c_str ());
dirname.clear ();
}
filename.clear ();
}
errno = saved_errno;
return -1;
try_tcpip:
// try to fallback to TCP/IP
// TODO: maybe remember this decision permanently?
#endif
return make_fdpair_tcpip (r_, w_);
#elif defined ZMQ_HAVE_OPENVMS
// Whilst OpenVMS supports socketpair - it maps to AF_INET only. Further,
// it does not set the socket options TCP_NODELAY and TCP_NODELACK which
// can lead to performance problems.
//
// The bug will be fixed in V5.6 ECO4 and beyond. In the meantime, we'll
// create the socket pair manually.
struct sockaddr_in lcladdr;
memset (&lcladdr, 0, sizeof lcladdr);
lcladdr.sin_family = AF_INET;
lcladdr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
lcladdr.sin_port = 0;
int listener = open_socket (AF_INET, SOCK_STREAM, 0);
errno_assert (listener != -1);
int on = 1;
int rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);
errno_assert (rc != -1);
rc = setsockopt (listener, IPPROTO_TCP, TCP_NODELACK, &on, sizeof on);
errno_assert (rc != -1);
rc = bind (listener, (struct sockaddr *) &lcladdr, sizeof lcladdr);
errno_assert (rc != -1);
socklen_t lcladdr_len = sizeof lcladdr;
rc = getsockname (listener, (struct sockaddr *) &lcladdr, &lcladdr_len);
errno_assert (rc != -1);
rc = listen (listener, 1);
errno_assert (rc != -1);
*w_ = open_socket (AF_INET, SOCK_STREAM, 0);
errno_assert (*w_ != -1);
rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY, &on, sizeof on);
errno_assert (rc != -1);
rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELACK, &on, sizeof on);
errno_assert (rc != -1);
rc = connect (*w_, (struct sockaddr *) &lcladdr, sizeof lcladdr);
errno_assert (rc != -1);
*r_ = accept (listener, NULL, NULL);
errno_assert (*r_ != -1);
close (listener);
return 0;
#elif defined ZMQ_HAVE_VXWORKS
struct sockaddr_in lcladdr;
memset (&lcladdr, 0, sizeof lcladdr);
lcladdr.sin_family = AF_INET;
lcladdr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
lcladdr.sin_port = 0;
int listener = open_socket (AF_INET, SOCK_STREAM, 0);
errno_assert (listener != -1);
int on = 1;
int rc =
setsockopt (listener, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof on);
errno_assert (rc != -1);
rc = bind (listener, (struct sockaddr *) &lcladdr, sizeof lcladdr);
errno_assert (rc != -1);
socklen_t lcladdr_len = sizeof lcladdr;
rc = getsockname (listener, (struct sockaddr *) &lcladdr,
(int *) &lcladdr_len);
errno_assert (rc != -1);
rc = listen (listener, 1);
errno_assert (rc != -1);
*w_ = open_socket (AF_INET, SOCK_STREAM, 0);
errno_assert (*w_ != -1);
rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof on);
errno_assert (rc != -1);
rc = connect (*w_, (struct sockaddr *) &lcladdr, sizeof lcladdr);
errno_assert (rc != -1);
*r_ = accept (listener, NULL, NULL);
errno_assert (*r_ != -1);
close (listener);
return 0;
#else
// All other implementations support socketpair()
int sv[2];
int type = SOCK_STREAM;
// Setting this option result in sane behaviour when exec() functions
// are used. Old sockets are closed and don't block TCP ports, avoid
// leaks, etc.
#if defined ZMQ_HAVE_SOCK_CLOEXEC
type |= SOCK_CLOEXEC;
#endif
int rc = socketpair (AF_UNIX, type, 0, sv);
if (rc == -1) {
errno_assert (errno == ENFILE || errno == EMFILE);
*w_ = *r_ = -1;
return -1;
} else {
make_socket_noninheritable (sv[0]);
make_socket_noninheritable (sv[1]);
*w_ = sv[0];
*r_ = sv[1];
return 0;
}
#endif
}
void zmq::make_socket_noninheritable (fd_t sock_)
{
#if defined ZMQ_HAVE_WINDOWS && !defined _WIN32_WCE \
&& !defined ZMQ_HAVE_WINDOWS_UWP
// On Windows, preventing sockets to be inherited by child processes.
const BOOL brc = SetHandleInformation (reinterpret_cast<HANDLE> (sock_),
HANDLE_FLAG_INHERIT, 0);
win_assert (brc);
#elif (!defined ZMQ_HAVE_SOCK_CLOEXEC || !defined HAVE_ACCEPT4) \
&& defined FD_CLOEXEC
// If there 's no SOCK_CLOEXEC, let's try the second best option.
// Race condition can cause socket not to be closed (if fork happens
// between accept and this point).
const int rc = fcntl (sock_, F_SETFD, FD_CLOEXEC);
errno_assert (rc != -1);
#else
LIBZMQ_UNUSED (sock_);
#endif
}
void zmq::assert_success_or_recoverable (zmq::fd_t s_, int rc_)
{
#ifdef ZMQ_HAVE_WINDOWS
if (rc_ != SOCKET_ERROR) {
return;
}
#else
if (rc_ != -1) {
return;
}
#endif
// Check whether an error occurred
int err = 0;
#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS
int len = sizeof err;
#else
socklen_t len = sizeof err;
#endif
const int rc = getsockopt (s_, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char *> (&err), &len);
// Assert if the error was caused by 0MQ bug.
// Networking problems are OK. No need to assert.
#ifdef ZMQ_HAVE_WINDOWS
zmq_assert (rc == 0);
if (err != 0) {
wsa_assert (err == WSAECONNREFUSED || err == WSAECONNRESET
|| err == WSAECONNABORTED || err == WSAEINTR
|| err == WSAETIMEDOUT || err == WSAEHOSTUNREACH
|| err == WSAENETUNREACH || err == WSAENETDOWN
|| err == WSAENETRESET || err == WSAEACCES
|| err == WSAEINVAL || err == WSAEADDRINUSE);
}
#else
// Following code should handle both Berkeley-derived socket
// implementations and Solaris.
if (rc == -1)
err = errno;
if (err != 0) {
errno = err;
errno_assert (errno == ECONNREFUSED || errno == ECONNRESET
|| errno == ECONNABORTED || errno == EINTR
|| errno == ETIMEDOUT || errno == EHOSTUNREACH
|| errno == ENETUNREACH || errno == ENETDOWN
|| errno == ENETRESET || errno == EINVAL);
}
#endif
}
#ifdef ZMQ_HAVE_IPC
int zmq::create_ipc_wildcard_address (std::string &path_, std::string &file_)
{
#if defined ZMQ_HAVE_WINDOWS
char buffer[MAX_PATH];
{
const errno_t rc = tmpnam_s (buffer);
errno_assert (rc == 0);
}
// TODO or use CreateDirectoryA and specify permissions?
const int rc = _mkdir (buffer);
if (rc != 0) {
return -1;
}
path_.assign (buffer);
file_ = path_ + "/socket";
#else
std::string tmp_path;
// If TMPDIR, TEMPDIR, or TMP are available and are directories, create
// the socket directory there.
const char **tmp_env = tmp_env_vars;
while (tmp_path.empty () && *tmp_env != 0) {
const char *const tmpdir = getenv (*tmp_env);
struct stat statbuf;
// Confirm it is actually a directory before trying to use
if (tmpdir != 0 && ::stat (tmpdir, &statbuf) == 0
&& S_ISDIR (statbuf.st_mode)) {
tmp_path.assign (tmpdir);
if (*(tmp_path.rbegin ()) != '/') {
tmp_path.push_back ('/');
}
}
// Try the next environment variable
++tmp_env;
}
// Append a directory name
tmp_path.append ("tmpXXXXXX");
// We need room for tmp_path + trailing NUL
std::vector<char> buffer (tmp_path.length () + 1);
memcpy (&buffer[0], tmp_path.c_str (), tmp_path.length () + 1);
#if defined HAVE_MKDTEMP
// Create the directory. POSIX requires that mkdtemp() creates the
// directory with 0700 permissions, meaning the only possible race
// with socket creation could be the same user. However, since
// each socket is created in a directory created by mkdtemp(), and
// mkdtemp() guarantees a unique directory name, there will be no
// collision.
if (mkdtemp (&buffer[0]) == 0) {
return -1;
}
path_.assign (&buffer[0]);
file_ = path_ + "/socket";
#else
LIBZMQ_UNUSED (path_);
int fd = mkstemp (&buffer[0]);
if (fd == -1)
return -1;
::close (fd);
file_.assign (&buffer[0]);
#endif
#endif
return 0;
}
#endif

89
vendor/ZMQ/src/ip.hpp vendored Normal file
View File

@ -0,0 +1,89 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_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 protocol-defined priority for the underlying socket
void set_socket_priority (fd_t s_, int priority_);
// 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
int bind_to_device (fd_t s_, const std::string &bound_device_);
// Initialize network subsystem. May be called multiple times. Each call must be matched by a call to shutdown_network.
bool initialize_network ();
// Shutdown network subsystem. Must be called once for each call to initialize_network before terminating.
void shutdown_network ();
// Creates a pair of sockets (using signaler_port on OS using TCP sockets).
// Returns -1 if we could not make the socket pair successfully
int make_fdpair (fd_t *r_, fd_t *w_);
// Makes a socket non-inheritable to child processes.
// Asserts on any failure.
void make_socket_noninheritable (fd_t sock_);
// Asserts that:
// - an internal 0MQ error did not occur,
// - and, if a socket error occured, it can be recovered from.
void assert_success_or_recoverable (fd_t s_, int rc_);
#ifdef ZMQ_HAVE_IPC
// Create an IPC wildcard path address
int create_ipc_wildcard_address (std::string &path_, std::string &file_);
#endif
}
#endif

743
vendor/ZMQ/src/ip_resolver.cpp vendored Normal file
View File

@ -0,0 +1,743 @@
#include "precompiled.hpp"
#include <string>
#include <cstring>
#include "macros.hpp"
#include "stdint.hpp"
#include "err.hpp"
#include "ip.hpp"
#ifndef ZMQ_HAVE_WINDOWS
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <net/if.h>
#include <netdb.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#endif
#include "ip_resolver.hpp"
int zmq::ip_addr_t::family () const
{
return generic.sa_family;
}
bool zmq::ip_addr_t::is_multicast () const
{
if (family () == AF_INET) {
// IPv4 Multicast: address MSBs are 1110
// Range: 224.0.0.0 - 239.255.255.255
return IN_MULTICAST (ntohl (ipv4.sin_addr.s_addr));
}
// IPv6 Multicast: ff00::/8
return IN6_IS_ADDR_MULTICAST (&ipv6.sin6_addr) != 0;
}
uint16_t zmq::ip_addr_t::port () const
{
if (family () == AF_INET6) {
return ntohs (ipv6.sin6_port);
}
return ntohs (ipv4.sin_port);
}
const struct sockaddr *zmq::ip_addr_t::as_sockaddr () const
{
return &generic;
}
zmq::zmq_socklen_t zmq::ip_addr_t::sockaddr_len () const
{
return static_cast<zmq_socklen_t> (family () == AF_INET6 ? sizeof (ipv6)
: sizeof (ipv4));
}
void zmq::ip_addr_t::set_port (uint16_t port_)
{
if (family () == AF_INET6) {
ipv6.sin6_port = htons (port_);
} else {
ipv4.sin_port = htons (port_);
}
}
// Construct an "ANY" address for the given family
zmq::ip_addr_t zmq::ip_addr_t::any (int family_)
{
ip_addr_t addr;
if (family_ == AF_INET) {
sockaddr_in *ip4_addr = &addr.ipv4;
memset (ip4_addr, 0, sizeof (*ip4_addr));
ip4_addr->sin_family = AF_INET;
ip4_addr->sin_addr.s_addr = htonl (INADDR_ANY);
} else if (family_ == AF_INET6) {
sockaddr_in6 *ip6_addr = &addr.ipv6;
memset (ip6_addr, 0, sizeof (*ip6_addr));
ip6_addr->sin6_family = AF_INET6;
#ifdef ZMQ_HAVE_VXWORKS
struct in6_addr newaddr = IN6ADDR_ANY_INIT;
memcpy (&ip6_addr->sin6_addr, &newaddr, sizeof (in6_addr));
#else
memcpy (&ip6_addr->sin6_addr, &in6addr_any, sizeof (in6addr_any));
#endif
} else {
assert (0 == "unsupported address family");
}
return addr;
}
zmq::ip_resolver_options_t::ip_resolver_options_t () :
_bindable_wanted (false),
_nic_name_allowed (false),
_ipv6_wanted (false),
_port_expected (false),
_dns_allowed (false),
_path_allowed (false)
{
}
zmq::ip_resolver_options_t &
zmq::ip_resolver_options_t::bindable (bool bindable_)
{
_bindable_wanted = bindable_;
return *this;
}
zmq::ip_resolver_options_t &
zmq::ip_resolver_options_t::allow_nic_name (bool allow_)
{
_nic_name_allowed = allow_;
return *this;
}
zmq::ip_resolver_options_t &zmq::ip_resolver_options_t::ipv6 (bool ipv6_)
{
_ipv6_wanted = ipv6_;
return *this;
}
// If true we expect that the host will be followed by a colon and a port
// number or service name
zmq::ip_resolver_options_t &
zmq::ip_resolver_options_t::expect_port (bool expect_)
{
_port_expected = expect_;
return *this;
}
zmq::ip_resolver_options_t &zmq::ip_resolver_options_t::allow_dns (bool allow_)
{
_dns_allowed = allow_;
return *this;
}
zmq::ip_resolver_options_t &zmq::ip_resolver_options_t::allow_path (bool allow_)
{
_path_allowed = allow_;
return *this;
}
bool zmq::ip_resolver_options_t::bindable ()
{
return _bindable_wanted;
}
bool zmq::ip_resolver_options_t::allow_nic_name ()
{
return _nic_name_allowed;
}
bool zmq::ip_resolver_options_t::ipv6 ()
{
return _ipv6_wanted;
}
bool zmq::ip_resolver_options_t::expect_port ()
{
return _port_expected;
}
bool zmq::ip_resolver_options_t::allow_dns ()
{
return _dns_allowed;
}
bool zmq::ip_resolver_options_t::allow_path ()
{
return _path_allowed;
}
zmq::ip_resolver_t::ip_resolver_t (ip_resolver_options_t opts_) :
_options (opts_)
{
}
int zmq::ip_resolver_t::resolve (ip_addr_t *ip_addr_, const char *name_)
{
std::string addr;
uint16_t port;
if (_options.expect_port ()) {
// We expect 'addr:port'. It's important to use str*r*chr to only get
// the latest colon since IPv6 addresses use colons as delemiters.
const char *delim = strrchr (name_, ':');
if (delim == NULL) {
errno = EINVAL;
return -1;
}
addr = std::string (name_, delim - name_);
const std::string port_str = std::string (delim + 1);
if (port_str == "*") {
if (_options.bindable ()) {
// Resolve wildcard to 0 to allow autoselection of port
port = 0;
} else {
errno = EINVAL;
return -1;
}
} else if (port_str == "0") {
// Using "0" for a bind address is equivalent to using "*". For a
// connectable address it could be used to connect to port 0.
port = 0;
} else {
// Parse the port number (0 is not a valid port).
port = static_cast<uint16_t> (atoi (port_str.c_str ()));
if (port == 0) {
errno = EINVAL;
return -1;
}
}
} else {
addr = std::string (name_);
port = 0;
}
// Check if path is allowed in ip address, if allowed it must be truncated
if (_options.allow_path ()) {
const size_t pos = addr.find ('/');
if (pos != std::string::npos)
addr = addr.substr (0, pos);
}
// Trim any square brackets surrounding the address. Used for
// IPv6 addresses to remove the confusion with the port
// delimiter.
// TODO Should we validate that the brackets are present if
// 'addr' contains ':' ?
const size_t brackets_length = 2;
if (addr.size () >= brackets_length && addr[0] == '['
&& addr[addr.size () - 1] == ']') {
addr = addr.substr (1, addr.size () - brackets_length);
}
// Look for an interface name / zone_id in the address
// Reference: https://tools.ietf.org/html/rfc4007
const std::size_t pos = addr.rfind ('%');
uint32_t zone_id = 0;
if (pos != std::string::npos) {
std::string if_str = addr.substr (pos + 1);
if (if_str.empty ()) {
errno = EINVAL;
return -1;
}
addr = addr.substr (0, pos);
if (isalpha (if_str.at (0))) {
zone_id = do_if_nametoindex (if_str.c_str ());
} else {
zone_id = static_cast<uint32_t> (atoi (if_str.c_str ()));
}
if (zone_id == 0) {
errno = EINVAL;
return -1;
}
}
bool resolved = false;
const char *addr_str = addr.c_str ();
if (_options.bindable () && addr == "*") {
// Return an ANY address
*ip_addr_ = ip_addr_t::any (_options.ipv6 () ? AF_INET6 : AF_INET);
resolved = true;
}
if (!resolved && _options.allow_nic_name ()) {
// Try to resolve the string as a NIC name.
const int rc = resolve_nic_name (ip_addr_, addr_str);
if (rc == 0) {
resolved = true;
} else if (errno != ENODEV) {
return rc;
}
}
if (!resolved) {
const int rc = resolve_getaddrinfo (ip_addr_, addr_str);
if (rc != 0) {
return rc;
}
resolved = true;
}
// Store the port into the structure. We could get 'getaddrinfo' to do it
// for us but since we don't resolve service names it's a bit overkill and
// we'd still have to do it manually when the address is resolved by
// 'resolve_nic_name'
ip_addr_->set_port (port);
if (ip_addr_->family () == AF_INET6) {
ip_addr_->ipv6.sin6_scope_id = zone_id;
}
assert (resolved == true);
return 0;
}
int zmq::ip_resolver_t::resolve_getaddrinfo (ip_addr_t *ip_addr_,
const char *addr_)
{
#if defined ZMQ_HAVE_OPENVMS && defined __ia64
__addrinfo64 *res = NULL;
__addrinfo64 req;
#else
addrinfo *res = NULL;
addrinfo req;
#endif
memset (&req, 0, sizeof (req));
// Choose IPv4 or IPv6 protocol family. Note that IPv6 allows for
// IPv4-in-IPv6 addresses.
req.ai_family = _options.ipv6 () ? AF_INET6 : AF_INET;
// Arbitrary, not used in the output, but avoids duplicate results.
req.ai_socktype = SOCK_STREAM;
req.ai_flags = 0;
if (_options.bindable ()) {
req.ai_flags |= AI_PASSIVE;
}
if (!_options.allow_dns ()) {
req.ai_flags |= AI_NUMERICHOST;
}
#if defined AI_V4MAPPED
// In this API we only require IPv4-mapped addresses when
// no native IPv6 interfaces are available (~AI_ALL).
// This saves an additional DNS roundtrip for IPv4 addresses.
if (req.ai_family == AF_INET6) {
req.ai_flags |= AI_V4MAPPED;
}
#endif
// Resolve the literal address. Some of the error info is lost in case
// of error, however, there's no way to report EAI errors via errno.
int rc = do_getaddrinfo (addr_, NULL, &req, &res);
#if defined AI_V4MAPPED
// Some OS do have AI_V4MAPPED defined but it is not supported in getaddrinfo()
// returning EAI_BADFLAGS. Detect this and retry
if (rc == EAI_BADFLAGS && (req.ai_flags & AI_V4MAPPED)) {
req.ai_flags &= ~AI_V4MAPPED;
rc = do_getaddrinfo (addr_, NULL, &req, &res);
}
#endif
#if defined ZMQ_HAVE_WINDOWS
// Resolve specific case on Windows platform when using IPv4 address
// with ZMQ_IPv6 socket option.
if ((req.ai_family == AF_INET6) && (rc == WSAHOST_NOT_FOUND)) {
req.ai_family = AF_INET;
rc = do_getaddrinfo (addr_, NULL, &req, &res);
}
#endif
if (rc) {
switch (rc) {
case EAI_MEMORY:
errno = ENOMEM;
break;
default:
if (_options.bindable ()) {
errno = ENODEV;
} else {
errno = EINVAL;
}
break;
}
return -1;
}
// Use the first result.
zmq_assert (res != NULL);
zmq_assert (static_cast<size_t> (res->ai_addrlen) <= sizeof (*ip_addr_));
memcpy (ip_addr_, res->ai_addr, res->ai_addrlen);
// Cleanup getaddrinfo after copying the possibly referenced result.
do_freeaddrinfo (res);
return 0;
}
#ifdef ZMQ_HAVE_SOLARIS
#include <sys/sockio.h>
// On Solaris platform, network interface name can be queried by ioctl.
int zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)
{
// Create a socket.
const int fd = open_socket (AF_INET, SOCK_DGRAM, 0);
errno_assert (fd != -1);
// Retrieve number of interfaces.
lifnum ifn;
ifn.lifn_family = AF_INET;
ifn.lifn_flags = 0;
int rc = ioctl (fd, SIOCGLIFNUM, (char *) &ifn);
errno_assert (rc != -1);
// Allocate memory to get interface names.
const size_t ifr_size = sizeof (struct lifreq) * ifn.lifn_count;
char *ifr = (char *) malloc (ifr_size);
alloc_assert (ifr);
// Retrieve interface names.
lifconf ifc;
ifc.lifc_family = AF_INET;
ifc.lifc_flags = 0;
ifc.lifc_len = ifr_size;
ifc.lifc_buf = ifr;
rc = ioctl (fd, SIOCGLIFCONF, (char *) &ifc);
errno_assert (rc != -1);
// Find the interface with the specified name and AF_INET family.
bool found = false;
lifreq *ifrp = ifc.lifc_req;
for (int n = 0; n < (int) (ifc.lifc_len / sizeof (lifreq)); n++, ifrp++) {
if (!strcmp (nic_, ifrp->lifr_name)) {
rc = ioctl (fd, SIOCGLIFADDR, (char *) ifrp);
errno_assert (rc != -1);
if (ifrp->lifr_addr.ss_family == AF_INET) {
ip_addr_->ipv4 = *(sockaddr_in *) &ifrp->lifr_addr;
found = true;
break;
}
}
}
// Clean-up.
free (ifr);
close (fd);
if (!found) {
errno = ENODEV;
return -1;
}
return 0;
}
#elif defined ZMQ_HAVE_AIX || defined ZMQ_HAVE_HPUX \
|| defined ZMQ_HAVE_ANDROID || defined ZMQ_HAVE_VXWORKS
#include <sys/ioctl.h>
#ifdef ZMQ_HAVE_VXWORKS
#include <ioLib.h>
#endif
int zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)
{
#if defined ZMQ_HAVE_AIX || defined ZMQ_HAVE_HPUX
// IPv6 support not implemented for AIX or HP/UX.
if (_options.ipv6 ()) {
errno = ENODEV;
return -1;
}
#endif
// Create a socket.
const int sd =
open_socket (_options.ipv6 () ? AF_INET6 : AF_INET, SOCK_DGRAM, 0);
errno_assert (sd != -1);
struct ifreq ifr;
// Copy interface name for ioctl get.
strncpy (ifr.ifr_name, nic_, sizeof (ifr.ifr_name));
// Fetch interface address.
const int rc = ioctl (sd, SIOCGIFADDR, (caddr_t) &ifr, sizeof (ifr));
// Clean up.
close (sd);
if (rc == -1) {
errno = ENODEV;
return -1;
}
const int family = ifr.ifr_addr.sa_family;
if (family == (_options.ipv6 () ? AF_INET6 : AF_INET)
&& !strcmp (nic_, ifr.ifr_name)) {
memcpy (ip_addr_, &ifr.ifr_addr,
(family == AF_INET) ? sizeof (struct sockaddr_in)
: sizeof (struct sockaddr_in6));
} else {
errno = ENODEV;
return -1;
}
return 0;
}
#elif ((defined ZMQ_HAVE_LINUX || defined ZMQ_HAVE_FREEBSD \
|| defined ZMQ_HAVE_OSX || defined ZMQ_HAVE_OPENBSD \
|| defined ZMQ_HAVE_QNXNTO || defined ZMQ_HAVE_NETBSD \
|| defined ZMQ_HAVE_DRAGONFLY || defined ZMQ_HAVE_GNU) \
&& defined ZMQ_HAVE_IFADDRS)
#include <ifaddrs.h>
// On these platforms, network interface name can be queried
// using getifaddrs function.
int zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)
{
// Get the addresses.
ifaddrs *ifa = NULL;
int rc = 0;
const int max_attempts = 10;
const int backoff_msec = 1;
for (int i = 0; i < max_attempts; i++) {
rc = getifaddrs (&ifa);
if (rc == 0 || (rc < 0 && errno != ECONNREFUSED))
break;
usleep ((backoff_msec << i) * 1000);
}
if (rc != 0 && ((errno == EINVAL) || (errno == EOPNOTSUPP))) {
// Windows Subsystem for Linux compatibility
errno = ENODEV;
return -1;
}
errno_assert (rc == 0);
zmq_assert (ifa != NULL);
// Find the corresponding network interface.
bool found = false;
for (const ifaddrs *ifp = ifa; ifp != NULL; ifp = ifp->ifa_next) {
if (ifp->ifa_addr == NULL)
continue;
const int family = ifp->ifa_addr->sa_family;
if (family == (_options.ipv6 () ? AF_INET6 : AF_INET)
&& !strcmp (nic_, ifp->ifa_name)) {
memcpy (ip_addr_, ifp->ifa_addr,
(family == AF_INET) ? sizeof (struct sockaddr_in)
: sizeof (struct sockaddr_in6));
found = true;
break;
}
}
// Clean-up;
freeifaddrs (ifa);
if (!found) {
errno = ENODEV;
return -1;
}
return 0;
}
#elif (defined ZMQ_HAVE_WINDOWS)
#include <netioapi.h>
int zmq::ip_resolver_t::get_interface_name (unsigned long index_,
char **dest_) const
{
#ifdef ZMQ_HAVE_WINDOWS_UWP
char *buffer = (char *) malloc (1024);
#else
char *buffer = static_cast<char *> (malloc (IF_MAX_STRING_SIZE));
#endif
alloc_assert (buffer);
char *if_name_result = NULL;
#if _WIN32_WINNT > _WIN32_WINNT_WINXP && !defined ZMQ_HAVE_WINDOWS_UWP
if_name_result = if_indextoname (index_, buffer);
#endif
if (if_name_result == NULL) {
free (buffer);
return -1;
}
*dest_ = buffer;
return 0;
}
int zmq::ip_resolver_t::wchar_to_utf8 (const WCHAR *src_, char **dest_) const
{
int rc;
const int buffer_len =
WideCharToMultiByte (CP_UTF8, 0, src_, -1, NULL, 0, NULL, 0);
char *buffer = static_cast<char *> (malloc (buffer_len));
alloc_assert (buffer);
rc =
WideCharToMultiByte (CP_UTF8, 0, src_, -1, buffer, buffer_len, NULL, 0);
if (rc == 0) {
free (buffer);
return -1;
}
*dest_ = buffer;
return 0;
}
int zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)
{
int rc;
bool found = false;
const int max_attempts = 10;
int iterations = 0;
IP_ADAPTER_ADDRESSES *addresses;
unsigned long out_buf_len = sizeof (IP_ADAPTER_ADDRESSES);
do {
addresses = static_cast<IP_ADAPTER_ADDRESSES *> (malloc (out_buf_len));
alloc_assert (addresses);
rc =
GetAdaptersAddresses (AF_UNSPEC,
GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_DNS_SERVER,
NULL, addresses, &out_buf_len);
if (rc == ERROR_BUFFER_OVERFLOW) {
free (addresses);
addresses = NULL;
} else {
break;
}
iterations++;
} while ((rc == ERROR_BUFFER_OVERFLOW) && (iterations < max_attempts));
if (rc == 0) {
for (const IP_ADAPTER_ADDRESSES *current_addresses = addresses;
current_addresses; current_addresses = current_addresses->Next) {
char *if_name = NULL;
char *if_friendly_name = NULL;
const int str_rc1 =
get_interface_name (current_addresses->IfIndex, &if_name);
const int str_rc2 = wchar_to_utf8 (current_addresses->FriendlyName,
&if_friendly_name);
// Find a network adapter by its "name" or "friendly name"
if (((str_rc1 == 0) && (!strcmp (nic_, if_name)))
|| ((str_rc2 == 0) && (!strcmp (nic_, if_friendly_name)))) {
// Iterate over all unicast addresses bound to the current network interface
for (const IP_ADAPTER_UNICAST_ADDRESS *current_unicast_address =
current_addresses->FirstUnicastAddress;
current_unicast_address;
current_unicast_address = current_unicast_address->Next) {
const ADDRESS_FAMILY family =
current_unicast_address->Address.lpSockaddr->sa_family;
if (family == (_options.ipv6 () ? AF_INET6 : AF_INET)) {
memcpy (
ip_addr_, current_unicast_address->Address.lpSockaddr,
(family == AF_INET) ? sizeof (struct sockaddr_in)
: sizeof (struct sockaddr_in6));
found = true;
break;
}
}
if (found)
break;
}
if (str_rc1 == 0)
free (if_name);
if (str_rc2 == 0)
free (if_friendly_name);
}
free (addresses);
}
if (!found) {
errno = ENODEV;
return -1;
}
return 0;
}
#else
// On other platforms we assume there are no sane interface names.
int zmq::ip_resolver_t::resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_)
{
LIBZMQ_UNUSED (ip_addr_);
LIBZMQ_UNUSED (nic_);
errno = ENODEV;
return -1;
}
#endif
int zmq::ip_resolver_t::do_getaddrinfo (const char *node_,
const char *service_,
const struct addrinfo *hints_,
struct addrinfo **res_)
{
return getaddrinfo (node_, service_, hints_, res_);
}
void zmq::ip_resolver_t::do_freeaddrinfo (struct addrinfo *res_)
{
freeaddrinfo (res_);
}
unsigned int zmq::ip_resolver_t::do_if_nametoindex (const char *ifname_)
{
#ifdef HAVE_IF_NAMETOINDEX
return if_nametoindex (ifname_);
#else
LIBZMQ_UNUSED (ifname_);
// The function 'if_nametoindex' is not supported on Windows XP.
// If we are targeting XP using a vxxx_xp toolset then fail.
// This is brutal as this code could be run on later windows clients
// meaning the IPv6 zone_id cannot have an interface name.
// This could be fixed with a runtime check.
return 0;
#endif
}

121
vendor/ZMQ/src/ip_resolver.hpp vendored Normal file
View File

@ -0,0 +1,121 @@
/*
Copyright (c) 2007-2018 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_RESOLVER_HPP_INCLUDED__
#define __ZMQ_IP_RESOLVER_HPP_INCLUDED__
#if !defined ZMQ_HAVE_WINDOWS
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
#include "address.hpp"
namespace zmq
{
union ip_addr_t
{
sockaddr generic;
sockaddr_in ipv4;
sockaddr_in6 ipv6;
int family () const;
bool is_multicast () const;
uint16_t port () const;
const struct sockaddr *as_sockaddr () const;
zmq_socklen_t sockaddr_len () const;
void set_port (uint16_t);
static ip_addr_t any (int family_);
};
class ip_resolver_options_t
{
public:
ip_resolver_options_t ();
ip_resolver_options_t &bindable (bool bindable_);
ip_resolver_options_t &allow_nic_name (bool allow_);
ip_resolver_options_t &ipv6 (bool ipv6_);
ip_resolver_options_t &expect_port (bool expect_);
ip_resolver_options_t &allow_dns (bool allow_);
ip_resolver_options_t &allow_path (bool allow_);
bool bindable ();
bool allow_nic_name ();
bool ipv6 ();
bool expect_port ();
bool allow_dns ();
bool allow_path ();
private:
bool _bindable_wanted;
bool _nic_name_allowed;
bool _ipv6_wanted;
bool _port_expected;
bool _dns_allowed;
bool _path_allowed;
};
class ip_resolver_t
{
public:
ip_resolver_t (ip_resolver_options_t opts_);
virtual ~ip_resolver_t (){};
int resolve (ip_addr_t *ip_addr_, const char *name_);
protected:
// Virtual functions that are overridden in tests
virtual int do_getaddrinfo (const char *node_,
const char *service_,
const struct addrinfo *hints_,
struct addrinfo **res_);
virtual void do_freeaddrinfo (struct addrinfo *res_);
virtual unsigned int do_if_nametoindex (const char *ifname_);
private:
ip_resolver_options_t _options;
int resolve_nic_name (ip_addr_t *ip_addr_, const char *nic_);
int resolve_getaddrinfo (ip_addr_t *ip_addr_, const char *addr_);
#if defined ZMQ_HAVE_WINDOWS
int get_interface_name (unsigned long index_, char **dest_) const;
int wchar_to_utf8 (const WCHAR *src_, char **dest_) const;
#endif
};
}
#endif

120
vendor/ZMQ/src/ipc_address.cpp vendored Normal file
View File

@ -0,0 +1,120 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "compat.hpp"
#include "ipc_address.hpp"
#if defined ZMQ_HAVE_IPC
#include "err.hpp"
#include <string>
zmq::ipc_address_t::ipc_address_t ()
{
memset (&_address, 0, sizeof _address);
}
zmq::ipc_address_t::ipc_address_t (const sockaddr *sa_, socklen_t sa_len_) :
_addrlen (sa_len_)
{
zmq_assert (sa_ && sa_len_ > 0);
memset (&_address, 0, sizeof _address);
if (sa_->sa_family == AF_UNIX)
memcpy (&_address, sa_, sa_len_);
}
zmq::ipc_address_t::~ipc_address_t ()
{
}
int zmq::ipc_address_t::resolve (const char *path_)
{
const size_t path_len = strlen (path_);
if (path_len >= sizeof _address.sun_path) {
errno = ENAMETOOLONG;
return -1;
}
if (path_[0] == '@' && !path_[1]) {
errno = EINVAL;
return -1;
}
_address.sun_family = AF_UNIX;
memcpy (_address.sun_path, path_, path_len + 1);
/* Abstract sockets start with '\0' */
if (path_[0] == '@')
*_address.sun_path = '\0';
_addrlen =
static_cast<socklen_t> (offsetof (sockaddr_un, sun_path) + path_len);
return 0;
}
int zmq::ipc_address_t::to_string (std::string &addr_) const
{
if (_address.sun_family != AF_UNIX) {
addr_.clear ();
return -1;
}
const char prefix[] = "ipc://";
char buf[sizeof prefix + sizeof _address.sun_path];
char *pos = buf;
memcpy (pos, prefix, sizeof prefix - 1);
pos += sizeof prefix - 1;
const char *src_pos = _address.sun_path;
if (!_address.sun_path[0] && _address.sun_path[1]) {
*pos++ = '@';
src_pos++;
}
// according to http://man7.org/linux/man-pages/man7/unix.7.html, NOTES
// section, address.sun_path might not always be null-terminated; therefore,
// we calculate the length based of addrlen
const size_t src_len =
strnlen (src_pos, _addrlen - offsetof (sockaddr_un, sun_path)
- (src_pos - _address.sun_path));
memcpy (pos, src_pos, src_len);
addr_.assign (buf, pos - buf + src_len);
return 0;
}
const sockaddr *zmq::ipc_address_t::addr () const
{
return reinterpret_cast<const sockaddr *> (&_address);
}
socklen_t zmq::ipc_address_t::addrlen () const
{
return _addrlen;
}
#endif

74
vendor/ZMQ/src/ipc_address.hpp vendored Normal file
View File

@ -0,0 +1,74 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IPC_ADDRESS_HPP_INCLUDED__
#define __ZMQ_IPC_ADDRESS_HPP_INCLUDED__
#if defined ZMQ_HAVE_IPC
#include <string>
#if defined _MSC_VER
#include <afunix.h>
#else
#include <sys/socket.h>
#include <sys/un.h>
#endif
#include "macros.hpp"
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;
const sockaddr *addr () const;
socklen_t addrlen () const;
private:
struct sockaddr_un _address;
socklen_t _addrlen;
ZMQ_NON_COPYABLE_NOR_MOVABLE (ipc_address_t)
};
}
#endif
#endif

186
vendor/ZMQ/src/ipc_connecter.cpp vendored Normal file
View File

@ -0,0 +1,186 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "ipc_connecter.hpp"
#if defined ZMQ_HAVE_IPC
#include <new>
#include <string>
#include "io_thread.hpp"
#include "random.hpp"
#include "err.hpp"
#include "ip.hpp"
#include "address.hpp"
#include "ipc_address.hpp"
#include "session_base.hpp"
#ifdef _MSC_VER
#include <afunix.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#endif
zmq::ipc_connecter_t::ipc_connecter_t (class io_thread_t *io_thread_,
class session_base_t *session_,
const options_t &options_,
address_t *addr_,
bool delayed_start_) :
stream_connecter_base_t (
io_thread_, session_, options_, addr_, delayed_start_)
{
zmq_assert (_addr->protocol == protocol_name::ipc);
}
void zmq::ipc_connecter_t::out_event ()
{
const fd_t fd = connect ();
rm_handle ();
// Handle the error condition by attempt to reconnect.
if (fd == retired_fd) {
close ();
add_reconnect_timer ();
return;
}
create_engine (fd, get_socket_name<ipc_address_t> (fd, socket_end_local));
}
void zmq::ipc_connecter_t::start_connecting ()
{
// Open the connecting socket.
const int rc = open ();
// Connect may succeed in synchronous manner.
if (rc == 0) {
_handle = add_fd (_s);
out_event ();
}
// Connection establishment may be delayed. Poll for its completion.
else if (rc == -1 && errno == EINPROGRESS) {
_handle = add_fd (_s);
set_pollout (_handle);
_socket->event_connect_delayed (
make_unconnected_connect_endpoint_pair (_endpoint), zmq_errno ());
// TODO, tcp_connecter_t adds a connect timer in this case; maybe this
// should be done here as well (and then this could be pulled up to
// stream_connecter_base_t).
}
//stop connecting after called zmq_disconnect
else if (rc == -1
&& (options.reconnect_stop & ZMQ_RECONNECT_STOP_AFTER_DISCONNECT)
&& errno == ECONNREFUSED && _socket->is_disconnected ()) {
if (_s != retired_fd)
close ();
}
// Handle any other error condition by eventual reconnect.
else {
if (_s != retired_fd)
close ();
add_reconnect_timer ();
}
}
int zmq::ipc_connecter_t::open ()
{
zmq_assert (_s == retired_fd);
// Create the socket.
_s = open_socket (AF_UNIX, SOCK_STREAM, 0);
if (_s == retired_fd)
return -1;
// Set the non-blocking flag.
unblock_socket (_s);
// Connect to the remote peer.
const int rc = ::connect (_s, _addr->resolved.ipc_addr->addr (),
_addr->resolved.ipc_addr->addrlen ());
// Connect was successful immediately.
if (rc == 0)
return 0;
// Translate other error codes indicating asynchronous connect has been
// launched to a uniform EINPROGRESS.
#ifdef ZMQ_HAVE_WINDOWS
const int last_error = WSAGetLastError ();
if (last_error == WSAEINPROGRESS || last_error == WSAEWOULDBLOCK)
errno = EINPROGRESS;
else
errno = wsa_error_to_errno (last_error);
#else
if (rc == -1 && errno == EINTR) {
errno = EINPROGRESS;
}
#endif
// Forward the error.
return -1;
}
zmq::fd_t zmq::ipc_connecter_t::connect ()
{
// Following code should handle both Berkeley-derived socket
// implementations and Solaris.
int err = 0;
zmq_socklen_t len = static_cast<zmq_socklen_t> (sizeof (err));
const int rc = getsockopt (_s, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char *> (&err), &len);
if (rc == -1) {
if (errno == ENOPROTOOPT)
errno = 0;
err = errno;
}
if (err != 0) {
// Assert if the error was caused by 0MQ bug.
// Networking problems are OK. No need to assert.
errno = err;
errno_assert (errno == ECONNREFUSED || errno == ECONNRESET
|| errno == ETIMEDOUT || errno == EHOSTUNREACH
|| errno == ENETUNREACH || errno == ENETDOWN);
return retired_fd;
}
const fd_t result = _s;
_s = retired_fd;
return result;
}
#endif

73
vendor/ZMQ/src/ipc_connecter.hpp vendored Normal file
View File

@ -0,0 +1,73 @@
/*
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_IPC
#include "fd.hpp"
#include "stream_connecter_base.hpp"
namespace zmq
{
class ipc_connecter_t ZMQ_FINAL : public stream_connecter_base_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_,
address_t *addr_,
bool delayed_start_);
private:
// Handlers for I/O events.
void out_event ();
// Internal function to start the actual connection establishment.
void start_connecting ();
// 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 ();
// Get the file descriptor of newly created connection. Returns
// retired_fd if the connection was unsuccessful.
fd_t connect ();
ZMQ_NON_COPYABLE_NOR_MOVABLE (ipc_connecter_t)
};
}
#endif
#endif

357
vendor/ZMQ/src/ipc_listener.cpp vendored Normal file
View File

@ -0,0 +1,357 @@
/*
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 "ipc_listener.hpp"
#if defined ZMQ_HAVE_IPC
#include <new>
#include <string.h>
#include "ipc_address.hpp"
#include "io_thread.hpp"
#include "config.hpp"
#include "err.hpp"
#include "ip.hpp"
#include "socket_base.hpp"
#include "address.hpp"
#ifdef _MSC_VER
#ifdef ZMQ_IOTHREAD_POLLER_USE_SELECT
#error On Windows, IPC does not work with POLLER=select, use POLLER=epoll instead, or disable IPC transport
#endif
#include <afunix.h>
#include <direct.h>
#define rmdir _rmdir
#define unlink _unlink
#else
#include <unistd.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <sys/un.h>
#endif
#ifdef ZMQ_HAVE_LOCAL_PEERCRED
#include <sys/types.h>
#include <sys/ucred.h>
#endif
#ifdef ZMQ_HAVE_SO_PEERCRED
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#if defined ZMQ_HAVE_OPENBSD
#define ucred sockpeercred
#endif
#endif
zmq::ipc_listener_t::ipc_listener_t (io_thread_t *io_thread_,
socket_base_t *socket_,
const options_t &options_) :
stream_listener_base_t (io_thread_, socket_, options_),
_has_file (false)
{
}
void zmq::ipc_listener_t::in_event ()
{
const fd_t fd = accept ();
// If connection was reset by the peer in the meantime, just ignore it.
// TODO: Handle specific errors like ENFILE/EMFILE etc.
if (fd == retired_fd) {
_socket->event_accept_failed (
make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());
return;
}
// Create the engine object for this connection.
create_engine (fd);
}
std::string
zmq::ipc_listener_t::get_socket_name (zmq::fd_t fd_,
socket_end_t socket_end_) const
{
return zmq::get_socket_name<ipc_address_t> (fd_, socket_end_);
}
int zmq::ipc_listener_t::set_local_address (const char *addr_)
{
// Create addr on stack for auto-cleanup
std::string addr (addr_);
// Allow wildcard file
if (options.use_fd == -1 && addr[0] == '*') {
if (create_ipc_wildcard_address (_tmp_socket_dirname, addr) < 0) {
return -1;
}
}
// Get rid of the file associated with the UNIX domain socket that
// may have been left behind by the previous run of the application.
// MUST NOT unlink if the FD is managed by the user, or it will stop
// working after the first client connects. The user will take care of
// cleaning up the file after the service is stopped.
if (options.use_fd == -1) {
::unlink (addr.c_str ());
}
_filename.clear ();
// Initialise the address structure.
ipc_address_t address;
int rc = address.resolve (addr.c_str ());
if (rc != 0) {
if (!_tmp_socket_dirname.empty ()) {
// We need to preserve errno to return to the user
const int tmp_errno = errno;
::rmdir (_tmp_socket_dirname.c_str ());
_tmp_socket_dirname.clear ();
errno = tmp_errno;
}
return -1;
}
address.to_string (_endpoint);
if (options.use_fd != -1) {
_s = options.use_fd;
} else {
// Create a listening socket.
_s = open_socket (AF_UNIX, SOCK_STREAM, 0);
if (_s == retired_fd) {
if (!_tmp_socket_dirname.empty ()) {
// We need to preserve errno to return to the user
const int tmp_errno = errno;
::rmdir (_tmp_socket_dirname.c_str ());
_tmp_socket_dirname.clear ();
errno = tmp_errno;
}
return -1;
}
// Bind the socket to the file path.
rc = bind (_s, const_cast<sockaddr *> (address.addr ()),
address.addrlen ());
if (rc != 0)
goto error;
// Listen for incoming connections.
rc = listen (_s, options.backlog);
if (rc != 0)
goto error;
}
_filename = ZMQ_MOVE (addr);
_has_file = true;
_socket->event_listening (make_unconnected_bind_endpoint_pair (_endpoint),
_s);
return 0;
error:
const int err = errno;
close ();
errno = err;
return -1;
}
int zmq::ipc_listener_t::close ()
{
zmq_assert (_s != retired_fd);
const fd_t fd_for_event = _s;
#ifdef ZMQ_HAVE_WINDOWS
int rc = closesocket (_s);
wsa_assert (rc != SOCKET_ERROR);
#else
int rc = ::close (_s);
errno_assert (rc == 0);
#endif
_s = retired_fd;
if (_has_file && options.use_fd == -1) {
if (!_tmp_socket_dirname.empty ()) {
// TODO review this behaviour, it is inconsistent with the use of
// unlink in open since 656cdb959a7482c45db979c1d08ede585d12e315;
// however, we must at least remove the file before removing the
// directory, otherwise it will always fail
rc = ::unlink (_filename.c_str ());
if (rc == 0) {
rc = ::rmdir (_tmp_socket_dirname.c_str ());
_tmp_socket_dirname.clear ();
}
}
if (rc != 0) {
_socket->event_close_failed (
make_unconnected_bind_endpoint_pair (_endpoint), zmq_errno ());
return -1;
}
}
_socket->event_closed (make_unconnected_bind_endpoint_pair (_endpoint),
fd_for_event);
return 0;
}
#if defined ZMQ_HAVE_SO_PEERCRED
bool zmq::ipc_listener_t::filter (fd_t sock_)
{
if (options.ipc_uid_accept_filters.empty ()
&& options.ipc_pid_accept_filters.empty ()
&& options.ipc_gid_accept_filters.empty ())
return true;
struct ucred cred;
socklen_t size = sizeof (cred);
if (getsockopt (sock_, SOL_SOCKET, SO_PEERCRED, &cred, &size))
return false;
if (options.ipc_uid_accept_filters.find (cred.uid)
!= options.ipc_uid_accept_filters.end ()
|| options.ipc_gid_accept_filters.find (cred.gid)
!= options.ipc_gid_accept_filters.end ()
|| options.ipc_pid_accept_filters.find (cred.pid)
!= options.ipc_pid_accept_filters.end ())
return true;
const struct passwd *pw;
const struct group *gr;
if (!(pw = getpwuid (cred.uid)))
return false;
for (options_t::ipc_gid_accept_filters_t::const_iterator
it = options.ipc_gid_accept_filters.begin (),
end = options.ipc_gid_accept_filters.end ();
it != end; it++) {
if (!(gr = getgrgid (*it)))
continue;
for (char **mem = gr->gr_mem; *mem; mem++) {
if (!strcmp (*mem, pw->pw_name))
return true;
}
}
return false;
}
#elif defined ZMQ_HAVE_LOCAL_PEERCRED
bool zmq::ipc_listener_t::filter (fd_t sock_)
{
if (options.ipc_uid_accept_filters.empty ()
&& options.ipc_gid_accept_filters.empty ())
return true;
struct xucred cred;
socklen_t size = sizeof (cred);
if (getsockopt (sock_, 0, LOCAL_PEERCRED, &cred, &size))
return false;
if (cred.cr_version != XUCRED_VERSION)
return false;
if (options.ipc_uid_accept_filters.find (cred.cr_uid)
!= options.ipc_uid_accept_filters.end ())
return true;
for (int i = 0; i < cred.cr_ngroups; i++) {
if (options.ipc_gid_accept_filters.find (cred.cr_groups[i])
!= options.ipc_gid_accept_filters.end ())
return true;
}
return false;
}
#endif
zmq::fd_t zmq::ipc_listener_t::accept ()
{
// Accept one connection and deal with different failure modes.
// The situation where connection cannot be accepted due to insufficient
// resources is considered valid and treated by ignoring the connection.
zmq_assert (_s != retired_fd);
#if defined ZMQ_HAVE_SOCK_CLOEXEC && defined HAVE_ACCEPT4
fd_t sock = ::accept4 (_s, NULL, NULL, SOCK_CLOEXEC);
#else
struct sockaddr_storage ss;
memset (&ss, 0, sizeof (ss));
#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS
int ss_len = sizeof (ss);
#else
socklen_t ss_len = sizeof (ss);
#endif
const fd_t sock =
::accept (_s, reinterpret_cast<struct sockaddr *> (&ss), &ss_len);
#endif
if (sock == retired_fd) {
#if defined ZMQ_HAVE_WINDOWS
const int last_error = WSAGetLastError ();
wsa_assert (last_error == WSAEWOULDBLOCK || last_error == WSAECONNRESET
|| last_error == WSAEMFILE || last_error == WSAENOBUFS);
#else
errno_assert (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR
|| errno == ECONNABORTED || errno == EPROTO
|| errno == ENFILE);
#endif
return retired_fd;
}
make_socket_noninheritable (sock);
// IPC accept() filters
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
if (!filter (sock)) {
int rc = ::close (sock);
errno_assert (rc == 0);
return retired_fd;
}
#endif
if (zmq::set_nosigpipe (sock)) {
#ifdef ZMQ_HAVE_WINDOWS
const int rc = closesocket (sock);
wsa_assert (rc != SOCKET_ERROR);
#else
int rc = ::close (sock);
errno_assert (rc == 0);
#endif
return retired_fd;
}
return sock;
}
#endif

88
vendor/ZMQ/src/ipc_listener.hpp vendored Normal file
View File

@ -0,0 +1,88 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_IPC_LISTENER_HPP_INCLUDED__
#define __ZMQ_IPC_LISTENER_HPP_INCLUDED__
#if defined ZMQ_HAVE_IPC
#include <string>
#include "fd.hpp"
#include "stream_listener_base.hpp"
namespace zmq
{
class ipc_listener_t ZMQ_FINAL : public stream_listener_base_t
{
public:
ipc_listener_t (zmq::io_thread_t *io_thread_,
zmq::socket_base_t *socket_,
const options_t &options_);
// Set address to listen on.
int set_local_address (const char *addr_);
protected:
std::string get_socket_name (fd_t fd_, socket_end_t socket_end_) const;
private:
// Handlers for I/O events.
void in_event ();
// 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
int close ();
// 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
// UNIX domain socket
std::string _tmp_socket_dirname;
// Name of the file associated with the UNIX domain address.
std::string _filename;
ZMQ_NON_COPYABLE_NOR_MOVABLE (ipc_listener_t)
};
}
#endif
#endif

230
vendor/ZMQ/src/kqueue.cpp vendored Normal file
View File

@ -0,0 +1,230 @@
/*
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 "kqueue.hpp"
#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE
#include <sys/time.h>
#include <sys/types.h>
#include <sys/event.h>
#include <stdlib.h>
#include <unistd.h>
#include <algorithm>
#include <new>
#include "macros.hpp"
#include "kqueue.hpp"
#include "err.hpp"
#include "config.hpp"
#include "i_poll_events.hpp"
#include "likely.hpp"
// NetBSD defines (struct kevent).udata as intptr_t, everyone else
// as void *.
#if defined ZMQ_HAVE_NETBSD
#define kevent_udata_t intptr_t
#else
#define kevent_udata_t void *
#endif
zmq::kqueue_t::kqueue_t (const zmq::thread_ctx_t &ctx_) :
worker_poller_base_t (ctx_)
{
// Create event queue
kqueue_fd = kqueue ();
errno_assert (kqueue_fd != -1);
#ifdef HAVE_FORK
pid = getpid ();
#endif
}
zmq::kqueue_t::~kqueue_t ()
{
stop_worker ();
close (kqueue_fd);
}
void zmq::kqueue_t::kevent_add (fd_t fd_, short filter_, void *udata_)
{
check_thread ();
struct kevent ev;
EV_SET (&ev, fd_, filter_, EV_ADD, 0, 0, (kevent_udata_t) udata_);
int rc = kevent (kqueue_fd, &ev, 1, NULL, 0, NULL);
errno_assert (rc != -1);
}
void zmq::kqueue_t::kevent_delete (fd_t fd_, short filter_)
{
struct kevent ev;
EV_SET (&ev, fd_, filter_, EV_DELETE, 0, 0, 0);
int rc = kevent (kqueue_fd, &ev, 1, NULL, 0, NULL);
errno_assert (rc != -1);
}
zmq::kqueue_t::handle_t zmq::kqueue_t::add_fd (fd_t fd_,
i_poll_events *reactor_)
{
check_thread ();
poll_entry_t *pe = new (std::nothrow) poll_entry_t;
alloc_assert (pe);
pe->fd = fd_;
pe->flag_pollin = 0;
pe->flag_pollout = 0;
pe->reactor = reactor_;
adjust_load (1);
return pe;
}
void zmq::kqueue_t::rm_fd (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = (poll_entry_t *) handle_;
if (pe->flag_pollin)
kevent_delete (pe->fd, EVFILT_READ);
if (pe->flag_pollout)
kevent_delete (pe->fd, EVFILT_WRITE);
pe->fd = retired_fd;
retired.push_back (pe);
adjust_load (-1);
}
void zmq::kqueue_t::set_pollin (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = (poll_entry_t *) handle_;
if (likely (!pe->flag_pollin)) {
pe->flag_pollin = true;
kevent_add (pe->fd, EVFILT_READ, pe);
}
}
void zmq::kqueue_t::reset_pollin (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = (poll_entry_t *) handle_;
if (likely (pe->flag_pollin)) {
pe->flag_pollin = false;
kevent_delete (pe->fd, EVFILT_READ);
}
}
void zmq::kqueue_t::set_pollout (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = (poll_entry_t *) handle_;
if (likely (!pe->flag_pollout)) {
pe->flag_pollout = true;
kevent_add (pe->fd, EVFILT_WRITE, pe);
}
}
void zmq::kqueue_t::reset_pollout (handle_t handle_)
{
check_thread ();
poll_entry_t *pe = (poll_entry_t *) handle_;
if (likely (pe->flag_pollout)) {
pe->flag_pollout = false;
kevent_delete (pe->fd, EVFILT_WRITE);
}
}
void zmq::kqueue_t::stop ()
{
}
int zmq::kqueue_t::max_fds ()
{
return -1;
}
void zmq::kqueue_t::loop ()
{
while (true) {
// Execute any due timers.
int timeout = (int) execute_timers ();
if (get_load () == 0) {
if (timeout == 0)
break;
// TODO sleep for timeout
continue;
}
// Wait for events.
struct kevent ev_buf[max_io_events];
timespec ts = {timeout / 1000, (timeout % 1000) * 1000000};
int n = kevent (kqueue_fd, NULL, 0, &ev_buf[0], max_io_events,
timeout ? &ts : NULL);
#ifdef HAVE_FORK
if (unlikely (pid != getpid ())) {
//printf("zmq::kqueue_t::loop aborting on forked child %d\n", (int)getpid());
// simply exit the loop in a forked process.
return;
}
#endif
if (n == -1) {
errno_assert (errno == EINTR);
continue;
}
for (int i = 0; i < n; i++) {
poll_entry_t *pe = (poll_entry_t *) ev_buf[i].udata;
if (pe->fd == retired_fd)
continue;
if (ev_buf[i].flags & EV_EOF)
pe->reactor->in_event ();
if (pe->fd == retired_fd)
continue;
if (ev_buf[i].filter == EVFILT_WRITE)
pe->reactor->out_event ();
if (pe->fd == retired_fd)
continue;
if (ev_buf[i].filter == EVFILT_READ)
pe->reactor->in_event ();
}
// Destroy retired event sources.
for (retired_t::iterator it = retired.begin (); it != retired.end ();
++it) {
LIBZMQ_DELETE (*it);
}
retired.clear ();
}
}
#endif

109
vendor/ZMQ/src/kqueue.hpp vendored Normal file
View File

@ -0,0 +1,109 @@
/*
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_KQUEUE_HPP_INCLUDED__
#define __ZMQ_KQUEUE_HPP_INCLUDED__
// poller.hpp decides which polling mechanism to use.
#include "poller.hpp"
#if defined ZMQ_IOTHREAD_POLLER_USE_KQUEUE
#include <vector>
#include <unistd.h>
#include "ctx.hpp"
#include "fd.hpp"
#include "thread.hpp"
#include "poller_base.hpp"
namespace zmq
{
struct i_poll_events;
// Implements socket polling mechanism using the BSD-specific
// kqueue interface.
class kqueue_t ZMQ_FINAL : public worker_poller_base_t
{
public:
typedef void *handle_t;
kqueue_t (const thread_ctx_t &ctx_);
~kqueue_t () ZMQ_FINAL;
// "poller" concept.
handle_t add_fd (fd_t fd_, zmq::i_poll_events *events_);
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 stop ();
static int max_fds ();
private:
// Main event loop.
void loop () ZMQ_FINAL;
// File descriptor referring to the kernel event queue.
fd_t kqueue_fd;
// Adds the event to the kqueue.
void kevent_add (fd_t fd_, short filter_, void *udata_);
// Deletes the event from the kqueue.
void kevent_delete (fd_t fd_, short filter_);
struct poll_entry_t
{
fd_t fd;
bool flag_pollin;
bool flag_pollout;
zmq::i_poll_events *reactor;
};
// List of retired event sources.
typedef std::vector<poll_entry_t *> retired_t;
retired_t retired;
ZMQ_NON_COPYABLE_NOR_MOVABLE (kqueue_t)
#ifdef HAVE_FORK
// the process that created this context. Used to detect forking.
pid_t pid;
#endif
};
typedef kqueue_t poller_t;
}
#endif
#endif

180
vendor/ZMQ/src/lb.cpp vendored Normal file
View File

@ -0,0 +1,180 @@
/*
Copyright (c) 2007-2018 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_)
{
const 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) != 0;
_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 ();
// At this point the pipe is already being deallocated
// and the first N frames are unreachable (_outpipe is
// most likely already NULL so rollback won't actually do
// anything and they can't be un-written to deliver later).
// Return EFAULT to socket_base caller to drop current message
// and any other subsequent frames to avoid them being
// "stuck" and received when a new client reconnects, which
// would break atomicity of multi-part messages (in blocking mode
// socket_base just tries again and again to send the same message)
// Note that given dropping mode returns 0, the user will
// never know that the message could not be delivered, but
// can't really fix it without breaking backward compatibility.
// -2/EAGAIN will make sure socket_base caller does not re-enter
// immediately or after a short sleep in blocking mode.
_dropping = (msg_->flags () & msg_t::more) != 0;
_more = false;
errno = EAGAIN;
return -2;
}
_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) != 0;
if (!_more) {
_pipes[_current]->flush ();
if (++_current >= _active)
_current = 0;
}
// Detach the message from the data buffer.
const 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;
}

85
vendor/ZMQ/src/lb.hpp vendored Normal file
View File

@ -0,0 +1,85 @@
/*
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"
namespace zmq
{
class msg_t;
class pipe_t;
// 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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (lb_t)
};
}
#endif

12
vendor/ZMQ/src/libzmq.pc.in vendored Normal file
View File

@ -0,0 +1,12 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libzmq
Description: 0MQ c++ library
Version: @VERSION@
Libs: -L${libdir} -lzmq
Libs.private: -lstdc++ @pkg_config_libs_private@
Requires.private: @pkg_config_names_private@
Cflags: -I${includedir} @pkg_config_defines@

4
vendor/ZMQ/src/libzmq.vers vendored Normal file
View File

@ -0,0 +1,4 @@
{
global: zmq_*;
local: *;
};

42
vendor/ZMQ/src/likely.hpp vendored Normal file
View File

@ -0,0 +1,42 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_LIKELY_HPP_INCLUDED__
#define __ZMQ_LIKELY_HPP_INCLUDED__
#if defined __GNUC__
#define likely(x) __builtin_expect ((x), 1)
#define unlikely(x) __builtin_expect ((x), 0)
#else
#define likely(x) (x)
#define unlikely(x) (x)
#endif
#endif

63
vendor/ZMQ/src/macros.hpp vendored Normal file
View File

@ -0,0 +1,63 @@
/******************************************************************************/
/* 0MQ Internal Use */
/******************************************************************************/
#define LIBZMQ_UNUSED(object) (void) object
#define LIBZMQ_DELETE(p_object) \
{ \
delete p_object; \
p_object = 0; \
}
/******************************************************************************/
#if !defined ZMQ_NOEXCEPT
#if defined ZMQ_HAVE_NOEXCEPT
#define ZMQ_NOEXCEPT noexcept
#else
#define ZMQ_NOEXCEPT
#endif
#endif
#if !defined ZMQ_OVERRIDE
#if defined ZMQ_HAVE_NOEXCEPT
#define ZMQ_OVERRIDE override
#else
#define ZMQ_OVERRIDE
#endif
#endif
#if !defined ZMQ_FINAL
#if defined ZMQ_HAVE_NOEXCEPT
#define ZMQ_FINAL final
#else
#define ZMQ_FINAL
#endif
#endif
#if !defined ZMQ_DEFAULT
#if defined ZMQ_HAVE_NOEXCEPT
#define ZMQ_DEFAULT = default;
#else
#define ZMQ_DEFAULT \
{ \
}
#endif
#endif
#if !defined ZMQ_NON_COPYABLE_NOR_MOVABLE
#if defined ZMQ_HAVE_NOEXCEPT
#define ZMQ_NON_COPYABLE_NOR_MOVABLE(classname) \
public: \
classname (const classname &) = delete; \
classname &operator= (const classname &) = delete; \
classname (classname &&) = delete; \
classname &operator= (classname &&) = delete;
#else
#define ZMQ_NON_COPYABLE_NOR_MOVABLE(classname) \
private: \
classname (const classname &); \
classname &operator= (const classname &);
#endif
#endif

106
vendor/ZMQ/src/mailbox.cpp vendored Normal file
View File

@ -0,0 +1,106 @@
/*
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.check_read ();
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;
}
bool zmq::mailbox_t::valid () const
{
return _signaler.valid ();
}

86
vendor/ZMQ/src/mailbox.hpp vendored Normal file
View File

@ -0,0 +1,86 @@
/*
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 ZMQ_FINAL : 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_);
bool valid () const;
#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 () ZMQ_FINAL { _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;
ZMQ_NON_COPYABLE_NOR_MOVABLE (mailbox_t)
};
}
#endif

125
vendor/ZMQ/src/mailbox_safe.cpp vendored Normal file
View File

@ -0,0 +1,125 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "precompiled.hpp"
#include "mailbox_safe.hpp"
#include "clock.hpp"
#include "err.hpp"
#include <algorithm>
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.check_read ();
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_)
{
// TODO: make a copy of array and signal outside the lock
const std::vector<zmq::signaler_t *>::iterator end = _signalers.end ();
const std::vector<signaler_t *>::iterator it =
std::find (_signalers.begin (), end, signaler_);
if (it != 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 (),
end = _signalers.end ();
it != 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;
// If the timeout is zero, it will be quicker to release the lock, giving other a chance to send a command
// and immediately relock it.
if (timeout_ == 0) {
_sync->unlock ();
_sync->lock ();
} else {
// Wait for signal from the command sender.
const 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;
}

88
vendor/ZMQ/src/mailbox_safe.hpp vendored Normal file
View File

@ -0,0 +1,88 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_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 ZMQ_FINAL : 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 () ZMQ_FINAL
{
// 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 *const _sync;
std::vector<zmq::signaler_t *> _signalers;
ZMQ_NON_COPYABLE_NOR_MOVABLE (mailbox_safe_t)
};
}
#endif

370
vendor/ZMQ/src/mechanism.cpp vendored Normal file
View File

@ -0,0 +1,370 @@
/*
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 <limits.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 *user_id_, size_t size_)
{
_user_id.set (static_cast<const unsigned char *> (user_id_), size_);
_zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE (
std::string (ZMQ_MSG_PROPERTY_USER_ID),
std::string (reinterpret_cast<const char *> (user_id_), size_));
}
const zmq::blob_t &zmq::mechanism_t::get_user_id () const
{
return _user_id;
}
const char socket_type_pair[] = "PAIR";
const char socket_type_pub[] = "PUB";
const char socket_type_sub[] = "SUB";
const char socket_type_req[] = "REQ";
const char socket_type_rep[] = "REP";
const char socket_type_dealer[] = "DEALER";
const char socket_type_router[] = "ROUTER";
const char socket_type_pull[] = "PULL";
const char socket_type_push[] = "PUSH";
const char socket_type_xpub[] = "XPUB";
const char socket_type_xsub[] = "XSUB";
const char socket_type_stream[] = "STREAM";
#ifdef ZMQ_BUILD_DRAFT_API
const char socket_type_server[] = "SERVER";
const char socket_type_client[] = "CLIENT";
const char socket_type_radio[] = "RADIO";
const char socket_type_dish[] = "DISH";
const char socket_type_gather[] = "GATHER";
const char socket_type_scatter[] = "SCATTER";
const char socket_type_dgram[] = "DGRAM";
const char socket_type_peer[] = "PEER";
const char socket_type_channel[] = "CHANNEL";
#endif
const char *zmq::mechanism_t::socket_type_string (int socket_type_)
{
// TODO the order must of the names must correspond to the values resp. order of ZMQ_* socket type definitions in zmq.h!
static const char *names[] = {socket_type_pair, socket_type_pub,
socket_type_sub, socket_type_req,
socket_type_rep, socket_type_dealer,
socket_type_router, socket_type_pull,
socket_type_push, socket_type_xpub,
socket_type_xsub, socket_type_stream,
#ifdef ZMQ_BUILD_DRAFT_API
socket_type_server, socket_type_client,
socket_type_radio, socket_type_dish,
socket_type_gather, socket_type_scatter,
socket_type_dgram, socket_type_peer,
socket_type_channel
#endif
};
static const size_t names_count = sizeof (names) / sizeof (names[0]);
zmq_assert (socket_type_ >= 0
&& socket_type_ < static_cast<int> (names_count));
return names[socket_type_];
}
const size_t name_len_size = sizeof (unsigned char);
const size_t value_len_size = sizeof (uint32_t);
static size_t property_len (size_t name_len_, size_t value_len_)
{
return name_len_size + name_len_ + value_len_size + value_len_;
}
static size_t name_len (const char *name_)
{
const size_t name_len = strlen (name_);
zmq_assert (name_len <= UCHAR_MAX);
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);
ptr_ += name_len_size;
memcpy (ptr_, name_, name_len);
ptr_ += name_len;
zmq_assert (value_len_ <= 0x7FFFFFFF);
put_uint32 (ptr_, static_cast<uint32_t> (value_len_));
ptr_ += value_len_size;
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 *ptr_,
size_t ptr_capacity_) const
{
unsigned char *ptr = ptr_;
// Add socket type property
const char *socket_type = socket_type_string (options.type);
ptr += add_property (ptr, ptr_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, ptr_capacity_ - (ptr - ptr_),
ZMTP_PROPERTY_IDENTITY, options.routing_id,
options.routing_id_size);
}
for (std::map<std::string, std::string>::const_iterator
it = options.app_metadata.begin (),
end = options.app_metadata.end ();
it != end; ++it) {
ptr +=
add_property (ptr, ptr_capacity_ - (ptr - ptr_), it->first.c_str (),
it->second.c_str (), strlen (it->second.c_str ()));
}
return ptr - ptr_;
}
size_t zmq::mechanism_t::basic_properties_len () const
{
const char *socket_type = socket_type_string (options.type);
size_t meta_len = 0;
for (std::map<std::string, std::string>::const_iterator
it = options.app_metadata.begin (),
end = options.app_metadata.end ();
it != end; ++it) {
meta_len +=
property_len (it->first.c_str (), strlen (it->second.c_str ()));
}
return property_len (ZMTP_PROPERTY_SOCKET_TYPE, strlen (socket_type))
+ meta_len
+ ((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 = static_cast<unsigned char *> (msg_->data ());
// Add prefix
memcpy (ptr, prefix_, prefix_len_);
ptr += prefix_len_;
add_basic_properties (
ptr, command_size - (ptr - static_cast<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_ += name_len_size;
bytes_left -= name_len_size;
if (bytes_left < name_length)
break;
const std::string name =
std::string (reinterpret_cast<const char *> (ptr_), name_length);
ptr_ += name_length;
bytes_left -= name_length;
if (bytes_left < value_len_size)
break;
const size_t value_length = static_cast<size_t> (get_uint32 (ptr_));
ptr_ += value_len_size;
bytes_left -= value_len_size;
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) {
if (!check_socket_type (reinterpret_cast<const char *> (value),
value_length)) {
errno = EINVAL;
return -1;
}
} else {
const int rc = property (name, value, value_length);
if (rc == -1)
return -1;
}
(zap_flag_ ? _zap_properties : _zmtp_properties)
.ZMQ_MAP_INSERT_OR_EMPLACE (
name,
std::string (reinterpret_cast<const 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;
}
template <size_t N>
static bool strequals (const char *actual_type_,
const size_t actual_len_,
const char (&expected_type_)[N])
{
return actual_len_ == N - 1
&& memcmp (actual_type_, expected_type_, N - 1) == 0;
}
bool zmq::mechanism_t::check_socket_type (const char *type_,
const size_t len_) const
{
switch (options.type) {
case ZMQ_REQ:
return strequals (type_, len_, socket_type_rep)
|| strequals (type_, len_, socket_type_router);
case ZMQ_REP:
return strequals (type_, len_, socket_type_req)
|| strequals (type_, len_, socket_type_dealer);
case ZMQ_DEALER:
return strequals (type_, len_, socket_type_rep)
|| strequals (type_, len_, socket_type_dealer)
|| strequals (type_, len_, socket_type_router);
case ZMQ_ROUTER:
return strequals (type_, len_, socket_type_req)
|| strequals (type_, len_, socket_type_dealer)
|| strequals (type_, len_, socket_type_router);
case ZMQ_PUSH:
return strequals (type_, len_, socket_type_pull);
case ZMQ_PULL:
return strequals (type_, len_, socket_type_push);
case ZMQ_PUB:
return strequals (type_, len_, socket_type_sub)
|| strequals (type_, len_, socket_type_xsub);
case ZMQ_SUB:
return strequals (type_, len_, socket_type_pub)
|| strequals (type_, len_, socket_type_xpub);
case ZMQ_XPUB:
return strequals (type_, len_, socket_type_sub)
|| strequals (type_, len_, socket_type_xsub);
case ZMQ_XSUB:
return strequals (type_, len_, socket_type_pub)
|| strequals (type_, len_, socket_type_xpub);
case ZMQ_PAIR:
return strequals (type_, len_, socket_type_pair);
#ifdef ZMQ_BUILD_DRAFT_API
case ZMQ_SERVER:
return strequals (type_, len_, socket_type_client);
case ZMQ_CLIENT:
return strequals (type_, len_, socket_type_server);
case ZMQ_RADIO:
return strequals (type_, len_, socket_type_dish);
case ZMQ_DISH:
return strequals (type_, len_, socket_type_radio);
case ZMQ_GATHER:
return strequals (type_, len_, socket_type_scatter);
case ZMQ_SCATTER:
return strequals (type_, len_, socket_type_gather);
case ZMQ_DGRAM:
return strequals (type_, len_, socket_type_dgram);
case ZMQ_PEER:
return strequals (type_, len_, socket_type_peer);
case ZMQ_CHANNEL:
return strequals (type_, len_, socket_type_channel);
#endif
default:
break;
}
return false;
}

151
vendor/ZMQ/src/mechanism.hpp vendored Normal file
View File

@ -0,0 +1,151 @@
/*
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 () const
{
return _zmtp_properties;
}
const metadata_t::dict_t &get_zap_properties () const
{
return _zap_properties;
}
protected:
// Only used to identify the socket for the Socket-Type
// property in the wire protocol.
static const char *socket_type_string (int socket_type_);
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_);
const options_t options;
private:
// Properties received from ZMTP peer.
metadata_t::dict_t _zmtp_properties;
// Properties received from ZAP server.
metadata_t::dict_t _zap_properties;
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 char *type_, size_t len_) const;
};
}
#endif

82
vendor/ZMQ/src/mechanism_base.cpp vendored Normal file
View File

@ -0,0 +1,82 @@
/*
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_) const
{
if (msg_->size () <= 1
|| msg_->size () <= (static_cast<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_)
{
const size_t status_code_len = 3;
const char zero_digit = '0';
const size_t significant_digit_index = 0;
const size_t first_zero_digit_index = 1;
const size_t second_zero_digit_index = 2;
const int factor = 100;
if (error_reason_len_ == status_code_len
&& error_reason_[first_zero_digit_index] == zero_digit
&& error_reason_[second_zero_digit_index] == zero_digit
&& error_reason_[significant_digit_index] >= '3'
&& error_reason_[significant_digit_index] <= '5') {
// it is a ZAP error status code (300, 400 or 500), so emit an authentication failure event
session->get_socket ()->event_handshake_failed_auth (
session->get_endpoint (),
(error_reason_[significant_digit_index] - zero_digit) * factor);
} else {
// this is a violation of the ZAP protocol
// TODO zmq_assert in this case?
}
}
bool zmq::mechanism_base_t::zap_required () const
{
return !options.zap_domain.empty ();
}

55
vendor/ZMQ/src/mechanism_base.hpp vendored Normal file
View File

@ -0,0 +1,55 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MECHANISM_BASE_HPP_INCLUDED__
#define __ZMQ_MECHANISM_BASE_HPP_INCLUDED__
#include "mechanism.hpp"
namespace zmq
{
class msg_t;
class mechanism_base_t : public mechanism_t
{
protected:
mechanism_base_t (session_base_t *session_, const options_t &options_);
session_base_t *const session;
int check_basic_command_structure (msg_t *msg_) const;
void handle_error_reason (const char *error_reason_,
size_t error_reason_len_);
bool zap_required () const;
};
}
#endif

58
vendor/ZMQ/src/metadata.cpp vendored Normal file
View File

@ -0,0 +1,58 @@
/*
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
{
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;
}
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);
}

68
vendor/ZMQ/src/metadata.hpp vendored Normal file
View File

@ -0,0 +1,68 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_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:
// Reference counter.
atomic_counter_t _ref_cnt;
// Dictionary holding metadata.
const dict_t _dict;
ZMQ_NON_COPYABLE_NOR_MOVABLE (metadata_t)
};
}
#endif

725
vendor/ZMQ/src/msg.cpp vendored Normal file
View File

@ -0,0 +1,725 @@
/*
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 "compat.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) {
const int rc = init_size (size_);
if (rc != -1) {
memcpy (data (), data_, size_);
return 0;
}
return -1;
}
if (content_) {
return init_external_storage (content_, data_, size_, ffn_, hint_);
}
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.sgroup.group[0] = '\0';
_u.vsm.group.type = group_type_short;
_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 = static_cast<unsigned char> (size_);
_u.vsm.group.sgroup.group[0] = '\0';
_u.vsm.group.type = group_type_short;
_u.vsm.routing_id = 0;
} else {
_u.lmsg.metadata = NULL;
_u.lmsg.type = type_lmsg;
_u.lmsg.flags = 0;
_u.lmsg.group.sgroup.group[0] = '\0';
_u.lmsg.group.type = group_type_short;
_u.lmsg.routing_id = 0;
_u.lmsg.content = NULL;
if (sizeof (content_t) + size_ > size_)
_u.lmsg.content =
static_cast<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_buffer (const void *buf_, size_t size_)
{
const int rc = init_size (size_);
if (unlikely (rc < 0)) {
return -1;
}
if (size_) {
// NULL and zero size is allowed
assert (NULL != buf_);
memcpy (data (), buf_, size_);
}
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.sgroup.group[0] = '\0';
_u.zclmsg.group.type = group_type_short;
_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.sgroup.group[0] = '\0';
_u.cmsg.group.type = group_type_short;
_u.cmsg.routing_id = 0;
} else {
_u.lmsg.metadata = NULL;
_u.lmsg.type = type_lmsg;
_u.lmsg.flags = 0;
_u.lmsg.group.sgroup.group[0] = '\0';
_u.lmsg.group.type = group_type_short;
_u.lmsg.routing_id = 0;
_u.lmsg.content =
static_cast<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.sgroup.group[0] = '\0';
_u.delimiter.group.type = group_type_short;
_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.sgroup.group[0] = '\0';
_u.base.group.type = group_type_short;
_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.sgroup.group[0] = '\0';
_u.base.group.type = group_type_short;
_u.base.routing_id = 0;
return 0;
}
int zmq::msg_t::init_subscribe (const size_t size_, const unsigned char *topic_)
{
int rc = init_size (size_);
if (rc == 0) {
set_flags (zmq::msg_t::subscribe);
// We explicitly allow a NULL subscription with size zero
if (size_) {
assert (topic_);
memcpy (data (), topic_, size_);
}
}
return rc;
}
int zmq::msg_t::init_cancel (const size_t size_, const unsigned char *topic_)
{
int rc = init_size (size_);
if (rc == 0) {
set_flags (zmq::msg_t::cancel);
// We explicitly allow a NULL subscription with size zero
if (size_) {
assert (topic_);
memcpy (data (), topic_, size_);
}
}
return rc;
}
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;
}
if (_u.base.group.type == group_type_long) {
if (!_u.base.group.lgroup.content->refcnt.sub (1)) {
// We used "placement new" operator to initialize the reference
// counter so we call the destructor explicitly now.
_u.base.group.lgroup.content->refcnt.~atomic_counter_t ();
free (_u.base.group.lgroup.content);
}
}
// 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;
}
const int rc = close ();
if (unlikely (rc < 0))
return rc;
// The initial reference count, when a non-shared message is initially
// shared (between the original and the copy we create here).
const atomic_counter_t::integer_t initial_shared_refcnt = 2;
if (src_.is_lmsg () || src_.is_zcmsg ()) {
// One reference is added to shared messages. Non-shared messages
// are turned into shared messages.
if (src_.flags () & msg_t::shared)
src_.refcnt ()->add (1);
else {
src_.set_flags (msg_t::shared);
src_.refcnt ()->set (initial_shared_refcnt);
}
}
if (src_._u.base.metadata != NULL)
src_._u.base.metadata->add_ref ();
if (src_._u.base.group.type == group_type_long)
src_._u.base.group.lgroup.content->refcnt.add (1);
*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;
}
}
void zmq::msg_t::shrink (size_t new_size_)
{
// Check the validity of the message.
zmq_assert (check ());
zmq_assert (new_size_ <= size ());
switch (_u.base.type) {
case type_vsm:
_u.vsm.size = static_cast<unsigned char> (new_size_);
break;
case type_lmsg:
_u.lmsg.content->size = new_size_;
break;
case type_zclmsg:
_u.zclmsg.content->size = new_size_;
break;
case type_cmsg:
_u.cmsg.size = new_size_;
break;
default:
zmq_assert (false);
}
}
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_lmsg () const
{
return _u.base.type == type_lmsg;
}
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;
}
bool zmq::msg_t::is_ping () const
{
return (_u.base.flags & CMD_TYPE_MASK) == ping;
}
bool zmq::msg_t::is_pong () const
{
return (_u.base.flags & CMD_TYPE_MASK) == pong;
}
bool zmq::msg_t::is_close_cmd () const
{
return (_u.base.flags & CMD_TYPE_MASK) == close_cmd;
}
size_t zmq::msg_t::command_body_size () const
{
if (this->is_ping () || this->is_pong ())
return this->size () - ping_cmd_name_size;
else if (!(this->flags () & msg_t::command)
&& (this->is_subscribe () || this->is_cancel ()))
return this->size ();
else if (this->is_subscribe ())
return this->size () - sub_cmd_name_size;
else if (this->is_cancel ())
return this->size () - cancel_cmd_name_size;
return 0;
}
void *zmq::msg_t::command_body ()
{
unsigned char *data = NULL;
if (this->is_ping () || this->is_pong ())
data =
static_cast<unsigned char *> (this->data ()) + ping_cmd_name_size;
// With inproc, command flag is not set for sub/cancel
else if (!(this->flags () & msg_t::command)
&& (this->is_subscribe () || this->is_cancel ()))
data = static_cast<unsigned char *> (this->data ());
else if (this->is_subscribe ())
data = static_cast<unsigned char *> (this->data ()) + sub_cmd_name_size;
else if (this->is_cancel ())
data =
static_cast<unsigned char *> (this->data ()) + cancel_cmd_name_size;
return data;
}
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 () const
{
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 () const
{
if (_u.base.group.type == group_type_long)
return _u.base.group.lgroup.content->group;
return _u.base.group.sgroup.group;
}
int zmq::msg_t::set_group (const char *group_)
{
size_t length = strnlen (group_, ZMQ_GROUP_MAX_LENGTH);
return set_group (group_, length);
}
int zmq::msg_t::set_group (const char *group_, size_t length_)
{
if (length_ > ZMQ_GROUP_MAX_LENGTH) {
errno = EINVAL;
return -1;
}
if (length_ > 14) {
_u.base.group.lgroup.type = group_type_long;
_u.base.group.lgroup.content =
(long_group_t *) malloc (sizeof (long_group_t));
assert (_u.base.group.lgroup.content);
new (&_u.base.group.lgroup.content->refcnt) zmq::atomic_counter_t ();
_u.base.group.lgroup.content->refcnt.set (1);
strncpy (_u.base.group.lgroup.content->group, group_, length_);
_u.base.group.lgroup.content->group[length_] = '\0';
} else {
strncpy (_u.base.group.sgroup.group, group_, length_);
_u.base.group.sgroup.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;
}
}

345
vendor/ZMQ/src/msg.hpp vendored Normal file
View File

@ -0,0 +1,345 @@
/*
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"
// bits 2-5
#define CMD_TYPE_MASK 0x1c
// 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).
static const char cancel_cmd_name[] = "\6CANCEL";
static const char sub_cmd_name[] = "\x9SUBSCRIBE";
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)
// Command types, use only bits 2-5 and compare with ==, not bitwise,
// a command can never be of more that one type at the same time
ping = 4,
pong = 8,
subscribe = 12,
cancel = 16,
close_cmd = 20,
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_buffer (const void *buf_, 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 init_subscribe (const size_t size_, const unsigned char *topic);
int init_cancel (const size_t size_, const unsigned char *topic);
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_ping () const;
bool is_pong () const;
bool is_close_cmd () const;
// These are called on each message received by the session_base class,
// so get them inlined to avoid the overhead of 2 function calls per msg
bool is_subscribe () const
{
return (_u.base.flags & CMD_TYPE_MASK) == subscribe;
}
bool is_cancel () const
{
return (_u.base.flags & CMD_TYPE_MASK) == cancel;
}
size_t command_body_size () const;
void *command_body ();
bool is_vsm () const;
bool is_cmsg () const;
bool is_lmsg () const;
bool is_zcmsg () const;
uint32_t get_routing_id () const;
int set_routing_id (uint32_t routing_id_);
int reset_routing_id ();
const char *group () const;
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_);
void shrink (size_t new_size_);
// 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))
};
enum
{
ping_cmd_name_size = 5, // 4PING
cancel_cmd_name_size = 7, // 6CANCEL
sub_cmd_name_size = 10 // 9SUBSCRIBE
};
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
};
enum group_type_t
{
group_type_short,
group_type_long
};
struct long_group_t
{
char group[ZMQ_GROUP_MAX_LENGTH + 1];
atomic_counter_t refcnt;
};
union group_t
{
unsigned char type;
struct
{
unsigned char type;
char group[15];
} sgroup;
struct
{
unsigned char type;
long_group_t *content;
} lgroup;
};
// 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
+ sizeof (uint32_t) + sizeof (group_t))];
unsigned char type;
unsigned char flags;
uint32_t routing_id;
group_t group;
} base;
struct
{
metadata_t *metadata;
unsigned char data[max_vsm_size];
unsigned char size;
unsigned char type;
unsigned char flags;
uint32_t routing_id;
group_t group;
} vsm;
struct
{
metadata_t *metadata;
content_t *content;
unsigned char
unused[msg_t_size
- (sizeof (metadata_t *) + sizeof (content_t *) + 2
+ sizeof (uint32_t) + sizeof (group_t))];
unsigned char type;
unsigned char flags;
uint32_t routing_id;
group_t group;
} lmsg;
struct
{
metadata_t *metadata;
content_t *content;
unsigned char
unused[msg_t_size
- (sizeof (metadata_t *) + sizeof (content_t *) + 2
+ sizeof (uint32_t) + sizeof (group_t))];
unsigned char type;
unsigned char flags;
uint32_t routing_id;
group_t group;
} 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 + sizeof (uint32_t)
+ sizeof (group_t))];
unsigned char type;
unsigned char flags;
uint32_t routing_id;
group_t group;
} cmsg;
struct
{
metadata_t *metadata;
unsigned char unused[msg_t_size
- (sizeof (metadata_t *) + 2
+ sizeof (uint32_t) + sizeof (group_t))];
unsigned char type;
unsigned char flags;
uint32_t routing_id;
group_t group;
} 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.
const 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

37
vendor/ZMQ/src/mtrie.cpp vendored Normal file
View File

@ -0,0 +1,37 @@
/*
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 "mtrie.hpp"
#include "generic_mtrie_impl.hpp"
namespace zmq
{
template class generic_mtrie_t<pipe_t>;
}

52
vendor/ZMQ/src/mtrie.hpp vendored Normal file
View File

@ -0,0 +1,52 @@
/*
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
This file is part of libzmq, the ZeroMQ core engine in C++.
libzmq is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License (LGPL) as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
As a special exception, the Contributors give you permission to link
this library with independent modules to produce an executable,
regardless of the license terms of these independent modules, and to
copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the
terms and conditions of the license of that module. An independent
module is a module which is not derived from or based on this library.
If you modify this library, you must extend this exception to your
version of the library.
libzmq is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __ZMQ_MTRIE_HPP_INCLUDED__
#define __ZMQ_MTRIE_HPP_INCLUDED__
#include "generic_mtrie.hpp"
#if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER > 1600)
#define ZMQ_HAS_EXTERN_TEMPLATE 1
#else
#define ZMQ_HAS_EXTERN_TEMPLATE 0
#endif
namespace zmq
{
class pipe_t;
#if ZMQ_HAS_EXTERN_TEMPLATE
extern template class generic_mtrie_t<pipe_t>;
#endif
typedef generic_mtrie_t<pipe_t> mtrie_t;
}
#endif

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