premiere-libtorrent/src/socket_type.cpp

422 lines
11 KiB
C++
Raw Permalink Normal View History

/*
2018-04-09 09:04:33 +02:00
Copyright (c) 2009-2018, 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.
*/
2014-07-06 21:18:00 +02:00
#include "libtorrent/config.hpp"
2018-01-28 11:48:21 +01:00
#include "libtorrent/aux_/socket_type.hpp"
#include "libtorrent/aux_/openssl.hpp"
#include "libtorrent/deadline_timer.hpp"
#ifdef TORRENT_USE_OPENSSL
#include <boost/asio/ssl/context.hpp>
2012-04-05 06:17:19 +02:00
#include <boost/asio/ssl/rfc2818_verification.hpp>
#endif
2014-07-06 21:18:00 +02:00
#include "libtorrent/debug.hpp"
namespace libtorrent {
2018-01-28 11:48:21 +01:00
namespace aux {
bool is_ssl(socket_type const& s)
{
#ifdef TORRENT_USE_OPENSSL
#define CASE(t) case socket_type_int_impl<ssl_stream<t>>::value:
switch (s.type())
{
CASE(tcp::socket)
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
return true;
default: return false;
2019-04-09 23:56:31 +02:00
}
#undef CASE
#else
2015-04-20 02:01:27 +02:00
TORRENT_UNUSED(s);
return false;
#endif
}
2012-10-05 05:20:40 +02:00
bool is_utp(socket_type const& s)
{
return s.get<utp_stream>() != nullptr
2012-10-05 05:20:40 +02:00
#ifdef TORRENT_USE_OPENSSL
|| s.get<ssl_stream<utp_stream>>() != nullptr
2012-10-05 05:20:40 +02:00
#endif
;
}
2013-10-27 20:56:37 +01:00
#if TORRENT_USE_I2P
bool is_i2p(socket_type const& s)
{
return s.get<i2p_stream>() != nullptr
2013-10-27 20:56:37 +01:00
#ifdef TORRENT_USE_OPENSSL
|| s.get<ssl_stream<i2p_stream>>() != nullptr
2013-10-27 20:56:37 +01:00
#endif
;
}
#endif
2012-04-05 06:17:19 +02:00
void setup_ssl_hostname(socket_type& s, std::string const& hostname, error_code& ec)
{
#if defined TORRENT_USE_OPENSSL
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
2012-04-05 06:17:19 +02:00
// for SSL connections, make sure to authenticate the hostname
// of the certificate
#define CASE(t) case socket_type_int_impl<ssl_stream<t>>::value: \
s.get<ssl_stream<t>>()->set_verify_callback( \
boost::asio::ssl::rfc2818_verification(hostname), ec); \
ssl = s.get<ssl_stream<t>>()->native_handle(); \
ctx = SSL_get_SSL_CTX(ssl); \
2012-04-05 06:17:19 +02:00
break;
SSL* ssl = nullptr;
SSL_CTX* ctx = nullptr;
2012-04-05 06:17:19 +02:00
switch(s.type())
{
CASE(tcp::socket)
2012-04-05 06:17:19 +02:00
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
}
#undef CASE
#if OPENSSL_VERSION_NUMBER >= 0x90812f
2012-04-05 06:17:19 +02:00
if (ctx)
{
aux::openssl_set_tlsext_servername_callback(ctx, nullptr);
aux::openssl_set_tlsext_servername_arg(ctx, nullptr);
2012-04-05 06:17:19 +02:00
}
#endif // OPENSSL_VERSION_NUMBER
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
if (ssl)
{
aux::openssl_set_tlsext_hostname(ssl, hostname.c_str());
}
#endif
2015-04-20 02:01:27 +02:00
#else
TORRENT_UNUSED(ec);
TORRENT_UNUSED(hostname);
TORRENT_UNUSED(s);
#endif
#ifdef TORRENT_MACOS_DEPRECATED_LIBCRYPTO
#pragma clang diagnostic pop
2012-04-05 06:17:19 +02:00
#endif
}
#ifdef TORRENT_USE_OPENSSL
2015-04-20 02:01:27 +02:00
struct socket_closer
2012-04-05 06:17:19 +02:00
{
socket_closer(io_service& e
, std::shared_ptr<void> holder
, socket_type* s)
: h(std::move(holder))
, t(std::make_shared<deadline_timer>(e))
, sock(s)
{
t->expires_from_now(seconds(3));
t->async_wait(*this);
}
2012-04-05 06:17:19 +02:00
void operator()(error_code const&)
{
COMPLETE_ASYNC("on_close_socket");
error_code ec;
sock->close(ec);
t->cancel();
}
std::shared_ptr<void> h;
std::shared_ptr<deadline_timer> t;
socket_type* sock;
};
#endif
2015-04-20 02:01:27 +02:00
2012-04-05 06:17:19 +02:00
// 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, std::shared_ptr<void> holder)
2012-04-05 06:17:19 +02:00
{
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
// we call ASIO_DEBUGGING twice, because the socket_closer callback will be
// called twice
#define CASE(t) case socket_type_int_impl<ssl_stream<t>>::value: \
2012-04-05 06:17:19 +02:00
MAYBE_ASIO_DEBUGGING \
MAYBE_ASIO_DEBUGGING \
s.get<ssl_stream<t>>()->async_shutdown( \
socket_closer(s.get_io_service(), std::move(holder), &s)); \
2012-04-05 06:17:19 +02:00
break;
2015-01-26 03:07:03 +01:00
switch (s.type())
2012-04-05 06:17:19 +02:00
{
CASE(tcp::socket)
2012-04-05 06:17:19 +02:00
CASE(socks5_stream)
CASE(http_stream)
CASE(utp_stream)
default: s.close(e); break;
}
#undef CASE
#else
2015-04-20 02:01:27 +02:00
TORRENT_UNUSED(holder);
2012-04-05 06:17:19 +02:00
s.close(e);
#endif // TORRENT_USE_OPENSSL
}
void socket_type::destruct()
{
using tcp_socket = tcp::socket;
switch (m_type)
{
case 0: break;
case socket_type_int_impl<tcp::socket>::value:
get<tcp::socket>()->~tcp_socket();
break;
case socket_type_int_impl<socks5_stream>::value:
get<socks5_stream>()->~socks5_stream();
break;
case socket_type_int_impl<http_stream>::value:
get<http_stream>()->~http_stream();
break;
2010-11-29 02:33:05 +01:00
case socket_type_int_impl<utp_stream>::value:
get<utp_stream>()->~utp_stream();
break;
#if TORRENT_USE_I2P
case socket_type_int_impl<i2p_stream>::value:
get<i2p_stream>()->~i2p_stream();
break;
#endif
#ifdef TORRENT_USE_OPENSSL
case socket_type_int_impl<ssl_stream<tcp::socket>>::value:
get<ssl_stream<tcp::socket>>()->~ssl_stream();
break;
case socket_type_int_impl<ssl_stream<socks5_stream>>::value:
get<ssl_stream<socks5_stream>>()->~ssl_stream();
break;
case socket_type_int_impl<ssl_stream<http_stream>>::value:
get<ssl_stream<http_stream>>()->~ssl_stream();
break;
case socket_type_int_impl<ssl_stream<utp_stream>>::value:
get<ssl_stream<utp_stream>>()->~ssl_stream();
break;
#endif
default: TORRENT_ASSERT_FAIL();
}
m_type = 0;
}
void socket_type::construct(int type, void* userdata)
{
2015-08-16 18:17:23 +02:00
#ifndef TORRENT_USE_OPENSSL
TORRENT_UNUSED(userdata);
#endif
destruct();
switch (type)
{
case 0: break;
case socket_type_int_impl<tcp::socket>::value:
new (reinterpret_cast<tcp::socket*>(&m_data)) tcp::socket(m_io_service);
break;
case socket_type_int_impl<socks5_stream>::value:
new (reinterpret_cast<socks5_stream*>(&m_data)) socks5_stream(m_io_service);
break;
case socket_type_int_impl<http_stream>::value:
new (reinterpret_cast<http_stream*>(&m_data)) http_stream(m_io_service);
break;
2010-11-29 02:33:05 +01:00
case socket_type_int_impl<utp_stream>::value:
new (reinterpret_cast<utp_stream*>(&m_data)) utp_stream(m_io_service);
2010-11-29 02:33:05 +01:00
break;
#if TORRENT_USE_I2P
case socket_type_int_impl<i2p_stream>::value:
new (reinterpret_cast<i2p_stream*>(&m_data)) i2p_stream(m_io_service);
break;
#endif
#ifdef TORRENT_USE_OPENSSL
case socket_type_int_impl<ssl_stream<tcp::socket>>::value:
TORRENT_ASSERT(userdata);
new (reinterpret_cast<ssl_stream<tcp::socket>*>(&m_data)) ssl_stream<tcp::socket>(m_io_service
, *static_cast<ssl::context*>(userdata));
break;
case socket_type_int_impl<ssl_stream<socks5_stream>>::value:
TORRENT_ASSERT(userdata);
new (reinterpret_cast<ssl_stream<socks5_stream>*>(&m_data)) ssl_stream<socks5_stream>(m_io_service
, *static_cast<ssl::context*>(userdata));
break;
case socket_type_int_impl<ssl_stream<http_stream>>::value:
TORRENT_ASSERT(userdata);
new (reinterpret_cast<ssl_stream<http_stream>*>(&m_data)) ssl_stream<http_stream>(m_io_service
, *static_cast<ssl::context*>(userdata));
break;
case socket_type_int_impl<ssl_stream<utp_stream>>::value:
TORRENT_ASSERT(userdata);
new (reinterpret_cast<ssl_stream<utp_stream>*>(&m_data)) ssl_stream<utp_stream>(m_io_service
, *static_cast<ssl::context*>(userdata));
break;
#endif
default: TORRENT_ASSERT_FAIL();
}
m_type = type;
}
char const* socket_type::type_name() const
{
static char const* const names[] =
{
"uninitialized",
"TCP",
"Socks5",
"HTTP",
"uTP",
#if TORRENT_USE_I2P
"I2P",
#else
"",
#endif
#ifdef TORRENT_USE_OPENSSL
"SSL/TCP",
"SSL/Socks5",
"SSL/HTTP",
"SSL/uTP"
#else
"","","",""
#endif
};
return names[m_type];
}
io_service& socket_type::get_io_service() const
{ return m_io_service; }
socket_type::~socket_type()
{ destruct(); }
bool socket_type::is_open() const
{
if (m_type == 0) return false;
TORRENT_SOCKTYPE_FORWARD_RET(is_open(), false)
}
void socket_type::open(protocol_type const& p, error_code& ec)
{ TORRENT_SOCKTYPE_FORWARD(open(p, ec)) }
void socket_type::close(error_code& ec)
{
if (m_type == 0) return;
TORRENT_SOCKTYPE_FORWARD(close(ec))
}
2017-02-04 02:27:31 +01:00
void socket_type::set_close_reason(close_reason_t code)
{
switch (m_type)
{
case socket_type_int_impl<utp_stream>::value:
get<utp_stream>()->set_close_reason(code);
break;
#ifdef TORRENT_USE_OPENSSL
case socket_type_int_impl<ssl_stream<utp_stream>>::value:
get<ssl_stream<utp_stream>>()->lowest_layer().set_close_reason(code);
break;
#endif
default: break;
}
}
2017-02-04 02:27:31 +01:00
close_reason_t socket_type::get_close_reason()
{
switch (m_type)
{
case socket_type_int_impl<utp_stream>::value:
return get<utp_stream>()->get_close_reason();
#ifdef TORRENT_USE_OPENSSL
case socket_type_int_impl<ssl_stream<utp_stream>>::value:
return get<ssl_stream<utp_stream>>()->lowest_layer().get_close_reason();
#endif
2017-02-04 02:27:31 +01:00
default: return close_reason_t::none;
}
}
socket_type::endpoint_type socket_type::local_endpoint(error_code& ec) const
{ TORRENT_SOCKTYPE_FORWARD_RET(local_endpoint(ec), socket_type::endpoint_type()) }
socket_type::endpoint_type socket_type::remote_endpoint(error_code& ec) const
{ TORRENT_SOCKTYPE_FORWARD_RET(remote_endpoint(ec), socket_type::endpoint_type()) }
void socket_type::bind(endpoint_type const& endpoint, error_code& ec)
{ TORRENT_SOCKTYPE_FORWARD(bind(endpoint, ec)) }
std::size_t socket_type::available(error_code& ec) const
{ TORRENT_SOCKTYPE_FORWARD_RET(available(ec), 0) }
int socket_type::type() const { return m_type; }
#ifndef BOOST_NO_EXCEPTIONS
void socket_type::open(protocol_type const& p)
{ TORRENT_SOCKTYPE_FORWARD(open(p)) }
void socket_type::close()
{
if (m_type == 0) return;
TORRENT_SOCKTYPE_FORWARD(close())
}
socket_type::endpoint_type socket_type::local_endpoint() const
{ TORRENT_SOCKTYPE_FORWARD_RET(local_endpoint(), socket_type::endpoint_type()) }
socket_type::endpoint_type socket_type::remote_endpoint() const
{ TORRENT_SOCKTYPE_FORWARD_RET(remote_endpoint(), socket_type::endpoint_type()) }
void socket_type::bind(endpoint_type const& endpoint)
{ TORRENT_SOCKTYPE_FORWARD(bind(endpoint)) }
std::size_t socket_type::available() const
{ TORRENT_SOCKTYPE_FORWARD_RET(available(), 0) }
#endif
}
2018-01-28 11:48:21 +01:00
}