• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

zeromq / cppzmq / 6957349874

22 Nov 2023 12:34PM UTC coverage: 86.354% (-0.6%) from 86.965%
6957349874

Pull #565

github

web-flow
Merge 2fd8bfc74 into 6164cf7db
Pull Request #565: Remove ENABLE_DRAFTS option

848 of 982 relevant lines covered (86.35%)

23.35 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.88
/zmq.hpp
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 <type_traits>
112
#include <algorithm>
113
#include <exception>
114
#include <iomanip>
115
#include <sstream>
116
#include <string>
117
#include <vector>
118
#ifdef ZMQ_CPP11
119
#include <array>
120
#include <chrono>
121
#include <tuple>
122
#include <memory>
123
#endif
124

125
#if defined(__has_include) && defined(ZMQ_CPP17)
126
#define CPPZMQ_HAS_INCLUDE_CPP17(X) __has_include(X)
127
#else
128
#define CPPZMQ_HAS_INCLUDE_CPP17(X) 0
129
#endif
130

131
#if CPPZMQ_HAS_INCLUDE_CPP17(<optional>) && !defined(CPPZMQ_HAS_OPTIONAL)
132
#define CPPZMQ_HAS_OPTIONAL 1
133
#endif
134
#ifndef CPPZMQ_HAS_OPTIONAL
135
#define CPPZMQ_HAS_OPTIONAL 0
136
#elif CPPZMQ_HAS_OPTIONAL
137
#include <optional>
138
#endif
139

140
#if CPPZMQ_HAS_INCLUDE_CPP17(<string_view>) && !defined(CPPZMQ_HAS_STRING_VIEW)
141
#define CPPZMQ_HAS_STRING_VIEW 1
142
#endif
143
#ifndef CPPZMQ_HAS_STRING_VIEW
144
#define CPPZMQ_HAS_STRING_VIEW 0
145
#elif CPPZMQ_HAS_STRING_VIEW
146
#include <string_view>
147
#endif
148

149
/*  Version macros for compile-time API version detection                     */
150
#define CPPZMQ_VERSION_MAJOR 4
151
#define CPPZMQ_VERSION_MINOR 10
152
#define CPPZMQ_VERSION_PATCH 0
153

154
#define CPPZMQ_VERSION                                                              \
155
    ZMQ_MAKE_VERSION(CPPZMQ_VERSION_MAJOR, CPPZMQ_VERSION_MINOR,                    \
156
                     CPPZMQ_VERSION_PATCH)
157

158
//  Detect whether the compiler supports C++11 rvalue references.
159
#if (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2))   \
160
     && defined(__GXX_EXPERIMENTAL_CXX0X__))
161
#define ZMQ_HAS_RVALUE_REFS
162
#define ZMQ_DELETED_FUNCTION = delete
163
#elif defined(__clang__)
164
#if __has_feature(cxx_rvalue_references)
165
#define ZMQ_HAS_RVALUE_REFS
166
#endif
167

168
#if __has_feature(cxx_deleted_functions)
169
#define ZMQ_DELETED_FUNCTION = delete
170
#else
171
#define ZMQ_DELETED_FUNCTION
172
#endif
173
#elif defined(_MSC_VER) && (_MSC_VER >= 1900)
174
#define ZMQ_HAS_RVALUE_REFS
175
#define ZMQ_DELETED_FUNCTION = delete
176
#elif defined(_MSC_VER) && (_MSC_VER >= 1600)
177
#define ZMQ_HAS_RVALUE_REFS
178
#define ZMQ_DELETED_FUNCTION
179
#else
180
#define ZMQ_DELETED_FUNCTION
181
#endif
182

183
#if defined(ZMQ_CPP11) && !defined(__llvm__) && !defined(__INTEL_COMPILER)          \
184
  && defined(__GNUC__) && __GNUC__ < 5
185
#define ZMQ_CPP11_PARTIAL
186
#elif defined(__GLIBCXX__) && __GLIBCXX__ < 20160805
187
//the date here is the last date of gcc 4.9.4, which
188
// effectively means libstdc++ from gcc 5.5 and higher won't trigger this branch
189
#define ZMQ_CPP11_PARTIAL
190
#endif
191

192
#ifdef ZMQ_CPP11
193
#ifdef ZMQ_CPP11_PARTIAL
194
#define ZMQ_IS_TRIVIALLY_COPYABLE(T) __has_trivial_copy(T)
195
#else
196
#include <type_traits>
197
#define ZMQ_IS_TRIVIALLY_COPYABLE(T) std::is_trivially_copyable<T>::value
198
#endif
199
#endif
200

201
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 3, 0)
202
#define ZMQ_NEW_MONITOR_EVENT_LAYOUT
203
#endif
204

205
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0)
206
#define ZMQ_HAS_PROXY_STEERABLE
207
/*  Socket event data  */
208
typedef struct
209
{
210
    uint16_t event; // id of the event as bitfield
211
    int32_t value;  // value is either error code, fd or reconnect interval
212
} zmq_event_t;
213
#endif
214

215
// Avoid using deprecated message receive function when possible
216
#if ZMQ_VERSION < ZMQ_MAKE_VERSION(3, 2, 0)
217
#define zmq_msg_recv(msg, socket, flags) zmq_recvmsg(socket, msg, flags)
218
#endif
219

220

221
// In order to prevent unused variable warnings when building in non-debug
222
// mode use this macro to make assertions.
223
#ifndef NDEBUG
224
#define ZMQ_ASSERT(expression) assert(expression)
225
#else
226
#define ZMQ_ASSERT(expression) (void) (expression)
227
#endif
228

229
namespace zmq
230
{
231
#ifdef ZMQ_CPP11
232
namespace detail
233
{
234
namespace ranges
235
{
236
using std::begin;
237
using std::end;
238
template<class T> auto begin(T &&r) -> decltype(begin(std::forward<T>(r)))
239
{
240
    return begin(std::forward<T>(r));
241
}
242
template<class T> auto end(T &&r) -> decltype(end(std::forward<T>(r)))
243
{
244
    return end(std::forward<T>(r));
245
}
246
} // namespace ranges
247

248
template<class T> using void_t = void;
249

250
template<class Iter>
251
using iter_value_t = typename std::iterator_traits<Iter>::value_type;
252

253
template<class Range>
254
using range_iter_t = decltype(
255
  ranges::begin(std::declval<typename std::remove_reference<Range>::type &>()));
256

257
template<class Range> using range_value_t = iter_value_t<range_iter_t<Range>>;
258

259
template<class T, class = void> struct is_range : std::false_type
260
{
261
};
262

263
template<class T>
264
struct is_range<
265
  T,
266
  void_t<decltype(
267
    ranges::begin(std::declval<typename std::remove_reference<T>::type &>())
268
    == ranges::end(std::declval<typename std::remove_reference<T>::type &>()))>>
269
    : std::true_type
270
{
271
};
272

273
} // namespace detail
274
#endif
275

276
typedef zmq_free_fn free_fn;
277
typedef zmq_pollitem_t pollitem_t;
278

279
// duplicate definition from libzmq 4.3.3
280
#if defined _WIN32
281
#if defined _WIN64
282
typedef unsigned __int64 fd_t;
283
#else
284
typedef unsigned int fd_t;
285
#endif
286
#else
287
typedef int fd_t;
288
#endif
289

290
class error_t : public std::exception
291
{
292
  public:
293
    error_t() ZMQ_NOTHROW : errnum(zmq_errno()) {}
34✔
294
    explicit error_t(int err) ZMQ_NOTHROW : errnum(err) {}
1✔
295
    virtual const char *what() const ZMQ_NOTHROW ZMQ_OVERRIDE
6✔
296
    {
297
        return zmq_strerror(errnum);
6✔
298
    }
299
    int num() const ZMQ_NOTHROW { return errnum; }
9✔
300

301
  private:
302
    int errnum;
303
};
304

305
namespace detail {
306
inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_)
26✔
307
{
308
    int rc = zmq_poll(items_, static_cast<int>(nitems_), timeout_);
26✔
309
    if (rc < 0)
26✔
310
        throw error_t();
×
311
    return rc;
26✔
312
}
313
}
314

315
#ifdef ZMQ_CPP11
316
ZMQ_DEPRECATED("from 4.8.0, use poll taking std::chrono::duration instead of long")
317
inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_)
318
#else
319
inline int poll(zmq_pollitem_t *items_, size_t nitems_, long timeout_ = -1)
320
#endif
321
{
322
    return detail::poll(items_, nitems_, timeout_);
323
}
324

325
ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
326
inline int poll(zmq_pollitem_t const *items_, size_t nitems_, long timeout_ = -1)
327
{
328
    return detail::poll(const_cast<zmq_pollitem_t *>(items_), nitems_, timeout_);
329
}
330

331
#ifdef ZMQ_CPP11
332
ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
333
inline int
334
poll(zmq_pollitem_t const *items, size_t nitems, std::chrono::milliseconds timeout)
335
{
336
    return detail::poll(const_cast<zmq_pollitem_t *>(items), nitems,
337
                static_cast<long>(timeout.count()));
338
}
339

340
ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
341
inline int poll(std::vector<zmq_pollitem_t> const &items,
342
                std::chrono::milliseconds timeout)
343
{
344
    return detail::poll(const_cast<zmq_pollitem_t *>(items.data()), items.size(),
345
                static_cast<long>(timeout.count()));
346
}
347

348
ZMQ_DEPRECATED("from 4.3.1, use poll taking non-const items")
349
inline int poll(std::vector<zmq_pollitem_t> const &items, long timeout_ = -1)
350
{
351
    return detail::poll(const_cast<zmq_pollitem_t *>(items.data()), items.size(), timeout_);
352
}
353

354
inline int
355
poll(zmq_pollitem_t *items, size_t nitems, std::chrono::milliseconds timeout = std::chrono::milliseconds{-1})
20✔
356
{
357
    return detail::poll(items, nitems, static_cast<long>(timeout.count()));
26✔
358
}
359

360
inline int poll(std::vector<zmq_pollitem_t> &items,
361
                std::chrono::milliseconds timeout = std::chrono::milliseconds{-1})
362
{
363
    return detail::poll(items.data(), items.size(), static_cast<long>(timeout.count()));
364
}
365

366
ZMQ_DEPRECATED("from 4.3.1, use poll taking std::chrono::duration instead of long")
367
inline int poll(std::vector<zmq_pollitem_t> &items, long timeout_)
368
{
369
    return detail::poll(items.data(), items.size(), timeout_);
370
}
371

372
template<std::size_t SIZE>
373
inline int poll(std::array<zmq_pollitem_t, SIZE> &items,
374
                std::chrono::milliseconds timeout = std::chrono::milliseconds{-1})
375
{
376
    return detail::poll(items.data(), items.size(), static_cast<long>(timeout.count()));
377
}
378
#endif
379

380

381
inline void version(int *major_, int *minor_, int *patch_)
382
{
383
    zmq_version(major_, minor_, patch_);
384
}
385

386
#ifdef ZMQ_CPP11
387
inline std::tuple<int, int, int> version()
388
{
389
    std::tuple<int, int, int> v;
390
    zmq_version(&std::get<0>(v), &std::get<1>(v), &std::get<2>(v));
391
    return v;
392
}
393

394
#if !defined(ZMQ_CPP11_PARTIAL)
395
namespace detail
396
{
397
template<class T> struct is_char_type
398
{
399
    // true if character type for string literals in C++11
400
    static constexpr bool value =
401
      std::is_same<T, char>::value || std::is_same<T, wchar_t>::value
402
      || std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value;
403
};
404
}
405
#endif
406

407
#endif
408

409
class message_t
410
{
411
  public:
412
    message_t() ZMQ_NOTHROW
78✔
413
    {
78✔
414
        int rc = zmq_msg_init(&msg);
78✔
415
        ZMQ_ASSERT(rc == 0);
78✔
416
    }
78✔
417

418
    explicit message_t(size_t size_)
25✔
419
    {
25✔
420
        int rc = zmq_msg_init_size(&msg, size_);
25✔
421
        if (rc != 0)
25✔
422
            throw error_t();
×
423
    }
25✔
424

425
    template<class ForwardIter> message_t(ForwardIter first, ForwardIter last)
4✔
426
    {
427
        typedef typename std::iterator_traits<ForwardIter>::value_type value_t;
428

429
        assert(std::distance(first, last) >= 0);
4✔
430
        size_t const size_ =
4✔
431
          static_cast<size_t>(std::distance(first, last)) * sizeof(value_t);
4✔
432
        int const rc = zmq_msg_init_size(&msg, size_);
4✔
433
        if (rc != 0)
4✔
434
            throw error_t();
×
435
        std::copy(first, last, data<value_t>());
4✔
436
    }
4✔
437

438
    message_t(const void *data_, size_t size_)
100✔
439
    {
100✔
440
        int rc = zmq_msg_init_size(&msg, size_);
100✔
441
        if (rc != 0)
100✔
442
            throw error_t();
×
443
        if (size_) {
100✔
444
            // this constructor allows (nullptr, 0),
445
            // memcpy with a null pointer is UB
446
            memcpy(data(), data_, size_);
100✔
447
        }
448
    }
100✔
449

450
    message_t(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR)
451
    {
452
        int rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_);
453
        if (rc != 0)
454
            throw error_t();
455
    }
456

457
    // overload set of string-like types and generic containers
458
#if defined(ZMQ_CPP11) && !defined(ZMQ_CPP11_PARTIAL)
459
    // NOTE this constructor will include the null terminator
