From 72a793f78ae6c7b544d4c19530c01e8dfd23ccf5 Mon Sep 17 00:00:00 2001 From: Martin Sustrik Date: Thu, 21 Jul 2011 18:43:50 +0200 Subject: ZMQ_GENERIC renamed to ZMQ_ROUTER Signed-off-by: Martin Sustrik --- include/zmq.h | 2 +- src/Makefile.am | 4 +- src/generic.cpp | 265 ---------------------------------------------------- src/generic.hpp | 108 --------------------- src/router.cpp | 265 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/router.hpp | 107 +++++++++++++++++++++ src/socket_base.cpp | 6 +- 7 files changed, 378 insertions(+), 379 deletions(-) delete mode 100755 src/generic.cpp delete mode 100755 src/generic.hpp create mode 100755 src/router.cpp create mode 100755 src/router.hpp diff --git a/include/zmq.h b/include/zmq.h index 2ba560e..d18e4e5 100644 --- a/include/zmq.h +++ b/include/zmq.h @@ -158,7 +158,7 @@ ZMQ_EXPORT int zmq_term (void *context); #define ZMQ_PUSH 8 #define ZMQ_XPUB 9 #define ZMQ_XSUB 10 -#define ZMQ_GENERIC 13 +#define ZMQ_ROUTER 13 /* Socket options. */ #define ZMQ_AFFINITY 4 diff --git a/src/Makefile.am b/src/Makefile.am index 971ebeb..fb7b010 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,7 +23,6 @@ libzmq_la_SOURCES = \ err.hpp \ fd.hpp \ fq.hpp \ - generic.hpp \ io_object.hpp \ io_thread.hpp \ ip.hpp \ @@ -55,6 +54,7 @@ libzmq_la_SOURCES = \ reaper.hpp \ rep.hpp \ req.hpp \ + router.hpp \ select.hpp \ semaphore.hpp \ session.hpp \ @@ -89,7 +89,6 @@ libzmq_la_SOURCES = \ epoll.cpp \ err.cpp \ fq.cpp \ - generic.cpp \ io_object.cpp \ io_thread.cpp \ ip.cpp \ @@ -113,6 +112,7 @@ libzmq_la_SOURCES = \ reaper.cpp \ pub.cpp \ random.cpp \ + router.cpp \ rep.cpp \ req.cpp \ select.cpp \ diff --git a/src/generic.cpp b/src/generic.cpp deleted file mode 100755 index 9078ce3..0000000 --- a/src/generic.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - Copyright (c) 2007-2011 iMatix Corporation - Copyright (c) 2007-2011 Other 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 "generic.hpp" -#include "pipe.hpp" -#include "wire.hpp" -#include "random.hpp" -#include "likely.hpp" -#include "wire.hpp" -#include "err.hpp" - -zmq::generic_t::generic_t (class ctx_t *parent_, uint32_t tid_) : - socket_base_t (parent_, tid_), - prefetched (false), - more_in (false), - current_out (NULL), - more_out (false), - next_peer_id (generate_random ()) -{ - options.type = ZMQ_GENERIC; - - prefetched_msg.init (); -} - -zmq::generic_t::~generic_t () -{ - zmq_assert (outpipes.empty ()); - prefetched_msg.close (); -} - -void zmq::generic_t::xattach_pipe (pipe_t *pipe_) -{ - zmq_assert (pipe_); - - // Generate a new peer ID. Take care to avoid duplicates. - outpipes_t::iterator it = outpipes.lower_bound (next_peer_id); - if (!outpipes.empty ()) { - while (true) { - if (it == outpipes.end ()) - it = outpipes.begin (); - if (it->first != next_peer_id) - break; - ++next_peer_id; - ++it; - } - } - - // Add the pipe to the map out outbound pipes. - outpipe_t outpipe = {pipe_, true}; - bool ok = outpipes.insert (outpipes_t::value_type ( - next_peer_id, outpipe)).second; - zmq_assert (ok); - - // Add the pipe to the list of inbound pipes. - pipe_->set_pipe_id (next_peer_id); - fq.attach (pipe_); - - // Queue the connection command. - pending_command_t cmd = {1, next_peer_id}; - pending_commands.push_back (cmd); - - // Advance next peer ID so that if new connection is dropped shortly after - // its creation we don't accidentally get two subsequent peers with - // the same ID. - ++next_peer_id; -} - -void zmq::generic_t::xterminated (pipe_t *pipe_) -{ - fq.terminated (pipe_); - - for (outpipes_t::iterator it = outpipes.begin (); - it != outpipes.end (); ++it) { - if (it->second.pipe == pipe_) { - - // Queue the disconnection command. - pending_command_t cmd = {2, it->first}; - pending_commands.push_back (cmd); - - // Remove the pipe. - outpipes.erase (it); - if (pipe_ == current_out) - current_out = NULL; - return; - } - } - zmq_assert (false); -} - -void zmq::generic_t::xread_activated (pipe_t *pipe_) -{ - fq.activated (pipe_); -} - -void zmq::generic_t::xwrite_activated (pipe_t *pipe_) -{ - for (outpipes_t::iterator it = outpipes.begin (); - it != outpipes.end (); ++it) { - if (it->second.pipe == pipe_) { - zmq_assert (!it->second.active); - it->second.active = true; - return; - } - } - zmq_assert (false); -} - -int zmq::generic_t::xsend (msg_t *msg_, int flags_) -{ - // If this is the first part of the message it's the ID of the - // peer to send the message to. - if (!more_out) { - zmq_assert (!current_out); - - // If we have malformed message (prefix with no subsequent message) - // then just silently ignore it. - // TODO: The connections should be killed instead. - if (msg_->flags () & msg_t::label) { - - more_out = true; - - // Find the pipe associated with the peer ID stored in the prefix. - // If there's no such pipe just silently ignore the message. - zmq_assert (msg_->size () == 4); - uint32_t peer_id = get_uint32 ((unsigned char*) msg_->data ()); - outpipes_t::iterator it = outpipes.find (peer_id); - - if (it != outpipes.end ()) { - current_out = it->second.pipe; - msg_t empty; - int rc = empty.init (); - errno_assert (rc == 0); - if (!current_out->check_write (&empty)) { - it->second.active = false; - more_out = false; - current_out = NULL; - } - rc = empty.close (); - errno_assert (rc == 0); - } - } - - int rc = msg_->close (); - errno_assert (rc == 0); - rc = msg_->init (); - errno_assert (rc == 0); - return 0; - } - - // Check whether this is the last part of the message. - more_out = msg_->flags () & (msg_t::more | msg_t::label) ? true : false; - - // Push the message into the pipe. If there's no out pipe, just drop it. - if (current_out) { - bool ok = current_out->write (msg_); - zmq_assert (ok); - if (!more_out) { - current_out->flush (); - current_out = NULL; - } - } - else { - int rc = msg_->close (); - errno_assert (rc == 0); - } - - // Detach the message from the data buffer. - int rc = msg_->init (); - errno_assert (rc == 0); - - return 0; -} - -int zmq::generic_t::xrecv (msg_t *msg_, int flags_) -{ - // If there's a queued command, pass it to the caller. - if (unlikely (!more_in && !pending_commands.empty ())) { - msg_->init_size (5); - unsigned char *data = (unsigned char*) msg_->data (); - put_uint8 (data, pending_commands.front ().cmd); - put_uint32 (data + 1, pending_commands.front ().peer); - msg_->set_flags (msg_t::command); - pending_commands.pop_front (); - return 0; - } - - // If there is a prefetched message, return it. - if (prefetched) { - int rc = msg_->move (prefetched_msg); - errno_assert (rc == 0); - more_in = msg_->flags () & (msg_t::more | msg_t::label) ? true : false; - prefetched = false; - return 0; - } - - // Get next message part. - pipe_t *pipe; - int rc = fq.recvpipe (msg_, flags_, &pipe); - if (rc != 0) - return -1; - - // If we are in the middle of reading a message, just return the next part. - if (more_in) { - more_in = msg_->flags () & (msg_t::more | msg_t::label) ? true : false; - return 0; - } - - // We are at the beginning of a new message. Move the message part we - // have to the prefetched and return the ID of the peer instead. - rc = prefetched_msg.move (*msg_); - errno_assert (rc == 0); - prefetched = true; - rc = msg_->close (); - errno_assert (rc == 0); - rc = msg_->init_size (4); - errno_assert (rc == 0); - put_uint32 ((unsigned char*) msg_->data (), pipe->get_pipe_id ()); - msg_->set_flags (msg_t::label); - return 0; -} - -int zmq::generic_t::rollback (void) -{ - if (current_out) { - current_out->rollback (); - current_out = NULL; - more_out = false; - } - return 0; -} - -bool zmq::generic_t::xhas_in () -{ - if (prefetched) - return true; - return fq.has_in (); -} - -bool zmq::generic_t::xhas_out () -{ - // In theory, GENERIC socket is always ready for writing. Whether actual - // attempt to write succeeds depends on whitch pipe the message is going - // to be routed to. - return true; -} - - - diff --git a/src/generic.hpp b/src/generic.hpp deleted file mode 100755 index 7768333..0000000 --- a/src/generic.hpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - Copyright (c) 2007-2011 iMatix Corporation - Copyright (c) 2007-2011 Other 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 . -*/ - -#ifndef __ZMQ_GENERIC_HPP_INCLUDED__ -#define __ZMQ_GENERIC_HPP_INCLUDED__ - -#include -#include - -#include "socket_base.hpp" -#include "stdint.hpp" -#include "msg.hpp" -#include "fq.hpp" - -namespace zmq -{ - - // TODO: This class uses O(n) scheduling. Rewrite it to use O(1) algorithm. - class generic_t : - public socket_base_t - { - public: - - generic_t (class ctx_t *parent_, uint32_t tid_); - ~generic_t (); - - // Overloads of functions from socket_base_t. - void xattach_pipe (class pipe_t *pipe_); - int xsend (class msg_t *msg_, int flags_); - int xrecv (class msg_t *msg_, int flags_); - bool xhas_in (); - bool xhas_out (); - void xread_activated (class pipe_t *pipe_); - void xwrite_activated (class pipe_t *pipe_); - void xterminated (class pipe_t *pipe_); - - protected: - - // Rollback any message parts that were sent but not yet flushed. - int rollback (); - - private: - - // Fair queueing object for inbound pipes. - fq_t fq; - - // Have we prefetched a message. - bool prefetched; - - // Holds the prefetched message. - msg_t prefetched_msg; - - // If true, more incoming message parts are expected. - bool more_in; - - struct outpipe_t - { - class pipe_t *pipe; - bool active; - }; - - // Outbound pipes indexed by the peer IDs. - typedef std::map outpipes_t; - outpipes_t outpipes; - - // The pipe we are currently writing to. - class pipe_t *current_out; - - // If true, more outgoing message parts are expected. - bool more_out; - - // Peer ID are generated. It's a simple increment and wrap-over - // algorithm. This value is the next ID to use (if not used already). - uint32_t next_peer_id; - - // Commands to be delivered to the user. - struct pending_command_t - { - uint8_t cmd; - uint32_t peer; - }; - typedef std::deque pending_commands_t; - pending_commands_t pending_commands; - - generic_t (const generic_t&); - const generic_t &operator = (const generic_t&); - }; - -} - -#endif diff --git a/src/router.cpp b/src/router.cpp new file mode 100755 index 0000000..3428c87 --- /dev/null +++ b/src/router.cpp @@ -0,0 +1,265 @@ +/* + Copyright (c) 2007-2011 iMatix Corporation + Copyright (c) 2007-2011 Other 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 "router.hpp" +#include "pipe.hpp" +#include "wire.hpp" +#include "random.hpp" +#include "likely.hpp" +#include "wire.hpp" +#include "err.hpp" + +zmq::router_t::router_t (class ctx_t *parent_, uint32_t tid_) : + socket_base_t (parent_, tid_), + prefetched (false), + more_in (false), + current_out (NULL), + more_out (false), + next_peer_id (generate_random ()) +{ + options.type = ZMQ_ROUTER; + + prefetched_msg.init (); +} + +zmq::router_t::~router_t () +{ + zmq_assert (outpipes.empty ()); + prefetched_msg.close (); +} + +void zmq::router_t::xattach_pipe (pipe_t *pipe_) +{ + zmq_assert (pipe_); + + // Generate a new peer ID. Take care to avoid duplicates. + outpipes_t::iterator it = outpipes.lower_bound (next_peer_id); + if (!outpipes.empty ()) { + while (true) { + if (it == outpipes.end ()) + it = outpipes.begin (); + if (it->first != next_peer_id) + break; + ++next_peer_id; + ++it; + } + } + + // Add the pipe to the map out outbound pipes. + outpipe_t outpipe = {pipe_, true}; + bool ok = outpipes.insert (outpipes_t::value_type ( + next_peer_id, outpipe)).second; + zmq_assert (ok); + + // Add the pipe to the list of inbound pipes. + pipe_->set_pipe_id (next_peer_id); + fq.attach (pipe_); + + // Queue the connection command. + pending_command_t cmd = {1, next_peer_id}; + pending_commands.push_back (cmd); + + // Advance next peer ID so that if new connection is dropped shortly after + // its creation we don't accidentally get two subsequent peers with + // the same ID. + ++next_peer_id; +} + +void zmq::router_t::xterminated (pipe_t *pipe_) +{ + fq.terminated (pipe_); + + for (outpipes_t::iterator it = outpipes.begin (); + it != outpipes.end (); ++it) { + if (it->second.pipe == pipe_) { + + // Queue the disconnection command. + pending_command_t cmd = {2, it->first}; + pending_commands.push_back (cmd); + + // Remove the pipe. + outpipes.erase (it); + if (pipe_ == current_out) + current_out = NULL; + return; + } + } + zmq_assert (false); +} + +void zmq::router_t::xread_activated (pipe_t *pipe_) +{ + fq.activated (pipe_); +} + +void zmq::router_t::xwrite_activated (pipe_t *pipe_) +{ + for (outpipes_t::iterator it = outpipes.begin (); + it != outpipes.end (); ++it) { + if (it->second.pipe == pipe_) { + zmq_assert (!it->second.active); + it->second.active = true; + return; + } + } + zmq_assert (false); +} + +int zmq::router_t::xsend (msg_t *msg_, int flags_) +{ + // If this is the first part of the message it's the ID of the + // peer to send the message to. + if (!more_out) { + zmq_assert (!current_out); + + // If we have malformed message (prefix with no subsequent message) + // then just silently ignore it. + // TODO: The connections should be killed instead. + if (msg_->flags () & msg_t::label) { + + more_out = true; + + // Find the pipe associated with the peer ID stored in the prefix. + // If there's no such pipe just silently ignore the message. + zmq_assert (msg_->size () == 4); + uint32_t peer_id = get_uint32 ((unsigned char*) msg_->data ()); + outpipes_t::iterator it = outpipes.find (peer_id); + + if (it != outpipes.end ()) { + current_out = it->second.pipe; + msg_t empty; + int rc = empty.init (); + errno_assert (rc == 0); + if (!current_out->check_write (&empty)) { + it->second.active = false; + more_out = false; + current_out = NULL; + } + rc = empty.close (); + errno_assert (rc == 0); + } + } + + int rc = msg_->close (); + errno_assert (rc == 0); + rc = msg_->init (); + errno_assert (rc == 0); + return 0; + } + + // Check whether this is the last part of the message. + more_out = msg_->flags () & (msg_t::more | msg_t::label) ? true : false; + + // Push the message into the pipe. If there's no out pipe, just drop it. + if (current_out) { + bool ok = current_out->write (msg_); + zmq_assert (ok); + if (!more_out) { + current_out->flush (); + current_out = NULL; + } + } + else { + int rc = msg_->close (); + errno_assert (rc == 0); + } + + // Detach the message from the data buffer. + int rc = msg_->init (); + errno_assert (rc == 0); + + return 0; +} + +int zmq::router_t::xrecv (msg_t *msg_, int flags_) +{ + // If there's a queued command, pass it to the caller. + if (unlikely (!more_in && !pending_commands.empty ())) { + msg_->init_size (5); + unsigned char *data = (unsigned char*) msg_->data (); + put_uint8 (data, pending_commands.front ().cmd); + put_uint32 (data + 1, pending_commands.front ().peer); + msg_->set_flags (msg_t::command); + pending_commands.pop_front (); + return 0; + } + + // If there is a prefetched message, return it. + if (prefetched) { + int rc = msg_->move (prefetched_msg); + errno_assert (rc == 0); + more_in = msg_->flags () & (msg_t::more | msg_t::label) ? true : false; + prefetched = false; + return 0; + } + + // Get next message part. + pipe_t *pipe; + int rc = fq.recvpipe (msg_, flags_, &pipe); + if (rc != 0) + return -1; + + // If we are in the middle of reading a message, just return the next part. + if (more_in) { + more_in = msg_->flags () & (msg_t::more | msg_t::label) ? true : false; + return 0; + } + + // We are at the beginning of a new message. Move the message part we + // have to the prefetched and return the ID of the peer instead. + rc = prefetched_msg.move (*msg_); + errno_assert (rc == 0); + prefetched = true; + rc = msg_->close (); + errno_assert (rc == 0); + rc = msg_->init_size (4); + errno_assert (rc == 0); + put_uint32 ((unsigned char*) msg_->data (), pipe->get_pipe_id ()); + msg_->set_flags (msg_t::label); + return 0; +} + +int zmq::router_t::rollback (void) +{ + if (current_out) { + current_out->rollback (); + current_out = NULL; + more_out = false; + } + return 0; +} + +bool zmq::router_t::xhas_in () +{ + if (prefetched) + return true; + return fq.has_in (); +} + +bool zmq::router_t::xhas_out () +{ + // In theory, GENERIC socket is always ready for writing. Whether actual + // attempt to write succeeds depends on whitch pipe the message is going + // to be routed to. + return true; +} + + + diff --git a/src/router.hpp b/src/router.hpp new file mode 100755 index 0000000..aeac865 --- /dev/null +++ b/src/router.hpp @@ -0,0 +1,107 @@ +/* + Copyright (c) 2007-2011 iMatix Corporation + Copyright (c) 2007-2011 Other 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 . +*/ + +#ifndef __ZMQ_ROUTER_HPP_INCLUDED__ +#define __ZMQ_ROUTER_HPP_INCLUDED__ + +#include +#include + +#include "socket_base.hpp" +#include "stdint.hpp" +#include "msg.hpp" +#include "fq.hpp" + +namespace zmq +{ + + class router_t : + public socket_base_t + { + public: + + router_t (class ctx_t *parent_, uint32_t tid_); + ~router_t (); + + // Overloads of functions from socket_base_t. + void xattach_pipe (class pipe_t *pipe_); + int xsend (class msg_t *msg_, int flags_); + int xrecv (class msg_t *msg_, int flags_); + bool xhas_in (); + bool xhas_out (); + void xread_activated (class pipe_t *pipe_); + void xwrite_activated (class pipe_t *pipe_); + void xterminated (class pipe_t *pipe_); + + protected: + + // Rollback any message parts that were sent but not yet flushed. + int rollback (); + + private: + + // Fair queueing object for inbound pipes. + fq_t fq; + + // Have we prefetched a message. + bool prefetched; + + // Holds the prefetched message. + msg_t prefetched_msg; + + // If true, more incoming message parts are expected. + bool more_in; + + struct outpipe_t + { + class pipe_t *pipe; + bool active; + }; + + // Outbound pipes indexed by the peer IDs. + typedef std::map outpipes_t; + outpipes_t outpipes; + + // The pipe we are currently writing to. + class pipe_t *current_out; + + // If true, more outgoing message parts are expected. + bool more_out; + + // Peer ID are generated. It's a simple increment and wrap-over + // algorithm. This value is the next ID to use (if not used already). + uint32_t next_peer_id; + + // Commands to be delivered to the user. + struct pending_command_t + { + uint8_t cmd; + uint32_t peer; + }; + typedef std::deque pending_commands_t; + pending_commands_t pending_commands; + + router_t (const router_t&); + const router_t &operator = (const router_t&); + }; + +} + +#endif diff --git a/src/socket_base.cpp b/src/socket_base.cpp index 2513f81..92715b1 100644 --- a/src/socket_base.cpp +++ b/src/socket_base.cpp @@ -58,7 +58,7 @@ #include "xrep.hpp" #include "xpub.hpp" #include "xsub.hpp" -#include "generic.hpp" +#include "router.hpp" bool zmq::socket_base_t::check_tag () { @@ -104,8 +104,8 @@ zmq::socket_base_t *zmq::socket_base_t::create (int type_, class ctx_t *parent_, case ZMQ_XSUB: s = new (std::nothrow) xsub_t (parent_, tid_); break; - case ZMQ_GENERIC: - s = new (std::nothrow) generic_t (parent_, tid_); + case ZMQ_ROUTER: + s = new (std::nothrow) router_t (parent_, tid_); break; default: errno = EINVAL; -- cgit v1.2.3