Problem: CLIENT and SERVER don't check SNDMORE

These sockets don't handle multipart data, so if callers send it,
they drop frames, and things break silently.

Solution: if the caller tries to use ZMQ_SNDMORE, return -1 and
set errno to EINVAL.
This commit is contained in:
Pieter Hintjens
2015-12-29 17:00:06 +01:00
parent ae3b2734df
commit 2566c02a9e
8 changed files with 131 additions and 111 deletions

View File

@@ -67,6 +67,8 @@ ERRORS
Non-blocking mode was requested and the message cannot be sent at the moment. Non-blocking mode was requested and the message cannot be sent at the moment.
*ENOTSUP*:: *ENOTSUP*::
The _zmq_msg_send()_ operation is not supported by this socket type. The _zmq_msg_send()_ operation is not supported by this socket type.
*EINVAL*::
The sender tried to send multipart data, which the socket type does not allow.
*EFSM*:: *EFSM*::
The _zmq_msg_send()_ operation cannot be performed on this socket at the moment The _zmq_msg_send()_ operation cannot be performed on this socket at the moment
due to the socket not being in the appropriate state. This error may occur with due to the socket not being in the appropriate state. This error may occur with

View File

@@ -58,6 +58,8 @@ ERRORS
Non-blocking mode was requested and the message cannot be sent at the moment. Non-blocking mode was requested and the message cannot be sent at the moment.
*ENOTSUP*:: *ENOTSUP*::
The _zmq_send()_ operation is not supported by this socket type. The _zmq_send()_ operation is not supported by this socket type.
*EINVAL*::
The sender tried to send multipart data, which the socket type does not allow.
*EFSM*:: *EFSM*::
The _zmq_send()_ operation cannot be performed on this socket at the moment The _zmq_send()_ operation cannot be performed on this socket at the moment
due to the socket not being in the appropriate state. This error may occur with due to the socket not being in the appropriate state. This error may occur with

View File

@@ -63,6 +63,8 @@ ERRORS
Non-blocking mode was requested and the message cannot be sent at the moment. Non-blocking mode was requested and the message cannot be sent at the moment.
*ENOTSUP*:: *ENOTSUP*::
The _zmq_sendmsg()_ operation is not supported by this socket type. The _zmq_sendmsg()_ operation is not supported by this socket type.
*EINVAL*::
The sender tried to send multipart data, which the socket type does not allow.
*EFSM*:: *EFSM*::
The _zmq_sendmsg()_ operation cannot be performed on this socket at the moment The _zmq_sendmsg()_ operation cannot be performed on this socket at the moment
due to the socket not being in the appropriate state. This error may occur with due to the socket not being in the appropriate state. This error may occur with

View File

@@ -54,6 +54,11 @@ void zmq::client_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
int zmq::client_t::xsend (msg_t *msg_) int zmq::client_t::xsend (msg_t *msg_)
{ {
// CLIENT sockets do not allow multipart data (ZMQ_SNDMORE)
if (msg_->flags () & msg_t::more) {
errno = EINVAL;
return -1;
}
return lb.sendpipe (msg_, NULL); return lb.sendpipe (msg_, NULL);
} }

View File

@@ -93,6 +93,11 @@ void zmq::server_t::xwrite_activated (pipe_t *pipe_)
int zmq::server_t::xsend (msg_t *msg_) int zmq::server_t::xsend (msg_t *msg_)
{ {
// SERVER sockets do not allow multipart data (ZMQ_SNDMORE)
if (msg_->flags () & msg_t::more) {
errno = EINVAL;
return -1;
}
// Find the pipe associated with the routing stored in the message. // Find the pipe associated with the routing stored in the message.
uint32_t routing_id = msg_->get_routing_id (); uint32_t routing_id = msg_->get_routing_id ();
outpipes_t::iterator it = outpipes.find (routing_id); outpipes_t::iterator it = outpipes.find (routing_id);
@@ -108,7 +113,6 @@ int zmq::server_t::xsend (msg_t *msg_)
errno = EHOSTUNREACH; errno = EHOSTUNREACH;
return -1; return -1;
} }
bool ok = it->second.pipe->write (msg_); bool ok = it->second.pipe->write (msg_);
if (unlikely (!ok)) { if (unlikely (!ok)) {
// Message failed to send - we must close it ourselves. // Message failed to send - we must close it ourselves.
@@ -118,7 +122,6 @@ int zmq::server_t::xsend (msg_t *msg_)
else else
it->second.pipe->flush (); it->second.pipe->flush ();
// Detach the message from the data buffer. // Detach the message from the data buffer.
int rc = msg_->init (); int rc = msg_->init ();
errno_assert (rc == 0); errno_assert (rc == 0);

View File

@@ -96,7 +96,7 @@
if (thread_safe) \ if (thread_safe) \
sync.lock(); sync.lock();
#define EXIT_MUTEX() \ #define EXIT_MUTEX(); \
if (thread_safe) \ if (thread_safe) \
sync.unlock(); sync.unlock();
@@ -1047,7 +1047,7 @@ int zmq::socket_base_t::send (msg_t *msg_, int flags_)
msg_->reset_metadata (); msg_->reset_metadata ();
// Try to send the message. // Try to send the message using method in each socket class
rc = xsend (msg_); rc = xsend (msg_);
if (rc == 0) { if (rc == 0) {
EXIT_MUTEX (); EXIT_MUTEX ();
@@ -1426,7 +1426,6 @@ void zmq::socket_base_t::in_event ()
// of the reaper thread. Process any commands from other threads/sockets // of the reaper thread. Process any commands from other threads/sockets
// that may be available at the moment. Ultimately, the socket will // that may be available at the moment. Ultimately, the socket will
// be destroyed. // be destroyed.
ENTER_MUTEX (); ENTER_MUTEX ();
// If the socket is thread safe we need to unsignal the reaper signaler // If the socket is thread safe we need to unsignal the reaper signaler

View File

@@ -51,11 +51,15 @@ int main (void)
char *data = (char *) zmq_msg_data (&msg); char *data = (char *) zmq_msg_data (&msg);
data [0] = 1; data [0] = 1;
rc = zmq_msg_send (&msg, client, ZMQ_SNDMORE);
assert (rc == -1);
rc = zmq_msg_send (&msg, client, 0); rc = zmq_msg_send (&msg, client, 0);
assert (rc == 1); assert (rc == 1);
rc = zmq_msg_init (&msg); rc = zmq_msg_init (&msg);
assert (rc == 0); assert (rc == 0);
rc = zmq_msg_recv (&msg, server, 0); rc = zmq_msg_recv (&msg, server, 0);
assert (rc == 1); assert (rc == 1);
@@ -74,6 +78,9 @@ int main (void)
rc = zmq_msg_set_routing_id (&msg, routing_id); rc = zmq_msg_set_routing_id (&msg, routing_id);
assert (rc == 0); assert (rc == 0);
rc = zmq_msg_send (&msg, server, ZMQ_SNDMORE);
assert (rc == -1);
rc = zmq_msg_send (&msg, server, 0); rc = zmq_msg_send (&msg, server, 0);
assert (rc == 1); assert (rc == 1);