2 * Copyright (c) 2014, Peter Thorson. All rights reserved.
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.
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.
28 #ifndef WEBSOCKETPP_ENDPOINT_HPP
29 #define WEBSOCKETPP_ENDPOINT_HPP
31 #include <websocketpp/connection.hpp>
33 #include <websocketpp/logger/levels.hpp>
34 #include <websocketpp/version.hpp>
38 namespace websocketpp {
40 /// Creates and manages connections associated with a WebSocket endpoint
41 template <typename connection, typename config>
42 class endpoint : public config::transport_type, public config::endpoint_base {
44 // Import appropriate types from our helper class
45 // See endpoint_types for more details.
46 typedef endpoint<connection,config> type;
48 /// Type of the transport component of this endpoint
49 typedef typename config::transport_type transport_type;
50 /// Type of the concurrency component of this endpoint
51 typedef typename config::concurrency_type concurrency_type;
53 /// Type of the connections that this endpoint creates
54 typedef connection connection_type;
55 /// Shared pointer to connection_type
56 typedef typename connection_type::ptr connection_ptr;
57 /// Weak pointer to connection type
58 typedef typename connection_type::weak_ptr connection_weak_ptr;
60 /// Type of the transport component of the connections that this endpoint
62 typedef typename transport_type::transport_con_type transport_con_type;
63 /// Type of a shared pointer to the transport component of the connections
64 /// that this endpoint creates.
65 typedef typename transport_con_type::ptr transport_con_ptr;
67 /// Type of message_handler
68 typedef typename connection_type::message_handler message_handler;
69 /// Type of message pointers that this endpoint uses
70 typedef typename connection_type::message_ptr message_ptr;
72 /// Type of error logger
73 typedef typename config::elog_type elog_type;
74 /// Type of access logger
75 typedef typename config::alog_type alog_type;
77 /// Type of our concurrency policy's scoped lock object
78 typedef typename concurrency_type::scoped_lock_type scoped_lock_type;
79 /// Type of our concurrency policy's mutex object
80 typedef typename concurrency_type::mutex_type mutex_type;
83 typedef typename config::rng_type rng_type;
85 // TODO: organize these
86 typedef typename connection_type::termination_handler termination_handler;
88 // This would be ideal. Requires C++11 though
91 explicit endpoint(bool p_is_server)
92 : m_alog(config::alog_level, log::channel_type_hint::access)
93 , m_elog(config::elog_level, log::channel_type_hint::error)
94 , m_user_agent(::websocketpp::user_agent)
95 , m_open_handshake_timeout_dur(config::timeout_open_handshake)
96 , m_close_handshake_timeout_dur(config::timeout_close_handshake)
97 , m_pong_timeout_dur(config::timeout_pong)
98 , m_max_message_size(config::max_message_size)
99 , m_max_http_body_size(config::max_http_body_size)
100 , m_is_server(p_is_server)
102 m_alog.set_channels(config::alog_level);
103 m_elog.set_channels(config::elog_level);
105 m_alog.write(log::alevel::devel, "endpoint constructor");
107 transport_type::init_logging(&m_alog, &m_elog);
112 ~endpoint<connection,config>() {}
114 #ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
115 // no copy constructor because endpoints are not copyable
116 endpoint(endpoint &) = delete;
118 // no copy assignment operator because endpoints are not copyable
119 endpoint & operator=(endpoint const &) = delete;
120 #endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
122 #ifdef _WEBSOCKETPP_MOVE_SEMANTICS_
124 endpoint(endpoint && o)
125 : config::transport_type(std::move(o))
126 , config::endpoint_base(std::move(o))
127 , m_alog(std::move(o.m_alog))
128 , m_elog(std::move(o.m_elog))
129 , m_user_agent(std::move(o.m_user_agent))
130 , m_open_handler(std::move(o.m_open_handler))
132 , m_close_handler(std::move(o.m_close_handler))
133 , m_fail_handler(std::move(o.m_fail_handler))
134 , m_ping_handler(std::move(o.m_ping_handler))
135 , m_pong_handler(std::move(o.m_pong_handler))
136 , m_pong_timeout_handler(std::move(o.m_pong_timeout_handler))
137 , m_interrupt_handler(std::move(o.m_interrupt_handler))
138 , m_http_handler(std::move(o.m_http_handler))
139 , m_validate_handler(std::move(o.m_validate_handler))
140 , m_message_handler(std::move(o.m_message_handler))
142 , m_open_handshake_timeout_dur(o.m_open_handshake_timeout_dur)
143 , m_close_handshake_timeout_dur(o.m_close_handshake_timeout_dur)
144 , m_pong_timeout_dur(o.m_pong_timeout_dur)
145 , m_max_message_size(o.m_max_message_size)
146 , m_max_http_body_size(o.m_max_http_body_size)
148 , m_rng(std::move(o.m_rng))
149 , m_is_server(o.m_is_server)
152 #ifdef _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
153 // no move assignment operator because of const member variables
154 endpoint & operator=(endpoint &&) = delete;
155 #endif // _WEBSOCKETPP_DEFAULT_DELETE_FUNCTIONS_
157 #endif // _WEBSOCKETPP_MOVE_SEMANTICS_
160 /// Returns the user agent string that this endpoint will use
162 * Returns the user agent string that this endpoint will use when creating
165 * The default value for this version is stored in websocketpp::user_agent
167 * @return The user agent string.
169 std::string get_user_agent() const {
170 scoped_lock_type guard(m_mutex);
174 /// Sets the user agent string that this endpoint will use
176 * Sets the identifier that this endpoint will use when creating new
177 * connections. Changing this value will only affect future connections.
178 * For client endpoints this will be sent as the "User-Agent" header in
179 * outgoing requests. For server endpoints this will be sent in the "Server"
182 * Setting this value to the empty string will suppress the use of the
183 * Server and User-Agent headers. This is typically done to hide
184 * implementation details for security purposes.
186 * For best results set this before accepting or opening connections.
188 * The default value for this version is stored in websocketpp::user_agent
190 * This can be overridden on an individual connection basis by setting a
191 * custom "Server" header during the validate handler or "User-Agent"
192 * header on a connection before calling connect().
194 * @param ua The string to set the user agent to.
196 void set_user_agent(std::string const & ua) {
197 scoped_lock_type guard(m_mutex);
201 /// Returns whether or not this endpoint is a server.
203 * @return Whether or not this endpoint is a server
205 bool is_server() const {
209 /********************************/
210 /* Pass-through logging adaptor */
211 /********************************/
213 /// Set Access logging channel
215 * Set the access logger's channel value. The value is a number whose
216 * interpretation depends on the logging policy in use.
218 * @param channels The channel value(s) to set
220 void set_access_channels(log::level channels) {
221 m_alog.set_channels(channels);
224 /// Clear Access logging channels
226 * Clear the access logger's channel value. The value is a number whose
227 * interpretation depends on the logging policy in use.
229 * @param channels The channel value(s) to clear
231 void clear_access_channels(log::level channels) {
232 m_alog.clear_channels(channels);
235 /// Set Error logging channel
237 * Set the error logger's channel value. The value is a number whose
238 * interpretation depends on the logging policy in use.
240 * @param channels The channel value(s) to set
242 void set_error_channels(log::level channels) {
243 m_elog.set_channels(channels);
246 /// Clear Error logging channels
248 * Clear the error logger's channel value. The value is a number whose
249 * interpretation depends on the logging policy in use.
251 * @param channels The channel value(s) to clear
253 void clear_error_channels(log::level channels) {
254 m_elog.clear_channels(channels);
257 /// Get reference to access logger
259 * @return A reference to the access logger
261 alog_type & get_alog() {
265 /// Get reference to error logger
267 * @return A reference to the error logger
269 elog_type & get_elog() {
273 /*************************/
274 /* Set Handler functions */
275 /*************************/
277 void set_open_handler(open_handler h) {
278 m_alog.write(log::alevel::devel,"set_open_handler");
279 scoped_lock_type guard(m_mutex);
282 void set_close_handler(close_handler h) {
283 m_alog.write(log::alevel::devel,"set_close_handler");
284 scoped_lock_type guard(m_mutex);
287 void set_fail_handler(fail_handler h) {
288 m_alog.write(log::alevel::devel,"set_fail_handler");
289 scoped_lock_type guard(m_mutex);
292 void set_ping_handler(ping_handler h) {
293 m_alog.write(log::alevel::devel,"set_ping_handler");
294 scoped_lock_type guard(m_mutex);
297 void set_pong_handler(pong_handler h) {
298 m_alog.write(log::alevel::devel,"set_pong_handler");
299 scoped_lock_type guard(m_mutex);
302 void set_pong_timeout_handler(pong_timeout_handler h) {
303 m_alog.write(log::alevel::devel,"set_pong_timeout_handler");
304 scoped_lock_type guard(m_mutex);
305 m_pong_timeout_handler = h;
307 void set_interrupt_handler(interrupt_handler h) {
308 m_alog.write(log::alevel::devel,"set_interrupt_handler");
309 scoped_lock_type guard(m_mutex);
310 m_interrupt_handler = h;
312 void set_http_handler(http_handler h) {
313 m_alog.write(log::alevel::devel,"set_http_handler");
314 scoped_lock_type guard(m_mutex);
317 void set_validate_handler(validate_handler h) {
318 m_alog.write(log::alevel::devel,"set_validate_handler");
319 scoped_lock_type guard(m_mutex);
320 m_validate_handler = h;
322 void set_message_handler(message_handler h) {
323 m_alog.write(log::alevel::devel,"set_message_handler");
324 scoped_lock_type guard(m_mutex);
325 m_message_handler = h;
328 //////////////////////////////////////////
329 // Connection timeouts and other limits //
330 //////////////////////////////////////////
332 /// Set open handshake timeout
334 * Sets the length of time the library will wait after an opening handshake
335 * has been initiated before cancelling it. This can be used to prevent
336 * excessive wait times for outgoing clients or excessive resource usage
337 * from broken clients or DoS attacks on servers.
339 * Connections that time out will have their fail handlers called with the
340 * open_handshake_timeout error code.
342 * The default value is specified via the compile time config value
343 * 'timeout_open_handshake'. The default value in the core config
344 * is 5000ms. A value of 0 will disable the timer entirely.
346 * To be effective, the transport you are using must support timers. See
347 * the documentation for your transport policy for details about its
350 * @param dur The length of the open handshake timeout in ms
352 void set_open_handshake_timeout(long dur) {
353 scoped_lock_type guard(m_mutex);
354 m_open_handshake_timeout_dur = dur;
357 /// Set close handshake timeout
359 * Sets the length of time the library will wait after a closing handshake
360 * has been initiated before cancelling it. This can be used to prevent
361 * excessive wait times for outgoing clients or excessive resource usage
362 * from broken clients or DoS attacks on servers.
364 * Connections that time out will have their close handlers called with the
365 * close_handshake_timeout error code.
367 * The default value is specified via the compile time config value
368 * 'timeout_close_handshake'. The default value in the core config
369 * is 5000ms. A value of 0 will disable the timer entirely.
371 * To be effective, the transport you are using must support timers. See
372 * the documentation for your transport policy for details about its
375 * @param dur The length of the close handshake timeout in ms
377 void set_close_handshake_timeout(long dur) {
378 scoped_lock_type guard(m_mutex);
379 m_close_handshake_timeout_dur = dur;
384 * Sets the length of time the library will wait for a pong response to a
385 * ping. This can be used as a keepalive or to detect broken connections.
387 * Pong responses that time out will have the pong timeout handler called.
389 * The default value is specified via the compile time config value
390 * 'timeout_pong'. The default value in the core config
391 * is 5000ms. A value of 0 will disable the timer entirely.
393 * To be effective, the transport you are using must support timers. See
394 * the documentation for your transport policy for details about its
397 * @param dur The length of the pong timeout in ms
399 void set_pong_timeout(long dur) {
400 scoped_lock_type guard(m_mutex);
401 m_pong_timeout_dur = dur;
404 /// Get default maximum message size
406 * Get the default maximum message size that will be used for new
407 * connections created by this endpoint. The maximum message size determines
408 * the point at which the connection will fail a connection with the
409 * message_too_big protocol error.
411 * The default is set by the max_message_size value from the template config
415 size_t get_max_message_size() const {
416 return m_max_message_size;
419 /// Set default maximum message size
421 * Set the default maximum message size that will be used for new
422 * connections created by this endpoint. Maximum message size determines the
423 * point at which the connection will fail a connection with the
424 * message_too_big protocol error.
426 * The default is set by the max_message_size value from the template config
430 * @param new_value The value to set as the maximum message size.
432 void set_max_message_size(size_t new_value) {
433 m_max_message_size = new_value;
436 /// Get maximum HTTP message body size
438 * Get maximum HTTP message body size. Maximum message body size determines
439 * the point at which the connection will stop reading an HTTP request whose
442 * The default is set by the max_http_body_size value from the template
447 * @return The maximum HTTP message body size
449 size_t get_max_http_body_size() const {
450 return m_max_http_body_size;
453 /// Set maximum HTTP message body size
455 * Set maximum HTTP message body size. Maximum message body size determines
456 * the point at which the connection will stop reading an HTTP request whose
459 * The default is set by the max_http_body_size value from the template
464 * @param new_value The value to set as the maximum message size.
466 void set_max_http_body_size(size_t new_value) {
467 m_max_http_body_size = new_value;
470 /*************************************/
471 /* Connection pass through functions */
472 /*************************************/
475 * These functions act as adaptors to their counterparts in connection. They
476 * can produce one additional type of error, the bad_connection error, that
477 * indicates that the conversion from connection_hdl to connection_ptr
478 * failed due to the connection not existing anymore. Each method has a
479 * default and an exception free varient.
482 void interrupt(connection_hdl hdl, lib::error_code & ec);
483 void interrupt(connection_hdl hdl);
485 /// Pause reading of new data (exception free)
487 * Signals to the connection to halt reading of new data. While reading is
488 * paused, the connection will stop reading from its associated socket. In
489 * turn this will result in TCP based flow control kicking in and slowing
490 * data flow from the remote endpoint.
492 * This is useful for applications that push new requests to a queue to be
493 * processed by another thread and need a way to signal when their request
494 * queue is full without blocking the network processing thread.
496 * Use `resume_reading()` to resume.
498 * If supported by the transport this is done asynchronously. As such
499 * reading may not stop until the current read operation completes.
500 * Typically you can expect to receive no more bytes after initiating a read
501 * pause than the size of the read buffer.
503 * If reading is paused for this connection already nothing is changed.
505 void pause_reading(connection_hdl hdl, lib::error_code & ec);
507 /// Pause reading of new data
508 void pause_reading(connection_hdl hdl);
510 /// Resume reading of new data (exception free)
512 * Signals to the connection to resume reading of new data after it was
513 * paused by `pause_reading()`.
515 * If reading is not paused for this connection already nothing is changed.
517 void resume_reading(connection_hdl hdl, lib::error_code & ec);
519 /// Resume reading of new data
520 void resume_reading(connection_hdl hdl);
522 /// Send deferred HTTP Response
524 * Sends an http response to an HTTP connection that was deferred. This will
525 * send a complete response including all headers, status line, and body
526 * text. The connection will be closed afterwards.
528 * Exception free variant
532 * @param hdl The connection to send the response on
533 * @param ec A status code, zero on success, non-zero otherwise
535 void send_http_response(connection_hdl hdl, lib::error_code & ec);
537 /// Send deferred HTTP Response (exception free)
539 * Sends an http response to an HTTP connection that was deferred. This will
540 * send a complete response including all headers, status line, and body
541 * text. The connection will be closed afterwards.
547 * @param hdl The connection to send the response on
549 void send_http_response(connection_hdl hdl);
551 /// Create a message and add it to the outgoing send queue (exception free)
553 * Convenience method to send a message given a payload string and an opcode
555 * @param [in] hdl The handle identifying the connection to send via.
556 * @param [in] payload The payload string to generated the message with
557 * @param [in] op The opcode to generated the message with.
558 * @param [out] ec A code to fill in for errors
560 void send(connection_hdl hdl, std::string const & payload,
561 frame::opcode::value op, lib::error_code & ec);
562 /// Create a message and add it to the outgoing send queue
564 * Convenience method to send a message given a payload string and an opcode
566 * @param [in] hdl The handle identifying the connection to send via.
567 * @param [in] payload The payload string to generated the message with
568 * @param [in] op The opcode to generated the message with.
569 * @param [out] ec A code to fill in for errors
571 void send(connection_hdl hdl, std::string const & payload,
572 frame::opcode::value op);
574 void send(connection_hdl hdl, void const * payload, size_t len,
575 frame::opcode::value op, lib::error_code & ec);
576 void send(connection_hdl hdl, void const * payload, size_t len,
577 frame::opcode::value op);
579 void send(connection_hdl hdl, message_ptr msg, lib::error_code & ec);
580 void send(connection_hdl hdl, message_ptr msg);
582 void close(connection_hdl hdl, close::status::value const code,
583 std::string const & reason, lib::error_code & ec);
584 void close(connection_hdl hdl, close::status::value const code,
585 std::string const & reason);
587 /// Send a ping to a specific connection
589 * @since 0.3.0-alpha3
591 * @param [in] hdl The connection_hdl of the connection to send to.
592 * @param [in] payload The payload string to send.
593 * @param [out] ec A reference to an error code to fill in
595 void ping(connection_hdl hdl, std::string const & payload,
596 lib::error_code & ec);
597 /// Send a ping to a specific connection
599 * Exception variant of `ping`
601 * @since 0.3.0-alpha3
603 * @param [in] hdl The connection_hdl of the connection to send to.
604 * @param [in] payload The payload string to send.
606 void ping(connection_hdl hdl, std::string const & payload);
608 /// Send a pong to a specific connection
610 * @since 0.3.0-alpha3
612 * @param [in] hdl The connection_hdl of the connection to send to.
613 * @param [in] payload The payload string to send.
614 * @param [out] ec A reference to an error code to fill in
616 void pong(connection_hdl hdl, std::string const & payload,
617 lib::error_code & ec);
618 /// Send a pong to a specific connection
620 * Exception variant of `pong`
622 * @since 0.3.0-alpha3
624 * @param [in] hdl The connection_hdl of the connection to send to.
625 * @param [in] payload The payload string to send.
627 void pong(connection_hdl hdl, std::string const & payload);
629 /// Retrieves a connection_ptr from a connection_hdl (exception free)
631 * Converting a weak pointer to shared_ptr is not thread safe because the
632 * pointer could be deleted at any time.
634 * NOTE: This method may be called by handler to upgrade its handle to a
635 * full connection_ptr. That full connection may then be used safely for the
636 * remainder of the handler body. get_con_from_hdl and the resulting
637 * connection_ptr are NOT safe to use outside the handler loop.
639 * @param hdl The connection handle to translate
641 * @return the connection_ptr. May be NULL if the handle was invalid.
643 connection_ptr get_con_from_hdl(connection_hdl hdl, lib::error_code & ec) {
644 connection_ptr con = lib::static_pointer_cast<connection_type>(
647 ec = error::make_error_code(error::bad_connection);
652 /// Retrieves a connection_ptr from a connection_hdl (exception version)
653 connection_ptr get_con_from_hdl(connection_hdl hdl) {
655 connection_ptr con = this->get_con_from_hdl(hdl,ec);
662 connection_ptr create_connection();
668 std::string m_user_agent;
670 open_handler m_open_handler;
671 close_handler m_close_handler;
672 fail_handler m_fail_handler;
673 ping_handler m_ping_handler;
674 pong_handler m_pong_handler;
675 pong_timeout_handler m_pong_timeout_handler;
676 interrupt_handler m_interrupt_handler;
677 http_handler m_http_handler;
678 validate_handler m_validate_handler;
679 message_handler m_message_handler;
681 long m_open_handshake_timeout_dur;
682 long m_close_handshake_timeout_dur;
683 long m_pong_timeout_dur;
684 size_t m_max_message_size;
685 size_t m_max_http_body_size;
690 bool const m_is_server;
693 mutable mutex_type m_mutex;
696 } // namespace websocketpp
698 #include <websocketpp/impl/endpoint_impl.hpp>
700 #endif // WEBSOCKETPP_ENDPOINT_HPP