options.cpp 32.8 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 32
#include <string.h>

33
#include "options.hpp"
34
#include "err.hpp"
35
#include "macros.hpp"
36

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

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

47 48 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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
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?
    memset ((char *) optval_ + value_len_, 0, *optvallen_ - value_len_);
    *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;
    } else if (*optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
        zmq_z85_encode ((char *) optval_, curve_key_, CURVE_KEYSIZE);
        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
118
    int value = -1;
119 120 121 122 123 124 125 126 127 128 129 130 131
    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_)
{
132
    int value = -1;
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
    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;
    } else if (optval_ != NULL && optvallen_ > 0 && optvallen_ <= max_len_) {
        out_value_->assign ((const char *) optval_, optvallen_);
        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_) {
        out_value_->assign ((const char *) optval_, optvallen_);
        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 ();
}

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

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

        case CURVE_KEYSIZE_Z85 + 1:
            if (zmq_z85_decode (destination, (char *) optval_)) {
                mechanism = ZMQ_CURVE;
                return 0;
            }
            break;

        case CURVE_KEYSIZE_Z85:
267
            char z85_key[CURVE_KEYSIZE_Z85 + 1];
268
            memcpy (z85_key, (char *) optval_, optvallen_);
269
            z85_key[CURVE_KEYSIZE_Z85] = 0;
270 271 272 273 274 275 276 277 278 279 280 281
            if (zmq_z85_decode (destination, z85_key)) {
                mechanism = ZMQ_CURVE;
                return 0;
            }
            break;

        default:
            break;
    }
    return -1;
}

282 283 284
int zmq::options_t::setsockopt (int option_,
                                const void *optval_,
                                size_t optvallen_)
285
{
286
    bool is_int = (optvallen_ == sizeof (int));
287
    int value = 0;
288 289 290 291
    if (is_int)
        memcpy (&value, optval_, sizeof (int));
#if defined(ZMQ_ACT_MILITANT)
    bool malformed = true; //  Did caller pass a bad option value?
292
#endif
293

294
    switch (option_) {
295
        case ZMQ_SNDHWM:
296
            if (is_int && value >= 0) {
297
                sndhwm = value;
298 299
                return 0;
            }
300
            break;
301

302
        case ZMQ_RCVHWM:
303
            if (is_int && value >= 0) {
304
                rcvhwm = value;
305 306
                return 0;
            }
307
            break;
308

309
        case ZMQ_AFFINITY:
310
            return do_setsockopt (optval_, optvallen_, &affinity);
311

312 313
        case ZMQ_ROUTING_ID:
            //  Routing id is any binary string from 1 to 255 octets
314
            if (optvallen_ > 0 && optvallen_ < 256) {
315 316
                routing_id_size = (unsigned char) optvallen_;
                memcpy (routing_id, optval_, routing_id_size);
317
                return 0;
318 319
            }
            break;
320

321
        case ZMQ_RATE:
322
            if (is_int && value > 0) {
323
                rate = value;
324 325
                return 0;
            }
326
            break;
327

328
        case ZMQ_RECOVERY_IVL:
329
            if (is_int && value >= 0) {
330
                recovery_ivl = value;
331 332 333
                return 0;
            }
            break;
334

335
        case ZMQ_SNDBUF:
336
            if (is_int && value >= -1) {
337
                sndbuf = value;
338 339
                return 0;
            }
340
            break;
341

342
        case ZMQ_RCVBUF:
343
            if (is_int && value >= -1) {
344
                rcvbuf = value;
345 346
                return 0;
            }
347
            break;
348

349 350 351 352 353 354 355
        case ZMQ_TOS:
            if (is_int && value >= 0) {
                tos = value;
                return 0;
            }
            break;

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

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

370
        case ZMQ_TCP_MAXRT:
371
            if (is_int && value >= 0) {
372
                tcp_maxrt = value;
373 374 375 376
                return 0;
            }
            break;

377
        case ZMQ_RECONNECT_IVL:
378
            if (is_int && value >= -1) {
379
                reconnect_ivl = value;
380 381
                return 0;
            }
382
            break;
383

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

391
        case ZMQ_BACKLOG:
392
            if (is_int && value >= 0) {
393
                backlog = value;
394 395
                return 0;
            }
396
            break;
397

398
        case ZMQ_MAXMSGSIZE:
399
            return do_setsockopt (optval_, optvallen_, &maxmsgsize);
400

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

408 409 410 411 412 413 414
        case ZMQ_MULTICAST_MAXTPDU:
            if (is_int && value > 0) {
                multicast_maxtpdu = value;
                return 0;
            }
            break;

415
        case ZMQ_RCVTIMEO:
416
            if (is_int && value >= -1) {
417
                rcvtimeo = value;
418 419
                return 0;
            }
420
            break;
421

422
        case ZMQ_SNDTIMEO:
423
            if (is_int && value >= -1) {
424
                sndtimeo = value;
425 426
                return 0;
            }
427
            break;
428

Pieter Hintjens's avatar
Pieter Hintjens committed
429
        /*  Deprecated in favor of ZMQ_IPV6  */
430 431 432 433 434 435 436 437
        case ZMQ_IPV4ONLY: {
            bool value;
            int rc =
              do_setsockopt_int_as_bool_strict (optval_, optvallen_, &value);
            if (rc == 0)
                ipv6 = !value;
            return rc;
        }
438

439 440
        /*  To replace the somewhat surprising IPV4ONLY */
        case ZMQ_IPV6:
441 442
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &ipv6);
443

444
        case ZMQ_SOCKS_PROXY:
445 446
            return do_setsockopt_string_allow_empty_strict (
              optval_, optvallen_, &socks_proxy_address, SIZE_MAX);
447

448
        case ZMQ_TCP_KEEPALIVE:
449
            if (is_int && (value == -1 || value == 0 || value == 1)) {
450
                tcp_keepalive = value;
451 452
                return 0;
            }
453
            break;
454

455
        case ZMQ_TCP_KEEPALIVE_CNT:
456
            if (is_int && (value == -1 || value >= 0)) {
457
                tcp_keepalive_cnt = value;
458 459
                return 0;
            }
460
            break;
461

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

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

476
        case ZMQ_IMMEDIATE:
477
            // TODO why is immediate not bool (and called non_immediate, as its meaning appears to be reversed)
478
            if (is_int && (value == 0 || value == 1)) {
479
                immediate = value;
480 481
                return 0;
            }
482
            break;
483

484 485 486 487 488 489 490 491 492 493 494 495 496
        case ZMQ_TCP_ACCEPT_FILTER: {
            std::string filter_str;
            int rc = do_setsockopt_string_allow_empty_strict (
              optval_, optvallen_, &filter_str, 255);
            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);
                    }