460
    // when called with a string literal.
461
    // An overload taking const char* can not be added because
462
    // it would be preferred over this function and break compatiblity.
463
    template<
464
      class Char,
465
      size_t N,
466
      typename = typename std::enable_if<detail::is_char_type<Char>::value>::type>
467
    ZMQ_DEPRECATED("from 4.7.0, use constructors taking iterators, (pointer, size) "
468
                   "or strings instead")
469
    explicit message_t(const Char (&data)[N]) :
2✔
470
        message_t(detail::ranges::begin(data), detail::ranges::end(data))
2✔
471
    {
472
    }
2✔
473

474
    template<class Range,
475
             typename = typename std::enable_if<
476
               detail::is_range<Range>::value
477
               && ZMQ_IS_TRIVIALLY_COPYABLE(detail::range_value_t<Range>)
478
               && !detail::is_char_type<detail::range_value_t<Range>>::value
479
               && !std::is_same<Range, message_t>::value>::type>
480
    explicit message_t(const Range &rng) :
1✔
481
        message_t(detail::ranges::begin(rng), detail::ranges::end(rng))
1✔
482
    {
483
    }
1✔
484

485
    explicit message_t(const std::string &str) : message_t(str.data(), str.size()) {}
36✔
486

487
#if CPPZMQ_HAS_STRING_VIEW
488
    explicit message_t(std::string_view str) : message_t(str.data(), str.size()) {}
1✔
489
#endif
490

491
#endif
492

493
#ifdef ZMQ_HAS_RVALUE_REFS
494
    message_t(message_t &&rhs) ZMQ_NOTHROW : msg(rhs.msg)
97✔
495
    {
496
        int rc = zmq_msg_init(&rhs.msg);
97✔
497
        ZMQ_ASSERT(rc == 0);
97✔
498
    }
97✔
499

500
    message_t &operator=(message_t &&rhs) ZMQ_NOTHROW
12✔
501
    {
502
        std::swap(msg, rhs.msg);
12✔
503
        return *this;
12✔
504
    }
505
#endif
506

507
    ~message_t() ZMQ_NOTHROW
304✔
508
    {
304✔
509
        int rc = zmq_msg_close(&msg);
304✔
510
        ZMQ_ASSERT(rc == 0);
304✔
511
    }
304✔
512

513
    void rebuild()
514
    {
515
        int rc = zmq_msg_close(&msg);
516
        if (rc != 0)
517
            throw error_t();
518
        rc = zmq_msg_init(&msg);
519
        ZMQ_ASSERT(rc == 0);
520
    }
521

522
    void rebuild(size_t size_)
523
    {
524
        int rc = zmq_msg_close(&msg);
525
        if (rc != 0)
526
            throw error_t();
527
        rc = zmq_msg_init_size(&msg, size_);
528
        if (rc != 0)
529
            throw error_t();
530
    }
531

532
    void rebuild(const void *data_, size_t size_)
533
    {
534
        int rc = zmq_msg_close(&msg);
535
        if (rc != 0)
536
            throw error_t();
537
        rc = zmq_msg_init_size(&msg, size_);
538
        if (rc != 0)
539
            throw error_t();
540
        memcpy(data(), data_, size_);
541
    }
542
    
543
    void rebuild(const std::string &str)
544
    {
545
        rebuild(str.data(), str.size());
546
    }
547

548
    void rebuild(void *data_, size_t size_, free_fn *ffn_, void *hint_ = ZMQ_NULLPTR)
549
    {
550
        int rc = zmq_msg_close(&msg);
551
        if (rc != 0)
552
            throw error_t();
553
        rc = zmq_msg_init_data(&msg, data_, size_, ffn_, hint_);
554
        if (rc != 0)
555
            throw error_t();
556
    }
557

558
    ZMQ_DEPRECATED("from 4.3.1, use move taking non-const reference instead")
559
    void move(message_t const *msg_)
560
    {
561
        int rc = zmq_msg_move(&msg, const_cast<zmq_msg_t *>(msg_->handle()));
562
        if (rc != 0)
563
            throw error_t();
564
    }
565

566
    void move(message_t &msg_)
1✔
567
    {
568
        int rc = zmq_msg_move(&msg, msg_.handle());
1✔
569
        if (rc != 0)
1✔
570
            throw error_t();
×
571
    }
1✔
572

573
    ZMQ_DEPRECATED("from 4.3.1, use copy taking non-const reference instead")
574
    void copy(message_t const *msg_)
575
    {
576
        int rc = zmq_msg_copy(&msg, const_cast<zmq_msg_t *>(msg_->handle()));
577
        if (rc != 0)
578
            throw error_t();
579
    }
580

581
    void copy(message_t &msg_)
1✔
582
    {
583
        int rc = zmq_msg_copy(&msg, msg_.handle());
1✔
584
        if (rc != 0)
1✔
585
            throw error_t();
×
586
    }
1✔
587

588
    bool more() const ZMQ_NOTHROW
25✔
589
    {
590
        int rc = zmq_msg_more(const_cast<zmq_msg_t *>(&msg));
25✔
591
        return rc != 0;
25✔
592
    }
593

594
    void *data() ZMQ_NOTHROW { return zmq_msg_data(&msg); }
176✔
595

596
    const void *data() const ZMQ_NOTHROW
67✔
597
    {
598
        return zmq_msg_data(const_cast<zmq_msg_t *>(&msg));
67✔
599
    }
600

601
    size_t size() const ZMQ_NOTHROW
191✔
602
    {
603
        return zmq_msg_size(const_cast<zmq_msg_t *>(&msg));
191✔
604
    }
605

606
    ZMQ_NODISCARD bool empty() const ZMQ_NOTHROW { return size() == 0u; }
3✔
607

608
    template<typename T> T *data() ZMQ_NOTHROW { return static_cast<T *>(data()); }
63✔
609

610
    template<typename T> T const *data() const ZMQ_NOTHROW
12✔
611
    {
612
        return static_cast<T const *>(data());
12✔
613
    }
614

615
    ZMQ_DEPRECATED("from 4.3.0, use operator== instead")
616
    bool equal(const message_t *other) const ZMQ_NOTHROW { return *this == *other; }
617

618
    bool operator==(const message_t &other) const ZMQ_NOTHROW
15✔
619
    {
620
        const size_t my_size = size();
15✔
621
        return my_size == other.size() && 0 == memcmp(data(), other.data(), my_size);
15✔
622
    }
623

624
    bool operator!=(const message_t &other) const ZMQ_NOTHROW
12✔
625
    {
626
        return !(*this == other);
12✔
627
    }
628

629
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(3, 2, 0)
630
    int get(int property_)
5✔
631
    {
632
        int value = zmq_msg_get(&msg, property_);
5✔
633
        if (value == -1)
5✔
634
            throw error_t();
×
635
        return value;
5✔
636
    }
637
#endif
638

639
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 1, 0)
640
    const char *gets(const char *property_)
641
    {
642
        const char *value = zmq_msg_gets(&msg, property_);
643
        if (value == ZMQ_NULLPTR)
644
            throw error_t();
645
        return value;
646
    }
647
#endif
648

649
#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
650
    uint32_t routing_id() const
1✔
651
    {
652
        return zmq_msg_routing_id(const_cast<zmq_msg_t *>(&msg));
1✔
653
    }
654

655
    void set_routing_id(uint32_t routing_id)
1✔
656
    {
657
        int rc = zmq_msg_set_routing_id(&msg, routing_id);
1✔
658
        if (rc != 0)
1✔
659
            throw error_t();
×
660
    }
1✔
661

662
    const char *group() const
1✔
663
    {
664
        return zmq_msg_group(const_cast<zmq_msg_t *>(&msg));
1✔
665
    }
666

667
    void set_group(const char *group)
1✔
668
    {
669
        int rc = zmq_msg_set_group(&msg, group);
1✔
670
        if (rc != 0)
1✔
671
            throw error_t();
×
672
    }
1✔
673
#endif
674

675
    // interpret message content as a string
676
    std::string to_string() const
13✔
677
    {
678
        return std::string(static_cast<const char *>(data()), size());
13✔
679
    }
680
#if CPPZMQ_HAS_STRING_VIEW
681
    // interpret message content as a string
682
    std::string_view to_string_view() const noexcept
2✔
683
    {
684
        return std::string_view(static_cast<const char *>(data()), size());
2✔
685
    }
686
#endif
687

688
    /** Dump content to string for debugging.
689
    *   Ascii chars are readable, the rest is printed as hex.
690
    *   Probably ridiculously slow.
691
    *   Use to_string() or to_string_view() for
692
    *   interpreting the message as a string.
693
    */
694
    std::string str() const
×
695
    {
696
        // Partly mutuated from the same method in zmq::multipart_t
697
        std::stringstream os;
×
698

699
        const unsigned char *msg_data = this->data<unsigned char>();
×
700
        unsigned char byte;
701
        size_t size = this->size();
×
702
        int is_ascii[2] = {0, 0};
×
703

704
        os << "zmq::message_t [size " << std::dec << std::setw(3)
×
705
           << std::setfill('0') << size << "] (";
×
706
        // Totally arbitrary
707
        if (size >= 1000) {
×
708
            os << "... too big to print)";
×
709
        } else {
710
            while (size--) {
×
711
                byte = *msg_data++;
×
712

713
                is_ascii[1] = (byte >= 32 && byte < 127);
×
714
                if (is_ascii[1] != is_ascii[0])
×
715
                    os << " "; // Separate text/non text
×
716

717
                if (is_ascii[1]) {
×
718
                    os << byte;
×
719
                } else {
720
                    os << std::hex << std::uppercase << std::setw(2)
×
721
                       << std::setfill('0') << static_cast<short>(byte);
×
722
                }
723
                is_ascii[0] = is_ascii[1];
×
724
            }
725
            os << ")";
×
726
        }
727
        return os.str();
×
728
    }
729

730
    void swap(message_t &other) ZMQ_NOTHROW
2✔
731
    {
732
        // this assumes zmq::msg_t from libzmq is trivially relocatable
733
        std::swap(msg, other.msg);
2✔
734
    }
2✔
735

736
    ZMQ_NODISCARD zmq_msg_t *handle() ZMQ_NOTHROW { return &msg; }
113✔
737
    ZMQ_NODISCARD const zmq_msg_t *handle() const ZMQ_NOTHROW { return &msg; }
738

739
  private:
740
    //  The underlying message
741
    zmq_msg_t msg;
742

743
    //  Disable implicit message copying, so that users won't use shared
744
    //  messages (less efficient) without being aware of the fact.
745
    message_t(const message_t &) ZMQ_DELETED_FUNCTION;
746
    void operator=(const message_t &) ZMQ_DELETED_FUNCTION;
747
};
748

749
inline void swap(message_t &a, message_t &b) ZMQ_NOTHROW
2✔
750
{
751
    a.swap(b);
2✔
752
}
2✔
753

754
#ifdef ZMQ_CPP11
755
enum class ctxopt
756
{
757
#ifdef ZMQ_BLOCKY
758
    blocky = ZMQ_BLOCKY,
759
#endif
760
#ifdef ZMQ_IO_THREADS
761
    io_threads = ZMQ_IO_THREADS,
762
#endif
763
#ifdef ZMQ_THREAD_SCHED_POLICY
764
    thread_sched_policy = ZMQ_THREAD_SCHED_POLICY,
765
#endif
766
#ifdef ZMQ_THREAD_PRIORITY
767
    thread_priority = ZMQ_THREAD_PRIORITY,
768
#endif
769
#ifdef ZMQ_THREAD_AFFINITY_CPU_ADD
770
    thread_affinity_cpu_add = ZMQ_THREAD_AFFINITY_CPU_ADD,
771
#endif
772
#ifdef ZMQ_THREAD_AFFINITY_CPU_REMOVE
773
    thread_affinity_cpu_remove = ZMQ_THREAD_AFFINITY_CPU_REMOVE,
774
#endif
775
#ifdef ZMQ_THREAD_NAME_PREFIX
776
    thread_name_prefix = ZMQ_THREAD_NAME_PREFIX,
777
#endif
778
#ifdef ZMQ_MAX_MSGSZ
779
    max_msgsz = ZMQ_MAX_MSGSZ,
780
#endif
781
#ifdef ZMQ_ZERO_COPY_RECV
782
    zero_copy_recv = ZMQ_ZERO_COPY_RECV,
783
#endif
784
#ifdef ZMQ_MAX_SOCKETS
785
    max_sockets = ZMQ_MAX_SOCKETS,
786
#endif
787
#ifdef ZMQ_SOCKET_LIMIT
788
    socket_limit = ZMQ_SOCKET_LIMIT,
789
#endif
790
#ifdef ZMQ_IPV6
791
    ipv6 = ZMQ_IPV6,
792
#endif
793
#ifdef ZMQ_MSG_T_SIZE
794
    msg_t_size = ZMQ_MSG_T_SIZE
795
#endif
796
};
797
#endif
798

