/src/xsub.cpp

https://github.com/pjkundert/libzmq · C++ · 232 lines · 143 code · 37 blank · 52 comment · 35 complexity · 3f7ed6ebe35011b3b8e6151c19954fc5 MD5 · raw file

  1. /*
  2. Copyright (c) 2010-2011 250bpm s.r.o.
  3. Copyright (c) 2011 VMware, Inc.
  4. Copyright (c) 2010-2011 Other contributors as noted in the AUTHORS file
  5. This file is part of 0MQ.
  6. 0MQ is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU Lesser General Public License as published by
  8. the Free Software Foundation; either version 3 of the License, or
  9. (at your option) any later version.
  10. 0MQ is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public License
  15. along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <string.h>
  18. #include "xsub.hpp"
  19. #include "err.hpp"
  20. zmq::xsub_t::xsub_t (class ctx_t *parent_, uint32_t tid_) :
  21. socket_base_t (parent_, tid_),
  22. has_message (false),
  23. more (false)
  24. {
  25. options.type = ZMQ_XSUB;
  26. // When socket is being closed down we don't want to wait till pending
  27. // subscription commands are sent to the wire.
  28. options.linger = 0;
  29. int rc = message.init ();
  30. errno_assert (rc == 0);
  31. }
  32. zmq::xsub_t::~xsub_t ()
  33. {
  34. int rc = message.close ();
  35. errno_assert (rc == 0);
  36. }
  37. void zmq::xsub_t::xattach_pipe (pipe_t *pipe_)
  38. {
  39. zmq_assert (pipe_);
  40. fq.attach (pipe_);
  41. dist.attach (pipe_);
  42. // Send all the cached subscriptions to the new upstream peer.
  43. subscriptions.apply (send_subscription, pipe_);
  44. pipe_->flush ();
  45. }
  46. void zmq::xsub_t::xread_activated (pipe_t *pipe_)
  47. {
  48. fq.activated (pipe_);
  49. }
  50. void zmq::xsub_t::xwrite_activated (pipe_t *pipe_)
  51. {
  52. dist.activated (pipe_);
  53. }
  54. void zmq::xsub_t::xterminated (pipe_t *pipe_)
  55. {
  56. fq.terminated (pipe_);
  57. dist.terminated (pipe_);
  58. }
  59. void zmq::xsub_t::xhiccuped (pipe_t *pipe_)
  60. {
  61. // Send all the cached subscriptions to the hiccuped pipe.
  62. subscriptions.apply (send_subscription, pipe_);
  63. pipe_->flush ();
  64. }
  65. int zmq::xsub_t::xsend (msg_t *msg_, int flags_)
  66. {
  67. size_t size = msg_->size ();
  68. unsigned char *data = (unsigned char*) msg_->data ();
  69. // Malformed subscriptions.
  70. if (size < 1 || (*data != 0 && *data != 1)) {
  71. errno = EINVAL;
  72. return -1;
  73. }
  74. // Process the subscription.
  75. if (*data == 1) {
  76. if (subscriptions.add (data + 1, size - 1))
  77. return dist.send_to_all (msg_, flags_);
  78. else
  79. return 0;
  80. }
  81. else if (*data == 0) {
  82. if (subscriptions.rm (data + 1, size - 1))
  83. return dist.send_to_all (msg_, flags_);
  84. else
  85. return 0;
  86. }
  87. zmq_assert (false);
  88. return -1;
  89. }
  90. bool zmq::xsub_t::xhas_out ()
  91. {
  92. // Subscription can be added/removed anytime.
  93. return true;
  94. }
  95. int zmq::xsub_t::xrecv (msg_t *msg_, int flags_)
  96. {
  97. // If there's already a message prepared by a previous call to zmq_poll,
  98. // return it straight ahead.
  99. if (has_message) {
  100. int rc = msg_->move (message);
  101. errno_assert (rc == 0);
  102. has_message = false;
  103. more = msg_->flags () & msg_t::more ? true : false;
  104. return 0;
  105. }
  106. // TODO: This can result in infinite loop in the case of continuous
  107. // stream of non-matching messages which breaks the non-blocking recv
  108. // semantics.
  109. while (true) {
  110. // Get a message using fair queueing algorithm.
  111. int rc = fq.recv (msg_, flags_);
  112. // If there's no message available, return immediately.
  113. // The same when error occurs.
  114. if (rc != 0)
  115. return -1;
  116. // Check whether the message matches at least one subscription.
  117. // Non-initial parts of the message are passed
  118. if (more || !options.filter || match (msg_)) {
  119. more = msg_->flags () & msg_t::more ? true : false;
  120. return 0;
  121. }
  122. // Message doesn't match. Pop any remaining parts of the message
  123. // from the pipe.
  124. while (msg_->flags () & msg_t::more) {
  125. rc = fq.recv (msg_, ZMQ_DONTWAIT);
  126. zmq_assert (rc == 0);
  127. }
  128. }
  129. }
  130. bool zmq::xsub_t::xhas_in ()
  131. {
  132. // There are subsequent parts of the partly-read message available.
  133. if (more)
  134. return true;
  135. // If there's already a message prepared by a previous call to zmq_poll,
  136. // return straight ahead.
  137. if (has_message)
  138. return true;
  139. // TODO: This can result in infinite loop in the case of continuous
  140. // stream of non-matching messages.
  141. while (true) {
  142. // Get a message using fair queueing algorithm.
  143. int rc = fq.recv (&message, ZMQ_DONTWAIT);
  144. // If there's no message available, return immediately.
  145. // The same when error occurs.
  146. if (rc != 0) {
  147. zmq_assert (errno == EAGAIN);
  148. return false;
  149. }
  150. // Check whether the message matches at least one subscription.
  151. if (!options.filter || match (&message)) {
  152. has_message = true;
  153. return true;
  154. }
  155. // Message doesn't match. Pop any remaining parts of the message
  156. // from the pipe.
  157. while (message.flags () & msg_t::more) {
  158. rc = fq.recv (&message, ZMQ_DONTWAIT);
  159. zmq_assert (rc == 0);
  160. }
  161. }
  162. }
  163. bool zmq::xsub_t::match (msg_t *msg_)
  164. {
  165. return subscriptions.check ((unsigned char*) msg_->data (), msg_->size ());
  166. }
  167. void zmq::xsub_t::send_subscription (unsigned char *data_, size_t size_,
  168. void *arg_)
  169. {
  170. pipe_t *pipe = (pipe_t*) arg_;
  171. // Create the subsctription message.
  172. msg_t msg;
  173. int rc = msg.init_size (size_ + 1);
  174. zmq_assert (rc == 0);
  175. unsigned char *data = (unsigned char*) msg.data ();
  176. data [0] = 1;
  177. memcpy (data + 1, data_, size_);
  178. // Send it to the pipe.
  179. bool sent = pipe->write (&msg);
  180. zmq_assert (sent);
  181. }
  182. zmq::xsub_session_t::xsub_session_t (io_thread_t *io_thread_, bool connect_,
  183. socket_base_t *socket_, const options_t &options_,
  184. const char *protocol_, const char *address_) :
  185. session_base_t (io_thread_, connect_, socket_, options_, protocol_,
  186. address_)
  187. {
  188. }
  189. zmq::xsub_session_t::~xsub_session_t ()
  190. {
  191. }