adjust transport async_accept and async_connect to use connection_ptr instead of connection_hdl

prevents a newly created connection_ptr from being destroyed
immediately after accepting or connecting.
This commit is contained in:
Peter Thorson
2013-10-06 10:51:41 -05:00
parent 96f7d0f3f2
commit b934e71ace
8 changed files with 106 additions and 129 deletions

View File

@@ -156,14 +156,12 @@ struct mock_endpoint : public websocketpp::transport::asio::endpoint<config> {
&mock_endpoint::handle_connect,
this,
m_con,
websocketpp::lib::placeholders::_1,
websocketpp::lib::placeholders::_2
websocketpp::lib::placeholders::_1
)
);
}
void handle_connect(connection_ptr con, websocketpp::connection_hdl,
const websocketpp::lib::error_code & ec)
void handle_connect(connection_ptr con, websocketpp::lib::error_code const & ec)
{
BOOST_CHECK( !ec );
con->start();

View File

@@ -66,8 +66,7 @@ public:
explicit client() : endpoint_type(false)
{
endpoint_type::m_alog.write(log::alevel::devel,
"client constructor");
endpoint_type::m_alog.write(log::alevel::devel, "client constructor");
}
/// Get a new connection
@@ -77,15 +76,17 @@ public:
* applying connection specific settings before performing the opening
* handshake.
*
* @param [in] location URI to open the connection to as a uri_ptr
* @param [out] ec An status code indicating failure reasons, if any
*
* @return A connection_ptr to the new connection
*/
connection_ptr get_connection(uri_ptr location, lib::error_code &ec) {
connection_ptr get_connection(uri_ptr location, lib::error_code & ec) {
if (location->get_secure() && !transport_type::is_secure()) {
ec = error::make_error_code(error::endpoint_not_secure);
return connection_ptr();
}
// create connection
connection_ptr con = endpoint_type::create_connection();
if (!con) {
@@ -95,7 +96,6 @@ public:
con->set_uri(location);
// Success
ec = lib::error_code();
return con;
}
@@ -106,10 +106,12 @@ public:
* suitable for passing to connect(connection_ptr). This overload allows
* default construction of the uri_ptr from a standard string.
*
* @param [in] u URI to open the connection to as a string
* @param [out] ec An status code indicating failure reasons, if any
*
* @return A connection_ptr to the new connection
*/
connection_ptr get_connection(const std::string& u, lib::error_code &ec) {
// parse uri
connection_ptr get_connection(std::string const & u, lib::error_code & ec) {
uri_ptr location(new uri(u));
if (!location->get_valid()) {
@@ -137,35 +139,17 @@ public:
lib::bind(
&type::handle_connect,
this,
lib::placeholders::_1,
lib::placeholders::_2
con,
lib::placeholders::_1
)
);
return con;
}
// connect(...)
private:
// handle_connect
void handle_connect(connection_hdl hdl, const lib::error_code & ec) {
lib::error_code hdl_ec;
connection_ptr con = endpoint_type::get_con_from_hdl(hdl,hdl_ec);
if (hdl_ec == error::bad_connection) {
endpoint_type::m_elog.write(log::elevel::fatal,
"handle_connect got an invalid handle back");
} else if (hdl_ec) {
// There was some other unknown error attempting to convert the hdl
// to a connection.
endpoint_type::m_elog.write(log::elevel::fatal,
"handle_connect error in get_con_from_hdl: "+hdl_ec.message());
//con->terminate();
} else if (ec) {
// TODO
// Set connection's failure reasons
void handle_connect(connection_ptr con, lib::error_code const & ec) {
if (ec) {
con->terminate(ec);
endpoint_type::m_elog.write(log::elevel::rerror,

View File

@@ -90,37 +90,20 @@ public:
lib::bind(
&type::handle_accept,
this,
lib::placeholders::_1,
lib::placeholders::_2
con,
lib::placeholders::_1
)
);
}
void handle_accept(connection_hdl hdl, const lib::error_code& ec) {
lib::error_code hdl_ec;
connection_ptr con = endpoint_type::get_con_from_hdl(hdl,hdl_ec);
void handle_accept(connection_ptr con, const lib::error_code& ec) {
if (ec) {
con->terminate(ec);
if (hdl_ec == error::bad_connection) {
// The connection we were trying to connect went out of scope
// This really shouldn't happen
endpoint_type::m_elog.write(log::elevel::fatal,
"handle_accept got an invalid handle back");
//con->terminate();
} else if (hdl_ec) {
// There was some other unknown error attempting to convert the hdl
// to a connection.
endpoint_type::m_elog.write(log::elevel::fatal,
"handle_accept error in get_con_from_hdl: "+hdl_ec.message());
//con->terminate();
endpoint_type::m_elog.write(log::elevel::rerror,
"handle_accept error: "+ec.message());
} else {
if (ec) {
con->terminate(ec);
endpoint_type::m_elog.write(log::elevel::rerror,
"handle_accept error: "+ec.message());
} else {
con->start();
}
con->start();
}
// TODO: are there cases where we should terminate this loop?

View File

@@ -45,6 +45,11 @@ namespace transport {
*/
namespace asio {
// Forward declaration of class endpoint so that it can be friended/referenced
// before being included.
template <typename config>
class endpoint;
typedef lib::function<void(boost::system::error_code const &)>
socket_shutdown_handler;

View File

@@ -84,6 +84,11 @@ public:
/// Type of a pointer to the ASIO timer class
typedef lib::shared_ptr<boost::asio::deadline_timer> timer_ptr;
// connection is friends with its associated endpoint to allow the endpoint
// to call private/protected utility methods that we don't want to expose
// to the public api.
friend class endpoint<config>;
// generate and manage our own io_service
explicit connection(bool is_server, alog_type& alog, elog_type& elog)
: m_is_server(is_server)
@@ -102,29 +107,13 @@ public:
return socket_con_type::is_secure();
}
/// Finish constructing the transport
/// Sets the tcp init handler
/**
* init_asio is called once immediately after construction to initialize
* boost::asio components to the io_service
* The tcp init handler is called after the tcp connection has been
* established.
*
* TODO: this method is not protected because the endpoint needs to call it.
* need to figure out if there is a way to friend the endpoint safely across
* different compilers.
*
* @param io_service A pointer to the io_service to register with this
* connection
*
* @return Status code for the success or failure of the initialization
* @param h The handler to call on tcp init.
*/
lib::error_code init_asio (io_service_ptr io_service) {
// do we need to store or use the io_service at this level?
m_io_service = io_service;
//m_strand.reset(new boost::asio::strand(*io_service));
return socket_con_type::init_asio(io_service, m_is_server);
}
void set_tcp_init_handler(tcp_init_handler h) {
m_tcp_init_handler = h;
}
@@ -251,26 +240,6 @@ public:
return m_connection_hdl;
}
/// initialize the proxy buffers and http parsers
/**
*
* @param authority The address of the server we want the proxy to tunnel to
* in the format of a URI authority (host:port)
*/
lib::error_code proxy_init(const std::string & authority) {
if (!m_proxy_data) {
return websocketpp::error::make_error_code(
websocketpp::error::invalid_state);
}
m_proxy_data->req.set_version("HTTP/1.1");
m_proxy_data->req.set_method("CONNECT");
m_proxy_data->req.set_uri(authority);
m_proxy_data->req.replace_header("Host",authority);
return lib::error_code();
}
/// Call back a function after a period of time.
/**
* Sets a timer that calls back a function after the specified period of
@@ -311,10 +280,10 @@ public:
* The timer pointer is included to ensure the timer isn't destroyed until
* after it has expired.
*
* TODO: candidate for protected status
*
* @param t Pointer to the timer in question
*
* @param callback The function to call back
*
* @param ec The status code
*/
void handle_timer(timer_ptr t, timer_handler callback, const
@@ -367,6 +336,47 @@ protected:
);
}
/// initialize the proxy buffers and http parsers
/**
*
* @param authority The address of the server we want the proxy to tunnel to
* in the format of a URI authority (host:port)
*
* @return Status code indicating what errors occurred, if any
*/
lib::error_code proxy_init(std::string const & authority) {
if (!m_proxy_data) {
return websocketpp::error::make_error_code(
websocketpp::error::invalid_state);
}
m_proxy_data->req.set_version("HTTP/1.1");
m_proxy_data->req.set_method("CONNECT");
m_proxy_data->req.set_uri(authority);
m_proxy_data->req.replace_header("Host",authority);
return lib::error_code();
}
/// Finish constructing the transport
/**
* init_asio is called once immediately after construction to initialize
* boost::asio components to the io_service
*
* @param io_service A pointer to the io_service to register with this
* connection
*
* @return Status code for the success or failure of the initialization
*/
lib::error_code init_asio (io_service_ptr io_service) {
// do we need to store or use the io_service at this level?
m_io_service = io_service;
//m_strand.reset(new boost::asio::strand(*io_service));
return socket_con_type::init_asio(io_service, m_is_server);
}
void handle_pre_init(init_handler callback, const lib::error_code& ec) {
if (m_alog.static_test(log::alevel::devel)) {
m_alog.write(log::alevel::devel,"asio connection handle pre_init");

View File

@@ -577,7 +577,6 @@ public:
lib::bind(
&type::handle_accept,
this,
tcon->get_handle(),
callback,
lib::placeholders::_1
)
@@ -612,18 +611,19 @@ protected:
m_elog = e;
}
void handle_accept(connection_hdl hdl, accept_handler callback,
const boost::system::error_code& error)
void handle_accept(accept_handler callback, boost::system::error_code const
& boost_ec)
{
if (error) {
//con->terminate();
// TODO: Better translation of errors at this point
callback(hdl,make_error_code(error::pass_through));
return;
lib::error_code ret_ec;
m_alog->write(log::alevel::devel, "asio::handle_accept");
if (boost_ec) {
log_err(log::elevel::devel,"asio handle_accept",boost_ec);
ret_ec = make_error_code(error::pass_through);
}
//con->start();
callback(hdl,lib::error_code());
callback(ret_ec);
}
/// Initiate a new connection
@@ -649,13 +649,13 @@ protected:
uri_ptr pu(new uri(proxy));
if (!pu->get_valid()) {
cb(tcon->get_handle(),make_error_code(error::proxy_invalid));
cb(make_error_code(error::proxy_invalid));
return;
}
ec = tcon->proxy_init(u->get_authority());
if (ec) {
cb(tcon->get_handle(),ec);
cb(ec);
return;
}
@@ -677,7 +677,6 @@ protected:
lib::bind(
&type::handle_resolve_timeout,
this,
tcon,
dns_timer,
cb,
lib::placeholders::_1
@@ -698,8 +697,8 @@ protected:
);
}
void handle_resolve_timeout(transport_con_ptr tcon, timer_ptr dns_timer,
connect_handler callback, const lib::error_code & ec)
void handle_resolve_timeout(timer_ptr dns_timer, connect_handler callback,
lib::error_code const & ec)
{
lib::error_code ret_ec;
@@ -718,11 +717,11 @@ protected:
m_alog->write(log::alevel::devel,"DNS resolution timed out");
m_resolver->cancel();
callback(tcon->get_handle(),ret_ec);
callback(ret_ec);
}
void handle_resolve(transport_con_ptr tcon, timer_ptr dns_timer,
connect_handler callback, const boost::system::error_code& ec,
connect_handler callback, boost::system::error_code const & ec,
boost::asio::ip::tcp::resolver::iterator iterator)
{
if (ec == boost::asio::error::operation_aborted ||
@@ -736,7 +735,7 @@ protected:
if (ec) {
log_err(log::elevel::info,"asio async_resolve",ec);
callback(tcon->get_handle(),make_error_code(error::pass_through));
callback(make_error_code(error::pass_through));
return;
}
@@ -759,7 +758,7 @@ protected:
con_timer = set_timer(
config::timeout_connect,
lib::bind(
&type::handle_resolve_timeout,
&type::handle_connect_timeout,
this,
tcon,
con_timer,
@@ -783,7 +782,7 @@ protected:
}
void handle_connect_timeout(transport_con_ptr tcon, timer_ptr con_timer,
connect_handler callback, const lib::error_code & ec)
connect_handler callback, lib::error_code const & ec)
{
lib::error_code ret_ec;
@@ -802,11 +801,11 @@ protected:
m_alog->write(log::alevel::devel,"TCP connect timed out");
tcon->cancel_socket();
callback(tcon->get_handle(),ret_ec);
callback(ret_ec);
}
void handle_connect(transport_con_ptr tcon, timer_ptr con_timer,
connect_handler callback, const boost::system::error_code& ec)
connect_handler callback, boost::system::error_code const & ec)
{
if (ec == boost::asio::error::operation_aborted ||
con_timer->expires_from_now().is_negative())
@@ -819,7 +818,7 @@ protected:
if (ec) {
log_err(log::elevel::info,"asio async_connect",ec);
callback(tcon->get_handle(),make_error_code(error::pass_through));
callback(make_error_code(error::pass_through));
return;
}
@@ -828,7 +827,7 @@ protected:
"Async connect to "+tcon->get_remote_endpoint()+" successful.");
}
callback(tcon->get_handle(),lib::error_code());
callback(lib::error_code());
}
bool is_listening() const {

View File

@@ -71,12 +71,10 @@ namespace websocketpp {
namespace transport {
/// The type and signature of the callback passed to the accept method
typedef lib::function<void(connection_hdl, lib::error_code const &)>
accept_handler;
typedef lib::function<void(lib::error_code const &)> accept_handler;
/// The type and signature of the callback passed to the connect method
typedef lib::function<void(connection_hdl, lib::error_code const &)>
connect_handler;
typedef lib::function<void(lib::error_code const &)> connect_handler;
} // namespace transport
} // namespace websocketpp

View File

@@ -141,7 +141,7 @@ protected:
* @param cb The function to call back with the results when complete.
*/
void async_connect(transport_con_ptr tcon, uri_ptr u, connect_handler cb) {
cb(tcon->get_handle(),lib::error_code());
cb(lib::error_code());
}
/// Initialize a connection