mirror of
				https://github.com/zeromq/libzmq.git
				synced 2025-10-30 05:29:43 +01:00 
			
		
		
		
	Merge pull request #3142 from sigiesec/analyze
Remove duplication between stream_t and router_t
This commit is contained in:
		| @@ -63,7 +63,7 @@ void zmq::mechanism_t::peer_routing_id (msg_t *msg_) | |||||||
| void zmq::mechanism_t::set_user_id (const void *data_, size_t size_) | void zmq::mechanism_t::set_user_id (const void *data_, size_t size_) | ||||||
| { | { | ||||||
|     _user_id.set (static_cast<const unsigned char *> (data_), size_); |     _user_id.set (static_cast<const unsigned char *> (data_), size_); | ||||||
|     zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE ( |     _zap_properties.ZMQ_MAP_INSERT_OR_EMPLACE ( | ||||||
|       std::string (ZMQ_MSG_PROPERTY_USER_ID), |       std::string (ZMQ_MSG_PROPERTY_USER_ID), | ||||||
|       std::string (reinterpret_cast<const char *> (data_), size_)); |       std::string (reinterpret_cast<const char *> (data_), size_)); | ||||||
| } | } | ||||||
| @@ -268,7 +268,7 @@ int zmq::mechanism_t::parse_metadata (const unsigned char *ptr_, | |||||||
|             if (rc == -1) |             if (rc == -1) | ||||||
|                 return -1; |                 return -1; | ||||||
|         } |         } | ||||||
|         (zap_flag_ ? zap_properties : zmtp_properties) |         (zap_flag_ ? _zap_properties : _zmtp_properties) | ||||||
|           .ZMQ_MAP_INSERT_OR_EMPLACE ( |           .ZMQ_MAP_INSERT_OR_EMPLACE ( | ||||||
|             name, |             name, | ||||||
|             std::string (reinterpret_cast<const char *> (value), value_length)); |             std::string (reinterpret_cast<const char *> (value), value_length)); | ||||||
|   | |||||||
| @@ -81,9 +81,12 @@ class mechanism_t | |||||||
|  |  | ||||||
|     const blob_t &get_user_id () const; |     const blob_t &get_user_id () const; | ||||||
|  |  | ||||||
|     const metadata_t::dict_t &get_zmtp_properties () { return zmtp_properties; } |     const metadata_t::dict_t &get_zmtp_properties () | ||||||
|  |     { | ||||||
|  |         return _zmtp_properties; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     const metadata_t::dict_t &get_zap_properties () { return zap_properties; } |     const metadata_t::dict_t &get_zap_properties () { return _zap_properties; } | ||||||
|  |  | ||||||
|   protected: |   protected: | ||||||
|     //  Only used to identify the socket for the Socket-Type |     //  Only used to identify the socket for the Socket-Type | ||||||
| @@ -123,15 +126,15 @@ class mechanism_t | |||||||
|     virtual int |     virtual int | ||||||
|     property (const std::string &name_, const void *value_, size_t length_); |     property (const std::string &name_, const void *value_, size_t length_); | ||||||
|  |  | ||||||
|     //  Properties received from ZMTP peer. |  | ||||||
|     metadata_t::dict_t zmtp_properties; |  | ||||||
|  |  | ||||||
|     //  Properties received from ZAP server. |  | ||||||
|     metadata_t::dict_t zap_properties; |  | ||||||
|  |  | ||||||
|     const options_t options; |     const options_t options; | ||||||
|  |  | ||||||
|   private: |   private: | ||||||
|  |     //  Properties received from ZMTP peer. | ||||||
|  |     metadata_t::dict_t _zmtp_properties; | ||||||
|  |  | ||||||
|  |     //  Properties received from ZAP server. | ||||||
|  |     metadata_t::dict_t _zap_properties; | ||||||
|  |  | ||||||
|     blob_t _routing_id; |     blob_t _routing_id; | ||||||
|  |  | ||||||
|     blob_t _user_id; |     blob_t _user_id; | ||||||
|   | |||||||
							
								
								
									
										112
									
								
								src/router.cpp
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								src/router.cpp
									
									
									
									
									
								
							| @@ -37,7 +37,7 @@ | |||||||
| #include "err.hpp" | #include "err.hpp" | ||||||
|  |  | ||||||
| zmq::router_t::router_t (class ctx_t *parent_, uint32_t tid_, int sid_) : | zmq::router_t::router_t (class ctx_t *parent_, uint32_t tid_, int sid_) : | ||||||
|     socket_base_t (parent_, tid_, sid_), |     routing_socket_base_t (parent_, tid_, sid_), | ||||||
|     _prefetched (false), |     _prefetched (false), | ||||||
|     _routing_id_sent (false), |     _routing_id_sent (false), | ||||||
|     _current_in (NULL), |     _current_in (NULL), | ||||||
| @@ -63,8 +63,6 @@ zmq::router_t::router_t (class ctx_t *parent_, uint32_t tid_, int sid_) : | |||||||
| zmq::router_t::~router_t () | zmq::router_t::~router_t () | ||||||
| { | { | ||||||
|     zmq_assert (_anonymous_pipes.empty ()); |     zmq_assert (_anonymous_pipes.empty ()); | ||||||
|     ; |  | ||||||
|     zmq_assert (_out_pipes.empty ()); |  | ||||||
|     _prefetched_id.close (); |     _prefetched_id.close (); | ||||||
|     _prefetched_msg.close (); |     _prefetched_msg.close (); | ||||||
| } | } | ||||||
| @@ -99,21 +97,12 @@ int zmq::router_t::xsetsockopt (int option_, | |||||||
|                                 const void *optval_, |                                 const void *optval_, | ||||||
|                                 size_t optvallen_) |                                 size_t optvallen_) | ||||||
| { | { | ||||||
|     bool is_int = (optvallen_ == sizeof (int)); |     const bool is_int = (optvallen_ == sizeof (int)); | ||||||
|     int value = 0; |     int value = 0; | ||||||
|     if (is_int) |     if (is_int) | ||||||
|         memcpy (&value, optval_, sizeof (int)); |         memcpy (&value, optval_, sizeof (int)); | ||||||
|  |  | ||||||
|     switch (option_) { |     switch (option_) { | ||||||
|         case ZMQ_CONNECT_ROUTING_ID: |  | ||||||
|             // TODO why isn't it possible to set an empty connect_routing_id |  | ||||||
|             //   (which is the default value) |  | ||||||
|             if (optval_ && optvallen_) { |  | ||||||
|                 connect_routing_id.assign ((char *) optval_, optvallen_); |  | ||||||
|                 return 0; |  | ||||||
|             } |  | ||||||
|             break; |  | ||||||
|  |  | ||||||
|         case ZMQ_ROUTER_RAW: |         case ZMQ_ROUTER_RAW: | ||||||
|             if (is_int && value >= 0) { |             if (is_int && value >= 0) { | ||||||
|                 _raw_socket = (value != 0); |                 _raw_socket = (value != 0); | ||||||
| @@ -147,7 +136,8 @@ int zmq::router_t::xsetsockopt (int option_, | |||||||
|             break; |             break; | ||||||
|  |  | ||||||
|         default: |         default: | ||||||
|             break; |             return routing_socket_base_t::xsetsockopt (option_, optval_, | ||||||
|  |                                                        optvallen_); | ||||||
|     } |     } | ||||||
|     errno = EINVAL; |     errno = EINVAL; | ||||||
|     return -1; |     return -1; | ||||||
| @@ -160,9 +150,7 @@ void zmq::router_t::xpipe_terminated (pipe_t *pipe_) | |||||||
|     if (it != _anonymous_pipes.end ()) |     if (it != _anonymous_pipes.end ()) | ||||||
|         _anonymous_pipes.erase (it); |         _anonymous_pipes.erase (it); | ||||||
|     else { |     else { | ||||||
|         outpipes_t::iterator iter = _out_pipes.find (pipe_->get_routing_id ()); |         erase_out_pipe (pipe_); | ||||||
|         zmq_assert (iter != _out_pipes.end ()); |  | ||||||
|         _out_pipes.erase (iter); |  | ||||||
|         _fq.pipe_terminated (pipe_); |         _fq.pipe_terminated (pipe_); | ||||||
|         pipe_->rollback (); |         pipe_->rollback (); | ||||||
|         if (pipe_ == _current_out) |         if (pipe_ == _current_out) | ||||||
| @@ -184,18 +172,6 @@ void zmq::router_t::xread_activated (pipe_t *pipe_) | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| void zmq::router_t::xwrite_activated (pipe_t *pipe_) |  | ||||||
| { |  | ||||||
|     outpipes_t::iterator it; |  | ||||||
|     for (it = _out_pipes.begin (); it != _out_pipes.end (); ++it) |  | ||||||
|         if (it->second.pipe == pipe_) |  | ||||||
|             break; |  | ||||||
|  |  | ||||||
|     zmq_assert (it != _out_pipes.end ()); |  | ||||||
|     zmq_assert (!it->second.active); |  | ||||||
|     it->second.active = true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int zmq::router_t::xsend (msg_t *msg_) | int zmq::router_t::xsend (msg_t *msg_) | ||||||
| { | { | ||||||
|     //  If this is the first part of the message it's the ID of the |     //  If this is the first part of the message it's the ID of the | ||||||
| @@ -211,19 +187,19 @@ int zmq::router_t::xsend (msg_t *msg_) | |||||||
|  |  | ||||||
|             //  Find the pipe associated with the routing id stored in the prefix. |             //  Find the pipe associated with the routing id stored in the prefix. | ||||||
|             //  If there's no such pipe just silently ignore the message, unless |             //  If there's no such pipe just silently ignore the message, unless | ||||||
|             //  router_mandatory is set. |             //  router_mandatory is set.            ; | ||||||
|             blob_t routing_id (static_cast<unsigned char *> (msg_->data ()), |             out_pipe_t *out_pipe = lookup_out_pipe ( | ||||||
|                                msg_->size (), zmq::reference_tag_t ()); |               blob_t (static_cast<unsigned char *> (msg_->data ()), | ||||||
|             outpipes_t::iterator it = _out_pipes.find (routing_id); |                       msg_->size (), zmq::reference_tag_t ())); | ||||||
|  |  | ||||||
|             if (it != _out_pipes.end ()) { |             if (out_pipe) { | ||||||
|                 _current_out = it->second.pipe; |                 _current_out = out_pipe->pipe; | ||||||
|  |  | ||||||
|                 // Check whether pipe is closed or not |                 // Check whether pipe is closed or not | ||||||
|                 if (!_current_out->check_write ()) { |                 if (!_current_out->check_write ()) { | ||||||
|                     // Check whether pipe is full or not |                     // Check whether pipe is full or not | ||||||
|                     bool pipe_full = !_current_out->check_hwm (); |                     bool pipe_full = !_current_out->check_hwm (); | ||||||
|                     it->second.active = false; |                     out_pipe->active = false; | ||||||
|                     _current_out = NULL; |                     _current_out = NULL; | ||||||
|  |  | ||||||
|                     if (_mandatory) { |                     if (_mandatory) { | ||||||
| @@ -420,6 +396,11 @@ bool zmq::router_t::xhas_in () | |||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | static bool check_pipe_hwm (const zmq::pipe_t &pipe) | ||||||
|  | { | ||||||
|  |     return pipe.check_hwm (); | ||||||
|  | } | ||||||
|  |  | ||||||
| bool zmq::router_t::xhas_out () | bool zmq::router_t::xhas_out () | ||||||
| { | { | ||||||
|     //  In theory, ROUTER socket is always ready for writing (except when |     //  In theory, ROUTER socket is always ready for writing (except when | ||||||
| @@ -429,12 +410,7 @@ bool zmq::router_t::xhas_out () | |||||||
|     if (!_mandatory) |     if (!_mandatory) | ||||||
|         return true; |         return true; | ||||||
|  |  | ||||||
|     bool has_out = false; |     return any_of_out_pipes (check_pipe_hwm); | ||||||
|     outpipes_t::iterator it; |  | ||||||
|     for (it = _out_pipes.begin (); it != _out_pipes.end (); ++it) |  | ||||||
|         has_out |= it->second.pipe->check_hwm (); |  | ||||||
|  |  | ||||||
|     return has_out; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| const zmq::blob_t &zmq::router_t::get_credential () const | const zmq::blob_t &zmq::router_t::get_credential () const | ||||||
| @@ -448,14 +424,13 @@ int zmq::router_t::get_peer_state (const void *routing_id_, | |||||||
|     int res = 0; |     int res = 0; | ||||||
|  |  | ||||||
|     blob_t routing_id_blob ((unsigned char *) routing_id_, routing_id_size_); |     blob_t routing_id_blob ((unsigned char *) routing_id_, routing_id_size_); | ||||||
|     outpipes_t::const_iterator it = _out_pipes.find (routing_id_blob); |     const out_pipe_t *out_pipe = lookup_out_pipe (routing_id_blob); | ||||||
|     if (it == _out_pipes.end ()) { |     if (!out_pipe) { | ||||||
|         errno = EHOSTUNREACH; |         errno = EHOSTUNREACH; | ||||||
|         return -1; |         return -1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     const out_pipe_t &outpipe = it->second; |     if (out_pipe->pipe->check_hwm ()) | ||||||
|     if (outpipe.pipe->check_hwm ()) |  | ||||||
|         res |= ZMQ_POLLOUT; |         res |= ZMQ_POLLOUT; | ||||||
|  |  | ||||||
|     /** \todo does it make any sense to check the inpipe as well? */ |     /** \todo does it make any sense to check the inpipe as well? */ | ||||||
| @@ -466,16 +441,15 @@ int zmq::router_t::get_peer_state (const void *routing_id_, | |||||||
| bool zmq::router_t::identify_peer (pipe_t *pipe_) | bool zmq::router_t::identify_peer (pipe_t *pipe_) | ||||||
| { | { | ||||||
|     msg_t msg; |     msg_t msg; | ||||||
|     bool ok; |  | ||||||
|     blob_t routing_id; |     blob_t routing_id; | ||||||
|  |  | ||||||
|     if (connect_routing_id.length ()) { |     const std::string connect_routing_id = extract_connect_routing_id (); | ||||||
|         routing_id.set ((unsigned char *) connect_routing_id.c_str (), |     if (!connect_routing_id.empty ()) { | ||||||
|                         connect_routing_id.length ()); |         routing_id.set ( | ||||||
|         connect_routing_id.clear (); |           reinterpret_cast<const unsigned char *> (connect_routing_id.c_str ()), | ||||||
|         outpipes_t::iterator it = _out_pipes.find (routing_id); |           connect_routing_id.length ()); | ||||||
|         if (it != _out_pipes.end ()) |         //  Not allowed to duplicate an existing rid | ||||||
|             zmq_assert (false); //  Not allowed to duplicate an existing rid |         zmq_assert (!has_out_pipe (routing_id)); | ||||||
|     } else if ( |     } else if ( | ||||||
|       options |       options | ||||||
|         .raw_socket) { //  Always assign an integral routing id for raw-socket |         .raw_socket) { //  Always assign an integral routing id for raw-socket | ||||||
| @@ -486,7 +460,7 @@ bool zmq::router_t::identify_peer (pipe_t *pipe_) | |||||||
|     } else if (!options.raw_socket) { |     } else if (!options.raw_socket) { | ||||||
|         //  Pick up handshake cases and also case where next integral routing id is set |         //  Pick up handshake cases and also case where next integral routing id is set | ||||||
|         msg.init (); |         msg.init (); | ||||||
|         ok = pipe_->read (&msg); |         bool ok = pipe_->read (&msg); | ||||||
|         if (!ok) |         if (!ok) | ||||||
|             return false; |             return false; | ||||||
|  |  | ||||||
| @@ -500,10 +474,13 @@ bool zmq::router_t::identify_peer (pipe_t *pipe_) | |||||||
|         } else { |         } else { | ||||||
|             routing_id.set (static_cast<unsigned char *> (msg.data ()), |             routing_id.set (static_cast<unsigned char *> (msg.data ()), | ||||||
|                             msg.size ()); |                             msg.size ()); | ||||||
|             outpipes_t::iterator it = _out_pipes.find (routing_id); |  | ||||||
|             msg.close (); |             msg.close (); | ||||||
|  |  | ||||||
|             if (it != _out_pipes.end ()) { |             //  Try to remove an existing routing id entry to allow the new | ||||||
|  |             //  connection to take the routing id. | ||||||
|  |             out_pipe_t existing_outpipe = try_erase_out_pipe (routing_id); | ||||||
|  |  | ||||||
|  |             if (existing_outpipe.pipe) { | ||||||
|                 if (!_handover) |                 if (!_handover) | ||||||
|                     //  Ignore peers with duplicate ID |                     //  Ignore peers with duplicate ID | ||||||
|                     return false; |                     return false; | ||||||
| @@ -516,19 +493,10 @@ bool zmq::router_t::identify_peer (pipe_t *pipe_) | |||||||
|                 put_uint32 (buf + 1, _next_integral_routing_id++); |                 put_uint32 (buf + 1, _next_integral_routing_id++); | ||||||
|                 blob_t new_routing_id (buf, sizeof buf); |                 blob_t new_routing_id (buf, sizeof buf); | ||||||
|  |  | ||||||
|                 it->second.pipe->set_router_socket_routing_id (new_routing_id); |                 existing_outpipe.pipe->set_router_socket_routing_id ( | ||||||
|                 out_pipe_t existing_outpipe = {it->second.pipe, |                   new_routing_id); | ||||||
|                                                it->second.active}; |  | ||||||
|  |  | ||||||
|                 ok = _out_pipes |                 add_out_pipe (ZMQ_MOVE (new_routing_id), existing_outpipe.pipe); | ||||||
|                        .ZMQ_MAP_INSERT_OR_EMPLACE (ZMQ_MOVE (new_routing_id), |  | ||||||
|                                                    existing_outpipe) |  | ||||||
|                        .second; |  | ||||||
|                 zmq_assert (ok); |  | ||||||
|  |  | ||||||
|                 //  Remove the existing routing id entry to allow the new |  | ||||||
|                 //  connection to take the routing id. |  | ||||||
|                 _out_pipes.erase (it); |  | ||||||
|  |  | ||||||
|                 if (existing_outpipe.pipe == _current_in) |                 if (existing_outpipe.pipe == _current_in) | ||||||
|                     _terminate_current_in = true; |                     _terminate_current_in = true; | ||||||
| @@ -539,11 +507,7 @@ bool zmq::router_t::identify_peer (pipe_t *pipe_) | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     pipe_->set_router_socket_routing_id (routing_id); |     pipe_->set_router_socket_routing_id (routing_id); | ||||||
|     //  Add the record into output pipes lookup table |     add_out_pipe (ZMQ_MOVE (routing_id), pipe_); | ||||||
|     out_pipe_t outpipe = {pipe_, true}; |  | ||||||
|     ok = _out_pipes.ZMQ_MAP_INSERT_OR_EMPLACE (ZMQ_MOVE (routing_id), outpipe) |  | ||||||
|            .second; |  | ||||||
|     zmq_assert (ok); |  | ||||||
|  |  | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -45,7 +45,7 @@ class ctx_t; | |||||||
| class pipe_t; | class pipe_t; | ||||||
|  |  | ||||||
| //  TODO: This class uses O(n) scheduling. Rewrite it to use O(1) algorithm. | //  TODO: This class uses O(n) scheduling. Rewrite it to use O(1) algorithm. | ||||||
| class router_t : public socket_base_t | class router_t : public routing_socket_base_t | ||||||
| { | { | ||||||
|   public: |   public: | ||||||
|     router_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_); |     router_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_); | ||||||
| @@ -59,7 +59,6 @@ class router_t : public socket_base_t | |||||||
|     bool xhas_in (); |     bool xhas_in (); | ||||||
|     bool xhas_out (); |     bool xhas_out (); | ||||||
|     void xread_activated (zmq::pipe_t *pipe_); |     void xread_activated (zmq::pipe_t *pipe_); | ||||||
|     void xwrite_activated (zmq::pipe_t *pipe_); |  | ||||||
|     void xpipe_terminated (zmq::pipe_t *pipe_); |     void xpipe_terminated (zmq::pipe_t *pipe_); | ||||||
|     int get_peer_state (const void *identity_, size_t identity_size_) const; |     int get_peer_state (const void *identity_, size_t identity_size_) const; | ||||||
|  |  | ||||||
| @@ -97,19 +96,9 @@ class router_t : public socket_base_t | |||||||
|     //  If true, more incoming message parts are expected. |     //  If true, more incoming message parts are expected. | ||||||
|     bool _more_in; |     bool _more_in; | ||||||
|  |  | ||||||
|     struct out_pipe_t |  | ||||||
|     { |  | ||||||
|         zmq::pipe_t *pipe; |  | ||||||
|         bool active; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     //  We keep a set of pipes that have not been identified yet. |     //  We keep a set of pipes that have not been identified yet. | ||||||
|     std::set<pipe_t *> _anonymous_pipes; |     std::set<pipe_t *> _anonymous_pipes; | ||||||
|  |  | ||||||
|     //  Outbound pipes indexed by the peer IDs. |  | ||||||
|     typedef std::map<blob_t, out_pipe_t> outpipes_t; |  | ||||||
|     outpipes_t _out_pipes; |  | ||||||
|  |  | ||||||
|     //  The pipe we are currently writing to. |     //  The pipe we are currently writing to. | ||||||
|     zmq::pipe_t *_current_out; |     zmq::pipe_t *_current_out; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1762,3 +1762,102 @@ void zmq::socket_base_t::stop_monitor (bool send_monitor_stopped_event_) | |||||||
|         _monitor_events = 0; |         _monitor_events = 0; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | zmq::routing_socket_base_t::routing_socket_base_t (class ctx_t *parent_, | ||||||
|  |                                                    uint32_t tid_, | ||||||
|  |                                                    int sid_) : | ||||||
|  |     socket_base_t (parent_, tid_, sid_) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | zmq::routing_socket_base_t::~routing_socket_base_t () | ||||||
|  | { | ||||||
|  |     zmq_assert (_out_pipes.empty ()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int zmq::routing_socket_base_t::xsetsockopt (int option_, | ||||||
|  |                                              const void *optval_, | ||||||
|  |                                              size_t optvallen_) | ||||||
|  | { | ||||||
|  |     switch (option_) { | ||||||
|  |         case ZMQ_CONNECT_ROUTING_ID: | ||||||
|  |             // TODO why isn't it possible to set an empty connect_routing_id | ||||||
|  |             //   (which is the default value) | ||||||
|  |             if (optval_ && optvallen_) { | ||||||
|  |                 _connect_routing_id.assign (static_cast<const char *> (optval_), | ||||||
|  |                                             optvallen_); | ||||||
|  |                 return 0; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |     } | ||||||
|  |     errno = EINVAL; | ||||||
|  |     return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void zmq::routing_socket_base_t::xwrite_activated (pipe_t *pipe_) | ||||||
|  | { | ||||||
|  |     out_pipes_t::iterator it; | ||||||
|  |     for (it = _out_pipes.begin (); it != _out_pipes.end (); ++it) | ||||||
|  |         if (it->second.pipe == pipe_) | ||||||
|  |             break; | ||||||
|  |  | ||||||
|  |     zmq_assert (it != _out_pipes.end ()); | ||||||
|  |     zmq_assert (!it->second.active); | ||||||
|  |     it->second.active = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | std::string zmq::routing_socket_base_t::extract_connect_routing_id () | ||||||
|  | { | ||||||
|  |     std::string res = ZMQ_MOVE (_connect_routing_id); | ||||||
|  |     _connect_routing_id.clear (); | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void zmq::routing_socket_base_t::add_out_pipe (blob_t routing_id, pipe_t *pipe_) | ||||||
|  | { | ||||||
|  |     //  Add the record into output pipes lookup table | ||||||
|  |     const out_pipe_t outpipe = {pipe_, true}; | ||||||
|  |     const bool ok = | ||||||
|  |       _out_pipes.ZMQ_MAP_INSERT_OR_EMPLACE (ZMQ_MOVE (routing_id), outpipe) | ||||||
|  |         .second; | ||||||
|  |     zmq_assert (ok); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool zmq::routing_socket_base_t::has_out_pipe (const blob_t &routing_id) const | ||||||
|  | { | ||||||
|  |     return 0 != _out_pipes.count (routing_id); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | zmq::routing_socket_base_t::out_pipe_t * | ||||||
|  | zmq::routing_socket_base_t::lookup_out_pipe (const blob_t &routing_id) | ||||||
|  | { | ||||||
|  |     // TODO we could probably avoid constructor a temporary blob_t to call this function | ||||||
|  |     out_pipes_t::iterator it = _out_pipes.find (routing_id); | ||||||
|  |     return it == _out_pipes.end () ? NULL : &it->second; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const zmq::routing_socket_base_t::out_pipe_t * | ||||||
|  | zmq::routing_socket_base_t::lookup_out_pipe (const blob_t &routing_id) const | ||||||
|  | { | ||||||
|  |     // TODO we could probably avoid constructor a temporary blob_t to call this function | ||||||
|  |     out_pipes_t::const_iterator it = _out_pipes.find (routing_id); | ||||||
|  |     return it == _out_pipes.end () ? NULL : &it->second; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void zmq::routing_socket_base_t::erase_out_pipe (pipe_t *pipe_) | ||||||
|  | { | ||||||
|  |     const size_t erased = _out_pipes.erase (pipe_->get_routing_id ()); | ||||||
|  |     zmq_assert (erased); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | zmq::routing_socket_base_t::out_pipe_t | ||||||
|  | zmq::routing_socket_base_t::try_erase_out_pipe (const blob_t &routing_id) | ||||||
|  | { | ||||||
|  |     const out_pipes_t::iterator it = _out_pipes.find (routing_id); | ||||||
|  |     out_pipe_t res = {NULL, false}; | ||||||
|  |     if (it != _out_pipes.end ()) { | ||||||
|  |         res = it->second; | ||||||
|  |         _out_pipes.erase (it); | ||||||
|  |     } | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|   | |||||||
| @@ -184,9 +184,6 @@ class socket_base_t : public own_t, | |||||||
|     //  Delay actual destruction of the socket. |     //  Delay actual destruction of the socket. | ||||||
|     void process_destroy (); |     void process_destroy (); | ||||||
|  |  | ||||||
|     // Next assigned name on a zmq_connect() call used by ROUTER and STREAM socket types |  | ||||||
|     std::string connect_routing_id; |  | ||||||
|  |  | ||||||
|   private: |   private: | ||||||
|     // test if event should be sent and then dispatch it |     // test if event should be sent and then dispatch it | ||||||
|     void event (const std::string &addr_, intptr_t fd_, int type_); |     void event (const std::string &addr_, intptr_t fd_, int type_); | ||||||
| @@ -300,6 +297,53 @@ class socket_base_t : public own_t, | |||||||
|     socket_base_t (const socket_base_t &); |     socket_base_t (const socket_base_t &); | ||||||
|     const socket_base_t &operator= (const socket_base_t &); |     const socket_base_t &operator= (const socket_base_t &); | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | class routing_socket_base_t : public socket_base_t | ||||||
|  | { | ||||||
|  |   protected: | ||||||
|  |     routing_socket_base_t (class ctx_t *parent_, uint32_t tid_, int sid_); | ||||||
|  |     ~routing_socket_base_t (); | ||||||
|  |  | ||||||
|  |     // methods from socket_base_t | ||||||
|  |     virtual int | ||||||
|  |     xsetsockopt (int option_, const void *optval_, size_t optvallen_); | ||||||
|  |     virtual void xwrite_activated (pipe_t *pipe_); | ||||||
|  |  | ||||||
|  |     // own methods | ||||||
|  |     std::string extract_connect_routing_id (); | ||||||
|  |  | ||||||
|  |     struct out_pipe_t | ||||||
|  |     { | ||||||
|  |         pipe_t *pipe; | ||||||
|  |         bool active; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     void add_out_pipe (blob_t routing_id, pipe_t *pipe_); | ||||||
|  |     bool has_out_pipe (const blob_t &routing_id) const; | ||||||
|  |     out_pipe_t *lookup_out_pipe (const blob_t &routing_id); | ||||||
|  |     const out_pipe_t *lookup_out_pipe (const blob_t &routing_id) const; | ||||||
|  |     void erase_out_pipe (pipe_t *pipe_); | ||||||
|  |     out_pipe_t try_erase_out_pipe (const blob_t &routing_id); | ||||||
|  |     template <typename Func> bool any_of_out_pipes (Func func) | ||||||
|  |     { | ||||||
|  |         bool res = false; | ||||||
|  |         for (out_pipes_t::iterator it = _out_pipes.begin (); | ||||||
|  |              it != _out_pipes.end (); ++it) { | ||||||
|  |             if (res |= func (*it->second.pipe)) | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return res; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |   private: | ||||||
|  |     //  Outbound pipes indexed by the peer IDs. | ||||||
|  |     typedef std::map<blob_t, out_pipe_t> out_pipes_t; | ||||||
|  |     out_pipes_t _out_pipes; | ||||||
|  |  | ||||||
|  |     // Next assigned name on a zmq_connect() call used by ROUTER and STREAM socket types | ||||||
|  |     std::string _connect_routing_id; | ||||||
|  | }; | ||||||
| } | } | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -37,7 +37,7 @@ | |||||||
| #include "err.hpp" | #include "err.hpp" | ||||||
|  |  | ||||||
| zmq::stream_t::stream_t (class ctx_t *parent_, uint32_t tid_, int sid_) : | zmq::stream_t::stream_t (class ctx_t *parent_, uint32_t tid_, int sid_) : | ||||||
|     socket_base_t (parent_, tid_, sid_), |     routing_socket_base_t (parent_, tid_, sid_), | ||||||
|     _prefetched (false), |     _prefetched (false), | ||||||
|     _routing_id_sent (false), |     _routing_id_sent (false), | ||||||
|     _current_out (NULL), |     _current_out (NULL), | ||||||
| @@ -53,7 +53,6 @@ zmq::stream_t::stream_t (class ctx_t *parent_, uint32_t tid_, int sid_) : | |||||||
|  |  | ||||||
| zmq::stream_t::~stream_t () | zmq::stream_t::~stream_t () | ||||||
| { | { | ||||||
|     zmq_assert (_outpipes.empty ()); |  | ||||||
|     _prefetched_routing_id.close (); |     _prefetched_routing_id.close (); | ||||||
|     _prefetched_msg.close (); |     _prefetched_msg.close (); | ||||||
| } | } | ||||||
| @@ -70,10 +69,10 @@ void zmq::stream_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_) | |||||||
|  |  | ||||||
| void zmq::stream_t::xpipe_terminated (pipe_t *pipe_) | void zmq::stream_t::xpipe_terminated (pipe_t *pipe_) | ||||||
| { | { | ||||||
|     outpipes_t::iterator it = _outpipes.find (pipe_->get_routing_id ()); |     erase_out_pipe (pipe_); | ||||||
|     zmq_assert (it != _outpipes.end ()); |  | ||||||
|     _outpipes.erase (it); |  | ||||||
|     _fq.pipe_terminated (pipe_); |     _fq.pipe_terminated (pipe_); | ||||||
|  |     // TODO router_t calls pipe_->rollback() here; should this be done here as | ||||||
|  |     // well? then xpipe_terminated could be pulled up to routing_socket_base_t | ||||||
|     if (pipe_ == _current_out) |     if (pipe_ == _current_out) | ||||||
|         _current_out = NULL; |         _current_out = NULL; | ||||||
| } | } | ||||||
| @@ -83,18 +82,6 @@ void zmq::stream_t::xread_activated (pipe_t *pipe_) | |||||||
|     _fq.activated (pipe_); |     _fq.activated (pipe_); | ||||||
| } | } | ||||||
|  |  | ||||||
| void zmq::stream_t::xwrite_activated (pipe_t *pipe_) |  | ||||||
| { |  | ||||||
|     outpipes_t::iterator it; |  | ||||||
|     for (it = _outpipes.begin (); it != _outpipes.end (); ++it) |  | ||||||
|         if (it->second.pipe == pipe_) |  | ||||||
|             break; |  | ||||||
|  |  | ||||||
|     zmq_assert (it != _outpipes.end ()); |  | ||||||
|     zmq_assert (!it->second.active); |  | ||||||
|     it->second.active = true; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| int zmq::stream_t::xsend (msg_t *msg_) | int zmq::stream_t::xsend (msg_t *msg_) | ||||||
| { | { | ||||||
|     //  If this is the first part of the message it's the ID of the |     //  If this is the first part of the message it's the ID of the | ||||||
| @@ -108,14 +95,15 @@ int zmq::stream_t::xsend (msg_t *msg_) | |||||||
|         if (msg_->flags () & msg_t::more) { |         if (msg_->flags () & msg_t::more) { | ||||||
|             //  Find the pipe associated with the routing id stored in the prefix. |             //  Find the pipe associated with the routing id stored in the prefix. | ||||||
|             //  If there's no such pipe return an error |             //  If there's no such pipe return an error | ||||||
|             blob_t routing_id (static_cast<unsigned char *> (msg_->data ()), |  | ||||||
|                                msg_->size ()); |  | ||||||
|             outpipes_t::iterator it = _outpipes.find (routing_id); |  | ||||||
|  |  | ||||||
|             if (it != _outpipes.end ()) { |             out_pipe_t *out_pipe = lookup_out_pipe ( | ||||||
|                 _current_out = it->second.pipe; |               blob_t (static_cast<unsigned char *> (msg_->data ()), | ||||||
|  |                       msg_->size (), reference_tag_t ())); | ||||||
|  |  | ||||||
|  |             if (out_pipe) { | ||||||
|  |                 _current_out = out_pipe->pipe; | ||||||
|                 if (!_current_out->check_write ()) { |                 if (!_current_out->check_write ()) { | ||||||
|                     it->second.active = false; |                     out_pipe->active = false; | ||||||
|                     _current_out = NULL; |                     _current_out = NULL; | ||||||
|                     errno = EAGAIN; |                     errno = EAGAIN; | ||||||
|                     return -1; |                     return -1; | ||||||
| @@ -177,25 +165,14 @@ int zmq::stream_t::xsetsockopt (int option_, | |||||||
|                                 size_t optvallen_) |                                 size_t optvallen_) | ||||||
| { | { | ||||||
|     switch (option_) { |     switch (option_) { | ||||||
|         case ZMQ_CONNECT_ROUTING_ID: |  | ||||||
|             // TODO why isn't it possible to set an empty connect_routing_id |  | ||||||
|             //   (which is the default value) |  | ||||||
|             if (optval_ && optvallen_) { |  | ||||||
|                 connect_routing_id.assign ((char *) optval_, optvallen_); |  | ||||||
|                 return 0; |  | ||||||
|             } |  | ||||||
|             break; |  | ||||||
|  |  | ||||||
|         case ZMQ_STREAM_NOTIFY: |         case ZMQ_STREAM_NOTIFY: | ||||||
|             return do_setsockopt_int_as_bool_strict (optval_, optvallen_, |             return do_setsockopt_int_as_bool_strict (optval_, optvallen_, | ||||||
|                                                      &options.raw_notify); |                                                      &options.raw_notify); | ||||||
|             break; |  | ||||||
|  |  | ||||||
|         default: |         default: | ||||||
|             break; |             return routing_socket_base_t::xsetsockopt (option_, optval_, | ||||||
|  |                                                        optvallen_); | ||||||
|     } |     } | ||||||
|     errno = EINVAL; |  | ||||||
|     return -1; |  | ||||||
| } | } | ||||||
|  |  | ||||||
| int zmq::stream_t::xrecv (msg_t *msg_) | int zmq::stream_t::xrecv (msg_t *msg_) | ||||||
| @@ -293,12 +270,13 @@ void zmq::stream_t::identify_peer (pipe_t *pipe_) | |||||||
|     unsigned char buffer[5]; |     unsigned char buffer[5]; | ||||||
|     buffer[0] = 0; |     buffer[0] = 0; | ||||||
|     blob_t routing_id; |     blob_t routing_id; | ||||||
|     if (connect_routing_id.length ()) { |     const std::string connect_routing_id = extract_connect_routing_id (); | ||||||
|         routing_id.set ((unsigned char *) connect_routing_id.c_str (), |     if (!connect_routing_id.empty ()) { | ||||||
|                         connect_routing_id.length ()); |         routing_id.set ( | ||||||
|         connect_routing_id.clear (); |           reinterpret_cast<const unsigned char *> (connect_routing_id.c_str ()), | ||||||
|         outpipes_t::iterator it = _outpipes.find (routing_id); |           connect_routing_id.length ()); | ||||||
|         zmq_assert (it == _outpipes.end ()); |         //  Not allowed to duplicate an existing rid | ||||||
|  |         zmq_assert (!has_out_pipe (routing_id)); | ||||||
|     } else { |     } else { | ||||||
|         put_uint32 (buffer + 1, _next_integral_routing_id++); |         put_uint32 (buffer + 1, _next_integral_routing_id++); | ||||||
|         routing_id.set (buffer, sizeof buffer); |         routing_id.set (buffer, sizeof buffer); | ||||||
| @@ -307,10 +285,5 @@ void zmq::stream_t::identify_peer (pipe_t *pipe_) | |||||||
|           static_cast<unsigned char> (routing_id.size ()); |           static_cast<unsigned char> (routing_id.size ()); | ||||||
|     } |     } | ||||||
|     pipe_->set_router_socket_routing_id (routing_id); |     pipe_->set_router_socket_routing_id (routing_id); | ||||||
|     //  Add the record into output pipes lookup table |     add_out_pipe (ZMQ_MOVE (routing_id), pipe_); | ||||||
|     outpipe_t outpipe = {pipe_, true}; |  | ||||||
|     const bool ok = |  | ||||||
|       _outpipes.ZMQ_MAP_INSERT_OR_EMPLACE (ZMQ_MOVE (routing_id), outpipe) |  | ||||||
|         .second; |  | ||||||
|     zmq_assert (ok); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -39,7 +39,7 @@ namespace zmq | |||||||
| class ctx_t; | class ctx_t; | ||||||
| class pipe_t; | class pipe_t; | ||||||
|  |  | ||||||
| class stream_t : public socket_base_t | class stream_t : public routing_socket_base_t | ||||||
| { | { | ||||||
|   public: |   public: | ||||||
|     stream_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_); |     stream_t (zmq::ctx_t *parent_, uint32_t tid_, int sid_); | ||||||
| @@ -52,7 +52,6 @@ class stream_t : public socket_base_t | |||||||
|     bool xhas_in (); |     bool xhas_in (); | ||||||
|     bool xhas_out (); |     bool xhas_out (); | ||||||
|     void xread_activated (zmq::pipe_t *pipe_); |     void xread_activated (zmq::pipe_t *pipe_); | ||||||
|     void xwrite_activated (zmq::pipe_t *pipe_); |  | ||||||
|     void xpipe_terminated (zmq::pipe_t *pipe_); |     void xpipe_terminated (zmq::pipe_t *pipe_); | ||||||
|     int xsetsockopt (int option_, const void *optval_, size_t optvallen_); |     int xsetsockopt (int option_, const void *optval_, size_t optvallen_); | ||||||
|  |  | ||||||
| @@ -76,16 +75,6 @@ class stream_t : public socket_base_t | |||||||
|     //  Holds the prefetched message. |     //  Holds the prefetched message. | ||||||
|     msg_t _prefetched_msg; |     msg_t _prefetched_msg; | ||||||
|  |  | ||||||
|     struct outpipe_t |  | ||||||
|     { |  | ||||||
|         zmq::pipe_t *pipe; |  | ||||||
|         bool active; |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     //  Outbound pipes indexed by the peer IDs. |  | ||||||
|     typedef std::map<blob_t, outpipe_t> outpipes_t; |  | ||||||
|     outpipes_t _outpipes; |  | ||||||
|  |  | ||||||
|     //  The pipe we are currently writing to. |     //  The pipe we are currently writing to. | ||||||
|     zmq::pipe_t *_current_out; |     zmq::pipe_t *_current_out; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Luca Boccassi
					Luca Boccassi