aboutsummaryrefslogtreecommitdiffstats
path: root/websocketpp/message_buffer/message.hpp
blob: da36e2001273b841992fcdb4089b13df0948c9d8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/*
 * Copyright (c) 2014, Peter Thorson. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the WebSocket++ Project nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#ifndef WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP
#define WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP

#include <websocketpp/common/memory.hpp>
#include <websocketpp/frame.hpp>

#include <string>

namespace websocketpp {
namespace message_buffer {

/* # message:
 * object that stores a message while it is being sent or received. Contains
 * the message payload itself, the message header, the extension data, and the
 * opcode.
 *
 * # connection_message_manager:
 * An object that manages all of the message_buffers associated with a given
 * connection. Implements the get_message_buffer(size) method that returns
 * a message buffer at least size bytes long.
 *
 * Message buffers are reference counted with shared ownership semantics. Once
 * requested from the manager the requester and it's associated downstream code
 * may keep a pointer to the message indefinitely at a cost of extra resource
 * usage. Once the reference count drops to the point where the manager is the
 * only reference the messages is recycled using whatever method is implemented
 * in the manager.
 *
 * # endpoint_message_manager:
 * An object that manages connection_message_managers. Implements the
 * get_message_manager() method. This is used once by each connection to
 * request the message manager that they are supposed to use to manage message
 * buffers for their own use.
 *
 * TYPES OF CONNECTION_MESSAGE_MANAGERS
 * - allocate a message with the exact size every time one is requested
 * - maintain a pool of pre-allocated messages and return one when needed.
 *   Recycle previously used messages back into the pool
 *
 * TYPES OF ENDPOINT_MESSAGE_MANAGERS
 *  - allocate a new connection manager for each connection. Message pools
 *    become connection specific. This increases memory usage but improves
 *    concurrency.
 *  - allocate a single connection manager and share a pointer to it with all
 *    connections created by this endpoint. The message pool will be shared
 *    among all connections, improving memory usage and performance at the cost
 *    of reduced concurrency
 */


/// Represents a buffer for a single WebSocket message.
/**
 *
 *
 */
template <template<class> class con_msg_manager>
class message {
public:
    typedef lib::shared_ptr<message> ptr;

    typedef con_msg_manager<message> con_msg_man_type;
    typedef typename con_msg_man_type::ptr con_msg_man_ptr;
    typedef typename con_msg_man_type::weak_ptr con_msg_man_weak_ptr;

    /// Construct an empty message
    /**
     * Construct an empty message
     */
    message(const con_msg_man_ptr manager)
      : m_manager(manager)
      , m_prepared(false)
      , m_fin(true)
      , m_terminal(false)
      , m_compressed(false) {}

    /// Construct a message and fill in some values
    /**
     *
     */
    message(const con_msg_man_ptr manager, frame::opcode::value op, size_t size = 128)
      : m_manager(manager)
      , m_opcode(op)
      , m_prepared(false)
      , m_fin(true)
      , m_terminal(false)
      , m_compressed(false)
    {
        m_payload.reserve(size);
    }

    /// Return whether or not the message has been prepared for sending
    /**
     * The prepared flag indicates that the message has been prepared by a
     * websocket protocol processor and is ready to be written to the wire.
     *
     * @return whether or not the message has been prepared for sending
     */
    bool get_prepared() const {
        return m_prepared;
    }

    /// Set or clear the flag that indicates that the message has been prepared
    /**
     * This flag should not be set by end user code without a very good reason.
     *
     * @param value The value to set the prepared flag to
     */
    void set_prepared(bool value) {
        m_prepared = value;
    }

    /// Return whether or not the message is flagged as compressed
    /**
     * @return whether or not the message is/should be compressed
     */
    bool get_compressed() const {
        return m_compressed;
    }

    /// Set or clear the compression flag
    /**
     * Setting the compression flag indicates that the data in this message
     * would benefit from compression. If both endpoints negotiate a compression
     * extension WebSocket++ will attempt to compress messages with this flag.
     * Setting this flag does not guarantee that the message will be compressed.
     *
     * @param value The value to set the compressed flag to
     */
    void set_compressed(bool value) {
        m_compressed = value;
    }

    /// Get whether or not the message is terminal
    /**
     * Messages can be flagged as terminal, which results in the connection
     * being close after they are written rather than the implementation going
     * on to the next message in the queue. This is typically used internally
     * for close messages only.
     *
     * @return Whether or not this message is marked terminal
     */
    bool get_terminal() const {
        return m_terminal;
    }

    /// Set the terminal flag
    /**
     * This flag should not be set by end user code without a very good reason.
     *
     * @see get_terminal()
     *
     * @param value The value to set the terminal flag to.
     */
    void set_terminal(bool value) {
        m_terminal = value;
    }
    /// Read the fin bit
    /**
     * A message with the fin bit set will be sent as the last message of its
     * sequence. A message with the fin bit cleared will require subsequent
     * frames of opcode continuation until one of them has the fin bit set.
     *
     * The remote end likely will not deliver any bytes until the frame with the fin
     * bit set has been received.
     *
     * @return Whether or not the fin bit is set
     */
    bool get_fin() const {
        return m_fin;
    }

    /// Set the fin bit
    /**
     * @see get_fin for a more detailed explaination of the fin bit
     *
     * @param value The value to set the fin bit to.
     */
    void set_fin(bool value) {
        m_fin = value;
    }

    /// Return the message opcode
    frame::opcode::value get_opcode() const {
        return m_opcode;
    }

    /// Set the opcode
    void set_opcode(frame::opcode::value op) {
        m_opcode = op;
    }

    /// Return the prepared frame header
    /**
     * This value is typically set by a websocket protocol processor
     * and shouldn't be tampered with.
     */
    std::string const & get_header() const {
        return m_header;
    }

    /// Set prepared frame header
    /**
     * Under normal circumstances this should not be called by end users
     *
     * @param header A string to set the header to.
     */
    void set_header(std::string const & header) {
        m_header = header;
    }

    std::string const & get_extension_data() const {
        return m_extension_data;
    }

    /// Get a reference to the payload string
    /**
     * @return A const reference to the message's payload string
     */
    std::string const & get_payload() const {
        return m_payload;
    }

    /// Get a non-const reference to the payload string
    /**
     * @return A reference to the message's payload string
     */
    std::string & get_raw_payload() {
        return m_payload;
    }

    /// Set payload data
    /**
     * Set the message buffer's payload to the given value.
     *
     * @param payload A string to set the payload to.
     */
    void set_payload(std::string const & payload) {
        m_payload = payload;
    }

    /// Set payload data
    /**
     * Set the message buffer's payload to the given value.
     *
     * @param payload A pointer to a data array to set to.
     * @param len The length of new payload in bytes.
     */
    void set_payload(void const * payload, size_t len) {
        m_payload.reserve(len);
        char const * pl = static_cast<char const *>(payload);
        m_payload.assign(pl, pl + len);
    }

    /// Append payload data
    /**
     * Append data to the message buffer's payload.
     *
     * @param payload A string containing the data array to append.
     */
    void append_payload(std::string const & payload) {
        m_payload.append(payload);
    }

    /// Append payload data
    /**
     * Append data to the message buffer's payload.
     *
     * @param payload A pointer to a data array to append
     * @param len The length of payload in bytes
     */
    void append_payload(void const * payload, size_t len) {
        m_payload.reserve(m_payload.size()+len);
        m_payload.append(static_cast<char const *>(payload),len);
    }

    /// Recycle the message
    /**
     * A request to recycle this message was received. Forward that request to
     * the connection message manager for processing. Errors and exceptions
     * from the manager's recycle member function should be passed back up the
     * call chain. The caller to message::recycle will deal with them.
     *
     * Recycle must *only* be called by the message shared_ptr's destructor.
     * Once recycled successfully, ownership of the memory has been passed to
     * another system and must not be accessed again.
     *
     * @return true if the message was successfully recycled, false otherwise.
     */
    bool recycle() {
        con_msg_man_ptr shared = m_manager.lock();

        if (shared) {
            return shared->recycle(this);
        } else {
            return false;
        }
    }
private:
    con_msg_man_weak_ptr        m_manager;
    std::string                 m_header;
    std::string                 m_extension_data;
    std::string                 m_payload;
    frame::opcode::value        m_opcode;
    bool                        m_prepared;
    bool                        m_fin;
    bool                        m_terminal;
    bool                        m_compressed;
};

} // namespace message_buffer
} // namespace websocketpp

#endif // WEBSOCKETPP_MESSAGE_BUFFER_MESSAGE_HPP