0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-28 16:15:23 +08:00
This commit is contained in:
Richard Newton 2013-10-18 14:09:39 +01:00
commit 1bb982ecc2
45 changed files with 484 additions and 116 deletions

2
.gitignore vendored
View File

@ -22,6 +22,7 @@ autom4te.cache
.*~
tools/curve_keygen.o
tools/curve_keygen
tests/test_issue_566
tests/test_ctx_destroy
tests/test_term_endpoint
tests/test_system
@ -68,6 +69,7 @@ tests/test_inproc_connect
tests/test_linger
tests/test_security_null
tests/test_security_plain
tests/test_abstract_ipc
tests/test*.log
tests/test*.trs
src/platform.hpp*

View File

@ -6,8 +6,11 @@ language: c
before_script:
# libsodium
# Commit 8d0942 broke installation (sodium.h not found) so for now
# we're checking out the last good commit.
- git clone git://github.com/jedisct1/libsodium.git
- cd libsodium
- git checkout e2a30a
- ./autogen.sh
- ./configure && make check
- sudo make install

View File

@ -20,6 +20,7 @@ Ben Gray <ben@benjamg.com>
Bernd Prager <bernd@prager.ws>
Bernd Melchers <melchers@ZEDAT.FU-Berlin.DE>
Bob Beaty <rbeaty@peak6.com>
Brandon Carpenter <hashstat@yahoo.com>
Brian Buchanan <bwb@holo.org>
Brett Cameron <Brett.Cameron@hp.com>
Burak Arslan <burak-github@arskom.com.tr>

View File

@ -610,14 +610,15 @@ set(tests
test_sub_forward
test_term_endpoint
test_timeo
test_inproc_connect)
test_inproc_connect
test_issue_566)
if(NOT WIN32)
list(APPEND tests
test_monitor
test_pair_ipc
test_reqrep_ipc
test_stream)
endif()
endif()
foreach(test ${tests})
add_executable(${test} tests/${test}.cpp)

41
NEWS
View File

