Commit 84e0c799 authored by Martin Sustrik's avatar Martin Sustrik

queue device fixed

parent 4a6bac1d
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <stddef.h>
#include "../include/zmq.h" #include "../include/zmq.h"
#include "queue.hpp" #include "queue.hpp"
...@@ -26,15 +28,12 @@ ...@@ -26,15 +28,12 @@
int zmq::queue (class socket_base_t *insocket_, int zmq::queue (class socket_base_t *insocket_,
class socket_base_t *outsocket_) class socket_base_t *outsocket_)
{ {
zmq_msg_t request_msg; zmq_msg_t msg;
int rc = zmq_msg_init (&request_msg); int rc = zmq_msg_init (&msg);
errno_assert (rc == 0); zmq_assert (rc == 0);
bool has_request = false;
zmq_msg_t response_msg; int64_t more;
rc = zmq_msg_init (&response_msg); size_t moresz;
errno_assert (rc == 0);
bool has_response = false;
zmq_pollitem_t items [2]; zmq_pollitem_t items [2];
items [0].socket = insocket_; items [0].socket = insocket_;
...@@ -47,53 +46,54 @@ int zmq::queue (class socket_base_t *insocket_, ...@@ -47,53 +46,54 @@ int zmq::queue (class socket_base_t *insocket_,
items [1].revents = 0; items [1].revents = 0;
while (true) { while (true) {
// Wait while there are either requests or replies to process.
rc = zmq_poll (&items [0], 2, -1); rc = zmq_poll (&items [0], 2, -1);
errno_assert (rc > 0); errno_assert (rc > 0);
// The algorithm below asumes ratio of request and replies processed // The algorithm below asumes ratio of request and replies processed
// under full load to be 1:1. While processing requests replies first // under full load to be 1:1. Although processing requests replies
// is tempting it is suspectible to DoS attacks (overloading the system // first is tempting it is suspectible to DoS attacks (overloading
// with unsolicited replies). // the system with unsolicited replies).
// Receive a new request. // Process a request.
if (items [0].revents & ZMQ_POLLIN) { if (items [0].revents & ZMQ_POLLIN) {
zmq_assert (!has_request); while (true) {
rc = insocket_->recv (&request_msg, ZMQ_NOBLOCK);
errno_assert (rc == 0); rc = insocket_->recv (&msg, 0);
items [0].events &= ~ZMQ_POLLIN; errno_assert (rc == 0);
items [1].events |= ZMQ_POLLOUT;
has_request = true; moresz = sizeof (more);
} rc = insocket_->getsockopt (ZMQ_RCVMORE, &more, &moresz);
errno_assert (rc == 0);
rc = outsocket_->send (&msg, more ? ZMQ_SNDMORE : 0);
errno_assert (rc == 0);
// Send the request further. if (!more)
if (items [1].revents & ZMQ_POLLOUT) { break;
zmq_assert (has_request); }
rc = outsocket_->send (&request_msg, ZMQ_NOBLOCK);
errno_assert (rc == 0);
items [0].events |= ZMQ_POLLIN;
items [1].events &= ~ZMQ_POLLOUT;
has_request = false;
} }
// Get a new reply. // Process a reply.
if (items [1].revents & ZMQ_POLLIN) { if (items [1].revents & ZMQ_POLLIN) {
zmq_assert (!has_response); while (true) {
rc = outsocket_->recv (&response_msg, ZMQ_NOBLOCK);
errno_assert (rc == 0); rc = outsocket_->recv (&msg, 0);
items [0].events |= ZMQ_POLLOUT; errno_assert (rc == 0);
items [1].events &= ~ZMQ_POLLIN;
has_response = true; moresz = sizeof (more);
} rc = outsocket_->getsockopt (ZMQ_RCVMORE, &more, &moresz);
errno_assert (rc == 0);
// Send the reply further. rc = insocket_->send (&msg, more ? ZMQ_SNDMORE : 0);
if (items [0].revents & ZMQ_POLLOUT) {\ errno_assert (rc == 0);
zmq_assert (has_response);
rc = insocket_->send (&response_msg, ZMQ_NOBLOCK); if (!more)
errno_assert (rc == 0); break;
items [0].events &= ~ZMQ_POLLOUT; }
items [1].events |= ZMQ_POLLIN;
has_response = false;
} }
} }
return 0; return 0;
......
...@@ -23,7 +23,8 @@ ...@@ -23,7 +23,8 @@
#include "err.hpp" #include "err.hpp"
zmq::xreq_t::xreq_t (class app_thread_t *parent_) : zmq::xreq_t::xreq_t (class app_thread_t *parent_) :
socket_base_t (parent_) socket_base_t (parent_),
dropping (false)
{ {
options.requires_in = true; options.requires_in = true;
options.requires_out = true; options.requires_out = true;
...@@ -77,7 +78,25 @@ int zmq::xreq_t::xsetsockopt (int option_, const void *optval_, ...@@ -77,7 +78,25 @@ int zmq::xreq_t::xsetsockopt (int option_, const void *optval_,
int zmq::xreq_t::xsend (zmq_msg_t *msg_, int flags_) int zmq::xreq_t::xsend (zmq_msg_t *msg_, int flags_)
{ {
return lb.send (msg_, flags_); while (true) {
// If we are ignoring the current message, just drop it and return.
if (dropping) {
if (!(msg_->flags & ZMQ_MSG_MORE))
dropping = false;
int rc = zmq_msg_close (msg_);
zmq_assert (rc == 0);
rc = zmq_msg_init (msg_);
zmq_assert (rc == 0);
return 0;
}
int rc = lb.send (msg_, flags_);
if (rc != 0 && errno == EAGAIN)
dropping = true;
else
return rc;
}
} }
int zmq::xreq_t::xrecv (zmq_msg_t *msg_, int flags_) int zmq::xreq_t::xrecv (zmq_msg_t *msg_, int flags_)
...@@ -92,6 +111,8 @@ bool zmq::xreq_t::xhas_in () ...@@ -92,6 +111,8 @@ bool zmq::xreq_t::xhas_in ()
bool zmq::xreq_t::xhas_out () bool zmq::xreq_t::xhas_out ()
{ {
return lb.has_out (); // Socket is always ready for writing. When the queue is full, message
// will be silently dropped.
return true;
} }
...@@ -55,6 +55,9 @@ namespace zmq ...@@ -55,6 +55,9 @@ namespace zmq
fq_t fq; fq_t fq;
lb_t lb; lb_t lb;
// If true, curently sent message is being dropped.
bool dropping;
xreq_t (const xreq_t&); xreq_t (const xreq_t&);
void operator = (const xreq_t&); void operator = (const xreq_t&);
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment