28 #ifndef WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP
29 #define WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP
31 #include <websocketpp/common/cpp11.hpp>
32 #include <websocketpp/common/memory.hpp>
33 #include <websocketpp/common/functional.hpp>
34 #include <websocketpp/common/connection_hdl.hpp>
35 #include <websocketpp/logger/levels.hpp>
36 #include <websocketpp/http/constants.hpp>
37 #include <websocketpp/transport/asio/base.hpp>
38 #include <websocketpp/transport/base/connection.hpp>
40 #include <websocketpp/base64/base64.hpp>
41 #include <websocketpp/error.hpp>
43 #include <boost/asio.hpp>
44 #include <boost/system/error_code.hpp>
53 typedef lib::function<void(connection_hdl)> tcp_init_handler;
61 template <
typename config>
62 class connection :
public config::socket_type::socket_con_type {
67 typedef lib::shared_ptr<type>
ptr;
78 typedef typename config::request_type request_type;
79 typedef typename request_type::ptr request_ptr;
80 typedef typename config::response_type response_type;
81 typedef typename response_type::ptr response_ptr;
86 typedef lib::shared_ptr<boost::asio::io_service::strand>
strand_ptr;
88 typedef lib::shared_ptr<boost::asio::deadline_timer>
timer_ptr;
96 explicit connection(
bool is_server, alog_type& alog, elog_type& elog)
97 : m_is_server(is_server)
106 return lib::static_pointer_cast<type>(socket_con_type::get_shared());
109 bool is_secure()
const {
110 return socket_con_type::is_secure();
124 m_tcp_pre_init_handler = h;
153 m_tcp_post_init_handler = h;
172 m_proxy_data.reset(
new proxy_data());
173 ec = lib::error_code();
180 if (ec) {
throw ec; }
197 std::string & password, lib::error_code & ec)
205 std::string val =
"Basic "+base64_encode(username +
":" + password);
206 m_proxy_data->req.replace_header(
"Proxy-Authorization",val);
207 ec = lib::error_code();
212 std::string & password)
216 if (ec) {
throw ec; }
235 m_proxy_data->timeout_proxy = duration;
236 ec = lib::error_code();
243 if (ec) {
throw ec; }
246 const std::string & get_proxy()
const {
263 std::string ret = socket_con_type::get_remote_endpoint(ec);
275 return m_connection_hdl;
294 new boost::asio::deadline_timer(
296 boost::posix_time::milliseconds(duration)
300 if (config::enable_multithreading) {
301 new_timer->async_wait(m_strand->wrap(lib::bind(
305 lib::placeholders::_1
308 new_timer->async_wait(lib::bind(
312 lib::placeholders::_1
331 boost::system::error_code
const & ec)
334 if (ec == boost::asio::error::operation_aborted) {
341 callback(lib::error_code());
375 m_init_handler = callback;
377 socket_con_type::pre_init(
379 &type::handle_pre_init,
381 lib::placeholders::_1
396 return websocketpp::error::make_error_code(
399 m_proxy_data->req.set_version(
"HTTP/1.1");
400 m_proxy_data->req.set_method(
"CONNECT");
402 m_proxy_data->req.set_uri(authority);
403 m_proxy_data->req.replace_header(
"Host",authority);
405 return lib::error_code();
419 m_io_service = io_service;
421 if (config::enable_multithreading) {
422 m_strand.reset(
new boost::asio::strand(*io_service));
424 m_async_read_handler = m_strand->wrap(lib::bind(
425 &type::handle_async_read,
get_shared(),lib::placeholders::_1,
426 lib::placeholders::_2));
428 m_async_write_handler = m_strand->wrap(lib::bind(
429 &type::handle_async_write,
get_shared(),lib::placeholders::_1,
430 lib::placeholders::_2));
432 m_async_read_handler = lib::bind(&type::handle_async_read,
433 get_shared(), lib::placeholders::_1, lib::placeholders::_2);
435 m_async_write_handler = lib::bind(&type::handle_async_write,
436 get_shared(), lib::placeholders::_1, lib::placeholders::_2);
439 lib::error_code ec = socket_con_type::init_asio(io_service, m_strand,
445 m_async_read_handler = _WEBSOCKETPP_NULLPTR_TOKEN_;
446 m_async_write_handler = _WEBSOCKETPP_NULLPTR_TOKEN_;
452 void handle_pre_init(lib::error_code
const & ec) {
457 if (m_tcp_pre_init_handler) {
458 m_tcp_pre_init_handler(m_connection_hdl);
467 if (!m_proxy.empty()) {
479 timer_ptr post_timer;
481 if (config::timeout_socket_post_init > 0) {
483 config::timeout_socket_post_init,
485 &type::handle_post_init_timeout,
489 lib::placeholders::_1
494 socket_con_type::post_init(
496 &type::handle_post_init,
500 lib::placeholders::_1
505 void handle_post_init_timeout(timer_ptr post_timer,
init_handler callback,
506 lib::error_code
const & ec)
508 lib::error_code ret_ec;
513 "asio post init timer cancelled");
520 if (socket_con_type::get_ec()) {
521 ret_ec = socket_con_type::get_ec();
528 socket_con_type::cancel_socket();
532 void handle_post_init(timer_ptr post_timer,
init_handler callback,
533 lib::error_code
const & ec)
536 (post_timer && post_timer->expires_from_now().is_negative()))
543 post_timer->cancel();
550 if (m_tcp_post_init_handler) {
551 m_tcp_post_init_handler(m_connection_hdl);
564 "assertion failed: !m_proxy_data in asio::connection::proxy_write");
569 m_proxy_data->write_buf = m_proxy_data->req.raw();
571 m_bufs.push_back(boost::asio::buffer(m_proxy_data->write_buf.data(),
572 m_proxy_data->write_buf.size()));
578 m_proxy_data->timeout_proxy,
580 &type::handle_proxy_timeout,
583 lib::placeholders::_1
588 if (config::enable_multithreading) {
589 boost::asio::async_write(
590 socket_con_type::get_next_layer(),
592 m_strand->wrap(lib::bind(
595 lib::placeholders::_1
599 boost::asio::async_write(
600 socket_con_type::get_next_layer(),
605 lib::placeholders::_1
611 void handle_proxy_timeout(
init_handler callback, lib::error_code
const & ec)
615 "asio handle_proxy_write timer cancelled");
622 "asio handle_proxy_write timer expired");
623 socket_con_type::cancel_socket();
629 boost::system::error_code
const & ec)
633 "asio connection handle_proxy_write");
641 if (ec == boost::asio::error::operation_aborted ||
642 m_proxy_data->timer->expires_from_now().is_negative())
650 m_proxy_data->timer->cancel();
655 proxy_read(callback);
665 "assertion failed: !m_proxy_data in asio::connection::proxy_read");
666 m_proxy_data->timer->cancel();
671 if (config::enable_multithreading) {
672 boost::asio::async_read_until(
673 socket_con_type::get_next_layer(),
674 m_proxy_data->read_buf,
676 m_strand->wrap(lib::bind(
679 lib::placeholders::_1, lib::placeholders::_2
683 boost::asio::async_read_until(
684 socket_con_type::get_next_layer(),
685 m_proxy_data->read_buf,
690 lib::placeholders::_1, lib::placeholders::_2
697 boost::system::error_code
const & ec,
size_t bytes_transferred)
701 "asio connection handle_proxy_read");
707 if (ec == boost::asio::error::operation_aborted ||
708 m_proxy_data->timer->expires_from_now().is_negative())
715 m_proxy_data->timer->cancel();
719 "asio handle_proxy_read error: "+ec.message());
724 "assertion failed: !m_proxy_data in asio::connection::handle_proxy_read");
729 std::istream input(&m_proxy_data->read_buf);
731 m_proxy_data->res.consume(input);
733 if (!m_proxy_data->res.headers_ready()) {
742 if (m_proxy_data->res.get_status_code() != http::status_code::ok) {
747 s <<
"Proxy connection error: "
748 << m_proxy_data->res.get_status_code()
750 << m_proxy_data->res.get_status_msg()
766 m_proxy_data.reset();
783 s <<
"asio async_read_at_least: " << num_bytes;
787 if (!m_async_read_handler) {
789 "async_read_at_least called after async_shutdown");
804 m_read_handler = handler;
806 if (!m_read_handler) {
808 "asio con async_read_at_least called with bad handler");
811 boost::asio::async_read(
812 socket_con_type::get_socket(),
813 boost::asio::buffer(buf,len),
814 boost::asio::transfer_at_least(num_bytes),
815 make_custom_alloc_handler(
816 m_read_handler_allocator,
822 void handle_async_read(boost::system::error_code
const & ec,
823 size_t bytes_transferred)
829 if (ec == boost::asio::error::eof) {
834 tec = socket_con_type::translate_ec(ec);
845 if (m_read_handler) {
846 m_read_handler(tec,bytes_transferred);
853 "handle_async_read called with null read handler");
857 void async_write(
const char* buf,
size_t len,
write_handler handler) {
858 if (!m_async_write_handler) {
860 "async_write (single) called after async_shutdown");
865 m_bufs.push_back(boost::asio::buffer(buf,len));
867 m_write_handler = handler;
869 boost::asio::async_write(
870 socket_con_type::get_socket(),
872 make_custom_alloc_handler(
873 m_write_handler_allocator,
874 m_async_write_handler
879 void async_write(
const std::vector<buffer>& bufs,
write_handler handler) {
880 if (!m_async_write_handler) {
882 "async_write (vector) called after async_shutdown");
886 std::vector<buffer>::const_iterator it;
888 for (it = bufs.begin(); it != bufs.end(); ++it) {
889 m_bufs.push_back(boost::asio::buffer((*it).buf,(*it).len));
892 m_write_handler = handler;
894 boost::asio::async_write(
895 socket_con_type::get_socket(),
897 make_custom_alloc_handler(
898 m_write_handler_allocator,
899 m_async_write_handler
904 void handle_async_write(boost::system::error_code
const & ec,
905 size_t bytes_transferred)
913 if (m_write_handler) {
914 m_write_handler(tec);
921 "handle_async_write called with null write handler");
933 m_connection_hdl = hdl;
934 socket_con_type::set_handle(hdl);
942 if (config::enable_multithreading) {
943 m_io_service->post(m_strand->wrap(handler));
945 m_io_service->post(handler);
947 return lib::error_code();
951 if (config::enable_multithreading) {
952 m_io_service->post(m_strand->wrap(handler));
954 m_io_service->post(handler);
956 return lib::error_code();
972 m_async_read_handler = _WEBSOCKETPP_NULLPTR_TOKEN_;
973 m_async_write_handler = _WEBSOCKETPP_NULLPTR_TOKEN_;
974 m_init_handler = _WEBSOCKETPP_NULLPTR_TOKEN_;
976 m_read_handler = _WEBSOCKETPP_NULLPTR_TOKEN_;
977 m_write_handler = _WEBSOCKETPP_NULLPTR_TOKEN_;
979 timer_ptr shutdown_timer;
981 config::timeout_socket_shutdown,
983 &type::handle_async_shutdown_timeout,
987 lib::placeholders::_1
991 socket_con_type::async_shutdown(
993 &type::handle_async_shutdown,
997 lib::placeholders::_1
1002 void handle_async_shutdown_timeout(timer_ptr shutdown_timer,
init_handler
1003 callback, lib::error_code
const & ec)
1005 lib::error_code ret_ec;
1010 "asio socket shutdown timer cancelled");
1021 "Asio transport socket shutdown timed out");
1022 socket_con_type::cancel_socket();
1027 callback, boost::system::error_code
const & ec)
1029 if (ec == boost::asio::error::operation_aborted ||
1030 shutdown_timer->expires_from_now().is_negative())
1036 shutdown_timer->cancel();
1038 lib::error_code tec;
1040 if (ec == boost::asio::error::not_connected) {
1048 tec = socket_con_type::translate_ec(ec);
1065 "asio con handle_async_shutdown");
1072 template <
typename error_type>
1073 void log_err(log::level l,
const char * msg,
const error_type & ec) {
1074 std::stringstream s;
1075 s << msg <<
" error: " << ec <<
" (" << ec.message() <<
")";
1076 m_elog.write(l,s.str());
1080 const bool m_is_server;
1085 proxy_data() : timeout_proxy(config::timeout_proxy) {}
1089 std::string write_buf;
1090 boost::asio::streambuf read_buf;
1095 std::string m_proxy;
1096 lib::shared_ptr<proxy_data> m_proxy_data;
1099 io_service_ptr m_io_service;
1100 strand_ptr m_strand;
1103 std::vector<boost::asio::const_buffer> m_bufs;
1106 tcp_init_handler m_tcp_pre_init_handler;
1107 tcp_init_handler m_tcp_post_init_handler;
1109 handler_allocator m_read_handler_allocator;
1110 handler_allocator m_write_handler_allocator;
1116 async_read_handler m_async_read_handler;
1117 async_write_handler m_async_write_handler;
1125 #endif // WEBSOCKETPP_TRANSPORT_ASIO_CON_HPP
void handle_timer(timer_ptr t, timer_handler callback, boost::system::error_code const &ec)
Timer callback.
void set_proxy_basic_auth(const std::string &username, const std::string &password, lib::error_code &ec)
Set the basic auth credentials to use (exception free)
config::elog_type elog_type
Type of this transport's error logging policy.
void set_proxy(const std::string &uri, lib::error_code &ec)
Set the proxy to connect through (exception free)
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.
boost::asio::io_service * io_service_ptr
Type of a pointer to the ASIO io_service being used.
socket_con_type::ptr socket_con_ptr
Type of a shared pointer to the socket connection component.
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.
lib::shared_ptr< boost::asio::io_service::strand > strand_ptr
Type of a pointer to the ASIO io_service::strand being used.
underlying transport pass through
void init(init_handler callback)
Initialize transport for reading.
connection_hdl get_handle() const
Get the connection handle.
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.
timer_ptr set_timer(long duration, timer_handler callback)
Call back a function after a period of time.
config::alog_type alog_type
Type of this transport's access logging policy.
lib::function< void()> dispatch_handler
The type and signature of the callback passed to the dispatch method.
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::shared_ptr< boost::asio::deadline_timer > timer_ptr
Type of a pointer to the ASIO timer class.
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.
Boost Asio based connection transport component.
void set_proxy(const std::string &uri)
Set the proxy to connect through (exception)
Boost Asio based endpoint transport component.
void set_proxy_basic_auth(const std::string &username, const std::string &password)
Set the basic auth credentials to use (exception)
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 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 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.