options.cpp 33.4 KB
Newer Older
1
/*
2
    Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
3

4
    This file is part of libzmq, the ZeroMQ core engine in C++.
5

6 7 8
    libzmq is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 3 of the License, or
9 10
    (at your option) any later version.

11 12 13 14 15 16 17 18 19 20 21 22 23 24
    As a special exception, the Contributors give you permission to link
    this library with independent modules to produce an executable,
    regardless of the license terms of these independent modules, and to
    copy and distribute the resulting executable under terms of your choice,
    provided that you also meet, for each linked independent module, the
    terms and conditions of the license of that module. An independent
    module is a module which is not derived from or based on this library.
    If you modify this library, you must extend this exception to your
    version of the library.

    libzmq is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    License for more details.
25

26
    You should have received a copy of the GNU Lesser General Public License
27 28 29
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

30
#include "precompiled.hpp"
31
#include <string.h>
32
#include <limits.h>
33
#include <set>
34

35
#include "options.hpp"
36
#include "err.hpp"
37
#include "macros.hpp"
38

39 40 41 42 43 44 45 46 47 48
#ifndef ZMQ_HAVE_WINDOWS
#include <net/if.h>
#endif

#if defined IFNAMSIZ
#define BINDDEVSIZ IFNAMSIZ
#else
#define BINDDEVSIZ 16
#endif

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
static int sockopt_invalid ()
{
#if defined(ZMQ_ACT_MILITANT)
    zmq_assert (false);
#endif
    errno = EINVAL;
    return -1;
}

int zmq::do_getsockopt (void *const optval_,
                        size_t *const optvallen_,
                        const std::string &value_)
{
    return do_getsockopt (optval_, optvallen_, value_.c_str (),
                          value_.size () + 1);
}

int zmq::do_getsockopt (void *const optval_,
                        size_t *const optvallen_,
                        const void *value_,
                        const size_t value_len_)
{
    // TODO behaviour is inconsistent with options_t::getsockopt; there, an
    // *exact* length match is required except for string-like (but not the
    // CURVE keys!) (and therefore null-ing remaining memory is a no-op, see
    // comment below)
    if (*optvallen_ < value_len_) {
        return sockopt_invalid ();
    }
    memcpy (optval_, value_, value_len_);
    // TODO why is the remaining memory null-ed?
80 81
    memset (static_cast<char *> (optval_) + value_len_, 0,
            *optvallen_ - value_len_);
82 83 84 85 86 87 88 89 90 91 92 93
    *optvallen_ = value_len_;
    return 0;
}

#ifdef ZMQ_HAVE_CURVE
static int do_getsockopt_curve_key (void *const optval_,
                                    size_t *const optvallen_,
                                    const uint8_t (&curve_key_)[CURVE_KEYSIZE])
{
    if (*optvallen_ == CURVE_KEYSIZE) {
        memcpy (optval_, curve_key_, CURVE_KEYSIZE);
        return 0;
94 95
    }
    if (*optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
96 97
        zmq_z85_encode (static_cast<char *> (optval_), curve_key_,
                        CURVE_KEYSIZE);
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
        return 0;
    }
    return sockopt_invalid ();
}
#endif

template <typename T>
int do_setsockopt (const void *const optval_,
                   const size_t optvallen_,
                   T *const out_value_)
{
    if (optvallen_ == sizeof (T)) {
        memcpy (out_value_, optval_, sizeof (T));
        return 0;
    }
    return sockopt_invalid ();
}

int zmq::do_setsockopt_int_as_bool_strict (const void *const optval_,
                                           const size_t optvallen_,
                                           bool *const out_value_)
{
    // TODO handling of values other than 0 or 1 is not consistent,
    // here it is disallowed, but for other options such as
    // ZMQ_ROUTER_RAW any positive value is accepted
123
    int value = -1;
124 125 126 127 128 129 130 131 132 133 134 135 136
    if (do_setsockopt (optval_, optvallen_, &value) == -1)
        return -1;
    if (value == 0 || value == 1) {
        *out_value_ = (value != 0);
        return 0;
    }
    return sockopt_invalid ();
}

int zmq::do_setsockopt_int_as_bool_relaxed (const void *const optval_,
                                            const size_t optvallen_,
                                            bool *const out_value_)
{
137
    int value = -1;
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
    if (do_setsockopt (optval_, optvallen_, &value) == -1)
        return -1;
    *out_value_ = (value != 0);
    return 0;
}

static int
do_setsockopt_string_allow_empty_strict (const void *const optval_,
                                         const size_t optvallen_,
                                         std::string *const out_value_,
                                         const size_t max_len_)
{
    // TODO why is optval_ != NULL not allowed in case of optvallen_== 0?
    // TODO why are empty strings allowed for some socket options, but not for others?
    if (optval_ == NULL && optvallen_ == 0) {
        out_value_->clear ();
        return 0;
155 156
    }
    if (optval_ != NULL && optvallen_ > 0 && optvallen_ <= max_len_) {
157
        out_value_->assign (static_cast<const char *> (optval_), optvallen_);
158 159 160 161 162 163 164 165 166 167 168 169 170 171
        return 0;
    }
    return sockopt_invalid ();
}

static int
do_setsockopt_string_allow_empty_relaxed (const void *const optval_,
                                          const size_t optvallen_,
                                          std::string *const out_value_,
                                          const size_t max_len_)
{
    // TODO use either do_setsockopt_string_allow_empty_relaxed or
    // do_setsockopt_string_allow_empty_strict everywhere
    if (optvallen_ > 0 && optvallen_ <= max_len_) {
172
        out_value_->assign (static_cast<const char *> (optval_), optvallen_);
173 174 175 176 177 178 179 180 181 182 183 184 185
        return 0;
    }
    return sockopt_invalid ();
}

template <typename T>
int do_setsockopt_set (const void *const optval_,
                       const size_t optvallen_,
                       std::set<T> *const set_)
{
    if (optvallen_ == 0 && optval_ == NULL) {
        set_->clear ();
        return 0;
186 187 188
    }
    if (optvallen_ == sizeof (T) && optval_ != NULL) {
        set_->insert (*(static_cast<const T *> (optval_)));
189 190 191 192 193
        return 0;
    }
    return sockopt_invalid ();
}

194 195 196
// TODO why is 1000 a sensible default?
const int default_hwm = 1000;

197
zmq::options_t::options_t () :
198 199
    sndhwm (default_hwm),
    rcvhwm (default_hwm),
malosek's avatar
malosek committed
200
    affinity (0),
201
    routing_id_size (0),
202
    rate (100),
203
    recovery_ivl (10000),
204
    multicast_hops (1),
205
    multicast_maxtpdu (1500),
206 207
    sndbuf (-1),
    rcvbuf (-1),
208
    tos (0),
209
    type (-1),
210
    linger (-1),
211
    connect_timeout (0),
212
    tcp_maxrt (0),
213
    reconnect_ivl (100),
214
    reconnect_ivl_max (0),
215
    backlog (100),
216
    maxmsgsize (-1),
217 218
    rcvtimeo (-1),
    sndtimeo (-1),
219
    ipv6 (false),
220
    immediate (0),
221
    filter (false),
222
    invert_matching (false),
223
    recv_routing_id (false),
224
    raw_socket (false),
225
    raw_notify (true),
226 227 228 229
    tcp_keepalive (-1),
    tcp_keepalive_cnt (-1),
    tcp_keepalive_idle (-1),
    tcp_keepalive_intvl (-1),
230
    mechanism (ZMQ_NULL),
231
    as_server (0),
232 233
    gss_principal_nt (ZMQ_GSSAPI_NT_HOSTBASED),
    gss_service_principal_nt (ZMQ_GSSAPI_NT_HOSTBASED),
234
    gss_plaintext (false),
danielkr's avatar
danielkr committed
235
    socket_id (0),
236
    conflate (false),
237
    handshake_ivl (30000),
Jonathan Reams's avatar
Jonathan Reams committed
238 239 240
    connected (false),
    heartbeat_ttl (0),
    heartbeat_interval (0),
241
    heartbeat_timeout (-1),
242
    use_fd (-1),
243
    zap_enforce_domain (false),
244
    loopback_fastpath (false),
245
    multicast_loop (true),
246
    zero_copy (true)
247
{
248 249 250
    memset (curve_public_key, 0, CURVE_KEYSIZE);
    memset (curve_secret_key, 0, CURVE_KEYSIZE);
    memset (curve_server_key, 0, CURVE_KEYSIZE);
Ilya Kulakov's avatar
Ilya Kulakov committed
251 252 253 254 255 256
#if defined ZMQ_HAVE_VMCI
    vmci_buffer_size = 0;
    vmci_buffer_min_size = 0;
    vmci_buffer_max_size = 0;
    vmci_connect_timeout = -1;
#endif
257
}
258

259
int zmq::options_t::set_curve_key (uint8_t *destination_,
260 261
                                   const void *optval_,
                                   size_t optvallen_)
262 263 264
{
    switch (optvallen_) {
        case CURVE_KEYSIZE:
265
            memcpy (destination_, optval_, optvallen_);
266 267 268 269
            mechanism = ZMQ_CURVE;
            return 0;

        case CURVE_KEYSIZE_Z85 + 1:
270 271
            if (zmq_z85_decode (destination_,
                                reinterpret_cast<const char *> (optval_))) {
272 273 274 275 276 277
                mechanism = ZMQ_CURVE;
                return 0;
            }
            break;

        case CURVE_KEYSIZE_Z85:
278
            char z85_key[CURVE_KEYSIZE_Z85 + 1];
279 280
            memcpy (z85_key, reinterpret_cast<const char *> (optval_),
                    optvallen_);
281
            z85_key[CURVE_KEYSIZE_Z85] = 0;
282
            if (zmq_z85_decode (destination_, z85_key)) {
283 284 285 286 287 288 289 290 291 292 293
                mechanism = ZMQ_CURVE;
                return 0;
            }
            break;

        default:
            break;
    }
    return -1;
}

294 295
const int deciseconds_per_millisecond = 100;

296 297 298
int zmq::options_t::setsockopt (int option_,
                                const void *optval_,
                                size_t optvallen_)
299
{
300
    bool is_int = (optvallen_ == sizeof (int));
301
    int value = 0;
302 303 304 305
    if (is_int)
        memcpy (&value, optval_, sizeof (int));
#if defined(ZMQ_ACT_MILITANT)
    bool malformed = true; //  Did caller pass a bad option value?
306
#endif
307

308
    switch (option_) {
309
        case ZMQ_SNDHWM:
310
            if (is_int && value >= 0) {
311
                sndhwm = value;
312 313
                return 0;
            }
314
            break;
315

316
        case ZMQ_RCVHWM:
317
            if (is_int && value >= 0) {
318
                rcvhwm = value;
319 320
                return 0;
            }
321
            break;
322

323
        case ZMQ_AFFINITY:
324
            return do_setsockopt (optval_, optvallen_, &affinity);
325

326 327
        case ZMQ_ROUTING_ID:
            //  Routing id is any binary string from 1 to 255 octets
328
            if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX) {
329
                routing_id_size = static_cast<unsigned char> (optvallen_);
330
                memcpy (routing_id, optval_, routing_id_size);
331
                return 0;
332 333
            }
            break;
334

335
        case ZMQ_RATE:
336
            if (is_int && value > 0) {
337
                rate = value;
338 339
                return 0;
            }
340
            break;
341

342
        case ZMQ_RECOVERY_IVL:
343
            if (is_int && value >= 0) {
344
                recovery_ivl = value;
345 346 347
                return 0;
            }
            break;
348

349
        case ZMQ_SNDBUF:
350
            if (is_int && value >= -1) {
351
                sndbuf = value;
352 353
                return 0;
            }
354
            break;
355

356
        case ZMQ_RCVBUF:
357
            if (is_int && value >= -1) {
358
                rcvbuf = value;
359 360
                return 0;
            }
361
            break;
362

363 364 365 366 367 368 369
        case ZMQ_TOS:
            if (is_int && value >= 0) {
                tos = value;
                return 0;
            }
            break;

370
        case ZMQ_LINGER:
371
            if (is_int && value >= -1) {
372
                linger.store (value);
373 374
                return 0;
            }
375
            break;
376

377 378 379 380 381 382 383
        case ZMQ_CONNECT_TIMEOUT:
            if (is_int && value >= 0) {
                connect_timeout = value;
                return 0;
            }
            break;

384
        case ZMQ_TCP_MAXRT:
385
            if (is_int && value >= 0) {
386
                tcp_maxrt = value;
387 388 389 390
                return 0;
            }
            break;

391
        case ZMQ_RECONNECT_IVL:
392
            if (is_int && value >= -1) {
393
                reconnect_ivl = value;
394 395
                return 0;
            }
396
            break;
397

398
        case ZMQ_RECONNECT_IVL_MAX:
399
            if (is_int && value >= 0) {
400
                reconnect_ivl_max = value;
401 402
                return 0;
            }
403
            break;
404

405
        case ZMQ_BACKLOG:
406
            if (is_int && value >= 0) {
407
                backlog = value;
408 409
                return 0;
            }
410
            break;
411

412
        case ZMQ_MAXMSGSIZE:
413
            return do_setsockopt (optval_, optvallen_, &maxmsgsize);
414

415
        case ZMQ_MULTICAST_HOPS:
416
            if (is_int && value > 0) {
417
                multicast_hops = value;
418 419
                return 0;
            }
420
            break;
421

422 423 424 425 426 427 428
        case ZMQ_MULTICAST_MAXTPDU:
            if (is_int && value > 0) {
                multicast_maxtpdu = value;
                return 0;
            }
            break;

429
        case ZMQ_RCVTIMEO:
430
            if (is_int && value >= -1) {
431
                rcvtimeo = value;
432 433
                return 0;
            }
434
            break;
435

436
        case ZMQ_SNDTIMEO:
437
            if (is_int && value >= -1) {
438
                sndtimeo = value;
439 440
                return 0;
            }
441
            break;
442

Pieter Hintjens's avatar
Pieter Hintjens committed
443
        /*  Deprecated in favor of ZMQ_IPV6  */
