options.cpp 33.3 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 186 187 188 189 190 191 192
        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;
    } else if (optvallen_ == sizeof (T) && optval_ != NULL) {
        set_->insert (*((const T *) optval_));
        return 0;
    }
    return sockopt_invalid ();
}

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

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

        case CURVE_KEYSIZE_Z85 + 1:
266 267
            if (zmq_z85_decode (destination_,
                                reinterpret_cast<const char *> (optval_))) {
268 269 270 271 272 273
                mechanism = ZMQ_CURVE;
                return 0;
            }
            break;

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

        default:
            break;
    }
    return -1;
}

290 291
const int deciseconds_per_millisecond = 100;

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

304
    switch (option_) {
305
        case ZMQ_SNDHWM:
306
            if (is_int && value >= 0) {
307
                sndhwm = value;
308 309
                return 0;
            }
310
            break;
311

312
        case ZMQ_RCVHWM:
313
            if (is_int && value >= 0) {
314
                rcvhwm = value;
315 316
                return 0;
            }
317
            break;
318

319
        case ZMQ_AFFINITY:
320
            return do_setsockopt (optval_, optvallen_, &affinity);
321

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

331
        case ZMQ_RATE:
332
            if (is_int && value > 0) {
333
                rate = value;
334 335
                return 0;
            }
336
            break;
337

338
        case ZMQ_RECOVERY_IVL:
339
            if (is_int && value >= 0) {
340
                recovery_ivl = value;
341 342 343
                return 0;
            }
            break;
344

345
        case ZMQ_SNDBUF:
346
            if (is_int && value >= -1) {
347
                sndbuf = value;
348 349
                return 0;
            }
350
            break;
351

352
        case ZMQ_RCVBUF:
353
            if (is_int && value >= -1) {
354
                rcvbuf = value;
355 356
                return 0;
            }
357
            break;
358

359 360 361 362 363 364 365
        case ZMQ_TOS:
            if (is_int && value >= 0) {
                tos = value;
                return 0;
            }
            break;

366
        case ZMQ_LINGER:
367
            if (is_int && value >= -1) {
368
                linger.store (value);
369 370
                return 0;
            }
371
            break;
372

373 374 375 376 377 378 379
        case ZMQ_CONNECT_TIMEOUT:
            if (is_int && value >= 0) {
                connect_timeout = value;
                return 0;
            }
            break;

380
        case ZMQ_TCP_MAXRT:
381
            if (is_int && value >= 0) {
382
                tcp_maxrt = value;
383 384 385 386
                return 0;
            }
            break;

387
        case ZMQ_RECONNECT_IVL:
388
            if (is_int && value >= -1) {
389
                reconnect_ivl = value;
390 391
                return 0;
            }
392
            break;
393

394
        case ZMQ_RECONNECT_IVL_MAX:
395
            if (is_int && value >= 0) {
396
                reconnect_ivl_max = value;
397 398
                return 0;
            }
399
            break;
400

401
        case ZMQ_BACKLOG:
402
            if (is_int && value >= 0) {
403
                backlog = value;
404 405
                return 0;
            }
406
            break;
407

408
        case ZMQ_MAXMSGSIZE:
409
            return do_setsockopt (optval_, optvallen_, &maxmsgsize);
410

411
        case ZMQ_MULTICAST_HOPS:
412
            if (is_int && value > 0) {
413
                multicast_hops = value;
414 415
                return 0;
            }
416
            break;
417

418 419 420 421 422 423 424
        case ZMQ_MULTICAST_MAXTPDU:
            if (is_int && value > 0) {
                multicast_maxtpdu = value;
                return 0;
            }
            break;

425
        case ZMQ_RCVTIMEO:
426
            if (is_int && value >= -1) {
427
                rcvtimeo = value;
428 429
                return 0;
            }
430
            break;
431

432
        case ZMQ_SNDTIMEO:
433
            if (is_int && value >= -1) {
434
                sndtimeo = value;
435 436
                return 0;
            }
437
            break;
438

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

449 450
        /*  To replace the somewhat surprising IPV4ONLY */
        case ZMQ_IPV6:
451 452
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &ipv6);
453

