@@ -982,7 +982,7 @@ namespace net_utils
982982 boost::uuids::random_generator ()(),
983983 *real_remote,
984984 is_income,
985- connection_basic::m_ssl_support == ssl_support_t ::e_ssl_support_enabled
985+ connection_basic::m_ssl_support
986986 );
987987 m_host = real_remote->host_str ();
988988 try { host_count (1 ); } catch (...) { /* ignore */ }
@@ -1709,7 +1709,7 @@ namespace net_utils
17091709 }
17101710 // ---------------------------------------------------------------------------------
17111711 template <class t_protocol_handler >
1712- typename boosted_tcp_server<t_protocol_handler>::try_connect_result_t boosted_tcp_server<t_protocol_handler>::try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_support_t ssl_support )
1712+ typename boosted_tcp_server<t_protocol_handler>::try_connect_result_t boosted_tcp_server<t_protocol_handler>::try_connect(connection_ptr new_connection_l, const std::string& adr, const std::string& port, boost::asio::ip::tcp::socket &sock_, const boost::asio::ip::tcp::endpoint &remote_endpoint, const std::string &bind_ip, uint32_t conn_timeout, epee::net_utils::ssl_options_t & ssl_options )
17131713 {
17141714 TRY_ENTRY ();
17151715
@@ -1785,7 +1785,7 @@ namespace net_utils
17851785 {
17861786 // Handshake
17871787 MDEBUG (" Handshaking SSL..." );
1788- if (!new_connection_l->handshake (boost::asio::ssl::stream_base::client ))
1788+ if (!new_connection_l->client_handshake (ssl_options ))
17891789 {
17901790 if (ssl_support == epee::net_utils::ssl_support_t ::e_ssl_support_autodetect)
17911791 {
@@ -1799,6 +1799,7 @@ namespace net_utils
17991799 sock_.close ();
18001800 return CONNECT_FAILURE ;
18011801 }
1802+ new_connection_l->set_ssl_enabled ();
18021803 }
18031804
18041805 return CONNECT_SUCCESS ;
@@ -1807,11 +1808,11 @@ namespace net_utils
18071808 }
18081809 // ---------------------------------------------------------------------------------
18091810 template <class t_protocol_handler >
1810- bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support )
1811+ bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, const std::string& port, uint32_t conn_timeout, t_connection_context& conn_context, const std::string& bind_ip, epee::net_utils::ssl_options_t ssl_options )
18111812 {
18121813 TRY_ENTRY ();
18131814
1814- connection_ptr new_connection_l (new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support ) );
1815+ connection_ptr new_connection_l (new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_options. support ) );
18151816 connections_mutex.lock ();
18161817 connections_.insert (new_connection_l);
18171818 MDEBUG (" connections_ size now " << connections_.size ());
@@ -1899,24 +1900,22 @@ namespace net_utils
18991900 // boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port);
19001901 boost::asio::ip::tcp::endpoint remote_endpoint (*iterator);
19011902
1902- auto try_connect_result = try_connect (new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_support );
1903+ auto try_connect_result = try_connect (new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_options );
19031904 if (try_connect_result == CONNECT_FAILURE )
19041905 return false ;
1905- if (ssl_support == epee::net_utils::ssl_support_t ::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL )
1906+ if (ssl_options. support == epee::net_utils::ssl_support_t ::e_ssl_support_autodetect && try_connect_result == CONNECT_NO_SSL )
19061907 {
19071908 // we connected, but could not connect with SSL, try without
19081909 MERROR (" SSL handshake failed on an autodetect connection, reconnecting without SSL" );
19091910 new_connection_l->disable_ssl ();
1910- try_connect_result = try_connect (new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, epee::net_utils::ssl_support_t ::e_ssl_support_disabled);
1911+ ssl_options = epee::net_utils::ssl_support_t ::e_ssl_support_disabled;
1912+ try_connect_result = try_connect (new_connection_l, adr, port, sock_, remote_endpoint, bind_ip_to_use, conn_timeout, ssl_options);
19111913 if (try_connect_result != CONNECT_SUCCESS )
19121914 return false ;
19131915 }
19141916
19151917 // start adds the connection to the config object's list, so we don't need to have it locally anymore
1916- connections_mutex.lock ();
1917- connections_.erase (new_connection_l);
1918- connections_mutex.unlock ();
1919- bool r = new_connection_l->start (false , 1 < m_threads_count);
1918+ bool r = remove_connection (new_connection_l) && new_connection_l->start (false , 1 < m_threads_count);
19201919 if (r)
19211920 {
19221921 new_connection_l->get_context (conn_context);
@@ -1935,10 +1934,10 @@ namespace net_utils
19351934 }
19361935 // ---------------------------------------------------------------------------------
19371936 template <class t_protocol_handler > template <class t_callback >
1938- bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, const std::chrono::milliseconds conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_support_t ssl_support , t_connection_context&& initial)
1937+ bool boosted_tcp_server<t_protocol_handler>::connect_async(const std::string& adr, const std::string& port, const std::chrono::milliseconds conn_timeout, const t_callback &cb, const std::string& bind_ip, epee::net_utils::ssl_options_t ssl_options , t_connection_context&& initial)
19391938 {
19401939 TRY_ENTRY ();
1941- connection_ptr new_connection_l (new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_support , std::move (initial)) );
1940+ connection_ptr new_connection_l (new connection<t_protocol_handler>(io_context_, m_state, m_connection_type, ssl_options. support , std::move (initial)) );
19421941 connections_mutex.lock ();
19431942 connections_.insert (new_connection_l);
19441943 MDEBUG (" connections_ size now " << connections_.size ());
@@ -2015,60 +2014,117 @@ namespace net_utils
20152014 return false ;
20162015 }
20172016 }
2018-
2019- std::shared_ptr<boost::asio::steady_timer> sh_deadline (std::make_shared<boost::asio::steady_timer>(io_context_));
2020- // start deadline
2021- sh_deadline->expires_after (conn_timeout);
2022- sh_deadline->async_wait ([=](const boost::system::error_code& error)
2017+
2018+ ssl_options.configure (new_connection_l->socket_ , boost::asio::ssl::stream_base::client);
2019+ return connect_async_internal (new_connection_l, remote_endpoint, conn_timeout, cb);
2020+ CATCH_ENTRY_L0 (" boosted_tcp_server<t_protocol_handler>::connect_async" , false );
2021+ }
2022+
2023+ template <class t_protocol_handler > template <class t_callback >
2024+ bool boosted_tcp_server<t_protocol_handler>::connect_async_internal(const connection_ptr& new_connection_l, const boost::asio::ip::tcp::endpoint& remote_endpoint, const std::chrono::milliseconds conn_timeout, const t_callback &cb)
2025+ {
2026+ if (!new_connection_l)
2027+ return false ;
2028+
2029+ TRY_ENTRY ();
2030+
2031+ const auto on_timer = [=](boost::system::error_code error)
20232032 {
2024- if (error != boost::asio::error::operation_aborted)
2025- {
2026- _dbg3 (" Failed to connect to " << adr << ' :' << port << " , because of timeout (" << conn_timeout.count () << " )" );
2027- new_connection_l->socket ().close ();
2028- }
2029- });
2030- // start async connect
2031- sock_.async_connect (remote_endpoint, [=](const boost::system::error_code& ec_)
2033+ if (error != boost::asio::error::operation_aborted)
2034+ {
2035+ _dbg3 (" Failed to connect to " << remote_endpoint << " , because of timeout (" << conn_timeout.count () << " ms)" );
2036+ new_connection_l->socket ().close (error); // ignore errors
2037+ }
2038+ };
2039+
2040+ auto sh_deadline = std::make_shared<boost::asio::steady_timer>(io_context_);
2041+ sh_deadline->expires_after (conn_timeout);
2042+ sh_deadline->async_wait (new_connection_l->wrap (on_timer));
2043+
2044+ new_connection_l->socket ().async_connect (remote_endpoint, new_connection_l->wrap ([=](const boost::system::error_code& ec_)
20322045 {
2033- t_connection_context conn_context = AUTO_VAL_INIT (conn_context);
2034- boost::system::error_code ignored_ec;
2035- boost::asio::ip::tcp::socket::endpoint_type lep = new_connection_l->socket ().local_endpoint (ignored_ec);
2046+ const auto on_cancel = [=](const boost::system::error_code& error)
2047+ {
2048+ boost::system::error_code ignored_ec{};
2049+ const auto lep = new_connection_l->socket ().local_endpoint (ignored_ec);
2050+ _dbg3 (" [sock " << new_connection_l->socket ().native_handle () << " ] to " << remote_endpoint << " from " << lep << " failed: " << error.message ());
2051+ if (remove_connection (new_connection_l))
2052+ cb (t_connection_context{}, error);
2053+ };
2054+
20362055 if (!ec_)
20372056 {// success
2038- if (!sh_deadline->cancel ())
2039- {
2040- cb (conn_context, boost::asio::error::operation_aborted);// this mean that deadline timer already queued callback with cancel operation, rare situation
2041- }else
2042- {
2043- _dbg3 (" [sock " << new_connection_l->socket ().native_handle () << " ] Connected success to " << adr << ' :' << port <<
2044- " from " << lep.address ().to_string () << ' :' << lep.port ());
2045-
2046- // start adds the connection to the config object's list, so we don't need to have it locally anymore
2047- connections_mutex.lock ();
2048- connections_.erase (new_connection_l);
2049- connections_mutex.unlock ();
2050- bool r = new_connection_l->start (false , 1 < m_threads_count);
2051- if (r)
2057+ const auto on_ready = [=] ()
20522058 {
2053- new_connection_l->get_context (conn_context);
2054- cb (conn_context, ec_);
2055- }
2056- else
2059+ if (sh_deadline->cancel ())
2060+ {
2061+ boost::system::error_code ignored_ec{};
2062+ const auto lep = new_connection_l->socket ().local_endpoint (ignored_ec);
2063+ _dbg3 (" [sock " << new_connection_l->socket ().native_handle () << " ] Connected successfully to " << remote_endpoint <<
2064+ " from " << lep.address ().to_string () << ' :' << lep.port ());
2065+
2066+ if (remove_connection (new_connection_l) && new_connection_l->start (false , 1 < m_threads_count))
2067+ {
2068+ t_connection_context conn_context{};
2069+ new_connection_l->get_context (conn_context);
2070+ cb (conn_context, ec_);
2071+ }
2072+ else
2073+ on_cancel (boost::asio::error::fault);
2074+ }
2075+ else // if timer already expired
2076+ on_cancel (boost::asio::error::operation_aborted);
2077+ };
2078+
2079+ if (new_connection_l->get_ssl_support () != ssl_support_t ::e_ssl_support_disabled)
2080+ {
2081+ // set new timer for handshake
2082+ if (sh_deadline->expires_after (conn_timeout))
20572083 {
2058- _dbg3 (" [sock " << new_connection_l->socket ().native_handle () << " ] Failed to start connection to " << adr << ' :' << port);
2059- cb (conn_context, boost::asio::error::fault);
2084+ sh_deadline->async_wait (new_connection_l->wrap (on_timer));
2085+ new_connection_l->socket_ .async_handshake (boost::asio::ssl::stream_base::client, new_connection_l->wrap ([=] (const boost::system::error_code& ec)
2086+ {
2087+ if (ec)
2088+ {
2089+ sh_deadline->cancel ();
2090+ if (new_connection_l->get_ssl_support () == ssl_support_t ::e_ssl_support_autodetect)
2091+ {
2092+ _dbg3 (" [sock " << new_connection_l->socket ().native_handle () << " ] SSL connection to " <<
2093+ remote_endpoint << " failed: " << ec.message () << " . Trying without SSL" );
2094+ new_connection_l->disable_ssl ();
2095+ connect_async_internal (new_connection_l, remote_endpoint, conn_timeout, cb);
2096+ }
2097+ else // ssl mandatory and failed
2098+ on_cancel (ec);
2099+ }
2100+ else // ssl handshake complete
2101+ {
2102+ new_connection_l->set_ssl_enabled ();
2103+ on_ready ();
2104+ }
2105+ }));
20602106 }
2107+ else // if timer already expired
2108+ on_cancel (boost::asio::error::operation_aborted);
20612109 }
2062- }else
2063- {
2064- _dbg3 (" [sock " << new_connection_l->socket ().native_handle () << " ] Failed to connect to " << adr << ' :' << port <<
2065- " from " << lep.address ().to_string () << ' :' << lep.port () << " : " << ec_.message () << ' :' << ec_.value ());
2066- cb (conn_context, ec_);
2110+ else // ssl disabled
2111+ on_ready ();
20672112 }
2068- });
2113+ else // ec_ has error
2114+ on_cancel (ec_);
2115+ }));
2116+ return true ;
2117+ CATCH_ENTRY_L0 (" boosted_tcp_server<t_protocol_handler>::connect_async_internal" , false );
2118+ }
2119+
2120+ template <class t_protocol_handler >
2121+ bool boosted_tcp_server<t_protocol_handler>::remove_connection(const connection_ptr& new_connection)
2122+ {
2123+ if (!new_connection)
2124+ return false ;
2125+ const boost::lock_guard<boost::mutex> sync{connections_mutex};
2126+ connections_.erase (new_connection);
20692127 return true ;
2070- CATCH_ENTRY_L0 (" boosted_tcp_server<t_protocol_handler>::connect_async" , false );
20712128 }
2072-
20732129} // namespace
20742130} // namespace
0 commit comments