444 445 446 447 448 449 450 451
        case ZMQ_IPV4ONLY: {
            bool value;
            int rc =
              do_setsockopt_int_as_bool_strict (optval_, optvallen_, &value);
            if (rc == 0)
                ipv6 = !value;
            return rc;
        }
452

453 454
        /*  To replace the somewhat surprising IPV4ONLY */
        case ZMQ_IPV6:
455 456
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &ipv6);
457

458
        case ZMQ_SOCKS_PROXY:
459 460
            return do_setsockopt_string_allow_empty_strict (
              optval_, optvallen_, &socks_proxy_address, SIZE_MAX);
461

462
        case ZMQ_TCP_KEEPALIVE:
463
            if (is_int && (value == -1 || value == 0 || value == 1)) {
464
                tcp_keepalive = value;
465 466
                return 0;
            }
467
            break;
468

469
        case ZMQ_TCP_KEEPALIVE_CNT:
470
            if (is_int && (value == -1 || value >= 0)) {
471
                tcp_keepalive_cnt = value;
472 473
                return 0;
            }
474
            break;
475

476
        case ZMQ_TCP_KEEPALIVE_IDLE:
477
            if (is_int && (value == -1 || value >= 0)) {
478
                tcp_keepalive_idle = value;
479 480
                return 0;
            }
481
            break;
482

483
        case ZMQ_TCP_KEEPALIVE_INTVL:
484
            if (is_int && (value == -1 || value >= 0)) {
485
                tcp_keepalive_intvl = value;
486 487
                return 0;
            }
488
            break;
489

490
        case ZMQ_IMMEDIATE:
491
            // TODO why is immediate not bool (and called non_immediate, as its meaning appears to be reversed)
492
            if (is_int && (value == 0 || value == 1)) {
493
                immediate = value;
494 495
                return 0;
            }
496
            break;
497

498 499 500
        case ZMQ_TCP_ACCEPT_FILTER: {
            std::string filter_str;
            int rc = do_setsockopt_string_allow_empty_strict (
501
              optval_, optvallen_, &filter_str, UCHAR_MAX);
502 503 504 505 506 507 508 509 510
            if (rc == 0) {
                if (filter_str.empty ()) {
                    tcp_accept_filters.clear ();
                } else {
                    tcp_address_mask_t mask;
                    rc = mask.resolve (filter_str.c_str (), ipv6);
                    if (rc == 0) {
                        tcp_accept_filters.push_back (mask);
                    }
511 512
                }
            }
513 514
            return rc;
        }
515

516
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
517
        case ZMQ_IPC_FILTER_UID:
518 519 520
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_uid_accept_filters);

521

522
        case ZMQ_IPC_FILTER_GID:
523 524
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_gid_accept_filters);
525
#endif
526

527
#if defined ZMQ_HAVE_SO_PEERCRED
528
        case ZMQ_IPC_FILTER_PID:
529 530
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_pid_accept_filters);
531
#endif
532

533 534
        case ZMQ_PLAIN_SERVER:
            if (is_int && (value == 0 || value == 1)) {
535
                as_server = value;
536
                mechanism = value ? ZMQ_PLAIN : ZMQ_NULL;
537 538 539
                return 0;
            }
            break;
540

541 542 543 544
        case ZMQ_PLAIN_USERNAME:
            if (optvallen_ == 0 && optval_ == NULL) {
                mechanism = ZMQ_NULL;
                return 0;
545 546
            } else if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX
                       && optval_ != NULL) {
547 548
                plain_username.assign (static_cast<const char *> (optval_),
                                       optvallen_);
549
                as_server = 0;
550 551 552 553
                mechanism = ZMQ_PLAIN;
                return 0;
            }
            break;
554

555 556 557 558
        case ZMQ_PLAIN_PASSWORD:
            if (optvallen_ == 0 && optval_ == NULL) {
                mechanism = ZMQ_NULL;
                return 0;
559 560
            } else if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX
                       && optval_ != NULL) {
561 562
                plain_password.assign (static_cast<const char *> (optval_),
                                       optvallen_);
563
                as_server = 0;
564 565
                mechanism = ZMQ_PLAIN;
                return 0;
566
            }
567
            break;
568 569

        case ZMQ_ZAP_DOMAIN:
570
            return do_setsockopt_string_allow_empty_relaxed (
571
              optval_, optvallen_, &zap_domain, UCHAR_MAX);
572 573
            break;

574
            //  If curve encryption isn't built, these options provoke EINVAL
575
#ifdef ZMQ_HAVE_CURVE
576
        case ZMQ_CURVE_SERVER:
577
            if (is_int && (value == 0 || value == 1)) {
578
                as_server = value;
579
                mechanism = value ? ZMQ_CURVE : ZMQ_NULL;
580 581 582
                return 0;
            }
            break;
583

584
        case ZMQ_CURVE_PUBLICKEY:
585
            if (0 == set_curve_key (curve_public_key, optval_, optvallen_)) {
586
                return 0;
587
            }
588
            break;
589

590
        case ZMQ_CURVE_SECRETKEY:
591
            if (0 == set_curve_key (curve_secret_key, optval_, optvallen_)) {
592
                return 0;
593
            }
594 595
            break;

596
        case ZMQ_CURVE_SERVERKEY:
597
            if (0 == set_curve_key (curve_server_key, optval_, optvallen_)) {
598
                as_server = 0;
599
                return 0;
600
            }
601
            break;
602
#endif
Martin Hurton's avatar
Martin Hurton committed
603

danielkr's avatar
danielkr committed
604
        case ZMQ_CONFLATE:
605 606
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &conflate);
607

608
            //  If libgssapi isn't installed, these options provoke EINVAL
609
#ifdef HAVE_LIBGSSAPI_KRB5
610 611 612 613 614 615 616
        case ZMQ_GSSAPI_SERVER:
            if (is_int && (value == 0 || value == 1)) {
                as_server = value;
                mechanism = ZMQ_GSSAPI;
                return 0;
            }
            break;
617

Chris Busbey's avatar
Chris Busbey committed
618
        case ZMQ_GSSAPI_PRINCIPAL:
619
            if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX && optval_ != NULL) {
Chris Busbey's avatar
Chris Busbey committed
620
                gss_principal.assign ((const char *) optval_, optvallen_);
621 622 623 624 625
                mechanism = ZMQ_GSSAPI;
                return 0;
            }
            break;

Chris Busbey's avatar
Chris Busbey committed
626
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
627
            if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX && optval_ != NULL) {
628 629
                gss_service_principal.assign ((const char *) optval_,
                                              optvallen_);
630
                mechanism = ZMQ_GSSAPI;
Chris Busbey's avatar
Chris Busbey committed
631
                as_server = 0;
632 633 634
                return 0;
            }
            break;
danielkr's avatar
danielkr committed
635

636
        case ZMQ_GSSAPI_PLAINTEXT:
637 638
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &gss_plaintext);
639

640
        case ZMQ_GSSAPI_PRINCIPAL_NAMETYPE:
