From 56e81cb6eba858841812e85b1a690a51ce9903dd Mon Sep 17 00:00:00 2001 From: Peter Thorson Date: Sun, 9 Jun 2013 07:33:30 -0500 Subject: [PATCH] impliment close handshake timeouts references #226 --- test/transport/integration.cpp | 55 ++++++++++++++++++++++++++++ websocketpp/impl/connection_impl.hpp | 31 +++++++++++++++- 2 files changed, 84 insertions(+), 2 deletions(-) diff --git a/test/transport/integration.cpp b/test/transport/integration.cpp index dadc31d0b3..82a55f20ac 100644 --- a/test/transport/integration.cpp +++ b/test/transport/integration.cpp @@ -299,3 +299,58 @@ BOOST_AUTO_TEST_CASE( server_open_handshake_timeout ) { sthread.join(); } + +BOOST_AUTO_TEST_CASE( client_self_initiated_close_handshake_timeout ) { + server s; + client c; + + // on open server sleeps for longer than the timeout + // on open client sends close handshake + // client handshake timer should be triggered + s.set_open_handler(bind(&delay,::_1,1)); + s.set_close_handler(bind(&stop_on_close,&s,::_1)); + + c.set_open_handler(bind(&close,&c,::_1)); + c.set_close_handler(bind(&check_ec,&c, + websocketpp::error::close_handshake_timeout,::_1)); + + websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false)); + websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); + tthread.detach(); + + run_client(c, "http://localhost:9005",false); + + sthread.join(); +} + +BOOST_AUTO_TEST_CASE( client_peer_initiated_close_handshake_timeout ) { + // on open server sends close + // client should ack normally and then wait + // server leaves TCP connection open + // client handshake timer should be triggered + + // TODO: how to make a mock server that leaves the TCP connection open? +} + +BOOST_AUTO_TEST_CASE( server_self_initiated_close_handshake_timeout ) { + server s; + client c; + + // on open server sends close + // on open client sleeps for longer than the timeout + // server handshake timer should be triggered + + s.set_open_handler(bind(&close,&s,::_1)); + s.set_close_handler(bind(&check_ec_and_stop,&s, + websocketpp::error::close_handshake_timeout,::_1)); + + c.set_open_handler(bind(&delay,::_1,1)); + + websocketpp::lib::thread sthread(websocketpp::lib::bind(&run_server,&s,9005,false)); + websocketpp::lib::thread tthread(websocketpp::lib::bind(&run_test_timer,6)); + tthread.detach(); + + run_client(c, "http://localhost:9005",false); + + sthread.join(); +} diff --git a/websocketpp/impl/connection_impl.hpp b/websocketpp/impl/connection_impl.hpp index cc17b03eba..2429598a79 100644 --- a/websocketpp/impl/connection_impl.hpp +++ b/websocketpp/impl/connection_impl.hpp @@ -1368,7 +1368,17 @@ template void connection::handle_close_handshake_timeout( lib::error_code const & ec) { - + if (ec == transport::error::operation_aborted) { + m_alog.write(log::alevel::devel, + "asio close handshake timer cancelled"); + } else if (ec) { + m_alog.write(log::alevel::devel, + "asio open handle_close_handshake_timeout error: "+ec.message()); + // TODO: ignore or fail here? + } else { + m_alog.write(log::alevel::devel, "asio close handshake timer expired"); + terminate(make_error_code(error::close_handshake_timeout)); + } } template @@ -1376,7 +1386,13 @@ void connection::terminate(const lib::error_code & ec) { if (m_alog.static_test(log::alevel::devel)) { m_alog.write(log::alevel::devel,"connection terminate"); } - + + // Cancel close handshake timer + if (m_handshake_timer) { + m_handshake_timer->cancel(); + m_handshake_timer.reset(); + } + terminate_status tstat = unknown; if (ec) { m_ec = ec; @@ -1768,6 +1784,17 @@ lib::error_code connection::send_close_frame(close::status::value code, m_state = session::state::closing; + // Start a timer so we don't wait forever for the acknowledgement close + // frame + m_handshake_timer = transport_con_type::set_timer( + config::timeout_close_handshake, + lib::bind( + &type::handle_close_handshake_timeout, + type::shared_from_this(), + lib::placeholders::_1 + ) + ); + bool needs_writing = false; { scoped_lock_type lock(m_write_lock);