src/loggers/zmq.hpp
Go to the documentation of this file.
1 /*
2  Copyright (c) 2016-2017 ZeroMQ community
3  Copyright (c) 2009-2011 250bpm s.r.o.
4  Copyright (c) 2011 Botond Ballo
5  Copyright (c) 2007-2009 iMatix Corporation
6 
7  Permission is hereby granted, free of charge, to any person obtaining a copy
8  of this software and associated documentation files (the "Software"), to
9  deal in the Software without restriction, including without limitation the
10  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11  sell copies of the Software, and to permit persons to whom the Software is
12  furnished to do so, subject to the following conditions:
13 
14  The above copyright notice and this permission notice shall be included in
15  all copies or substantial portions of the Software.
16 
17  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
23  IN THE SOFTWARE.
24 */
25 
26 #ifndef __ZMQ_HPP_INCLUDED__
27 #define __ZMQ_HPP_INCLUDED__
28 
29 #ifdef _WIN32
30 #ifndef NOMINMAX
31 #define NOMINMAX
32 #endif
33 #endif
34 
35 // included here for _HAS_CXX* macros
36 #include <zmq.h>
37 
38 #if defined(_MSVC_LANG)
39 #define CPPZMQ_LANG _MSVC_LANG
40 #else
41 #define CPPZMQ_LANG __cplusplus
42 #endif
43 // overwrite if specific language macros indicate higher version
44 #if defined(_HAS_CXX14) && _HAS_CXX14 && CPPZMQ_LANG < 201402L
45 #undef CPPZMQ_LANG
46 #define CPPZMQ_LANG 201402L
47 #endif
48 #if defined(_HAS_CXX17) && _HAS_CXX17 && CPPZMQ_LANG < 201703L
49 #undef CPPZMQ_LANG
50 #define CPPZMQ_LANG 201703L
51 #endif
52 
53 // macros defined if has a specific standard or greater
54 #if CPPZMQ_LANG >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1900)
55 #define ZMQ_CPP11
56 #endif
57 #if CPPZMQ_LANG >= 201402L
58 #define ZMQ_CPP14
59 #endif
60 #if CPPZMQ_LANG >= 201703L
61 #define ZMQ_CPP17
62 #endif
63 
64 #if defined(ZMQ_CPP14) && !defined(_MSC_VER)
65 #define ZMQ_DEPRECATED(msg) [[deprecated(msg)]]
66 #elif defined(_MSC_VER)
67 #define ZMQ_DEPRECATED(msg) __declspec(deprecated(msg))
68 #elif defined(__GNUC__)
69 #define ZMQ_DEPRECATED(msg) __attribute__((deprecated(msg)))
70 #endif
71 
72 #if defined(ZMQ_CPP17)
73 #define ZMQ_NODISCARD [[nodiscard]]
74 #else
75 #define ZMQ_NODISCARD
76 #endif
77 
78 #if defined(ZMQ_CPP11)
79 #define ZMQ_NOTHROW noexcept
80 #define ZMQ_EXPLICIT explicit
81 #define ZMQ_OVERRIDE override
82 #define ZMQ_NULLPTR nullptr
83 #define ZMQ_CONSTEXPR_FN constexpr
84 #define ZMQ_CONSTEXPR_VAR constexpr
85 #define ZMQ_CPP11_DEPRECATED(msg) ZMQ_DEPRECATED(msg)
86 #else
87 #define ZMQ_NOTHROW throw()
88 #define ZMQ_EXPLICIT
89 #define ZMQ_OVERRIDE
90 #define ZMQ_NULLPTR 0
91 #define ZMQ_CONSTEXPR_FN
92 #define ZMQ_CONSTEXPR_VAR const
93 #define ZMQ_CPP11_DEPRECATED(msg)
94 #endif
95 #if defined(ZMQ_CPP14) && (!defined(_MSC_VER) || _MSC_VER > 1900)
96 #define ZMQ_EXTENDED_CONSTEXPR
97 #endif
98 #if defined(ZMQ_CPP17)
99 #define ZMQ_INLINE_VAR inline
100 #else
101 #define ZMQ_INLINE_VAR
102 #endif
103 
104 #include <cassert>
105 #include <cstring>
106 
107 #include <algorithm>
108 #include <exception>
109 #include <iomanip>
110 #include <sstream>
111 #include <string>
112 #include <vector>
113 #ifdef ZMQ_CPP11
114 #include <array>
115 #include <chrono>
116 #include <tuple>
117 #include <memory>
118 #endif
119 
120 #if defined(__has_include) && defined(ZMQ_CPP17)
121 #define CPPZMQ_HAS_INCLUDE_CPP17(X) __has_include(X)
122 #else
123 #define CPPZMQ_HAS_INCLUDE_CPP17(X) 0
124 #endif
125 
126 #if CPPZMQ_HAS_INCLUDE_CPP17(<optional>) && !defined(CPPZMQ_HAS_OPTIONAL)
127 #define CPPZMQ_HAS_OPTIONAL 1
128 #endif
129 #ifndef CPPZMQ_HAS_OPTIONAL
130 #define CPPZMQ_HAS_OPTIONAL 0
131 #elif CPPZMQ_HAS_OPTIONAL
132 #include <optional>
133 #endif
134 
135 #if CPPZMQ_HAS_INCLUDE_CPP17(<string_view>) && !defined(CPPZMQ_HAS_STRING_VIEW)
136 #define CPPZMQ_HAS_STRING_VIEW 1
137 #endif
138 #ifndef CPPZMQ_HAS_STRING_VIEW
139 #define CPPZMQ_HAS_STRING_VIEW 0
140 #elif CPPZMQ_HAS_STRING_VIEW
141 #include <string_view>
142 #endif
143 
144 /* Version macros for compile-time API version detection */
145 #define CPPZMQ_VERSION_MAJOR 4
146 #define CPPZMQ_VERSION_MINOR 7
147 #define CPPZMQ_VERSION_PATCH 1
148 
149 #define CPPZMQ_VERSION \
150  ZMQ_MAKE_VERSION(CPPZMQ_VERSION_MAJOR, CPPZMQ_VERSION_MINOR, \
151  CPPZMQ_VERSION_PATCH)
152 
153 // Detect whether the compiler supports C++11 rvalue references.
154 #if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)) \
155  && defined(__GXX_EXPERIMENTAL_CXX0X__))
156 #define ZMQ_HAS_RVALUE_REFS
157 #define ZMQ_DELETED_FUNCTION = delete
158 #elif defined(__clang__)
159 #if __has_feature(cxx_rvalue_references)
160 #define ZMQ_HAS_RVALUE_REFS
161 #endif
162 
163 #if __has_feature(cxx_deleted_functions)
164 #define ZMQ_DELETED_FUNCTION = delete
165 #else
166 #define ZMQ_DELETED_FUNCTION
167 #endif
168 #elif defined(_MSC_VER) && (_MSC_VER >= 1900)
169 #define ZMQ_HAS_RVALUE_REFS
170 #define ZMQ_DELETED_FUNCTION = delete
171 #elif defined(_MSC_VER) && (_MSC_VER >= 1600)
172 #define ZMQ_HAS_RVALUE_REFS
173 #define ZMQ_DELETED_FUNCTION
174 #else
175 #define ZMQ_DELETED_FUNCTION
176 #endif
177 
178 #if defined(ZMQ_CPP11) && !defined(__llvm__) && !defined(__INTEL_COMPILER) \
179  && defined(__GNUC__) && __GNUC__ < 5
180 #define ZMQ_CPP11_PARTIAL
181 #elif defined(__GLIBCXX__) && __GLIBCXX__ < 20160805
182 //the date here is the last date of gcc 4.9.4, which
183 // effectively means libstdc++ from gcc 5.5 and higher won't trigger this branch
184 #define ZMQ_CPP11_PARTIAL
185 #endif
186 
187 #ifdef ZMQ_CPP11
188 #ifdef ZMQ_CPP11_PARTIAL
189 #define ZMQ_IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T)
190 #else
191 #include <type_traits>
192 #define ZMQ_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
193 #endif
194 #endif
195 
196 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 3, 0)
197 #define ZMQ_NEW_MONITOR_EVENT_LAYOUT
198 #endif
199 
200 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0)
201 #define ZMQ_HAS_PROXY_STEERABLE
202 /* Socket event data */
203 typedef struct
204 {
205  uint16_t event; // id of the event as bitfield
206  int32_t value; // value is either error code, fd or reconnect interval
207 } zmq_event_t;
208 #endif
209 
210 // Avoid using deprecated message receive function when possible
211 #if ZMQ_VERSION < ZMQ_MAKE_VERSION(3, 2, 0)
212 #define zmq_msg_recv(msg, socket, flags) zmq_recvmsg(socket, msg, flags)
213 #endif
214 
215 
216 // In order to prevent unused variable warnings when building in non-debug
217 // mode use this macro to make assertions.
218 #ifndef NDEBUG
219 #define ZMQ_ASSERT(expression) assert(expression)
220 #else
221 #define ZMQ_ASSERT(expression) (void) (expression)
222 #endif
223 
224 namespace zmq
225 {
226 #ifdef ZMQ_CPP11
227 namespace detail
228 {
229 namespace ranges
230 {
231 using std::begin;
232 using std::end;
233 template<class T> auto begin(T &&r) -> decltype(begin(std::forward<T>(r)))
234 {
235  return begin(std::forward<T>(r));
236 }
237 template<class T> auto end(T &&r) -> decltype(end(std::forward<T>(r)))
238 {
239  return end(std::forward<T>(r));
240 }
241 } // namespace ranges
242 
243 template<class T> using void_t = void;
244 
245 template<class Iter>
246 using iter_value_t = typename std::iterator_traits<Iter>::value_type;
247 
248 template<class Range>
249 using range_iter_t = decltype(
250  ranges::begin(std::declval<typename std::remove_reference<Range>::type &>()));
251 
252 template<class Range> using range_value_t = iter_value_t<range_iter_t<Range>>;
253 
254 template<class T, class = void> struct is_range : std::false_type
255 {
256 };
257 
258 template<class T>
259 struct is_range<
260  T,
261  void_t<decltype(
262  ranges::begin(std::declval<typename std::remove_reference<T>::type &>())
263  == ranges::end(std::declval<typename std::remove_reference<T>::type &>()))>>
264  : std::true_type
265 {
266 };
267 
268 } // namespace detail
269 #endif
270 
271 typedef zmq_free_fn free_fn;
272 typedef zmq_pollitem_t pollitem_t;
273 
274 class error_t : public std::exception
275 {
276  public:
277  error_t() ZMQ_NOTHROW : errnum(zmq_errno()) {}
278  explicit error_t(int err) ZMQ_NOTHROW : errnum(err) {}
279  virtual const char *what() const ZMQ_NOTHROW ZMQ_OVERRIDE
280  {
281  return zmq_strerror(errnum);
282  }
283  int num() const ZMQ_NOTHROW { return errnum; }
284 
285  private:
286  int errnum;
287 };
288 
289 inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_ = -1)
290 {
291  int rc = zmq_poll(items_, static_cast<int>(nitems_), timeout_);
292  if (rc < 0)
293  throw error_t();
294  return rc;
295 }
296 
297 ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
298 inline int poll(zmq_pollitem_t const *items_, size_t nitems_, long timeout_ = -1)
299 {
300  return poll(const_cast<zmq_pollitem_t *>(items_), nitems_, timeout_);
301 }
302 
303 #ifdef ZMQ_CPP11
304 ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
305 inline int
306 poll(zmq_pollitem_t const *items, size_t nitems, std::chrono::milliseconds timeout)
307 {
308  return poll(const_cast<zmq_pollitem_t *>(items), nitems,
309  static_cast<long>(timeout.count()));
310 }
311 
312 ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
313 inline int poll(std::vector<zmq_pollitem_t> const &items,
314  std::chrono::milliseconds timeout)
315 {
316  return poll(const_cast<zmq_pollitem_t *>(items.data()), items.size(),
317  static_cast<long>(timeout.count()));
318 }
319 
320 ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
321 inline int poll(std::vector<zmq_pollitem_t> const &items, long timeout_ = -1)
322 {
323  return poll(const_cast<zmq_pollitem_t *>(items.data()), items.size(), timeout_);
324 }
325 
326 inline int
327 poll(zmq_pollitem_t *items, size_t nitems, std::chrono::milliseconds timeout)
328 {
329  return poll(items, nitems, static_cast<long>(timeout.count()));
330 }
331 
332 inline int poll(std::vector<zmq_pollitem_t> &items,
333  std::chrono::milliseconds timeout)
334 {
335  return poll(items.data(), items.size(), static_cast<long>(timeout.count()));
336 }
337 
338 ZMQ_DEPRECATED("from 4.3.1, use poll taking std::chrono instead of long")
339 inline int poll(std::vector<zmq_pollitem_t> &items, long timeout_ = -1)
340 {
341  return poll(items.data(), items.size(), timeout_);
342 }
343 
344 template<std::size_t SIZE>
345 inline int poll(std::array<zmq_pollitem_t, SIZE> &items,
346  std::chrono::milliseconds timeout)
347 {
348  return poll(items.data(), items.size(), static_cast<long>(timeout.count()));
349 }
350 #endif
351 
352 
353 inline void version(int *major_, int *minor_, int *patch_)
354 {
355  zmq_version(major_, minor_, patch_);
356 }
357 
358 #ifdef ZMQ_CPP11
359 inline std::tuple<int, int, int> version()
360 {
361  std::tuple<int, int, int> v;
362  zmq_version(&std::get<0>(v), &std::get<1>(v), &std::get<2>(v));
363  return v;
364 }
365 
366 #if !defined(ZMQ_CPP11_PARTIAL)
367 namespace detail
368 {
369 template<class T> struct is_char_type
370 {
371  // true if character type for string literals in C++11
372  static constexpr bool value =
373  std::is_same<T, char>::value || std::is_same<T, wchar_t>::value
374  || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value;
375 };
376 }
377 #endif
378 
379 #endif
380 
381 class message_t
382 {
383  public:
385  {
386  int rc = zmq_msg_init(&msg);
387  ZMQ_ASSERT(rc == 0);
388  }
389 
390  explicit message_t(size_t size_)
391  {
392  int rc = zmq_msg_init_size(&msg, size_);
393  if (rc != 0)
394  throw error_t();
395  }
396 
397  template<class ForwardIter> message_t(ForwardIter first, ForwardIter last)
398  {
399  typedef typename std::iterator_traits<ForwardIter>::value_type value_t;
400 
401  assert(std::distance(first, last) >= 0);
402  size_t const size_ =
403  static_cast<size_t>(std::distance(first, last)) * sizeof(value_t);
404  int const rc = zmq_msg_init_size(&msg, size_);
405  if (rc != 0)
406  throw error_t();
407  std::copy(first, last, data<value_t>());
408  }
409 
410  message_t(const void *data_, size_t size_)
411  {
412  int rc = zmq_msg_init_size(&msg, size_);
413  if (rc != 0)
414  throw error_t();
415  if (size_) {
416  // this constructor allows (nullptr, 0),
417  // memcpy with a null pointer is UB
418  memcpy(data(), data_, size_);
419  }
420  }
421 
422  message_t(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR)
423  {
424  int rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_);
425  if (rc != 0)
426  throw error_t();
427  }
428 
429  // overload set of string-like types and generic containers
430 #if defined(ZMQ_CPP11) && !defined(ZMQ_CPP11_PARTIAL)
431  // NOTE this constructor will include the null terminator
432  // when called with a string literal.
433  // An overload taking const char* can not be added because
434  // it would be preferred over this function and break compatiblity.
435  template<
436  class Char,
437  size_t N,
438  typename = typename std::enable_if<detail::is_char_type<Char>::value>::type>
439  ZMQ_DEPRECATED("from 4.7.0, use constructors taking iterators, (pointer, size) "
440  "or strings instead")
441  explicit message_t(const Char (&data)[N]) :
442  message_t(detail::ranges::begin(data), detail::ranges::end(data))
443  {
444  }
445 
446  template<class Range,
447  typename = typename std::enable_if<
448  detail::is_range<Range>::value
449  && ZMQ_IS_TRIVIALLY_COPYABLE(detail::range_value_t<Range>)
450  && !detail::is_char_type<detail::range_value_t<Range>>::value
451  && !std::is_same<Range, message_t>::value>::type>
452  explicit message_t(const Range &rng) :
453  message_t(detail::ranges::begin(rng), detail::ranges::end(rng))
454  {
455  }
456 
457  explicit message_t(const std::string &str) : message_t(str.data(), str.size()) {}
458 
459 #if CPPZMQ_HAS_STRING_VIEW
460  explicit message_t(std::string_view str) : message_t(str.data(), str.size()) {}
461 #endif
462 
463 #endif
464 
465 #ifdef ZMQ_HAS_RVALUE_REFS
466  message_t(message_t &&rhs) ZMQ_NOTHROW : msg(rhs.msg)
467  {
468  int rc = zmq_msg_init(&rhs.msg);
469  ZMQ_ASSERT(rc == 0);
470  }
471 
472  message_t &operator=(message_t &&rhs) ZMQ_NOTHROW
473  {
474  std::swap(msg, rhs.msg);
475  return *this;
476  }
477 #endif
478 
480  {
481  int rc = zmq_msg_close(&msg);
482  ZMQ_ASSERT(rc == 0);
483  }
484 
485  void rebuild()
486  {
487  int rc = zmq_msg_close(&msg);
488  if (rc != 0)
489  throw error_t();
490  rc = zmq_msg_init(&msg);
491  ZMQ_ASSERT(rc == 0);
492  }
493 
494  void rebuild(size_t size_)
495  {
496  int rc = zmq_msg_close(&msg);
497  if (rc != 0)
498  throw error_t();
499  rc = zmq_msg_init_size(&msg, size_);
500  if (rc != 0)
501  throw error_t();
502  }
503 
504  void rebuild(const void *data_, size_t size_)
505  {
506  int rc = zmq_msg_close(&msg);
507  if (rc != 0)
508  throw error_t();
509  rc = zmq_msg_init_size(&msg, size_);
510  if (rc != 0)
511  throw error_t();
512  memcpy(data(), data_, size_);
513  }
514 
515  void rebuild(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR)
516  {
517  int rc = zmq_msg_close(&msg);
518  if (rc != 0)
519  throw error_t();
520  rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_);
521  if (rc != 0)
522  throw error_t();
523  }
524 
525  ZMQ_DEPRECATED("from 4.3.1, use move taking non-const reference instead")
526  void move(message_t const *msg_)
527  {
528  int rc = zmq_msg_move(&msg, const_cast<zmq_msg_t *>(msg_->handle()));
529  if (rc != 0)
530  throw error_t();
531  }
532 
533  void move(message_t &msg_)
534  {
535  int rc = zmq_msg_move(&msg, msg_.handle());
536  if (rc != 0)
537  throw error_t();
538  }
539 
540  ZMQ_DEPRECATED("from 4.3.1, use copy taking non-const reference instead")
541  void copy(message_t const *msg_)
542  {
543  int rc = zmq_msg_copy(&msg, const_cast<zmq_msg_t *>(msg_->handle()));
544  if (rc != 0)
545  throw error_t();
546  }
547 
548  void copy(message_t &msg_)
549  {
550  int rc = zmq_msg_copy(&msg, msg_.handle());
551  if (rc != 0)
552  throw error_t();
553  }
554 
555  bool more() const ZMQ_NOTHROW
556  {
557  int rc = zmq_msg_more(const_cast<zmq_msg_t *>(&msg));
558  return rc != 0;
559  }
560 
561  void *data() ZMQ_NOTHROW { return zmq_msg_data(&msg); }
562 
563  const void *data() const ZMQ_NOTHROW
564  {
565  return zmq_msg_data(const_cast<zmq_msg_t *>(&msg));
566  }
567 
568  size_t size() const ZMQ_NOTHROW
569  {
570  return zmq_msg_size(const_cast<zmq_msg_t *>(&msg));
571  }
572 
573  ZMQ_NODISCARD bool empty() const ZMQ_NOTHROW { return size() == 0u; }
574 
575  template<typename T> T *data() ZMQ_NOTHROW { return static_cast<T *>(data()); }
576 
577  template<typename T> T const *data() const ZMQ_NOTHROW
578  {
579  return static_cast<T const *>(data());
580  }
581 
582  ZMQ_DEPRECATED("from 4.3.0, use operator== instead")
583  bool equal(const message_t *other) const ZMQ_NOTHROW { return *this == *other; }
584 
585  bool operator==(const message_t &other) const ZMQ_NOTHROW
586  {
587  const size_t my_size = size();
588  return my_size == other.size() && 0 == memcmp(data(), other.data(), my_size);
589  }
590 
591  bool operator!=(const message_t &other) const ZMQ_NOTHROW
592  {
593  return !(*this == other);
594  }
595 
596 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 2, 0)
597  int get(int property_)
598  {
599  int value = zmq_msg_get(&msg, property_);
600  if (value == -1)
601  throw error_t();
602  return value;
603  }
604 #endif
605 
606 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0)
607  const char *gets(const char *property_)
608  {
609  const char *value = zmq_msg_gets(&msg, property_);
610  if (value == ZMQ_NULLPTR)
611  throw error_t();
612  return value;
613  }
614 #endif
615 
616 #if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
617  uint32_t routing_id() const
618  {
619  return zmq_msg_routing_id(const_cast<zmq_msg_t *>(&msg));
620  }
621 
622  void set_routing_id(uint32_t routing_id)
623  {
624  int rc = zmq_msg_set_routing_id(&msg, routing_id);
625  if (rc != 0)
626  throw error_t();
627  }
628 
629  const char *group() const
630  {
631  return zmq_msg_group(const_cast<zmq_msg_t *>(&msg));
632  }
633 
634  void set_group(const char *group)
635  {
636  int rc = zmq_msg_set_group(&msg, group);
637  if (rc != 0)
638  throw error_t();
639  }
640 #endif
641 
642  // interpret message content as a string
643  std::string to_string() const
644  {
645  return std::string(static_cast<const char *>(data()), size());
646  }
647 #if CPPZMQ_HAS_STRING_VIEW
648  // interpret message content as a string
649  std::string_view to_string_view() const noexcept
650  {
651  return std::string_view(static_cast<const char *>(data()), size());
652  }
653 #endif
654 
661  std::string str() const
662  {
663  // Partly mutuated from the same method in zmq::multipart_t
664  std::stringstream os;
665 
666  const unsigned char *msg_data = this->data<unsigned char>();
667  unsigned char byte;
668  size_t size = this->size();
669  int is_ascii[2] = {0, 0};
670 
671  os << "zmq::message_t [size " << std::dec << std::setw(3)
672  << std::setfill('0') << size << "] (";
673  // Totally arbitrary
674  if (size >= 1000) {
675  os << "... too big to print)";
676  } else {
677  while (size--) {
678  byte = *msg_data++;
679 
680  is_ascii[1] = (byte >= 32 && byte < 127);
681  if (is_ascii[1] != is_ascii[0])
682  os << " "; // Separate text/non text
683 
684  if (is_ascii[1]) {
685  os << byte;
686  } else {
687  os << std::hex << std::uppercase << std::setw(2)
688  << std::setfill('0') << static_cast<short>(byte);
689  }
690  is_ascii[0] = is_ascii[1];
691  }
692  os << ")";
693  }
694  return os.str();
695  }
696 
698  {
699  // this assumes zmq::msg_t from libzmq is trivially relocatable
700  std::swap(msg, other.msg);
701  }
702 
703  ZMQ_NODISCARD zmq_msg_t *handle() ZMQ_NOTHROW { return &msg; }
704  ZMQ_NODISCARD const zmq_msg_t *handle() const ZMQ_NOTHROW { return &msg; }
705 
706  private:
707  // The underlying message
708  zmq_msg_t msg;
709 
710  // Disable implicit message copying, so that users won't use shared
711  // messages (less efficient) without being aware of the fact.
713  void operator=(const message_t &) ZMQ_DELETED_FUNCTION;
714 };
715 
716 inline void swap(message_t &a, message_t &b) ZMQ_NOTHROW
717 {
718  a.swap(b);
719 }
720 
721 #ifdef ZMQ_CPP11
722 enum class ctxopt
723 {
724 #ifdef ZMQ_BLOCKY
725  blocky = ZMQ_BLOCKY,
726 #endif
727 #ifdef ZMQ_IO_THREADS
728  io_threads = ZMQ_IO_THREADS,
729 #endif
730 #ifdef ZMQ_THREAD_SCHED_POLICY
731  thread_sched_policy = ZMQ_THREAD_SCHED_POLICY,
732 #endif
733 #ifdef ZMQ_THREAD_PRIORITY
734  thread_priority = ZMQ_THREAD_PRIORITY,
735 #endif
736 #ifdef ZMQ_THREAD_AFFINITY_CPU_ADD
737  thread_affinity_cpu_add = ZMQ_THREAD_AFFINITY_CPU_ADD,
738 #endif
739 #ifdef ZMQ_THREAD_AFFINITY_CPU_REMOVE
740  thread_affinity_cpu_remove = ZMQ_THREAD_AFFINITY_CPU_REMOVE,
741 #endif
742 #ifdef ZMQ_THREAD_NAME_PREFIX
743  thread_name_prefix = ZMQ_THREAD_NAME_PREFIX,
744 #endif
745 #ifdef ZMQ_MAX_MSGSZ
746  max_msgsz = ZMQ_MAX_MSGSZ,
747 #endif
748 #ifdef ZMQ_ZERO_COPY_RECV
749  zero_copy_recv = ZMQ_ZERO_COPY_RECV,
750 #endif
751 #ifdef ZMQ_MAX_SOCKETS
752  max_sockets = ZMQ_MAX_SOCKETS,
753 #endif
754 #ifdef ZMQ_SOCKET_LIMIT
755  socket_limit = ZMQ_SOCKET_LIMIT,
756 #endif
757 #ifdef ZMQ_IPV6
758  ipv6 = ZMQ_IPV6,
759 #endif
760 #ifdef ZMQ_MSG_T_SIZE
761  msg_t_size = ZMQ_MSG_T_SIZE
762 #endif
763 };
764 #endif
765 
766 class context_t
767 {
768  public:
770  {
771  ptr = zmq_ctx_new();
772  if (ptr == ZMQ_NULLPTR)
773  throw error_t();
774  }
775 
776 
777  explicit context_t(int io_threads_, int max_sockets_ = ZMQ_MAX_SOCKETS_DFLT)
778  {
779  ptr = zmq_ctx_new();
780  if (ptr == ZMQ_NULLPTR)
781  throw error_t();
782 
783  int rc = zmq_ctx_set(ptr, ZMQ_IO_THREADS, io_threads_);
784  ZMQ_ASSERT(rc == 0);
785 
786  rc = zmq_ctx_set(ptr, ZMQ_MAX_SOCKETS, max_sockets_);
787  ZMQ_ASSERT(rc == 0);
788  }
789 
790 #ifdef ZMQ_HAS_RVALUE_REFS
791  context_t(context_t &&rhs) ZMQ_NOTHROW : ptr(rhs.ptr) { rhs.ptr = ZMQ_NULLPTR; }
792  context_t &operator=(context_t &&rhs) ZMQ_NOTHROW
793  {
794  close();
795  std::swap(ptr, rhs.ptr);
796  return *this;
797  }
798 #endif
799 
800  ~context_t() ZMQ_NOTHROW { close(); }
801 
802  ZMQ_CPP11_DEPRECATED("from 4.7.0, use set taking zmq::ctxopt instead")
803  int setctxopt(int option_, int optval_)
804  {
805  int rc = zmq_ctx_set(ptr, option_, optval_);
806  ZMQ_ASSERT(rc == 0);
807  return rc;
808  }
809 
810  ZMQ_CPP11_DEPRECATED("from 4.7.0, use get taking zmq::ctxopt instead")
811  int getctxopt(int option_) { return zmq_ctx_get(ptr, option_); }
812 
813 #ifdef ZMQ_CPP11
814  void set(ctxopt option, int optval)
815  {
816  int rc = zmq_ctx_set(ptr, static_cast<int>(option), optval);
817  if (rc == -1)
818  throw error_t();
819  }
820 
821  ZMQ_NODISCARD int get(ctxopt option)
822  {
823  int rc = zmq_ctx_get(ptr, static_cast<int>(option));
824  // some options have a default value of -1
825  // which is unfortunate, and may result in errors
826  // that don't make sense
827  if (rc == -1)
828  throw error_t();
829  return rc;
830  }
831 #endif
832 
833  // Terminates context (see also shutdown()).
835  {
836  if (ptr == ZMQ_NULLPTR)
837  return;
838 
839  int rc;
840  do {
841  rc = zmq_ctx_destroy(ptr);
842  } while (rc == -1 && errno == EINTR);
843 
844  ZMQ_ASSERT(rc == 0);
845  ptr = ZMQ_NULLPTR;
846  }
847 
848  // Shutdown context in preparation for termination (close()).
849  // Causes all blocking socket operations and any further
850  // socket operations to return with ETERM.
852  {
853  if (ptr == ZMQ_NULLPTR)
854  return;
855  int rc = zmq_ctx_shutdown(ptr);
856  ZMQ_ASSERT(rc == 0);
857  }
858 
859  // Be careful with this, it's probably only useful for
860  // using the C api together with an existing C++ api.
861  // Normally you should never need to use this.
862  ZMQ_EXPLICIT operator void *() ZMQ_NOTHROW { return ptr; }
863 
864  ZMQ_EXPLICIT operator void const *() const ZMQ_NOTHROW { return ptr; }
865 
866  ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return ptr; }
867 
868  ZMQ_DEPRECATED("from 4.7.0, use handle() != nullptr instead")
869  operator bool() const ZMQ_NOTHROW { return ptr != ZMQ_NULLPTR; }
870 
871  void swap(context_t &other) ZMQ_NOTHROW { std::swap(ptr, other.ptr); }
872 
873  private:
874  void *ptr;
875 
877  void operator=(const context_t &) ZMQ_DELETED_FUNCTION;
878 };
879 
880 inline void swap(context_t &a, context_t &b) ZMQ_NOTHROW
881 {
882  a.swap(b);
883 }
884 
885 #ifdef ZMQ_CPP11
886 
887 struct recv_buffer_size
888 {
889  size_t size; // number of bytes written to buffer
890  size_t untruncated_size; // untruncated message size in bytes
891 
892  ZMQ_NODISCARD bool truncated() const noexcept
893  {
894  return size != untruncated_size;
895  }
896 };
897 
898 #if CPPZMQ_HAS_OPTIONAL
899 
900 using send_result_t = std::optional<size_t>;
901 using recv_result_t = std::optional<size_t>;
902 using recv_buffer_result_t = std::optional<recv_buffer_size>;
903 
904 #else
905 
906 namespace detail
907 {
908 // A C++11 type emulating the most basic
909 // operations of std::optional for trivial types
910 template<class T> class trivial_optional
911 {
912  public:
913  static_assert(std::is_trivial<T>::value, "T must be trivial");
914  using value_type = T;
915 
916  trivial_optional() = default;
917  trivial_optional(T value) noexcept : _value(value), _has_value(true) {}
918 
919  const T *operator->() const noexcept
920  {
921  assert(_has_value);
922  return &_value;
923  }
924  T *operator->() noexcept
925  {
926  assert(_has_value);
927  return &_value;
928  }
929 
930  const T &operator*() const noexcept
931  {
932  assert(_has_value);
933  return _value;
934  }
935  T &operator*() noexcept
936  {
937  assert(_has_value);
938  return _value;
939  }
940 
941  T &value()
942  {
943  if (!_has_value)
944  throw std::exception();
945  return _value;
946  }
947  const T &value() const
948  {
949  if (!_has_value)
950  throw std::exception();
951  return _value;
952  }
953 
954  explicit operator bool() const noexcept { return _has_value; }
955  bool has_value() const noexcept { return _has_value; }
956 
957  private:
958  T _value{};
959  bool _has_value{false};
960 };
961 } // namespace detail
962 
963 using send_result_t = detail::trivial_optional<size_t>;
964 using recv_result_t = detail::trivial_optional<size_t>;
965 using recv_buffer_result_t = detail::trivial_optional<recv_buffer_size>;
966 
967 #endif
968 
969 namespace detail
970 {
971 template<class T> constexpr T enum_bit_or(T a, T b) noexcept
972 {
973  static_assert(std::is_enum<T>::value, "must be enum");
974  using U = typename std::underlying_type<T>::type;
975  return static_cast<T>(static_cast<U>(a) | static_cast<U>(b));
976 }
977 template<class T> constexpr T enum_bit_and(T a, T b) noexcept
978 {
979  static_assert(std::is_enum<T>::value, "must be enum");
980  using U = typename std::underlying_type<T>::type;
981  return static_cast<T>(static_cast<U>(a) & static_cast<U>(b));
982 }
983 template<class T> constexpr T enum_bit_xor(T a, T b) noexcept
984 {
985  static_assert(std::is_enum<T>::value, "must be enum");
986  using U = typename std::underlying_type<T>::type;
987  return static_cast<T>(static_cast<U>(a) ^ static_cast<U>(b));
988 }
989 template<class T> constexpr T enum_bit_not(T a) noexcept
990 {
991  static_assert(std::is_enum<T>::value, "must be enum");
992  using U = typename std::underlying_type<T>::type;
993  return static_cast<T>(~static_cast<U>(a));
994 }
995 } // namespace detail
996 
997 // partially satisfies named requirement BitmaskType
998 enum class send_flags : int
999 {
1000  none = 0,
1001  dontwait = ZMQ_DONTWAIT,
1002  sndmore = ZMQ_SNDMORE
1003 };
1004 
1005 constexpr send_flags operator|(send_flags a, send_flags b) noexcept
1006 {
1007  return detail::enum_bit_or(a, b);
1008 }
1009 constexpr send_flags operator&(send_flags a, send_flags b) noexcept
1010 {
1011  return detail::enum_bit_and(a, b);
1012 }
1013 constexpr send_flags operator^(send_flags a, send_flags b) noexcept
1014 {
1015  return detail::enum_bit_xor(a, b);
1016 }
1017 constexpr send_flags operator~(send_flags a) noexcept
1018 {
1019  return detail::enum_bit_not(a);
1020 }
1021 
1022 // partially satisfies named requirement BitmaskType
1023 enum class recv_flags : int
1024 {
1025  none = 0,
1026  dontwait = ZMQ_DONTWAIT
1027 };
1028 
1029 constexpr recv_flags operator|(recv_flags a, recv_flags b) noexcept
1030 {
1031  return detail::enum_bit_or(a, b);
1032 }
1033 constexpr recv_flags operator&(recv_flags a, recv_flags b) noexcept
1034 {
1035  return detail::enum_bit_and(a, b);
1036 }
1037 constexpr recv_flags operator^(recv_flags a, recv_flags b) noexcept
1038 {
1039  return detail::enum_bit_xor(a, b);
1040 }
1041 constexpr recv_flags operator~(recv_flags a) noexcept
1042 {
1043  return detail::enum_bit_not(a);
1044 }
1045 
1046 
1047 // mutable_buffer, const_buffer and buffer are based on
1048 // the Networking TS specification, draft:
1049 // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4771.pdf
1050 
1051 class mutable_buffer
1052 {
1053  public:
1054  constexpr mutable_buffer() noexcept : _data(nullptr), _size(0) {}
1055  constexpr mutable_buffer(void *p, size_t n) noexcept : _data(p), _size(n)
1056  {
1057 #ifdef ZMQ_EXTENDED_CONSTEXPR
1058  assert(p != nullptr || n == 0);
1059 #endif
1060  }
1061 
1062  constexpr void *data() const noexcept { return _data; }
1063  constexpr size_t size() const noexcept { return _size; }
1064  mutable_buffer &operator+=(size_t n) noexcept
1065  {
1066  // (std::min) is a workaround for when a min macro is defined
1067  const auto shift = (std::min)(n, _size);
1068  _data = static_cast<char *>(_data) + shift;
1069  _size -= shift;
1070  return *this;
1071  }
1072 
1073  private:
1074  void *_data;
1075  size_t _size;
1076 };
1077 
1078 inline mutable_buffer operator+(const mutable_buffer &mb, size_t n) noexcept
1079 {
1080  return mutable_buffer(static_cast<char *>(mb.data()) + (std::min)(n, mb.size()),
1081  mb.size() - (std::min)(n, mb.size()));
1082 }
1083 inline mutable_buffer operator+(size_t n, const mutable_buffer &mb) noexcept
1084 {
1085  return mb + n;
1086 }
1087 
1088 class const_buffer
1089 {
1090  public:
1091  constexpr const_buffer() noexcept : _data(nullptr), _size(0) {}
1092  constexpr const_buffer(const void *p, size_t n) noexcept : _data(p), _size(n)
1093  {
1094 #ifdef ZMQ_EXTENDED_CONSTEXPR
1095  assert(p != nullptr || n == 0);
1096 #endif
1097  }
1098  constexpr const_buffer(const mutable_buffer &mb) noexcept :
1099  _data(mb.data()),
1100  _size(mb.size())
1101  {
1102  }
1103 
1104  constexpr const void *data() const noexcept { return _data; }
1105  constexpr size_t size() const noexcept { return _size; }
1106  const_buffer &operator+=(size_t n) noexcept
1107  {
1108  const auto shift = (std::min)(n, _size);
1109  _data = static_cast<const char *>(_data) + shift;
1110  _size -= shift;
1111  return *this;
1112  }
1113 
1114  private:
1115  const void *_data;
1116  size_t _size;
1117 };
1118 
1119 inline const_buffer operator+(const const_buffer &cb, size_t n) noexcept
1120 {
1121  return const_buffer(static_cast<const char *>(cb.data())
1122  + (std::min)(n, cb.size()),
1123  cb.size() - (std::min)(n, cb.size()));
1124 }
1125 inline const_buffer operator+(size_t n, const const_buffer &cb) noexcept
1126 {
1127  return cb + n;
1128 }
1129 
1130 // buffer creation
1131 
1132 constexpr mutable_buffer buffer(void *p, size_t n) noexcept
1133 {
1134  return mutable_buffer(p, n);
1135 }
1136 constexpr const_buffer buffer(const void *p, size_t n) noexcept
1137 {
1138  return const_buffer(p, n);
1139 }
1140 constexpr mutable_buffer buffer(const mutable_buffer &mb) noexcept
1141 {
1142  return mb;
1143 }
1144 inline mutable_buffer buffer(const mutable_buffer &mb, size_t n) noexcept
1145 {
1146  return mutable_buffer(mb.data(), (std::min)(mb.size(), n));
1147 }
1148 constexpr const_buffer buffer(const const_buffer &cb) noexcept
1149 {
1150  return cb;
1151 }
1152 inline const_buffer buffer(const const_buffer &cb, size_t n) noexcept
1153 {
1154  return const_buffer(cb.data(), (std::min)(cb.size(), n));
1155 }
1156 
1157 namespace detail
1158 {
1159 template<class T> struct is_buffer
1160 {
1161  static constexpr bool value =
1162  std::is_same<T, const_buffer>::value || std::is_same<T, mutable_buffer>::value;
1163 };
1164 
1165 template<class T> struct is_pod_like
1166 {
1167  // NOTE: The networking draft N4771 section 16.11 requires
1168  // T in the buffer functions below to be
1169  // trivially copyable OR standard layout.
1170  // Here we decide to be conservative and require both.
1171  static constexpr bool value =
1172  ZMQ_IS_TRIVIALLY_COPYABLE(T) && std::is_standard_layout<T>::value;
1173 };
1174 
1175 template<class C> constexpr auto seq_size(const C &c) noexcept -> decltype(c.size())
1176 {
1177  return c.size();
1178 }
1179 template<class T, size_t N>
1180 constexpr size_t seq_size(const T (&/*array*/)[N]) noexcept
1181 {
1182  return N;
1183 }
1184 
1185 template<class Seq>
1186 auto buffer_contiguous_sequence(Seq &&seq) noexcept
1187  -> decltype(buffer(std::addressof(*std::begin(seq)), size_t{}))
1188 {
1189  using T = typename std::remove_cv<
1190  typename std::remove_reference<decltype(*std::begin(seq))>::type>::type;
1191  static_assert(detail::is_pod_like<T>::value, "T must be POD");
1192 
1193  const auto size = seq_size(seq);
1194  return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr,
1195  size * sizeof(T));
1196 }
1197 template<class Seq>
1198 auto buffer_contiguous_sequence(Seq &&seq, size_t n_bytes) noexcept
1199  -> decltype(buffer_contiguous_sequence(seq))
1200 {
1201  using T = typename std::remove_cv<
1202  typename std::remove_reference<decltype(*std::begin(seq))>::type>::type;
1203  static_assert(detail::is_pod_like<T>::value, "T must be POD");
1204 
1205  const auto size = seq_size(seq);
1206  return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr,
1207  (std::min)(size * sizeof(T), n_bytes));
1208 }
1209 
1210 } // namespace detail
1211 
1212 // C array
1213 template<class T, size_t N> mutable_buffer buffer(T (&data)[N]) noexcept
1214 {
1215  return detail::buffer_contiguous_sequence(data);
1216 }
1217 template<class T, size_t N>
1218 mutable_buffer buffer(T (&data)[N], size_t n_bytes) noexcept
1219 {
1220  return detail::buffer_contiguous_sequence(data, n_bytes);
1221 }
1222 template<class T, size_t N> const_buffer buffer(const T (&data)[N]) noexcept
1223 {
1224  return detail::buffer_contiguous_sequence(data);
1225 }
1226 template<class T, size_t N>
1227 const_buffer buffer(const T (&data)[N], size_t n_bytes) noexcept
1228 {
1229  return detail::buffer_contiguous_sequence(data, n_bytes);
1230 }
1231 // std::array
1232 template<class T, size_t N> mutable_buffer buffer(std::array<T, N> &data) noexcept
1233 {
1234  return detail::buffer_contiguous_sequence(data);
1235 }
1236 template<class T, size_t N>
1237 mutable_buffer buffer(std::array<T, N> &data, size_t n_bytes) noexcept
1238 {
1239  return detail::buffer_contiguous_sequence(data, n_bytes);
1240 }
1241 template<class T, size_t N>
1242 const_buffer buffer(std::array<const T, N> &data) noexcept
1243 {
1244  return detail::buffer_contiguous_sequence(data);
1245 }
1246 template<class T, size_t N>
1247 const_buffer buffer(std::array<const T, N> &data, size_t n_bytes) noexcept
1248 {
1249  return detail::buffer_contiguous_sequence(data, n_bytes);
1250 }
1251 template<class T, size_t N>
1252 const_buffer buffer(const std::array<T, N> &data) noexcept
1253 {
1254  return detail::buffer_contiguous_sequence(data);
1255 }
1256 template<class T, size_t N>
1257 const_buffer buffer(const std::array<T, N> &data, size_t n_bytes) noexcept
1258 {
1259  return detail::buffer_contiguous_sequence(data, n_bytes);
1260 }
1261 // std::vector
1262 template<class T, class Allocator>
1263 mutable_buffer buffer(std::vector<T, Allocator> &data) noexcept
1264 {
1265  return detail::buffer_contiguous_sequence(data);
1266 }
1267 template<class T, class Allocator>
1268 mutable_buffer buffer(std::vector<T, Allocator> &data, size_t n_bytes) noexcept
1269 {
1270  return detail::buffer_contiguous_sequence(data, n_bytes);
1271 }
1272 template<class T, class Allocator>
1273 const_buffer buffer(const std::vector<T, Allocator> &data) noexcept
1274 {
1275  return detail::buffer_contiguous_sequence(data);
1276 }
1277 template<class T, class Allocator>
1278 const_buffer buffer(const std::vector<T, Allocator> &data, size_t n_bytes) noexcept
1279 {
1280  return detail::buffer_contiguous_sequence(data, n_bytes);
1281 }
1282 // std::basic_string
1283 template<class T, class Traits, class Allocator>
1284 mutable_buffer buffer(std::basic_string<T, Traits, Allocator> &data) noexcept
1285 {
1286  return detail::buffer_contiguous_sequence(data);
1287 }
1288 template<class T, class Traits, class Allocator>
1289 mutable_buffer buffer(std::basic_string<T, Traits, Allocator> &data,
1290  size_t n_bytes) noexcept
1291 {
1292  return detail::buffer_contiguous_sequence(data, n_bytes);
1293 }
1294 template<class T, class Traits, class Allocator>
1295 const_buffer buffer(const std::basic_string<T, Traits, Allocator> &data) noexcept
1296 {
1297  return detail::buffer_contiguous_sequence(data);
1298 }
1299 template<class T, class Traits, class Allocator>
1300 const_buffer buffer(const std::basic_string<T, Traits, Allocator> &data,
1301  size_t n_bytes) noexcept
1302 {
1303  return detail::buffer_contiguous_sequence(data, n_bytes);
1304 }
1305 
1306 #if CPPZMQ_HAS_STRING_VIEW
1307 // std::basic_string_view
1308 template<class T, class Traits>
1309 const_buffer buffer(std::basic_string_view<T, Traits> data) noexcept
1310 {
1311  return detail::buffer_contiguous_sequence(data);
1312 }
1313 template<class T, class Traits>
1314 const_buffer buffer(std::basic_string_view<T, Traits> data, size_t n_bytes) noexcept
1315 {
1316  return detail::buffer_contiguous_sequence(data, n_bytes);
1317 }
1318 #endif
1319 
1320 // Buffer for a string literal (null terminated)
1321 // where the buffer size excludes the terminating character.
1322 // Equivalent to zmq::buffer(std::string_view("...")).
1323 template<class Char, size_t N>
1324 constexpr const_buffer str_buffer(const Char (&data)[N]) noexcept
1325 {
1326  static_assert(detail::is_pod_like<Char>::value, "Char must be POD");
1327 #ifdef ZMQ_EXTENDED_CONSTEXPR
1328  assert(data[N - 1] == Char{0});
1329 #endif
1330  return const_buffer(static_cast<const Char *>(data), (N - 1) * sizeof(Char));
1331 }
1332 
1333 namespace literals
1334 {
1335 constexpr const_buffer operator"" _zbuf(const char *str, size_t len) noexcept
1336 {
1337  return const_buffer(str, len * sizeof(char));
1338 }
1339 constexpr const_buffer operator"" _zbuf(const wchar_t *str, size_t len) noexcept
1340 {
1341  return const_buffer(str, len * sizeof(wchar_t));
1342 }
1343 constexpr const_buffer operator"" _zbuf(const char16_t *str, size_t len) noexcept
1344 {
1345  return const_buffer(str, len * sizeof(char16_t));
1346 }
1347 constexpr const_buffer operator"" _zbuf(const char32_t *str, size_t len) noexcept
1348 {
1349  return const_buffer(str, len * sizeof(char32_t));
1350 }
1351 }
1352 
1353 #endif // ZMQ_CPP11
1354 
1355 
1356 #ifdef ZMQ_CPP11
1357 namespace sockopt
1358 {
1359 // There are two types of options,
1360 // integral type with known compiler time size (int, bool, int64_t, uint64_t)
1361 // and arrays with dynamic size (strings, binary data).
1362 
1363 // BoolUnit: if true accepts values of type bool (but passed as T into libzmq)
1364 template<int Opt, class T, bool BoolUnit = false> struct integral_option
1365 {
1366 };
1367 
1368 // NullTerm:
1369 // 0: binary data
1370 // 1: null-terminated string (`getsockopt` size includes null)
1371 // 2: binary (size 32) or Z85 encoder string of size 41 (null included)
1372 template<int Opt, int NullTerm = 1> struct array_option
1373 {
1374 };
1375 
1376 #define ZMQ_DEFINE_INTEGRAL_OPT(OPT, NAME, TYPE) \
1377  using NAME##_t = integral_option<OPT, TYPE, false>; \
1378  ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1379 #define ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(OPT, NAME, TYPE) \
1380  using NAME##_t = integral_option<OPT, TYPE, true>; \
1381  ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1382 #define ZMQ_DEFINE_ARRAY_OPT(OPT, NAME) \
1383  using NAME##_t = array_option<OPT>; \
1384  ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1385 #define ZMQ_DEFINE_ARRAY_OPT_BINARY(OPT, NAME) \
1386  using NAME##_t = array_option<OPT, 0>; \
1387  ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1388 #define ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(OPT, NAME) \
1389  using NAME##_t = array_option<OPT, 2>; \
1390  ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1391 
1392 // duplicate definition from libzmq 4.3.3
1393 #if defined _WIN32
1394 #if defined _WIN64
1395 typedef unsigned __int64 cppzmq_fd_t;
1396 #else
1397 typedef unsigned int cppzmq_fd_t;
1398 #endif
1399 #else
1400 typedef int cppzmq_fd_t;
1401 #endif
1402 
1403 #ifdef ZMQ_AFFINITY
1404 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_AFFINITY, affinity, uint64_t);
1405 #endif
1406 #ifdef ZMQ_BACKLOG
1407 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_BACKLOG, backlog, int);
1408 #endif
1409 #ifdef ZMQ_BINDTODEVICE
1410 ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_BINDTODEVICE, bindtodevice);
1411 #endif
1412 #ifdef ZMQ_CONFLATE
1413 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CONFLATE, conflate, int);
1414 #endif
1415 #ifdef ZMQ_CONNECT_ROUTING_ID
1416 ZMQ_DEFINE_ARRAY_OPT(ZMQ_CONNECT_ROUTING_ID, connect_routing_id);
1417 #endif
1418 #ifdef ZMQ_CONNECT_TIMEOUT
1419 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_CONNECT_TIMEOUT, connect_timeout, int);
1420 #endif
1421 #ifdef ZMQ_CURVE_PUBLICKEY
1422 ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_PUBLICKEY, curve_publickey);
1423 #endif
1424 #ifdef ZMQ_CURVE_SECRETKEY
1425 ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SECRETKEY, curve_secretkey);
1426 #endif
1427 #ifdef ZMQ_CURVE_SERVER
1428 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CURVE_SERVER, curve_server, int);
1429 #endif
1430 #ifdef ZMQ_CURVE_SERVERKEY
1431 ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SERVERKEY, curve_serverkey);
1432 #endif
1433 #ifdef ZMQ_EVENTS
1434 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_EVENTS, events, int);
1435 #endif
1436 #ifdef ZMQ_FD
1437 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_FD, fd, cppzmq_fd_t);
1438 #endif
1439 #ifdef ZMQ_GSSAPI_PLAINTEXT
1440 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_PLAINTEXT, gssapi_plaintext, int);
1441 #endif
1442 #ifdef ZMQ_GSSAPI_SERVER
1443 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_SERVER, gssapi_server, int);
1444 #endif
1445 #ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL
1446 ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL, gssapi_service_principal);
1447 #endif
1448 #ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE
1449 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE,
1450  gssapi_service_principal_nametype,
1451  int);
1452 #endif
1453 #ifdef ZMQ_GSSAPI_PRINCIPAL
1454 ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_PRINCIPAL, gssapi_principal);
1455 #endif
1456 #ifdef ZMQ_GSSAPI_PRINCIPAL_NAMETYPE
1457 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_PRINCIPAL_NAMETYPE,
1458  gssapi_principal_nametype,
1459  int);
1460 #endif
1461 #ifdef ZMQ_HANDSHAKE_IVL
1462 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HANDSHAKE_IVL, handshake_ivl, int);
1463 #endif
1464 #ifdef ZMQ_HEARTBEAT_IVL
1465 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_IVL, heartbeat_ivl, int);
1466 #endif
1467 #ifdef ZMQ_HEARTBEAT_TIMEOUT
1468 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TIMEOUT, heartbeat_timeout, int);
1469 #endif
1470 #ifdef ZMQ_HEARTBEAT_TTL
1471 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TTL, heartbeat_ttl, int);
1472 #endif
1473 #ifdef ZMQ_IMMEDIATE
1474 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IMMEDIATE, immediate, int);
1475 #endif
1476 #ifdef ZMQ_INVERT_MATCHING
1477 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_INVERT_MATCHING, invert_matching, int);
1478 #endif
1479 #ifdef ZMQ_IPV6
1480 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IPV6, ipv6, int);
1481 #endif
1482 #ifdef ZMQ_LAST_ENDPOINT
1483 ZMQ_DEFINE_ARRAY_OPT(ZMQ_LAST_ENDPOINT, last_endpoint);
1484 #endif
1485 #ifdef ZMQ_LINGER
1486 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_LINGER, linger, int);
1487 #endif
1488 #ifdef ZMQ_MAXMSGSIZE
1489 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MAXMSGSIZE, maxmsgsize, int64_t);
1490 #endif
1491 #ifdef ZMQ_MECHANISM
1492 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MECHANISM, mechanism, int);
1493 #endif
1494 #ifdef ZMQ_METADATA
1495 ZMQ_DEFINE_ARRAY_OPT(ZMQ_METADATA, metadata);
1496 #endif
1497 #ifdef ZMQ_MULTICAST_HOPS
1498 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_HOPS, multicast_hops, int);
1499 #endif
1500 #ifdef ZMQ_MULTICAST_LOOP
1501 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_MULTICAST_LOOP, multicast_loop, int);
1502 #endif
1503 #ifdef ZMQ_MULTICAST_MAXTPDU
1504 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_MAXTPDU, multicast_maxtpdu, int);
1505 #endif
1506 #ifdef ZMQ_PLAIN_SERVER
1507 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PLAIN_SERVER, plain_server, int);
1508 #endif
1509 #ifdef ZMQ_PLAIN_PASSWORD
1510 ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_PASSWORD, plain_password);
1511 #endif
1512 #ifdef ZMQ_PLAIN_USERNAME
1513 ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_USERNAME, plain_username);
1514 #endif
1515 #ifdef ZMQ_USE_FD
1516 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_USE_FD, use_fd, int);
1517 #endif
1518 #ifdef ZMQ_PROBE_ROUTER
1519 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PROBE_ROUTER, probe_router, int);
1520 #endif
1521 #ifdef ZMQ_RATE
1522 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RATE, rate, int);
1523 #endif
1524 #ifdef ZMQ_RCVBUF
1525 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVBUF, rcvbuf, int);
1526 #endif
1527 #ifdef ZMQ_RCVHWM
1528 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVHWM, rcvhwm, int);
1529 #endif
1530 #ifdef ZMQ_RCVMORE
1531 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_RCVMORE, rcvmore, int);
1532 #endif
1533 #ifdef ZMQ_RCVTIMEO
1534 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVTIMEO, rcvtimeo, int);
1535 #endif
1536 #ifdef ZMQ_RECONNECT_IVL
1537 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL, reconnect_ivl, int);
1538 #endif
1539 #ifdef ZMQ_RECONNECT_IVL_MAX
1540 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL_MAX, reconnect_ivl_max, int);
1541 #endif
1542 #ifdef ZMQ_RECOVERY_IVL
1543 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECOVERY_IVL, recovery_ivl, int);
1544 #endif
1545 #ifdef ZMQ_REQ_CORRELATE
1546 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_CORRELATE, req_correlate, int);
1547 #endif
1548 #ifdef ZMQ_REQ_RELAXED
1549 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_RELAXED, req_relaxed, int);
1550 #endif
1551 #ifdef ZMQ_ROUTER_HANDOVER
1552 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_HANDOVER, router_handover, int);
1553 #endif
1554 #ifdef ZMQ_ROUTER_MANDATORY
1555 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_MANDATORY, router_mandatory, int);
1556 #endif
1557 #ifdef ZMQ_ROUTER_NOTIFY
1558 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_ROUTER_NOTIFY, router_notify, int);
1559 #endif
1560 #ifdef ZMQ_ROUTING_ID
1561 ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_ROUTING_ID, routing_id);
1562 #endif
1563 #ifdef ZMQ_SNDBUF
1564 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDBUF, sndbuf, int);
1565 #endif
1566 #ifdef ZMQ_SNDHWM
1567 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDHWM, sndhwm, int);
1568 #endif
1569 #ifdef ZMQ_SNDTIMEO
1570 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDTIMEO, sndtimeo, int);
1571 #endif
1572 #ifdef ZMQ_SOCKS_PROXY
1573 ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PROXY, socks_proxy);
1574 #endif
1575 #ifdef ZMQ_STREAM_NOTIFY
1576 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_STREAM_NOTIFY, stream_notify, int);
1577 #endif
1578 #ifdef ZMQ_SUBSCRIBE
1579 ZMQ_DEFINE_ARRAY_OPT(ZMQ_SUBSCRIBE, subscribe);
1580 #endif
1581 #ifdef ZMQ_TCP_KEEPALIVE
1582 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE, tcp_keepalive, int);
1583 #endif
1584 #ifdef ZMQ_TCP_KEEPALIVE_CNT
1585 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_CNT, tcp_keepalive_cnt, int);
1586 #endif
1587 #ifdef ZMQ_TCP_KEEPALIVE_IDLE
1588 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_IDLE, tcp_keepalive_idle, int);
1589 #endif
1590 #ifdef ZMQ_TCP_KEEPALIVE_INTVL
1591 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_INTVL, tcp_keepalive_intvl, int);
1592 #endif
1593 #ifdef ZMQ_TCP_MAXRT
1594 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_MAXRT, tcp_maxrt, int);
1595 #endif
1596 #ifdef ZMQ_THREAD_SAFE
1597 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_THREAD_SAFE, thread_safe, int);
1598 #endif
1599 #ifdef ZMQ_TOS
1600 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TOS, tos, int);
1601 #endif
1602 #ifdef ZMQ_TYPE
1603 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, type, int);
1604 #endif
1605 #ifdef ZMQ_UNSUBSCRIBE
1606 ZMQ_DEFINE_ARRAY_OPT(ZMQ_UNSUBSCRIBE, unsubscribe);
1607 #endif
1608 #ifdef ZMQ_VMCI_BUFFER_SIZE
1609 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_SIZE, vmci_buffer_size, uint64_t);
1610 #endif
1611 #ifdef ZMQ_VMCI_BUFFER_MIN_SIZE
1612 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MIN_SIZE, vmci_buffer_min_size, uint64_t);
1613 #endif
1614 #ifdef ZMQ_VMCI_BUFFER_MAX_SIZE
1615 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MAX_SIZE, vmci_buffer_max_size, uint64_t);
1616 #endif
1617 #ifdef ZMQ_VMCI_CONNECT_TIMEOUT
1618 ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_CONNECT_TIMEOUT, vmci_connect_timeout, int);
1619 #endif
1620 #ifdef ZMQ_XPUB_VERBOSE
1621 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSE, xpub_verbose, int);
1622 #endif
1623 #ifdef ZMQ_XPUB_VERBOSER
1624 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSER, xpub_verboser, int);
1625 #endif
1626 #ifdef ZMQ_XPUB_MANUAL
1627 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL, xpub_manual, int);
1628 #endif
1629 #ifdef ZMQ_XPUB_NODROP
1630 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_NODROP, xpub_nodrop, int);
1631 #endif
1632 #ifdef ZMQ_XPUB_WELCOME_MSG
1633 ZMQ_DEFINE_ARRAY_OPT(ZMQ_XPUB_WELCOME_MSG, xpub_welcome_msg);
1634 #endif
1635 #ifdef ZMQ_ZAP_ENFORCE_DOMAIN
1636 ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ZAP_ENFORCE_DOMAIN, zap_enforce_domain, int);
1637 #endif
1638 #ifdef ZMQ_ZAP_DOMAIN
1639 ZMQ_DEFINE_ARRAY_OPT(ZMQ_ZAP_DOMAIN, zap_domain);
1640 #endif
1641 
1642 } // namespace sockopt
1643 #endif // ZMQ_CPP11
1644 
1645 
1646 namespace detail
1647 {
1648 class socket_base
1649 {
1650  public:
1652  ZMQ_EXPLICIT socket_base(void *handle) ZMQ_NOTHROW : _handle(handle) {}
1653 
1654  template<typename T>
1655  ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt")
1656  void setsockopt(int option_, T const &optval)
1657  {
1658  setsockopt(option_, &optval, sizeof(T));
1659  }
1660 
1661  ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt")
1662  void setsockopt(int option_, const void *optval_, size_t optvallen_)
1663  {
1664  int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_);
1665  if (rc != 0)
1666  throw error_t();
1667  }
1668 
1669  ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt")
1670  void getsockopt(int option_, void *optval_, size_t *optvallen_) const
1671  {
1672  int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_);
1673  if (rc != 0)
1674  throw error_t();
1675  }
1676 
1677  template<typename T>
1678  ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt")
1679  T getsockopt(int option_) const
1680  {
1681  T optval;
1682  size_t optlen = sizeof(T);
1683  getsockopt(option_, &optval, &optlen);
1684  return optval;
1685  }
1686 
1687 #ifdef ZMQ_CPP11
1688  // Set integral socket option, e.g.
1689  // `socket.set(zmq::sockopt::linger, 0)`
1690  template<int Opt, class T, bool BoolUnit>
1691  void set(sockopt::integral_option<Opt, T, BoolUnit>, const T &val)
1692  {
1693  static_assert(std::is_integral<T>::value, "T must be integral");
1694  set_option(Opt, &val, sizeof val);
1695  }
1696 
1697  // Set integral socket option from boolean, e.g.
1698  // `socket.set(zmq::sockopt::immediate, false)`
1699  template<int Opt, class T>
1700  void set(sockopt::integral_option<Opt, T, true>, bool val)
1701  {
1702  static_assert(std::is_integral<T>::value, "T must be integral");
1703  T rep_val = val;
1704  set_option(Opt, &rep_val, sizeof rep_val);
1705  }
1706 
1707  // Set array socket option, e.g.
1708  // `socket.set(zmq::sockopt::plain_username, "foo123")`
1709  template<int Opt, int NullTerm>
1710  void set(sockopt::array_option<Opt, NullTerm>, const char *buf)
1711  {
1712  set_option(Opt, buf, std::strlen(buf));
1713  }
1714 
1715  // Set array socket option, e.g.
1716  // `socket.set(zmq::sockopt::routing_id, zmq::buffer(id))`
1717  template<int Opt, int NullTerm>
1718  void set(sockopt::array_option<Opt, NullTerm>, const_buffer buf)
1719  {
1720  set_option(Opt, buf.data(), buf.size());
1721  }
1722 
1723  // Set array socket option, e.g.
1724  // `socket.set(zmq::sockopt::routing_id, id_str)`
1725  template<int Opt, int NullTerm>
1726  void set(sockopt::array_option<Opt, NullTerm>, const std::string &buf)
1727  {
1728  set_option(Opt, buf.data(), buf.size());
1729  }
1730 
1731 #if CPPZMQ_HAS_STRING_VIEW
1732  // Set array socket option, e.g.
1733  // `socket.set(zmq::sockopt::routing_id, id_str)`
1734  template<int Opt, int NullTerm>
1735  void set(sockopt::array_option<Opt, NullTerm>, std::string_view buf)
1736  {
1737  set_option(Opt, buf.data(), buf.size());
1738  }
1739 #endif
1740 
1741  // Get scalar socket option, e.g.
1742  // `auto opt = socket.get(zmq::sockopt::linger)`
1743  template<int Opt, class T, bool BoolUnit>
1744  ZMQ_NODISCARD T get(sockopt::integral_option<Opt, T, BoolUnit>) const
1745  {
1746  static_assert(std::is_integral<T>::value, "T must be integral");
1747  T val;
1748  size_t size = sizeof val;
1749  get_option(Opt, &val, &size);
1750  assert(size == sizeof val);
1751  return val;
1752  }
1753 
1754  // Get array socket option, writes to buf, returns option size in bytes, e.g.
1755  // `size_t optsize = socket.get(zmq::sockopt::routing_id, zmq::buffer(id))`
1756  template<int Opt, int NullTerm>
1757  ZMQ_NODISCARD size_t get(sockopt::array_option<Opt, NullTerm>,
1758  mutable_buffer buf) const
1759  {
1760  size_t size = buf.size();
1761  get_option(Opt, buf.data(), &size);
1762  return size;
1763  }
1764 
1765  // Get array socket option as string (initializes the string buffer size to init_size) e.g.
1766  // `auto s = socket.get(zmq::sockopt::routing_id)`
1767  // Note: removes the null character from null-terminated string options,
1768  // i.e. the string size excludes the null character.
1769  template<int Opt, int NullTerm>
1770  ZMQ_NODISCARD std::string get(sockopt::array_option<Opt, NullTerm>,
1771  size_t init_size = 1024) const
1772  {
1773  if (NullTerm == 2 && init_size == 1024) {
1774  init_size = 41; // get as Z85 string
1775  }
1776  std::string str(init_size, '\0');
1777  size_t size = get(sockopt::array_option<Opt>{}, buffer(str));
1778  if (NullTerm == 1) {
1779  if (size > 0) {
1780  assert(str[size - 1] == '\0');
1781  --size;
1782  }
1783  } else if (NullTerm == 2) {
1784  assert(size == 32 || size == 41);
1785  if (size == 41) {
1786  assert(str[size - 1] == '\0');
1787  --size;
1788  }
1789  }
1790  str.resize(size);
1791  return str;
1792  }
1793 #endif
1794 
1795  void bind(std::string const &addr) { bind(addr.c_str()); }
1796 
1797  void bind(const char *addr_)
1798  {
1799  int rc = zmq_bind(_handle, addr_);
1800  if (rc != 0)
1801  throw error_t();
1802  }
1803 
1804  void unbind(std::string const &addr) { unbind(addr.c_str()); }
1805 
1806  void unbind(const char *addr_)
1807  {
1808  int rc = zmq_unbind(_handle, addr_);
1809  if (rc != 0)
1810  throw error_t();
1811  }
1812 
1813  void connect(std::string const &addr) { connect(addr.c_str()); }
1814 
1815  void connect(const char *addr_)
1816  {
1817  int rc = zmq_connect(_handle, addr_);
1818  if (rc != 0)
1819  throw error_t();
1820  }
1821 
1822  void disconnect(std::string const &addr) { disconnect(addr.c_str()); }
1823 
1824  void disconnect(const char *addr_)
1825  {
1826  int rc = zmq_disconnect(_handle, addr_);
1827  if (rc != 0)
1828  throw error_t();
1829  }
1830 
1831  bool connected() const ZMQ_NOTHROW { return (_handle != ZMQ_NULLPTR); }
1832 
1833  ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking a const_buffer and send_flags")
1834  size_t send(const void *buf_, size_t len_, int flags_ = 0)
1835  {
1836  int nbytes = zmq_send(_handle, buf_, len_, flags_);
1837  if (nbytes >= 0)
1838  return static_cast<size_t>(nbytes);
1839  if (zmq_errno() == EAGAIN)
1840  return 0;
1841  throw error_t();
1842  }
1843 
1844  ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags")
1845  bool send(message_t &msg_,
1846  int flags_ = 0) // default until removed
1847  {
1848  int nbytes = zmq_msg_send(msg_.handle(), _handle, flags_);
1849  if (nbytes >= 0)
1850  return true;
1851  if (zmq_errno() == EAGAIN)
1852  return false;
1853  throw error_t();
1854  }
1855 
1856  template<typename T>
1858  "from 4.4.1, use send taking message_t or buffer (for contiguous "
1859  "ranges), and send_flags")
1860  bool send(T first, T last, int flags_ = 0)
1861  {
1862  zmq::message_t msg(first, last);
1863  int nbytes = zmq_msg_send(msg.handle(), _handle, flags_);
1864  if (nbytes >= 0)
1865  return true;
1866  if (zmq_errno() == EAGAIN)
1867  return false;
1868  throw error_t();
1869  }
1870 
1871 #ifdef ZMQ_HAS_RVALUE_REFS
1872  ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags")
1873  bool send(message_t &&msg_,
1874  int flags_ = 0) // default until removed
1875  {
1876 #ifdef ZMQ_CPP11
1877  return send(msg_, static_cast<send_flags>(flags_)).has_value();
1878 #else
1879  return send(msg_, flags_);
1880 #endif
1881  }
1882 #endif
1883 
1884 #ifdef ZMQ_CPP11
1885  send_result_t send(const_buffer buf, send_flags flags = send_flags::none)
1886  {
1887  const int nbytes =
1888  zmq_send(_handle, buf.data(), buf.size(), static_cast<int>(flags));
1889  if (nbytes >= 0)
1890  return static_cast<size_t>(nbytes);
1891  if (zmq_errno() == EAGAIN)
1892  return {};
1893  throw error_t();
1894  }
1895 
1896  send_result_t send(message_t &msg, send_flags flags)
1897  {
1898  int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast<int>(flags));
1899  if (nbytes >= 0)
1900  return static_cast<size_t>(nbytes);
1901  if (zmq_errno() == EAGAIN)
1902  return {};
1903  throw error_t();
1904  }
1905 
1906  send_result_t send(message_t &&msg, send_flags flags)
1907  {
1908  return send(msg, flags);
1909  }
1910 #endif
1911 
1913  "from 4.3.1, use recv taking a mutable_buffer and recv_flags")
1914  size_t recv(void *buf_, size_t len_, int flags_ = 0)
1915  {
1916  int nbytes = zmq_recv(_handle, buf_, len_, flags_);
1917  if (nbytes >= 0)
1918  return static_cast<size_t>(nbytes);
1919  if (zmq_errno() == EAGAIN)
1920  return 0;
1921  throw error_t();
1922  }
1923 
1925  "from 4.3.1, use recv taking a reference to message_t and recv_flags")
1926  bool recv(message_t *msg_, int flags_ = 0)
1927  {
1928  int nbytes = zmq_msg_recv(msg_->handle(), _handle, flags_);
1929  if (nbytes >= 0)
1930  return true;
1931  if (zmq_errno() == EAGAIN)
1932  return false;
1933  throw error_t();
1934  }
1935 
1936 #ifdef ZMQ_CPP11
1938  recv_buffer_result_t recv(mutable_buffer buf,
1939  recv_flags flags = recv_flags::none)
1940  {
1941  const int nbytes =
1942  zmq_recv(_handle, buf.data(), buf.size(), static_cast<int>(flags));
1943  if (nbytes >= 0) {
1944  return recv_buffer_size{
1945  (std::min)(static_cast<size_t>(nbytes), buf.size()),
1946  static_cast<size_t>(nbytes)};
1947  }
1948  if (zmq_errno() == EAGAIN)
1949  return {};
1950  throw error_t();
1951  }
1952 
1954  recv_result_t recv(message_t &msg, recv_flags flags = recv_flags::none)
1955  {
1956  const int nbytes =
1957  zmq_msg_recv(msg.handle(), _handle, static_cast<int>(flags));
1958  if (nbytes >= 0) {
1959  assert(msg.size() == static_cast<size_t>(nbytes));
1960  return static_cast<size_t>(nbytes);
1961  }
1962  if (zmq_errno() == EAGAIN)
1963  return {};
1964  throw error_t();
1965  }
1966 #endif
1967 
1968 #if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
1969  void join(const char *group)
1970  {
1971  int rc = zmq_join(_handle, group);
1972  if (rc != 0)
1973  throw error_t();
1974  }
1975 
1976  void leave(const char *group)
1977  {
1978  int rc = zmq_leave(_handle, group);
1979  if (rc != 0)
1980  throw error_t();
1981  }
1982 #endif
1983 
1984  ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return _handle; }
1985  ZMQ_NODISCARD const void *handle() const ZMQ_NOTHROW { return _handle; }
1986 
1987  ZMQ_EXPLICIT operator bool() const ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; }
1988  // note: non-const operator bool can be removed once
1989  // operator void* is removed from socket_t
1990  ZMQ_EXPLICIT operator bool() ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; }
1991 
1992  protected:
1993  void *_handle;
1994 
1995  private:
1996  void set_option(int option_, const void *optval_, size_t optvallen_)
1997  {
1998  int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_);
1999  if (rc != 0)
2000  throw error_t();
2001  }
2002 
2003  void get_option(int option_, void *optval_, size_t *optvallen_) const
2004  {
2005  int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_);
2006  if (rc != 0)
2007  throw error_t();
2008  }
2009 };
2010 } // namespace detail
2011 
2012 #ifdef ZMQ_CPP11
2013 enum class socket_type : int
2014 {
2015  req = ZMQ_REQ,
2016  rep = ZMQ_REP,
2017  dealer = ZMQ_DEALER,
2018  router = ZMQ_ROUTER,
2019  pub = ZMQ_PUB,
2020  sub = ZMQ_SUB,
2021  xpub = ZMQ_XPUB,
2022  xsub = ZMQ_XSUB,
2023  push = ZMQ_PUSH,
2024  pull = ZMQ_PULL,
2025 #if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
2026  server = ZMQ_SERVER,
2027  client = ZMQ_CLIENT,
2028  radio = ZMQ_RADIO,
2029  dish = ZMQ_DISH,
2030 #endif
2031 #if ZMQ_VERSION_MAJOR >= 4
2032  stream = ZMQ_STREAM,
2033 #endif
2034  pair = ZMQ_PAIR
2035 };
2036 #endif
2037 
2038 struct from_handle_t
2039 {
2040  struct _private
2041  {
2042  }; // disabling use other than with from_handle
2044 };
2045 
2048 
2049 // A non-owning nullable reference to a socket.
2050 // The reference is invalidated on socket close or destruction.
2051 class socket_ref : public detail::socket_base
2052 {
2053  public:
2054  socket_ref() ZMQ_NOTHROW : detail::socket_base() {}
2055 #ifdef ZMQ_CPP11
2056  socket_ref(std::nullptr_t) ZMQ_NOTHROW : detail::socket_base() {}
2057 #endif
2058  socket_ref(from_handle_t /*fh*/, void *handle) ZMQ_NOTHROW
2059  : detail::socket_base(handle)
2060  {
2061  }
2062 };
2063 
2064 #ifdef ZMQ_CPP11
2065 inline bool operator==(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW
2066 {
2067  return sr.handle() == nullptr;
2068 }
2069 inline bool operator==(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW
2070 {
2071  return sr.handle() == nullptr;
2072 }
2073 inline bool operator!=(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW
2074 {
2075  return !(sr == nullptr);
2076 }
2077 inline bool operator!=(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW
2078 {
2079  return !(sr == nullptr);
2080 }
2081 #endif
2082 
2084 {
2085  return std::equal_to<void *>()(a.handle(), b.handle());
2086 }
2088 {
2089  return !(a == b);
2090 }
2092 {
2093  return std::less<void *>()(a.handle(), b.handle());
2094 }
2096 {
2097  return b < a;
2098 }
2100 {
2101  return !(a > b);
2102 }
2104 {
2105  return !(a < b);
2106 }
2107 
2108 } // namespace zmq
2109 
2110 #ifdef ZMQ_CPP11
2111 namespace std
2112 {
2113 template<> struct hash<zmq::socket_ref>
2114 {
2115  size_t operator()(zmq::socket_ref sr) const ZMQ_NOTHROW
2116  {
2117  return hash<void *>()(sr.handle());
2118  }
2119 };
2120 } // namespace std
2121 #endif
2122 
2123 namespace zmq
2124 {
2125 class socket_t : public detail::socket_base
2126 {
2127  friend class monitor_t;
2128 
2129  public:
2130  socket_t() ZMQ_NOTHROW : detail::socket_base(ZMQ_NULLPTR), ctxptr(ZMQ_NULLPTR) {}
2131 
2132  socket_t(context_t &context_, int type_) :
2133  detail::socket_base(zmq_socket(context_.handle(), type_)),
2134  ctxptr(context_.handle())
2135  {
2136  if (_handle == ZMQ_NULLPTR)
2137  throw error_t();
2138  }
2139 
2140 #ifdef ZMQ_CPP11
2141  socket_t(context_t &context_, socket_type type_) :
2142  socket_t(context_, static_cast<int>(type_))
2143  {
2144  }
2145 #endif
2146 
2147 #ifdef ZMQ_HAS_RVALUE_REFS
2148  socket_t(socket_t &&rhs) ZMQ_NOTHROW : detail::socket_base(rhs._handle),
2149  ctxptr(rhs.ctxptr)
2150  {
2151  rhs._handle = ZMQ_NULLPTR;
2152  rhs.ctxptr = ZMQ_NULLPTR;
2153  }
2154  socket_t &operator=(socket_t &&rhs) ZMQ_NOTHROW
2155  {
2156  close();
2157  std::swap(_handle, rhs._handle);
2158  std::swap(ctxptr, rhs.ctxptr);
2159  return *this;
2160  }
2161 #endif
2162 
2163  ~socket_t() ZMQ_NOTHROW { close(); }
2164 
2165  operator void *() ZMQ_NOTHROW { return _handle; }
2166 
2167  operator void const *() const ZMQ_NOTHROW { return _handle; }
2168 
2170  {
2171  if (_handle == ZMQ_NULLPTR)
2172  // already closed
2173  return;
2174  int rc = zmq_close(_handle);
2175  ZMQ_ASSERT(rc == 0);
2176  _handle = ZMQ_NULLPTR;
2177  ctxptr = ZMQ_NULLPTR;
2178  }
2179 
2181  {
2182  std::swap(_handle, other._handle);
2183  std::swap(ctxptr, other.ctxptr);
2184  }
2185 
2186  operator socket_ref() ZMQ_NOTHROW { return socket_ref(from_handle, _handle); }
2187 
2188  private:
2189  void *ctxptr;
2190 
2192  void operator=(const socket_t &) ZMQ_DELETED_FUNCTION;
2193 
2194  // used by monitor_t
2195  socket_t(void *context_, int type_) :
2196  detail::socket_base(zmq_socket(context_, type_)),
2197  ctxptr(context_)
2198  {
2199  if (_handle == ZMQ_NULLPTR)
2200  throw error_t();
2201  if (ctxptr == ZMQ_NULLPTR)
2202  throw error_t();
2203  }
2204 };
2205 
2206 inline void swap(socket_t &a, socket_t &b) ZMQ_NOTHROW
2207 {
2208  a.swap(b);
2209 }
2210 
2211 ZMQ_DEPRECATED("from 4.3.1, use proxy taking socket_t objects")
2212 inline void proxy(void *frontend, void *backend, void *capture)
2213 {
2214  int rc = zmq_proxy(frontend, backend, capture);
2215  if (rc != 0)
2216  throw error_t();
2217 }
2218 
2219 inline void
2220 proxy(socket_ref frontend, socket_ref backend, socket_ref capture = socket_ref())
2221 {
2222  int rc = zmq_proxy(frontend.handle(), backend.handle(), capture.handle());
2223  if (rc != 0)
2224  throw error_t();
2225 }
2226 
2227 #ifdef ZMQ_HAS_PROXY_STEERABLE
2228 ZMQ_DEPRECATED("from 4.3.1, use proxy_steerable taking socket_t objects")
2229 inline void
2230 proxy_steerable(void *frontend, void *backend, void *capture, void *control)
2231 {
2232  int rc = zmq_proxy_steerable(frontend, backend, capture, control);
2233  if (rc != 0)
2234  throw error_t();
2235 }
2236 
2237 inline void proxy_steerable(socket_ref frontend,
2238  socket_ref backend,
2239  socket_ref capture,
2240  socket_ref control)
2241 {
2242  int rc = zmq_proxy_steerable(frontend.handle(), backend.handle(),
2243  capture.handle(), control.handle());
2244  if (rc != 0)
2245  throw error_t();
2246 }
2247 #endif
2248 
2249 class monitor_t
2250 {
2251  public:
2252  monitor_t() : _socket(), _monitor_socket() {}
2253 
2254  virtual ~monitor_t() { close(); }
2255 
2256 #ifdef ZMQ_HAS_RVALUE_REFS
2257  monitor_t(monitor_t &&rhs) ZMQ_NOTHROW : _socket(), _monitor_socket()
2258  {
2259  std::swap(_socket, rhs._socket);
2260  std::swap(_monitor_socket, rhs._monitor_socket);
2261  }
2262 
2263  monitor_t &operator=(monitor_t &&rhs) ZMQ_NOTHROW
2264  {
2265  close();
2266  _socket = socket_ref();
2267  std::swap(_socket, rhs._socket);
2268  std::swap(_monitor_socket, rhs._monitor_socket);
2269  return *this;
2270  }
2271 #endif
2272 
2273 
2274  void
2275  monitor(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL)
2276  {
2277  monitor(socket, addr.c_str(), events);
2278  }
2279 
2280  void monitor(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL)
2281  {
2282  init(socket, addr_, events);
2283  while (true) {
2284  check_event(-1);
2285  }
2286  }
2287 
2288  void init(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL)
2289  {
2290  init(socket, addr.c_str(), events);
2291  }
2292 
2293  void init(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL)
2294  {
2295  int rc = zmq_socket_monitor(socket.handle(), addr_, events);
2296  if (rc != 0)
2297  throw error_t();
2298 
2299  _socket = socket;
2300  _monitor_socket = socket_t(socket.ctxptr, ZMQ_PAIR);
2301  _monitor_socket.connect(addr_);
2302 
2303  on_monitor_started();
2304  }
2305 
2306  bool check_event(int timeout = 0)
2307  {
2308  assert(_monitor_socket);
2309 
2310  zmq_msg_t eventMsg;
2311  zmq_msg_init(&eventMsg);
2312 
2313  zmq::pollitem_t items[] = {
2314  {_monitor_socket.handle(), 0, ZMQ_POLLIN, 0},
2315  };
2316 
2317  zmq::poll(&items[0], 1, timeout);
2318 
2319  if (items[0].revents & ZMQ_POLLIN) {
2320  int rc = zmq_msg_recv(&eventMsg, _monitor_socket.handle(), 0);
2321  if (rc == -1 && zmq_errno() == ETERM)
2322  return false;
2323  assert(rc != -1);
2324 
2325  } else {
2326  zmq_msg_close(&eventMsg);
2327  return false;
2328  }
2329 
2330 #if ZMQ_VERSION_MAJOR >= 4
2331  const char *data = static_cast<const char *>(zmq_msg_data(&eventMsg));
2332  zmq_event_t msgEvent;
2333  memcpy(&msgEvent.event, data, sizeof(uint16_t));
2334  data += sizeof(uint16_t);
2335  memcpy(&msgEvent.value, data, sizeof(int32_t));
2336  zmq_event_t *event = &msgEvent;
2337 #else
2338  zmq_event_t *event = static_cast<zmq_event_t *>(zmq_msg_data(&eventMsg));
2339 #endif
2340 
2341 #ifdef ZMQ_NEW_MONITOR_EVENT_LAYOUT
2342  zmq_msg_t addrMsg;
2343  zmq_msg_init(&addrMsg);
2344  int rc = zmq_msg_recv(&addrMsg, _monitor_socket.handle(), 0);
2345  if (rc == -1 && zmq_errno() == ETERM) {
2346  zmq_msg_close(&eventMsg);
2347  return false;
2348  }
2349 
2350  assert(rc != -1);
2351  const char *str = static_cast<const char *>(zmq_msg_data(&addrMsg));
2352  std::string address(str, str + zmq_msg_size(&addrMsg));
2353  zmq_msg_close(&addrMsg);
2354 #else
2355  // Bit of a hack, but all events in the zmq_event_t union have the same layout so this will work for all event types.
2356  std::string address = event->data.connected.addr;
2357 #endif
2358 
2359 #ifdef ZMQ_EVENT_MONITOR_STOPPED
2360  if (event->event == ZMQ_EVENT_MONITOR_STOPPED) {
2361  zmq_msg_close(&eventMsg);
2362  return false;
2363  }
2364 
2365 #endif
2366 
2367  switch (event->event) {
2368  case ZMQ_EVENT_CONNECTED:
2369  on_event_connected(*event, address.c_str());
2370  break;
2371  case ZMQ_EVENT_CONNECT_DELAYED:
2372  on_event_connect_delayed(*event, address.c_str());
2373  break;
2374  case ZMQ_EVENT_CONNECT_RETRIED:
2375  on_event_connect_retried(*event, address.c_str());
2376  break;
2377  case ZMQ_EVENT_LISTENING:
2378  on_event_listening(*event, address.c_str());
2379  break;
2380  case ZMQ_EVENT_BIND_FAILED:
2381  on_event_bind_failed(*event, address.c_str());
2382  break;
2383  case ZMQ_EVENT_ACCEPTED:
2384  on_event_accepted(*event, address.c_str());
2385  break;
2386  case ZMQ_EVENT_ACCEPT_FAILED:
2387  on_event_accept_failed(*event, address.c_str());
2388  break;
2389  case ZMQ_EVENT_CLOSED:
2390  on_event_closed(*event, address.c_str());
2391  break;
2392  case ZMQ_EVENT_CLOSE_FAILED:
2393  on_event_close_failed(*event, address.c_str());
2394  break;
2395  case ZMQ_EVENT_DISCONNECTED:
2396  on_event_disconnected(*event, address.c_str());
2397  break;
2398 #ifdef ZMQ_BUILD_DRAFT_API
2399 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)
2400  case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL:
2401  on_event_handshake_failed_no_detail(*event, address.c_str());
2402  break;
2403  case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL:
2404  on_event_handshake_failed_protocol(*event, address.c_str());
2405  break;
2406  case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH:
2407  on_event_handshake_failed_auth(*event, address.c_str());
2408  break;
2409  case ZMQ_EVENT_HANDSHAKE_SUCCEEDED:
2410  on_event_handshake_succeeded(*event, address.c_str());
2411  break;
2412 #elif ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1)
2413  case ZMQ_EVENT_HANDSHAKE_FAILED:
2414  on_event_handshake_failed(*event, address.c_str());
2415  break;
2416  case ZMQ_EVENT_HANDSHAKE_SUCCEED:
2417  on_event_handshake_succeed(*event, address.c_str());
2418  break;
2419 #endif
2420 #endif
2421  default:
2422  on_event_unknown(*event, address.c_str());
2423  break;
2424  }
2425  zmq_msg_close(&eventMsg);
2426 
2427  return true;
2428  }
2429 
2430 #ifdef ZMQ_EVENT_MONITOR_STOPPED
2431  void abort()
2432  {
2433  if (_socket)
2434  zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0);
2435 
2436  _socket = socket_ref();
2437  }
2438 #endif
2439  virtual void on_monitor_started() {}
2440  virtual void on_event_connected(const zmq_event_t &event_, const char *addr_)
2441  {
2442  (void) event_;
2443  (void) addr_;
2444  }
2445  virtual void on_event_connect_delayed(const zmq_event_t &event_,
2446  const char *addr_)
2447  {
2448  (void) event_;
2449  (void) addr_;
2450  }
2451  virtual void on_event_connect_retried(const zmq_event_t &event_,
2452  const char *addr_)
2453  {
2454  (void) event_;
2455  (void) addr_;
2456  }
2457  virtual void on_event_listening(const zmq_event_t &event_, const char *addr_)
2458  {
2459  (void) event_;
2460  (void) addr_;
2461  }
2462  virtual void on_event_bind_failed(const zmq_event_t &event_, const char *addr_)
2463  {
2464  (void) event_;
2465  (void) addr_;
2466  }
2467  virtual void on_event_accepted(const zmq_event_t &event_, const char *addr_)
2468  {
2469  (void) event_;
2470  (void) addr_;
2471  }
2472  virtual void on_event_accept_failed(const zmq_event_t &event_, const char *addr_)
2473  {
2474  (void) event_;
2475  (void) addr_;
2476  }
2477  virtual void on_event_closed(const zmq_event_t &event_, const char *addr_)
2478  {
2479  (void) event_;
2480  (void) addr_;
2481  }
2482  virtual void on_event_close_failed(const zmq_event_t &event_, const char *addr_)
2483  {
2484  (void) event_;
2485  (void) addr_;
2486  }
2487  virtual void on_event_disconnected(const zmq_event_t &event_, const char *addr_)
2488  {
2489  (void) event_;
2490  (void) addr_;
2491  }
2492 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)
2494  const char *addr_)
2495  {
2496  (void) event_;
2497  (void) addr_;
2498  }
2500  const char *addr_)
2501  {
2502  (void) event_;
2503  (void) addr_;
2504  }
2505  virtual void on_event_handshake_failed_auth(const zmq_event_t &event_,
2506  const char *addr_)
2507  {
2508  (void) event_;
2509  (void) addr_;
2510  }
2511  virtual void on_event_handshake_succeeded(const zmq_event_t &event_,
2512  const char *addr_)
2513  {
2514  (void) event_;
2515  (void) addr_;
2516  }
2517 #elif ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1)
2518  virtual void on_event_handshake_failed(const zmq_event_t &event_,
2519  const char *addr_)
2520  {
2521  (void) event_;
2522  (void) addr_;
2523  }
2524  virtual void on_event_handshake_succeed(const zmq_event_t &event_,
2525  const char *addr_)
2526  {
2527  (void) event_;
2528  (void) addr_;
2529  }
2530 #endif
2531  virtual void on_event_unknown(const zmq_event_t &event_, const char *addr_)
2532  {
2533  (void) event_;
2534  (void) addr_;
2535  }
2536 
2537  private:
2539  void operator=(const monitor_t &) ZMQ_DELETED_FUNCTION;
2540 
2541  socket_ref _socket;
2542  socket_t _monitor_socket;
2543 
2545  {
2546  if (_socket)
2547  zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0);
2548  _monitor_socket.close();
2549  }
2550 };
2551 
2552 #if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER)
2553 
2554 // polling events
2555 enum class event_flags : short
2556 {
2557  none = 0,
2558  pollin = ZMQ_POLLIN,
2559  pollout = ZMQ_POLLOUT,
2560  pollerr = ZMQ_POLLERR,
2561  pollpri = ZMQ_POLLPRI
2562 };
2563 
2564 constexpr event_flags operator|(event_flags a, event_flags b) noexcept
2565 {
2566  return detail::enum_bit_or(a, b);
2567 }
2568 constexpr event_flags operator&(event_flags a, event_flags b) noexcept
2569 {
2570  return detail::enum_bit_and(a, b);
2571 }
2572 constexpr event_flags operator^(event_flags a, event_flags b) noexcept
2573 {
2574  return detail::enum_bit_xor(a, b);
2575 }
2576 constexpr event_flags operator~(event_flags a) noexcept
2577 {
2578  return detail::enum_bit_not(a);
2579 }
2580 
2581 struct no_user_data;
2582 
2583 // layout compatible with zmq_poller_event_t
2584 template<class T = no_user_data> struct poller_event
2585 {
2586  socket_ref socket;
2587 #ifdef _WIN32
2588  SOCKET fd;
2589 #else
2590  int fd;
2591 #endif
2592  T *user_data;
2593  event_flags events;
2594 };
2595 
2596 template<typename T = no_user_data> class poller_t
2597 {
2598  public:
2599  using event_type = poller_event<T>;
2600 
2601  poller_t() : poller_ptr(zmq_poller_new())
2602  {
2603  if (!poller_ptr)
2604  throw error_t();
2605  }
2606 
2607  template<
2608  typename Dummy = void,
2609  typename =
2610  typename std::enable_if<!std::is_same<T, no_user_data>::value, Dummy>::type>
2611  void add(zmq::socket_ref socket, event_flags events, T *user_data)
2612  {
2613  add_impl(socket, events, user_data);
2614  }
2615 
2616  void add(zmq::socket_ref socket, event_flags events)
2617  {
2618  add_impl(socket, events, nullptr);
2619  }
2620 
2621  void remove(zmq::socket_ref socket)
2622  {
2623  if (0 != zmq_poller_remove(poller_ptr.get(), socket.handle())) {
2624  throw error_t();
2625  }
2626  }
2627 
2628  void modify(zmq::socket_ref socket, event_flags events)
2629  {
2630  if (0
2631  != zmq_poller_modify(poller_ptr.get(), socket.handle(),
2632  static_cast<short>(events))) {
2633  throw error_t();
2634  }
2635  }
2636 
2637  size_t wait_all(std::vector<event_type> &poller_events,
2638  const std::chrono::milliseconds timeout)
2639  {
2640  int rc = zmq_poller_wait_all(
2641  poller_ptr.get(),
2642  reinterpret_cast<zmq_poller_event_t *>(poller_events.data()),
2643  static_cast<int>(poller_events.size()),
2644  static_cast<long>(timeout.count()));
2645  if (rc > 0)
2646  return static_cast<size_t>(rc);
2647 
2648 #if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)
2649  if (zmq_errno() == EAGAIN)
2650 #else
2651  if (zmq_errno() == ETIMEDOUT)
2652 #endif
2653  return 0;
2654 
2655  throw error_t();
2656  }
2657 
2658  private:
2659  struct destroy_poller_t
2660  {
2661  void operator()(void *ptr) noexcept
2662  {
2663  int rc = zmq_poller_destroy(&ptr);
2664  ZMQ_ASSERT(rc == 0);
2665  }
2666  };
2667 
2668  std::unique_ptr<void, destroy_poller_t> poller_ptr;
2669 
2670  void add_impl(zmq::socket_ref socket, event_flags events, T *user_data)
2671  {
2672  if (0
2673  != zmq_poller_add(poller_ptr.get(), socket.handle(), user_data,
2674  static_cast<short>(events))) {
2675  throw error_t();
2676  }
2677  }
2678 };
2679 #endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER)
2680 
2681 inline std::ostream &operator<<(std::ostream &os, const message_t &msg)
2682 {
2683  return os << msg.str();
2684 }
2685 
2686 } // namespace zmq
2687 
2688 #endif // __ZMQ_HPP_INCLUDED__
void monitor(socket_t &socket, const char *addr_, int events=ZMQ_EVENT_ALL)
void swap(context_t &other) ZMQ_NOTHROW
const T * data(const std::vector< T, Alloc > &v)
Definition: flatbuffers.h:1108
context_t(int io_threads_, int max_sockets_=ZMQ_MAX_SOCKETS_DFLT)
ZMQ_CONSTEXPR_FN ZMQ_EXPLICIT from_handle_t(_private) ZMQ_NOTHROW
socket_t(void *context_, int type_)
virtual const char * what() const ZMQ_NOTHROW ZMQ_OVERRIDE
ZMQ_NODISCARD const zmq_msg_t * handle() const ZMQ_NOTHROW
bool operator<(const detail::socket_base &a, const detail::socket_base &b) ZMQ_NOTHROW
void monitor(socket_t &socket, std::string const &addr, int events=ZMQ_EVENT_ALL)
virtual void on_event_handshake_failed_protocol(const zmq_event_t &event_, const char *addr_)
zmq_pollitem_t pollitem_t
virtual void on_event_connect_delayed(const zmq_event_t &event_, const char *addr_)
static raw_event_t * buffer
Definition: minitrace.cpp:54
void close() ZMQ_NOTHROW
bool connected() const ZMQ_NOTHROW
std::ostream & operator<<(std::ostream &os, const message_t &msg)
const char * gets(const char *property_)
void swap(socket_t &other) ZMQ_NOTHROW
void bind(const char *addr_)
T * data() ZMQ_NOTHROW
void get_option(int option_, void *optval_, size_t *optvallen_) const
virtual void on_event_closed(const zmq_event_t &event_, const char *addr_)
virtual void on_event_disconnected(const zmq_event_t &event_, const char *addr_)
virtual void on_event_accepted(const zmq_event_t &event_, const char *addr_)
void rebuild(const void *data_, size_t size_)
message_t(const void *data_, size_t size_)
Definition: any.hpp:455
void swap(linb::any &lhs, linb::any &rhs) noexcept
Definition: any.hpp:457
ZMQ_NODISCARD void * handle() ZMQ_NOTHROW
std::string str() const
ZMQ_NODISCARD bool empty() const ZMQ_NOTHROW
basic_string_view< CharT, Traits > to_string_view(std::basic_string< CharT, Traits, Allocator > const &s)
void unbind(std::string const &addr)
void disconnect(const char *addr_)
void close() ZMQ_NOTHROW
#define ZMQ_OVERRIDE
bool operator>=(const detail::socket_base &a, const detail::socket_base &b) ZMQ_NOTHROW
error_t() ZMQ_NOTHROW
virtual void on_event_handshake_succeeded(const zmq_event_t &event_, const char *addr_)
ZMQ_NODISCARD zmq_msg_t * handle() ZMQ_NOTHROW
T const * data() const ZMQ_NOTHROW
~message_t() ZMQ_NOTHROW
ZMQ_EXPLICIT socket_base(void *handle) ZMQ_NOTHROW
void proxy_steerable(void *frontend, void *backend, void *capture, void *control)
void * data() ZMQ_NOTHROW
socket_ref() ZMQ_NOTHROW
zmq_free_fn free_fn
int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_=-1)
void proxy(void *frontend, void *backend, void *capture)
#define ZMQ_NULLPTR
virtual void on_event_handshake_failed_auth(const zmq_event_t &event_, const char *addr_)
void move(message_t &msg_)
socket_t() ZMQ_NOTHROW
const void * data() const ZMQ_NOTHROW
void set_option(int option_, const void *optval_, size_t optvallen_)
void copy(message_t &msg_)
#define ZMQ_ASSERT(expression)
#define ZMQ_NODISCARD
void init(socket_t &socket, const char *addr_, int events=ZMQ_EVENT_ALL)
bool operator>(const detail::socket_base &a, const detail::socket_base &b) ZMQ_NOTHROW
#define ZMQ_DELETED_FUNCTION
bool check_event(int timeout=0)
message_t(ForwardIter first, ForwardIter last)
virtual void on_event_close_failed(const zmq_event_t &event_, const char *addr_)
virtual void on_event_handshake_failed_no_detail(const zmq_event_t &event_, const char *addr_)
int num() const ZMQ_NOTHROW
message_t(void *data_, size_t size_, free_fn *ffn_, void *hint_=ZMQ_NULLPTR)
#define ZMQ_CPP11_DEPRECATED(msg)
~socket_t() ZMQ_NOTHROW
virtual void on_event_unknown(const zmq_event_t &event_, const char *addr_)
socket_t(context_t &context_, int type_)
void rebuild(size_t size_)
bool operator<=(const detail::socket_base &a, const detail::socket_base &b) ZMQ_NOTHROW
message_t(size_t size_)
typename std::enable_if< Predicate::value >::type * enable_if
Definition: basic_types.h:168
bool operator==(const message_t &other) const ZMQ_NOTHROW
virtual void on_event_listening(const zmq_event_t &event_, const char *addr_)
void version(int *major_, int *minor_, int *patch_)
virtual void on_event_connected(const zmq_event_t &event_, const char *addr_)
void connect(std::string const &addr)
bool operator==(const detail::socket_base &a, const detail::socket_base &b) ZMQ_NOTHROW
socket_ref(from_handle_t, void *handle) ZMQ_NOTHROW
bool operator!=(const message_t &other) const ZMQ_NOTHROW
void connect(const char *addr_)
void swap(message_t &a, message_t &b) ZMQ_NOTHROW
void shutdown() ZMQ_NOTHROW
size_t size() const ZMQ_NOTHROW
#define ZMQ_CONSTEXPR_FN
#define ZMQ_NOTHROW
void bind(std::string const &addr)
void rebuild(void *data_, size_t size_, free_fn *ffn_, void *hint_=ZMQ_NULLPTR)
bool operator!=(const detail::socket_base &a, const detail::socket_base &b) ZMQ_NOTHROW
virtual void on_monitor_started()
virtual void on_event_bind_failed(const zmq_event_t &event_, const char *addr_)
#define ZMQ_CONSTEXPR_VAR
void init(socket_t &socket, std::string const &addr, int events=ZMQ_EVENT_ALL)
virtual void on_event_accept_failed(const zmq_event_t &event_, const char *addr_)
message_t() ZMQ_NOTHROW
void disconnect(std::string const &addr)
~context_t() ZMQ_NOTHROW
void swap(message_t &other) ZMQ_NOTHROW
void close() ZMQ_NOTHROW
#define ZMQ_EXPLICIT
void unbind(const char *addr_)
std::string to_string() const
virtual void on_event_connect_retried(const zmq_event_t &event_, const char *addr_)
error_t(int err) ZMQ_NOTHROW
ZMQ_CONSTEXPR_VAR from_handle_t from_handle
bool more() const ZMQ_NOTHROW


behaviotree_cpp_v3
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Tue May 4 2021 02:56:25