454
        case ZMQ_SOCKS_PROXY:
455 456
            return do_setsockopt_string_allow_empty_strict (
              optval_, optvallen_, &socks_proxy_address, SIZE_MAX);
457

458
        case ZMQ_TCP_KEEPALIVE:
459
            if (is_int && (value == -1 || value == 0 || value == 1)) {
460
                tcp_keepalive = value;
461 462
                return 0;
            }
463
            break;
464

465
        case ZMQ_TCP_KEEPALIVE_CNT:
466
            if (is_int && (value == -1 || value >= 0)) {
467
                tcp_keepalive_cnt = value;
468 469
                return 0;
            }
470
            break;
471

472
        case ZMQ_TCP_KEEPALIVE_IDLE:
473
            if (is_int && (value == -1 || value >= 0)) {
474
                tcp_keepalive_idle = value;
475 476
                return 0;
            }
477
            break;
478

479
        case ZMQ_TCP_KEEPALIVE_INTVL:
480
            if (is_int && (value == -1 || value >= 0)) {
481
                tcp_keepalive_intvl = value;
482 483
                return 0;
            }
484
            break;
485

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

494 495 496
        case ZMQ_TCP_ACCEPT_FILTER: {
            std::string filter_str;
            int rc = do_setsockopt_string_allow_empty_strict (
497
              optval_, optvallen_, &filter_str, UCHAR_MAX);
498 499 500 501 502 503 504 505 506
            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);
                    }
507 508
                }
            }
509 510
            return rc;
        }
511

512
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
513
        case ZMQ_IPC_FILTER_UID:
514 515 516
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_uid_accept_filters);

517

518
        case ZMQ_IPC_FILTER_GID:
519 520
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_gid_accept_filters);
521
#endif
522

523
#if defined ZMQ_HAVE_SO_PEERCRED
524
        case ZMQ_IPC_FILTER_PID:
525 526
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_pid_accept_filters);
527
#endif
528

529 530
        case ZMQ_PLAIN_SERVER:
            if (is_int && (value == 0 || value == 1)) {
531
                as_server = value;
532
                mechanism = value ? ZMQ_PLAIN : ZMQ_NULL;
533 534 535
                return 0;
            }
            break;
536

537 538 539 540
        case ZMQ_PLAIN_USERNAME:
            if (optvallen_ == 0 && optval_ == NULL) {
                mechanism = ZMQ_NULL;
                return 0;
541
            } else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
542 543
                plain_username.assign (static_cast<const char *> (optval_),
                                       optvallen_);
544
                as_server = 0;
545 546 547 548
                mechanism = ZMQ_PLAIN;
                return 0;
            }
            break;
549

550 551 552 553
        case ZMQ_PLAIN_PASSWORD:
            if (optvallen_ == 0 && optval_ == NULL) {
                mechanism = ZMQ_NULL;
                return 0;
554
            } else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
555 556
                plain_password.assign (static_cast<const char *> (optval_),
                                       optvallen_);
557
                as_server = 0;
558 559
                mechanism = ZMQ_PLAIN;
                return 0;
560
            }
561
            break;
562 563

        case ZMQ_ZAP_DOMAIN:
564
            return do_setsockopt_string_allow_empty_relaxed (
565
              optval_, optvallen_, &zap_domain, UCHAR_MAX);
566 567
            break;

568
            //  If curve encryption isn't built, these options provoke EINVAL
569
#ifdef ZMQ_HAVE_CURVE
570
        case ZMQ_CURVE_SERVER:
571
            if (is_int && (value == 0 || value == 1)) {
572
                as_server = value;
573
                mechanism = value ? ZMQ_CURVE : ZMQ_NULL;
574 575 576
                return 0;
            }
            break;
577

578
        case ZMQ_CURVE_PUBLICKEY:
579
            if (0 == set_curve_key (curve_public_key, optval_, optvallen_)) {
580
                return 0;
581
            }
582
            break;
583

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

590
        case ZMQ_CURVE_SERVERKEY:
591
            if (0 == set_curve_key (curve_server_key, optval_, optvallen_)) {
592
                as_server = 0;
593
                return 0;
594
            }
595
            break;
596
#endif
Martin Hurton's avatar
Martin Hurton committed
597

danielkr's avatar
danielkr committed
598
        case ZMQ_CONFLATE:
599 600
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &conflate);
601

602
            //  If libgssapi isn't installed, these options provoke EINVAL
603
#ifdef HAVE_LIBGSSAPI_KRB5
604 605 606 607 608 609 610
        case ZMQ_GSSAPI_SERVER:
            if (is_int && (value == 0 || value == 1)) {
                as_server = value;
                mechanism = ZMQ_GSSAPI;
                return 0;
            }
            break;
611

Chris Busbey's avatar
Chris Busbey committed
612
        case ZMQ_GSSAPI_PRINCIPAL:
613
            if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
Chris Busbey's avatar
Chris Busbey committed
614
                gss_principal.assign ((const char *) optval_, optvallen_);
615 616 617 618 619
                mechanism = ZMQ_GSSAPI;
                return 0;
            }
            break;

Chris Busbey's avatar
Chris Busbey committed
620
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
621
            if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
622 623
                gss_service_principal.assign ((const char *) optval_,
                                              optvallen_);
624
                mechanism = ZMQ_GSSAPI;
Chris Busbey's avatar
Chris Busbey committed
625
                as_server = 0;
626 627 628
                return 0;
            }
            break;
danielkr's avatar
danielkr committed
629

630
        case ZMQ_GSSAPI_PLAINTEXT:
631 632
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &gss_plaintext);
633

634
        case ZMQ_GSSAPI_PRINCIPAL_NAMETYPE:
635 636 637 638
            if (is_int
                && (value == ZMQ_GSSAPI_NT_HOSTBASED
                    || value == ZMQ_GSSAPI_NT_USER_NAME
                    || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {
639 640 641 642
                gss_principal_nt = value;
                return 0;
            }
            break;
643

644
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE:
645 646 647 648
            if (is_int
                && (value == ZMQ_GSSAPI_NT_HOSTBASED
                    || value == ZMQ_GSSAPI_NT_USER_NAME
                    || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {
649 650 651 652
                gss_service_principal_nt = value;
                return 0;
            }
            break;
653
#endif
654

655 656 657 658 659 660 661
        case ZMQ_HANDSHAKE_IVL:
            if (is_int && value >= 0) {
                handshake_ivl = value;
                return 0;
            }
            break;

662
        case ZMQ_INVERT_MATCHING:
663 664
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &invert_matching);
665

Jonathan Reams's avatar
Jonathan Reams committed
666 667 668 669 670 671 672 673
        case ZMQ_HEARTBEAT_IVL:
            if (is_int && value >= 0) {
                heartbeat_interval = value;
                return 0;
            }
            break;

        case ZMQ_HEARTBEAT_TTL:
674
            // Convert this to deciseconds from milliseconds
675 676
            value = value / deciseconds_per_millisecond;
            if (is_int && value >= 0 && value <= UINT16_MAX) {
677
                heartbeat_ttl = static_cast<uint16_t> (value);
Jonathan Reams's avatar
Jonathan Reams committed
678 679 680 681 682 683 684 685 686 687 688
                return 0;
            }
            break;

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

689
#ifdef ZMQ_HAVE_VMCI
Ilya Kulakov's avatar
Ilya Kulakov committed
690
        case ZMQ_VMCI_BUFFER_SIZE:
691
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
692 693

        case ZMQ_VMCI_BUFFER_MIN_SIZE:
694
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_min_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
695 696

        case ZMQ_VMCI_BUFFER_MAX_SIZE:
697
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_max_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
698 699

        case ZMQ_VMCI_CONNECT_TIMEOUT:
700
            return do_setsockopt (optval_, optvallen_, &vmci_connect_timeout);
701
#endif
Ilya Kulakov's avatar
Ilya Kulakov committed
702

703
        case ZMQ_USE_FD:
704
            if (is_int && value >= -1) {
705
                use_fd = value;
706 707 708 709
                return 0;
            }
            break;

710
        case ZMQ_BINDTODEVICE:
711 712
            return do_setsockopt_string_allow_empty_strict (
              optval_, optvallen_, &bound_device, BINDDEVSIZ);
713

714
        case ZMQ_ZAP_ENFORCE_DOMAIN:
715 716
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &zap_enforce_domain);
717

718
        case ZMQ_LOOPBACK_FASTPATH:
719 720
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &loopback_fastpath);
721

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

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

danielkr's avatar
danielkr committed
745
        default:
746
#if defined(ZMQ_ACT_MILITANT)
747 748 749 750 751
            //  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;
752
#endif
danielkr's avatar
danielkr committed
753
            break;
754
    }