799
class context_t
800
{
801
  public:
802
    context_t()
105✔
803
    {
105✔
804
        ptr = zmq_ctx_new();
105✔
805
        if (ptr == ZMQ_NULLPTR)
105✔
806
            throw error_t();
×
807
    }
105✔
808

809

810
    explicit context_t(int io_threads_, int max_sockets_ = ZMQ_MAX_SOCKETS_DFLT)
22✔
811
    {
22✔
812
        ptr = zmq_ctx_new();
22✔
813
        if (ptr == ZMQ_NULLPTR)
22✔
814
            throw error_t();
×
815

816
        int rc = zmq_ctx_set(ptr, ZMQ_IO_THREADS, io_threads_);
22✔
817
        ZMQ_ASSERT(rc == 0);
22✔
818

819
        rc = zmq_ctx_set(ptr, ZMQ_MAX_SOCKETS, max_sockets_);
22✔
820
        ZMQ_ASSERT(rc == 0);
22✔
821
    }
22✔
822

823
#ifdef ZMQ_HAS_RVALUE_REFS
824
    context_t(context_t &&rhs) ZMQ_NOTHROW : ptr(rhs.ptr) { rhs.ptr = ZMQ_NULLPTR; }
50✔
825
    context_t &operator=(context_t &&rhs) ZMQ_NOTHROW
826
    {
827
        close();
828
        std::swap(ptr, rhs.ptr);
829
        return *this;
830
    }
831
#endif
832

833
    ~context_t() ZMQ_NOTHROW { close(); }
177✔
834

835
    ZMQ_CPP11_DEPRECATED("from 4.7.0, use set taking zmq::ctxopt instead")
836
    int setctxopt(int option_, int optval_)
837
    {
838
        int rc = zmq_ctx_set(ptr, option_, optval_);
839
        ZMQ_ASSERT(rc == 0);
840
        return rc;
841
    }
842

843
    ZMQ_CPP11_DEPRECATED("from 4.7.0, use get taking zmq::ctxopt instead")
844
    int getctxopt(int option_) { return zmq_ctx_get(ptr, option_); }
845

846
#ifdef ZMQ_CPP11
847
    void set(ctxopt option, int optval)
3✔
848
    {
849
        int rc = zmq_ctx_set(ptr, static_cast<int>(option), optval);
3✔
850
        if (rc == -1)
3✔
851
            throw error_t();
1✔
852
    }
2✔
853

854
    ZMQ_NODISCARD int get(ctxopt option)
2✔
855
    {
856
        int rc = zmq_ctx_get(ptr, static_cast<int>(option));
2✔
857
        // some options have a default value of -1
858
        // which is unfortunate, and may result in errors
859
        // that don't make sense
860
        if (rc == -1)
2✔
861
            throw error_t();
1✔
862
        return rc;
1✔
863
    }
864
#endif
865

866
    // Terminates context (see also shutdown()).
867
    void close() ZMQ_NOTHROW
182✔
868
    {
869
        if (ptr == ZMQ_NULLPTR)
182✔
870
            return;
55✔
871

872
        int rc;
873
        do {
×
874
            rc = zmq_ctx_term(ptr);
127✔
875
        } while (rc == -1 && errno == EINTR);
127✔
876

877
        ZMQ_ASSERT(rc == 0);
127✔
878
        ptr = ZMQ_NULLPTR;
127✔
879
    }
880

881
    // Shutdown context in preparation for termination (close()).
882
    // Causes all blocking socket operations and any further
883
    // socket operations to return with ETERM.
884
    void shutdown() ZMQ_NOTHROW
4✔
885
    {
886
        if (ptr == ZMQ_NULLPTR)
4✔
887
            return;
×
888
        int rc = zmq_ctx_shutdown(ptr);
4✔
889
        ZMQ_ASSERT(rc == 0);
4✔
890
    }
891

892
    //  Be careful with this, it's probably only useful for
893
    //  using the C api together with an existing C++ api.
894
    //  Normally you should never need to use this.
895
    ZMQ_EXPLICIT operator void *() ZMQ_NOTHROW { return ptr; }
896

897
    ZMQ_EXPLICIT operator void const *() const ZMQ_NOTHROW { return ptr; }
898

899
    ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return ptr; }
407✔
900

901
    ZMQ_DEPRECATED("from 4.7.0, use handle() != nullptr instead")
902
    operator bool() const ZMQ_NOTHROW { return ptr != ZMQ_NULLPTR; }
903

904
    void swap(context_t &other) ZMQ_NOTHROW { std::swap(ptr, other.ptr); }
1✔
905

906
  private:
907
    void *ptr;
908

909
    context_t(const context_t &) ZMQ_DELETED_FUNCTION;
910
    void operator=(const context_t &) ZMQ_DELETED_FUNCTION;
911
};
912

913
inline void swap(context_t &a, context_t &b) ZMQ_NOTHROW
1✔
914
{
915
    a.swap(b);
1✔
916
}
1✔
917

918
#ifdef ZMQ_CPP11
919

920
struct recv_buffer_size
921
{
922
    size_t size;             // number of bytes written to buffer
923
    size_t untruncated_size; // untruncated message size in bytes
924

925
    ZMQ_NODISCARD bool truncated() const noexcept
3✔
926
    {
927
        return size != untruncated_size;
3✔
928
    }
929
};
930

931
#if CPPZMQ_HAS_OPTIONAL
932

933
using send_result_t = std::optional<size_t>;
934
using recv_result_t = std::optional<size_t>;
935
using recv_buffer_result_t = std::optional<recv_buffer_size>;
936

937
#else
938

939
namespace detail
940
{
941
// A C++11 type emulating the most basic
942
// operations of std::optional for trivial types
943
template<class T> class trivial_optional
944
{
945
  public:
946
    static_assert(std::is_trivial<T>::value, "T must be trivial");
947
    using value_type = T;
948

949
    trivial_optional() = default;
950
    trivial_optional(T value) noexcept : _value(value), _has_value(true) {}
951

952
    const T *operator->() const noexcept
953
    {
954
        assert(_has_value);
955
        return &_value;
956
    }
957
    T *operator->() noexcept
958
    {
959
        assert(_has_value);
960
        return &_value;
961
    }
962

963
    const T &operator*() const noexcept
964
    {
965
        assert(_has_value);
966
        return _value;
967
    }
968
    T &operator*() noexcept
969
    {
970
        assert(_has_value);
971
        return _value;
972
    }
973

974
    T &value()
975
    {
976
        if (!_has_value)
977
            throw std::exception();
978
        return _value;
979
    }
980
    const T &value() const
981
    {
982
        if (!_has_value)
983
            throw std::exception();
984
        return _value;
985
    }
986

987
    explicit operator bool() const noexcept { return _has_value; }
988
    bool has_value() const noexcept { return _has_value; }
989

990
  private:
991
    T _value{};
992
    bool _has_value{false};
993
};
994
} // namespace detail
995

996
using send_result_t = detail::trivial_optional<size_t>;
997
using recv_result_t = detail::trivial_optional<size_t>;
998
using recv_buffer_result_t = detail::trivial_optional<recv_buffer_size>;
999

1000
#endif
1001

1002
namespace detail
1003
{
1004
template<class T> constexpr T enum_bit_or(T a, T b) noexcept
28✔
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));
28✔
1009
}
1010
template<class T> constexpr T enum_bit_and(T a, T b) noexcept
7✔
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));
7✔
1015
}
1016
template<class T> constexpr T enum_bit_xor(T a, T b) noexcept
3✔
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) ^ static_cast<U>(b));
3✔
1021
}
1022
template<class T> constexpr T enum_bit_not(T a) noexcept
4✔
1023
{
1024
    static_assert(std::is_enum<T>::value, "must be enum");
1025
    using U = typename std::underlying_type<T>::type;
1026
    return static_cast<T>(~static_cast<U>(a));
4✔
1027
}
1028
} // namespace detail
1029

1030
// partially satisfies named requirement BitmaskType
1031
enum class send_flags : int
1032
{
1033
    none = 0,
1034
    dontwait = ZMQ_DONTWAIT,
1035
    sndmore = ZMQ_SNDMORE
1036
};
1037

1038
constexpr send_flags operator|(send_flags a, send_flags b) noexcept
19✔
1039
{
1040
    return detail::enum_bit_or(a, b);
19✔
1041
}
1042
constexpr send_flags operator&(send_flags a, send_flags b) noexcept
1✔
1043
{
1044
    return detail::enum_bit_and(a, b);
1✔
1045
}
1046
constexpr send_flags operator^(send_flags a, send_flags b) noexcept
1✔
1047
{
1048
    return detail::enum_bit_xor(a, b);
1✔
1049
}
1050
constexpr send_flags operator~(send_flags a) noexcept
1✔
1051
{
1052
    return detail::enum_bit_not(a);
1✔
1053
}
1054

1055
// partially satisfies named requirement BitmaskType
1056
enum class recv_flags : int
1057
{
1058
    none = 0,
1059
    dontwait = ZMQ_DONTWAIT
1060
};
1061

1062
constexpr recv_flags operator|(recv_flags a, recv_flags b) noexcept
1✔
1063
{
1064
    return detail::enum_bit_or(a, b);
1✔
1065
}
1066
constexpr recv_flags operator&(recv_flags a, recv_flags b) noexcept
1✔
1067
{
1068
    return detail::enum_bit_and(a, b);
1✔
1069
}
1070
constexpr recv_flags operator^(recv_flags a, recv_flags b) noexcept
1✔
1071
{
1072
    return detail::enum_bit_xor(a, b);
1✔
1073
}
1074
constexpr recv_flags operator~(recv_flags a) noexcept
1✔
1075
{
1076
    return detail::enum_bit_not(a);
1✔
1077
}
1078

1079

1080
// mutable_buffer, const_buffer and buffer are based on
1081
// the Networking TS specification, draft:
1082
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/n4771.pdf
1083

1084
class mutable_buffer
1085
{
1086
  public:
1087
    constexpr mutable_buffer() noexcept : _data(nullptr), _size(0) {}
1088
    constexpr mutable_buffer(void *p, size_t n) noexcept : _data(p), _size(n)
81✔
1089
    {
1090
#ifdef ZMQ_EXTENDED_CONSTEXPR
1091
        assert(p != nullptr || n == 0);
81✔
1092
#endif
1093
    }
81✔
1094

1095
    constexpr void *data() const noexcept { return _data; }
95✔
1096
    constexpr size_t size() const noexcept { return _size; }
104✔
1097
    mutable_buffer &operator+=(size_t n) noexcept
1✔
1098
    {
1099
        // (std::min) is a workaround for when a min macro is defined
1100
        const auto shift = (std::min)(n, _size);
1✔
1101
        _data = static_cast<char *>(_data) + shift;
1✔
1102
        _size -= shift;
1✔
1103
        return *this;
1✔
1104
    }
1105

1106
  private:
1107
    void *_data;
1108
    size_t _size;
1109
};
1110

1111
inline mutable_buffer operator+(const mutable_buffer &mb, size_t n) noexcept
2✔
1112
{
1113
    return mutable_buffer(static_cast<char *>(mb.data()) + (std::min)(n, mb.size()),
2✔
1114
                          mb.size() - (std::min)(n, mb.size()));
4✔
1115
}
1116
inline mutable_buffer operator+(size_t n, const mutable_buffer &mb) noexcept
1✔
1117
{
1118
    return mb + n;
1✔
1119
}
1120

1121
class const_buffer
1122
{
1123
  public:
1124
    constexpr const_buffer() noexcept : _data(nullptr), _size(0) {}
1125
    constexpr const_buffer(const void *p, size_t n) noexcept : _data(p), _size(n)
42✔
1126
    {
1127
#ifdef ZMQ_EXTENDED_CONSTEXPR
1128
        assert(p != nullptr || n == 0);
42✔
1129
#endif
1130
    }
42✔
1131
    constexpr const_buffer(const mutable_buffer &mb) noexcept :
11✔
1132
        _data(mb.data()), _size(mb.size())
11✔
1133
    {
1134
    }
11✔
1135

1136
    constexpr const void *data() const noexcept { return _data; }
75✔
1137
    constexpr size_t size() const noexcept { return _size; }
87✔
1138
    const_buffer &operator+=(size_t n) noexcept
1✔
1139
    {
1140
        const auto shift = (std::min)(n, _size);
1✔
1141
        _data = static_cast<const char *>(_data) + shift;
1✔
1142
        _size -= shift;
1✔
1143
        return *this;
1✔
1144
    }
1145

1146
  private:
1147
    const void *_data;
1148
    size_t _size;
1149
};
1150

1151
inline const_buffer operator+(const const_buffer &cb, size_t n) noexcept
2✔
1152
{
1153
    return const_buffer(static_cast<const char *>(cb.data())
6✔
1154
                          + (std::min)(n, cb.size()),
2✔
1155
                        cb.size() - (std::min)(n, cb.size()));
4✔
1156
}
1157
inline const_buffer operator+(size_t n, const const_buffer &cb) noexcept
1✔
1158
{
1159
    return cb + n;
1✔
1160
}
1161

1162
// buffer creation
1163

1164
constexpr mutable_buffer buffer(void *p, size_t n) noexcept
72✔
1165
{
1166
    return mutable_buffer(p, n);
72✔
1167
}
1168
constexpr const_buffer buffer(const void *p, size_t n) noexcept
17✔
1169
{
1170
    return const_buffer(p, n);
17✔
1171
}
1172
constexpr mutable_buffer buffer(const mutable_buffer &mb) noexcept
1✔
1173
{
1174
    return mb;
1✔
1175
}
1176
inline mutable_buffer buffer(const mutable_buffer &mb, size_t n) noexcept
2✔
1177
{
1178
    return mutable_buffer(mb.data(), (std::min)(mb.size(), n));
2✔
1179
}
1180
constexpr const_buffer buffer(const const_buffer &cb) noexcept
1✔
1181
{
1182
    return cb;
1✔
1183
}
1184
inline const_buffer buffer(const const_buffer &cb, size_t n) noexcept
2✔
1185
{
1186
    return const_buffer(cb.data(), (std::min)(cb.size(), n));
2✔
1187
}
1188

1189
namespace detail
1190
{
1191
template<class T> struct is_buffer
1192
{
1193
    static constexpr bool value =
1194
      std::is_same<T, const_buffer>::value || std::is_same<T, mutable_buffer>::value;
1195
};
1196

1197
template<class T> struct is_pod_like
1198
{
1199
    // NOTE: The networking draft N4771 section 16.11 requires
1200
    // T in the buffer functions below to be
1201
    // trivially copyable OR standard layout.
1202
    // Here we decide to be conservative and require both.
1203
    static constexpr bool value =
1204
      ZMQ_IS_TRIVIALLY_COPYABLE(T) && std::is_standard_layout<T>::value;
1205
};
1206

1207
template<class C> constexpr auto seq_size(const C &c) noexcept -> decltype(c.size())
71✔
1208
{
1209
    return c.size();
71✔
1210
}
1211
template<class T, size_t N>
1212
constexpr size_t seq_size(const T (&/*array*/)[N]) noexcept
1213
{
1214
    return N;
1215
}
1216

1217
template<class Seq>
1218
auto buffer_contiguous_sequence(Seq &&seq) noexcept
75✔
1219
  -> decltype(buffer(std::addressof(*std::begin(seq)), size_t{}))
1220
{
1221
    using T = typename std::remove_cv<
1222
      typename std::remove_reference<decltype(*std::begin(seq))>::type>::type;
1223
    static_assert(detail::is_pod_like<T>::value, "T must be POD");
1224

1225
    const auto size = seq_size(seq);
75✔
1226
    return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr,
140✔
1227
                  size * sizeof(T));
75✔
1228
}
1229
template<class Seq>
1230
auto buffer_contiguous_sequence(Seq &&seq, size_t n_bytes) noexcept
11✔
1231
  -> decltype(buffer_contiguous_sequence(seq))
1232
{
1233
    using T = typename std::remove_cv<
1234
      typename std::remove_reference<decltype(*std::begin(seq))>::type>::type;
1235
    static_assert(detail::is_pod_like<T>::value, "T must be POD");
1236

1237
    const auto size = seq_size(seq);
11✔
1238
    return buffer(size != 0u ? std::addressof(*std::begin(seq)) : nullptr,
11✔
1239
                  (std::min)(size * sizeof(T), n_bytes));
22✔
1240
}
1241

1242
} // namespace detail
1243

1244
// C array
1245
template<class T, size_t N> mutable_buffer buffer(T (&data)[N]) noexcept
3✔
1246
{
1247
    return detail::buffer_contiguous_sequence(data);
3✔
1248
}
1249
template<class T, size_t N>
1250
mutable_buffer buffer(T (&data)[N], size_t n_bytes) noexcept
2✔
1251
{
1252
    return detail::buffer_contiguous_sequence(data, n_bytes);
2✔
1253
}
1254
template<class T, size_t N> const_buffer buffer(const T (&data)[N]) noexcept
2✔
1255
{
1256
    return detail::buffer_contiguous_sequence(data);
2✔
1257
}
1258
template<class T, size_t N>
1259
const_buffer buffer(const T (&data)[N], size_t n_bytes) noexcept
1✔
1260
{
1261
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1262
}
1263
// std::array
1264
template<class T, size_t N> mutable_buffer buffer(std::array<T, N> &data) noexcept
2✔
1265
{
1266
    return detail::buffer_contiguous_sequence(data);
2✔
1267
}
1268
template<class T, size_t N>
1269
mutable_buffer buffer(std::array<T, N> &data, size_t n_bytes) noexcept
1✔
1270
{
1271
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1272
}
1273
template<class T, size_t N>
1274
const_buffer buffer(std::array<const T, N> &data) noexcept
1✔
1275
{
1276
    return detail::buffer_contiguous_sequence(data);
1✔
1277
}
1278
template<class T, size_t N>
1279
const_buffer buffer(std::array<const T, N> &data, size_t n_bytes) noexcept
1✔
1280
{
1281
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1282
}
1283
template<class T, size_t N>
1284
const_buffer buffer(const std::array<T, N> &data) noexcept
1✔
1285
{
1286
    return detail::buffer_contiguous_sequence(data);
1✔
1287
}
1288
template<class T, size_t N>
1289
const_buffer buffer(const std::array<T, N> &data, size_t n_bytes) noexcept
1✔
1290
{
1291
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1292
}
1293
// std::vector
1294
template<class T, class Allocator>
1295
mutable_buffer buffer(std::vector<T, Allocator> &data) noexcept
13✔
1296
{
1297
    return detail::buffer_contiguous_sequence(data);
13✔
1298
}
1299
template<class T, class Allocator>
1300
mutable_buffer buffer(std::vector<T, Allocator> &data, size_t n_bytes) noexcept
1✔
1301
{
1302
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1303
}
1304
template<class T, class Allocator>
1305
const_buffer buffer(const std::vector<T, Allocator> &data) noexcept
2✔
1306
{
1307
    return detail::buffer_contiguous_sequence(data);
2✔
1308
}
1309
template<class T, class Allocator>
1310
const_buffer buffer(const std::vector<T, Allocator> &data, size_t n_bytes) noexcept
1✔
1311
{
1312
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1313
}
1314
// std::basic_string
1315
template<class T, class Traits, class Allocator>
1316
mutable_buffer buffer(std::basic_string<T, Traits, Allocator> &data) noexcept
48✔
1317
{
1318
    return detail::buffer_contiguous_sequence(data);
48✔
1319
}
1320
template<class T, class Traits, class Allocator>
1321
mutable_buffer buffer(std::basic_string<T, Traits, Allocator> &data,
1✔
1322
                      size_t n_bytes) noexcept
1323
{
1324
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1325
}
1326
template<class T, class Traits, class Allocator>
1327
const_buffer buffer(const std::basic_string<T, Traits, Allocator> &data) noexcept
2✔
1328
{
1329
    return detail::buffer_contiguous_sequence(data);
2✔
1330
}
1331
template<class T, class Traits, class Allocator>
1332
const_buffer buffer(const std::basic_string<T, Traits, Allocator> &data,
1✔
1333
                    size_t n_bytes) noexcept
1334
{
1335
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1336
}
1337

1338
#if CPPZMQ_HAS_STRING_VIEW
1339
// std::basic_string_view
1340
template<class T, class Traits>
1341
const_buffer buffer(std::basic_string_view<T, Traits> data) noexcept
1✔
1342
{
1343
    return detail::buffer_contiguous_sequence(data);
1✔
1344
}
1345
template<class T, class Traits>
1346
const_buffer buffer(std::basic_string_view<T, Traits> data, size_t n_bytes) noexcept
1✔
1347
{
1348
    return detail::buffer_contiguous_sequence(data, n_bytes);
1✔
1349
}
1350
#endif
1351

1352
// Buffer for a string literal (null terminated)
1353
// where the buffer size excludes the terminating character.
1354
// Equivalent to zmq::buffer(std::string_view("...")).
1355
template<class Char, size_t N>
1356
constexpr const_buffer str_buffer(const Char (&data)[N]) noexcept
16✔
1357
{
1358
    static_assert(detail::is_pod_like<Char>::value, "Char must be POD");
1359
#ifdef ZMQ_EXTENDED_CONSTEXPR
1360
    assert(data[N - 1] == Char{0});
16✔
1361
#endif
1362
    return const_buffer(static_cast<const Char *>(data), (N - 1) * sizeof(Char));
16✔
1363
}
1364

1365
namespace literals
1366
{
1367
constexpr const_buffer operator"" _zbuf(const char *str, size_t len) noexcept
1368
{
1369
    return const_buffer(str, len * sizeof(char));
1370
}
1371
constexpr const_buffer operator"" _zbuf(const wchar_t *str, size_t len) noexcept
1372
{
1373
    return const_buffer(str, len * sizeof(wchar_t));
1374
}
1375
constexpr const_buffer operator"" _zbuf(const char16_t *str, size_t len) noexcept
1376
{
1377
    return const_buffer(str, len * sizeof(char16_t));
1378
}
1379
constexpr const_buffer operator"" _zbuf(const char32_t *str, size_t len) noexcept
1380
{
1381
    return const_buffer(str, len * sizeof(char32_t));
1382
}
1383
}
1384

1385
#ifdef ZMQ_CPP11
1386
enum class socket_type : int
1387
{
1388
    req = ZMQ_REQ,
1389
    rep = ZMQ_REP,
1390
    dealer = ZMQ_DEALER,
1391
    router = ZMQ_ROUTER,
1392
    pub = ZMQ_PUB,
1393
    sub = ZMQ_SUB,
1394
    xpub = ZMQ_XPUB,
1395
    xsub = ZMQ_XSUB,
1396
    push = ZMQ_PUSH,
1397
    pull = ZMQ_PULL,
1398
#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
1399
    server = ZMQ_SERVER,
1400
    client = ZMQ_CLIENT,
1401
    radio = ZMQ_RADIO,
1402
    dish = ZMQ_DISH,
1403
    gather = ZMQ_GATHER,
1404
    scatter = ZMQ_SCATTER,
1405
    dgram = ZMQ_DGRAM,
1406
#endif
1407
#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3)
1408
    peer = ZMQ_PEER,
1409
    channel = ZMQ_CHANNEL,
1410
#endif
1411
#if ZMQ_VERSION_MAJOR >= 4
1412
    stream = ZMQ_STREAM,
1413
#endif
1414
    pair = ZMQ_PAIR
1415
};
1416
#endif
1417

1418
namespace sockopt
1419
{
1420
// There are two types of options,
1421
// integral type with known compiler time size (int, bool, int64_t, uint64_t)
1422
// and arrays with dynamic size (strings, binary data).
1423

1424
// BoolUnit: if true accepts values of type bool (but passed as T into libzmq)
1425
template<int Opt, class T, bool BoolUnit = false> struct integral_option
1426
{
1427
};
1428

1429
// NullTerm:
1430
// 0: binary data
1431
// 1: null-terminated string (`getsockopt` size includes null)
1432
// 2: binary (size 32) or Z85 encoder string of size 41 (null included)
1433
template<int Opt, int NullTerm = 1> struct array_option
1434
{
1435
};
1436

1437
#define ZMQ_DEFINE_INTEGRAL_OPT(OPT, NAME, TYPE)                                    \
1438
    using NAME##_t = integral_option<OPT, TYPE, false>;                             \
1439
    ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1440
#define ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(OPT, NAME, TYPE)                          \
1441
    using NAME##_t = integral_option<OPT, TYPE, true>;                              \
1442
    ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1443
#define ZMQ_DEFINE_ARRAY_OPT(OPT, NAME)                                             \
1444
    using NAME##_t = array_option<OPT>;                                             \
1445
    ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1446
#define ZMQ_DEFINE_ARRAY_OPT_BINARY(OPT, NAME)                                      \
1447
    using NAME##_t = array_option<OPT, 0>;                                          \
1448
    ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1449
#define ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(OPT, NAME)                                  \
1450
    using NAME##_t = array_option<OPT, 2>;                                          \
1451
    ZMQ_INLINE_VAR ZMQ_CONSTEXPR_VAR NAME##_t NAME {}
1452

1453
// deprecated, use zmq::fd_t
1454
using cppzmq_fd_t = ::zmq::fd_t;
1455

1456
#ifdef ZMQ_AFFINITY
1457
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_AFFINITY, affinity, uint64_t);
1458
#endif
1459
#ifdef ZMQ_BACKLOG
1460
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_BACKLOG, backlog, int);
1461
#endif
1462
#ifdef ZMQ_BINDTODEVICE
1463
ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_BINDTODEVICE, bindtodevice);
1464
#endif
1465
#ifdef ZMQ_CONFLATE
1466
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CONFLATE, conflate, int);
1467
#endif
1468
#ifdef ZMQ_CONNECT_ROUTING_ID
1469
ZMQ_DEFINE_ARRAY_OPT(ZMQ_CONNECT_ROUTING_ID, connect_routing_id);
1470
#endif
1471
#ifdef ZMQ_CONNECT_TIMEOUT
1472
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_CONNECT_TIMEOUT, connect_timeout, int);
1473
#endif
1474
#ifdef ZMQ_CURVE_PUBLICKEY
1475
ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_PUBLICKEY, curve_publickey);
1476
#endif
1477
#ifdef ZMQ_CURVE_SECRETKEY
1478
ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SECRETKEY, curve_secretkey);
1479
#endif
1480
#ifdef ZMQ_CURVE_SERVER
1481
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_CURVE_SERVER, curve_server, int);
1482
#endif
1483
#ifdef ZMQ_CURVE_SERVERKEY
1484
ZMQ_DEFINE_ARRAY_OPT_BIN_OR_Z85(ZMQ_CURVE_SERVERKEY, curve_serverkey);
1485
#endif
1486
#ifdef ZMQ_DISCONNECT_MSG
1487
ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_DISCONNECT_MSG, disconnect_msg);
1488
#endif
1489
#ifdef ZMQ_EVENTS
1490
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_EVENTS, events, int);
1491
#endif
1492
#ifdef ZMQ_FD
1493
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_FD, fd, ::zmq::fd_t);
1494
#endif
1495
#ifdef ZMQ_GSSAPI_PLAINTEXT
1496
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_PLAINTEXT, gssapi_plaintext, int);
1497
#endif
1498
#ifdef ZMQ_GSSAPI_SERVER
1499
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_GSSAPI_SERVER, gssapi_server, int);
1500
#endif
1501
#ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL
1502
ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL, gssapi_service_principal);
1503
#endif
1504
#ifdef ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE
1505
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE,
1506
                        gssapi_service_principal_nametype,