@ -1,5 +1,42 @@
0MQ version 4.1.0, released on 2014/xx/xx
=========================================
0MQ version 4.0.1 stable, released on 2013/10/08
================================================
Changes
-------
* Updated CURVE mechanism to track revised RFC 27 (INITIATE vouch).
The INITIATE command vouch box is Box[C',S](C->S') instead of
Box[C'](C->S), to reduce the risk of client impersonation, as per
https://codesinchaos.wordpress.com/2012/09/09/curvecp-1/.
* Fixed LIBZMQ-567, adding abstract namespaces for IPC sockets on Linux.
Converts an initial strudel or "at sign" (@) in the Unix socket path to
a NULL character ('\0') indicating that the socket uses the abstract
namespace instead of the filesystem namespace. For instance, binding a
socket to 'ipc://@/tmp/tester' will not create a file associated with
the socket whereas binding to 'ipc:///tmp/tester' will create the file
/tmp/tester. See issue 567 for more information.
* Added zmq_z85_encode and zmq_z85_decode to core libzmq API.
* Added zmq_curve_keypair to core libzmq API.
* Bumped library ABI version to 4:0:1.
Bug fixes
---------
* Fixed some build/test errors on OS/X + Clang++.
* Fixed LIBZMQ-565, typo in code.
* Fixed LIBZMQ-566, dealer-to-router connections sometimes failing.
* Fixed builds for AIX, MSVC 2008, OS/X with clang++, Solaris.
* Improved CURVE handshake error handling.
0MQ version 4.0.0 (RC1), released on 2013/09/20

View File

@ -73,7 +73,7 @@ AC_ARG_WITH([libsodium],
if test "x$zmq_search_libsodium" = "xyes"; then
if test -r "${with_libsodium}/include/sodium.h"; then
CXXFLAGS="-I${with_libsodium}/include ${CXXFLAGS}"
CPPFLAGS="-I${with_libsodium}/include ${CPPFLAGS}"
LDFLAGS="-L${with_libsodium}/lib ${LDFLAGS}"
fi
fi
@ -86,7 +86,7 @@ AC_ARG_WITH([libsodium-include-dir],
if test "x$zmq_search_libsodium_include" = "xyes"; then
if test -r "${with_libsodium_include_dir}/sodium.h"; then
CXXFLAGS="-I${with_libsodium_include_dir}/include ${CXXFLAGS}"
CPPFLAGS="-I${with_libsodium_include_dir}/include ${CPPFLAGS}"
fi
fi
@ -102,11 +102,6 @@ if test "x$zmq_search_libsodium_lib" = "xyes"; then
fi
fi
# Checks for libraries
AC_CHECK_LIB([pthread], [pthread_create])
AC_CHECK_LIB([rt], [clock_gettime])
AC_CHECK_LIB([sodium], [sodium_init],,AC_MSG_WARN(libsodium is needed for CURVE security))
# Set pedantic
libzmq_pedantic="yes"
@ -119,6 +114,7 @@ libzmq_dso_visibility="yes"
# Platform specific checks
libzmq_on_mingw32="no"
libzmq_on_android="no"
libzmq_on_linux="no"
# Set some default features required by 0MQ code.
CPPFLAGS="-D_REENTRANT -D_THREAD_SAFE $CPPFLAGS"
@ -134,6 +130,7 @@ case "${host_os}" in
CPPFLAGS="-D_GNU_SOURCE $CPPFLAGS"
fi
AC_DEFINE(ZMQ_HAVE_LINUX, 1, [Have Linux OS])
libzmq_on_linux="yes"
case "${host_os}" in
*android*)
@ -161,6 +158,9 @@ case "${host_os}" in
if test "x$solaris_has_atomic" = "xno"; then
AC_DEFINE(ZMQ_FORCE_MUTEXES, 1, [Force to use mutexes])
fi
# ssp library is required for libsodium on Solaris-like systems
LDFLAGS="-lssp $LDFLAGS"
CPPFLAGS="$CPPFLAGS -Wno-long-long"
;;
*freebsd*)
# Define on FreeBSD to enable all library features
@ -254,6 +254,11 @@ case "${host_os}" in
;;
esac
# Checks for libraries
AC_CHECK_LIB([pthread], [pthread_create])
AC_CHECK_LIB([rt], [clock_gettime])
AC_CHECK_LIB([sodium], [sodium_init],,AC_MSG_WARN(libsodium is needed for CURVE security))
#
# Check if the compiler supports -fvisibility=hidden flag. MinGW32 uses __declspec
#
@ -425,6 +430,7 @@ AC_LANG_POP([C++])
AM_CONDITIONAL(BUILD_PGM, test "x$libzmq_pgm_ext" = "xyes")
AM_CONDITIONAL(ON_MINGW, test "x$libzmq_on_mingw32" = "xyes")
AM_CONDITIONAL(ON_ANDROID, test "x$libzmq_on_android" = "xyes")
AM_CONDITIONAL(ON_LINUX, test "x$libzmq_on_linux" = "xyes")
# Checks for library functions.
AC_TYPE_SIGNAL

View File

@ -9,7 +9,7 @@ MAN3 = zmq_bind.3 zmq_unbind.3 zmq_connect.3 zmq_disconnect.3 zmq_close.3 \
zmq_socket.3 zmq_socket_monitor.3 zmq_poll.3 \
zmq_errno.3 zmq_strerror.3 zmq_version.3 zmq_proxy.3 \
zmq_sendmsg.3 zmq_recvmsg.3 zmq_init.3 zmq_term.3 \
zmq_z85_encode.3 zmq_z85_decode.3
zmq_z85_encode.3 zmq_z85_decode.3 zmq_curve_keypair.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

View File

@ -194,6 +194,15 @@ Plain-text authentication using username and password::
Elliptic curve authentication and encryption::
linkzmq:zmq_curve[7]
Generate a CURVE keypair in armored text format:
linkzmq:zmq_curve_keypair[3]
Convert an armored key into a 32-byte binary key:
linkzmq:zmq_z85_decode[3]
Convert a 32-byte binary CURVE key to an armored text string:
linkzmq:zmq_z85_encode[3]
ERROR HANDLING
--------------

View File

@ -54,7 +54,7 @@ EXAMPLE
.Setting a limit on the number of sockets
----
void *context = zmq_ctx_new ();
zmq_ctx_get (context, ZMQ_MAX_SOCKETS, 256);
zmq_ctx_set (context, ZMQ_MAX_SOCKETS, 256);
int max_sockets = zmq_ctx_get (context, ZMQ_MAX_SOCKETS);
assert (max_sockets == 256);
----

56
doc/zmq_curve_keypair.txt Normal file
View File

@ -0,0 +1,56 @@
zmq_curve_keypair(3)
====================
NAME
----
zmq_curve_keypair - generate a new CURVE keypair
SYNOPSIS
--------
*int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key);*
DESCRIPTION
-----------
The _zmq_curve_keypair()_ function shall return a newly generated random
keypair consisting of a public key and a secret key. The caller provides
two buffers, each at least 41 octets large, in which this method will
store the keys. The keys are encoded using linkzmq:zmq_z85_encode[3].
RETURN VALUE
------------
The _zmq_curve_keypair()_ function shall return 0 if successful, else it
shall return `-1` and set 'errno' to one of the values defined below.
ERRORS
------
*ENOTSUP*::
The libzmq library was not built with cryptographic support (libsodium).
EXAMPLE
-------
.Generating a new CURVE keypair
----
char public_key [41];
char secret_key [41];
int rc = crypto_box_keypair (public_key, secret_key);
assert (rc == 0);
----
SEE ALSO
--------
linkzmq:zmq_z85_decode[3]
linkzmq:zmq_z85_encode[3]
linkzmq:zmq_curve[7]
AUTHORS
-------
This page was written by the 0MQ community. To make a change please
read the 0MQ Contribution Policy at <http://www.zeromq.org/docs:contributing>.

View File

@ -120,8 +120,8 @@ Default value:: 0
Applicable socket types:: N/A
ZMQ_IDENTITY: Set socket identity
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
ZMQ_IDENTITY: Retrieve socket identity
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_IDENTITY' option shall retrieve the identity of the specified 'socket'.
Socket identity is used only by request/reply pattern. Namely, it can be used
in tandem with ROUTER socket to route messages to the peer with specific
@ -134,7 +134,7 @@ starting with binary zero are reserved for use by 0MQ infrastructure.
Option value type:: binary data
Option value unit:: N/A
Default value:: NULL
Applicable socket types:: all
Applicable socket types:: ZMQ_REP, ZMQ_REQ, ZMQ_ROUTER, ZMQ_DEALER.
ZMQ_RATE: Retrieve multicast data rate

View File

@ -48,6 +48,11 @@ NOTE: the endpoint pathname must be writable by the process. When the endpoint
starts with '/', e.g., `ipc:///pathname`, this will be an _absolute_ pathname.
If the endpoint specifies a directory that does not exist, the bind shall fail.
NOTE: on Linux only, when the endpoint pathname starts with `@`, the abstract
namespace shall be used. The abstract namespace is independent of the
filesystem and if a process attempts to bind an endpoint already bound by a
process, it will fail. See unix(7) for details.
Connecting a socket
~~~~~~~~~~~~~~~~~~~
When connecting a 'socket' to a peer address using _zmq_connect()_ with the

View File

@ -31,6 +31,10 @@ _zmq_msg_ family of functions.
CAUTION: The deallocation function 'ffn' needs to be thread-safe, since it
will be called from an arbitrary thread.
CAUTION: If the deallocation function is not provided, the allocated memory
will not be freed, and this may cause a memory leak.
CAUTION: The functions _zmq_msg_init()_, _zmq_msg_init_data()_ and
_zmq_msg_init_size()_ are mutually exclusive. Never initialize the same
'zmq_msg_t' twice.

View File

@ -150,7 +150,7 @@ results shall be undefined.
Option value type:: binary data
Option value unit:: N/A
Default value:: NULL
Applicable socket types:: all
Applicable socket types:: ZMQ_REQ, ZMQ_REP, ZMQ_ROUTER, ZMQ_DEALER.
ZMQ_RATE: Set multicast data rate

View File

@ -31,7 +31,6 @@ EXAMPLE
-------
.Decoding a CURVE key
----
#include <sodium.h>
char decoded [] = "rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7";
uint8_t public_key [32];
zmq_z85_decode (public_key, decoded);
@ -41,6 +40,7 @@ zmq_z85_decode (public_key, decoded);
SEE ALSO
--------
linkzmq:zmq_z85_decode[3]
linkzmq:zmq_curve_keypair[3]
linkzmq:zmq_curve[7]

View File

@ -47,6 +47,7 @@ puts (encoded);
SEE ALSO
--------
linkzmq:zmq_z85_decode[3]
linkzmq:zmq_curve_keypair[3]
linkzmq:zmq_curve[7]

View File

@ -15,6 +15,14 @@
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*************************************************************************
NOTE to contributors. This file comprises the principal public contract
for ZeroMQ API users (along with zmq_utils.h). Any change to this file
supplied in a stable release SHOULD not break existing applications.
In practice this means that the value of constants must not change, and
that old values may not be reused for new constants.
*************************************************************************
*/
#ifndef __ZMQ_H_INCLUDED__

View File

@ -61,8 +61,22 @@ extern "C" {
# endif
#endif
/* These functions are documented by man pages */
/* 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 */
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. */
ZMQ_EXPORT int zmq_curve_keypair (char *z85_public_key, char *z85_secret_key);
typedef void (zmq_thread_fn) (void*);
/* These functions are not documented by man pages */
/* Helper functions are used by perf tests so that they don't have to care */
/* about minutiae of time-related functions on different OS platforms. */

View File

@ -74,14 +74,12 @@ zmq::ctx_t::~ctx_t ()
delete io_threads [i];
// Deallocate the reaper thread object.
if (reaper)
delete reaper;
delete reaper;
// Deallocate the array of mailboxes. No special work is
// needed as mailboxes themselves were deallocated with their
// corresponding io_thread/socket objects.
if (slots)
free (slots);
free (slots);
// Remove the tag, so that the object is considered dead.
tag = ZMQ_CTX_TAG_VALUE_BAD;

View File

@ -132,8 +132,8 @@ namespace zmq
sockets_t sockets;
// List of unused thread slots.
typedef std::vector <uint32_t> emtpy_slots_t;
emtpy_slots_t empty_slots;
typedef std::vector <uint32_t> empty_slots_t;
empty_slots_t empty_slots;
// If true, zmq_init has been called but no socket has been created
// yet. Launching of I/O threads is delayed.

View File

@ -371,7 +371,7 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
// Check cookie plain text is as expected [C' + s']
if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, cn_client, 32)
|| memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32, cn_secret, 32)) {
errno = EAGAIN;
errno = EPROTO;
return -1;
}

View File

@ -41,11 +41,11 @@ namespace zmq
// This method is called by the session to signalise that more
// messages can be written to the pipe.
virtual void activate_in () = 0;
virtual void restart_input () = 0;
// This method is called by the session to signalise that there
// are messages to send available.
virtual void activate_out () = 0;
virtual void restart_output () = 0;
virtual void zap_msg_available () = 0;
};

View File

@ -51,9 +51,20 @@ int zmq::ipc_address_t::resolve (const char *path_)
errno = ENAMETOOLONG;
return -1;
}
#if defined ZMQ_HAVE_LINUX
if (path_[0] == '@' && !path_[1]) {
errno = EINVAL;
return -1;
}
#endif
address.sun_family = AF_UNIX;
strcpy (address.sun_path, path_);
#if defined ZMQ_HAVE_LINUX
/* Abstract sockets on Linux start with '\0' */
if (path_[0] == '@')
*address.sun_path = '\0';
#endif
return 0;
}
@ -65,7 +76,15 @@ int zmq::ipc_address_t::to_string (std::string &addr_)
}
std::stringstream s;
#if !defined ZMQ_HAVE_LINUX
s << "ipc://" << address.sun_path;
#else
s << "ipc://";
if (!address.sun_path[0] && address.sun_path[1])
s << "@" << address.sun_path + 1;
else
s << address.sun_path;
#endif
addr_ = s.str ();
return 0;
}
@ -77,6 +96,10 @@ const sockaddr *zmq::ipc_address_t::addr () const
socklen_t zmq::ipc_address_t::addrlen () const
{
#if defined ZMQ_HAVE_LINUX
if (!address.sun_path[0] && address.sun_path[1])
return (socklen_t) strlen(address.sun_path + 1) + sizeof (sa_family_t) + 1;
#endif
return (socklen_t) sizeof (address);
}

View File

@ -54,8 +54,7 @@ zmq::mtrie_t::~mtrie_t ()
else
if (count > 1) {
for (unsigned short i = 0; i != count; ++i)
if (next.table [i])
delete next.table [i];
delete next.table [i];
free (next.table);
}
}

View File

@ -286,7 +286,7 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
break;
case ZMQ_ZAP_DOMAIN:
if (optvallen_ >= 0 && optvallen_ < 256) {
if (optvallen_ < 256) {
zap_domain.assign ((const char *) optval_, optvallen_);
return 0;
}

View File

@ -102,12 +102,12 @@ void zmq::pgm_receiver_t::terminate ()
delete this;
}
void zmq::pgm_receiver_t::activate_out ()
void zmq::pgm_receiver_t::restart_output ()
{
drop_subscriptions ();
}
void zmq::pgm_receiver_t::activate_in ()
void zmq::pgm_receiver_t::restart_input ()
{
zmq_assert (session != NULL);
zmq_assert (active_tsi != NULL);

View File

@ -57,8 +57,8 @@ namespace zmq
void plug (zmq::io_thread_t *io_thread_,
zmq::session_base_t *session_);
void terminate ();
void activate_in ();
void activate_out ();
void restart_input ();
void restart_output ();
void zap_msg_available () {}
// i_poll_events interface implementation.

View File

@ -119,13 +119,13 @@ void zmq::pgm_sender_t::terminate ()
delete this;
}
void zmq::pgm_sender_t::activate_out ()
void zmq::pgm_sender_t::restart_output ()
{
set_pollout (handle);
out_event ();
}
void zmq::pgm_sender_t::activate_in ()
void zmq::pgm_sender_t::restart_input ()
{
zmq_assert (false);
}

View File

@ -56,8 +56,8 @@ namespace zmq
void plug (zmq::io_thread_t *io_thread_,
zmq::session_base_t *session_);
void terminate ();
void activate_in ();
void activate_out ();
void restart_input ();
void restart_output ();
void zap_msg_available () {}
// i_poll_events interface implementation.

View File

@ -96,8 +96,7 @@ zmq::session_base_t::~session_base_t ()
if (engine)
engine->terminate ();
if (addr)
delete addr;
delete addr;
}
void zmq::session_base_t::attach_pipe (pipe_t *pipe_)
@ -244,7 +243,7 @@ void zmq::session_base_t::read_activated (pipe_t *pipe_)
}
if (likely (pipe_ == pipe))
engine->activate_out ();
engine->restart_output ();
else
engine->zap_msg_available ();
}
@ -258,7 +257,7 @@ void zmq::session_base_t::write_activated (pipe_t *pipe_)
}
if (engine)
engine->activate_in ();
engine->restart_input ();
}
void zmq::session_base_t::hiccuped (pipe_t *)

View File

@ -74,8 +74,8 @@ zmq::stream_engine_t::stream_engine_t (fd_t fd_, const options_t &options_,
io_error (false),
subscription_required (false),
mechanism (NULL),
input_paused (false),
output_paused (false),
input_stopped (false),
output_stopped (false),
socket (NULL)
{
int rc = tx_msg.init ();
@ -114,12 +114,9 @@ zmq::stream_engine_t::~stream_engine_t ()
int rc = tx_msg.close ();
errno_assert (rc == 0);
if (encoder != NULL)
delete encoder;
if (decoder != NULL)
delete decoder;
if (mechanism != NULL)
delete mechanism;
delete encoder;
delete decoder;
delete mechanism;
}
void zmq::stream_engine_t::plug (io_thread_t *io_thread_,
@ -207,7 +204,7 @@ void zmq::stream_engine_t::in_event ()
zmq_assert (decoder);
// If there has been an I/O error, stop polling.
if (input_paused) {
if (input_stopped) {
rm_fd (handle);
io_error = true;
return;
@ -255,7 +252,7 @@ void zmq::stream_engine_t::in_event ()
error ();
return;
}
input_paused = true;
input_stopped = true;
reset_pollin (handle);
}
@ -294,7 +291,7 @@ void zmq::stream_engine_t::out_event ()
// If there is no data to send, stop polling for output.
if (outsize == 0) {
output_paused = true;
output_stopped = true;
reset_pollout (handle);
return;
}
@ -331,14 +328,14 @@ void zmq::stream_engine_t::out_event ()
terminate ();
}
void zmq::stream_engine_t::activate_out ()
void zmq::stream_engine_t::restart_output ()
{
if (unlikely (io_error))
return;
if (likely (output_paused)) {
if (likely (output_stopped)) {
set_pollout (handle);
output_paused = false;
output_stopped = false;
}
// Speculative write: The assumption is that at the moment new message
@ -348,9 +345,9 @@ void zmq::stream_engine_t::activate_out ()
out_event ();
}
void zmq::stream_engine_t::activate_in ()
void zmq::stream_engine_t::restart_input ()
{
zmq_assert (input_paused);
zmq_assert (input_stopped);
zmq_assert (session != NULL);
zmq_assert (decoder != NULL);
@ -382,7 +379,7 @@ void zmq::stream_engine_t::activate_in ()
if (rc == -1 || io_error)
error ();
else {
input_paused = false;
input_stopped = false;
set_pollin (handle);
session->flush ();
@ -483,6 +480,13 @@ bool zmq::stream_engine_t::handshake ()
// header data away.
const size_t header_size = options.identity_size + 1 >= 255 ? 10 : 2;
unsigned char tmp [10], *bufferp = tmp;
// Prepare the identity message and load it into encoder.
// Then consume bytes we have already sent to the peer.
const int rc = tx_msg.init_size (options.identity_size);
zmq_assert (rc == 0);
memcpy (tx_msg.data (), options.identity, options.identity_size);
encoder->load_msg (&tx_msg);
size_t buffer_size = encoder->encode (&bufferp, header_size);
zmq_assert (buffer_size == header_size);
@ -617,8 +621,8 @@ int zmq::stream_engine_t::process_handshake_command (msg_t *msg_)
if (rc == 0) {
if (mechanism->is_handshake_complete ())
mechanism_ready ();
if (output_paused)
activate_out ();
if (output_stopped)
restart_output ();
}
return rc;
@ -633,10 +637,10 @@ void zmq::stream_engine_t::zap_msg_available ()
error ();
return;
}
if (input_paused)
activate_in ();
if (output_paused)
activate_out ();
if (input_stopped)
restart_input ();
if (output_stopped)
restart_output ();
}
void zmq::stream_engine_t::mechanism_ready ()
@ -652,6 +656,7 @@ void zmq::stream_engine_t::mechanism_ready ()
return;
}
errno_assert (rc == 0);
session->flush ();
}
read_msg = &stream_engine_t::pull_and_encode;
@ -738,7 +743,7 @@ int zmq::stream_engine_t::write (const void *data_, size_t size_)
// we'll get an error (this may happen during the speculative write).
if (nbytes == SOCKET_ERROR && WSAGetLastError () == WSAEWOULDBLOCK)
return 0;
// Signalise peer failure.
if (nbytes == SOCKET_ERROR && (
WSAGetLastError () == WSAENETDOWN ||

View File

@ -60,8 +60,8 @@ namespace zmq
void plug (zmq::io_thread_t *io_thread_,
zmq::session_base_t *session_);
void terminate ();
void activate_in ();
void activate_out ();
void restart_input ();
void restart_output ();
void zap_msg_available ();
// i_poll_events interface implementation.
@ -179,10 +179,10 @@ namespace zmq
mechanism_t *mechanism;
// True iff the engine couldn't consume the last decoded message.
bool input_paused;
bool input_stopped;
// True iff the engine doesn't have any message to encode.
bool output_paused;
bool output_stopped;
// Socket
zmq::socket_base_t *socket;

View File

@ -48,8 +48,7 @@ zmq::trie_t::~trie_t ()
else
if (count > 1) {
for (unsigned short i = 0; i != count; ++i)
if (next.table [i])
delete next.table [i];
delete next.table [i];
free (next.table);
}
}

View File

@ -72,8 +72,7 @@ namespace zmq
}
chunk_t *sc = spare_chunk.xchg (NULL);
if (sc)
free (sc);
free (sc);
}
// Returns reference to the front element of the queue.
@ -156,8 +155,7 @@ namespace zmq
// so for cache reasons we'll get rid of the spare and
// use 'o' as the spare.
chunk_t *cs = spare_chunk.xchg (o);
if (cs)
free (cs);
free (cs);
}
}

View File

@ -30,6 +30,10 @@
#else
#include "windows.hpp"
#endif
#ifdef HAVE_LIBSODIUM
# include <sodium.h>
#endif
void zmq_sleep (int seconds_)
{
@ -100,10 +104,14 @@ static uint8_t decoder [96] = {
// Encode a binary frame as a string; destination string MUST be at least
// size * 5 / 4 bytes long plus 1 byte for the null terminator. Returns
// dest. Size must be a multiple of 4.
// Returns NULL and sets errno = EINVAL for invalid input.
char *zmq_z85_encode (char *dest, uint8_t *data, size_t size)
{
assert (size % 4 == 0);
if (size % 4 != 0) {
errno = EINVAL;
return NULL;
}
unsigned int char_nbr = 0;
unsigned int byte_nbr = 0;
uint32_t value = 0;
@ -125,15 +133,20 @@ char *zmq_z85_encode (char *dest, uint8_t *data, size_t size)
return dest;
}
// --------------------------------------------------------------------------
// Decode an encoded string into a binary frame; dest must be at least
// strlen (string) * 4 / 5 bytes long. Returns dest. strlen (string)
// must be a multiple of 5.
// Returns NULL and sets errno = EINVAL for invalid input.
uint8_t *zmq_z85_decode (uint8_t *dest, char *string)
{
assert (strlen (string) % 5 == 0);
if (strlen (string) % 5 != 0) {
errno = EINVAL;
return NULL;
}
unsigned int byte_nbr = 0;
unsigned int char_nbr = 0;
uint32_t value = 0;
@ -153,3 +166,34 @@ uint8_t *zmq_z85_decode (uint8_t *dest, char *string)
assert (byte_nbr == strlen (string) * 4 / 5);
return dest;
}
// --------------------------------------------------------------------------
// Generate a public/private keypair with libsodium.
// Generated keys will be 40 byte z85-encoded strings.
// Returns 0 on success, -1 on failure, setting errno.
// Sets errno = ENOTSUP in the absence of libsodium.
int zmq_curve_keypair (char* z85_public_key, char *z85_secret_key)
{
#ifdef HAVE_LIBSODIUM
# if crypto_box_PUBLICKEYBYTES != 32 \
|| crypto_box_SECRETKEYBYTES != 32
# error "libsodium not built correctly"
# endif
uint8_t public_key [32];
uint8_t secret_key [32];
int rc = crypto_box_keypair (public_key, secret_key);
// is there a sensible errno to set here?
if (rc) return rc;
zmq_z85_encode (z85_public_key, public_key, 32);
zmq_z85_encode (z85_secret_key, secret_key, 32);
return 0;
#else // requires libsodium
errno = ENOTSUP;
return -1;
#endif
}

View File

@ -37,7 +37,9 @@ noinst_PROGRAMS = test_system \
test_req_correlate \
test_req_relaxed \
test_conflate \
test_inproc_connect
test_inproc_connect \
test_issue_566 \
test_abstract_ipc
if !ON_MINGW
noinst_PROGRAMS += test_shutdown_stress \
@ -82,6 +84,8 @@ test_req_correlate_SOURCES = test_req_correlate.cpp
test_req_relaxed_SOURCES = test_req_relaxed.cpp
test_conflate_SOURCES = test_conflate.cpp
test_inproc_connect_SOURCES = test_inproc_connect.cpp
test_issue_566_SOURCES = test_issue_566.cpp
test_abstract_ipc_SOURCES = test_abstract_ipc.cpp
if !ON_MINGW
test_shutdown_stress_SOURCES = test_shutdown_stress.cpp
test_pair_ipc_SOURCES = test_pair_ipc.cpp testutil.hpp
@ -93,3 +97,7 @@ endif
# Run the test cases
TESTS = $(noinst_PROGRAMS)
XFAIL_TESTS = test_linger
if !ON_LINUX
XFAIL_TESTS += test_abstract_ipc
endif

View File

@ -0,0 +1,57 @@
/*
Copyright (c) 2007-2013 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 <http://www.gnu.org/licenses/>.
*/
#include "testutil.hpp"
int main (void)
{
setup_test_environment();
void *ctx = zmq_ctx_new ();
assert (ctx);
void *sb = zmq_socket (ctx, ZMQ_PAIR);
assert (sb);
int rc = zmq_bind (sb, "ipc://@/tmp/tester");
assert (rc == 0);
char endpoint[200];
size_t size = sizeof(endpoint);
rc = zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, endpoint, &size);
assert (rc == 0);
rc = strncmp(endpoint, "ipc://@/tmp/tester", size);
assert (rc == 0);
void *sc = zmq_socket (ctx, ZMQ_PAIR);
assert (sc);
rc = zmq_connect (sc, "ipc://@/tmp/tester");
assert (rc == 0);
bounce (sb, sc);
rc = zmq_close (sc);
assert (rc == 0);
rc = zmq_close (sb);
assert (rc == 0);
rc = zmq_ctx_term (ctx);
assert (rc == 0);
return 0 ;
}

85
tests/test_issue_566.cpp Normal file
View File

@ -0,0 +1,85 @@
/*
Copyright (c) 2007-2013 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 <http://www.gnu.org/licenses/>.
*/
#include "testutil.hpp"
// Issue 566 describes a problem in libzmq v4.0.0 where a dealer to router
// connection would fail randomly. The test works when the two sockets are
// on the same context, and failed when they were on separate contexts.
// Fixed by https://github.com/zeromq/libzmq/commit/be25cf.
int main (void)
{
setup_test_environment();
void *ctx1 = zmq_ctx_new ();
assert (ctx1);
void *ctx2 = zmq_ctx_new ();
assert (ctx2);
void *router = zmq_socket (ctx1, ZMQ_ROUTER);
int on = 1;
int rc = zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY, &on, sizeof (on));
assert (rc == 0);
rc = zmq_bind (router, "tcp://127.0.0.1:5555");
assert (rc != -1);
// Repeat often enough to be sure this works as it should
for (int cycle = 0; cycle < 100; cycle++) {
// Create dealer with unique explicit identity
// We assume the router learns this out-of-band
void *dealer = zmq_socket (ctx2, ZMQ_DEALER);
char identity [10];
sprintf (identity, "%09d", cycle);
rc = zmq_setsockopt (dealer, ZMQ_IDENTITY, identity, 10);
assert (rc == 0);
int rcvtimeo = 1000;
rc = zmq_setsockopt (dealer, ZMQ_RCVTIMEO, &rcvtimeo, sizeof (int));
assert (rc == 0);
rc = zmq_connect (dealer, "tcp://127.0.0.1:5555");
assert (rc == 0);
// Router will try to send to dealer, at short intervals.
// It typically takes 2-5 msec for the connection to establish
// on a loopback interface, but we'll allow up to one second
// before failing the test (e.g. for running on a debugger or
// a very slow system).
for (int attempt = 0; attempt < 500; attempt++) {
zmq_poll (0, 0, 2);
rc = zmq_send (router, identity, 10, ZMQ_SNDMORE);
if (rc == -1 && errno == EHOSTUNREACH)
continue;
assert (rc == 10);
rc = zmq_send (router, "HELLO", 5, 0);
assert (rc == 5);
break;
}
uint8_t buffer [5];
rc = zmq_recv (dealer, buffer, 5, 0);
assert (rc == 5);
assert (memcmp (buffer, "HELLO", 5) == 0);
close_zero_linger (dealer);
}
zmq_close (router);
zmq_ctx_destroy (ctx1);
zmq_ctx_destroy (ctx2);
return 0;
}

View File

@ -19,11 +19,11 @@
#include "testutil.hpp"
// Test keys from the zmq_curve man page
static char client_public [] = "Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID";
static char client_secret [] = "D:)Q[IlAW!ahhC2ac:9*A}h:p?([4%wOTJ%JR%cs";
static char server_public [] = "rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7";
static char server_secret [] = "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6";
// We'll generate random test keys at startup
static char client_public [41];
static char client_secret [41];
static char server_public [41];
static char server_secret [41];
// --------------------------------------------------------------------------
// Encode a binary frame as a string; destination string MUST be at least
@ -86,6 +86,13 @@ int main (void)
printf ("libsodium not installed, skipping CURVE test\n");
return 0;
#endif
// Generate new keypairs for this test
int rc = zmq_curve_keypair (client_public, client_secret);
assert (rc == 0);
rc = zmq_curve_keypair (server_public, server_secret);
assert (rc == 0);
setup_test_environment ();
void *ctx = zmq_ctx_new ();
assert (ctx);
@ -95,7 +102,7 @@ int main (void)
// where child thread does not start up fast enough.
void *handler = zmq_socket (ctx, ZMQ_REP);
assert (handler);
int rc = zmq_bind (handler, "inproc://zeromq.zap.01");
rc = zmq_bind (handler, "inproc://zeromq.zap.01");
assert (rc == 0);
void *zap_thread = zmq_threadstart (&zap_handler, handler);
@ -175,8 +182,9 @@ int main (void)
// Check CURVE security with bogus client credentials
// This must be caught by the ZAP handler
char bogus_public [] = "8)<]6{NT{}=MZBsH)i%l0k}y*^i#80n-Yf{I8Z+P";
char bogus_secret [] = "[m9E0TW2Mf?Ke3K>fuBGCrkBpc6aJbj4jv4451Nx";
char bogus_public [41];
char bogus_secret [41];
zmq_curve_keypair (bogus_public, bogus_secret);
client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);

View File

@ -57,6 +57,8 @@ void test_fair_queue_in (void *ctx)
s_send_seq (rep, "A", SEQ_END);
s_recv_seq (reqs [0], "A", SEQ_END);
// TODO: following test fails randomly on some boxes
#ifdef SOMEONE_FIXES_THIS
// send N requests
for (size_t peer = 0; peer < services; ++peer) {
char * str = strdup("A");
@ -69,12 +71,13 @@ void test_fair_queue_in (void *ctx)
for (size_t peer = 0; peer < services; ++peer) {
char * str = strdup("A");
str [0] += peer;
// Test fails here
s_recv_seq (rep, str, SEQ_END);
s_send_seq (rep, str, SEQ_END);
s_recv_seq (reqs [peer], str, SEQ_END);
free (str);
}
#endif
close_zero_linger (rep);
for (size_t peer = 0; peer < services; ++peer)

View File

@ -102,7 +102,6 @@ test_stream_to_dealer (void)
assert (rc >= 0);
bytes_read += rc;
}
assert (rc == 97);
// First two bytes are major and minor version numbers.
assert (buffer [0] == 3); // ZMTP/3.0

View File

@ -20,7 +20,7 @@
#include "testutil.hpp"
#if defined (ZMQ_HAVE_WINDOWS)
# include <WinSock2.h>
# include <winsock2.h>
# include <stdexcept>
#else
# include <sys/socket.h>

View File

@ -31,8 +31,10 @@
#include <string>
#if defined _WIN32
# include <crtdbg.h>
# pragma warning(disable:4996)
# if defined _MSC_VER
# include <crtdbg.h>
# pragma warning(disable:4996)
# endif
#else
# include <unistd.h>
# include <signal.h>
@ -249,9 +251,11 @@ void close_zero_linger (void *socket)
void setup_test_environment()
{
#if defined _WIN32
# if defined _MSC_VER
_set_abort_behavior( 0, _WRITE_ABORT_MSG);
_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
# endif
#endif
}

View File

@ -4,6 +4,6 @@ INCLUDES = -I$(top_srcdir)/include
bin_PROGRAMS = curve_keygen
curve_keygen_LDADD = $(top_srcdir)/src/libzmq.la
curve_keygen_LDADD = $(top_builddir)/src/libzmq.la
curve_keygen_SOURCES = curve_keygen.c

View File

@ -24,19 +24,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <platform.hpp>
#include <zmq.h>
#include <zmq_utils.h>
#ifdef HAVE_LIBSODIUM
# include <sodium.h>
#endif
int main (void)
{
#ifdef HAVE_LIBSODIUM
# if crypto_box_PUBLICKEYBYTES != 32 \
|| crypto_box_SECRETKEYBYTES != 32
# error "libsodium not built correctly"
# endif
puts ("This tool generates a CurveZMQ keypair, as two printable strings you can");
puts ("use in configuration files or source code. The encoding uses Z85, which");
puts ("is a base-85 format that is described in 0MQ RFC 32, and which has an");
@ -44,23 +38,21 @@ int main (void)
puts ("always works with the secret key held by one party and the public key");
puts ("distributed (securely!) to peers wishing to connect to it.");
uint8_t public_key [32];
uint8_t secret_key [32];
char public_key [41];
char secret_key [41];
int rc = zmq_curve_keypair (public_key, secret_key);
if (rc != 0) {
if (zmq_errno () == ENOTSUP) {
puts ("To use curve_keygen, please install libsodium and then rebuild libzmq.");
}
exit (1);
}
int rc = crypto_box_keypair (public_key, secret_key);
assert (rc == 0);
char encoded [41];
zmq_z85_encode (encoded, public_key, 32);
puts ("\n== CURVE PUBLIC KEY ==");
puts (encoded);
puts (public_key);
zmq_z85_encode (encoded, secret_key, 32);
puts ("\n== CURVE SECRET KEY ==");
puts (encoded);
puts (secret_key);
#else
puts ("To build curve_keygen, please install libsodium and then rebuild libzmq.");
#endif
exit (0);
}