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 libzmq is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 As a special exception, the Contributors give you permission to link
12 this library with independent modules to produce an executable,
13 regardless of the license terms of these independent modules, and to
14 copy and distribute the resulting executable under terms of your choice,
15 provided that you also meet, for each linked independent module, the
16 terms and conditions of the license of that module. An independent
17 module is a module which is not derived from or based on this library.
18 If you modify this library, you must extend this exception to your
19 version of the library.
20
21 libzmq is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24 License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
28*/
29
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#ifndef ZMQ_HAVE_WINDOWS
40#include <net/if.h>
41#endif
42
43#if defined IFNAMSIZ
44#define BINDDEVSIZ IFNAMSIZ
45#else
46#define BINDDEVSIZ 16
47#endif
48
49static int sockopt_invalid ()
50{
51#if defined(ZMQ_ACT_MILITANT)
52 zmq_assert (false);
53#endif
54 errno = EINVAL;
55 return -1;
56}
57
58int zmq::do_getsockopt (void *const optval_,
59 size_t *const optvallen_,
60 const std::string &value_)
61{
62 return do_getsockopt (optval_, optvallen_, value_.c_str (),
63 value_.size () + 1);
64}
65
66int zmq::do_getsockopt (void *const optval_,
67 size_t *const optvallen_,
68 const void *value_,
69 const size_t value_len_)
70{
71 // TODO behaviour is inconsistent with options_t::getsockopt; there, an
72 // *exact* length match is required except for string-like (but not the
73 // CURVE keys!) (and therefore null-ing remaining memory is a no-op, see
74 // comment below)
75 if (*optvallen_ < value_len_) {
76 return sockopt_invalid ();
77 }
78 memcpy (optval_, value_, value_len_);
79 // TODO why is the remaining memory null-ed?
80 memset (static_cast<char *> (optval_) + value_len_, 0,
81 *optvallen_ - value_len_);
82 *optvallen_ = value_len_;
83 return 0;
84}
85
86#ifdef ZMQ_HAVE_CURVE
87static int do_getsockopt_curve_key (void *const optval_,
88 const size_t *const optvallen_,
89 const uint8_t (&curve_key_)[CURVE_KEYSIZE])
90{
91 if (*optvallen_ == CURVE_KEYSIZE) {
92 memcpy (optval_, curve_key_, CURVE_KEYSIZE);
93 return 0;
94 }
95 if (*optvallen_ == CURVE_KEYSIZE_Z85 + 1) {
96 zmq_z85_encode (static_cast<char *> (optval_), curve_key_,
97 CURVE_KEYSIZE);
98 return 0;
99 }
100 return sockopt_invalid ();
101}
102#endif
103
104template <typename T>
105int do_setsockopt (const void *const optval_,
106 const size_t optvallen_,
107 T *const out_value_)
108{
109 if (optvallen_ == sizeof (T)) {
110 memcpy (out_value_, optval_, sizeof (T));
111 return 0;
112 }
113 return sockopt_invalid ();
114}
115
116int zmq::do_setsockopt_int_as_bool_strict (const void *const optval_,
117 const size_t optvallen_,
118 bool *const out_value_)
119{
120 // TODO handling of values other than 0 or 1 is not consistent,
121 // here it is disallowed, but for other options such as
122 // ZMQ_ROUTER_RAW any positive value is accepted
123 int value = -1;
124 if (do_setsockopt (optval_, optvallen_, &value) == -1)
125 return -1;
126 if (value == 0 || value == 1) {
127 *out_value_ = (value != 0);
128 return 0;
129 }
130 return sockopt_invalid ();
131}
132
133int zmq::do_setsockopt_int_as_bool_relaxed (const void *const optval_,
134 const size_t optvallen_,
135 bool *const out_value_)
136{
137 int value = -1;
138 if (do_setsockopt (optval_, optvallen_, &value) == -1)
139 return -1;
140 *out_value_ = (value != 0);
141 return 0;
142}
143
144static int
145do_setsockopt_string_allow_empty_strict (const void *const optval_,
146 const size_t optvallen_,
147 std::string *const out_value_,
148 const size_t max_len_)
149{
150 // TODO why is optval_ != NULL not allowed in case of optvallen_== 0?
151 // TODO why are empty strings allowed for some socket options, but not for others?
152 if (optval_ == NULL && optvallen_ == 0) {
153 out_value_->clear ();
154 return 0;
155 }
156 if (optval_ != NULL && optvallen_ > 0 && optvallen_ <= max_len_) {
157 out_value_->assign (static_cast<const char *> (optval_), optvallen_);
158 return 0;
159 }
160 return sockopt_invalid ();
161}
162
163static int
164do_setsockopt_string_allow_empty_relaxed (const void *const optval_,
165 const size_t optvallen_,
166 std::string *const out_value_,
167 const size_t max_len_)
168{
169 // TODO use either do_setsockopt_string_allow_empty_relaxed or
170 // do_setsockopt_string_allow_empty_strict everywhere
171 if (optvallen_ > 0 && optvallen_ <= max_len_) {
172 out_value_->assign (static_cast<const char *> (optval_), optvallen_);
173 return 0;
174 }
175 return sockopt_invalid ();
176}
177
178template <typename T>
179int do_setsockopt_set (const void *const optval_,
180 const size_t optvallen_,
181 std::set<T> *const set_)
182{
183 if (optvallen_ == 0 && optval_ == NULL) {
184 set_->clear ();
185 return 0;
186 }
187 if (optvallen_ == sizeof (T) && optval_ != NULL) {
188 set_->insert (*(static_cast<const T *> (optval_)));
189 return 0;
190 }
191 return sockopt_invalid ();
192}
193
194// TODO why is 1000 a sensible default?
195const int default_hwm = 1000;
196
197zmq::options_t::options_t () :
198 sndhwm (default_hwm),
199 rcvhwm (default_hwm),
200 affinity (0),
201 routing_id_size (0),
202 rate (100),
203 recovery_ivl (10000),
204 multicast_hops (1),
205 multicast_maxtpdu (1500),
206 sndbuf (-1),
207 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 rcvtimeo (-1),
218 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 tcp_keepalive (-1),
227 tcp_keepalive_cnt (-1),
228 tcp_keepalive_idle (-1),
229 tcp_keepalive_intvl (-1),
230 mechanism (ZMQ_NULL),
231 as_server (0),
232 gss_principal_nt (ZMQ_GSSAPI_NT_HOSTBASED),
233 gss_service_principal_nt (ZMQ_GSSAPI_NT_HOSTBASED),
234 gss_plaintext (false),
235 socket_id (0),
236 conflate (false),
237 handshake_ivl (30000),
238 connected (false),
239 heartbeat_ttl (0),
240 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 in_batch_size (8192),
247 out_batch_size (8192),
248 zero_copy (true),
249 router_notify (0),
250 monitor_event_version (1),
251 wss_trust_system (false)
252{
253 memset (curve_public_key, 0, CURVE_KEYSIZE);
254 memset (curve_secret_key, 0, CURVE_KEYSIZE);
255 memset (curve_server_key, 0, CURVE_KEYSIZE);
256#if defined ZMQ_HAVE_VMCI
257 vmci_buffer_size = 0;
258 vmci_buffer_min_size = 0;
259 vmci_buffer_max_size = 0;
260 vmci_connect_timeout = -1;
261#endif
262}
263
264int zmq::options_t::set_curve_key (uint8_t *destination_,
265 const void *optval_,
266 size_t optvallen_)
267{
268 switch (optvallen_) {
269 case CURVE_KEYSIZE:
270 memcpy (destination_, optval_, optvallen_);
271 mechanism = ZMQ_CURVE;
272 return 0;
273
274 case CURVE_KEYSIZE_Z85 + 1:
275 if (zmq_z85_decode (destination_,
276 reinterpret_cast<const char *> (optval_))) {
277 mechanism = ZMQ_CURVE;
278 return 0;
279 }
280 break;
281
282 case CURVE_KEYSIZE_Z85:
283 char z85_key[CURVE_KEYSIZE_Z85 + 1];
284 memcpy (z85_key, reinterpret_cast<const char *> (optval_),
285 optvallen_);
286 z85_key[CURVE_KEYSIZE_Z85] = 0;
287 if (zmq_z85_decode (destination_, z85_key)) {
288 mechanism = ZMQ_CURVE;
289 return 0;
290 }
291 break;
292
293 default:
294 break;
295 }
296 return -1;
297}
298
299const int deciseconds_per_millisecond = 100;
300
301int zmq::options_t::setsockopt (int option_,
302 const void *optval_,
303 size_t optvallen_)
304{
305 bool is_int = (optvallen_ == sizeof (int));
306 int value = 0;
307 if (is_int)
308 memcpy (&value, optval_, sizeof (int));
309#if defined(ZMQ_ACT_MILITANT)
310 bool malformed = true; // Did caller pass a bad option value?
311#endif
312
313 switch (option_) {
314 case ZMQ_SNDHWM:
315 if (is_int && value >= 0) {
316 sndhwm = value;
317 return 0;
318 }
319 break;
320
321 case ZMQ_RCVHWM:
322 if (is_int && value >= 0) {
323 rcvhwm = value;
324 return 0;
325 }
326 break;
327
328 case ZMQ_AFFINITY:
329 return do_setsockopt (optval_, optvallen_, &affinity);
330
331 case ZMQ_ROUTING_ID:
332 // Routing id is any binary string from 1 to 255 octets
333 if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX) {
334 routing_id_size = static_cast<unsigned char> (optvallen_);
335 memcpy (routing_id, optval_, routing_id_size);
336 return 0;
337 }
338 break;
339
340 case ZMQ_RATE:
341 if (is_int && value > 0) {
342 rate = value;
343 return 0;
344 }
345 break;
346
347 case ZMQ_RECOVERY_IVL:
348 if (is_int && value >= 0) {
349 recovery_ivl = value;
350 return 0;
351 }
352 break;
353
354 case ZMQ_SNDBUF:
355 if (is_int && value >= -1) {
356 sndbuf = value;
357 return 0;
358 }
359 break;
360
361 case ZMQ_RCVBUF:
362 if (is_int && value >= -1) {
363 rcvbuf = value;
364 return 0;
365 }
366 break;
367
368 case ZMQ_TOS:
369 if (is_int && value >= 0) {
370 tos = value;
371 return 0;
372 }
373 break;
374
375 case ZMQ_LINGER:
376 if (is_int && value >= -1) {
377 linger.store (value);
378 return 0;
379 }
380 break;
381
382 case ZMQ_CONNECT_TIMEOUT:
383 if (is_int && value >= 0) {
384 connect_timeout = value;
385 return 0;
386 }
387 break;
388
389 case ZMQ_TCP_MAXRT:
390 if (is_int && value >= 0) {
391 tcp_maxrt = value;
392 return 0;
393 }
394 break;
395
396 case ZMQ_RECONNECT_IVL:
397 if (is_int && value >= -1) {
398 reconnect_ivl = value;
399 return 0;
400 }
401 break;
402
403 case ZMQ_RECONNECT_IVL_MAX:
404 if (is_int && value >= 0) {
405 reconnect_ivl_max = value;
406 return 0;
407 }
408 break;
409
410 case ZMQ_BACKLOG:
411 if (is_int && value >= 0) {
412 backlog = value;
413 return 0;
414 }
415 break;
416
417 case ZMQ_MAXMSGSIZE:
418 return do_setsockopt (optval_, optvallen_, &maxmsgsize);
419
420 case ZMQ_MULTICAST_HOPS:
421 if (is_int && value > 0) {
422 multicast_hops = value;
423 return 0;
424 }
425 break;
426
427 case ZMQ_MULTICAST_MAXTPDU:
428 if (is_int && value > 0) {
429 multicast_maxtpdu = value;
430 return 0;
431 }
432 break;
433
434 case ZMQ_RCVTIMEO:
435 if (is_int && value >= -1) {
436 rcvtimeo = value;
437 return 0;
438 }
439 break;
440
441 case ZMQ_SNDTIMEO:
442 if (is_int && value >= -1) {
443 sndtimeo = value;
444 return 0;
445 }
446 break;
447
448 /* Deprecated in favor of ZMQ_IPV6 */
449 case ZMQ_IPV4ONLY: {
450 bool value;
451 int rc =
452 do_setsockopt_int_as_bool_strict (optval_, optvallen_, &value);
453 if (rc == 0)
454 ipv6 = !value;
455 return rc;
456 }
457
458 /* To replace the somewhat surprising IPV4ONLY */
459 case ZMQ_IPV6:
460 return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
461 &ipv6);
462
463 case ZMQ_SOCKS_PROXY:
464 return do_setsockopt_string_allow_empty_strict (
465 optval_, optvallen_, &socks_proxy_address, SIZE_MAX);
466
467 case ZMQ_SOCKS_USERNAME:
468 /* Make empty string or NULL equivalent. */
469 if (optval_ == NULL || optvallen_ == 0) {
470 socks_proxy_username.clear ();
471 return 0;
472 } else {
473 return do_setsockopt_string_allow_empty_strict (
474 optval_, optvallen_, &socks_proxy_username, 255);
475 }
476 case ZMQ_SOCKS_PASSWORD:
477 /* Make empty string or NULL equivalent. */
478 if (optval_ == NULL || optvallen_ == 0) {
479 socks_proxy_password.clear ();
480 return 0;
481 } else {
482 return do_setsockopt_string_allow_empty_strict (
483 optval_, optvallen_, &socks_proxy_password, 255);
484 }
485 case ZMQ_TCP_KEEPALIVE:
486 if (is_int && (value == -1 || value == 0 || value == 1)) {
487 tcp_keepalive = value;
488 return 0;
489 }
490 break;
491
492 case ZMQ_TCP_KEEPALIVE_CNT:
493 if (is_int && (value == -1 || value >= 0)) {
494 tcp_keepalive_cnt = value;
495 return 0;
496 }
497 break;
498
499 case ZMQ_TCP_KEEPALIVE_IDLE:
500 if (is_int && (value == -1 || value >= 0)) {
501 tcp_keepalive_idle = value;
502 return 0;
503 }
504 break;
505
506 case ZMQ_TCP_KEEPALIVE_INTVL:
507 if (is_int && (value == -1 || value >= 0)) {
508 tcp_keepalive_intvl = value;
509 return 0;
510 }
511 break;
512
513 case ZMQ_IMMEDIATE:
514 // TODO why is immediate not bool (and called non_immediate, as its meaning appears to be reversed)
515 if (is_int && (value == 0 || value == 1)) {
516 immediate = value;
517 return 0;
518 }
519 break;
520
521 case ZMQ_TCP_ACCEPT_FILTER: {
522 std::string filter_str;
523 int rc = do_setsockopt_string_allow_empty_strict (
524 optval_, optvallen_, &filter_str, UCHAR_MAX);
525 if (rc == 0) {
526 if (filter_str.empty ()) {
527 tcp_accept_filters.clear ();
528 } else {
529 tcp_address_mask_t mask;
530 rc = mask.resolve (filter_str.c_str (), ipv6);
531 if (rc == 0) {
532 tcp_accept_filters.push_back (mask);
533 }
534 }
535 }
536 return rc;
537 }
538
539#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
540 case ZMQ_IPC_FILTER_UID:
541 return do_setsockopt_set (optval_, optvallen_,
542 &ipc_uid_accept_filters);
543
544
545 case ZMQ_IPC_FILTER_GID:
546 return do_setsockopt_set (optval_, optvallen_,
547 &ipc_gid_accept_filters);
548#endif
549
550#if defined ZMQ_HAVE_SO_PEERCRED
551 case ZMQ_IPC_FILTER_PID:
552 return do_setsockopt_set (optval_, optvallen_,
553 &ipc_pid_accept_filters);
554#endif
555
556 case ZMQ_PLAIN_SERVER:
557 if (is_int && (value == 0 || value == 1)) {
558 as_server = value;
559 mechanism = value ? ZMQ_PLAIN : ZMQ_NULL;
560 return 0;
561 }
562 break;
563
564 case ZMQ_PLAIN_USERNAME:
565 if (optvallen_ == 0 && optval_ == NULL) {
566 mechanism = ZMQ_NULL;
567 return 0;
568 } else if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX
569 && optval_ != NULL) {
570 plain_username.assign (static_cast<const char *> (optval_),
571 optvallen_);
572 as_server = 0;
573 mechanism = ZMQ_PLAIN;
574 return 0;
575 }
576 break;
577
578 case ZMQ_PLAIN_PASSWORD:
579 if (optvallen_ == 0 && optval_ == NULL) {
580 mechanism = ZMQ_NULL;
581 return 0;
582 } else if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX
583 && optval_ != NULL) {
584 plain_password.assign (static_cast<const char *> (optval_),
585 optvallen_);
586 as_server = 0;
587 mechanism = ZMQ_PLAIN;
588 return 0;
589 }
590 break;
591
592 case ZMQ_ZAP_DOMAIN:
593 return do_setsockopt_string_allow_empty_relaxed (
594 optval_, optvallen_, &zap_domain, UCHAR_MAX);
595 break;
596
597 // If curve encryption isn't built, these options provoke EINVAL
598#ifdef ZMQ_HAVE_CURVE
599 case ZMQ_CURVE_SERVER:
600 if (is_int && (value == 0 || value == 1)) {
601 as_server = value;
602 mechanism = value ? ZMQ_CURVE : ZMQ_NULL;
603 return 0;
604 }
605 break;
606
607 case ZMQ_CURVE_PUBLICKEY:
608 if (0 == set_curve_key (curve_public_key, optval_, optvallen_)) {
609 return 0;
610 }
611 break;
612
613 case ZMQ_CURVE_SECRETKEY:
614 if (0 == set_curve_key (curve_secret_key, optval_, optvallen_)) {
615 return 0;
616 }
617 break;
618
619 case ZMQ_CURVE_SERVERKEY:
620 if (0 == set_curve_key (curve_server_key, optval_, optvallen_)) {
621 as_server = 0;
622 return 0;
623 }
624 break;
625#endif
626
627 case ZMQ_CONFLATE:
628 return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
629 &conflate);
630
631 // If libgssapi isn't installed, these options provoke EINVAL
632#ifdef HAVE_LIBGSSAPI_KRB5
633 case ZMQ_GSSAPI_SERVER:
634 if (is_int && (value == 0 || value == 1)) {
635 as_server = value;
636 mechanism = ZMQ_GSSAPI;
637 return 0;
638 }
639 break;
640
641 case ZMQ_GSSAPI_PRINCIPAL:
642 if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX && optval_ != NULL) {
643 gss_principal.assign ((const char *) optval_, optvallen_);
644 mechanism = ZMQ_GSSAPI;
645 return 0;
646 }
647 break;
648
649 case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
650 if (optvallen_ > 0 && optvallen_ <= UCHAR_MAX && optval_ != NULL) {
651 gss_service_principal.assign ((const char *) optval_,
652 optvallen_);
653 mechanism = ZMQ_GSSAPI;
654 as_server = 0;
655 return 0;
656 }
657 break;
658
659 case ZMQ_GSSAPI_PLAINTEXT:
660 return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
661 &gss_plaintext);
662
663 case ZMQ_GSSAPI_PRINCIPAL_NAMETYPE:
664 if (is_int
665 && (value == ZMQ_GSSAPI_NT_HOSTBASED
666 || value == ZMQ_GSSAPI_NT_USER_NAME
667 || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {
668 gss_principal_nt = value;
669 return 0;
670 }
671 break;
672
673 case ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE:
674 if (is_int
675 && (value == ZMQ_GSSAPI_NT_HOSTBASED
676 || value == ZMQ_GSSAPI_NT_USER_NAME
677 || value == ZMQ_GSSAPI_NT_KRB5_PRINCIPAL)) {
678 gss_service_principal_nt = value;
679 return 0;
680 }
681 break;
682#endif
683
684 case ZMQ_HANDSHAKE_IVL:
685 if (is_int && value >= 0) {
686 handshake_ivl = value;
687 return 0;
688 }
689 break;
690
691 case ZMQ_INVERT_MATCHING:
692 return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
693 &invert_matching);
694
695 case ZMQ_HEARTBEAT_IVL:
696 if (is_int && value >= 0) {
697 heartbeat_interval = value;
698 return 0;
699 }
700 break;
701
702 case ZMQ_HEARTBEAT_TTL:
703 // Convert this to deciseconds from milliseconds
704 value = value / deciseconds_per_millisecond;
705 if (is_int && value >= 0 && value <= UINT16_MAX) {
706 heartbeat_ttl = static_cast<uint16_t> (value);
707 return 0;
708 }
709 break;
710
711 case ZMQ_HEARTBEAT_TIMEOUT:
712 if (is_int && value >= 0) {
713 heartbeat_timeout = value;
714 return 0;
715 }
716 break;
717
718#ifdef ZMQ_HAVE_VMCI
719 case ZMQ_VMCI_BUFFER_SIZE:
720 return do_setsockopt (optval_, optvallen_, &vmci_buffer_size);
721
722 case ZMQ_VMCI_BUFFER_MIN_SIZE:
723 return do_setsockopt (optval_, optvallen_, &vmci_buffer_min_size);
724
725 case ZMQ_VMCI_BUFFER_MAX_SIZE:
726 return do_setsockopt (optval_, optvallen_, &vmci_buffer_max_size);
727
728 case ZMQ_VMCI_CONNECT_TIMEOUT:
729 return do_setsockopt (optval_, optvallen_, &vmci_connect_timeout);
730#endif
731
732 case ZMQ_USE_FD:
733 if (is_int && value >= -1) {
734 use_fd = value;
735 return 0;
736 }
737 break;
738
739 case ZMQ_BINDTODEVICE:
740 return do_setsockopt_string_allow_empty_strict (
741 optval_, optvallen_, &bound_device, BINDDEVSIZ);
742
743 case ZMQ_ZAP_ENFORCE_DOMAIN:
744 return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
745 &zap_enforce_domain);
746
747 case ZMQ_LOOPBACK_FASTPATH:
748 return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
749 &loopback_fastpath);
750
751 case ZMQ_METADATA:
752 if (optvallen_ > 0 && !is_int) {
753 const std::string s (static_cast<const char *> (optval_));
754 const size_t pos = s.find (':');
755 if (pos != std::string::npos && pos != 0
756 && pos != s.length () - 1) {
757 const std::string key = s.substr (0, pos);
758 if (key.compare (0, 2, "X-") == 0
759 && key.length () <= UCHAR_MAX) {
760 std::string val = s.substr (pos + 1, s.length ());
761 app_metadata.insert (
762 std::pair<std::string, std::string> (key, val));
763 return 0;
764 }
765 }
766 }
767 errno = EINVAL;
768 return -1;
769
770 case ZMQ_MULTICAST_LOOP:
771 return do_setsockopt_int_as_bool_relaxed (optval_, optvallen_,
772 &multicast_loop);
773
774#ifdef ZMQ_BUILD_DRAFT_API
775 case ZMQ_IN_BATCH_SIZE:
776 if (is_int && value > 0) {
777 in_batch_size = value;
778 return 0;
779 }
780 break;
781
782 case ZMQ_OUT_BATCH_SIZE:
783 if (is_int && value > 0) {
784 out_batch_size = value;
785 return 0;
786 }
787 break;
788
789 case ZMQ_WSS_KEY_PEM:
790 // TODO: check if valid certificate
791 wss_key_pem = std::string ((char *) optval_, optvallen_);
792 return 0;
793 case ZMQ_WSS_CERT_PEM:
794 // TODO: check if valid certificate
795 wss_cert_pem = std::string ((char *) optval_, optvallen_);
796 return 0;
797 case ZMQ_WSS_TRUST_PEM:
798 // TODO: check if valid certificate
799 wss_trust_pem = std::string ((char *) optval_, optvallen_);
800 return 0;
801 case ZMQ_WSS_HOSTNAME:
802 wss_hostname = std::string ((char *) optval_, optvallen_);
803 return 0;
804 case ZMQ_WSS_TRUST_SYSTEM:
805 return do_setsockopt_int_as_bool_strict (optval_, optvallen_,
806 &wss_trust_system);
807
808#endif
809
810 default:
811#if defined(ZMQ_ACT_MILITANT)
812 // There are valid scenarios for probing with unknown socket option
813 // values, e.g. to check if security is enabled or not. This will not
814 // provoke a militant assert. However, passing bad values to a valid
815 // socket option will, if ZMQ_ACT_MILITANT is defined.
816 malformed = false;
817#endif
818 break;
819 }
820
821 // TODO mechanism should either be set explicitly, or determined when
822 // connecting. currently, it depends on the order of setsockopt calls
823 // if there is some inconsistency, which is confusing. in addition,
824 // the assumed or set mechanism should be queryable (as a socket option)
825
826#if defined(ZMQ_ACT_MILITANT)
827 // There is no valid use case for passing an error back to the application
828 // when it sent malformed arguments to a socket option. Use ./configure
829 // --with-militant to enable this checking.
830 if (malformed)
831 zmq_assert (false);
832#endif
833 errno = EINVAL;
834 return -1;
835}
836
837int zmq::options_t::getsockopt (int option_,
838 void *optval_,
839 size_t *optvallen_) const
840{
841 const bool is_int = (*optvallen_ == sizeof (int));
842 int *value = static_cast<int *> (optval_);
843#if defined(ZMQ_ACT_MILITANT)
844 bool malformed = true; // Did caller pass a bad option value?
845#endif
846
847 switch (option_) {
848 case ZMQ_SNDHWM:
849 if (is_int) {
850 *value = sndhwm;
851 return 0;
852 }
853 break;
854
855 case ZMQ_RCVHWM:
856 if (is_int) {
857 *value = rcvhwm;
858 return 0;
859 }
860 break;
861
862 case ZMQ_AFFINITY:
863 if (*optvallen_ == sizeof (uint64_t)) {
864 *(static_cast<uint64_t *> (optval_)) = affinity;
865 return 0;
866 }
867 break;
868
869 case ZMQ_ROUTING_ID:
870 return do_getsockopt (optval_, optvallen_, routing_id,
871 routing_id_size);
872 break;
873
874 case ZMQ_RATE:
875 if (is_int) {
876 *value = rate;
877 return 0;
878 }
879 break;
880
881 case ZMQ_RECOVERY_IVL:
882 if (is_int) {
883 *value = recovery_ivl;
884 return 0;
885 }
886 break;
887
888 case ZMQ_SNDBUF:
889 if (is_int) {
890 *value = sndbuf;
891 return 0;
892 }
893 break;
894
895 case ZMQ_RCVBUF:
896 if (is_int) {
897 *value = rcvbuf;
898 return 0;
899 }
900 break;
901
902 case ZMQ_TOS:
903 if (is_int) {
904 *value = tos;
905 return 0;
906 }
907 break;
908
909 case ZMQ_TYPE:
910 if (is_int) {
911 *value = type;
912 return 0;
913 }
914 break;
915
916 case ZMQ_LINGER:
917 if (is_int) {
918 *value = linger.load ();
919 return 0;
920 }
921 break;
922
923 case ZMQ_CONNECT_TIMEOUT:
924 if (is_int) {
925 *value = connect_timeout;
926 return 0;
927 }
928 break;
929
930 case ZMQ_TCP_MAXRT:
931 if (is_int) {
932 *value = tcp_maxrt;
933 return 0;
934 }
935 break;
936
937 case ZMQ_RECONNECT_IVL:
938 if (is_int) {
939 *value = reconnect_ivl;
940 return 0;
941 }
942 break;
943
944 case ZMQ_RECONNECT_IVL_MAX:
945 if (is_int) {
946 *value = reconnect_ivl_max;
947 return 0;
948 }
949 break;
950
951 case ZMQ_BACKLOG:
952 if (is_int) {
953 *value = backlog;
954 return 0;
955 }
956 break;
957
958 case ZMQ_MAXMSGSIZE:
959 if (*optvallen_ == sizeof (int64_t)) {
960 *(static_cast<int64_t *> (optval_)) = maxmsgsize;
961 *optvallen_ = sizeof (int64_t);
962 return 0;
963 }
964 break;
965
966 case ZMQ_MULTICAST_HOPS:
967 if (is_int) {
968 *value = multicast_hops;
969 return 0;
970 }
971 break;
972
973 case ZMQ_MULTICAST_MAXTPDU:
974 if (is_int) {
975 *value = multicast_maxtpdu;
976 return 0;
977 }
978 break;
979
980 case ZMQ_RCVTIMEO:
981 if (is_int) {
982 *value = rcvtimeo;
983 return 0;
984 }
985 break;
986
987 case ZMQ_SNDTIMEO:
988 if (is_int) {
989 *value = sndtimeo;
990 return 0;
991 }
992 break;
993
994 case ZMQ_IPV4ONLY:
995 if (is_int) {
996 *value = 1 - ipv6;
997 return 0;
998 }
999 break;
1000
1001 case ZMQ_IPV6:
1002 if (is_int) {
1003 *value = ipv6;
1004 return 0;
1005 }
1006 break;
1007
1008 case ZMQ_IMMEDIATE:
1009 if (is_int) {
1010 *value = immediate;
1011 return 0;
1012 }
1013 break;
1014
1015 case ZMQ_SOCKS_PROXY:
1016 return do_getsockopt (optval_, optvallen_, socks_proxy_address);
1017 break;
1018
1019 case ZMQ_SOCKS_USERNAME:
1020 return do_getsockopt (optval_, optvallen_, socks_proxy_username);
1021 break;
1022
1023 case ZMQ_SOCKS_PASSWORD:
1024 return do_getsockopt (optval_, optvallen_, socks_proxy_password);
1025 break;
1026
1027 case ZMQ_TCP_KEEPALIVE:
1028 if (is_int) {
1029 *value = tcp_keepalive;
1030 return 0;
1031 }
1032 break;
1033
1034 case ZMQ_TCP_KEEPALIVE_CNT:
1035 if (is_int) {
1036 *value = tcp_keepalive_cnt;
1037 return 0;
1038 }
1039 break;
1040
1041 case ZMQ_TCP_KEEPALIVE_IDLE:
1042 if (is_int) {
1043 *value = tcp_keepalive_idle;
1044 return 0;
1045 }
1046 break;
1047
1048 case ZMQ_TCP_KEEPALIVE_INTVL:
1049 if (is_int) {
1050 *value = tcp_keepalive_intvl;
1051 return 0;
1052 }
1053 break;
1054
1055 case ZMQ_MECHANISM:
1056 if (is_int) {
1057 *value = mechanism;
1058 return 0;
1059 }
1060 break;
1061
1062 case ZMQ_PLAIN_SERVER:
1063 if (is_int) {
1064 *value = as_server && mechanism == ZMQ_PLAIN;
1065 return 0;
1066 }
1067 break;
1068
1069 case ZMQ_PLAIN_USERNAME:
1070 return do_getsockopt (optval_, optvallen_, plain_username);
1071 break;
1072
1073 case ZMQ_PLAIN_PASSWORD:
1074 return do_getsockopt (optval_, optvallen_, plain_password);
1075 break;
1076
1077 case ZMQ_ZAP_DOMAIN:
1078 return do_getsockopt (optval_, optvallen_, zap_domain);
1079 break;
1080
1081 // If curve encryption isn't built, these options provoke EINVAL
1082#ifdef ZMQ_HAVE_CURVE
1083 case ZMQ_CURVE_SERVER:
1084 if (is_int) {
1085 *value = as_server && mechanism == ZMQ_CURVE;
1086 return 0;
1087 }
1088 break;
1089
1090 case ZMQ_CURVE_PUBLICKEY:
1091 return do_getsockopt_curve_key (optval_, optvallen_,
1092 curve_public_key);
1093 break;
1094
1095 case ZMQ_CURVE_SECRETKEY:
1096 return do_getsockopt_curve_key (optval_, optvallen_,
1097 curve_secret_key);
1098 break;
1099
1100 case ZMQ_CURVE_SERVERKEY:
1101 return do_getsockopt_curve_key (optval_, optvallen_,
1102 curve_server_key);
1103 break;
1104#endif
1105
1106 case ZMQ_CONFLATE:
1107 if (is_int) {
1108 *value = conflate;
1109 return 0;
1110 }
1111 break;
1112
1113 // If libgssapi isn't installed, these options provoke EINVAL
1114#ifdef HAVE_LIBGSSAPI_KRB5
1115 case ZMQ_GSSAPI_SERVER:
1116 if (is_int) {
1117 *value = as_server && mechanism == ZMQ_GSSAPI;
1118 return 0;
1119 }
1120 break;
1121
1122 case ZMQ_GSSAPI_PRINCIPAL:
1123 return do_getsockopt (optval_, optvallen_, gss_principal);
1124 break;
1125
1126 case ZMQ_GSSAPI_SERVICE_PRINCIPAL:
1127 return do_getsockopt (optval_, optvallen_, gss_service_principal);
1128 break;
1129
1130 case ZMQ_GSSAPI_PLAINTEXT:
1131 if (is_int) {
1132 *value = gss_plaintext;
1133 return 0;
1134 }
1135 break;
1136
1137 case ZMQ_GSSAPI_PRINCIPAL_NAMETYPE:
1138 if (is_int) {
1139 *value = gss_principal_nt;
1140 return 0;
1141 }
1142 break;
1143 case ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE:
1144 if (is_int) {
1145 *value = gss_service_principal_nt;
1146 return 0;
1147 }
1148 break;
1149#endif
1150
1151 case ZMQ_HANDSHAKE_IVL:
1152 if (is_int) {
1153 *value = handshake_ivl;
1154 return 0;
1155 }
1156 break;
1157
1158 case ZMQ_INVERT_MATCHING:
1159 if (is_int) {
1160 *value = invert_matching;
1161 return 0;
1162 }
1163 break;
1164
1165 case ZMQ_HEARTBEAT_IVL:
1166 if (is_int) {
1167 *value = heartbeat_interval;
1168 return 0;
1169 }
1170 break;
1171
1172 case ZMQ_HEARTBEAT_TTL:
1173 if (is_int) {
1174 // Convert the internal deciseconds value to milliseconds
1175 *value = heartbeat_ttl * 100;
1176 return 0;
1177 }
1178 break;
1179
1180 case ZMQ_HEARTBEAT_TIMEOUT:
1181 if (is_int) {
1182 *value = heartbeat_timeout;
1183 return 0;
1184 }
1185 break;
1186
1187 case ZMQ_USE_FD:
1188 if (is_int) {
1189 *value = use_fd;
1190 return 0;
1191 }
1192 break;
1193
1194 case ZMQ_BINDTODEVICE:
1195 return do_getsockopt (optval_, optvallen_, bound_device);
1196 break;
1197
1198 case ZMQ_ZAP_ENFORCE_DOMAIN:
1199 if (is_int) {
1200 *value = zap_enforce_domain;
1201 return 0;
1202 }
1203 break;
1204
1205 case ZMQ_LOOPBACK_FASTPATH:
1206 if (is_int) {
1207 *value = loopback_fastpath;
1208 return 0;
1209 }
1210 break;
1211
1212 case ZMQ_MULTICAST_LOOP:
1213 if (is_int) {
1214 *value = multicast_loop;
1215 return 0;
1216 }
1217 break;
1218
1219#ifdef ZMQ_BUILD_DRAFT_API
1220 case ZMQ_ROUTER_NOTIFY:
1221 if (is_int) {
1222 *value = router_notify;
1223 return 0;
1224 }
1225 break;
1226 case ZMQ_IN_BATCH_SIZE:
1227 if (is_int) {
1228 *value = in_batch_size;
1229 return 0;
1230 }
1231 break;
1232
1233 case ZMQ_OUT_BATCH_SIZE:
1234 if (is_int) {
1235 *value = out_batch_size;
1236 return 0;
1237 }
1238 break;
1239#endif
1240
1241
1242 default:
1243#if defined(ZMQ_ACT_MILITANT)
1244 malformed = false;
1245#endif
1246 break;
1247 }
1248#if defined(ZMQ_ACT_MILITANT)
1249 if (malformed)
1250 zmq_assert (false);
1251#endif
1252 errno = EINVAL;
1253 return -1;
1254}
1255