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:
143
vendor/ZMQ/src/address.cpp
vendored
Normal file
143
vendor/ZMQ/src/address.cpp
vendored
Normal 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
162
vendor/ZMQ/src/address.hpp
vendored
Normal 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
140
vendor/ZMQ/src/array.hpp
vendored
Normal 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
235
vendor/ZMQ/src/atomic_counter.hpp
vendored
Normal 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
306
vendor/ZMQ/src/atomic_ptr.hpp
vendored
Normal 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
205
vendor/ZMQ/src/blob.hpp
vendored
Normal 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
160
vendor/ZMQ/src/channel.cpp
vendored
Normal 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
69
vendor/ZMQ/src/channel.hpp
vendored
Normal 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
114
vendor/ZMQ/src/client.cpp
vendored
Normal 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
73
vendor/ZMQ/src/client.hpp
vendored
Normal 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
277
vendor/ZMQ/src/clock.cpp
vendored
Normal 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
80
vendor/ZMQ/src/clock.hpp
vendored
Normal 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
225
vendor/ZMQ/src/command.hpp
vendored
Normal 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
75
vendor/ZMQ/src/compat.hpp
vendored
Normal 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
313
vendor/ZMQ/src/condition_variable.hpp
vendored
Normal 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
89
vendor/ZMQ/src/config.hpp
vendored
Normal 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
893
vendor/ZMQ/src/ctx.cpp
vendored
Normal 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
271
vendor/ZMQ/src/ctx.hpp
vendored
Normal 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
287
vendor/ZMQ/src/curve_client.cpp
vendored
Normal 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
86
vendor/ZMQ/src/curve_client.hpp
vendored
Normal 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
316
vendor/ZMQ/src/curve_client_tools.hpp
vendored
Normal 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
313
vendor/ZMQ/src/curve_mechanism_base.cpp
vendored
Normal 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
108
vendor/ZMQ/src/curve_mechanism_base.hpp
vendored
Normal 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
506
vendor/ZMQ/src/curve_server.cpp
vendored
Normal 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
92
vendor/ZMQ/src/curve_server.hpp
vendored
Normal 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
134
vendor/ZMQ/src/dbuffer.hpp
vendored
Normal 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
145
vendor/ZMQ/src/dealer.cpp
vendored
Normal 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
85
vendor/ZMQ/src/dealer.hpp
vendored
Normal 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
191
vendor/ZMQ/src/decoder.hpp
vendored
Normal 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
151
vendor/ZMQ/src/decoder_allocators.cpp
vendored
Normal 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
133
vendor/ZMQ/src/decoder_allocators.hpp
vendored
Normal 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
208
vendor/ZMQ/src/devpoll.cpp
vendored
Normal 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
101
vendor/ZMQ/src/devpoll.hpp
vendored
Normal 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
169
vendor/ZMQ/src/dgram.cpp
vendored
Normal 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
74
vendor/ZMQ/src/dgram.hpp
vendored
Normal 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
350
vendor/ZMQ/src/dish.cpp
vendored
Normal 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
121
vendor/ZMQ/src/dish.hpp
vendored
Normal 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
237
vendor/ZMQ/src/dist.cpp
vendored
Normal 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
115
vendor/ZMQ/src/dist.hpp
vendored
Normal 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
178
vendor/ZMQ/src/encoder.hpp
vendored
Normal 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
44
vendor/ZMQ/src/endpoint.cpp
vendored
Normal 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
72
vendor/ZMQ/src/endpoint.hpp
vendored
Normal 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
218
vendor/ZMQ/src/epoll.cpp
vendored
Normal 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
114
vendor/ZMQ/src/epoll.hpp
vendored
Normal 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
453
vendor/ZMQ/src/err.cpp
vendored
Normal 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
183
vendor/ZMQ/src/err.hpp
vendored
Normal 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
63
vendor/ZMQ/src/fd.hpp
vendored
Normal 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
150
vendor/ZMQ/src/fq.cpp
vendored
Normal 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
84
vendor/ZMQ/src/fq.hpp
vendored
Normal 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
91
vendor/ZMQ/src/gather.cpp
vendored
Normal 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
66
vendor/ZMQ/src/gather.hpp
vendored
Normal 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
117
vendor/ZMQ/src/generic_mtrie.hpp
vendored
Normal 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
593
vendor/ZMQ/src/generic_mtrie_impl.hpp
vendored
Normal 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
236
vendor/ZMQ/src/gssapi_client.cpp
vendored
Normal 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
92
vendor/ZMQ/src/gssapi_client.hpp
vendored
Normal 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
402
vendor/ZMQ/src/gssapi_mechanism_base.cpp
vendored
Normal 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
132
vendor/ZMQ/src/gssapi_mechanism_base.hpp
vendored
Normal 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
248
vendor/ZMQ/src/gssapi_server.cpp
vendored
Normal 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
93
vendor/ZMQ/src/gssapi_server.hpp
vendored
Normal 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
61
vendor/ZMQ/src/i_decoder.hpp
vendored
Normal 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
58
vendor/ZMQ/src/i_encoder.hpp
vendored
Normal 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
82
vendor/ZMQ/src/i_engine.hpp
vendored
Normal 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
58
vendor/ZMQ/src/i_mailbox.hpp
vendored
Normal 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
55
vendor/ZMQ/src/i_poll_events.hpp
vendored
Normal 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
116
vendor/ZMQ/src/io_object.cpp
vendored
Normal 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
83
vendor/ZMQ/src/io_object.hpp
vendored
Normal 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
121
vendor/ZMQ/src/io_thread.cpp
vendored
Normal 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
92
vendor/ZMQ/src/io_thread.hpp
vendored
Normal 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
945
vendor/ZMQ/src/ip.cpp
vendored
Normal 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
89
vendor/ZMQ/src/ip.hpp
vendored
Normal 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
743
vendor/ZMQ/src/ip_resolver.cpp
vendored
Normal 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
121
vendor/ZMQ/src/ip_resolver.hpp
vendored
Normal 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
120
vendor/ZMQ/src/ipc_address.cpp
vendored
Normal 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
74
vendor/ZMQ/src/ipc_address.hpp
vendored
Normal 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
186
vendor/ZMQ/src/ipc_connecter.cpp
vendored
Normal 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
73
vendor/ZMQ/src/ipc_connecter.hpp
vendored
Normal 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
357
vendor/ZMQ/src/ipc_listener.cpp
vendored
Normal 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
88
vendor/ZMQ/src/ipc_listener.hpp
vendored
Normal 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
230
vendor/ZMQ/src/kqueue.cpp
vendored
Normal 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
109
vendor/ZMQ/src/kqueue.hpp
vendored
Normal 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
180
vendor/ZMQ/src/lb.cpp
vendored
Normal 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
85
vendor/ZMQ/src/lb.hpp
vendored
Normal 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
12
vendor/ZMQ/src/libzmq.pc.in
vendored
Normal 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
4
vendor/ZMQ/src/libzmq.vers
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
global: zmq_*;
|
||||
local: *;
|
||||
};
|
42
vendor/ZMQ/src/likely.hpp
vendored
Normal file
42
vendor/ZMQ/src/likely.hpp
vendored
Normal 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
63
vendor/ZMQ/src/macros.hpp
vendored
Normal 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
106
vendor/ZMQ/src/mailbox.cpp
vendored
Normal 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
86
vendor/ZMQ/src/mailbox.hpp
vendored
Normal 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
125
vendor/ZMQ/src/mailbox_safe.cpp
vendored
Normal 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
88
vendor/ZMQ/src/mailbox_safe.hpp
vendored
Normal 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
370
vendor/ZMQ/src/mechanism.cpp
vendored
Normal 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
151
vendor/ZMQ/src/mechanism.hpp
vendored
Normal 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
82
vendor/ZMQ/src/mechanism_base.cpp
vendored
Normal 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
55
vendor/ZMQ/src/mechanism_base.hpp
vendored
Normal 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
58
vendor/ZMQ/src/metadata.cpp
vendored
Normal 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
68
vendor/ZMQ/src/metadata.hpp
vendored
Normal 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
725
vendor/ZMQ/src/msg.cpp
vendored
Normal 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
345
vendor/ZMQ/src/msg.hpp
vendored
Normal 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
37
vendor/ZMQ/src/mtrie.cpp
vendored
Normal 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
52
vendor/ZMQ/src/mtrie.hpp
vendored
Normal 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
Reference in New Issue
Block a user