497 498
                }
            }
499 500
            return rc;
        }
501

502
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
503
        case ZMQ_IPC_FILTER_UID:
504 505 506
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_uid_accept_filters);

507

508
        case ZMQ_IPC_FILTER_GID:
509 510
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_gid_accept_filters);
511
#endif
512

513
#if defined ZMQ_HAVE_SO_PEERCRED
514
        case ZMQ_IPC_FILTER_PID:
515 516
            return do_setsockopt_set (optval_, optvallen_,
                                      &ipc_pid_accept_filters);
517
#endif
518

519 520
        case ZMQ_PLAIN_SERVER:
            if (is_int && (value == 0 || value == 1)) {
521
                as_server = value;
522
                mechanism = value ? ZMQ_PLAIN : ZMQ_NULL;
523 524 525
                return 0;
            }
            break;
526

527 528 529 530
        case ZMQ_PLAIN_USERNAME:
            if (optvallen_ == 0 && optval_ == NULL) {
                mechanism = ZMQ_NULL;
                return 0;
531
            } else if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
532
                plain_username.assign ((const char *) optval_, optvallen_);
533
                as_server = 0;
534 535 536 537
                mechanism = ZMQ_PLAIN;
                return 0;
            }
            break;
538

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

        case ZMQ_ZAP_DOMAIN:
552 553
            return do_setsockopt_string_allow_empty_relaxed (
              optval_, optvallen_, &zap_domain, 255);
554 555
            break;

556
            //  If curve encryption isn't built, these options provoke EINVAL
557
#ifdef ZMQ_HAVE_CURVE
558
        case ZMQ_CURVE_SERVER:
559
            if (is_int && (value == 0 || value == 1)) {
560
                as_server = value;
561
                mechanism = value ? ZMQ_CURVE : ZMQ_NULL;
562 563 564
                return 0;
            }
            break;
565

566
        case ZMQ_CURVE_PUBLICKEY:
567
            if (0 == set_curve_key (curve_public_key, optval_, optvallen_)) {
568
                return 0;
569
            }
570
            break;
571

572
        case ZMQ_CURVE_SECRETKEY:
573
            if (0 == set_curve_key (curve_secret_key, optval_, optvallen_)) {
574
                return 0;
575
            }
576 577
            break;

578
        case ZMQ_CURVE_SERVERKEY:
579
            if (0 == set_curve_key (curve_server_key, optval_, optvallen_)) {
580
                as_server = 0;
581
                return 0;
582
            }
583
            break;
584
#endif
Martin Hurton's avatar
Martin Hurton committed
585

danielkr's avatar
danielkr committed
586
        case ZMQ_CONFLATE:
587 588
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &conflate);
589

590
            //  If libgssapi isn't installed, these options provoke EINVAL
591
#ifdef HAVE_LIBGSSAPI_KRB5
592 593 594 595 596 597 598
        case ZMQ_GSSAPI_SERVER:
            if (is_int && (value == 0 || value == 1)) {
                as_server = value;
                mechanism = ZMQ_GSSAPI;
                return 0;
            }
            break;
599

Chris Busbey's avatar
Chris Busbey committed
600
        case ZMQ_GSSAPI_PRINCIPAL:
601
            if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
Chris Busbey's avatar
Chris Busbey committed
602
                gss_principal.assign ((const char *) optval_, optvallen_);
603 604 605 606 607
                mechanism = ZMQ_GSSAPI;
                return 0;
            }
            break;

Chris Busbey's avatar
Chris Busbey committed
608
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
609
            if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) {
610 611
                gss_service_principal.assign ((const char *) optval_,
                                              optvallen_);
612
                mechanism = ZMQ_GSSAPI;
Chris Busbey's avatar
Chris Busbey committed
613
                as_server = 0;
614 615 616
                return 0;
            }
            break;
danielkr's avatar
danielkr committed
617

618
        case ZMQ_GSSAPI_PLAINTEXT:
619 620
            return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
                                                     &gss_plaintext);
621

622
        case ZMQ_GSSAPI_PRINCIPAL_NAMETYPE:
623 624 625 626
            if (is_int
                && (value == ZMQ_GSSAPI_NT_HOSTBASED
                    || value == ZMQ_GSSAPI_NT_USER_NAME
                    || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {
627 628 629 630
                gss_principal_nt = value;
                return 0;
            }
            break;
631

632
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE:
633 634 635 636
            if (is_int
                && (value == ZMQ_GSSAPI_NT_HOSTBASED
                    || value == ZMQ_GSSAPI_NT_USER_NAME
                    || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {
637 638 639 640
                gss_service_principal_nt = value;
                return 0;
            }
            break;
641
#endif
642

643 644 645 646 647 648 649
        case ZMQ_HANDSHAKE_IVL:
            if (is_int && value >= 0) {
                handshake_ivl = value;
                return 0;
            }
            break;

650
        case ZMQ_INVERT_MATCHING:
651 652
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &invert_matching);
653

Jonathan Reams's avatar
Jonathan Reams committed
654 655 656 657 658 659 660 661
        case ZMQ_HEARTBEAT_IVL:
            if (is_int && value >= 0) {
                heartbeat_interval = value;
                return 0;
            }
            break;

        case ZMQ_HEARTBEAT_TTL:
662 663 664
            // Convert this to deciseconds from milliseconds
            value = value / 100;
            if (is_int && value >= 0 && value <= 6553) {
665
                heartbeat_ttl = (uint16_t) value;
Jonathan Reams's avatar
Jonathan Reams committed
666 667 668 669 670 671 672 673 674 675 676
                return 0;
            }
            break;

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

677
#ifdef ZMQ_HAVE_VMCI
Ilya Kulakov's avatar
Ilya Kulakov committed
678
        case ZMQ_VMCI_BUFFER_SIZE:
679
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
680 681

        case ZMQ_VMCI_BUFFER_MIN_SIZE:
682
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_min_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
683 684

        case ZMQ_VMCI_BUFFER_MAX_SIZE:
685
            return do_setsockopt (optval_, optvallen_, &vmci_buffer_max_size);
Ilya Kulakov's avatar
Ilya Kulakov committed
686 687

        case ZMQ_VMCI_CONNECT_TIMEOUT:
688
            return do_setsockopt (optval_, optvallen_, &vmci_connect_timeout);
689
#endif
Ilya Kulakov's avatar
Ilya Kulakov committed
690

691
        case ZMQ_USE_FD:
692
            if (is_int && value >= -1) {
693
                use_fd = value;
694 695 696 697
                return 0;
            }
            break;

698
        case ZMQ_BINDTODEVICE:
699 700
            return do_setsockopt_string_allow_empty_strict (
              optval_, optvallen_, &bound_device, BINDDEVSIZ);
701

702
        case ZMQ_ZAP_ENFORCE_DOMAIN:
703 704
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &zap_enforce_domain);
705

706
        case ZMQ_LOOPBACK_FASTPATH:
707 708
            return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
                                                      &loopback_fastpath);
709

710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
        case ZMQ_METADATA:
            if (optvallen_ > 0 && !is_int) {
                std::string s ((char *) optval_);
                size_t pos = 0;
                std::string key, val, delimiter = ":";
                pos = s.find (delimiter);
                if (pos != std::string::npos && pos != 0
                    && pos != s.length () - 1) {
                    key = s.substr (0, pos);
                    if (key.compare (0, 2, "X-") == 0 && key.length () < 256) {
                        val = s.substr (pos + 1, s.length ());
                        app_metadata.insert (
                          std::pair<std::string, std::string> (key, val));
                        return 0;
                    }
                }
            }
            errno = EINVAL;
            return -1;
            break;
730 731 732 733 734

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

danielkr's avatar
danielkr committed
735
        default:
736
#if defined(ZMQ_ACT_MILITANT)
737 738 739 740 741
            //  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;
742
#endif
danielkr's avatar
danielkr committed
743
            break;
744
    }