641 642 643 644
            if (is_int
                && (value == ZMQ_GSSAPI_NT_HOSTBASED
                    || value == ZMQ_GSSAPI_NT_USER_NAME
                    || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {
645 646 647 648
                gss_principal_nt = value;
                return 0;
            }
            break;
649

650
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE:
651 652 653 654
            if (is_int
                && (value == ZMQ_GSSAPI_NT_HOSTBASED
                    || value == ZMQ_GSSAPI_NT_USER_NAME
                    || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {
655 656 657 658
                gss_service_principal_nt = value;
                return 0;
            }
            break;
659
#endif
660

661 662 663 664 665 666 667
        case ZMQ_HANDSHAKE_IVL:
            if (is_int && value >= 0) {
                handshake_ivl = value;
                return 0;
            }
            break;

668
        case ZMQ_INVERT_MATCHING:
669 670
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &invert_matching);
671

Jonathan Reams's avatar
Jonathan Reams committed
672 673 674 675 676 677 678 679
        case ZMQ_HEARTBEAT_IVL:
            if (is_int && value >= 0) {
                heartbeat_interval = value;
                return 0;
            }
            break;

        case ZMQ_HEARTBEAT_TTL:
680
            // Convert this to deciseconds from milliseconds
681 682
            value = value / deciseconds_per_millisecond;
            if (is_int && value >= 0 && value <= UINT16_MAX) {
683
                heartbeat_ttl = static_cast<uint16_t> (value);
Jonathan Reams's avatar
Jonathan Reams committed
684 685 686 687 688 689 690 691 692 693 694
                return 0;
            }
            break;

        case ZMQ_HEARTBEAT_TIMEOUT:
            if (is_int && value >= 0) {
                heartbeat_timeout = value;
                return 0;
            }
            break;

695
#ifdef ZMQ_HAVE_VMCI
Ilya Kulakov's avatar
Ilya Kulakov committed
696
        case ZMQ_VMCI_BUFFER_SIZE:
697
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
698 699

        case ZMQ_VMCI_BUFFER_MIN_SIZE:
700
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_min_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
701 702

        case ZMQ_VMCI_BUFFER_MAX_SIZE:
703
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_max_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
704 705

        case ZMQ_VMCI_CONNECT_TIMEOUT:
706
            return do_setsockopt (optval_, optvallen_, &vmci_connect_timeout);
707
#endif
Ilya Kulakov's avatar
Ilya Kulakov committed
708

709
        case ZMQ_USE_FD:
710
            if (is_int && value >= -1) {
711
                use_fd = value;
712 713 714 715
                return 0;
            }
            break;

716
        case ZMQ_BINDTODEVICE:
717 718
            return do_setsockopt_string_allow_empty_strict (
              optval_, optvallen_, &bound_device, BINDDEVSIZ);
719

720
        case ZMQ_ZAP_ENFORCE_DOMAIN:
721 722
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &zap_enforce_domain);
723

724
        case ZMQ_LOOPBACK_FASTPATH:
725 726
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &loopback_fastpath);
727

728 729
        case ZMQ_METADATA:
            if (optvallen_ > 0 && !is_int) {
730 731
                const std::string s (static_cast<const char *> (optval_));
                const size_t pos = s.find (':');
732 733
                if (pos != std::string::npos && pos != 0
                    && pos != s.length () - 1) {
734
                    const std::string key = s.substr (0, pos);
735 736 737
                    if (key.compare (0, 2, "X-") == 0
                        && key.length () <= UCHAR_MAX) {
                        std::string val = s.substr (pos + 1, s.length ());
738 739 740 741 742 743 744 745
                        app_metadata.insert (
                          std::pair<std::string, std::string> (key, val));
                        return 0;
                    }
                }
            }
            errno = EINVAL;
            return -1;
746 747 748 749 750

        case ZMQ_MULTICAST_LOOP:
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &multicast_loop);

danielkr's avatar
danielkr committed
751
        default:
752
#if defined(ZMQ_ACT_MILITANT)
753 754 755 756 757
            //  There are valid scenarios for probing with unknown socket option
            //  values, e.g. to check if security is enabled or not. This will not
            //  provoke a militant assert. However, passing bad values to a valid
            //  socket option will, if ZMQ_ACT_MILITANT is defined.
            malformed = false;
758
#endif
danielkr's avatar
danielkr committed
759
            break;
760
    }
761

762 763 764 765
            // TODO mechanism should either be set explicitly, or determined when
            // connecting. currently, it depends on the order of setsockopt calls
            // if there is some inconsistency, which is confusing. in addition,
            // the assumed or set mechanism should be queryable (as a socket option)
766

767
#if defined(ZMQ_ACT_MILITANT)
768 769 770 771 772 773
    //  There is no valid use case for passing an error back to the application
    //  when it sent malformed arguments to a socket option. Use ./configure
    //  --with-militant to enable this checking.
    if (malformed)
        zmq_assert (false);
#endif
774 775
    errno = EINVAL;
    return -1;
776
}
777

778 779 780
int zmq::options_t::getsockopt (int option_,
                                void *optval_,
                                size_t *optvallen_) const