755

756 757 758 759
            // 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)
760

761
#if defined(ZMQ_ACT_MILITANT)
762 763 764 765 766 767
    //  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
768 769
    errno = EINVAL;
    return -1;
770
}
771

772 773 774
int zmq::options_t::getsockopt (int option_,
                                void *optval_,
                                size_t *optvallen_) const
775
{
776
    bool is_int = (*optvallen_ == sizeof (int));
777
    int *value = static_cast<int *> (optval_);
778 779
#if defined(ZMQ_ACT_MILITANT)
    bool malformed = true; //  Did caller pass a bad option value?
780
#endif
781

782
    switch (option_) {
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
        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)) {
799
                *(static_cast<uint64_t *> (optval_)) = affinity;
800 801 802 803
                return 0;
            }
            break;

804
        case ZMQ_ROUTING_ID:
805 806
            return do_getsockopt (optval_, optvallen_, routing_id,
                                  routing_id_size);
807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
            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;

837 838 839 840 841 842
        case ZMQ_TOS:
            if (is_int) {
                *value = tos;
                return 0;
            }
            break;
Martin Hurton's avatar
Martin Hurton committed
843

844 845 846 847 848 849 850 851 852
        case ZMQ_TYPE:
            if (is_int) {
                *value = type;
                return 0;
            }
            break;

        case ZMQ_LINGER:
            if (is_int) {
853
                *value = linger.load ();
854 855 856
                return 0;
            }
            break;
857

858 859 860 861 862 863 864
        case ZMQ_CONNECT_TIMEOUT:
            if (is_int) {
                *value = connect_timeout;
                return 0;
            }
            break;

865
        case ZMQ_TCP_MAXRT:
866
            if (is_int) {
867
                *value = tcp_maxrt;
868 869 870 871
                return 0;
            }
            break;

872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
        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)) {
895
                *(static_cast<int64_t *> (optval_)) = maxmsgsize;
896 897 898 899 900 901 902 903 904 905 906 907
                *optvallen_ = sizeof (int64_t);
                return 0;
            }
            break;

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

908 909 910 911 912 913 914
        case ZMQ_MULTICAST_MAXTPDU:
            if (is_int) {
                *value = multicast_maxtpdu;
                return 0;
            }
            break;

915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
        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;
935

936 937 938 939 940 941 942 943 944 945 946 947 948 949
        case ZMQ_IPV6:
            if (is_int) {
                *value = ipv6;
                return 0;
            }
            break;

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

950
        case ZMQ_SOCKS_PROXY:
951
            return do_getsockopt (optval_, optvallen_, socks_proxy_address);
952 953
            break;

954 955 956 957 958 959 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
        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;
988

989
        case ZMQ_PLAIN_SERVER:
990
            if (is_int) {
991
                *value = as_server && mechanism == ZMQ_PLAIN;
992 993 994
                return 0;
            }
            break;
995

996
        case ZMQ_PLAIN_USERNAME:
997
            return do_getsockopt (optval_, optvallen_, plain_username);
998
            break;
999

1000
        case ZMQ_PLAIN_PASSWORD:
1001
            return do_getsockopt (optval_, optvallen_, plain_password);
1002
            break;
1003 1004

        case ZMQ_ZAP_DOMAIN:
1005
            return do_getsockopt (optval_, optvallen_, zap_domain);
1006 1007
            break;

1008
            //  If curve encryption isn't built, these options provoke EINVAL
1009
#ifdef ZMQ_HAVE_CURVE
1010
        case ZMQ_CURVE_SERVER:
