diff --git a/.gitignore b/.gitignore index 7bb22d23..38222661 100644 --- a/.gitignore +++ b/.gitignore @@ -94,6 +94,7 @@ tests/test_proxy_chain tests/test_bind_src_address tests/test_metadata tests/test_id2fd +tests/test_capabilities tests/test*.log tests/test*.trs src/platform.hpp* diff --git a/doc/Makefile.am b/doc/Makefile.am index dd4e014b..21393597 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -10,7 +10,7 @@ MAN3 = zmq_bind.3 zmq_unbind.3 zmq_connect.3 zmq_disconnect.3 zmq_close.3 \ zmq_errno.3 zmq_strerror.3 zmq_version.3 \ zmq_sendmsg.3 zmq_recvmsg.3 \ zmq_proxy.3 zmq_proxy_steerable.3 \ - zmq_z85_encode.3 zmq_z85_decode.3 zmq_curve_keypair.3 + zmq_z85_encode.3 zmq_z85_decode.3 zmq_curve_keypair.3 zmq_has.3 MAN7 = zmq.7 zmq_tcp.7 zmq_pgm.7 zmq_epgm.7 zmq_inproc.7 zmq_ipc.7 \ zmq_null.7 zmq_plain.7 zmq_curve.7 zmq_tipc.7 diff --git a/doc/zmq_has.txt b/doc/zmq_has.txt new file mode 100644 index 00000000..2f7d75b9 --- /dev/null +++ b/doc/zmq_has.txt @@ -0,0 +1,43 @@ +zmq_has(3) +========== + + +NAME +---- +zmq_has - check a ZMQ capability + + +SYNOPSIS +-------- +*int zmq_has (const char *capability);* + + +DESCRIPTION +----------- +The _zmq_has()_ function shall report whether a specified capability is +available in the library. This allows bindings and applications to probe +a library directly, for transport and security options. + +Capabilities shall be lowercase strings. The following capabilities are +defined: + +* ipc - the library supports the ipc:// protocol +* pgm - the library supports the pgm:// protocol +* tipc - the library supports the tipc:// protocol +* norm - the library supports the norm:// protocol +* curve - the library supports the CURVE security mechanism +* gssapi - the library supports the GSSAPI security mechanism + +When this method is provided, the zmq.h header file will define +ZMQ_HAS_CAPABILITIES. + +RETURN VALUE +------------ +The _zmq_has()_ function shall return 1 if the specified capability is +provided. Otherwise it shall return 0. + + +AUTHORS +------- +This page was written by the 0MQ community. To make a change please +read the 0MQ Contribution Policy at . diff --git a/include/zmq.h b/include/zmq.h index 86a52638..08831ec3 100644 --- a/include/zmq.h +++ b/include/zmq.h @@ -359,9 +359,6 @@ ZMQ_EXPORT int zmq_send_const (void *s, const void *buf, size_t len, int flags); ZMQ_EXPORT int zmq_recv (void *s, void *buf, size_t len, int flags); ZMQ_EXPORT int zmq_socket_monitor (void *s, const char *addr, int events); -ZMQ_EXPORT int zmq_sendmsg (void *s, zmq_msg_t *msg, int flags); -ZMQ_EXPORT int zmq_recvmsg (void *s, zmq_msg_t *msg, int flags); - /* Experimental */ struct iovec; @@ -397,12 +394,21 @@ ZMQ_EXPORT int zmq_poll (zmq_pollitem_t *items, int nitems, long timeout); ZMQ_EXPORT int zmq_proxy (void *frontend, void *backend, void *capture); ZMQ_EXPORT int zmq_proxy_steerable (void *frontend, void *backend, void *capture, void *control); +/* Probe library capabilities */ + +#define ZMQ_HAS_CAPABILITIES 1 +ZMQ_EXPORT int zmq_has (const char *capability); + /* Deprecated aliases */ #define ZMQ_STREAMER 1 #define ZMQ_FORWARDER 2 #define ZMQ_QUEUE 3 -/* Deprecated method */ + +/* Deprecated methods */ ZMQ_EXPORT int zmq_device (int type, void *frontend, void *backend); +ZMQ_EXPORT int zmq_sendmsg (void *s, zmq_msg_t *msg, int flags); +ZMQ_EXPORT int zmq_recvmsg (void *s, zmq_msg_t *msg, int flags); + #undef ZMQ_EXPORT diff --git a/include/zmq_utils.h b/include/zmq_utils.h index bd1486c0..f10b6a20 100644 --- a/include/zmq_utils.h +++ b/include/zmq_utils.h @@ -61,16 +61,16 @@ extern "C" { # endif #endif -/* These functions are documented by man pages */ +/* These functions are documented by man pages */ -/* Encode data with Z85 encoding. Returns encoded data */ +/* Encode data with Z85 encoding. Returns encoded data */ ZMQ_EXPORT char *zmq_z85_encode (char *dest, uint8_t *data, size_t size); -/* Decode data with Z85 encoding. Returns decoded data */ +/* Decode data with Z85 encoding. Returns decoded data */ ZMQ_EXPORT uint8_t *zmq_z85_decode (uint8_t *dest, char *string); -/* Generate z85-encoded public and private keypair with libsodium. */ -/* Returns 0 on success. */ +/* Generate z85-encoded public and private keypair with libsodium. */ +/* Returns 0 on success. */ ZMQ_EXPORT int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key); typedef void (zmq_thread_fn) (void*); diff --git a/src/options.cpp b/src/options.cpp index ef945486..b8c688ba 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -68,6 +68,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_, #if defined (ZMQ_ACT_MILITANT) bool malformed = true; // Did caller pass a bad option value? #endif + switch (option_) { case ZMQ_SNDHWM: if (is_int && value >= 0) { @@ -415,7 +416,9 @@ int zmq::options_t::setsockopt (int option_, const void *optval_, return 0; } break; - + + // If libgssapi isn't installed, these options provoke EINVAL +# ifdef HAVE_LIBGSSAPI_KRB5 case ZMQ_GSSAPI_SERVER: if (is_int && (value == 0 || value == 1)) { as_server = value; @@ -423,7 +426,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_, return 0; } break; - + case ZMQ_GSSAPI_PRINCIPAL: if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL) { gss_principal.assign ((const char *) optval_, optvallen_); @@ -447,7 +450,8 @@ int zmq::options_t::setsockopt (int option_, const void *optval_, return 0; } break; - +# endif + case ZMQ_HANDSHAKE_IVL: if (is_int && value >= 0) { handshake_ivl = value; @@ -480,6 +484,9 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_) { bool is_int = (*optvallen_ == sizeof (int)); int *value = (int *) optval_; +#if defined (ZMQ_ACT_MILITANT) + bool malformed = true; // Did caller pass a bad option value? +#endif switch (option_) { case ZMQ_SNDHWM: @@ -758,6 +765,8 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_) } break; + // If libgssapi isn't installed, these options provoke EINVAL +# ifdef HAVE_LIBGSSAPI_KRB5 case ZMQ_GSSAPI_SERVER: if (is_int) { *value = as_server && mechanism == ZMQ_GSSAPI; @@ -787,14 +796,25 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_) return 0; } break; - +#endif + case ZMQ_HANDSHAKE_IVL: if (is_int) { *value = handshake_ivl; return 0; } break; + + default: +#if defined (ZMQ_ACT_MILITANT) + malformed = false; +#endif + break; } +#if defined (ZMQ_ACT_MILITANT) + if (malformed) + zmq_assert (false); +#endif errno = EINVAL; return -1; } diff --git a/src/zmq.cpp b/src/zmq.cpp index ef53a1b8..3b0b568b 100644 --- a/src/zmq.cpp +++ b/src/zmq.cpp @@ -1043,3 +1043,35 @@ int zmq_device (int /* type */, void *frontend_, void *backend_) (zmq::socket_base_t*) frontend_, (zmq::socket_base_t*) backend_, NULL); } + +// Probe library capabilities; for now, reports on transport and security + +int zmq_has (const char *capability) +{ +#if !defined (ZMQ_HAVE_WINDOWS) && !defined (ZMQ_HAVE_OPENVMS) + if (strcmp (capability, "ipc") == 0) + return true; +#endif +#if defined (ZMQ_HAVE_OPENPGM) + if (strcmp (capability, "pgm") == 0) + return true; +#endif +#if defined (ZMQ_HAVE_TIPC) + if (strcmp (capability, "tipc") == 0) + return true; +#endif +#if defined (ZMQ_HAVE_NORM) + if (strcmp (capability, "norm") == 0) + return true; +#endif +#if defined (HAVE_LIBSODIUM) + if (strcmp (capability, "curve") == 0) + return true; +#endif +#if defined (HAVE_LIBGSSAPI_KRB5) + if (strcmp (capability, "gssapi") == 0) + return true; +#endif + // Whatever the application asked for, we don't have + return false; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 70ff5399..7b526d00 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -48,9 +48,10 @@ noinst_PROGRAMS = test_system \ test_ipc_wildcard \ test_diffserv \ test_connect_rid \ - test_bind_src_address \ - test_metadata\ - test_id2fd + test_bind_src_address \ + test_metadata \ + test_id2fd \ + test_capabilities if !ON_MINGW noinst_PROGRAMS += test_shutdown_stress \ @@ -127,6 +128,7 @@ test_connect_rid_SOURCES = test_connect_rid.cpp test_bind_src_address_SOURCES = test_bind_src_address.cpp test_metadata_SOURCES = test_metadata.cpp test_id2fd_SOURCES = test_id2fd.cpp +test_capabilities_SOURCES = test_capabilities.cpp if !ON_MINGW test_shutdown_stress_SOURCES = test_shutdown_stress.cpp test_pair_ipc_SOURCES = test_pair_ipc.cpp testutil.hpp diff --git a/tests/test_capabilities.cpp b/tests/test_capabilities.cpp new file mode 100644 index 00000000..eaa8699f --- /dev/null +++ b/tests/test_capabilities.cpp @@ -0,0 +1,61 @@ +/* + Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file + + This file is part of 0MQ. + + 0MQ is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + 0MQ 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "testutil.hpp" + +int main (void) +{ +#if !defined (ZMQ_HAVE_WINDOWS) && !defined (ZMQ_HAVE_OPENVMS) + assert (zmq_has ("ipc")); +#else + assert (!zmq_has ("ipc")); +#endif + +#if defined (ZMQ_HAVE_OPENPGM) + assert (zmq_has ("pgm")); +#else + assert (!zmq_has ("pgm")); +#endif + +#if defined (ZMQ_HAVE_TIPC) + assert (zmq_has ("tipc")); +#else + assert (!zmq_has ("tipc")); +#endif + +#if defined (ZMQ_HAVE_NORM) + assert (zmq_has ("norm")); +#else + assert (!zmq_has ("norm")); +#endif + +#if defined (HAVE_LIBSODIUM) + assert (zmq_has ("curve")); +#else + assert (!zmq_has ("curve")); +#endif + +#if defined (HAVE_LIBGSSAPI_KRB5) + assert (zmq_has ("gssapi")); +#else + assert (!zmq_has ("gssapi")); +#endif + + return 0; +}