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