1011
            if (is_int) {
1012
                *value = as_server && mechanism == ZMQ_CURVE;
1013 1014 1015
                return 0;
            }
            break;
1016

1017
        case ZMQ_CURVE_PUBLICKEY:
1018 1019
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_public_key);
1020
            break;
1021

1022
        case ZMQ_CURVE_SECRETKEY:
1023 1024
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_secret_key);
1025 1026
            break;

1027
        case ZMQ_CURVE_SERVERKEY:
1028 1029
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_server_key);
1030
            break;
1031
#endif
danielkr's avatar
danielkr committed
1032 1033 1034 1035 1036 1037 1038

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

1040
            //  If libgssapi isn't installed, these options provoke EINVAL
1041
#ifdef HAVE_LIBGSSAPI_KRB5
1042 1043 1044 1045 1046 1047
        case ZMQ_GSSAPI_SERVER:
            if (is_int) {
                *value = as_server && mechanism == ZMQ_GSSAPI;
                return 0;
            }
            break;
1048

Chris Busbey's avatar
Chris Busbey committed
1049
        case ZMQ_GSSAPI_PRINCIPAL:
1050
            return do_getsockopt (optval_, optvallen_, gss_principal);
1051
            break;
danielkr's avatar
danielkr committed
1052

Chris Busbey's avatar
Chris Busbey committed
1053
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
1054
            return do_getsockopt (optval_, optvallen_, gss_service_principal);
1055
            break;
1056

1057 1058 1059 1060 1061 1062
        case ZMQ_GSSAPI_PLAINTEXT:
            if (is_int) {
                *value = gss_plaintext;
                return 0;
            }
            break;
1063

1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075
        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;
1076 1077
#endif

1078 1079 1080 1081 1082 1083
        case ZMQ_HANDSHAKE_IVL:
            if (is_int) {
                *value = handshake_ivl;
                return 0;
            }
            break;
1084

1085 1086 1087 1088 1089 1090 1091
        case ZMQ_INVERT_MATCHING:
            if (is_int) {
                *value = invert_matching;
                return 0;
            }
            break;

Jonathan Reams's avatar
Jonathan Reams committed
1092 1093 1094 1095 1096 1097 1098 1099 1100
        case ZMQ_HEARTBEAT_IVL:
            if (is_int) {
                *value = heartbeat_interval;
                return 0;
            }
            break;

        case ZMQ_HEARTBEAT_TTL:
            if (is_int) {
1101 1102
                // Convert the internal deciseconds value to milliseconds
                *value = heartbeat_ttl * 100;
Jonathan Reams's avatar
Jonathan Reams committed
1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
                return 0;
            }
            break;

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

1114
        case ZMQ_USE_FD:
1115
            if (is_int) {
1116
                *value = use_fd;
1117 1118 1119 1120
                return 0;
            }
            break;

1121
        case ZMQ_BINDTODEVICE:
1122
            return do_getsockopt (optval_, optvallen_, bound_device);
1123 1124
            break;

1125 1126 1127 1128 1129 1130 1131
        case ZMQ_ZAP_ENFORCE_DOMAIN:
            if (is_int) {
                *value = zap_enforce_domain;
                return 0;
            }
            break;

1132 1133 1134 1135 1136 1137 1138
        case ZMQ_LOOPBACK_FASTPATH:
            if (is_int) {
                *value = loopback_fastpath;
                return 0;
            }
            break;

1139 1140 1141 1142 1143 1144 1145
        case ZMQ_MULTICAST_LOOP:
            if (is_int) {
                *value = multicast_loop;
                return 0;
            }
            break;

1146
        default:
1147
#if defined(ZMQ_ACT_MILITANT)
1148 1149 1150
            malformed = false;
#endif
            break;
1151
    }
1152
#if defined(ZMQ_ACT_MILITANT)
1153 1154 1155
    if (malformed)
        zmq_assert (false);
#endif
1156 1157 1158
    errno = EINVAL;
    return -1;
}
1159 1160 1161

bool zmq::options_t::is_valid (int option_) const
{
1162
    LIBZMQ_UNUSED (option_);
1163
    return true;
1164
}