Showing
1 changed file
with
2713 additions
and
0 deletions
etc_files/zmq.hpp
0 → 100644
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) && (!defined(__GNUC__) || __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3)) | ||
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; | ||
237 | +template<class T> auto begin(T &&r) -> decltype(begin(std::forward<T>(r))) | ||
238 | +{ | ||
239 | + return begin(std::forward<T>(r)); | ||
240 | +} | ||
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: | ||
292 | + error_t() ZMQ_NOTHROW : errnum(zmq_errno()) {} | ||
293 | + explicit error_t(int err) ZMQ_NOTHROW : errnum(err) {} | ||
294 | + virtual const char *what() const ZMQ_NOTHROW ZMQ_OVERRIDE | ||
295 | + { | ||
296 | + return zmq_strerror(errnum); | ||
297 | + } | ||
298 | + int num() const ZMQ_NOTHROW { return errnum; } | ||
299 | + | ||
300 | + private: | ||
301 | + int errnum; | ||
302 | +}; | ||
303 | + | ||
304 | +namespace detail { | ||
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") | ||
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") | ||
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 | ||
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") | ||
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") | ||
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 | ||
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 | + | ||
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") | ||
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> | ||
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 | + | ||
380 | +inline void version(int *major_, int *minor_, int *patch_) | ||
381 | +{ | ||
382 | + zmq_version(major_, minor_, patch_); | ||
383 | +} | ||
384 | + | ||
385 | +#ifdef ZMQ_CPP11 | ||
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: | ||
411 | + message_t() ZMQ_NOTHROW | ||
412 | + { | ||
413 | + int rc = zmq_msg_init(&msg); | ||
414 | + ZMQ_ASSERT(rc == 0); | ||
415 | + } | ||
416 | + | ||
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 | + | ||
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 | + | ||
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 | + | ||
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") | ||
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> | ||
479 | + explicit message_t(const Range &rng) : | ||
480 | + message_t(detail::ranges::begin(rng), detail::ranges::end(rng)) | ||
481 | + { | ||
482 | + } | ||
483 | + | ||
484 | + explicit message_t(const std::string &str) : message_t(str.data(), str.size()) {} | ||
485 | + | ||
486 | +#if CPPZMQ_HAS_STRING_VIEW | ||
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 | ||
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 | + | ||
499 | + message_t &operator=(message_t &&rhs) ZMQ_NOTHROW | ||
500 | + { | ||
501 | + std::swap(msg, rhs.msg); | ||
502 | + return *this; | ||
503 | + } | ||
504 | +#endif | ||
505 | + | ||
506 | + ~message_t() ZMQ_NOTHROW | ||
507 | + { | ||
508 | + int rc = zmq_msg_close(&msg); | ||
509 | + ZMQ_ASSERT(rc == 0); | ||
510 | + } | ||
511 | + | ||
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 | + | ||
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 | + | ||
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 | + | ||
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") | ||
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 | + | ||
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") | ||
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 | + | ||
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 | + | ||
582 | + bool more() const ZMQ_NOTHROW | ||
583 | + { | ||
584 | + int rc = zmq_msg_more(const_cast<zmq_msg_t *>(&msg)); | ||
585 | + return rc != 0; | ||
586 | + } | ||
587 | + | ||
588 | + void *data() ZMQ_NOTHROW { return zmq_msg_data(&msg); } | ||
589 | + | ||
590 | + const void *data() const ZMQ_NOTHROW | ||
591 | + { | ||
592 | + return zmq_msg_data(const_cast<zmq_msg_t *>(&msg)); | ||
593 | + } | ||
594 | + | ||
595 | + size_t size() const ZMQ_NOTHROW | ||
596 | + { | ||
597 | + return zmq_msg_size(const_cast<zmq_msg_t *>(&msg)); | ||
598 | + } | ||
599 | + | ||
600 | + ZMQ_NODISCARD bool empty() const ZMQ_NOTHROW { return size() == 0u; } | ||
601 | + | ||
602 | + template<typename T> T *data() ZMQ_NOTHROW { return static_cast<T *>(data()); } | ||
603 | + | ||
604 | + 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") | ||
610 | + bool equal(const message_t *other) const ZMQ_NOTHROW { return *this == *other; } | ||
611 | + | ||
612 | + 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 | + | ||
618 | + 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) | ||
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) | ||
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) | ||
644 | + uint32_t routing_id() const | ||
645 | + { | ||
646 | + return zmq_msg_routing_id(const_cast<zmq_msg_t *>(&msg)); | ||
647 | + } | ||
648 | + | ||
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 | + | ||
656 | + const char *group() const | ||
657 | + { | ||
658 | + return zmq_msg_group(const_cast<zmq_msg_t *>(&msg)); | ||
659 | + } | ||
660 | + | ||
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 | ||
670 | + 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 | ||
676 | + 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 | + */ | ||
688 | + 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 | + | ||
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 | + | ||
730 | + ZMQ_NODISCARD zmq_msg_t *handle() ZMQ_NOTHROW { return &msg; } | ||
731 | + 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 | + | ||
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: | ||
796 | + context_t() | ||
797 | + { | ||
798 | + ptr = zmq_ctx_new(); | ||
799 | + if (ptr == ZMQ_NULLPTR) | ||
800 | + throw error_t(); | ||
801 | + } | ||
802 | + | ||
803 | + | ||
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 | ||
818 | + context_t(context_t &&rhs) ZMQ_NOTHROW : ptr(rhs.ptr) { rhs.ptr = ZMQ_NULLPTR; } | ||
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 | + | ||
827 | + ~context_t() ZMQ_NOTHROW { close(); } | ||
828 | + | ||
829 | + ZMQ_CPP11_DEPRECATED("from 4.7.0, use set taking zmq::ctxopt instead") | ||
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") | ||
838 | + int getctxopt(int option_) { return zmq_ctx_get(ptr, option_); } | ||
839 | + | ||
840 | +#ifdef ZMQ_CPP11 | ||
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 | + | ||
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()). | ||
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. | ||
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. | ||
889 | + ZMQ_EXPLICIT operator void *() ZMQ_NOTHROW { return ptr; } | ||
890 | + | ||
891 | + ZMQ_EXPLICIT operator void const *() const ZMQ_NOTHROW { return ptr; } | ||
892 | + | ||
893 | + ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return ptr; } | ||
894 | + | ||
895 | + ZMQ_DEPRECATED("from 4.7.0, use handle() != nullptr instead") | ||
896 | + operator bool() const ZMQ_NOTHROW { return ptr != ZMQ_NULLPTR; } | ||
897 | + | ||
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 | + | ||
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 | + | ||
919 | + 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; | ||
944 | + trivial_optional(T value) noexcept : _value(value), _has_value(true) {} | ||
945 | + | ||
946 | + const T *operator->() const noexcept | ||
947 | + { | ||
948 | + assert(_has_value); | ||
949 | + return &_value; | ||
950 | + } | ||
951 | + T *operator->() noexcept | ||
952 | + { | ||
953 | + assert(_has_value); | ||
954 | + return &_value; | ||
955 | + } | ||
956 | + | ||
957 | + const T &operator*() const noexcept | ||
958 | + { | ||
959 | + assert(_has_value); | ||
960 | + return _value; | ||
961 | + } | ||
962 | + T &operator*() noexcept | ||
963 | + { | ||
964 | + assert(_has_value); | ||
965 | + return _value; | ||
966 | + } | ||
967 | + | ||
968 | + T &value() | ||
969 | + { | ||
970 | + if (!_has_value) | ||
971 | + throw std::exception(); | ||
972 | + return _value; | ||
973 | + } | ||
974 | + const T &value() const | ||
975 | + { | ||
976 | + if (!_has_value) | ||
977 | + throw std::exception(); | ||
978 | + return _value; | ||
979 | + } | ||
980 | + | ||
981 | + explicit operator bool() const noexcept { return _has_value; } | ||
982 | + 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 | +{ | ||
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 | +} | ||
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 | +} | ||
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 | +} | ||
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 | + | ||
1032 | +constexpr send_flags operator|(send_flags a, send_flags b) noexcept | ||
1033 | +{ | ||
1034 | + return detail::enum_bit_or(a, b); | ||
1035 | +} | ||
1036 | +constexpr send_flags operator&(send_flags a, send_flags b) noexcept | ||
1037 | +{ | ||
1038 | + return detail::enum_bit_and(a, b); | ||
1039 | +} | ||
1040 | +constexpr send_flags operator^(send_flags a, send_flags b) noexcept | ||
1041 | +{ | ||
1042 | + return detail::enum_bit_xor(a, b); | ||
1043 | +} | ||
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 | + | ||
1056 | +constexpr recv_flags operator|(recv_flags a, recv_flags b) noexcept | ||
1057 | +{ | ||
1058 | + return detail::enum_bit_or(a, b); | ||
1059 | +} | ||
1060 | +constexpr recv_flags operator&(recv_flags a, recv_flags b) noexcept | ||
1061 | +{ | ||
1062 | + return detail::enum_bit_and(a, b); | ||
1063 | +} | ||
1064 | +constexpr recv_flags operator^(recv_flags a, recv_flags b) noexcept | ||
1065 | +{ | ||
1066 | + return detail::enum_bit_xor(a, b); | ||
1067 | +} | ||
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: | ||
1081 | + constexpr mutable_buffer() noexcept : _data(nullptr), _size(0) {} | ||
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 | + | ||
1089 | + constexpr void *data() const noexcept { return _data; } | ||
1090 | + constexpr size_t size() const noexcept { return _size; } | ||
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 | + | ||
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 | +} | ||
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: | ||
1118 | + constexpr const_buffer() noexcept : _data(nullptr), _size(0) {} | ||
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 | + } | ||
1125 | + constexpr const_buffer(const mutable_buffer &mb) noexcept : | ||
1126 | + _data(mb.data()), _size(mb.size()) | ||
1127 | + { | ||
1128 | + } | ||
1129 | + | ||
1130 | + constexpr const void *data() const noexcept { return _data; } | ||
1131 | + constexpr size_t size() const noexcept { return _size; } | ||
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 | + | ||
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 | +} | ||
1151 | +inline const_buffer operator+(size_t n, const const_buffer &cb) noexcept | ||
1152 | +{ | ||
1153 | + return cb + n; | ||
1154 | +} | ||
1155 | + | ||
1156 | +// buffer creation | ||
1157 | + | ||
1158 | +constexpr mutable_buffer buffer(void *p, size_t n) noexcept | ||
1159 | +{ | ||
1160 | + return mutable_buffer(p, n); | ||
1161 | +} | ||
1162 | +constexpr const_buffer buffer(const void *p, size_t n) noexcept | ||
1163 | +{ | ||
1164 | + return const_buffer(p, n); | ||
1165 | +} | ||
1166 | +constexpr mutable_buffer buffer(const mutable_buffer &mb) noexcept | ||
1167 | +{ | ||
1168 | + return mb; | ||
1169 | +} | ||
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 | +} | ||
1174 | +constexpr const_buffer buffer(const const_buffer &cb) noexcept | ||
1175 | +{ | ||
1176 | + return cb; | ||
1177 | +} | ||
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 | + | ||
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> | ||
1206 | +constexpr size_t seq_size(const T (&/*array*/)[N]) noexcept | ||
1207 | +{ | ||
1208 | + return N; | ||
1209 | +} | ||
1210 | + | ||
1211 | +template<class 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> | ||
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 | ||
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> | ||
1244 | +mutable_buffer buffer(T (&data)[N], size_t n_bytes) noexcept | ||
1245 | +{ | ||
1246 | + return detail::buffer_contiguous_sequence(data, n_bytes); | ||
1247 | +} | ||
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> | ||
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 | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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> | ||
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 | +{ | ||
1361 | +constexpr const_buffer operator"" _zbuf(const char *str, size_t len) noexcept | ||
1362 | +{ | ||
1363 | + return const_buffer(str, len * sizeof(char)); | ||
1364 | +} | ||
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 | +} | ||
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 | +} | ||
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 | +#ifdef ZMQ_CPP11 | ||
1380 | +enum class socket_type : int | ||
1381 | +{ | ||
1382 | + req = ZMQ_REQ, | ||
1383 | + rep = ZMQ_REP, | ||
1384 | + dealer = ZMQ_DEALER, | ||
1385 | + router = ZMQ_ROUTER, | ||
1386 | + pub = ZMQ_PUB, | ||
1387 | + sub = ZMQ_SUB, | ||
1388 | + xpub = ZMQ_XPUB, | ||
1389 | + xsub = ZMQ_XSUB, | ||
1390 | + push = ZMQ_PUSH, | ||
1391 | + pull = ZMQ_PULL, | ||
1392 | +#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) | ||
1393 | + server = ZMQ_SERVER, | ||
1394 | + client = ZMQ_CLIENT, | ||
1395 | + radio = ZMQ_RADIO, | ||
1396 | + dish = ZMQ_DISH, | ||
1397 | + gather = ZMQ_GATHER, | ||
1398 | + scatter = ZMQ_SCATTER, | ||
1399 | + dgram = ZMQ_DGRAM, | ||
1400 | +#endif | ||
1401 | +#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3) | ||
1402 | + peer = ZMQ_PEER, | ||
1403 | + channel = ZMQ_CHANNEL, | ||
1404 | +#endif | ||
1405 | +#if ZMQ_VERSION_MAJOR >= 4 | ||
1406 | + stream = ZMQ_STREAM, | ||
1407 | +#endif | ||
1408 | + pair = ZMQ_PAIR | ||
1409 | +}; | ||
1410 | +#endif | ||
1411 | + | ||
1412 | +namespace sockopt | ||
1413 | +{ | ||
1414 | +// There are two types of options, | ||
1415 | +// integral type with known compiler time size (int, bool, int64_t, uint64_t) | ||
1416 | +// and arrays with dynamic size (strings, binary data). | ||
1417 | + | ||
1418 | +// BoolUnit: if true accepts values of type bool (but passed as T into libzmq) | ||
1419 | +template<int Opt, class T, bool BoolUnit = false> struct integral_option | ||
1420 | +{ | ||
1421 | +}; | ||
1422 | + | ||
1423 | +// NullTerm: | ||
1424 | +// 0: binary data | ||
1425 | +// 1: null-terminated string (`getsockopt` size includes null) | ||
1426 | +// 2: binary (size 32) or Z85 encoder string of size 41 (null included) | ||
1427 | +template<int Opt, int NullTerm = 1> struct array_option | ||
1428 | +{ | ||
1429 | +}; | ||
1430 | + | ||
1431 | +#define ZMQ_DEFINE_INTEGRAL_OPT(OPT, NAME, TYPE) \ | ||
1432 | + using NAME##_t = integral_option<OPT, TYPE, false>; \ | ||
1433 | + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} | ||
1434 | +#define ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(OPT, NAME, TYPE) \ | ||
1435 | + using NAME##_t = integral_option<OPT, TYPE, true>; \ | ||
1436 | + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} | ||
1437 | +#define ZMQ_DEFINE_ARRAY_OPT(OPT, NAME) \ | ||
1438 | + using NAME##_t = array_option<OPT>; \ | ||
1439 | + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} | ||
1440 | +#define ZMQ_DEFINE_ARRAY_OPT_BINARY(OPT, NAME) \ | ||
1441 | + using NAME##_t = array_option<OPT, 0>; \ | ||
1442 | + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} | ||
1443 | +#define ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(OPT, NAME) \ | ||
1444 | + using NAME##_t = array_option<OPT, 2>; \ | ||
1445 | + ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {} | ||
1446 | + | ||
1447 | +// deprecated, use zmq::fd_t | ||
1448 | +using cppzmq_fd_t = ::zmq::fd_t; | ||
1449 | + | ||
1450 | +#ifdef ZMQ_AFFINITY | ||
1451 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_AFFINITY, affinity, uint64_t); | ||
1452 | +#endif | ||
1453 | +#ifdef ZMQ_BACKLOG | ||
1454 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_BACKLOG, backlog, int); | ||
1455 | +#endif | ||
1456 | +#ifdef ZMQ_BINDTODEVICE | ||
1457 | +ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_BINDTODEVICE, bindtodevice); | ||
1458 | +#endif | ||
1459 | +#ifdef ZMQ_CONFLATE | ||
1460 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CONFLATE, conflate, int); | ||
1461 | +#endif | ||
1462 | +#ifdef ZMQ_CONNECT_ROUTING_ID | ||
1463 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_CONNECT_ROUTING_ID, connect_routing_id); | ||
1464 | +#endif | ||
1465 | +#ifdef ZMQ_CONNECT_TIMEOUT | ||
1466 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_CONNECT_TIMEOUT, connect_timeout, int); | ||
1467 | +#endif | ||
1468 | +#ifdef ZMQ_CURVE_PUBLICKEY | ||
1469 | +ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_PUBLICKEY, curve_publickey); | ||
1470 | +#endif | ||
1471 | +#ifdef ZMQ_CURVE_SECRETKEY | ||
1472 | +ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SECRETKEY, curve_secretkey); | ||
1473 | +#endif | ||
1474 | +#ifdef ZMQ_CURVE_SERVER | ||
1475 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CURVE_SERVER, curve_server, int); | ||
1476 | +#endif | ||
1477 | +#ifdef ZMQ_CURVE_SERVERKEY | ||
1478 | +ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SERVERKEY, curve_serverkey); | ||
1479 | +#endif | ||
1480 | +#ifdef ZMQ_EVENTS | ||
1481 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_EVENTS, events, int); | ||
1482 | +#endif | ||
1483 | +#ifdef ZMQ_FD | ||
1484 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_FD, fd, ::zmq::fd_t); | ||
1485 | +#endif | ||
1486 | +#ifdef ZMQ_GSSAPI_PLAINTEXT | ||
1487 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_PLAINTEXT, gssapi_plaintext, int); | ||
1488 | +#endif | ||
1489 | +#ifdef ZMQ_GSSAPI_SERVER | ||
1490 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_SERVER, gssapi_server, int); | ||
1491 | +#endif | ||
1492 | +#ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL | ||
1493 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL, gssapi_service_principal); | ||
1494 | +#endif | ||
1495 | +#ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE | ||
1496 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE, | ||
1497 | + gssapi_service_principal_nametype, | ||
1498 | + int); | ||
1499 | +#endif | ||
1500 | +#ifdef ZMQ_GSSAPI_PRINCIPAL | ||
1501 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_PRINCIPAL, gssapi_principal); | ||
1502 | +#endif | ||
1503 | +#ifdef ZMQ_GSSAPI_PRINCIPAL_NAMETYPE | ||
1504 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, | ||
1505 | + gssapi_principal_nametype, | ||
1506 | + int); | ||
1507 | +#endif | ||
1508 | +#ifdef ZMQ_HANDSHAKE_IVL | ||
1509 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HANDSHAKE_IVL, handshake_ivl, int); | ||
1510 | +#endif | ||
1511 | +#ifdef ZMQ_HEARTBEAT_IVL | ||
1512 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_IVL, heartbeat_ivl, int); | ||
1513 | +#endif | ||
1514 | +#ifdef ZMQ_HEARTBEAT_TIMEOUT | ||
1515 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TIMEOUT, heartbeat_timeout, int); | ||
1516 | +#endif | ||
1517 | +#ifdef ZMQ_HEARTBEAT_TTL | ||
1518 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TTL, heartbeat_ttl, int); | ||
1519 | +#endif | ||
1520 | +#ifdef ZMQ_IMMEDIATE | ||
1521 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IMMEDIATE, immediate, int); | ||
1522 | +#endif | ||
1523 | +#ifdef ZMQ_INVERT_MATCHING | ||
1524 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_INVERT_MATCHING, invert_matching, int); | ||
1525 | +#endif | ||
1526 | +#ifdef ZMQ_IPV6 | ||
1527 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IPV6, ipv6, int); | ||
1528 | +#endif | ||
1529 | +#ifdef ZMQ_LAST_ENDPOINT | ||
1530 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_LAST_ENDPOINT, last_endpoint); | ||
1531 | +#endif | ||
1532 | +#ifdef ZMQ_LINGER | ||
1533 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_LINGER, linger, int); | ||
1534 | +#endif | ||
1535 | +#ifdef ZMQ_MAXMSGSIZE | ||
1536 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MAXMSGSIZE, maxmsgsize, int64_t); | ||
1537 | +#endif | ||
1538 | +#ifdef ZMQ_MECHANISM | ||
1539 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MECHANISM, mechanism, int); | ||
1540 | +#endif | ||
1541 | +#ifdef ZMQ_METADATA | ||
1542 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_METADATA, metadata); | ||
1543 | +#endif | ||
1544 | +#ifdef ZMQ_MULTICAST_HOPS | ||
1545 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_HOPS, multicast_hops, int); | ||
1546 | +#endif | ||
1547 | +#ifdef ZMQ_MULTICAST_LOOP | ||
1548 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_MULTICAST_LOOP, multicast_loop, int); | ||
1549 | +#endif | ||
1550 | +#ifdef ZMQ_MULTICAST_MAXTPDU | ||
1551 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_MAXTPDU, multicast_maxtpdu, int); | ||
1552 | +#endif | ||
1553 | +#ifdef ZMQ_PLAIN_SERVER | ||
1554 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PLAIN_SERVER, plain_server, int); | ||
1555 | +#endif | ||
1556 | +#ifdef ZMQ_PLAIN_PASSWORD | ||
1557 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_PASSWORD, plain_password); | ||
1558 | +#endif | ||
1559 | +#ifdef ZMQ_PLAIN_USERNAME | ||
1560 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_USERNAME, plain_username); | ||
1561 | +#endif | ||
1562 | +#ifdef ZMQ_USE_FD | ||
1563 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_USE_FD, use_fd, int); | ||
1564 | +#endif | ||
1565 | +#ifdef ZMQ_PROBE_ROUTER | ||
1566 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PROBE_ROUTER, probe_router, int); | ||
1567 | +#endif | ||
1568 | +#ifdef ZMQ_RATE | ||
1569 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RATE, rate, int); | ||
1570 | +#endif | ||
1571 | +#ifdef ZMQ_RCVBUF | ||
1572 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVBUF, rcvbuf, int); | ||
1573 | +#endif | ||
1574 | +#ifdef ZMQ_RCVHWM | ||
1575 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVHWM, rcvhwm, int); | ||
1576 | +#endif | ||
1577 | +#ifdef ZMQ_RCVMORE | ||
1578 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_RCVMORE, rcvmore, int); | ||
1579 | +#endif | ||
1580 | +#ifdef ZMQ_RCVTIMEO | ||
1581 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVTIMEO, rcvtimeo, int); | ||
1582 | +#endif | ||
1583 | +#ifdef ZMQ_RECONNECT_IVL | ||
1584 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL, reconnect_ivl, int); | ||
1585 | +#endif | ||
1586 | +#ifdef ZMQ_RECONNECT_IVL_MAX | ||
1587 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL_MAX, reconnect_ivl_max, int); | ||
1588 | +#endif | ||
1589 | +#ifdef ZMQ_RECOVERY_IVL | ||
1590 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECOVERY_IVL, recovery_ivl, int); | ||
1591 | +#endif | ||
1592 | +#ifdef ZMQ_REQ_CORRELATE | ||
1593 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_CORRELATE, req_correlate, int); | ||
1594 | +#endif | ||
1595 | +#ifdef ZMQ_REQ_RELAXED | ||
1596 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_RELAXED, req_relaxed, int); | ||
1597 | +#endif | ||
1598 | +#ifdef ZMQ_ROUTER_HANDOVER | ||
1599 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_HANDOVER, router_handover, int); | ||
1600 | +#endif | ||
1601 | +#ifdef ZMQ_ROUTER_MANDATORY | ||
1602 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_MANDATORY, router_mandatory, int); | ||
1603 | +#endif | ||
1604 | +#ifdef ZMQ_ROUTER_NOTIFY | ||
1605 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_ROUTER_NOTIFY, router_notify, int); | ||
1606 | +#endif | ||
1607 | +#ifdef ZMQ_ROUTING_ID | ||
1608 | +ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_ROUTING_ID, routing_id); | ||
1609 | +#endif | ||
1610 | +#ifdef ZMQ_SNDBUF | ||
1611 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDBUF, sndbuf, int); | ||
1612 | +#endif | ||
1613 | +#ifdef ZMQ_SNDHWM | ||
1614 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDHWM, sndhwm, int); | ||
1615 | +#endif | ||
1616 | +#ifdef ZMQ_SNDTIMEO | ||
1617 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDTIMEO, sndtimeo, int); | ||
1618 | +#endif | ||
1619 | +#ifdef ZMQ_SOCKS_PROXY | ||
1620 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PROXY, socks_proxy); | ||
1621 | +#endif | ||
1622 | +#ifdef ZMQ_STREAM_NOTIFY | ||
1623 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_STREAM_NOTIFY, stream_notify, int); | ||
1624 | +#endif | ||
1625 | +#ifdef ZMQ_SUBSCRIBE | ||
1626 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_SUBSCRIBE, subscribe); | ||
1627 | +#endif | ||
1628 | +#ifdef ZMQ_TCP_KEEPALIVE | ||
1629 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE, tcp_keepalive, int); | ||
1630 | +#endif | ||
1631 | +#ifdef ZMQ_TCP_KEEPALIVE_CNT | ||
1632 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_CNT, tcp_keepalive_cnt, int); | ||
1633 | +#endif | ||
1634 | +#ifdef ZMQ_TCP_KEEPALIVE_IDLE | ||
1635 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_IDLE, tcp_keepalive_idle, int); | ||
1636 | +#endif | ||
1637 | +#ifdef ZMQ_TCP_KEEPALIVE_INTVL | ||
1638 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_INTVL, tcp_keepalive_intvl, int); | ||
1639 | +#endif | ||
1640 | +#ifdef ZMQ_TCP_MAXRT | ||
1641 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_MAXRT, tcp_maxrt, int); | ||
1642 | +#endif | ||
1643 | +#ifdef ZMQ_THREAD_SAFE | ||
1644 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_THREAD_SAFE, thread_safe, int); | ||
1645 | +#endif | ||
1646 | +#ifdef ZMQ_TOS | ||
1647 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TOS, tos, int); | ||
1648 | +#endif | ||
1649 | +#ifdef ZMQ_TYPE | ||
1650 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, type, int); | ||
1651 | +#ifdef ZMQ_CPP11 | ||
1652 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, socket_type, socket_type); | ||
1653 | +#endif // ZMQ_CPP11 | ||
1654 | +#endif // ZMQ_TYPE | ||
1655 | +#ifdef ZMQ_UNSUBSCRIBE | ||
1656 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_UNSUBSCRIBE, unsubscribe); | ||
1657 | +#endif | ||
1658 | +#ifdef ZMQ_VMCI_BUFFER_SIZE | ||
1659 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_SIZE, vmci_buffer_size, uint64_t); | ||
1660 | +#endif | ||
1661 | +#ifdef ZMQ_VMCI_BUFFER_MIN_SIZE | ||
1662 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MIN_SIZE, vmci_buffer_min_size, uint64_t); | ||
1663 | +#endif | ||
1664 | +#ifdef ZMQ_VMCI_BUFFER_MAX_SIZE | ||
1665 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MAX_SIZE, vmci_buffer_max_size, uint64_t); | ||
1666 | +#endif | ||
1667 | +#ifdef ZMQ_VMCI_CONNECT_TIMEOUT | ||
1668 | +ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_CONNECT_TIMEOUT, vmci_connect_timeout, int); | ||
1669 | +#endif | ||
1670 | +#ifdef ZMQ_XPUB_VERBOSE | ||
1671 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSE, xpub_verbose, int); | ||
1672 | +#endif | ||
1673 | +#ifdef ZMQ_XPUB_VERBOSER | ||
1674 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSER, xpub_verboser, int); | ||
1675 | +#endif | ||
1676 | +#ifdef ZMQ_XPUB_MANUAL | ||
1677 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL, xpub_manual, int); | ||
1678 | +#endif | ||
1679 | +#ifdef ZMQ_XPUB_NODROP | ||
1680 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_NODROP, xpub_nodrop, int); | ||
1681 | +#endif | ||
1682 | +#ifdef ZMQ_XPUB_WELCOME_MSG | ||
1683 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_XPUB_WELCOME_MSG, xpub_welcome_msg); | ||
1684 | +#endif | ||
1685 | +#ifdef ZMQ_ZAP_ENFORCE_DOMAIN | ||
1686 | +ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ZAP_ENFORCE_DOMAIN, zap_enforce_domain, int); | ||
1687 | +#endif | ||
1688 | +#ifdef ZMQ_ZAP_DOMAIN | ||
1689 | +ZMQ_DEFINE_ARRAY_OPT(ZMQ_ZAP_DOMAIN, zap_domain); | ||
1690 | +#endif | ||
1691 | + | ||
1692 | +} // namespace sockopt | ||
1693 | +#endif // ZMQ_CPP11 | ||
1694 | + | ||
1695 | + | ||
1696 | +namespace detail | ||
1697 | +{ | ||
1698 | +class socket_base | ||
1699 | +{ | ||
1700 | + public: | ||
1701 | + socket_base() ZMQ_NOTHROW : _handle(ZMQ_NULLPTR) {} | ||
1702 | + ZMQ_EXPLICIT socket_base(void *handle) ZMQ_NOTHROW : _handle(handle) {} | ||
1703 | + | ||
1704 | + template<typename T> | ||
1705 | + ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt") | ||
1706 | + void setsockopt(int option_, T const &optval) | ||
1707 | + { | ||
1708 | + setsockopt(option_, &optval, sizeof(T)); | ||
1709 | + } | ||
1710 | + | ||
1711 | + ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt") | ||
1712 | + void setsockopt(int option_, const void *optval_, size_t optvallen_) | ||
1713 | + { | ||
1714 | + int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_); | ||
1715 | + if (rc != 0) | ||
1716 | + throw error_t(); | ||
1717 | + } | ||
1718 | + | ||
1719 | + ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt") | ||
1720 | + void getsockopt(int option_, void *optval_, size_t *optvallen_) const | ||
1721 | + { | ||
1722 | + int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_); | ||
1723 | + if (rc != 0) | ||
1724 | + throw error_t(); | ||
1725 | + } | ||
1726 | + | ||
1727 | + template<typename T> | ||
1728 | + ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt") | ||
1729 | + T getsockopt(int option_) const | ||
1730 | + { | ||
1731 | + T optval; | ||
1732 | + size_t optlen = sizeof(T); | ||
1733 | + getsockopt(option_, &optval, &optlen); | ||
1734 | + return optval; | ||
1735 | + } | ||
1736 | + | ||
1737 | +#ifdef ZMQ_CPP11 | ||
1738 | + // Set integral socket option, e.g. | ||
1739 | + // `socket.set(zmq::sockopt::linger, 0)` | ||
1740 | + template<int Opt, class T, bool BoolUnit> | ||
1741 | + void set(sockopt::integral_option<Opt, T, BoolUnit>, const T &val) | ||
1742 | + { | ||
1743 | + static_assert(std::is_integral<T>::value, "T must be integral"); | ||
1744 | + set_option(Opt, &val, sizeof val); | ||
1745 | + } | ||
1746 | + | ||
1747 | + // Set integral socket option from boolean, e.g. | ||
1748 | + // `socket.set(zmq::sockopt::immediate, false)` | ||
1749 | + template<int Opt, class T> | ||
1750 | + void set(sockopt::integral_option<Opt, T, true>, bool val) | ||
1751 | + { | ||
1752 | + static_assert(std::is_integral<T>::value, "T must be integral"); | ||
1753 | + T rep_val = val; | ||
1754 | + set_option(Opt, &rep_val, sizeof rep_val); | ||
1755 | + } | ||
1756 | + | ||
1757 | + // Set array socket option, e.g. | ||
1758 | + // `socket.set(zmq::sockopt::plain_username, "foo123")` | ||
1759 | + template<int Opt, int NullTerm> | ||
1760 | + void set(sockopt::array_option<Opt, NullTerm>, const char *buf) | ||
1761 | + { | ||
1762 | + set_option(Opt, buf, std::strlen(buf)); | ||
1763 | + } | ||
1764 | + | ||
1765 | + // Set array socket option, e.g. | ||
1766 | + // `socket.set(zmq::sockopt::routing_id, zmq::buffer(id))` | ||
1767 | + template<int Opt, int NullTerm> | ||
1768 | + void set(sockopt::array_option<Opt, NullTerm>, const_buffer buf) | ||
1769 | + { | ||
1770 | + set_option(Opt, buf.data(), buf.size()); | ||
1771 | + } | ||
1772 | + | ||
1773 | + // Set array socket option, e.g. | ||
1774 | + // `socket.set(zmq::sockopt::routing_id, id_str)` | ||
1775 | + template<int Opt, int NullTerm> | ||
1776 | + void set(sockopt::array_option<Opt, NullTerm>, const std::string &buf) | ||
1777 | + { | ||
1778 | + set_option(Opt, buf.data(), buf.size()); | ||
1779 | + } | ||
1780 | + | ||
1781 | +#if CPPZMQ_HAS_STRING_VIEW | ||
1782 | + // Set array socket option, e.g. | ||
1783 | + // `socket.set(zmq::sockopt::routing_id, id_str)` | ||
1784 | + template<int Opt, int NullTerm> | ||
1785 | + void set(sockopt::array_option<Opt, NullTerm>, std::string_view buf) | ||
1786 | + { | ||
1787 | + set_option(Opt, buf.data(), buf.size()); | ||
1788 | + } | ||
1789 | +#endif | ||
1790 | + | ||
1791 | + // Get scalar socket option, e.g. | ||
1792 | + // `auto opt = socket.get(zmq::sockopt::linger)` | ||
1793 | + template<int Opt, class T, bool BoolUnit> | ||
1794 | + ZMQ_NODISCARD T get(sockopt::integral_option<Opt, T, BoolUnit>) const | ||
1795 | + { | ||
1796 | + static_assert(std::is_scalar<T>::value, "T must be scalar"); | ||
1797 | + T val; | ||
1798 | + size_t size = sizeof val; | ||
1799 | + get_option(Opt, &val, &size); | ||
1800 | + assert(size == sizeof val); | ||
1801 | + return val; | ||
1802 | + } | ||
1803 | + | ||
1804 | + // Get array socket option, writes to buf, returns option size in bytes, e.g. | ||
1805 | + // `size_t optsize = socket.get(zmq::sockopt::routing_id, zmq::buffer(id))` | ||
1806 | + template<int Opt, int NullTerm> | ||
1807 | + ZMQ_NODISCARD size_t get(sockopt::array_option<Opt, NullTerm>, | ||
1808 | + mutable_buffer buf) const | ||
1809 | + { | ||
1810 | + size_t size = buf.size(); | ||
1811 | + get_option(Opt, buf.data(), &size); | ||
1812 | + return size; | ||
1813 | + } | ||
1814 | + | ||
1815 | + // Get array socket option as string (initializes the string buffer size to init_size) e.g. | ||
1816 | + // `auto s = socket.get(zmq::sockopt::routing_id)` | ||
1817 | + // Note: removes the null character from null-terminated string options, | ||
1818 | + // i.e. the string size excludes the null character. | ||
1819 | + template<int Opt, int NullTerm> | ||
1820 | + ZMQ_NODISCARD std::string get(sockopt::array_option<Opt, NullTerm>, | ||
1821 | + size_t init_size = 1024) const | ||
1822 | + { | ||
1823 | + if ZMQ_CONSTEXPR_IF (NullTerm == 2) { | ||
1824 | + if (init_size == 1024) { | ||
1825 | + init_size = 41; // get as Z85 string | ||
1826 | + } | ||
1827 | + } | ||
1828 | + std::string str(init_size, '\0'); | ||
1829 | + size_t size = get(sockopt::array_option<Opt>{}, buffer(str)); | ||
1830 | + if ZMQ_CONSTEXPR_IF (NullTerm == 1) { | ||
1831 | + if (size > 0) { | ||
1832 | + assert(str[size - 1] == '\0'); | ||
1833 | + --size; | ||
1834 | + } | ||
1835 | + } else if ZMQ_CONSTEXPR_IF (NullTerm == 2) { | ||
1836 | + assert(size == 32 || size == 41); | ||
1837 | + if (size == 41) { | ||
1838 | + assert(str[size - 1] == '\0'); | ||
1839 | + --size; | ||
1840 | + } | ||
1841 | + } | ||
1842 | + str.resize(size); | ||
1843 | + return str; | ||
1844 | + } | ||
1845 | +#endif | ||
1846 | + | ||
1847 | + void bind(std::string const &addr) { bind(addr.c_str()); } | ||
1848 | + | ||
1849 | + void bind(const char *addr_) | ||
1850 | + { | ||
1851 | + int rc = zmq_bind(_handle, addr_); | ||
1852 | + if (rc != 0) | ||
1853 | + throw error_t(); | ||
1854 | + } | ||
1855 | + | ||
1856 | + void unbind(std::string const &addr) { unbind(addr.c_str()); } | ||
1857 | + | ||
1858 | + void unbind(const char *addr_) | ||
1859 | + { | ||
1860 | + int rc = zmq_unbind(_handle, addr_); | ||
1861 | + if (rc != 0) | ||
1862 | + throw error_t(); | ||
1863 | + } | ||
1864 | + | ||
1865 | + void connect(std::string const &addr) { connect(addr.c_str()); } | ||
1866 | + | ||
1867 | + void connect(const char *addr_) | ||
1868 | + { | ||
1869 | + int rc = zmq_connect(_handle, addr_); | ||
1870 | + if (rc != 0) | ||
1871 | + throw error_t(); | ||
1872 | + } | ||
1873 | + | ||
1874 | + void disconnect(std::string const &addr) { disconnect(addr.c_str()); } | ||
1875 | + | ||
1876 | + void disconnect(const char *addr_) | ||
1877 | + { | ||
1878 | + int rc = zmq_disconnect(_handle, addr_); | ||
1879 | + if (rc != 0) | ||
1880 | + throw error_t(); | ||
1881 | + } | ||
1882 | + | ||
1883 | + ZMQ_DEPRECATED("from 4.7.1, use handle() != nullptr or operator bool") | ||
1884 | + bool connected() const ZMQ_NOTHROW { return (_handle != ZMQ_NULLPTR); } | ||
1885 | + | ||
1886 | + ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking a const_buffer and send_flags") | ||
1887 | + size_t send(const void *buf_, size_t len_, int flags_ = 0) | ||
1888 | + { | ||
1889 | + int nbytes = zmq_send(_handle, buf_, len_, flags_); | ||
1890 | + if (nbytes >= 0) | ||
1891 | + return static_cast<size_t>(nbytes); | ||
1892 | + if (zmq_errno() == EAGAIN) | ||
1893 | + return 0; | ||
1894 | + throw error_t(); | ||
1895 | + } | ||
1896 | + | ||
1897 | + ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags") | ||
1898 | + bool send(message_t &msg_, | ||
1899 | + int flags_ = 0) // default until removed | ||
1900 | + { | ||
1901 | + int nbytes = zmq_msg_send(msg_.handle(), _handle, flags_); | ||
1902 | + if (nbytes >= 0) | ||
1903 | + return true; | ||
1904 | + if (zmq_errno() == EAGAIN) | ||
1905 | + return false; | ||
1906 | + throw error_t(); | ||
1907 | + } | ||
1908 | + | ||
1909 | + template<typename T> | ||
1910 | + ZMQ_CPP11_DEPRECATED( | ||
1911 | + "from 4.4.1, use send taking message_t or buffer (for contiguous " | ||
1912 | + "ranges), and send_flags") | ||
1913 | + bool send(T first, T last, int flags_ = 0) | ||
1914 | + { | ||
1915 | + zmq::message_t msg(first, last); | ||
1916 | + int nbytes = zmq_msg_send(msg.handle(), _handle, flags_); | ||
1917 | + if (nbytes >= 0) | ||
1918 | + return true; | ||
1919 | + if (zmq_errno() == EAGAIN) | ||
1920 | + return false; | ||
1921 | + throw error_t(); | ||
1922 | + } | ||
1923 | + | ||
1924 | +#ifdef ZMQ_HAS_RVALUE_REFS | ||
1925 | + ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags") | ||
1926 | + bool send(message_t &&msg_, | ||
1927 | + int flags_ = 0) // default until removed | ||
1928 | + { | ||
1929 | +#ifdef ZMQ_CPP11 | ||
1930 | + return send(msg_, static_cast<send_flags>(flags_)).has_value(); | ||
1931 | +#else | ||
1932 | + return send(msg_, flags_); | ||
1933 | +#endif | ||
1934 | + } | ||
1935 | +#endif | ||
1936 | + | ||
1937 | +#ifdef ZMQ_CPP11 | ||
1938 | + send_result_t send(const_buffer buf, send_flags flags = send_flags::none) | ||
1939 | + { | ||
1940 | + const int nbytes = | ||
1941 | + zmq_send(_handle, buf.data(), buf.size(), static_cast<int>(flags)); | ||
1942 | + if (nbytes >= 0) | ||
1943 | + return static_cast<size_t>(nbytes); | ||
1944 | + if (zmq_errno() == EAGAIN) | ||
1945 | + return {}; | ||
1946 | + throw error_t(); | ||
1947 | + } | ||
1948 | + | ||
1949 | + send_result_t send(message_t &msg, send_flags flags) | ||
1950 | + { | ||
1951 | + int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast<int>(flags)); | ||
1952 | + if (nbytes >= 0) | ||
1953 | + return static_cast<size_t>(nbytes); | ||
1954 | + if (zmq_errno() == EAGAIN) | ||
1955 | + return {}; | ||
1956 | + throw error_t(); | ||
1957 | + } | ||
1958 | + | ||
1959 | + send_result_t send(message_t &&msg, send_flags flags) | ||
1960 | + { | ||
1961 | + return send(msg, flags); | ||
1962 | + } | ||
1963 | +#endif | ||
1964 | + | ||
1965 | + ZMQ_CPP11_DEPRECATED( | ||
1966 | + "from 4.3.1, use recv taking a mutable_buffer and recv_flags") | ||
1967 | + size_t recv(void *buf_, size_t len_, int flags_ = 0) | ||
1968 | + { | ||
1969 | + int nbytes = zmq_recv(_handle, buf_, len_, flags_); | ||
1970 | + if (nbytes >= 0) | ||
1971 | + return static_cast<size_t>(nbytes); | ||
1972 | + if (zmq_errno() == EAGAIN) | ||
1973 | + return 0; | ||
1974 | + throw error_t(); | ||
1975 | + } | ||
1976 | + | ||
1977 | + ZMQ_CPP11_DEPRECATED( | ||
1978 | + "from 4.3.1, use recv taking a reference to message_t and recv_flags") | ||
1979 | + bool recv(message_t *msg_, int flags_ = 0) | ||
1980 | + { | ||
1981 | + int nbytes = zmq_msg_recv(msg_->handle(), _handle, flags_); | ||
1982 | + if (nbytes >= 0) | ||
1983 | + return true; | ||
1984 | + if (zmq_errno() == EAGAIN) | ||
1985 | + return false; | ||
1986 | + throw error_t(); | ||
1987 | + } | ||
1988 | + | ||
1989 | +#ifdef ZMQ_CPP11 | ||
1990 | + ZMQ_NODISCARD | ||
1991 | + recv_buffer_result_t recv(mutable_buffer buf, | ||
1992 | + recv_flags flags = recv_flags::none) | ||
1993 | + { | ||
1994 | + const int nbytes = | ||
1995 | + zmq_recv(_handle, buf.data(), buf.size(), static_cast<int>(flags)); | ||
1996 | + if (nbytes >= 0) { | ||
1997 | + return recv_buffer_size{ | ||
1998 | + (std::min)(static_cast<size_t>(nbytes), buf.size()), | ||
1999 | + static_cast<size_t>(nbytes)}; | ||
2000 | + } | ||
2001 | + if (zmq_errno() == EAGAIN) | ||
2002 | + return {}; | ||
2003 | + throw error_t(); | ||
2004 | + } | ||
2005 | + | ||
2006 | + ZMQ_NODISCARD | ||
2007 | + recv_result_t recv(message_t &msg, recv_flags flags = recv_flags::none) | ||
2008 | + { | ||
2009 | + const int nbytes = | ||
2010 | + zmq_msg_recv(msg.handle(), _handle, static_cast<int>(flags)); | ||
2011 | + if (nbytes >= 0) { | ||
2012 | + assert(msg.size() == static_cast<size_t>(nbytes)); | ||
2013 | + return static_cast<size_t>(nbytes); | ||
2014 | + } | ||
2015 | + if (zmq_errno() == EAGAIN) | ||
2016 | + return {}; | ||
2017 | + throw error_t(); | ||
2018 | + } | ||
2019 | +#endif | ||
2020 | + | ||
2021 | +#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0) | ||
2022 | + void join(const char *group) | ||
2023 | + { | ||
2024 | + int rc = zmq_join(_handle, group); | ||
2025 | + if (rc != 0) | ||
2026 | + throw error_t(); | ||
2027 | + } | ||
2028 | + | ||
2029 | + void leave(const char *group) | ||
2030 | + { | ||
2031 | + int rc = zmq_leave(_handle, group); | ||
2032 | + if (rc != 0) | ||
2033 | + throw error_t(); | ||
2034 | + } | ||
2035 | +#endif | ||
2036 | + | ||
2037 | + ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return _handle; } | ||
2038 | + ZMQ_NODISCARD const void *handle() const ZMQ_NOTHROW { return _handle; } | ||
2039 | + | ||
2040 | + ZMQ_EXPLICIT operator bool() const ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; } | ||
2041 | + // note: non-const operator bool can be removed once | ||
2042 | + // operator void* is removed from socket_t | ||
2043 | + ZMQ_EXPLICIT operator bool() ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; } | ||
2044 | + | ||
2045 | + protected: | ||
2046 | + void *_handle; | ||
2047 | + | ||
2048 | + private: | ||
2049 | + void set_option(int option_, const void *optval_, size_t optvallen_) | ||
2050 | + { | ||
2051 | + int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_); | ||
2052 | + if (rc != 0) | ||
2053 | + throw error_t(); | ||
2054 | + } | ||
2055 | + | ||
2056 | + void get_option(int option_, void *optval_, size_t *optvallen_) const | ||
2057 | + { | ||
2058 | + int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_); | ||
2059 | + if (rc != 0) | ||
2060 | + throw error_t(); | ||
2061 | + } | ||
2062 | +}; | ||
2063 | +} // namespace detail | ||
2064 | + | ||
2065 | +struct from_handle_t | ||
2066 | +{ | ||
2067 | + struct _private | ||
2068 | + { | ||
2069 | + }; // disabling use other than with from_handle | ||
2070 | + ZMQ_CONSTEXPR_FN ZMQ_EXPLICIT from_handle_t(_private /*p*/) ZMQ_NOTHROW {} | ||
2071 | +}; | ||
2072 | + | ||
2073 | +ZMQ_CONSTEXPR_VAR from_handle_t from_handle = | ||
2074 | + from_handle_t(from_handle_t::_private()); | ||
2075 | + | ||
2076 | +// A non-owning nullable reference to a socket. | ||
2077 | +// The reference is invalidated on socket close or destruction. | ||
2078 | +class socket_ref : public detail::socket_base | ||
2079 | +{ | ||
2080 | + public: | ||
2081 | + socket_ref() ZMQ_NOTHROW : detail::socket_base() {} | ||
2082 | +#ifdef ZMQ_CPP11 | ||
2083 | + socket_ref(std::nullptr_t) ZMQ_NOTHROW : detail::socket_base() {} | ||
2084 | +#endif | ||
2085 | + socket_ref(from_handle_t /*fh*/, void *handle) ZMQ_NOTHROW | ||
2086 | + : detail::socket_base(handle) | ||
2087 | + { | ||
2088 | + } | ||
2089 | +}; | ||
2090 | + | ||
2091 | +#ifdef ZMQ_CPP11 | ||
2092 | +inline bool operator==(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW | ||
2093 | +{ | ||
2094 | + return sr.handle() == nullptr; | ||
2095 | +} | ||
2096 | +inline bool operator==(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW | ||
2097 | +{ | ||
2098 | + return sr.handle() == nullptr; | ||
2099 | +} | ||
2100 | +inline bool operator!=(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW | ||
2101 | +{ | ||
2102 | + return !(sr == nullptr); | ||
2103 | +} | ||
2104 | +inline bool operator!=(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW | ||
2105 | +{ | ||
2106 | + return !(sr == nullptr); | ||
2107 | +} | ||
2108 | +#endif | ||
2109 | + | ||
2110 | +inline bool operator==(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW | ||
2111 | +{ | ||
2112 | + return std::equal_to<const void *>()(a.handle(), b.handle()); | ||
2113 | +} | ||
2114 | +inline bool operator!=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW | ||
2115 | +{ | ||
2116 | + return !(a == b); | ||
2117 | +} | ||
2118 | +inline bool operator<(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW | ||
2119 | +{ | ||
2120 | + return std::less<const void *>()(a.handle(), b.handle()); | ||
2121 | +} | ||
2122 | +inline bool operator>(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW | ||
2123 | +{ | ||
2124 | + return b < a; | ||
2125 | +} | ||
2126 | +inline bool operator<=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW | ||
2127 | +{ | ||
2128 | + return !(a > b); | ||
2129 | +} | ||
2130 | +inline bool operator>=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW | ||
2131 | +{ | ||
2132 | + return !(a < b); | ||
2133 | +} | ||
2134 | + | ||
2135 | +} // namespace zmq | ||
2136 | + | ||
2137 | +#ifdef ZMQ_CPP11 | ||
2138 | +namespace std | ||
2139 | +{ | ||
2140 | +template<> struct hash<zmq::socket_ref> | ||
2141 | +{ | ||
2142 | + size_t operator()(zmq::socket_ref sr) const ZMQ_NOTHROW | ||
2143 | + { | ||
2144 | + return hash<void *>()(sr.handle()); | ||
2145 | + } | ||
2146 | +}; | ||
2147 | +} // namespace std | ||
2148 | +#endif | ||
2149 | + | ||
2150 | +namespace zmq | ||
2151 | +{ | ||
2152 | +class socket_t : public detail::socket_base | ||
2153 | +{ | ||
2154 | + friend class monitor_t; | ||
2155 | + | ||
2156 | + public: | ||
2157 | + socket_t() ZMQ_NOTHROW : detail::socket_base(ZMQ_NULLPTR), ctxptr(ZMQ_NULLPTR) {} | ||
2158 | + | ||
2159 | + socket_t(context_t &context_, int type_) : | ||
2160 | + detail::socket_base(zmq_socket(context_.handle(), type_)), | ||
2161 | + ctxptr(context_.handle()) | ||
2162 | + { | ||
2163 | + if (_handle == ZMQ_NULLPTR) | ||
2164 | + throw error_t(); | ||
2165 | + } | ||
2166 | + | ||
2167 | +#ifdef ZMQ_CPP11 | ||
2168 | + socket_t(context_t &context_, socket_type type_) : | ||
2169 | + socket_t(context_, static_cast<int>(type_)) | ||
2170 | + { | ||
2171 | + } | ||
2172 | +#endif | ||
2173 | + | ||
2174 | +#ifdef ZMQ_HAS_RVALUE_REFS | ||
2175 | + socket_t(socket_t &&rhs) ZMQ_NOTHROW : detail::socket_base(rhs._handle), | ||
2176 | + ctxptr(rhs.ctxptr) | ||
2177 | + { | ||
2178 | + rhs._handle = ZMQ_NULLPTR; | ||
2179 | + rhs.ctxptr = ZMQ_NULLPTR; | ||
2180 | + } | ||
2181 | + socket_t &operator=(socket_t &&rhs) ZMQ_NOTHROW | ||
2182 | + { | ||
2183 | + close(); | ||
2184 | + std::swap(_handle, rhs._handle); | ||
2185 | + std::swap(ctxptr, rhs.ctxptr); | ||
2186 | + return *this; | ||
2187 | + } | ||
2188 | +#endif | ||
2189 | + | ||
2190 | + ~socket_t() ZMQ_NOTHROW { close(); } | ||
2191 | + | ||
2192 | + operator void *() ZMQ_NOTHROW { return _handle; } | ||
2193 | + | ||
2194 | + operator void const *() const ZMQ_NOTHROW { return _handle; } | ||
2195 | + | ||
2196 | + void close() ZMQ_NOTHROW | ||
2197 | + { | ||
2198 | + if (_handle == ZMQ_NULLPTR) | ||
2199 | + // already closed | ||
2200 | + return; | ||
2201 | + int rc = zmq_close(_handle); | ||
2202 | + ZMQ_ASSERT(rc == 0); | ||
2203 | + _handle = ZMQ_NULLPTR; | ||
2204 | + ctxptr = ZMQ_NULLPTR; | ||
2205 | + } | ||
2206 | + | ||
2207 | + void swap(socket_t &other) ZMQ_NOTHROW | ||
2208 | + { | ||
2209 | + std::swap(_handle, other._handle); | ||
2210 | + std::swap(ctxptr, other.ctxptr); | ||
2211 | + } | ||
2212 | + | ||
2213 | + operator socket_ref() ZMQ_NOTHROW { return socket_ref(from_handle, _handle); } | ||
2214 | + | ||
2215 | + private: | ||
2216 | + void *ctxptr; | ||
2217 | + | ||
2218 | + socket_t(const socket_t &) ZMQ_DELETED_FUNCTION; | ||
2219 | + void operator=(const socket_t &) ZMQ_DELETED_FUNCTION; | ||
2220 | + | ||
2221 | + // used by monitor_t | ||
2222 | + socket_t(void *context_, int type_) : | ||
2223 | + detail::socket_base(zmq_socket(context_, type_)), ctxptr(context_) | ||
2224 | + { | ||
2225 | + if (_handle == ZMQ_NULLPTR) | ||
2226 | + throw error_t(); | ||
2227 | + if (ctxptr == ZMQ_NULLPTR) | ||
2228 | + throw error_t(); | ||
2229 | + } | ||
2230 | +}; | ||
2231 | + | ||
2232 | +inline void swap(socket_t &a, socket_t &b) ZMQ_NOTHROW | ||
2233 | +{ | ||
2234 | + a.swap(b); | ||
2235 | +} | ||
2236 | + | ||
2237 | +ZMQ_DEPRECATED("from 4.3.1, use proxy taking socket_t objects") | ||
2238 | +inline void proxy(void *frontend, void *backend, void *capture) | ||
2239 | +{ | ||
2240 | + int rc = zmq_proxy(frontend, backend, capture); | ||
2241 | + if (rc != 0) | ||
2242 | + throw error_t(); | ||
2243 | +} | ||
2244 | + | ||
2245 | +inline void | ||
2246 | +proxy(socket_ref frontend, socket_ref backend, socket_ref capture = socket_ref()) | ||
2247 | +{ | ||
2248 | + int rc = zmq_proxy(frontend.handle(), backend.handle(), capture.handle()); | ||
2249 | + if (rc != 0) | ||
2250 | + throw error_t(); | ||
2251 | +} | ||
2252 | + | ||
2253 | +#ifdef ZMQ_HAS_PROXY_STEERABLE | ||
2254 | +ZMQ_DEPRECATED("from 4.3.1, use proxy_steerable taking socket_t objects") | ||
2255 | +inline void | ||
2256 | +proxy_steerable(void *frontend, void *backend, void *capture, void *control) | ||
2257 | +{ | ||
2258 | + int rc = zmq_proxy_steerable(frontend, backend, capture, control); | ||
2259 | + if (rc != 0) | ||
2260 | + throw error_t(); | ||
2261 | +} | ||
2262 | + | ||
2263 | +inline void proxy_steerable(socket_ref frontend, | ||
2264 | + socket_ref backend, | ||
2265 | + socket_ref capture, | ||
2266 | + socket_ref control) | ||
2267 | +{ | ||
2268 | + int rc = zmq_proxy_steerable(frontend.handle(), backend.handle(), | ||
2269 | + capture.handle(), control.handle()); | ||
2270 | + if (rc != 0) | ||
2271 | + throw error_t(); | ||
2272 | +} | ||
2273 | +#endif | ||
2274 | + | ||
2275 | +class monitor_t | ||
2276 | +{ | ||
2277 | + public: | ||
2278 | + monitor_t() : _socket(), _monitor_socket() {} | ||
2279 | + | ||
2280 | + virtual ~monitor_t() { close(); } | ||
2281 | + | ||
2282 | +#ifdef ZMQ_HAS_RVALUE_REFS | ||
2283 | + monitor_t(monitor_t &&rhs) ZMQ_NOTHROW : _socket(), _monitor_socket() | ||
2284 | + { | ||
2285 | + std::swap(_socket, rhs._socket); | ||
2286 | + std::swap(_monitor_socket, rhs._monitor_socket); | ||
2287 | + } | ||
2288 | + | ||
2289 | + monitor_t &operator=(monitor_t &&rhs) ZMQ_NOTHROW | ||
2290 | + { | ||
2291 | + close(); | ||
2292 | + _socket = socket_ref(); | ||
2293 | + std::swap(_socket, rhs._socket); | ||
2294 | + std::swap(_monitor_socket, rhs._monitor_socket); | ||
2295 | + return *this; | ||
2296 | + } | ||
2297 | +#endif | ||
2298 | + | ||
2299 | + | ||
2300 | + void | ||
2301 | + monitor(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL) | ||
2302 | + { | ||
2303 | + monitor(socket, addr.c_str(), events); | ||
2304 | + } | ||
2305 | + | ||
2306 | + void monitor(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL) | ||
2307 | + { | ||
2308 | + init(socket, addr_, events); | ||
2309 | + while (true) { | ||
2310 | + check_event(-1); | ||
2311 | + } | ||
2312 | + } | ||
2313 | + | ||
2314 | + void init(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL) | ||
2315 | + { | ||
2316 | + init(socket, addr.c_str(), events); | ||
2317 | + } | ||
2318 | + | ||
2319 | + void init(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL) | ||
2320 | + { | ||
2321 | + int rc = zmq_socket_monitor(socket.handle(), addr_, events); | ||
2322 | + if (rc != 0) | ||
2323 | + throw error_t(); | ||
2324 | + | ||
2325 | + _socket = socket; | ||
2326 | + _monitor_socket = socket_t(socket.ctxptr, ZMQ_PAIR); | ||
2327 | + _monitor_socket.connect(addr_); | ||
2328 | + | ||
2329 | + on_monitor_started(); | ||
2330 | + } | ||
2331 | + | ||
2332 | + bool check_event(int timeout = 0) | ||
2333 | + { | ||
2334 | + assert(_monitor_socket); | ||
2335 | + | ||
2336 | + zmq::message_t eventMsg; | ||
2337 | + | ||
2338 | + zmq::pollitem_t items[] = { | ||
2339 | + {_monitor_socket.handle(), 0, ZMQ_POLLIN, 0}, | ||
2340 | + }; | ||
2341 | + | ||
2342 | + #ifdef ZMQ_CPP11 | ||
2343 | + zmq::poll(&items[0], 1, std::chrono::milliseconds(timeout)); | ||
2344 | + #else | ||
2345 | + zmq::poll(&items[0], 1, timeout); | ||
2346 | + #endif | ||
2347 | + | ||
2348 | + if (items[0].revents & ZMQ_POLLIN) { | ||
2349 | + int rc = zmq_msg_recv(eventMsg.handle(), _monitor_socket.handle(), 0); | ||
2350 | + if (rc == -1 && zmq_errno() == ETERM) | ||
2351 | + return false; | ||
2352 | + assert(rc != -1); | ||
2353 | + | ||
2354 | + } else { | ||
2355 | + return false; | ||
2356 | + } | ||
2357 | + | ||
2358 | +#if ZMQ_VERSION_MAJOR >= 4 | ||
2359 | + const char *data = static_cast<const char *>(eventMsg.data()); | ||
2360 | + zmq_event_t msgEvent; | ||
2361 | + memcpy(&msgEvent.event, data, sizeof(uint16_t)); | ||
2362 | + data += sizeof(uint16_t); | ||
2363 | + memcpy(&msgEvent.value, data, sizeof(int32_t)); | ||
2364 | + zmq_event_t *event = &msgEvent; | ||
2365 | +#else | ||
2366 | + zmq_event_t *event = static_cast<zmq_event_t *>(eventMsg.data()); | ||
2367 | +#endif | ||
2368 | + | ||
2369 | +#ifdef ZMQ_NEW_MONITOR_EVENT_LAYOUT | ||
2370 | + zmq::message_t addrMsg; | ||
2371 | + int rc = zmq_msg_recv(addrMsg.handle(), _monitor_socket.handle(), 0); | ||
2372 | + if (rc == -1 && zmq_errno() == ETERM) { | ||
2373 | + return false; | ||
2374 | + } | ||
2375 | + | ||
2376 | + assert(rc != -1); | ||
2377 | + std::string address = addrMsg.to_string(); | ||
2378 | +#else | ||
2379 | + // 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. | ||
2380 | + std::string address = event->data.connected.addr; | ||
2381 | +#endif | ||
2382 | + | ||
2383 | +#ifdef ZMQ_EVENT_MONITOR_STOPPED | ||
2384 | + if (event->event == ZMQ_EVENT_MONITOR_STOPPED) { | ||
2385 | + return false; | ||
2386 | + } | ||
2387 | + | ||
2388 | +#endif | ||
2389 | + | ||
2390 | + switch (event->event) { | ||
2391 | + case ZMQ_EVENT_CONNECTED: | ||
2392 | + on_event_connected(*event, address.c_str()); | ||
2393 | + break; | ||
2394 | + case ZMQ_EVENT_CONNECT_DELAYED: | ||
2395 | + on_event_connect_delayed(*event, address.c_str()); | ||
2396 | + break; | ||
2397 | + case ZMQ_EVENT_CONNECT_RETRIED: | ||
2398 | + on_event_connect_retried(*event, address.c_str()); | ||
2399 | + break; | ||
2400 | + case ZMQ_EVENT_LISTENING: | ||
2401 | + on_event_listening(*event, address.c_str()); | ||
2402 | + break; | ||
2403 | + case ZMQ_EVENT_BIND_FAILED: | ||
2404 | + on_event_bind_failed(*event, address.c_str()); | ||
2405 | + break; | ||
2406 | + case ZMQ_EVENT_ACCEPTED: | ||
2407 | + on_event_accepted(*event, address.c_str()); | ||
2408 | + break; | ||
2409 | + case ZMQ_EVENT_ACCEPT_FAILED: | ||
2410 | + on_event_accept_failed(*event, address.c_str()); | ||
2411 | + break; | ||
2412 | + case ZMQ_EVENT_CLOSED: | ||
2413 | + on_event_closed(*event, address.c_str()); | ||
2414 | + break; | ||
2415 | + case ZMQ_EVENT_CLOSE_FAILED: | ||
2416 | + on_event_close_failed(*event, address.c_str()); | ||
2417 | + break; | ||
2418 | + case ZMQ_EVENT_DISCONNECTED: | ||
2419 | + on_event_disconnected(*event, address.c_str()); | ||
2420 | + break; | ||
2421 | +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 0) || (defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)) | ||
2422 | + case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL: | ||
2423 | + on_event_handshake_failed_no_detail(*event, address.c_str()); | ||
2424 | + break; | ||
2425 | + case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL: | ||
2426 | + on_event_handshake_failed_protocol(*event, address.c_str()); | ||
2427 | + break; | ||
2428 | + case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH: | ||
2429 | + on_event_handshake_failed_auth(*event, address.c_str()); | ||
2430 | + break; | ||
2431 | + case ZMQ_EVENT_HANDSHAKE_SUCCEEDED: | ||
2432 | + on_event_handshake_succeeded(*event, address.c_str()); | ||
2433 | + break; | ||
2434 | +#elif defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1) | ||
2435 | + case ZMQ_EVENT_HANDSHAKE_FAILED: | ||
2436 | + on_event_handshake_failed(*event, address.c_str()); | ||
2437 | + break; | ||
2438 | + case ZMQ_EVENT_HANDSHAKE_SUCCEED: | ||
2439 | + on_event_handshake_succeed(*event, address.c_str()); | ||
2440 | + break; | ||
2441 | +#endif | ||
2442 | + default: | ||
2443 | + on_event_unknown(*event, address.c_str()); | ||
2444 | + break; | ||
2445 | + } | ||
2446 | + | ||
2447 | + return true; | ||
2448 | + } | ||
2449 | + | ||
2450 | +#ifdef ZMQ_EVENT_MONITOR_STOPPED | ||
2451 | + void abort() | ||
2452 | + { | ||
2453 | + if (_socket) | ||
2454 | + zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0); | ||
2455 | + | ||
2456 | + _socket = socket_ref(); | ||
2457 | + } | ||
2458 | +#endif | ||
2459 | + virtual void on_monitor_started() {} | ||
2460 | + virtual void on_event_connected(const zmq_event_t &event_, const char *addr_) | ||
2461 | + { | ||
2462 | + (void) event_; | ||
2463 | + (void) addr_; | ||
2464 | + } | ||
2465 | + virtual void on_event_connect_delayed(const zmq_event_t &event_, | ||
2466 | + const char *addr_) | ||
2467 | + { | ||
2468 | + (void) event_; | ||
2469 | + (void) addr_; | ||
2470 | + } | ||
2471 | + virtual void on_event_connect_retried(const zmq_event_t &event_, | ||
2472 | + const char *addr_) | ||
2473 | + { | ||
2474 | + (void) event_; | ||
2475 | + (void) addr_; | ||
2476 | + } | ||
2477 | + virtual void on_event_listening(const zmq_event_t &event_, const char *addr_) | ||
2478 | + { | ||
2479 | + (void) event_; | ||
2480 | + (void) addr_; | ||
2481 | + } | ||
2482 | + virtual void on_event_bind_failed(const zmq_event_t &event_, const char *addr_) | ||
2483 | + { | ||
2484 | + (void) event_; | ||
2485 | + (void) addr_; | ||
2486 | + } | ||
2487 | + virtual void on_event_accepted(const zmq_event_t &event_, const char *addr_) | ||
2488 | + { | ||
2489 | + (void) event_; | ||
2490 | + (void) addr_; | ||
2491 | + } | ||
2492 | + virtual void on_event_accept_failed(const zmq_event_t &event_, const char *addr_) | ||
2493 | + { | ||
2494 | + (void) event_; | ||
2495 | + (void) addr_; | ||
2496 | + } | ||
2497 | + virtual void on_event_closed(const zmq_event_t &event_, const char *addr_) | ||
2498 | + { | ||
2499 | + (void) event_; | ||
2500 | + (void) addr_; | ||
2501 | + } | ||
2502 | + virtual void on_event_close_failed(const zmq_event_t &event_, const char *addr_) | ||
2503 | + { | ||
2504 | + (void) event_; | ||
2505 | + (void) addr_; | ||
2506 | + } | ||
2507 | + virtual void on_event_disconnected(const zmq_event_t &event_, const char *addr_) | ||
2508 | + { | ||
2509 | + (void) event_; | ||
2510 | + (void) addr_; | ||
2511 | + } | ||
2512 | +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3) | ||
2513 | + virtual void on_event_handshake_failed_no_detail(const zmq_event_t &event_, | ||
2514 | + const char *addr_) | ||
2515 | + { | ||
2516 | + (void) event_; | ||
2517 | + (void) addr_; | ||
2518 | + } | ||
2519 | + virtual void on_event_handshake_failed_protocol(const zmq_event_t &event_, | ||
2520 | + const char *addr_) | ||
2521 | + { | ||
2522 | + (void) event_; | ||
2523 | + (void) addr_; | ||
2524 | + } | ||
2525 | + virtual void on_event_handshake_failed_auth(const zmq_event_t &event_, | ||
2526 | + const char *addr_) | ||
2527 | + { | ||
2528 | + (void) event_; | ||
2529 | + (void) addr_; | ||
2530 | + } | ||
2531 | + virtual void on_event_handshake_succeeded(const zmq_event_t &event_, | ||
2532 | + const char *addr_) | ||
2533 | + { | ||
2534 | + (void) event_; | ||
2535 | + (void) addr_; | ||
2536 | + } | ||
2537 | +#elif ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1) | ||
2538 | + virtual void on_event_handshake_failed(const zmq_event_t &event_, | ||
2539 | + const char *addr_) | ||
2540 | + { | ||
2541 | + (void) event_; | ||
2542 | + (void) addr_; | ||
2543 | + } | ||
2544 | + virtual void on_event_handshake_succeed(const zmq_event_t &event_, | ||
2545 | + const char *addr_) | ||
2546 | + { | ||
2547 | + (void) event_; | ||
2548 | + (void) addr_; | ||
2549 | + } | ||
2550 | +#endif | ||
2551 | + virtual void on_event_unknown(const zmq_event_t &event_, const char *addr_) | ||
2552 | + { | ||
2553 | + (void) event_; | ||
2554 | + (void) addr_; | ||
2555 | + } | ||
2556 | + | ||
2557 | + private: | ||
2558 | + monitor_t(const monitor_t &) ZMQ_DELETED_FUNCTION; | ||
2559 | + void operator=(const monitor_t &) ZMQ_DELETED_FUNCTION; | ||
2560 | + | ||
2561 | + socket_ref _socket; | ||
2562 | + socket_t _monitor_socket; | ||
2563 | + | ||
2564 | + void close() ZMQ_NOTHROW | ||
2565 | + { | ||
2566 | + if (_socket) | ||
2567 | + zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0); | ||
2568 | + _monitor_socket.close(); | ||
2569 | + } | ||
2570 | +}; | ||
2571 | + | ||
2572 | +#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) | ||
2573 | + | ||
2574 | +// polling events | ||
2575 | +enum class event_flags : short | ||
2576 | +{ | ||
2577 | + none = 0, | ||
2578 | + pollin = ZMQ_POLLIN, | ||
2579 | + pollout = ZMQ_POLLOUT, | ||
2580 | + pollerr = ZMQ_POLLERR, | ||
2581 | + pollpri = ZMQ_POLLPRI | ||
2582 | +}; | ||
2583 | + | ||
2584 | +constexpr event_flags operator|(event_flags a, event_flags b) noexcept | ||
2585 | +{ | ||
2586 | + return detail::enum_bit_or(a, b); | ||
2587 | +} | ||
2588 | +constexpr event_flags operator&(event_flags a, event_flags b) noexcept | ||
2589 | +{ | ||
2590 | + return detail::enum_bit_and(a, b); | ||
2591 | +} | ||
2592 | +constexpr event_flags operator^(event_flags a, event_flags b) noexcept | ||
2593 | +{ | ||
2594 | + return detail::enum_bit_xor(a, b); | ||
2595 | +} | ||
2596 | +constexpr event_flags operator~(event_flags a) noexcept | ||
2597 | +{ | ||
2598 | + return detail::enum_bit_not(a); | ||
2599 | +} | ||
2600 | + | ||
2601 | +struct no_user_data; | ||
2602 | + | ||
2603 | +// layout compatible with zmq_poller_event_t | ||
2604 | +template<class T = no_user_data> struct poller_event | ||
2605 | +{ | ||
2606 | + socket_ref socket; | ||
2607 | + ::zmq::fd_t fd; | ||
2608 | + T *user_data; | ||
2609 | + event_flags events; | ||
2610 | +}; | ||
2611 | + | ||
2612 | +template<typename T = no_user_data> class poller_t | ||
2613 | +{ | ||
2614 | + public: | ||
2615 | + using event_type = poller_event<T>; | ||
2616 | + | ||
2617 | + poller_t() : poller_ptr(zmq_poller_new()) | ||
2618 | + { | ||
2619 | + if (!poller_ptr) | ||
2620 | + throw error_t(); | ||
2621 | + } | ||
2622 | + | ||
2623 | + template< | ||
2624 | + typename Dummy = void, | ||
2625 | + typename = | ||
2626 | + typename std::enable_if<!std::is_same<T, no_user_data>::value, Dummy>::type> | ||
2627 | + void add(zmq::socket_ref socket, event_flags events, T *user_data) | ||
2628 | + { | ||
2629 | + add_impl(socket, events, user_data); | ||
2630 | + } | ||
2631 | + | ||
2632 | + void add(zmq::socket_ref socket, event_flags events) | ||
2633 | + { | ||
2634 | + add_impl(socket, events, nullptr); | ||
2635 | + } | ||
2636 | + | ||
2637 | + void remove(zmq::socket_ref socket) | ||
2638 | + { | ||
2639 | + if (0 != zmq_poller_remove(poller_ptr.get(), socket.handle())) { | ||
2640 | + throw error_t(); | ||
2641 | + } | ||
2642 | + } | ||
2643 | + | ||
2644 | + void modify(zmq::socket_ref socket, event_flags events) | ||
2645 | + { | ||
2646 | + if (0 | ||
2647 | + != zmq_poller_modify(poller_ptr.get(), socket.handle(), | ||
2648 | + static_cast<short>(events))) { | ||
2649 | + throw error_t(); | ||
2650 | + } | ||
2651 | + } | ||
2652 | + | ||
2653 | + size_t wait_all(std::vector<event_type> &poller_events, | ||
2654 | + const std::chrono::milliseconds timeout) | ||
2655 | + { | ||
2656 | + int rc = zmq_poller_wait_all( | ||
2657 | + poller_ptr.get(), | ||
2658 | + reinterpret_cast<zmq_poller_event_t *>(poller_events.data()), | ||
2659 | + static_cast<int>(poller_events.size()), | ||
2660 | + static_cast<long>(timeout.count())); | ||
2661 | + if (rc > 0) | ||
2662 | + return static_cast<size_t>(rc); | ||
2663 | + | ||
2664 | +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3) | ||
2665 | + if (zmq_errno() == EAGAIN) | ||
2666 | +#else | ||
2667 | + if (zmq_errno() == ETIMEDOUT) | ||
2668 | +#endif | ||
2669 | + return 0; | ||
2670 | + | ||
2671 | + throw error_t(); | ||
2672 | + } | ||
2673 | + | ||
2674 | +#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3) | ||
2675 | + size_t size() const noexcept | ||
2676 | + { | ||
2677 | + int rc = zmq_poller_size(const_cast<void *>(poller_ptr.get())); | ||
2678 | + ZMQ_ASSERT(rc >= 0); | ||
2679 | + return static_cast<size_t>(std::max(rc, 0)); | ||
2680 | + } | ||
2681 | +#endif | ||
2682 | + | ||
2683 | + private: | ||
2684 | + struct destroy_poller_t | ||
2685 | + { | ||
2686 | + void operator()(void *ptr) noexcept | ||
2687 | + { | ||
2688 | + int rc = zmq_poller_destroy(&ptr); | ||
2689 | + ZMQ_ASSERT(rc == 0); | ||
2690 | + } | ||
2691 | + }; | ||
2692 | + | ||
2693 | + std::unique_ptr<void, destroy_poller_t> poller_ptr; | ||
2694 | + | ||
2695 | + void add_impl(zmq::socket_ref socket, event_flags events, T *user_data) | ||
2696 | + { | ||
2697 | + if (0 | ||
2698 | + != zmq_poller_add(poller_ptr.get(), socket.handle(), user_data, | ||
2699 | + static_cast<short>(events))) { | ||
2700 | + throw error_t(); | ||
2701 | + } | ||
2702 | + } | ||
2703 | +}; | ||
2704 | +#endif // defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER) | ||
2705 | + | ||
2706 | +inline std::ostream &operator<<(std::ostream &os, const message_t &msg) | ||
2707 | +{ | ||
2708 | + return os << msg.str(); | ||
2709 | +} | ||
2710 | + | ||
2711 | +} // namespace zmq | ||
2712 | + | ||
2713 | +#endif // __ZMQ_HPP_INCLUDED__ |
-
Please register or login to post a comment