28 #ifndef WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP
29 #define WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP
31 #include <websocketpp/transport/asio/base.hpp>
33 #include <websocketpp/transport/base/connection.hpp>
35 #include <websocketpp/logger/levels.hpp>
36 #include <websocketpp/http/constants.hpp>
38 #include <websocketpp/base64/base64.hpp>
39 #include <websocketpp/error.hpp>
40 #include <websocketpp/uri.hpp>
42 #include <websocketpp/common/asio.hpp>
43 #include <websocketpp/common/chrono.hpp>
44 #include <websocketpp/common/cpp11.hpp>
45 #include <websocketpp/common/memory.hpp>
46 #include <websocketpp/common/functional.hpp>
47 #include <websocketpp/common/connection_hdl.hpp>
58 typedef lib::function<void(connection_hdl)> tcp_init_handler;
66 template <
typename config>
67 class connection :
public config::socket_type::socket_con_type {
72 typedef lib::shared_ptr<type>
ptr;
83 typedef typename config::request_type request_type;
84 typedef typename request_type::ptr request_ptr;
85 typedef typename config::response_type response_type;
86 typedef typename response_type::ptr response_ptr;
91 typedef lib::shared_ptr<lib::asio::io_service::strand>
strand_ptr;
93 typedef lib::shared_ptr<lib::asio::steady_timer>
timer_ptr;
101 explicit connection(
bool is_server, alog_type & alog, elog_type & elog)
102 : m_is_server(is_server)
111 return lib::static_pointer_cast<type>(socket_con_type::get_shared());
114 bool is_secure()
const {
115 return socket_con_type::is_secure();
131 socket_con_type::set_uri(u);
145 m_tcp_pre_init_handler = h;
174 m_tcp_post_init_handler = h;
193 m_proxy_data = lib::make_shared<proxy_data>();
194 ec = lib::error_code();
218 password, lib::error_code & ec)
226 std::string val =
"Basic "+
base64_encode(username +
":" + password);
227 m_proxy_data->req.replace_header(
"Proxy-Authorization",val);
228 ec = lib::error_code();
256 m_proxy_data->timeout_proxy = duration;
257 ec = lib::error_code();
267 std::string
const & get_proxy()
const {
284 std::string ret = socket_con_type::get_remote_endpoint(ec);
296 return m_connection_hdl;
314 timer_ptr new_timer = lib::make_shared<lib::asio::steady_timer>(
315 lib::ref(*m_io_service),
316 lib::asio::milliseconds(duration)
319 if (config::enable_multithreading) {
320 new_timer->async_wait(m_strand->wrap(lib::bind(
324 lib::placeholders::_1
327 new_timer->async_wait(lib::bind(
331 lib::placeholders::_1
350 lib::asio::error_code
const & ec)
353 if (ec == lib::asio::error::operation_aborted) {
360 callback(lib::error_code());
395 m_init_handler = callback;
397 socket_con_type::pre_init(
399 &type::handle_pre_init,
401 lib::placeholders::_1
416 return websocketpp::error::make_error_code(
419 m_proxy_data->req.set_version(
"HTTP/1.1");
420 m_proxy_data->req.set_method(
"CONNECT");
422 m_proxy_data->req.set_uri(authority);
423 m_proxy_data->req.replace_header(
"Host",authority);
425 return lib::error_code();
439 m_io_service = io_service;
441 if (config::enable_multithreading) {
442 m_strand = lib::make_shared<lib::asio::strand>(
443 lib::ref(*io_service));
445 m_async_read_handler = m_strand->wrap(lib::bind(
446 &type::handle_async_read,
get_shared(),lib::placeholders::_1,
447 lib::placeholders::_2));
449 m_async_write_handler = m_strand->wrap(lib::bind(
451 lib::placeholders::_2));
453 m_async_read_handler = lib::bind(&type::handle_async_read,
454 get_shared(), lib::placeholders::_1, lib::placeholders::_2);
457 get_shared(), lib::placeholders::_1, lib::placeholders::_2);
460 lib::error_code ec = socket_con_type::init_asio(io_service, m_strand,
466 lib::clear_function(m_async_read_handler);
467 lib::clear_function(m_async_write_handler);
473 void handle_pre_init(lib::error_code
const & ec) {
478 if (m_tcp_pre_init_handler) {
479 m_tcp_pre_init_handler(m_connection_hdl);
488 if (!m_proxy.empty()) {
500 timer_ptr post_timer;
502 if (config::timeout_socket_post_init > 0) {
504 config::timeout_socket_post_init,
510 lib::placeholders::_1
515 socket_con_type::post_init(
521 lib::placeholders::_1
536 lib::error_code
const & ec)
538 lib::error_code ret_ec;
543 "asio post init timer cancelled");
550 if (socket_con_type::get_ec()) {
551 ret_ec = socket_con_type::get_ec();
558 socket_con_type::cancel_socket();
572 lib::error_code
const & ec)
575 (post_timer && lib::asio::is_neg(post_timer->expires_from_now())))
582 post_timer->cancel();
589 if (m_tcp_post_init_handler) {
590 m_tcp_post_init_handler(m_connection_hdl);
603 "assertion failed: !m_proxy_data in asio::connection::proxy_write");
608 m_proxy_data->write_buf = m_proxy_data->req.raw();
610 m_bufs.push_back(lib::asio::buffer(m_proxy_data->write_buf.data(),
611 m_proxy_data->write_buf.size()));
617 m_proxy_data->timeout_proxy,
619 &type::handle_proxy_timeout,
622 lib::placeholders::_1
627 if (config::enable_multithreading) {
628 lib::asio::async_write(
629 socket_con_type::get_next_layer(),
631 m_strand->wrap(lib::bind(
634 lib::placeholders::_1
638 lib::asio::async_write(
639 socket_con_type::get_next_layer(),
644 lib::placeholders::_1
650 void handle_proxy_timeout(
init_handler callback, lib::error_code
const & ec)
654 "asio handle_proxy_write timer cancelled");
661 "asio handle_proxy_write timer expired");
662 socket_con_type::cancel_socket();
668 lib::asio::error_code
const & ec)
672 "asio connection handle_proxy_write");
680 if (ec == lib::asio::error::operation_aborted ||
681 lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))
689 m_proxy_data->timer->cancel();
694 proxy_read(callback);
704 "assertion failed: !m_proxy_data in asio::connection::proxy_read");
705 m_proxy_data->timer->cancel();
710 if (config::enable_multithreading) {
711 lib::asio::async_read_until(
712 socket_con_type::get_next_layer(),
713 m_proxy_data->read_buf,
715 m_strand->wrap(lib::bind(
718 lib::placeholders::_1, lib::placeholders::_2
722 lib::asio::async_read_until(
723 socket_con_type::get_next_layer(),
724 m_proxy_data->read_buf,
729 lib::placeholders::_1, lib::placeholders::_2
742 lib::asio::error_code
const & ec,
size_t)
746 "asio connection handle_proxy_read");
752 if (ec == lib::asio::error::operation_aborted ||
753 lib::asio::is_neg(m_proxy_data->timer->expires_from_now()))
760 m_proxy_data->timer->cancel();
764 "asio handle_proxy_read error: "+ec.message());
769 "assertion failed: !m_proxy_data in asio::connection::handle_proxy_read");
774 std::istream input(&m_proxy_data->read_buf);
776 m_proxy_data->res.consume(input);
778 if (!m_proxy_data->res.headers_ready()) {
787 if (m_proxy_data->res.get_status_code() != http::status_code::ok) {
792 s <<
"Proxy connection error: "
793 << m_proxy_data->res.get_status_code()
795 << m_proxy_data->res.get_status_msg()
811 m_proxy_data.reset();
828 s <<
"asio async_read_at_least: " << num_bytes;
832 if (!m_async_read_handler) {
834 "async_read_at_least called after async_shutdown");
849 m_read_handler = handler;
851 if (!m_read_handler) {
853 "asio con async_read_at_least called with bad handler");
856 lib::asio::async_read(
857 socket_con_type::get_socket(),
858 lib::asio::buffer(buf,len),
859 lib::asio::transfer_at_least(num_bytes),
860 make_custom_alloc_handler(
861 m_read_handler_allocator,
867 void handle_async_read(lib::asio::error_code
const & ec,
868 size_t bytes_transferred)
874 if (ec == lib::asio::error::eof) {
879 tec = socket_con_type::translate_ec(ec);
890 if (m_read_handler) {
891 m_read_handler(tec,bytes_transferred);
898 "handle_async_read called with null read handler");
902 void async_write(
const char* buf,
size_t len,
write_handler handler) {
903 if (!m_async_write_handler) {
905 "async_write (single) called after async_shutdown");
910 m_bufs.push_back(lib::asio::buffer(buf,len));
912 m_write_handler = handler;
914 lib::asio::async_write(
915 socket_con_type::get_socket(),
917 make_custom_alloc_handler(
918 m_write_handler_allocator,
919 m_async_write_handler
924 void async_write(std::vector<buffer>
const & bufs,
write_handler handler) {
925 if (!m_async_write_handler) {
927 "async_write (vector) called after async_shutdown");
931 std::vector<buffer>::const_iterator it;
933 for (it = bufs.begin(); it != bufs.end(); ++it) {
934 m_bufs.push_back(lib::asio::buffer((*it).buf,(*it).len));
937 m_write_handler = handler;
939 lib::asio::async_write(
940 socket_con_type::get_socket(),
942 make_custom_alloc_handler(
943 m_write_handler_allocator,
944 m_async_write_handler
961 if (m_write_handler) {
962 m_write_handler(tec);
969 "handle_async_write called with null write handler");
981 m_connection_hdl = hdl;
982 socket_con_type::set_handle(hdl);
990 if (config::enable_multithreading) {
991 m_io_service->post(m_strand->wrap(handler));
993 m_io_service->post(handler);
995 return lib::error_code();
999 if (config::enable_multithreading) {
1000 m_io_service->post(m_strand->wrap(handler));
1002 m_io_service->post(handler);
1004 return lib::error_code();
1020 lib::clear_function(m_async_read_handler);
1021 lib::clear_function(m_async_write_handler);
1022 lib::clear_function(m_init_handler);
1024 lib::clear_function(m_read_handler);
1025 lib::clear_function(m_write_handler);
1027 timer_ptr shutdown_timer;
1029 config::timeout_socket_shutdown,
1035 lib::placeholders::_1
1039 socket_con_type::async_shutdown(
1041 &type::handle_async_shutdown,
1045 lib::placeholders::_1
1057 lib::error_code
const & ec)
1059 lib::error_code ret_ec;
1064 "asio socket shutdown timer cancelled");
1075 "Asio transport socket shutdown timed out");
1076 socket_con_type::cancel_socket();
1081 callback, lib::asio::error_code
const & ec)
1083 if (ec == lib::asio::error::operation_aborted ||
1084 lib::asio::is_neg(shutdown_timer->expires_from_now()))
1090 shutdown_timer->cancel();
1092 lib::error_code tec;
1094 if (ec == lib::asio::error::not_connected) {
1102 tec = socket_con_type::translate_ec(ec);
1119 "asio con handle_async_shutdown");
1126 template <
typename error_type>
1127 void log_err(log::level l,
const char * msg,
const error_type & ec) {
1128 std::stringstream s;
1129 s << msg <<
" error: " << ec <<
" (" << ec.message() <<
")";
1130 m_elog.write(l,s.str());
1134 const bool m_is_server;
1139 proxy_data() : timeout_proxy(config::timeout_proxy) {}
1143 std::string write_buf;
1144 lib::asio::streambuf read_buf;
1149 std::string m_proxy;
1150 lib::shared_ptr<proxy_data> m_proxy_data;
1153 io_service_ptr m_io_service;
1154 strand_ptr m_strand;
1157 std::vector<lib::asio::const_buffer> m_bufs;
1160 tcp_init_handler m_tcp_pre_init_handler;
1161 tcp_init_handler m_tcp_post_init_handler;
1163 handler_allocator m_read_handler_allocator;
1164 handler_allocator m_write_handler_allocator;
1170 async_read_handler m_async_read_handler;
1171 async_write_handler m_async_write_handler;
1179 #endif // WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP
Asio based endpoint transport component.
config::elog_type elog_type
Type of this transport's error logging policy.
void set_proxy_basic_auth(std::string const &username, std::string const &password, lib::error_code &ec)
Set the basic auth credentials to use (exception free)
lib::asio::io_service * io_service_ptr
Type of a pointer to the Asio io_service being used.
void set_tcp_pre_init_handler(tcp_init_handler h)
Sets the tcp pre init handler.
strand_ptr get_strand()
Get a pointer to this connection's strand.
lib::function< void(lib::error_code const &)> write_handler
The type and signature of the callback passed to the write method.
static level const devel
Low level debugging information (warning: very chatty)
lib::weak_ptr< void > connection_hdl
A handle to uniquely identify a connection.
socket_con_type::ptr socket_con_ptr
Type of a shared pointer to the socket connection component.
void handle_post_init_timeout(timer_ptr, init_handler callback, lib::error_code const &ec)
Post init timeout callback.
lib::function< void()> interrupt_handler
The type and signature of the callback passed to the interrupt method.
lib::shared_ptr< type > ptr
Type of a shared pointer to this connection transport component.
lib::function< void(lib::error_code const &, size_t)> read_handler
The type and signature of the callback passed to the read method.
std::string base64_encode(unsigned char const *input, size_t len)
Encode a char buffer into a base64 string.
underlying transport pass through
void init(init_handler callback)
Initialize transport for reading.
connection_hdl get_handle() const
Get the connection handle.
void handle_async_shutdown_timeout(timer_ptr, init_handler callback, lib::error_code const &ec)
Async shutdown timeout handler.
void set_tcp_post_init_handler(tcp_init_handler h)
Sets the tcp post init handler.
static level const devel
Development messages (warning: very chatty)
std::string get_remote_endpoint() const
Get the remote endpoint address.
void handle_timer(timer_ptr, timer_handler callback, lib::asio::error_code const &ec)
Timer callback.
timer_ptr set_timer(long duration, timer_handler callback)
Call back a function after a period of time.
void set_proxy(std::string const &uri, lib::error_code &ec)
Set the proxy to connect through (exception free)
config::alog_type alog_type
Type of this transport's access logging policy.
lib::shared_ptr< lib::asio::io_service::strand > strand_ptr
Type of a pointer to the Asio io_service::strand being used.
lib::function< void()> dispatch_handler
The type and signature of the callback passed to the dispatch method.
void handle_proxy_read(init_handler callback, lib::asio::error_code const &ec, size_t)
Proxy read callback.
The connection was in the wrong state for this operation.
lib::error_code interrupt(interrupt_handler handler)
Trigger the on_interrupt handler.
void set_proxy_timeout(long duration, lib::error_code &ec)
Set the proxy timeout duration (exception free)
lib::function< void(lib::error_code const &)> timer_handler
The type and signature of the callback passed to the read method.
there was an error in the underlying transport library
lib::function< void(lib::error_code const &)> shutdown_handler
The type and signature of the callback passed to the shutdown method.
Namespace for the WebSocket++ project.
void set_proxy_timeout(long duration)
Set the proxy timeout duration (exception)
lib::function< void(lib::error_code const &)> init_handler
The type and signature of the callback passed to the init hook.
void handle_async_write(lib::asio::error_code const &ec, size_t)
Async write callback.
Asio based connection transport component.
lib::shared_ptr< uri > uri_ptr
Pointer to a URI.
lib::shared_ptr< lib::asio::steady_timer > timer_ptr
Type of a pointer to the Asio timer class.
The connection to the requested proxy server failed.
ptr get_shared()
Get a shared pointer to this component.
connection< config > type
Type of this connection transport component.
void handle_post_init(timer_ptr post_timer, init_handler callback, lib::error_code const &ec)
Post init timeout callback.
void async_shutdown(shutdown_handler callback)
close and clean up the underlying socket
lib::error_code proxy_init(std::string const &authority)
initialize the proxy buffers and http parsers
read or write after shutdown
lib::error_code init_asio(io_service_ptr io_service)
Finish constructing the transport.
config::socket_type::socket_con_type socket_con_type
Type of the socket connection component.
void set_proxy(std::string const &uri)
Set the proxy to connect through (exception)
void async_read_at_least(size_t num_bytes, char *buf, size_t len, read_handler handler)
read at least num_bytes bytes into buf and then call handler.
void set_tcp_init_handler(tcp_init_handler h)
Sets the tcp pre init handler (deprecated)
static level const library
void set_handle(connection_hdl hdl)
Set Connection Handle.
void set_uri(uri_ptr u)
Set uri hook.
void set_proxy_basic_auth(std::string const &username, std::string const &password)
Set the basic auth credentials to use (exception)