1507
                        int);
1508
#endif
1509
#ifdef ZMQ_GSSAPI_PRINCIPAL
1510
ZMQ_DEFINE_ARRAY_OPT(ZMQ_GSSAPI_PRINCIPAL, gssapi_principal);
1511
#endif
1512
#ifdef ZMQ_GSSAPI_PRINCIPAL_NAMETYPE
1513
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_GSSAPI_PRINCIPAL_NAMETYPE,
1514
                        gssapi_principal_nametype,
1515
                        int);
1516
#endif
1517
#ifdef ZMQ_HANDSHAKE_IVL
1518
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HANDSHAKE_IVL, handshake_ivl, int);
1519
#endif
1520
#ifdef ZMQ_HEARTBEAT_IVL
1521
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_IVL, heartbeat_ivl, int);
1522
#endif
1523
#ifdef ZMQ_HEARTBEAT_TIMEOUT
1524
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TIMEOUT, heartbeat_timeout, int);
1525
#endif
1526
#ifdef ZMQ_HEARTBEAT_TTL
1527
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_HEARTBEAT_TTL, heartbeat_ttl, int);
1528
#endif
1529
#ifdef ZMQ_HELLO_MSG
1530
ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_HELLO_MSG, hello_msg);
1531
#endif
1532
#ifdef ZMQ_IMMEDIATE
1533
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IMMEDIATE, immediate, int);
1534
#endif
1535
#ifdef ZMQ_INVERT_MATCHING
1536
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_INVERT_MATCHING, invert_matching, int);
1537
#endif
1538
#ifdef ZMQ_IPV6
1539
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_IPV6, ipv6, int);
1540
#endif
1541
#ifdef ZMQ_LAST_ENDPOINT
1542
ZMQ_DEFINE_ARRAY_OPT(ZMQ_LAST_ENDPOINT, last_endpoint);
1543
#endif
1544
#ifdef ZMQ_LINGER
1545
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_LINGER, linger, int);
1546
#endif
1547
#ifdef ZMQ_MAXMSGSIZE
1548
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MAXMSGSIZE, maxmsgsize, int64_t);
1549
#endif
1550
#ifdef ZMQ_MECHANISM
1551
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MECHANISM, mechanism, int);
1552
#endif
1553
#ifdef ZMQ_METADATA
1554
ZMQ_DEFINE_ARRAY_OPT(ZMQ_METADATA, metadata);
1555
#endif
1556
#ifdef ZMQ_MULTICAST_HOPS
1557
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_HOPS, multicast_hops, int);
1558
#endif
1559
#ifdef ZMQ_MULTICAST_LOOP
1560
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_MULTICAST_LOOP, multicast_loop, int);
1561
#endif
1562
#ifdef ZMQ_MULTICAST_MAXTPDU
1563
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_MULTICAST_MAXTPDU, multicast_maxtpdu, int);
1564
#endif
1565
#ifdef ZMQ_ONLY_FIRST_SUBSCRIBE
1566
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ONLY_FIRST_SUBSCRIBE, only_first_subscribe, int);
1567
#endif
1568
#ifdef ZMQ_PLAIN_SERVER
1569
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PLAIN_SERVER, plain_server, int);
1570
#endif
1571
#ifdef ZMQ_PLAIN_PASSWORD
1572
ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_PASSWORD, plain_password);
1573
#endif
1574
#ifdef ZMQ_PLAIN_USERNAME
1575
ZMQ_DEFINE_ARRAY_OPT(ZMQ_PLAIN_USERNAME, plain_username);
1576
#endif
1577
#ifdef ZMQ_PRIORITY
1578
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_PRIORITY, priority, int);
1579
#endif
1580
#ifdef ZMQ_USE_FD
1581
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_USE_FD, use_fd, int);
1582
#endif
1583
#ifdef ZMQ_PROBE_ROUTER
1584
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_PROBE_ROUTER, probe_router, int);
1585
#endif
1586
#ifdef ZMQ_RATE
1587
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RATE, rate, int);
1588
#endif
1589
#ifdef ZMQ_RCVBUF
1590
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVBUF, rcvbuf, int);
1591
#endif
1592
#ifdef ZMQ_RCVHWM
1593
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVHWM, rcvhwm, int);
1594
#endif
1595
#ifdef ZMQ_RCVMORE
1596
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_RCVMORE, rcvmore, int);
1597
#endif
1598
#ifdef ZMQ_RCVTIMEO
1599
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RCVTIMEO, rcvtimeo, int);
1600
#endif
1601
#ifdef ZMQ_RECONNECT_IVL
1602
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL, reconnect_ivl, int);
1603
#endif
1604
#ifdef ZMQ_RECONNECT_IVL_MAX
1605
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_IVL_MAX, reconnect_ivl_max, int);
1606
#endif
1607
#ifdef ZMQ_RECONNECT_STOP
1608
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECONNECT_STOP, reconnect_stop, int);
1609
#endif
1610
#ifdef ZMQ_RECOVERY_IVL
1611
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_RECOVERY_IVL, recovery_ivl, int);
1612
#endif
1613
#ifdef ZMQ_REQ_CORRELATE
1614
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_CORRELATE, req_correlate, int);
1615
#endif
1616
#ifdef ZMQ_REQ_RELAXED
1617
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_REQ_RELAXED, req_relaxed, int);
1618
#endif
1619
#ifdef ZMQ_ROUTER_HANDOVER
1620
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_HANDOVER, router_handover, int);
1621
#endif
1622
#ifdef ZMQ_ROUTER_MANDATORY
1623
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ROUTER_MANDATORY, router_mandatory, int);
1624
#endif
1625
#ifdef ZMQ_ROUTER_NOTIFY
1626
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_ROUTER_NOTIFY, router_notify, int);
1627
#endif
1628
#ifdef ZMQ_ROUTING_ID
1629
ZMQ_DEFINE_ARRAY_OPT_BINARY(ZMQ_ROUTING_ID, routing_id);
1630
#endif
1631
#ifdef ZMQ_SNDBUF
1632
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDBUF, sndbuf, int);
1633
#endif
1634
#ifdef ZMQ_SNDHWM
1635
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDHWM, sndhwm, int);
1636
#endif
1637
#ifdef ZMQ_SNDTIMEO
1638
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_SNDTIMEO, sndtimeo, int);
1639
#endif
1640
#ifdef ZMQ_SOCKS_PASSWORD
1641
ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PASSWORD, socks_password);
1642
#endif
1643
#ifdef ZMQ_SOCKS_PROXY
1644
ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_PROXY, socks_proxy);
1645
#endif
1646
#ifdef ZMQ_SOCKS_USERNAME
1647
ZMQ_DEFINE_ARRAY_OPT(ZMQ_SOCKS_USERNAME, socks_username);
1648
#endif
1649
#ifdef ZMQ_STREAM_NOTIFY
1650
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_STREAM_NOTIFY, stream_notify, int);
1651
#endif
1652
#ifdef ZMQ_SUBSCRIBE
1653
ZMQ_DEFINE_ARRAY_OPT(ZMQ_SUBSCRIBE, subscribe);
1654
#endif
1655
#ifdef ZMQ_TCP_KEEPALIVE
1656
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE, tcp_keepalive, int);
1657
#endif
1658
#ifdef ZMQ_TCP_KEEPALIVE_CNT
1659
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_CNT, tcp_keepalive_cnt, int);
1660
#endif
1661
#ifdef ZMQ_TCP_KEEPALIVE_IDLE
1662
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_IDLE, tcp_keepalive_idle, int);
1663
#endif
1664
#ifdef ZMQ_TCP_KEEPALIVE_INTVL
1665
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_KEEPALIVE_INTVL, tcp_keepalive_intvl, int);
1666
#endif
1667
#ifdef ZMQ_TCP_MAXRT
1668
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TCP_MAXRT, tcp_maxrt, int);
1669
#endif
1670
#ifdef ZMQ_THREAD_SAFE
1671
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_THREAD_SAFE, thread_safe, int);
1672
#endif
1673
#ifdef ZMQ_TOS
1674
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TOS, tos, int);
1675
#endif
1676
#ifdef ZMQ_TYPE
1677
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, type, int);
1678
#ifdef ZMQ_CPP11
1679
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_TYPE, socket_type, socket_type);
1680
#endif // ZMQ_CPP11
1681
#endif // ZMQ_TYPE
1682
#ifdef ZMQ_UNSUBSCRIBE
1683
ZMQ_DEFINE_ARRAY_OPT(ZMQ_UNSUBSCRIBE, unsubscribe);
1684
#endif
1685
#ifdef ZMQ_VMCI_BUFFER_SIZE
1686
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_SIZE, vmci_buffer_size, uint64_t);
1687
#endif
1688
#ifdef ZMQ_VMCI_BUFFER_MIN_SIZE
1689
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MIN_SIZE, vmci_buffer_min_size, uint64_t);
1690
#endif
1691
#ifdef ZMQ_VMCI_BUFFER_MAX_SIZE
1692
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_BUFFER_MAX_SIZE, vmci_buffer_max_size, uint64_t);
1693
#endif
1694
#ifdef ZMQ_VMCI_CONNECT_TIMEOUT
1695
ZMQ_DEFINE_INTEGRAL_OPT(ZMQ_VMCI_CONNECT_TIMEOUT, vmci_connect_timeout, int);
1696
#endif
1697
#ifdef ZMQ_XPUB_VERBOSE
1698
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSE, xpub_verbose, int);
1699
#endif
1700
#ifdef ZMQ_XPUB_VERBOSER
1701
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_VERBOSER, xpub_verboser, int);
1702
#endif
1703
#ifdef ZMQ_XPUB_MANUAL
1704
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL, xpub_manual, int);
1705
#endif
1706
#ifdef ZMQ_XPUB_MANUAL_LAST_VALUE
1707
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_MANUAL_LAST_VALUE, xpub_manual_last_value, int);
1708
#endif
1709
#ifdef ZMQ_XPUB_NODROP
1710
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_XPUB_NODROP, xpub_nodrop, int);
1711
#endif
1712
#ifdef ZMQ_XPUB_WELCOME_MSG
1713
ZMQ_DEFINE_ARRAY_OPT(ZMQ_XPUB_WELCOME_MSG, xpub_welcome_msg);
1714
#endif
1715
#ifdef ZMQ_ZAP_ENFORCE_DOMAIN
1716
ZMQ_DEFINE_INTEGRAL_BOOL_UNIT_OPT(ZMQ_ZAP_ENFORCE_DOMAIN, zap_enforce_domain, int);
1717
#endif
1718
#ifdef ZMQ_ZAP_DOMAIN
1719
ZMQ_DEFINE_ARRAY_OPT(ZMQ_ZAP_DOMAIN, zap_domain);
1720
#endif
1721

1722
} // namespace sockopt
1723
#endif // ZMQ_CPP11
1724

1725

1726
namespace detail
1727
{
1728
class socket_base
1729
{
1730
  public:
1731
    socket_base() ZMQ_NOTHROW : _handle(ZMQ_NULLPTR) {}
76✔
1732
    ZMQ_EXPLICIT socket_base(void *handle) ZMQ_NOTHROW : _handle(handle) {}
492✔
1733

1734
    template<typename T>
1735
    ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt")
1736
    void setsockopt(int option_, T const &optval)
1737
    {
1738
        setsockopt(option_, &optval, sizeof(T));
1739
    }
1740

1741
    ZMQ_CPP11_DEPRECATED("from 4.7.0, use `set` taking option from zmq::sockopt")
1742
    void setsockopt(int option_, const void *optval_, size_t optvallen_)
1743
    {
1744
        int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_);
1745
        if (rc != 0)
1746
            throw error_t();
1747
    }
1748

1749
    ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt")
1750
    void getsockopt(int option_, void *optval_, size_t *optvallen_) const
1751
    {
1752
        int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_);
1753
        if (rc != 0)
1754
            throw error_t();
1755
    }
1756

1757
    template<typename T>
1758
    ZMQ_CPP11_DEPRECATED("from 4.7.0, use `get` taking option from zmq::sockopt")
1759
    T getsockopt(int option_) const
1760
    {
1761
        T optval;
1762
        size_t optlen = sizeof(T);
1763
        getsockopt(option_, &optval, &optlen);
1764
        return optval;
1765
    }
1766

1767
#ifdef ZMQ_CPP11
1768
    // Set integral socket option, e.g.
1769
    // `socket.set(zmq::sockopt::linger, 0)`
1770
    template<int Opt, class T, bool BoolUnit>
1771
    void set(sockopt::integral_option<Opt, T, BoolUnit>, const T &val)
49✔
1772
    {
1773
        static_assert(std::is_integral<T>::value, "T must be integral");
1774
        set_option(Opt, &val, sizeof val);
49✔
1775
    }
48✔
1776

1777
    // Set integral socket option from boolean, e.g.
1778
    // `socket.set(zmq::sockopt::immediate, false)`
1779
    template<int Opt, class T>
1780
    void set(sockopt::integral_option<Opt, T, true>, bool val)
1✔
1781
    {
1782
        static_assert(std::is_integral<T>::value, "T must be integral");
1783
        T rep_val = val;
1✔
1784
        set_option(Opt, &rep_val, sizeof rep_val);
1✔
1785
    }
