message.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * Copyright (c) 2014, Peter Thorson. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are met:
  6. * * Redistributions of source code must retain the above copyright
  7. * notice, this list of conditions and the following disclaimer.
  8. * * Redistributions in binary form must reproduce the above copyright
  9. * notice, this list of conditions and the following disclaimer in the
  10. * documentation and/or other materials provided with the distribution.
  11. * * Neither the name of the WebSocket++ Project nor the
  12. * names of its contributors may be used to endorse or promote products
  13. * derived from this software without specific prior written permission.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  18. * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
  19. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  22. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. */
  27. #ifndef WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP
  28. #define WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP
  29. #include <websocketpp/common/memory.hpp>
  30. #include <websocketpp/frame.hpp>
  31. #include <string>
  32. namespace websocketpp {
  33. namespace message_buffer {
  34. /* # message:
  35. * object that stores a message while it is being sent or received. Contains
  36. * the message payload itself, the message header, the extension data, and the
  37. * opcode.
  38. *
  39. * # connection_message_manager:
  40. * An object that manages all of the message_buffers associated with a given
  41. * connection. Implements the get_message_buffer(size) method that returns
  42. * a message buffer at least size bytes long.
  43. *
  44. * Message buffers are reference counted with shared ownership semantics. Once
  45. * requested from the manager the requester and it's associated downstream code
  46. * may keep a pointer to the message indefinitely at a cost of extra resource
  47. * usage. Once the reference count drops to the point where the manager is the
  48. * only reference the messages is recycled using whatever method is implemented
  49. * in the manager.
  50. *
  51. * # endpoint_message_manager:
  52. * An object that manages connection_message_managers. Implements the
  53. * get_message_manager() method. This is used once by each connection to
  54. * request the message manager that they are supposed to use to manage message
  55. * buffers for their own use.
  56. *
  57. * TYPES OF CONNECTION_MESSAGE_MANAGERS
  58. * - allocate a message with the exact size every time one is requested
  59. * - maintain a pool of pre-allocated messages and return one when needed.
  60. * Recycle previously used messages back into the pool
  61. *
  62. * TYPES OF ENDPOINT_MESSAGE_MANAGERS
  63. * - allocate a new connection manager for each connection. Message pools
  64. * become connection specific. This increases memory usage but improves
  65. * concurrency.
  66. * - allocate a single connection manager and share a pointer to it with all
  67. * connections created by this endpoint. The message pool will be shared
  68. * among all connections, improving memory usage and performance at the cost
  69. * of reduced concurrency
  70. */
  71. /// Represents a buffer for a single WebSocket message.
  72. /**
  73. *
  74. *
  75. */
  76. template <template<class> class con_msg_manager>
  77. class message {
  78. public:
  79. typedef lib::shared_ptr<message> ptr;
  80. typedef con_msg_manager<message> con_msg_man_type;
  81. typedef typename con_msg_man_type::ptr con_msg_man_ptr;
  82. typedef typename con_msg_man_type::weak_ptr con_msg_man_weak_ptr;
  83. /// Construct an empty message
  84. /**
  85. * Construct an empty message
  86. */
  87. message(const con_msg_man_ptr manager)
  88. : m_manager(manager)
  89. , m_prepared(false)
  90. , m_fin(true)
  91. , m_terminal(false)
  92. , m_compressed(false) {}
  93. /// Construct a message and fill in some values
  94. /**
  95. *
  96. */
  97. message(const con_msg_man_ptr manager, frame::opcode::value op, size_t size = 128)
  98. : m_manager(manager)
  99. , m_opcode(op)
  100. , m_prepared(false)
  101. , m_fin(true)
  102. , m_terminal(false)
  103. , m_compressed(false)
  104. {
  105. m_payload.reserve(size);
  106. }
  107. /// Return whether or not the message has been prepared for sending
  108. /**
  109. * The prepared flag indicates that the message has been prepared by a
  110. * websocket protocol processor and is ready to be written to the wire.
  111. *
  112. * @return whether or not the message has been prepared for sending
  113. */
  114. bool get_prepared() const {
  115. return m_prepared;
  116. }
  117. /// Set or clear the flag that indicates that the message has been prepared
  118. /**
  119. * This flag should not be set by end user code without a very good reason.
  120. *
  121. * @param value The value to set the prepared flag to
  122. */
  123. void set_prepared(bool value) {
  124. m_prepared = value;
  125. }
  126. /// Return whether or not the message is flagged as compressed
  127. /**
  128. * @return whether or not the message is/should be compressed
  129. */
  130. bool get_compressed() const {
  131. return m_compressed;
  132. }
  133. /// Set or clear the compression flag
  134. /**
  135. * Setting the compression flag indicates that the data in this message
  136. * would benefit from compression. If both endpoints negotiate a compression
  137. * extension WebSocket++ will attempt to compress messages with this flag.
  138. * Setting this flag does not guarantee that the message will be compressed.
  139. *
  140. * @param value The value to set the compressed flag to
  141. */
  142. void set_compressed(bool value) {
  143. m_compressed = value;
  144. }
  145. /// Get whether or not the message is terminal
  146. /**
  147. * Messages can be flagged as terminal, which results in the connection
  148. * being close after they are written rather than the implementation going
  149. * on to the next message in the queue. This is typically used internally
  150. * for close messages only.
  151. *
  152. * @return Whether or not this message is marked terminal
  153. */
  154. bool get_terminal() const {
  155. return m_terminal;
  156. }
  157. /// Set the terminal flag
  158. /**
  159. * This flag should not be set by end user code without a very good reason.
  160. *
  161. * @see get_terminal()
  162. *
  163. * @param value The value to set the terminal flag to.
  164. */
  165. void set_terminal(bool value) {
  166. m_terminal = value;
  167. }
  168. /// Read the fin bit
  169. /**
  170. * A message with the fin bit set will be sent as the last message of its
  171. * sequence. A message with the fin bit cleared will require subsequent
  172. * frames of opcode continuation until one of them has the fin bit set.
  173. *
  174. * The remote end likely will not deliver any bytes until the frame with the fin
  175. * bit set has been received.
  176. *
  177. * @return Whether or not the fin bit is set
  178. */
  179. bool get_fin() const {
  180. return m_fin;
  181. }
  182. /// Set the fin bit
  183. /**
  184. * @see get_fin for a more detailed explaination of the fin bit
  185. *
  186. * @param value The value to set the fin bit to.
  187. */
  188. void set_fin(bool value) {
  189. m_fin = value;
  190. }
  191. /// Return the message opcode
  192. frame::opcode::value get_opcode() const {
  193. return m_opcode;
  194. }
  195. /// Set the opcode
  196. void set_opcode(frame::opcode::value op) {
  197. m_opcode = op;
  198. }
  199. /// Return the prepared frame header
  200. /**
  201. * This value is typically set by a websocket protocol processor
  202. * and shouldn't be tampered with.
  203. */
  204. std::string const & get_header() const {
  205. return m_header;
  206. }
  207. /// Set prepared frame header
  208. /**
  209. * Under normal circumstances this should not be called by end users
  210. *
  211. * @param header A string to set the header to.
  212. */
  213. void set_header(std::string const & header) {
  214. m_header = header;
  215. }
  216. std::string const & get_extension_data() const {
  217. return m_extension_data;
  218. }
  219. /// Get a reference to the payload string
  220. /**
  221. * @return A const reference to the message's payload string
  222. */
  223. std::string const & get_payload() const {
  224. return m_payload;
  225. }
  226. /// Get a non-const reference to the payload string
  227. /**
  228. * @return A reference to the message's payload string
  229. */
  230. std::string & get_raw_payload() {
  231. return m_payload;
  232. }
  233. /// Set payload data
  234. /**
  235. * Set the message buffer's payload to the given value.
  236. *
  237. * @param payload A string to set the payload to.
  238. */
  239. void set_payload(std::string const & payload) {
  240. m_payload = payload;
  241. }
  242. /// Set payload data
  243. /**
  244. * Set the message buffer's payload to the given value.
  245. *
  246. * @param payload A pointer to a data array to set to.
  247. * @param len The length of new payload in bytes.
  248. */
  249. void set_payload(void const * payload, size_t len) {
  250. m_payload.reserve(len);
  251. char const * pl = static_cast<char const *>(payload);
  252. m_payload.assign(pl, pl + len);
  253. }
  254. /// Append payload data
  255. /**
  256. * Append data to the message buffer's payload.
  257. *
  258. * @param payload A string containing the data array to append.
  259. */
  260. void append_payload(std::string const & payload) {
  261. m_payload.append(payload);
  262. }
  263. /// Append payload data
  264. /**
  265. * Append data to the message buffer's payload.
  266. *
  267. * @param payload A pointer to a data array to append
  268. * @param len The length of payload in bytes
  269. */
  270. void append_payload(void const * payload, size_t len) {
  271. m_payload.reserve(m_payload.size()+len);
  272. m_payload.append(static_cast<char const *>(payload),len);
  273. }
  274. /// Recycle the message
  275. /**
  276. * A request to recycle this message was received. Forward that request to
  277. * the connection message manager for processing. Errors and exceptions
  278. * from the manager's recycle member function should be passed back up the
  279. * call chain. The caller to message::recycle will deal with them.
  280. *
  281. * Recycle must *only* be called by the message shared_ptr's destructor.
  282. * Once recycled successfully, ownership of the memory has been passed to
  283. * another system and must not be accessed again.
  284. *
  285. * @return true if the message was successfully recycled, false otherwise.
  286. */
  287. bool recycle() {
  288. con_msg_man_ptr shared = m_manager.lock();
  289. if (shared) {
  290. return shared->recycle(this);
  291. } else {
  292. return false;
  293. }
  294. }
  295. private:
  296. con_msg_man_weak_ptr m_manager;
  297. std::string m_header;
  298. std::string m_extension_data;
  299. std::string m_payload;
  300. frame::opcode::value m_opcode;
  301. bool m_prepared;
  302. bool m_fin;
  303. bool m_terminal;
  304. bool m_compressed;
  305. };
  306. } // namespace message_buffer
  307. } // namespace websocketpp
  308. #endif // WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP