diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp index 8d0901d87..bea1e2f90 100644 --- a/include/libtorrent/config.hpp +++ b/include/libtorrent/config.hpp @@ -422,11 +422,11 @@ inline int snprintf(char* buf, int len, char const* fmt, ...) #endif #if !defined(TORRENT_READ_HANDLER_MAX_SIZE) -# define TORRENT_READ_HANDLER_MAX_SIZE 256 +# define TORRENT_READ_HANDLER_MAX_SIZE 300 #endif #if !defined(TORRENT_WRITE_HANDLER_MAX_SIZE) -# define TORRENT_WRITE_HANDLER_MAX_SIZE 256 +# define TORRENT_WRITE_HANDLER_MAX_SIZE 300 #endif #if defined _MSC_VER && _MSC_VER <= 1200 diff --git a/include/libtorrent/instantiate_connection.hpp b/include/libtorrent/instantiate_connection.hpp index cd19d2ef9..26c96a1f3 100644 --- a/include/libtorrent/instantiate_connection.hpp +++ b/include/libtorrent/instantiate_connection.hpp @@ -42,9 +42,7 @@ namespace libtorrent struct utp_socket_manager; struct socket_type; - // if from is specified, a new socket will be created - // using the same underlying socket object as 'from'. - // this can be used to "upgrade" a socket into an SSL socket + // instantiate a socket_type (s) according to the specified criteria TORRENT_EXTRA_EXPORT bool instantiate_connection(io_service& ios , proxy_settings const& ps, socket_type& s , void* ssl_context = 0 diff --git a/include/libtorrent/socket_type.hpp b/include/libtorrent/socket_type.hpp index 7de256d5e..0faeef9e1 100644 --- a/include/libtorrent/socket_type.hpp +++ b/include/libtorrent/socket_type.hpp @@ -295,8 +295,15 @@ namespace libtorrent size_type m_data[(storage_size + sizeof(size_type) - 1) / sizeof(size_type)]; }; + // returns true if this socket is an SSL socket bool is_ssl(socket_type const& s); + // assuming the socket_type s is an ssl socket, make sure it + // verifies the hostname in its SSL handshake + void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec); + + // properly shuts down SSL sockets. holder keeps s alive + void async_shutdown(socket_type& s, boost::shared_ptr holder); } #endif diff --git a/src/http_connection.cpp b/src/http_connection.cpp index 25235d24e..8a9e9c3ab 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -37,15 +37,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/parse_url.hpp" #include "libtorrent/socket.hpp" #include "libtorrent/connection_queue.hpp" +#include "libtorrent/socket_type.hpp" // for async_shutdown #if defined TORRENT_ASIO_DEBUGGING #include "libtorrent/debug.hpp" #endif -#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700 -#include -#endif - #include #include #include @@ -92,10 +89,6 @@ http_connection::http_connection(io_service& ios, connection_queue& cc , m_abort(false) { TORRENT_ASSERT(!m_handler.empty()); - // TODO: if we were handed an SSL context, we should really - // verify the hostname of the web server as well. This is supported - // in boost starting with version 1.47.0. See ssl::rfc2818_verification - // and ssl::context::set_verify_callback } http_connection::~http_connection() @@ -262,7 +255,7 @@ void http_connection::start(std::string const& hostname, std::string const& port m_ssl = ssl; m_bind_addr = bind_addr; error_code ec; - m_sock.close(ec); + if (m_sock.is_open()) m_sock.close(ec); #if TORRENT_USE_I2P bool is_i2p = false; @@ -340,30 +333,13 @@ void http_connection::start(std::string const& hostname, std::string const& port } } -#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700 - // for SSL connections, make sure to authenticate the hostname - // of the certificate -#define CASE(t) case socket_type_int_impl >::value: \ - m_sock.get >()->set_verify_callback(asio::ssl::rfc2818_verification(hostname), ec); \ - break; - - switch(m_sock.type()) - { - CASE(stream_socket) - CASE(socks5_stream) - CASE(http_stream) - CASE(utp_stream) - } - + setup_ssl_hostname(m_sock, hostname, ec); if (ec) { m_resolver.get_io_service().post(boost::bind(&http_connection::callback , me, ec, (char*)0, 0)); return; } -#undef CASE - -#endif #if TORRENT_USE_I2P if (is_i2p) @@ -443,7 +419,7 @@ void http_connection::on_timeout(boost::weak_ptr p add_outstanding_async("http_connection::on_timeout"); #endif error_code ec; - c->m_sock.close(ec); + async_shutdown(c->m_sock, c); c->m_timer.expires_at((std::min)( c->m_last_receive + c->m_read_timeout , c->m_start_time + c->m_completion_timeout), ec); @@ -470,11 +446,15 @@ void http_connection::on_timeout(boost::weak_ptr p void http_connection::close() { + if (m_abort) return; + error_code ec; m_timer.cancel(ec); m_resolver.cancel(); m_limiter_timer.cancel(ec); - m_sock.close(ec); + + async_shutdown(m_sock, shared_from_this()); + m_hostname.clear(); m_port.clear(); m_handler.clear(); @@ -812,6 +792,10 @@ void http_connection::on_read(error_code const& e } error_code ec; + // it would be nice to gracefully shut down SSL here + // but then we'd have to do all the reconnect logic + // in its handler. For now, just kill the connection. +// async_shutdown(m_sock, shared_from_this()); m_sock.close(ec); using boost::tuples::ignore; boost::tie(ignore, ignore, ignore, ignore, ignore) diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index a0597f702..61328f357 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -3489,15 +3489,6 @@ namespace libtorrent return; } - void on_close_socket(boost::shared_ptr const& s) - { -#if defined TORRENT_ASIO_DEBUGGING - complete_async("on_close_socket"); -#endif - error_code ec; - s->close(ec); - } - // the error argument defaults to 0, which means deliberate disconnect // 1 means unexpected disconnect/error // 2 protocol error (client sent something invalid) @@ -3711,29 +3702,7 @@ namespace libtorrent m_disconnecting = true; error_code e; -#ifdef TORRENT_USE_OPENSSL - // for SSL connections, first do an async_shutdown, before closing the socket -#if defined TORRENT_ASIO_DEBUGGING -#define MAYBE_ASIO_DEBUGGING add_outstanding_async("on_close_socket"); -#else -#define MAYBE_ASIO_DEBUGGING -#endif -#define CASE(t) case socket_type_int_impl >::value: \ - MAYBE_ASIO_DEBUGGING \ - m_socket->get >()->async_shutdown(boost::bind(&on_close_socket, m_socket)); \ - break; - switch(m_socket->type()) - { - CASE(stream_socket) - CASE(socks5_stream) - CASE(http_stream) - CASE(utp_stream) - default: m_socket->close(e); break; - } -#undef CASE -#else - m_socket->close(e); -#endif // TORRENT_USE_OPENSSL + async_shutdown(*m_socket, m_socket); m_ses.close_connection(this, ec); diff --git a/src/socket_type.cpp b/src/socket_type.cpp index 7bfdf0a6a..a84dc1187 100644 --- a/src/socket_type.cpp +++ b/src/socket_type.cpp @@ -34,6 +34,11 @@ POSSIBILITY OF SUCH DAMAGE. #ifdef TORRENT_USE_OPENSSL #include + +#if BOOST_VERSION >= 104700 +#include +#endif + #endif namespace libtorrent @@ -58,6 +63,76 @@ namespace libtorrent #endif } + void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec) + { +#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700 + // for SSL connections, make sure to authenticate the hostname + // of the certificate +#define CASE(t) case socket_type_int_impl >::value: \ + s.get >()->set_verify_callback(asio::ssl::rfc2818_verification(hostname), ec); \ + ctx = SSL_get_SSL_CTX(s.get >()->native_handle()); \ + break; + + SSL_CTX* ctx = 0; + + switch(s.type()) + { + CASE(stream_socket) + CASE(socks5_stream) + CASE(http_stream) + CASE(utp_stream) + } +#undef CASE + + if (ctx) + { + SSL_CTX_set_tlsext_servername_callback(ctx, 0); + SSL_CTX_set_tlsext_servername_arg(ctx, 0); + } +#endif + } + + void on_close_socket(socket_type* s, boost::shared_ptr holder) + { +#if defined TORRENT_ASIO_DEBUGGING + complete_async("on_close_socket"); +#endif + error_code ec; + s->close(ec); + } + + // the second argument is a shared pointer to an object that + // will keep the socket (s) alive for the duration of the async operation + void async_shutdown(socket_type& s, boost::shared_ptr holder) + { + error_code e; + +#ifdef TORRENT_USE_OPENSSL + // for SSL connections, first do an async_shutdown, before closing the socket +#if defined TORRENT_ASIO_DEBUGGING +#define MAYBE_ASIO_DEBUGGING add_outstanding_async("on_close_socket"); +#else +#define MAYBE_ASIO_DEBUGGING +#endif +#define CASE(t) case socket_type_int_impl >::value: \ + MAYBE_ASIO_DEBUGGING \ + s.get >()->async_shutdown(boost::bind(&on_close_socket, &s, holder)); \ + break; + + switch(s.type()) + { + CASE(stream_socket) + CASE(socks5_stream) + CASE(http_stream) + CASE(utp_stream) + default: s.close(e); break; + } +#undef CASE +#else + s.close(e); +#endif // TORRENT_USE_OPENSSL + } + void socket_type::destruct() { switch (m_type) diff --git a/src/torrent.cpp b/src/torrent.cpp index 169f0aca9..83c0bc276 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -86,7 +86,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/ssl_stream.hpp" #include #if BOOST_VERSION >= 104700 -#include #include #endif // BOOST_VERSION #endif // TORRENT_USE_OPENSSL @@ -4655,28 +4654,13 @@ namespace libtorrent str->set_dst_name(hostname); } -#if defined TORRENT_USE_OPENSSL && BOOST_VERSION >= 104700 - // for SSL connections, make sure to authenticate the hostname - // of the certificate -#define CASE(t) case socket_type_int_impl >::value: \ - s->get >()->set_verify_callback(asio::ssl::rfc2818_verification(hostname), ec); \ - break; - - switch(s->type()) - { - CASE(stream_socket) - CASE(socks5_stream) - CASE(http_stream) - CASE(utp_stream) - } + setup_ssl_hostname(*s, hostname, ec); if (ec) { if (m_ses.m_alerts.should_post()) m_ses.m_alerts.post_alert(url_seed_alert(get_handle(), web->url, ec)); return; } -#undef CASE -#endif boost::intrusive_ptr c; if (web->type == web_seed_entry::url_seed) diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index cb0230d4a..ae2b565fa 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -600,7 +600,7 @@ int start_web_server(bool ssl, bool chunked_encoding) system("echo test city >> tmp"); system("echo test company >> tmp"); system("echo test department >> tmp"); - system("echo tester >> tmp"); + system("echo 127.0.0.1 >> tmp"); system("echo test@test.com >> tmp"); system("openssl req -new -x509 -keyout server.pem -out server.pem " "-days 365 -nodes