1✔
1786

1787
    // Set array socket option, e.g.
1788
    // `socket.set(zmq::sockopt::plain_username, "foo123")`
1789
    template<int Opt, int NullTerm>
1790
    void set(sockopt::array_option<Opt, NullTerm>, const char *buf)
1✔
1791
    {
1792
        set_option(Opt, buf, std::strlen(buf));
1✔
1793
    }
1✔
1794

1795
    // Set array socket option, e.g.
1796
    // `socket.set(zmq::sockopt::routing_id, zmq::buffer(id))`
1797
    template<int Opt, int NullTerm>
1798
    void set(sockopt::array_option<Opt, NullTerm>, const_buffer buf)
2✔
1799
    {
1800
        set_option(Opt, buf.data(), buf.size());
2✔
1801
    }
2✔
1802

1803
    // Set array socket option, e.g.
1804
    // `socket.set(zmq::sockopt::routing_id, id_str)`
1805
    template<int Opt, int NullTerm>
1806
    void set(sockopt::array_option<Opt, NullTerm>, const std::string &buf)
10✔
1807
    {
1808
        set_option(Opt, buf.data(), buf.size());
10✔
1809
    }
10✔
1810

1811
#if CPPZMQ_HAS_STRING_VIEW
1812
    // Set array socket option, e.g.
1813
    // `socket.set(zmq::sockopt::routing_id, id_str)`
1814
    template<int Opt, int NullTerm>
1815
    void set(sockopt::array_option<Opt, NullTerm>, std::string_view buf)
1✔
1816
    {
1817
        set_option(Opt, buf.data(), buf.size());
1✔
1818
    }
1✔
1819
#endif
1820

1821
    // Get scalar socket option, e.g.
1822
    // `auto opt = socket.get(zmq::sockopt::linger)`
1823
    template<int Opt, class T, bool BoolUnit>
1824
    ZMQ_NODISCARD T get(sockopt::integral_option<Opt, T, BoolUnit>) const
45✔
1825
    {
1826
        static_assert(std::is_scalar<T>::value, "T must be scalar");
1827
        T val;
1828
        size_t size = sizeof val;
45✔
1829
        get_option(Opt, &val, &size);
45✔
1830
        assert(size == sizeof val);
45✔
1831
        return val;
45✔
1832
    }
1833

1834
    // Get array socket option, writes to buf, returns option size in bytes, e.g.
1835
    // `size_t optsize = socket.get(zmq::sockopt::routing_id, zmq::buffer(id))`
1836
    template<int Opt, int NullTerm>
1837
    ZMQ_NODISCARD size_t get(sockopt::array_option<Opt, NullTerm>,
47✔
1838
                             mutable_buffer buf) const
1839
    {
1840
        size_t size = buf.size();
47✔
1841
        get_option(Opt, buf.data(), &size);
47✔
1842
        return size;
46✔
1843
    }
1844

1845
    // Get array socket option as string (initializes the string buffer size to init_size) e.g.
1846
    // `auto s = socket.get(zmq::sockopt::routing_id)`
1847
    // Note: removes the null character from null-terminated string options,
1848
    // i.e. the string size excludes the null character.
1849
    template<int Opt, int NullTerm>
1850
    ZMQ_NODISCARD std::string get(sockopt::array_option<Opt, NullTerm>,
7✔
1851
                                  size_t init_size = 1024) const
1852
    {
1853
        if ZMQ_CONSTEXPR_IF (NullTerm == 2) {
1854
            if (init_size == 1024) {
×
1855
                init_size = 41; // get as Z85 string
×
1856
            }
1857
        }
1858
        std::string str(init_size, '\0');
7✔
1859
        size_t size = get(sockopt::array_option<Opt>{}, buffer(str));
7✔
1860
        if ZMQ_CONSTEXPR_IF (NullTerm == 1) {
1861
            if (size > 0) {
5✔
1862
                assert(str[size - 1] == '\0');
5✔
1863
                --size;
5✔
1864
            }
1865
        } else if ZMQ_CONSTEXPR_IF (NullTerm == 2) {
1866
            assert(size == 32 || size == 41);
×
1867
            if (size == 41) {
×
1868
                assert(str[size - 1] == '\0');
×
1869
                --size;
×
1870
            }
1871
        }
1872
        str.resize(size);
7✔
1873
        return str;
7✔
1874
    }
1875
#endif
1876

1877
    void bind(std::string const &addr) { bind(addr.c_str()); }
1878

1879
    void bind(const char *addr_)
77✔
1880
    {
1881
        int rc = zmq_bind(_handle, addr_);
77✔
1882
        if (rc != 0)
77✔
1883
            throw error_t();
×
1884
    }
77✔
1885

1886
    void unbind(std::string const &addr) { unbind(addr.c_str()); }
1887

1888
    void unbind(const char *addr_)
1889
    {
1890
        int rc = zmq_unbind(_handle, addr_);
1891
        if (rc != 0)
1892
            throw error_t();
1893
    }
1894

1895
    void connect(std::string const &addr) { connect(addr.c_str()); }
38✔
1896

1897
    void connect(const char *addr_)
75✔
1898
    {
1899
        int rc = zmq_connect(_handle, addr_);
75✔
1900
        if (rc != 0)
75✔
1901
            throw error_t();
1✔
1902
    }
74✔
1903

1904
    void disconnect(std::string const &addr) { disconnect(addr.c_str()); }
1905

1906
    void disconnect(const char *addr_)
1907
    {
1908
        int rc = zmq_disconnect(_handle, addr_);
1909
        if (rc != 0)
1910
            throw error_t();
1911
    }
1912

1913
    ZMQ_DEPRECATED("from 4.7.1, use handle() != nullptr or operator bool")
1914
    bool connected() const ZMQ_NOTHROW { return (_handle != ZMQ_NULLPTR); }
1915

1916
    ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking a const_buffer and send_flags")
1917
    size_t send(const void *buf_, size_t len_, int flags_ = 0)
1918
    {
1919
        int nbytes = zmq_send(_handle, buf_, len_, flags_);
1920
        if (nbytes >= 0)
1921
            return static_cast<size_t>(nbytes);
1922
        if (zmq_errno() == EAGAIN)
1923
            return 0;
1924
        throw error_t();
1925
    }
1926

1927
    ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags")
1928
    bool send(message_t &msg_,
1929
              int flags_ = 0) // default until removed
1930
    {
1931
        int nbytes = zmq_msg_send(msg_.handle(), _handle, flags_);
1932
        if (nbytes >= 0)
1933
            return true;
1934
        if (zmq_errno() == EAGAIN)
1935
            return false;
1936
        throw error_t();
1937
    }
1938

1939
    template<typename T>
1940
    ZMQ_CPP11_DEPRECATED(
1941
      "from 4.4.1, use send taking message_t or buffer (for contiguous "
1942
      "ranges), and send_flags")
1943
    bool send(T first, T last, int flags_ = 0)
1944
    {
1945
        zmq::message_t msg(first, last);
1946
        int nbytes = zmq_msg_send(msg.handle(), _handle, flags_);
1947
        if (nbytes >= 0)
1948
            return true;
1949
        if (zmq_errno() == EAGAIN)
1950
            return false;
1951
        throw error_t();
1952
    }
1953

1954
#ifdef ZMQ_HAS_RVALUE_REFS
1955
    ZMQ_CPP11_DEPRECATED("from 4.3.1, use send taking message_t and send_flags")
1956
    bool send(message_t &&msg_,
1957
              int flags_ = 0) // default until removed
1958
    {
1959
#ifdef ZMQ_CPP11
1960
        return send(msg_, static_cast<send_flags>(flags_)).has_value();
1961
#else
1962
        return send(msg_, flags_);
1963
#endif
1964
    }
1965
#endif
1966

1967
#ifdef ZMQ_CPP11
1968
    send_result_t send(const_buffer buf, send_flags flags = send_flags::none)
30✔
1969
    {
1970
        const int nbytes =
1971
          zmq_send(_handle, buf.data(), buf.size(), static_cast<int>(flags));
30✔
1972
        if (nbytes >= 0)
30✔
1973
            return static_cast<size_t>(nbytes);
26✔
1974
        if (zmq_errno() == EAGAIN)
4✔
1975
            return {};
3✔
1976
        throw error_t();
1✔
1977
    }
1978

1979
    send_result_t send(message_t &msg, send_flags flags)
60✔
1980
    {
1981
        int nbytes = zmq_msg_send(msg.handle(), _handle, static_cast<int>(flags));
60✔
1982
        if (nbytes >= 0)
60✔
1983
            return static_cast<size_t>(nbytes);
57✔
1984
        if (zmq_errno() == EAGAIN)
3✔
1985
            return {};
2✔
1986
        throw error_t();
1✔
1987
    }
1988

1989
    send_result_t send(message_t &&msg, send_flags flags)
37✔
1990
    {
1991
        return send(msg, flags);
37✔
1992
    }
1993
#endif
1994

1995
    ZMQ_CPP11_DEPRECATED(
1996
      "from 4.3.1, use recv taking a mutable_buffer and recv_flags")
1997
    size_t recv(void *buf_, size_t len_, int flags_ = 0)
1998
    {
1999
        int nbytes = zmq_recv(_handle, buf_, len_, flags_);
2000
        if (nbytes >= 0)
2001
            return static_cast<size_t>(nbytes);
2002
        if (zmq_errno() == EAGAIN)
2003
            return 0;
2004
        throw error_t();
2005
    }
2006

2007
    ZMQ_CPP11_DEPRECATED(
2008
      "from 4.3.1, use recv taking a reference to message_t and recv_flags")
2009
    bool recv(message_t *msg_, int flags_ = 0)
1✔
2010
    {
2011
        int nbytes = zmq_msg_recv(msg_->handle(), _handle, flags_);
1✔
2012
        if (nbytes >= 0)
1✔
2013
            return true;
1✔
2014
        if (zmq_errno() == EAGAIN)
×
2015
            return false;
×
2016
        throw error_t();
×
2017
    }
2018

2019
#ifdef ZMQ_CPP11
2020
    ZMQ_NODISCARD
2021
    recv_buffer_result_t recv(mutable_buffer buf,
5✔
2022
                              recv_flags flags = recv_flags::none)
2023
    {
2024
        const int nbytes =
2025
          zmq_recv(_handle, buf.data(), buf.size(), static_cast<int>(flags));
5✔
2026
        if (nbytes >= 0) {
5✔
2027
            return recv_buffer_size{
×
2028
              (std::min)(static_cast<size_t>(nbytes), buf.size()),
6✔
2029
              static_cast<size_t>(nbytes)};
3✔
2030
        }
2031
        if (zmq_errno() == EAGAIN)
2✔
2032
            return {};
1✔
2033
        throw error_t();
1✔
2034
    }
2035

2036
    ZMQ_NODISCARD
2037
    recv_result_t recv(message_t &msg, recv_flags flags = recv_flags::none)
36✔
2038
    {
2039
        const int nbytes =
2040
          zmq_msg_recv(msg.handle(), _handle, static_cast<int>(flags));
36✔
2041
        if (nbytes >= 0) {
36✔
2042
            assert(msg.size() == static_cast<size_t>(nbytes));
29✔
2043
            return static_cast<size_t>(nbytes);
29✔
2044
        }
2045
        if (zmq_errno() == EAGAIN)
7✔
2046
            return {};
5✔
2047
        throw error_t();
2✔
2048
    }
2049
#endif
2050

2051
#if defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 0)
2052
    void join(const char *group)
2053
    {
2054
        int rc = zmq_join(_handle, group);
2055
        if (rc != 0)
2056
            throw error_t();
2057
    }
2058

2059
    void leave(const char *group)
2060
    {
2061
        int rc = zmq_leave(_handle, group);
2062
        if (rc != 0)
2063
            throw error_t();
2064
    }
2065
#endif
2066

2067
    ZMQ_NODISCARD void *handle() ZMQ_NOTHROW { return _handle; }
240✔
2068
    ZMQ_NODISCARD const void *handle() const ZMQ_NOTHROW { return _handle; }
70✔
2069

2070
    ZMQ_EXPLICIT operator bool() const ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; }
2✔
2071
    // note: non-const operator bool can be removed once
2072
    // operator void* is removed from socket_t
2073
    ZMQ_EXPLICIT operator bool() ZMQ_NOTHROW { return _handle != ZMQ_NULLPTR; }
28✔
2074

2075
  protected:
2076
    void *_handle;
2077

2078
  private:
2079
    void set_option(int option_, const void *optval_, size_t optvallen_)
64✔
2080
    {
2081
        int rc = zmq_setsockopt(_handle, option_, optval_, optvallen_);
64✔
2082
        if (rc != 0)
64✔
2083
            throw error_t();
1✔
2084
    }
63✔
2085

2086
    void get_option(int option_, void *optval_, size_t *optvallen_) const
92✔
2087
    {
2088
        int rc = zmq_getsockopt(_handle, option_, optval_, optvallen_);
92✔
2089
        if (rc != 0)
92✔
2090
            throw error_t();
1✔
2091
    }
91✔
2092
};
2093
} // namespace detail
2094

2095
struct from_handle_t
2096
{
2097
    struct _private
2098
    {
2099
    }; // disabling use other than with from_handle
2100
    ZMQ_CONSTEXPR_FN ZMQ_EXPLICIT from_handle_t(_private /*p*/) ZMQ_NOTHROW {}
2101
};
2102