745

746 747 748 749
            // 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)
750

751
#if defined(ZMQ_ACT_MILITANT)
752 753 754 755 756 757
    //  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
758 759
    errno = EINVAL;
    return -1;
760
}
761

762 763 764
int zmq::options_t::getsockopt (int option_,
                                void *optval_,
                                size_t *optvallen_) const
765
{
766 767
    bool is_int = (*optvallen_ == sizeof (int));
    int *value = (int *) optval_;
768 769
#if defined(ZMQ_ACT_MILITANT)
    bool malformed = true; //  Did caller pass a bad option value?
770
#endif
771

772
    switch (option_) {
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793
        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)) {
                *((uint64_t *) optval_) = affinity;
                return 0;
            }
            break;

794
        case ZMQ_ROUTING_ID:
795 796
            return do_getsockopt (optval_, optvallen_, routing_id,
                                  routing_id_size);
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826
            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;

827 828 829 830 831 832
        case ZMQ_TOS:
            if (is_int) {
                *value = tos;
                return 0;
            }
            break;
Martin Hurton's avatar
Martin Hurton committed
833

834 835 836 837 838 839 840 841 842
        case ZMQ_TYPE:
            if (is_int) {
                *value = type;
                return 0;
            }
            break;

        case ZMQ_LINGER:
            if (is_int) {
843
                *value = linger.load ();
844 845 846
                return 0;
            }
            break;
847

848 849 850 851 852 853 854
        case ZMQ_CONNECT_TIMEOUT:
            if (is_int) {
                *value = connect_timeout;
                return 0;
            }
            break;

855
        case ZMQ_TCP_MAXRT:
856
            if (is_int) {
857
                *value = tcp_maxrt;
858 859 860 861
                return 0;
            }
            break;

862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897
        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)) {
                *((int64_t *) optval_) = maxmsgsize;
                *optvallen_ = sizeof (int64_t);
                return 0;
            }
            break;

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

898 899 900 901 902 903 904
        case ZMQ_MULTICAST_MAXTPDU:
            if (is_int) {
                *value = multicast_maxtpdu;
                return 0;
            }
            break;

905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924
        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;
925

926 927 928 929 930 931 932 933 934 935 936 937 938 939
        case ZMQ_IPV6:
            if (is_int) {
                *value = ipv6;
                return 0;
            }
            break;

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

940
        case ZMQ_SOCKS_PROXY:
941
            return do_getsockopt (optval_, optvallen_, socks_proxy_address);
942 943
            break;

944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977
        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;
978

979
        case ZMQ_PLAIN_SERVER:
980
            if (is_int) {
981
                *value = as_server && mechanism == ZMQ_PLAIN;
982 983 984
                return 0;
            }
            break;
985

986
        case ZMQ_PLAIN_USERNAME:
987
            return do_getsockopt (optval_, optvallen_, plain_username);
988
            break;
989

990
        case ZMQ_PLAIN_PASSWORD:
991
            return do_getsockopt (optval_, optvallen_, plain_password);
992
            break;
993 994

        case ZMQ_ZAP_DOMAIN:
995
            return do_getsockopt (optval_, optvallen_, zap_domain);
996 997
            break;

998
            //  If curve encryption isn't built, these options provoke EINVAL
999
#ifdef ZMQ_HAVE_CURVE
1000
        case ZMQ_CURVE_SERVER:
1001
            if (is_int) {
1002
                *value = as_server && mechanism == ZMQ_CURVE;
1003 1004 1005
                return 0;
            }
            break;
1006

1007
        case ZMQ_CURVE_PUBLICKEY:
1008 1009
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_public_key);
1010
            break;
1011

1012
        case ZMQ_CURVE_SECRETKEY:
1013 1014
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_secret_key);
1015 1016
            break;

1017
        case ZMQ_CURVE_SERVERKEY:
1018 1019
            return do_getsockopt_curve_key (optval_, optvallen_,
                                            curve_server_key);
1020
            break;
1021
#endif
danielkr's avatar
danielkr committed
1022 1023 1024 1025 1026 1027 1028

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

1030
            //  If libgssapi isn't installed, these options provoke EINVAL
1031
#ifdef HAVE_LIBGSSAPI_KRB5
1032 1033 1034 1035 1036 1037
        case ZMQ_GSSAPI_SERVER:
            if (is_int) {
                *value = as_server && mechanism == ZMQ_GSSAPI;
                return 0;
            }
            break;
1038

Chris Busbey's avatar
Chris Busbey committed
1039
        case ZMQ_GSSAPI_PRINCIPAL:
1040
            return do_getsockopt (optval_, optvallen_, gss_principal);
1041
            break;
danielkr's avatar
danielkr committed
1042

Chris Busbey's avatar
Chris Busbey committed
1043
        case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
1044
            return do_getsockopt (optval_, optvallen_, gss_service_principal);
1045
            break;
1046

1047 1048 1049 1050 1051 1052
        case ZMQ_GSSAPI_PLAINTEXT:
            if (is_int) {
                *value = gss_plaintext;
                return 0;
            }
            break;
1053

1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
        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;
1066 1067
#endif

1068 1069 1070 1071 1072 1073
        case ZMQ_HANDSHAKE_IVL:
            if (is_int) {
                *value = handshake_ivl;
                return 0;
            }
            break;
1074

1075 1076 1077 1078 1079 1080 1081
        case ZMQ_INVERT_MATCHING:
            if (is_int) {
                *value = invert_matching;
                return 0;
            }
            break;

Jonathan Reams's avatar
Jonathan Reams committed
1082 1083 1084 1085 1086 1087 1088 1089 1090
        case ZMQ_HEARTBEAT_IVL:
            if (is_int) {
                *value = heartbeat_interval;
                return 0;
            }
            break;

        case ZMQ_HEARTBEAT_TTL:
            if (is_int) {
1091 1092
                // Convert the internal deciseconds value to milliseconds
                *value = heartbeat_ttl * 100;
Jonathan Reams's avatar
Jonathan Reams committed
1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103
                return 0;
            }
            break;

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

1104
        case ZMQ_USE_FD:
1105
            if (is_int) {
1106
                *value = use_fd;
1107 1108 1109 1110
                return 0;
            }
            break;

1111
        case ZMQ_BINDTODEVICE:
1112
            return do_getsockopt (optval_, optvallen_, bound_device);
1113 1114
            break;

1115 1116 1117 1118 1119 1120 1121
        case ZMQ_ZAP_ENFORCE_DOMAIN:
            if (is_int) {
                *value = zap_enforce_domain;
                return 0;
            }
            break;

1122 1123 1124 1125 1126 1127 1128
        case ZMQ_LOOPBACK_FASTPATH:
            if (is_int) {
                *value = loopback_fastpath;
                return 0;
            }
            break;

1129 1130 1131 1132 1133 1134 1135
        case ZMQ_MULTICAST_LOOP:
            if (is_int) {
                *value = multicast_loop;
                return 0;
            }
            break;

1136
        default:
1137
#if defined(ZMQ_ACT_MILITANT)
1138 1139 1140
            malformed = false;
#endif
            break;
1141
    }
1142
#if defined(ZMQ_ACT_MILITANT)
1143 1144 1145
    if (malformed)
        zmq_assert (false);
#endif
1146 1147 1148
    errno = EINVAL;
    return -1;
}
1149 1150 1151

bool zmq::options_t::is_valid (int option_) const
{
1152
    LIBZMQ_UNUSED (option_);
1153
    return true;
1154
}