diff --git a/Jamfile b/Jamfile index 3b095f720..3571264b3 100755 --- a/Jamfile +++ b/Jamfile @@ -45,7 +45,7 @@ rule linking ( properties * ) } else { - result += crypto ; + result += crypto ssl ; } } @@ -210,6 +210,7 @@ lib thread : : boost_thread $(library-search-path) ; # openssl on linux/bsd/macos etc. lib crypto : : crypto ; +lib ssl : : ssl ; # time functions used on linux require librt lib librt : : rt ; diff --git a/include/libtorrent/http_connection.hpp b/include/libtorrent/http_connection.hpp index b65b303ae..4f0113e7b 100644 --- a/include/libtorrent/http_connection.hpp +++ b/include/libtorrent/http_connection.hpp @@ -45,6 +45,12 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/http_tracker_connection.hpp" #include "libtorrent/time.hpp" #include "libtorrent/assert.hpp" +#include "libtorrent/socket_type.hpp" + +#ifdef TORRENT_USE_OPENSSL +#include "libtorrent/ssl_stream.hpp" +#include "libtorrent/variant_stream.hpp" +#endif namespace libtorrent { @@ -57,6 +63,7 @@ typedef boost::function http_connect_handler; // TODO: add bind interface +// TODO: add gzip support // when bottled, the last two arguments to the handler // will always be 0 @@ -81,6 +88,7 @@ struct http_connection : boost::enable_shared_from_this, boost: , m_redirects(5) , m_connection_ticket(-1) , m_cc(cc) + , m_ssl(false) { TORRENT_ASSERT(!m_handler.empty()); } @@ -93,14 +101,20 @@ struct http_connection : boost::enable_shared_from_this, boost: std::string sendbuffer; void get(std::string const& url, time_duration timeout = seconds(30) - , int handle_redirects = 5); + , proxy_settings const* ps = 0, int handle_redirects = 5); void start(std::string const& hostname, std::string const& port - , time_duration timeout, int handle_redirect = 5); + , time_duration timeout, proxy_settings const* ps = 0, bool ssl = false + , int handle_redirect = 5); + void close(); - tcp::socket const& socket() const { return m_sock; } - +#ifdef TORRENT_USE_OPENSSL + variant_stream > const& socket() const { return m_sock; } +#else + socket_type const& socket() const { return m_sock; } +#endif + private: void on_resolve(asio::error_code const& e @@ -118,7 +132,11 @@ private: void callback(asio::error_code const& e, char const* data = 0, int size = 0); std::vector m_recvbuffer; - tcp::socket m_sock; +#ifdef TORRENT_USE_OPENSSL + variant_stream > m_sock; +#else + socket_type m_sock; +#endif int m_read_pos; tcp::resolver m_resolver; http_parser m_parser; @@ -158,6 +176,13 @@ private: int m_connection_ticket; connection_queue& m_cc; + + // specifies whether or not the connection is + // configured to use a proxy + proxy_settings m_proxy; + + // true if the connection is using ssl + bool m_ssl; }; } diff --git a/include/libtorrent/http_tracker_connection.hpp b/include/libtorrent/http_tracker_connection.hpp index a9521e886..cb1ce7fbd 100755 --- a/include/libtorrent/http_tracker_connection.hpp +++ b/include/libtorrent/http_tracker_connection.hpp @@ -63,6 +63,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/connection_queue.hpp" #include "libtorrent/http_parser.hpp" +#ifdef TORRENT_USE_OPENSSL +#include "libtorrent/ssl_stream.hpp" +#include "libtorrent/variant_stream.hpp" +#endif + namespace libtorrent { @@ -77,6 +82,7 @@ namespace libtorrent , connection_queue& cc , tracker_manager& man , tracker_request const& req + , std::string const& protocol , std::string const& hostname , unsigned short port , std::string request @@ -116,7 +122,12 @@ namespace libtorrent tcp::resolver m_name_lookup; int m_port; +#ifdef TORRENT_USE_OPENSSL + variant_stream > m_socket; + bool m_ssl; +#else socket_type m_socket; +#endif int m_recv_pos; std::vector m_buffer; std::string m_send_buffer; @@ -124,7 +135,7 @@ namespace libtorrent session_settings const& m_settings; proxy_settings const& m_proxy; std::string m_password; - + bool m_timed_out; int m_connection_ticket; diff --git a/include/libtorrent/proxy_base.hpp b/include/libtorrent/proxy_base.hpp index 153da5623..c7a10d9a1 100644 --- a/include/libtorrent/proxy_base.hpp +++ b/include/libtorrent/proxy_base.hpp @@ -141,25 +141,25 @@ public: } #ifndef BOOST_NO_EXCEPTIONS - endpoint_type remote_endpoint() + endpoint_type remote_endpoint() const { return m_remote_endpoint; } #endif - endpoint_type remote_endpoint(asio::error_code& ec) + endpoint_type remote_endpoint(asio::error_code& ec) const { return m_remote_endpoint; } #ifndef BOOST_NO_EXCEPTIONS - endpoint_type local_endpoint() + endpoint_type local_endpoint() const { return m_sock.local_endpoint(); } #endif - endpoint_type local_endpoint(asio::error_code& ec) + endpoint_type local_endpoint(asio::error_code& ec) const { return m_sock.local_endpoint(ec); } @@ -173,6 +173,8 @@ public: { return m_sock.lowest_layer(); } + + bool is_open() const { return m_sock.is_open(); } protected: diff --git a/include/libtorrent/ssl_stream.hpp b/include/libtorrent/ssl_stream.hpp new file mode 100644 index 000000000..b4cd62328 --- /dev/null +++ b/include/libtorrent/ssl_stream.hpp @@ -0,0 +1,224 @@ +/* + +Copyright (c) 2008, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_SSL_STREAM_HPP_INCLUDED +#define TORRENT_SSL_STREAM_HPP_INCLUDED + +#include "libtorrent/socket.hpp" +#include + +// openssl seems to believe it owns +// this name in every single scope +#undef set_key + +namespace libtorrent { + +template +class ssl_stream +{ +public: + + explicit ssl_stream(asio::io_service& io_service) + : m_context(io_service, asio::ssl::context::sslv23_client) + , m_sock(io_service, m_context) + { + m_context.set_verify_mode(asio::ssl::context::verify_none); + } + + typedef Stream next_layer_type; + typedef typename Stream::lowest_layer_type lowest_layer_type; + typedef typename Stream::endpoint_type endpoint_type; + typedef typename Stream::protocol_type protocol_type; + typedef typename asio::ssl::stream sock_type; + + typedef boost::function handler_type; + + template + void async_connect(endpoint_type const& endpoint, Handler const& handler) + { + // the connect is split up in the following steps: + // 1. connect to peer + // 2. perform SSL client handshake + + // to avoid unnecessary copying of the handler, + // store it in a shaed_ptr + boost::shared_ptr h(new handler_type(handler)); + + m_sock.next_layer().async_connect(endpoint + , boost::bind(&ssl_stream::connected, this, _1, h)); + } + + template + void async_read_some(Mutable_Buffers const& buffers, Handler const& handler) + { + m_sock.async_read_some(buffers, handler); + } + + template + std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec) + { + return m_sock.read_some(buffers, ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + template + std::size_t read_some(Mutable_Buffers const& buffers) + { + return m_sock.read_some(buffers); + } + + template + void io_control(IO_Control_Command& ioc) + { + m_sock.next_layer().io_control(ioc); + } +#endif + + template + void io_control(IO_Control_Command& ioc, asio::error_code& ec) + { + m_sock.next_layer().io_control(ioc, ec); + } + + template + void async_write_some(Const_Buffers const& buffers, Handler const& handler) + { + m_sock.async_write_some(buffers, handler); + } + +#ifndef BOOST_NO_EXCEPTIONS + void bind(endpoint_type const& endpoint) + { + m_sock.next_layer().bind(endpoint); + } +#endif + + void bind(endpoint_type const& endpoint, asio::error_code& ec) + { + m_sock.next_layer().bind(endpoint, ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + void open(protocol_type const& p) + { + m_sock.next_layer().open(p); + } +#endif + + void open(protocol_type const& p, asio::error_code& ec) + { + m_sock.next_layer().open(p, ec); + } + + bool is_open() const + { + return const_cast(m_sock).next_layer().is_open(); + } + +#ifndef BOOST_NO_EXCEPTIONS + void close() + { + m_sock.next_layer().close(); + } +#endif + + void close(asio::error_code& ec) + { + m_sock.next_layer().close(ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + endpoint_type remote_endpoint() const + { + return const_cast(m_sock).next_layer().remote_endpoint(); + } +#endif + + endpoint_type remote_endpoint(asio::error_code& ec) const + { + return const_cast(m_sock).next_layer().remote_endpoint(ec); + } + +#ifndef BOOST_NO_EXCEPTIONS + endpoint_type local_endpoint() const + { + return const_cast(m_sock).next_layer().local_endpoint(); + } +#endif + + endpoint_type local_endpoint(asio::error_code& ec) const + { + return const_cast(m_sock).next_layer().local_endpoint(ec); + } + + asio::io_service& io_service() + { + return m_sock.io_service(); + } + + lowest_layer_type& lowest_layer() + { + return m_sock.lowest_layer(); + } + + next_layer_type& next_layer() + { + return m_sock.next_layer(); + } + +private: + + void connected(asio::error_code const& e, boost::shared_ptr h) + { + if (e) + { + (*h)(e); + return; + } + + m_sock.async_handshake(asio::ssl::stream_base::client + , boost::bind(&ssl_stream::handshake, this, _1, h)); + } + + void handshake(asio::error_code const& e, boost::shared_ptr h) + { + (*h)(e); + } + + asio::ssl::context m_context; + asio::ssl::stream m_sock; +}; + +} + +#endif + diff --git a/include/libtorrent/variant_stream.hpp b/include/libtorrent/variant_stream.hpp index bbe3d964d..ff2f8f700 100644 --- a/include/libtorrent/variant_stream.hpp +++ b/include/libtorrent/variant_stream.hpp @@ -182,6 +182,20 @@ namespace aux Protocol const& proto; }; +// -------------- is_open ----------- + + struct is_open_visitor + : boost::static_visitor + { + is_open_visitor() {} + + template + bool operator()(T const* p) const + { return p->is_open(); } + + bool operator()(boost::blank) const { return false; } + }; + // -------------- close ----------- struct close_visitor_ec @@ -221,7 +235,7 @@ namespace aux {} template - EndpointType operator()(T* p) const + EndpointType operator()(T const* p) const { return p->remote_endpoint(error_code); } EndpointType operator()(boost::blank) const @@ -235,7 +249,7 @@ namespace aux : boost::static_visitor { template - EndpointType operator()(T* p) const + EndpointType operator()(T const* p) const { return p->remote_endpoint(); } EndpointType operator()(boost::blank) const @@ -253,7 +267,7 @@ namespace aux {} template - EndpointType operator()(T* p) const + EndpointType operator()(T const* p) const { return p->local_endpoint(error_code); } @@ -271,7 +285,7 @@ namespace aux : boost::static_visitor { template - EndpointType operator()(T* p) const + EndpointType operator()(T const* p) const { return p->local_endpoint(); } @@ -379,7 +393,7 @@ namespace aux {} template - std::size_t operator()(T* p) const + std::size_t operator()(T const* p) const { return p->in_avail(ec); } @@ -396,7 +410,7 @@ namespace aux : boost::static_visitor { template - std::size_t operator()(T* p) const + std::size_t operator()(T const* p) const { return p->in_avail(); } @@ -414,7 +428,7 @@ namespace aux template IOService& operator()(T* p) const { - return p->io_service(); + return p->get_io_service(); } IOService& operator()(boost::blank) const @@ -471,11 +485,13 @@ public: typedef typename S0::endpoint_type endpoint_type; typedef typename S0::protocol_type protocol_type; - explicit variant_stream() : m_variant(boost::blank()) {} + explicit variant_stream(asio::io_service& ios) + : m_io_service(ios), m_variant(boost::blank()) {} template void instantiate(asio::io_service& ios) { + TORRENT_ASSERT(&ios == &m_io_service); std::auto_ptr owned(new S(ios)); boost::apply_visitor(aux::delete_visitor(), m_variant); m_variant = owned.get(); @@ -594,6 +610,11 @@ public: ); } + bool is_open() const + { + return boost::apply_visitor(aux::is_open_visitor(), m_variant); + } + void close() { if (!instantiated()) return; @@ -608,13 +629,13 @@ public: ); } - std::size_t in_avail() + std::size_t in_avail() const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor(aux::in_avail_visitor(), m_variant); } - std::size_t in_avail(asio::error_code& ec) + std::size_t in_avail(asio::error_code& ec) const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor( @@ -622,13 +643,13 @@ public: ); } - endpoint_type remote_endpoint() + endpoint_type remote_endpoint() const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor(aux::remote_endpoint_visitor(), m_variant); } - endpoint_type remote_endpoint(asio::error_code& ec) + endpoint_type remote_endpoint(asio::error_code& ec) const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor( @@ -636,13 +657,13 @@ public: ); } - endpoint_type local_endpoint() + endpoint_type local_endpoint() const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor(aux::local_endpoint_visitor(), m_variant); } - endpoint_type local_endpoint(asio::error_code& ec) + endpoint_type local_endpoint(asio::error_code& ec) const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor( @@ -650,12 +671,9 @@ public: ); } - asio::io_service& io_service() + asio::io_service& get_io_service() { - TORRENT_ASSERT(instantiated()); - return boost::apply_visitor( - aux::io_service_visitor(), m_variant - ); + return m_io_service; } lowest_layer_type& lowest_layer() @@ -667,6 +685,7 @@ public: } private: + asio::io_service& m_io_service; variant_type m_variant; }; diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 5c1e3079e..aa069c238 100755 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -1742,7 +1742,7 @@ namespace libtorrent // vc,crypto_select,len(pad),pad, encrypt(handshake) // 8+4+2+0+handshake_len - reset_recv_buffer(8+4+2+0+handshake_len); + reset_recv_buffer(8+4+2+0+handshake_len); } else { diff --git a/src/http_connection.cpp b/src/http_connection.cpp index e02c6370b..2a93e3e47 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/http_connection.hpp" #include "libtorrent/escape_string.hpp" +#include "libtorrent/instantiate_connection.hpp" #include #include @@ -46,7 +47,7 @@ namespace libtorrent enum { max_bottled_buffer = 1024 * 1024 }; void http_connection::get(std::string const& url, time_duration timeout - , int handle_redirects) + , proxy_settings const* ps, int handle_redirects) { std::string protocol; std::string auth; @@ -54,21 +55,55 @@ void http_connection::get(std::string const& url, time_duration timeout std::string path; int port; boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url); + + bool ssl = false; + if (protocol == "https") ssl = true; +#ifndef TORRENT_USE_OPENSSL + if (ssl) + { + callback(asio::error::not_supported); + return; + } +#endif + std::stringstream headers; - headers << "GET " << path << " HTTP/1.0\r\n" - "Host:" << hostname << - "\r\nConnection: close\r\n"; + if (ps && (ps->type == proxy_settings::http + || ps->type == proxy_settings::http_pw) + && !ssl) + { + // if we're using an http proxy and not an ssl + // connection, just do a regular http proxy request + headers << "GET " << url << " HTTP/1.0\r\n" + "Connection: close\r\n"; + if (ps->type == proxy_settings::http_pw) + headers << "Proxy-Authorization: Basic " << base64encode( + ps->username + ":" + ps->password) << "\r\n"; + hostname = ps->hostname; + port = ps->port; + ps = 0; + } + else + { + headers << "GET " << path << " HTTP/1.0\r\n" + "Host:" << hostname << "\r\n" + "Connection: close\r\n"; + } + if (!auth.empty()) headers << "Authorization: Basic " << base64encode(auth) << "\r\n"; headers << "\r\n"; sendbuffer = headers.str(); - start(hostname, boost::lexical_cast(port), timeout, handle_redirects); + start(hostname, boost::lexical_cast(port), timeout, ps + , ssl, handle_redirects); } void http_connection::start(std::string const& hostname, std::string const& port - , time_duration timeout, int handle_redirects) + , time_duration timeout, proxy_settings const* ps, bool ssl, int handle_redirects) { m_redirects = handle_redirects; + if (ps) m_proxy = *ps; + + m_ssl = ssl; m_timeout = timeout; asio::error_code ec; m_timer.expires_from_now(m_timeout, ec); @@ -78,6 +113,7 @@ void http_connection::start(std::string const& hostname, std::string const& port m_parser.reset(); m_recvbuffer.clear(); m_read_pos = 0; + if (m_sock.is_open() && m_hostname == hostname && m_port == port) { asio::async_write(m_sock, asio::buffer(sendbuffer) @@ -87,6 +123,27 @@ void http_connection::start(std::string const& hostname, std::string const& port { asio::error_code ec; m_sock.close(ec); + +#ifdef TORRENT_USE_OPENSSL + if (m_ssl) + { + m_sock.instantiate >(m_resolver.get_io_service()); + ssl_stream& s = m_sock.get >(); + bool ret = instantiate_connection(m_resolver.get_io_service(), m_proxy, s.next_layer()); + TORRENT_ASSERT(ret); + } + else + { + m_sock.instantiate(m_resolver.get_io_service()); + bool ret = instantiate_connection(m_resolver.get_io_service() + , m_proxy, m_sock.get()); + TORRENT_ASSERT(ret); + } +#else + bool ret = instantiate_connection(m_resolver.get_io_service(), m_proxy, m_sock); + TORRENT_ASSERT(ret); +#endif + tcp::resolver::query query(hostname, port); m_resolver.async_resolve(query, bind(&http_connection::on_resolve , shared_from_this(), _1, _2)); @@ -295,7 +352,7 @@ void http_connection::on_read(asio::error_code const& e asio::error_code ec; m_sock.close(ec); - get(url, m_timeout, m_redirects - 1); + get(url, m_timeout, &m_proxy, m_redirects - 1); return; } diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 5af1ca040..5c1879831 100755 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -100,6 +100,7 @@ namespace libtorrent , connection_queue& cc , tracker_manager& man , tracker_request const& req + , std::string const& protocol , std::string const& hostname , unsigned short port , std::string request @@ -112,6 +113,10 @@ namespace libtorrent , m_man(man) , m_name_lookup(ios) , m_port(port) + , m_socket(ios) +#ifdef TORRENT_USE_OPENSSL + , m_ssl(protocol == "https") +#endif , m_recv_pos(0) , m_buffer(http_buffer_size) , m_settings(stn) @@ -390,9 +395,25 @@ namespace libtorrent } if (cb) cb->m_tracker_address = target_address; - bool ret = instantiate_connection(m_name_lookup.get_io_service(), m_proxy, m_socket); - + asio::io_service& ios = m_name_lookup.io_service(); +#ifdef TORRENT_USE_OPENSSL + if (m_ssl) + { + m_socket.instantiate >(ios); + ssl_stream& s = m_socket.get >(); + bool ret = instantiate_connection(ios, m_proxy, s.next_layer()); + TORRENT_ASSERT(ret); + } + else + { + m_socket.instantiate(ios); + bool ret = instantiate_connection(ios, m_proxy, m_socket.get()); + TORRENT_ASSERT(ret); + } +#else + bool ret = instantiate_connection(ios, m_proxy, m_socket); TORRENT_ASSERT(ret); +#endif if (m_proxy.type == proxy_settings::http || m_proxy.type == proxy_settings::http_pw) diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 9d1350ed8..9c7e7de19 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -698,7 +698,7 @@ namespace detail } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - (*m_logger) << time_now_string() << " aborting all torrents\n"; + (*m_logger) << time_now_string() << " aborting all torrents (" << m_torrents.size() << ")\n"; #endif // abort all torrents for (torrent_map::iterator i = m_torrents.begin() @@ -1006,7 +1006,7 @@ namespace detail void session_impl::async_accept(boost::shared_ptr const& listener) { - shared_ptr c(new socket_type); + shared_ptr c(new socket_type(m_io_service)); c->instantiate(m_io_service); listener->async_accept(c->get() , bind(&session_impl::on_incoming_connection, this, c @@ -1622,8 +1622,9 @@ namespace detail #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << " locking mutex\n"; #endif - session_impl::mutex_t::scoped_lock l(m_mutex); + session_impl::mutex_t::scoped_lock l(m_mutex); +/* #ifndef NDEBUG for (torrent_map::iterator i = m_torrents.begin(); i != m_torrents.end(); ++i) @@ -1631,7 +1632,7 @@ namespace detail TORRENT_ASSERT(i->second->num_peers() == 0); } #endif - +*/ #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << time_now_string() << " cleaning up torrents\n"; #endif diff --git a/src/torrent.cpp b/src/torrent.cpp index 4e1dcfb23..8ef39c7c6 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -520,7 +520,7 @@ namespace libtorrent // tracker request bool torrent::should_request() { - INVARIANT_CHECK; +// INVARIANT_CHECK; if (m_trackers.empty()) return false; @@ -1782,7 +1782,7 @@ namespace libtorrent return; } - boost::shared_ptr s(new socket_type); + boost::shared_ptr s(new socket_type(m_ses.m_io_service)); bool ret = instantiate_connection(m_ses.m_io_service, m_ses.web_seed_proxy(), *s); TORRENT_ASSERT(ret); @@ -2087,7 +2087,7 @@ namespace libtorrent tcp::endpoint const& a(peerinfo->ip); TORRENT_ASSERT((m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) == 0); - boost::shared_ptr s(new socket_type); + boost::shared_ptr s(new socket_type(m_ses.m_io_service)); bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s); TORRENT_ASSERT(ret); diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp index 59982066b..ec3f85dd6 100755 --- a/src/tracker_manager.cpp +++ b/src/tracker_manager.cpp @@ -355,7 +355,7 @@ namespace libtorrent { std::string hostname; // hostname only std::string auth; // user:pass - std::string protocol; // should be http + std::string protocol; // http or https for instance int port = 80; std::string::iterator at; @@ -371,6 +371,8 @@ namespace libtorrent = std::find(url.begin(), url.end(), ':'); protocol.assign(start, end); + if (protocol == "https") port = 443; + if (end == url.end()) goto exit; ++end; if (end == url.end()) goto exit; @@ -453,13 +455,18 @@ exit: boost::intrusive_ptr con; +#ifdef TORRENT_USE_OPENSSL + if (protocol == "http" || protocol == "https") +#else if (protocol == "http") +#endif { con = new http_tracker_connection( ios , cc , *this , req + , protocol , hostname , port , request_string diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 47fc0ef9a..3cd997e75 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -67,17 +67,34 @@ void stop_web_server(int port) system(cmd.str().c_str()); } -void start_web_server(int port) +void start_web_server(int port, bool ssl) { stop_web_server(port); - std::ofstream f("./lighty_config"); + + if (ssl) + { + system("echo -e \"AU\\ntest province\\ntest city\\ntest company\\n" + "test department\\ntester\\ntest@test.com\" | " + "openssl req -new -x509 -keyout server.pem -out server.pem " + "-days 365 -nodes"); + } + + std::ofstream f("lighty_config"); f << "server.modules = (\"mod_access\", \"mod_redirect\")\n" "server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n" "server.range-requests = \"enable\"\n" "server.port = " << port << "\n" "server.pid-file = \"./lighty" << port << ".pid\"\n" - "url.redirect = (\"^/redirect$\" => \"http://127.0.0.1:" << port << "/test_file\", " - "\"^/infinite_redirect$\" => \"http://127.0.0.1:" << port << "/infinite_redirect\")"; + "url.redirect = (\"^/redirect$\" => \"" + << (ssl?"https":"http") << "://127.0.0.1:" << port << "/test_file\", " + "\"^/infinite_redirect$\" => \"" + << (ssl?"https":"http") << "://127.0.0.1:" << port << "/infinite_redirect\")\n"; + // this requires lighttpd to be built with ssl support. + // The port distribution for mac is not built with ssl + // support by default. + if (ssl) + f << "ssl.engine = \"enable\"\n" + "ssl.pemfile = \"server.pem\"\n"; f.close(); system("lighttpd -f lighty_config &"); @@ -98,7 +115,8 @@ void start_proxy(int port, int proxy_type) stop_proxy(port); std::stringstream cmd; // we need to echo n since dg will ask us to configure it - cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com"; + cmd << "echo n | delegated -P" << port << " ADMIN=test@test.com " + "PERMIT=\"*:*:localhost\" REMITTABLE=+,https RELAY=proxy,delegate"; switch (proxy_type) { case proxy_settings::socks4: @@ -118,6 +136,7 @@ void start_proxy(int port, int proxy_type) break; } system(cmd.str().c_str()); + test_sleep(1000); } using namespace libtorrent; diff --git a/test/setup_transfer.hpp b/test/setup_transfer.hpp index 3d9e9d2fe..063e6c271 100644 --- a/test/setup_transfer.hpp +++ b/test/setup_transfer.hpp @@ -18,7 +18,7 @@ setup_transfer(libtorrent::session* ses1, libtorrent::session* ses2 , libtorrent::session* ses3, bool clear_files, bool use_metadata_transfer = true , bool connect = true, std::string suffix = ""); -void start_web_server(int port); +void start_web_server(int port, bool ssl = false); void stop_web_server(int port); void start_proxy(int port, int type); void stop_proxy(int port); diff --git a/test/test_http_connection.cpp b/test/test_http_connection.cpp index 19b5dc529..c5005f37e 100644 --- a/test/test_http_connection.cpp +++ b/test/test_http_connection.cpp @@ -66,7 +66,8 @@ void reset_globals() error_code = asio::error_code(); } -void run_test(char const* url, int size, int status, int connected, boost::optional ec) +void run_test(std::string const& url, int size, int status, int connected + , boost::optional ec, proxy_settings const& ps) { reset_globals(); @@ -74,7 +75,7 @@ void run_test(char const* url, int size, int status, int connected, boost::optio boost::shared_ptr h(new http_connection(ios, cq , &::http_handler, true, &::http_connect_handler)); - h->get(url); + h->get(url, seconds(30), &ps); ios.reset(); ios.run(); @@ -90,19 +91,63 @@ void run_test(char const* url, int size, int status, int connected, boost::optio TEST_CHECK(http_status == status || status == -1); } +void run_suite(std::string const& protocol, proxy_settings const& ps) +{ + if (ps.type != proxy_settings::none) + { + start_proxy(ps.port, ps.type); + } + char const* test_name[] = {"no", "SOCKS4", "SOCKS5" + , "SOCKS5 password protected", "HTTP", "HTTP password protected"}; + std::cout << "\n\n********************** using " << test_name[ps.type] + << " proxy **********************\n" << std::endl; + + typedef boost::optional err; + run_test(protocol + "://127.0.0.1:8001/redirect", 3216, 200, 2, asio::error_code(), ps); + run_test(protocol + "://127.0.0.1:8001/infinite_redirect", 0, 301, 6, asio::error_code(), ps); + run_test(protocol + "://127.0.0.1:8001/test_file", 3216, 200, 1, asio::error_code(), ps); + run_test(protocol + "://127.0.0.1:8001/non-existing-file", -1, 404, 1, err(), ps); + // if we're going through an http proxy, we won't get the same error as if the hostname + // resolution failed + if ((ps.type == proxy_settings::http || ps.type == proxy_settings::http_pw) && protocol != "https") + run_test(protocol + "://non-existent-domain.se/non-existing-file", -1, 502, 1, err(), ps); + else + run_test(protocol + "://non-existent-domain.se/non-existing-file", -1, -1, 0, err(asio::error::host_not_found), ps); + + if (ps.type != proxy_settings::none) + stop_proxy(ps.port); +} + int test_main() { - typedef boost::optional err; - start_web_server(8001); std::srand(std::time(0)); std::generate(data_buffer, data_buffer + sizeof(data_buffer), &std::rand); std::ofstream("test_file").write(data_buffer, 3216); - run_test("http://127.0.0.1:8001/redirect", 3216, 200, 2, asio::error_code()); - run_test("http://127.0.0.1:8001/infinite_redirect", 0, 301, 6, asio::error_code()); - run_test("http://127.0.0.1:8001/test_file", 3216, 200, 1, asio::error_code()); - run_test("http://127.0.0.1:8001/non-existing-file", -1, 404, 1, err()); - run_test("http://non-existent-domain.se/non-existing-file", -1, -1, 0, err(asio::error::host_not_found)); + + proxy_settings ps; + ps.hostname = "127.0.0.1"; + ps.port = 8034; + ps.username = "testuser"; + ps.password = "testpass"; + + start_web_server(8001); + for (int i = 0; i < 5; ++i) + { + ps.type = (proxy_settings::proxy_type)i; + run_suite("http", ps); + } stop_web_server(8001); + +#ifdef TORRENT_USE_OPENSSL + start_web_server(8001, true); + for (int i = 0; i < 5; ++i) + { + ps.type = (proxy_settings::proxy_type)i; + run_suite("https", ps); + } + stop_web_server(8001); +#endif + std::remove("test_file"); return 0; }