781
{
782
    const bool is_int = (*optvallen_ == sizeof (int));
783
    int *value = static_cast<int *> (optval_);
784 785
#if defined(ZMQ_ACT_MILITANT)
    bool malformed = true; //  Did caller pass a bad option value?
786
#endif
787

788
    switch (option_) {
789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
        case ZMQ_SNDHWM:
            if (is_int) {
                *value = sndhwm;
                return 0;
            }
            break;

        case ZMQ_RCVHWM:
            if (is_int) {
                *value = rcvhwm;
                return 0;
            }
            break;

        case ZMQ_AFFINITY:
            if (*optvallen_ == sizeof (uint64_t)) {
805
                *(static_cast<uint64_t *> (optval_)) = affinity;
806 807 808 809
                return 0;
            }
            break;

810
        case ZMQ_ROUTING_ID:
811 812
            return do_getsockopt (optval_, optvallen_, routing_id,
                                  routing_id_size);
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842
            break;

        case ZMQ_RATE:
            if (is_int) {
                *value = rate;
                return 0;
            }
            break;

        case ZMQ_RECOVERY_IVL:
            if (is_int) {
                *value = recovery_ivl;
                return 0;
            }
            break;

        case ZMQ_SNDBUF:
            if (is_int) {
                *value = sndbuf;
                return 0;
            }
            break;

        case ZMQ_RCVBUF:
            if (is_int) {
                *value = rcvbuf;
                return 0;
            }
            break;

843 844 845 846 847 848
        case ZMQ_TOS:
            if (is_int) {
                *value = tos;
                return 0;
            }
            break;
Martin Hurton's avatar
Martin Hurton committed
849

850 851 852 853 854 855 856 857 858
        case ZMQ_TYPE:
            if (is_int) {
                *value = type;
                return 0;
            }
            break;

        case ZMQ_LINGER:
            if (is_int) {
859
                *value = linger.load ();
860 861 862
                return 0;
            }
            break;
863

864 865 866 867 868 869 870
        case ZMQ_CONNECT_TIMEOUT:
            if (is_int) {
                *value = connect_timeout;
                return 0;
            }
            break;

871
        case ZMQ_TCP_MAXRT:
872
            if (is_int) {
873
                *value = tcp_maxrt;
874 875 876 877
                return 0;
            }
            break;

878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
        case ZMQ_RECONNECT_IVL:
            if (is_int) {
                *value = reconnect_ivl;
                return 0;
            }
            break;

        case ZMQ_RECONNECT_IVL_MAX:
            if (is_int) {
                *value = reconnect_ivl_max;
                return 0;
            }
            break;

        case ZMQ_BACKLOG:
            if (is_int) {
                *value = backlog;
                return 0;
            }
            break;

        case ZMQ_MAXMSGSIZE:
            if (*optvallen_ == sizeof (int64_t)) {
901
                *(static_cast<int64_t *> (optval_)) = maxmsgsize;
902 903 904 905 906 907 908 909 910 911 912 913
                *optvallen_ = sizeof (int64_t);
                return 0;
            }
            break;

        case ZMQ_MULTICAST_HOPS:
            if (is_int) {
                *value = multicast_hops;
                return 0;
            }
            break;

914 915 916 917 918 919 920
        case ZMQ_MULTICAST_MAXTPDU:
            if (is_int) {
                *value = multicast_maxtpdu;
                return 0;
            }
            break;

921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
        case ZMQ_RCVTIMEO:
            if (is_int) {
                *value = rcvtimeo;
                return 0;
            }
            break;

        case ZMQ_SNDTIMEO:
            if (is_int) {
                *value = sndtimeo;
                return 0;
            }
            break;

        case ZMQ_IPV4ONLY:
            if (is_int) {
                *value = 1 - ipv6;
                return 0;
            }
            break;
941

942 943 944 945 946 947 948 949 950 951 952 953 954 955
        case ZMQ_IPV6:
            if (is_int) {
                *value = ipv6;
                return 0;
            }
            break;

        case ZMQ_IMMEDIATE:
            if (is_int) {
                *value = immediate;
                return 0;
            }
            break;

956
        case ZMQ_SOCKS_PROXY:
957
            return do_getsockopt (optval_, optvallen_, socks_proxy_address);
958 959
            break;

960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
        case ZMQ_TCP_KEEPALIVE:
            if (is_int) {
                *value = tcp_keepalive;
                return 0;
            }
            break;

        case ZMQ_TCP_KEEPALIVE_CNT:
            if (is_int) {
                *value = tcp_keepalive_cnt;
                return 0;
            }
            break;

        case ZMQ_TCP_KEEPALIVE_IDLE:
            if (is_int) {
                *value = tcp_keepalive_idle;
                return 0;
            }
            break;

        case ZMQ_TCP_KEEPALIVE_INTVL:
            if (is_int) {
                *value = tcp_keepalive_intvl;
                return 0;
            }
            break;

        case ZMQ_MECHANISM:
            if (is_int) {
                *value = mechanism;
                return 0;
            }
            break;
994

995
        case ZMQ_PLAIN_SERVER:
996
            if (is_int) {
997
                *value = as_server && mechanism == ZMQ_PLAIN;
998 999 1000
                return 0;
            }
            break;
1001

1002
        case ZMQ_PLAIN_USERNAME:
1003
            return do_getsockopt (optval_, optvallen_, plain_username);
1004
            break;
1005

1006
        case ZMQ_PLAIN_PASSWORD:
1007
            return do_getsockopt (optval_, optvallen_, plain_password);
1008
            break;
1009 1010

        case ZMQ_ZAP_DOMAIN:
1011
            return do_getsockopt (optval_, optvallen_, zap_domain);
1012 1013
            break;

1014
            //  If curve encryption isn't built, these options provoke EINVAL
1015
#ifdef ZMQ_HAVE_CURVE
1016
        case ZMQ_CURVE_SERVER:
1017
            if (is_int) {
1018
                *value = as_server && mechanism == ZMQ_CURVE;
1019 1020 1021
                return 0;
            }
            break;
1022

1023
        case ZMQ_CURVE_PUBLICKEY:
1024 1025
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_public_key);
1026
            break;
1027

1028
        case ZMQ_CURVE_SECRETKEY:
1029 1030
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_secret_key);
1031 1032
            break;