2103
ZMQ_CONSTEXPR_VAR from_handle_t from_handle =
2104
  from_handle_t(from_handle_t::_private());
2105

2106
// A non-owning nullable reference to a socket.
2107
// The reference is invalidated on socket close or destruction.
2108
class socket_ref : public detail::socket_base
2109
{
2110
  public:
2111
    socket_ref() ZMQ_NOTHROW : detail::socket_base() {}
73✔
2112
#ifdef ZMQ_CPP11
2113
    socket_ref(std::nullptr_t) ZMQ_NOTHROW : detail::socket_base() {}
3✔
2114
#endif
2115
    socket_ref(from_handle_t /*fh*/, void *handle) ZMQ_NOTHROW
148✔
2116
        : detail::socket_base(handle)
148✔
2117
    {
2118
    }
148✔
2119
};
2120

2121
#ifdef ZMQ_CPP11
2122
inline bool operator==(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW
6✔
2123
{
2124
    return sr.handle() == nullptr;
6✔
2125
}
2126
inline bool operator==(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW
1✔
2127
{
2128
    return sr.handle() == nullptr;
1✔
2129
}
2130
inline bool operator!=(socket_ref sr, std::nullptr_t /*p*/) ZMQ_NOTHROW
2✔
2131
{
2132
    return !(sr == nullptr);
2✔
2133
}
2134
inline bool operator!=(std::nullptr_t /*p*/, socket_ref sr) ZMQ_NOTHROW
1✔
2135
{
2136
    return !(sr == nullptr);
1✔
2137
}
2138
#endif
2139

2140
inline bool operator==(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW
31✔
2141
{
2142
    return std::equal_to<const void *>()(a.handle(), b.handle());
31✔
2143
}
2144
inline bool operator!=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW
3✔
2145
{
2146
    return !(a == b);
3✔
2147
}
2148
inline bool operator<(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW
4✔
2149
{
2150
    return std::less<const void *>()(a.handle(), b.handle());
4✔
2151
}
2152
inline bool operator>(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW
2✔
2153
{
2154
    return b < a;
2✔
2155
}
2156
inline bool operator<=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW
1✔
2157
{
2158
    return !(a > b);
1✔
2159
}
2160
inline bool operator>=(const detail::socket_base& a, const detail::socket_base& b) ZMQ_NOTHROW
1✔
2161
{
2162
    return !(a < b);
1✔
2163
}
2164

2165
} // namespace zmq
2166

2167
#ifdef ZMQ_CPP11
2168
namespace std
2169
{
2170
template<> struct hash<zmq::socket_ref>
2171
{
2172
    size_t operator()(zmq::socket_ref sr) const ZMQ_NOTHROW
81✔
2173
    {
2174
        return hash<void *>()(sr.handle());
81✔
2175
    }
2176
};
2177
} // namespace std
2178
#endif
2179

2180
namespace zmq
2181
{
2182
class socket_t : public detail::socket_base
2183
{
2184
    friend class monitor_t;
2185

2186
  public:
2187
    socket_t() ZMQ_NOTHROW : detail::socket_base(ZMQ_NULLPTR), ctxptr(ZMQ_NULLPTR) {}
18✔
2188

2189
    socket_t(context_t &context_, int type_) :
201✔
2190
        detail::socket_base(zmq_socket(context_.handle(), type_)),
2191
        ctxptr(context_.handle())
201✔
2192
    {
2193
        if (_handle == ZMQ_NULLPTR)
201✔
2194
            throw error_t();
×
2195
    }
201✔
2196

2197
#ifdef ZMQ_CPP11
2198
    socket_t(context_t &context_, socket_type type_) :
139✔
2199
        socket_t(context_, static_cast<int>(type_))
139✔
2200
    {
2201
    }
139✔
2202
#endif
2203

2204
#ifdef ZMQ_HAS_RVALUE_REFS
2205
    socket_t(socket_t &&rhs) ZMQ_NOTHROW : detail::socket_base(rhs._handle),
117✔
2206
                                           ctxptr(rhs.ctxptr)
117✔
2207
    {
2208
        rhs._handle = ZMQ_NULLPTR;
117✔
2209
        rhs.ctxptr = ZMQ_NULLPTR;
117✔
2210
    }
117✔
2211
    socket_t &operator=(socket_t &&rhs) ZMQ_NOTHROW
20✔
2212
    {
2213
        close();
20✔
2214
        std::swap(_handle, rhs._handle);
20✔
2215
        std::swap(ctxptr, rhs.ctxptr);
20✔
2216
        return *this;
20✔
2217
    }
2218
#endif
2219

2220
    ~socket_t() ZMQ_NOTHROW { close(); }
344✔
2221

2222
    operator void *() ZMQ_NOTHROW { return _handle; }
20✔
2223

2224
    operator void const *() const ZMQ_NOTHROW { return _handle; }
×
2225

2226
    void close() ZMQ_NOTHROW
384✔
2227
    {
2228
        if (_handle == ZMQ_NULLPTR)
384✔
2229
            // already closed
2230
            return;
175✔
2231
        int rc = zmq_close(_handle);
209✔
2232
        ZMQ_ASSERT(rc == 0);
209✔
2233
        _handle = ZMQ_NULLPTR;
209✔
2234
        ctxptr = ZMQ_NULLPTR;
209✔
2235
    }
2236

2237
    void swap(socket_t &other) ZMQ_NOTHROW
1✔
2238
    {
2239
        std::swap(_handle, other._handle);
1✔
2240
        std::swap(ctxptr, other.ctxptr);
1✔
2241
    }
1✔
2242

2243
    operator socket_ref() ZMQ_NOTHROW { return socket_ref(from_handle, _handle); }
147✔
2244

2245
  private:
2246
    void *ctxptr;
2247

2248
    socket_t(const socket_t &) ZMQ_DELETED_FUNCTION;
2249
    void operator=(const socket_t &) ZMQ_DELETED_FUNCTION;
2250

2251
    // used by monitor_t
2252
    socket_t(void *context_, int type_) :
8✔
2253
        detail::socket_base(zmq_socket(context_, type_)), ctxptr(context_)
8✔
2254
    {
2255
        if (_handle == ZMQ_NULLPTR)
8✔
2256
            throw error_t();
×
2257
        if (ctxptr == ZMQ_NULLPTR)
8✔
2258
            throw error_t();
×
2259
    }
8✔
2260
};
2261

2262
inline void swap(socket_t &a, socket_t &b) ZMQ_NOTHROW
1✔
2263
{
2264
    a.swap(b);
1✔
2265
}
1✔
2266

2267
ZMQ_DEPRECATED("from 4.3.1, use proxy taking socket_t objects")
2268
inline void proxy(void *frontend, void *backend, void *capture)
2269
{
2270
    int rc = zmq_proxy(frontend, backend, capture);
2271
    if (rc != 0)
2272
        throw error_t();
2273
}
2274

2275
inline void
2276
proxy(socket_ref frontend, socket_ref backend, socket_ref capture = socket_ref())
1✔
2277
{
2278
    int rc = zmq_proxy(frontend.handle(), backend.handle(), capture.handle());
1✔
2279
    if (rc != 0)
1✔
2280
        throw error_t();
1✔
2281
}
×
2282

2283
#ifdef ZMQ_HAS_PROXY_STEERABLE
2284
ZMQ_DEPRECATED("from 4.3.1, use proxy_steerable taking socket_t objects")
2285
inline void
2286
proxy_steerable(void *frontend, void *backend, void *capture, void *control)
2287
{
2288
    int rc = zmq_proxy_steerable(frontend, backend, capture, control);
2289
    if (rc != 0)
2290
        throw error_t();
2291
}
2292

2293
inline void proxy_steerable(socket_ref frontend,
1✔
2294
                            socket_ref backend,
2295
                            socket_ref capture,
2296
                            socket_ref control)
2297
{
2298
    int rc = zmq_proxy_steerable(frontend.handle(), backend.handle(),
1✔
2299
                                 capture.handle(), control.handle());
2300
    if (rc != 0)
1✔
2301
        throw error_t();
1✔
2302
}
×
2303
#endif
2304

2305
class monitor_t
2306
{
2307
  public:
2308
    monitor_t() : _socket(), _monitor_socket() {}
13✔
2309

2310
    virtual ~monitor_t() { close(); }
15✔
2311

2312
#ifdef ZMQ_HAS_RVALUE_REFS
2313
    monitor_t(monitor_t &&rhs) ZMQ_NOTHROW : _socket(), _monitor_socket()
2✔
2314
    {
2315
        std::swap(_socket, rhs._socket);
2✔
2316
        std::swap(_monitor_socket, rhs._monitor_socket);
2✔
2317
    }
2✔
2318

2319
    monitor_t &operator=(monitor_t &&rhs) ZMQ_NOTHROW
3✔
2320
    {
2321
        close();
3✔
2322
        _socket = socket_ref();
3✔
2323
        std::swap(_socket, rhs._socket);
3✔
2324
        std::swap(_monitor_socket, rhs._monitor_socket);
3✔
2325
        return *this;
3✔
2326
    }
2327
#endif
2328

2329

2330
    void
2331
    monitor(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL)
2332
    {
2333
        monitor(socket, addr.c_str(), events);
2334
    }
2335

2336
    void monitor(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL)
2337
    {
2338
        init(socket, addr_, events);
2339
        while (true) {
2340
            check_event(-1);
2341
        }
2342
    }
2343

2344
    void init(socket_t &socket, std::string const &addr, int events = ZMQ_EVENT_ALL)
2345
    {
2346
        init(socket, addr.c_str(), events);
2347
    }
2348

2349
    void init(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL)
8✔
2350
    {
2351
        int rc = zmq_socket_monitor(socket.handle(), addr_, events);
8✔
2352
        if (rc != 0)
8✔
2353
            throw error_t();
×
2354

2355
        _socket = socket;
8✔
2356
        _monitor_socket = socket_t(socket.ctxptr, ZMQ_PAIR);
8✔
2357
        _monitor_socket.connect(addr_);
8✔
2358

2359
        on_monitor_started();
8✔
2360
    }
8✔
2361

2362
    bool check_event(int timeout = 0)
6✔
2363
    {
2364
        assert(_monitor_socket);
6✔
2365

2366
        zmq::pollitem_t items[] = {
6✔
2367
          {_monitor_socket.handle(), 0, ZMQ_POLLIN, 0},
6✔
2368
        };
6✔
2369

2370
        #ifdef ZMQ_CPP11
2371
        zmq::poll(&items[0], 1, std::chrono::milliseconds(timeout));
6✔
2372
        #else
2373
        zmq::poll(&items[0], 1, timeout);
2374
        #endif
2375

2376
        return process_event(items[0].revents);
12✔
2377
    }
2378

2379
#ifdef ZMQ_EVENT_MONITOR_STOPPED
2380
    void abort()
1✔
2381
    {
2382
        if (_socket)
1✔
2383
            zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0);
1✔
2384

2385
        _socket = socket_ref();
1✔
2386
    }
1✔
2387
#endif
2388
    virtual void on_monitor_started() {}
8✔
2389
    virtual void on_event_connected(const zmq_event_t &event_, const char *addr_)
×
2390
    {
2391
        (void) event_;
2392
        (void) addr_;
2393
    }
×
2394
    virtual void on_event_connect_delayed(const zmq_event_t &event_,
2✔
2395
                                          const char *addr_)
2396
    {
2397
        (void) event_;
2398
        (void) addr_;
2399
    }
2✔
2400
    virtual void on_event_connect_retried(const zmq_event_t &event_,
×
2401
                                          const char *addr_)
2402
    {
2403
        (void) event_;
2404
        (void) addr_;
2405
    }
×
2406
    virtual void on_event_listening(const zmq_event_t &event_, const char *addr_)
×
2407
    {
2408
        (void) event_;
2409
        (void) addr_;
2410
    }
×
2411
    virtual void on_event_bind_failed(const zmq_event_t &event_, const char *addr_)
×
2412
    {
2413
        (void) event_;
2414
        (void) addr_;
2415
    }
×
2416
    virtual void on_event_accepted(const zmq_event_t &event_, const char *addr_)
×
2417
    {
2418
        (void) event_;
2419
        (void) addr_;
2420
    }
×
2421
    virtual void on_event_accept_failed(const zmq_event_t &event_, const char *addr_)
×
2422
    {
2423
        (void) event_;
2424
        (void) addr_;
2425
    }
×
2426
    virtual void on_event_closed(const zmq_event_t &event_, const char *addr_)
×
2427
    {
2428
        (void) event_;
2429
        (void) addr_;
2430
    }
×
2431
    virtual void on_event_close_failed(const zmq_event_t &event_, const char *addr_)
×
2432
    {
2433
        (void) event_;
2434
        (void) addr_;
2435
    }
×
2436
    virtual void on_event_disconnected(const zmq_event_t &event_, const char *addr_)
×
2437
    {
2438
        (void) event_;
2439
        (void) addr_;
2440
    }
×
2441
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)
2442
    virtual void on_event_handshake_failed_no_detail(const zmq_event_t &event_,
×
2443
                                                     const char *addr_)
2444
    {
2445
        (void) event_;
2446
        (void) addr_;
2447
    }
×
2448
    virtual void on_event_handshake_failed_protocol(const zmq_event_t &event_,
×
2449
                                                    const char *addr_)
2450
    {
2451
        (void) event_;
2452
        (void) addr_;
2453
    }
×
2454
    virtual void on_event_handshake_failed_auth(const zmq_event_t &event_,
×
2455
                                                const char *addr_)
2456
    {
2457
        (void) event_;
2458
        (void) addr_;
2459
    }
×
2460
    virtual void on_event_handshake_succeeded(const zmq_event_t &event_,
×
2461
                                              const char *addr_)
2462
    {
2463
        (void) event_;
2464
        (void) addr_;
2465
    }
×
2466
#elif ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1)
2467
    virtual void on_event_handshake_failed(const zmq_event_t &event_,
2468
                                           const char *addr_)
2469
    {
2470
        (void) event_;
2471
        (void) addr_;
2472
    }
2473
    virtual void on_event_handshake_succeed(const zmq_event_t &event_,
2474
                                            const char *addr_)
2475
    {
2476
        (void) event_;
2477
        (void) addr_;
2478
    }
2479
#endif
2480
    virtual void on_event_unknown(const zmq_event_t &event_, const char *addr_)
×
2481
    {
2482
        (void) event_;
2483
        (void) addr_;
2484
    }
×
2485

2486
  protected:    
2487
    bool process_event(short events)
8✔
2488
    {
2489
        zmq::message_t eventMsg;
16✔
2490

2491
        if (events & ZMQ_POLLIN) {
8✔
2492
            int rc = zmq_msg_recv(eventMsg.handle(), _monitor_socket.handle(), 0);
7✔
2493
            if (rc == -1 && zmq_errno() == ETERM)
7✔
2494
                return false;
×
2495
            assert(rc != -1);
7✔
2496

2497
        } else {
2498
            return false;
1✔
2499
        }
2500

2501
#if ZMQ_VERSION_MAJOR >= 4
2502
        const char *data = static_cast<const char *>(eventMsg.data());
7✔
2503
        zmq_event_t msgEvent;
2504
        memcpy(&msgEvent.event, data, sizeof(uint16_t));
7✔
2505
        data += sizeof(uint16_t);
7✔
2506
        memcpy(&msgEvent.value, data, sizeof(int32_t));
7✔
2507
        zmq_event_t *event = &msgEvent;
7✔
2508
#else
2509
        zmq_event_t *event = static_cast<zmq_event_t *>(eventMsg.data());
2510
#endif
2511

2512
#ifdef ZMQ_NEW_MONITOR_EVENT_LAYOUT
2513
        zmq::message_t addrMsg;
14✔
2514
        int rc = zmq_msg_recv(addrMsg.handle(), _monitor_socket.handle(), 0);
7✔
2515
        if (rc == -1 && zmq_errno() == ETERM) {
7✔
2516
            return false;
×
2517
        }
2518

2519
        assert(rc != -1);
7✔
2520
        std::string address = addrMsg.to_string();
14✔
2521
#else
2522
        // 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.
2523
        std::string address = event->data.connected.addr;
2524
#endif
2525

2526
#ifdef ZMQ_EVENT_MONITOR_STOPPED
2527
        if (event->event == ZMQ_EVENT_MONITOR_STOPPED) {
7✔
2528
            return false;
1✔
2529
        }
2530

2531
#endif
2532

2533
        switch (event->event) {
6✔
2534
            case ZMQ_EVENT_CONNECTED:
2✔
2535
                on_event_connected(*event, address.c_str());
2✔
2536
                break;
2✔
2537
            case ZMQ_EVENT_CONNECT_DELAYED:
2✔
2538
                on_event_connect_delayed(*event, address.c_str());
2✔
2539
                break;
2✔
2540
            case ZMQ_EVENT_CONNECT_RETRIED:
×
2541
                on_event_connect_retried(*event, address.c_str());
×
2542
                break;
×
2543
            case ZMQ_EVENT_LISTENING:
×
2544
                on_event_listening(*event, address.c_str());
×
2545
                break;
×
2546
            case ZMQ_EVENT_BIND_FAILED:
×
2547
                on_event_bind_failed(*event, address.c_str());
×
2548
                break;
×
2549
            case ZMQ_EVENT_ACCEPTED:
1✔
2550
                on_event_accepted(*event, address.c_str());
1✔
2551
                break;
1✔
2552
            case ZMQ_EVENT_ACCEPT_FAILED:
×
2553
                on_event_accept_failed(*event, address.c_str());
×
2554
                break;
×
2555
            case ZMQ_EVENT_CLOSED:
×
2556
                on_event_closed(*event, address.c_str());
×
2557
                break;
×
2558
            case ZMQ_EVENT_CLOSE_FAILED:
×
2559
                on_event_close_failed(*event, address.c_str());
×
2560
                break;
×
2561
            case ZMQ_EVENT_DISCONNECTED:
1✔
2562
                on_event_disconnected(*event, address.c_str());
1✔
2563
                break;
1✔
2564
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 0) || (defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3))
2565
            case ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL:
×
2566
                on_event_handshake_failed_no_detail(*event, address.c_str());
×
2567
                break;
×
2568
            case ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL:
×
2569
                on_event_handshake_failed_protocol(*event, address.c_str());
×
2570
                break;
×
2571
            case ZMQ_EVENT_HANDSHAKE_FAILED_AUTH:
×
2572
                on_event_handshake_failed_auth(*event, address.c_str());
×
2573
                break;
×
2574
            case ZMQ_EVENT_HANDSHAKE_SUCCEEDED:
×
2575
                on_event_handshake_succeeded(*event, address.c_str());
×
2576
                break;
×
2577
#elif defined(ZMQ_BUILD_DRAFT_API) && ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 1)
2578
            case ZMQ_EVENT_HANDSHAKE_FAILED:
2579
                on_event_handshake_failed(*event, address.c_str());
2580
                break;
2581
            case ZMQ_EVENT_HANDSHAKE_SUCCEED:
2582
                on_event_handshake_succeed(*event, address.c_str());
2583
                break;
2584
#endif
2585
            default:
×
2586
                on_event_unknown(*event, address.c_str());
×
2587
                break;
×
2588
        }
2589

2590
        return true;
6✔
2591
    }
2592

2593
    socket_ref monitor_socket() {return _monitor_socket;}
1✔
2594

2595
  private:
2596
    monitor_t(const monitor_t &) ZMQ_DELETED_FUNCTION;
2597
    void operator=(const monitor_t &) ZMQ_DELETED_FUNCTION;
2598

2599
    socket_ref _socket;
2600
    socket_t _monitor_socket;
2601

2602
    void close() ZMQ_NOTHROW
18✔
2603
    {
2604
        if (_socket)
18✔
2605
            zmq_socket_monitor(_socket.handle(), ZMQ_NULLPTR, 0);
7✔
2606
        _monitor_socket.close();
18✔
2607
    }
18✔
2608
};
2609

2610
#if defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER)
2611

2612
// polling events
2613
enum class event_flags : short
2614
{
2615
    none = 0,
2616
    pollin = ZMQ_POLLIN,
2617
    pollout = ZMQ_POLLOUT,
2618
    pollerr = ZMQ_POLLERR,
2619
    pollpri = ZMQ_POLLPRI
2620
};
2621

2622
constexpr event_flags operator|(event_flags a, event_flags b) noexcept
8✔
2623
{
2624
    return detail::enum_bit_or(a, b);
8✔
2625
}
2626
constexpr event_flags operator&(event_flags a, event_flags b) noexcept
5✔
2627
{
2628
    return detail::enum_bit_and(a, b);
5✔
2629
}
2630
constexpr event_flags operator^(event_flags a, event_flags b) noexcept
1✔
2631
{
2632
    return detail::enum_bit_xor(a, b);
1✔
2633
}
2634
constexpr event_flags operator~(event_flags a) noexcept
2✔
2635
{
2636
    return detail::enum_bit_not(a);
2✔
2637
}
2638

2639
struct no_user_data;
2640

2641
// layout compatible with zmq_poller_event_t
2642
template<class T = no_user_data> struct poller_event
2643
{
2644
    socket_ref socket;
2645
    ::zmq::fd_t fd;
2646
    T *user_data;
2647
    event_flags events;
2648
};
2649

2650
template<typename T = no_user_data> class poller_t
2651
{
2652
  public:
2653
    using event_type = poller_event<T>;
2654

2655
    poller_t() : poller_ptr(zmq_poller_new())
68✔
2656
    {
2657
        if (!poller_ptr)
68✔
2658
            throw error_t();
×
2659
    }
68✔
2660

2661
    template<
2662
      typename Dummy = void,
2663
      typename =
2664
        typename std::enable_if<!std::is_same<T, no_user_data>::value, Dummy>::type>
2665
    void add(zmq::socket_ref socket, event_flags events, T *user_data)
39✔
2666
    {
2667
        add_impl(socket, events, user_data);
39✔
2668
    }
37✔
2669

2670
    void add(zmq::socket_ref socket, event_flags events)
24✔
2671
    {
2672
        add_impl(socket, events, nullptr);
24✔
2673
    }
21✔
2674

2675
    template<
2676
      typename Dummy = void,
2677
      typename =
2678
        typename std::enable_if<!std::is_same<T, no_user_data>::value, Dummy>::type>
2679
    void add(fd_t fd, event_flags events, T *user_data)
3✔
2680
    {
2681
        add_impl(fd, events, user_data);
3✔
2682
    }
3✔
2683

2684
    void add(fd_t fd, event_flags events) { add_impl(fd, events, nullptr); }
2685

2686
    void remove(zmq::socket_ref socket)
21✔
2687
    {
2688
        if (0 != zmq_poller_remove(poller_ptr.get(), socket.handle())) {
21✔
2689
            throw error_t();
4✔
2690
        }
2691
    }
17✔
2692

2693
    void remove(fd_t fd)
2✔
2694
    {
2695
        if (0 != zmq_poller_remove_fd(poller_ptr.get(), fd)) {
2✔
2696
            throw error_t();
1✔
2697
        }
2698
    }
1✔
2699

2700
    void modify(zmq::socket_ref socket, event_flags events)
10✔
2701
    {
2702
        if (0
10✔
2703
            != zmq_poller_modify(poller_ptr.get(), socket.handle(),
10✔
2704
                                 static_cast<short>(events))) {
2705
            throw error_t();
6✔
2706
        }
2707
    }
4✔
2708

2709
    void modify(fd_t fd, event_flags events)
2710
    {
2711
        if (0
2712
            != zmq_poller_modify_fd(poller_ptr.get(), fd,
2713
                                 static_cast<short>(events))) {
2714
            throw error_t();
2715
        }
2716
    }
2717

2718
    template <typename Sequence>
2719
    size_t wait_all(Sequence &poller_events,
32✔
2720
                    const std::chrono::milliseconds timeout)
2721
    {
2722
        static_assert(std::is_same<typename Sequence::value_type, event_type>::value,
2723
                      "Sequence::value_type must be of poller_t::event_type");
2724
        int rc = zmq_poller_wait_all(
32✔
2725
          poller_ptr.get(),
2726
          reinterpret_cast<zmq_poller_event_t *>(poller_events.data()),
32✔
2727
          static_cast<int>(poller_events.size()),
32✔
2728
          static_cast<long>(timeout.count()));
32✔
2729
        if (rc > 0)
32✔
2730
            return static_cast<size_t>(rc);
26✔
2731

2732
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 2, 3)
2733
        if (zmq_errno() == EAGAIN)
6✔
2734
#else
2735
        if (zmq_errno() == ETIMEDOUT)
2736
#endif
2737
            return 0;
×
2738

2739
        throw error_t();
6✔
2740
    }
2741

2742
#if ZMQ_VERSION >= ZMQ_MAKE_VERSION(4, 3, 3)
2743
    size_t size() const noexcept
3✔
2744
    {
2745
        int rc = zmq_poller_size(const_cast<void *>(poller_ptr.get()));
3✔
2746
        ZMQ_ASSERT(rc >= 0);
3✔
2747
        return static_cast<size_t>(std::max(rc, 0));
3✔
2748
    }
2749
#endif
2750

2751
  private:
2752
    struct destroy_poller_t
2753
    {
2754
        void operator()(void *ptr) noexcept
68✔
2755
        {
2756
            int rc = zmq_poller_destroy(&ptr);
68✔
2757
            ZMQ_ASSERT(rc == 0);
68✔
2758
        }
68✔
2759
    };
2760

2761
    std::unique_ptr<void, destroy_poller_t> poller_ptr;
2762

2763
    void add_impl(zmq::socket_ref socket, event_flags events, T *user_data)
63✔
2764
    {
2765
        if (0
63✔
2766
            != zmq_poller_add(poller_ptr.get(), socket.handle(), user_data,
63✔
2767
                              static_cast<short>(events))) {
2768
            throw error_t();
5✔
2769
        }
2770
    }
58✔
2771

2772
    void add_impl(fd_t fd, event_flags events, T *user_data)
3✔
2773
    {
2774
        if (0
3✔
2775
            != zmq_poller_add_fd(poller_ptr.get(), fd, user_data,
3✔
2776
                                 static_cast<short>(events))) {
2777
            throw error_t();
×
2778
        }
2779
    }
3✔
2780
};
2781
#endif //  defined(ZMQ_BUILD_DRAFT_API) && defined(ZMQ_CPP11) && defined(ZMQ_HAVE_POLLER)
2782

2783
inline std::ostream &operator<<(std::ostream &os, const message_t &msg)
×
2784
{
2785
    return os << msg.str();
×
2786
}
2787

2788
} // namespace zmq
2789

2790
#endif // __ZMQ_HPP_INCLUDED__
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc