ZMQ_MAXMSGSIZE option added

The new option allows user to guard against peers sending
oversized messages. Connection to peer sending oversized message
is dropped.

Signed-off-by: Martin Sustrik <sustrik@250bpm.com>
This commit is contained in:
Martin Sustrik 2011-03-02 09:00:36 +01:00
parent 4c7446211a
commit 5fcef1cac4
9 changed files with 72 additions and 7 deletions

View File

@ -311,6 +311,20 @@ Default value:: 100
Applicable socket types:: all, only for connection-oriented transports
ZMQ_MAXMSGSIZE: Maximum acceptable inbound message size
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The options shall retrieve limit for the inbound messages. If a peer sends
a message larger than ZMQ_MAXMSGSIZE it is disconnected. Value of -1 means
'no limit'.
[horizontal]
Option value type:: int64_t
Option value unit:: bytes
Default value:: -1
Applicable socket types:: all
ZMQ_FD: Retrieve file descriptor associated with the socket
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_FD' option shall retrieve the file descriptor associated with the

View File

@ -319,6 +319,18 @@ Option value unit:: connections
Default value:: 100
Applicable socket types:: all, only for connection-oriented transports.
ZMQ_MAXMSGSIZE: Maximum acceptable inbound message size
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Limits the size of the inbound message. If a peer sends a message larger than
ZMQ_MAXMSGSIZE it is disconnected. Value of -1 means 'no limit'.
[horizontal]
Option value type:: int64_t
Option value unit:: bytes
Default value:: -1
Applicable socket types:: all
RETURN VALUE
------------

View File

@ -204,6 +204,7 @@ ZMQ_EXPORT int zmq_term (void *context);
#define ZMQ_BACKLOG 19
#define ZMQ_RECOVERY_IVL_MSEC 20 /* opt. recovery time, reconcile in 3.x */
#define ZMQ_RECONNECT_IVL_MAX 21
#define ZMQ_MAXMSGSIZE 22
/* Send/recv options. */
#define ZMQ_NOBLOCK 1

View File

@ -25,9 +25,10 @@
#include "wire.hpp"
#include "err.hpp"
zmq::decoder_t::decoder_t (size_t bufsize_) :
zmq::decoder_t::decoder_t (size_t bufsize_, int64_t maxmsgsize_) :
decoder_base_t <decoder_t> (bufsize_),
destination (NULL)
destination (NULL),
maxmsgsize (maxmsgsize_)
{
zmq_msg_init (&in_progress);
@ -63,7 +64,13 @@ bool zmq::decoder_t::one_byte_size_ready ()
// in_progress is initialised at this point so in theory we should
// close it before calling zmq_msg_init_size, however, it's a 0-byte
// message and thus we can treat it as uninitialised...
int rc = zmq_msg_init_size (&in_progress, *tmpbuf - 1);
int rc;
if (maxmsgsize >= 0 && (int64_t) (*tmpbuf - 1) > maxmsgsize) {
rc = -1;
errno = ENOMEM;
}
else
rc = zmq_msg_init_size (&in_progress, *tmpbuf - 1);
if (rc != 0 && errno == ENOMEM) {
rc = zmq_msg_init (&in_progress);
errno_assert (rc == 0);
@ -92,7 +99,13 @@ bool zmq::decoder_t::eight_byte_size_ready ()
// in_progress is initialised at this point so in theory we should
// close it before calling zmq_msg_init_size, however, it's a 0-byte
// message and thus we can treat it as uninitialised...
int rc = zmq_msg_init_size (&in_progress, size - 1);
int rc;
if (maxmsgsize >= 0 && (int64_t) (size - 1) > maxmsgsize) {
rc = -1;
errno = ENOMEM;
}
else
rc = zmq_msg_init_size (&in_progress, size - 1);
if (rc != 0 && errno == ENOMEM) {
rc = zmq_msg_init (&in_progress);
errno_assert (rc == 0);

View File

@ -26,6 +26,7 @@
#include <algorithm>
#include "err.hpp"
#include "stdint.hpp"
#include "../include/zmq.h"
@ -180,7 +181,7 @@ namespace zmq
{
public:
decoder_t (size_t bufsize_);
decoder_t (size_t bufsize_, int64_t maxmsgsize_);
~decoder_t ();
void set_inout (struct i_inout *destination_);
@ -196,6 +197,8 @@ namespace zmq
unsigned char tmpbuf [8];
::zmq_msg_t in_progress;
int64_t maxmsgsize;
decoder_t (const decoder_t&);
void operator = (const decoder_t&);
};

View File

@ -39,6 +39,7 @@ zmq::options_t::options_t () :
reconnect_ivl (100),
reconnect_ivl_max (0),
backlog (100),
maxmsgsize (-1),
requires_in (false),
requires_out (false),
immediate_connect (true)
@ -182,6 +183,14 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
backlog = *((int*) optval_);
return 0;
case ZMQ_MAXMSGSIZE:
if (optvallen_ != sizeof (int64_t)) {
errno = EINVAL;
return -1;
}
maxmsgsize = *((int64_t*) optval_);
return 0;
}
errno = EINVAL;
@ -328,6 +337,15 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
*optvallen_ = sizeof (int);
return 0;
case ZMQ_MAXMSGSIZE:
if (*optvallen_ < sizeof (int64_t)) {
errno = EINVAL;
return -1;
}
*((int64_t*) optval_) = maxmsgsize;
*optvallen_ = sizeof (int64_t);
return 0;
}
errno = EINVAL;

View File

@ -69,6 +69,9 @@ namespace zmq
// Maximum backlog for pending connections.
int backlog;
// Maximal size of message to handle.
int64_t maxmsgsize;
// These options are never set by the user directly. Instead they are
// provided by the specific socket type.
bool requires_in;

View File

@ -211,7 +211,8 @@ void zmq::pgm_receiver_t::in_event ()
it->second.joined = true;
// Create and connect decoder for the peer.
it->second.decoder = new (std::nothrow) decoder_t (0);
it->second.decoder = new (std::nothrow) decoder_t (0,
options.maxmsgsize);
alloc_assert (it->second.decoder);
it->second.decoder->set_inout (inout);
}

View File

@ -35,7 +35,7 @@
zmq::zmq_engine_t::zmq_engine_t (fd_t fd_, const options_t &options_) :
inpos (NULL),
insize (0),
decoder (in_batch_size),
decoder (in_batch_size, options_.maxmsgsize),
outpos (NULL),
outsize (0),
encoder (out_batch_size),