1033
        case ZMQ_CURVE_SERVERKEY:
1034 1035
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_server_key);
1036
            break;
1037
#endif
danielkr's avatar
danielkr committed
1038 1039 1040 1041 1042 1043 1044

        case ZMQ_CONFLATE:
            if (is_int) {
                *value = conflate;
                return 0;
            }
            break;
Martin Hurton's avatar
Martin Hurton committed
1045

1046
            //  If libgssapi isn't installed, these options provoke EINVAL
1047
#ifdef HAVE_LIBGSSAPI_KRB5
1048 1049 1050 1051 1052 1053
        case ZMQ_GSSAPI_SERVER:
            if (is_int) {
                *value = as_server && mechanism == ZMQ_GSSAPI;
                return 0;
            }
            break;
1054

Chris Busbey's avatar
Chris Busbey committed
1055
        case ZMQ_GSSAPI_PRINCIPAL:
1056
            return do_getsockopt (optval_, optvallen_, gss_principal);
1057
            break;
danielkr's avatar
danielkr committed
1058

Chris Busbey's avatar
Chris Busbey committed
1059
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
1060
            return do_getsockopt (optval_, optvallen_, gss_service_principal);
1061
            break;
1062

1063 1064 1065 1066 1067 1068
        case ZMQ_GSSAPI_PLAINTEXT:
            if (is_int) {
                *value = gss_plaintext;
                return 0;
            }
            break;
1069

1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
        case ZMQ_GSSAPI_PRINCIPAL_NAMETYPE:
            if (is_int) {
                *value = gss_principal_nt;
                return 0;
            }
            break;
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE:
            if (is_int) {
                *value = gss_service_principal_nt;
                return 0;
            }
            break;
1082 1083
#endif

1084 1085 1086 1087 1088 1089
        case ZMQ_HANDSHAKE_IVL:
            if (is_int) {
                *value = handshake_ivl;
                return 0;
            }
            break;
1090

1091 1092 1093 1094 1095 1096 1097
        case ZMQ_INVERT_MATCHING:
            if (is_int) {
                *value = invert_matching;
                return 0;
            }
            break;

Jonathan Reams's avatar
Jonathan Reams committed
1098 1099 1100 1101 1102 1103 1104 1105 1106
        case ZMQ_HEARTBEAT_IVL:
            if (is_int) {
                *value = heartbeat_interval;
                return 0;
            }
            break;

        case ZMQ_HEARTBEAT_TTL:
            if (is_int) {
1107 1108
                // Convert the internal deciseconds value to milliseconds
                *value = heartbeat_ttl * 100;
Jonathan Reams's avatar
Jonathan Reams committed
1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119
                return 0;
            }
            break;

        case ZMQ_HEARTBEAT_TIMEOUT:
            if (is_int) {
                *value = heartbeat_timeout;
                return 0;
            }
            break;

1120
        case ZMQ_USE_FD:
1121
            if (is_int) {
1122
                *value = use_fd;
1123 1124 1125 1126
                return 0;
            }
            break;

1127
        case ZMQ_BINDTODEVICE:
1128
            return do_getsockopt (optval_, optvallen_, bound_device);
1129 1130
            break;

1131 1132 1133 1134 1135 1136 1137
        case ZMQ_ZAP_ENFORCE_DOMAIN:
            if (is_int) {
                *value = zap_enforce_domain;
                return 0;
            }
            break;

1138 1139 1140 1141 1142 1143 1144
        case ZMQ_LOOPBACK_FASTPATH:
            if (is_int) {
                *value = loopback_fastpath;
                return 0;
            }
            break;

1145 1146 1147 1148 1149 1150 1151
        case ZMQ_MULTICAST_LOOP:
            if (is_int) {
                *value = multicast_loop;
                return 0;
            }
            break;

1152
        default:
1153
#if defined(ZMQ_ACT_MILITANT)
1154 1155 1156
            malformed = false;
#endif
            break;
1157
    }
1158
#if defined(ZMQ_ACT_MILITANT)
1159 1160 1161
    if (malformed)
        zmq_assert (false);
#endif
1162 1163 1164
    errno = EINVAL;
    return -1;
}