2007-04-04 21:11:19 +02:00
|
|
|
/*
|
|
|
|
|
2016-01-18 00:57:46 +01:00
|
|
|
Copyright (c) 2007-2016, Arvid Norberg
|
2007-04-04 21:11:19 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2016-05-23 14:15:39 +02:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstdarg>
|
|
|
|
|
2007-04-04 21:11:19 +02:00
|
|
|
#include "libtorrent/lsd.hpp"
|
|
|
|
#include "libtorrent/io.hpp"
|
|
|
|
#include "libtorrent/http_tracker_connection.hpp"
|
2008-01-31 09:24:01 +01:00
|
|
|
#include "libtorrent/buffer.hpp"
|
2012-10-09 06:51:04 +02:00
|
|
|
#include "libtorrent/random.hpp"
|
2008-01-31 09:24:01 +01:00
|
|
|
#include "libtorrent/http_parser.hpp"
|
2009-09-20 17:21:31 +02:00
|
|
|
#include "libtorrent/socket_io.hpp" // for print_address
|
2010-11-28 02:47:30 +01:00
|
|
|
#include "libtorrent/debug.hpp"
|
2016-05-23 14:15:39 +02:00
|
|
|
#include "libtorrent/hex.hpp" // to_hex, from_hex
|
2010-11-28 02:47:30 +01:00
|
|
|
|
2015-04-21 06:30:34 +02:00
|
|
|
#include "libtorrent/aux_/disable_warnings_push.hpp"
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
#include <boost/asio/ip/host_name.hpp>
|
|
|
|
#include <boost/asio/ip/multicast.hpp>
|
2007-05-17 04:54:13 +02:00
|
|
|
#include <boost/config.hpp>
|
2007-04-04 21:11:19 +02:00
|
|
|
|
2015-04-21 06:30:34 +02:00
|
|
|
#include "libtorrent/aux_/disable_warnings_pop.hpp"
|
2007-04-04 21:11:19 +02:00
|
|
|
|
2016-05-25 06:31:52 +02:00
|
|
|
#include <cstdlib>
|
|
|
|
#include <functional>
|
|
|
|
#include <cstdarg>
|
|
|
|
|
|
|
|
using namespace std::placeholders;
|
|
|
|
|
2007-05-17 04:54:13 +02:00
|
|
|
namespace libtorrent
|
|
|
|
{
|
2015-04-21 06:30:34 +02:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
int render_lsd_packet(char* dst, int len, int listen_port
|
|
|
|
, char const* info_hash_hex, int m_cookie, char const* host)
|
|
|
|
{
|
2015-05-06 03:11:54 +02:00
|
|
|
TORRENT_ASSERT(len > 0);
|
2016-05-17 15:24:06 +02:00
|
|
|
return std::snprintf(dst, len,
|
2015-04-21 06:30:34 +02:00
|
|
|
"BT-SEARCH * HTTP/1.1\r\n"
|
|
|
|
"Host: %s:6771\r\n"
|
|
|
|
"Port: %d\r\n"
|
|
|
|
"Infohash: %s\r\n"
|
|
|
|
"cookie: %x\r\n"
|
|
|
|
"\r\n\r\n", host, listen_port, info_hash_hex, m_cookie);
|
2007-05-17 04:54:13 +02:00
|
|
|
}
|
2015-04-21 06:30:34 +02:00
|
|
|
} // anonymous namespace
|
2007-05-17 04:54:13 +02:00
|
|
|
|
2015-08-02 01:55:28 +02:00
|
|
|
static error_code dummy;
|
2008-11-05 06:39:18 +01:00
|
|
|
|
2015-01-17 00:01:14 +01:00
|
|
|
lsd::lsd(io_service& ios, peer_callback_t const& cb
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-01-17 00:01:14 +01:00
|
|
|
, log_callback_t const& log
|
|
|
|
#endif
|
|
|
|
)
|
2007-04-04 21:11:19 +02:00
|
|
|
: m_callback(cb)
|
2015-08-02 01:55:28 +02:00
|
|
|
, m_socket(udp::endpoint(address_v4::from_string("239.192.152.143", dummy), 6771))
|
2014-08-27 07:57:37 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
2015-08-02 01:55:28 +02:00
|
|
|
, m_socket6(udp::endpoint(address_v6::from_string("ff15::efc0:988f", dummy), 6771))
|
2015-01-17 00:01:14 +01:00
|
|
|
#endif
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-01-17 00:01:14 +01:00
|
|
|
, m_log_cb(log)
|
2014-08-27 07:57:37 +02:00
|
|
|
#endif
|
2007-04-04 21:11:19 +02:00
|
|
|
, m_broadcast_timer(ios)
|
2016-07-18 18:19:45 +02:00
|
|
|
, m_cookie(random() & 0x7fffffff)
|
2007-04-04 21:11:19 +02:00
|
|
|
, m_disabled(false)
|
2014-08-27 07:57:37 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
, m_disabled6(false)
|
|
|
|
#endif
|
2015-01-06 09:08:49 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-10 07:11:51 +02:00
|
|
|
TORRENT_FORMAT(2,3)
|
2015-01-17 00:01:14 +01:00
|
|
|
void lsd::debug_log(char const* fmt, ...) const
|
|
|
|
{
|
|
|
|
va_list v;
|
|
|
|
va_start(v, fmt);
|
|
|
|
|
|
|
|
char buf[1024];
|
|
|
|
vsnprintf(buf, sizeof(buf), fmt, v);
|
|
|
|
va_end(v);
|
|
|
|
m_log_cb(buf);
|
|
|
|
}
|
2012-10-09 06:16:37 +02:00
|
|
|
#endif
|
|
|
|
|
2015-01-17 00:01:14 +01:00
|
|
|
void lsd::start(error_code& ec)
|
|
|
|
{
|
2016-05-25 06:31:52 +02:00
|
|
|
m_socket.open(std::bind(&lsd::on_announce, self(), _1, _2, _3)
|
2015-01-06 09:08:49 +01:00
|
|
|
, m_broadcast_timer.get_io_service(), ec);
|
2015-01-17 00:01:14 +01:00
|
|
|
if (ec) return;
|
2014-08-27 07:57:37 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_IPV6
|
2016-05-25 06:31:52 +02:00
|
|
|
m_socket6.open(std::bind(&lsd::on_announce, self(), _1, _2, _3)
|
2015-01-06 09:08:49 +01:00
|
|
|
, m_broadcast_timer.get_io_service(), ec);
|
2014-08-27 07:57:37 +02:00
|
|
|
#endif
|
2007-04-04 21:11:19 +02:00
|
|
|
}
|
|
|
|
|
2016-07-10 13:34:45 +02:00
|
|
|
lsd::~lsd() = default;
|
2007-04-04 21:11:19 +02:00
|
|
|
|
2011-02-16 11:16:52 +01:00
|
|
|
void lsd::announce(sha1_hash const& ih, int listen_port, bool broadcast)
|
2007-04-04 21:11:19 +02:00
|
|
|
{
|
2014-08-27 07:57:37 +02:00
|
|
|
announce_impl(ih, listen_port, broadcast, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void lsd::announce_impl(sha1_hash const& ih, int listen_port, bool broadcast
|
|
|
|
, int retry_count)
|
|
|
|
{
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
if (m_disabled && m_disabled6) return;
|
|
|
|
#else
|
2007-04-04 21:11:19 +02:00
|
|
|
if (m_disabled) return;
|
2014-08-27 07:57:37 +02:00
|
|
|
#endif
|
2007-04-04 21:11:19 +02:00
|
|
|
|
2009-04-04 11:52:25 +02:00
|
|
|
char ih_hex[41];
|
2016-06-04 16:01:43 +02:00
|
|
|
aux::to_hex(ih.data(), 20, ih_hex);
|
2009-04-04 11:52:25 +02:00
|
|
|
char msg[200];
|
2007-04-04 21:11:19 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("==> LSD: ih: %s port: %u\n", ih_hex, listen_port);
|
2012-10-09 06:16:37 +02:00
|
|
|
#endif
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2014-08-27 07:57:37 +02:00
|
|
|
if (!m_disabled)
|
2007-05-12 20:53:37 +02:00
|
|
|
{
|
2014-08-27 07:57:37 +02:00
|
|
|
int msg_len = render_lsd_packet(msg, sizeof(msg), listen_port, ih_hex
|
|
|
|
, m_cookie, "239.192.152.143");
|
2016-07-05 14:42:11 +02:00
|
|
|
m_socket.send(msg, msg_len, ec, broadcast ? broadcast_socket::flag_broadcast : 0);
|
2014-08-27 07:57:37 +02:00
|
|
|
if (ec)
|
2012-10-09 06:16:37 +02:00
|
|
|
{
|
2014-08-27 07:57:37 +02:00
|
|
|
m_disabled = true;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("*** LSD: failed to send message: (%d) %s", ec.value()
|
2015-01-17 00:01:14 +01:00
|
|
|
, ec.message().c_str());
|
2007-04-04 21:11:19 +02:00
|
|
|
#endif
|
2014-08-27 07:57:37 +02:00
|
|
|
}
|
|
|
|
}
|
2007-04-04 21:11:19 +02:00
|
|
|
|
2014-08-27 07:57:37 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
if (!m_disabled6)
|
|
|
|
{
|
|
|
|
int msg_len = render_lsd_packet(msg, sizeof(msg), listen_port, ih_hex
|
|
|
|
, m_cookie, "[ff15::efc0:988f]");
|
2016-07-05 14:42:11 +02:00
|
|
|
m_socket6.send(msg, msg_len, ec, broadcast ? broadcast_socket::flag_broadcast : 0);
|
2014-08-27 07:57:37 +02:00
|
|
|
if (ec)
|
|
|
|
{
|
|
|
|
m_disabled6 = true;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("*** LSD: failed to send message6: (%d) %s", ec.value()
|
2015-01-17 00:01:14 +01:00
|
|
|
, ec.message().c_str());
|
2014-08-27 07:57:37 +02:00
|
|
|
#endif
|
|
|
|
}
|
2012-10-09 06:16:37 +02:00
|
|
|
}
|
2014-08-27 07:57:37 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
++retry_count;
|
|
|
|
if (retry_count >= 3) return;
|
|
|
|
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
if (m_disabled && m_disabled6) return;
|
|
|
|
#else
|
|
|
|
if (m_disabled) return;
|
|
|
|
#endif
|
2012-10-09 06:16:37 +02:00
|
|
|
|
2016-04-23 23:29:25 +02:00
|
|
|
ADD_OUTSTANDING_ASYNC("lsd::resend_announce");
|
2014-08-27 07:57:37 +02:00
|
|
|
m_broadcast_timer.expires_from_now(seconds(2 * retry_count), ec);
|
2016-05-25 06:31:52 +02:00
|
|
|
m_broadcast_timer.async_wait(std::bind(&lsd::resend_announce, self(), _1
|
2014-08-27 07:57:37 +02:00
|
|
|
, ih, listen_port, retry_count));
|
2007-04-04 21:11:19 +02:00
|
|
|
}
|
|
|
|
|
2014-08-27 07:57:37 +02:00
|
|
|
void lsd::resend_announce(error_code const& e, sha1_hash const& info_hash
|
|
|
|
, int listen_port, int retry_count)
|
2007-04-04 21:11:19 +02:00
|
|
|
{
|
2016-04-23 23:29:25 +02:00
|
|
|
COMPLETE_ASYNC("lsd::resend_announce");
|
2007-04-04 21:11:19 +02:00
|
|
|
if (e) return;
|
|
|
|
|
2014-08-27 07:57:37 +02:00
|
|
|
announce_impl(info_hash, listen_port, false, retry_count);
|
2007-04-04 21:11:19 +02:00
|
|
|
}
|
|
|
|
|
2015-05-06 03:11:54 +02:00
|
|
|
void lsd::on_announce(udp::endpoint const& from, char* buf
|
2007-04-04 21:11:19 +02:00
|
|
|
, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
using namespace libtorrent::detail;
|
|
|
|
|
2007-09-25 05:14:05 +02:00
|
|
|
http_parser p;
|
|
|
|
|
2007-12-29 19:24:50 +01:00
|
|
|
bool error = false;
|
2016-07-24 09:52:20 +02:00
|
|
|
p.incoming(span<char const>(buf, bytes_transferred), error);
|
2007-09-25 05:14:05 +02:00
|
|
|
|
2007-12-29 19:24:50 +01:00
|
|
|
if (!p.header_finished() || error)
|
2007-09-25 05:14:05 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("<== LSD: incomplete HTTP message");
|
2007-05-17 02:01:51 +02:00
|
|
|
#endif
|
2007-09-25 05:14:05 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p.method() != "bt-search")
|
2007-04-04 21:11:19 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("<== LSD: invalid HTTP method: %s", p.method().c_str());
|
2007-04-04 21:11:19 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2007-09-25 05:14:05 +02:00
|
|
|
|
|
|
|
std::string const& port_str = p.header("port");
|
|
|
|
if (port_str.empty())
|
2007-04-04 21:11:19 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("<== LSD: invalid BT-SEARCH, missing port");
|
2007-09-25 05:14:05 +02:00
|
|
|
#endif
|
|
|
|
return;
|
2007-04-04 21:11:19 +02:00
|
|
|
}
|
|
|
|
|
2011-02-16 08:41:44 +01:00
|
|
|
int port = std::atoi(port_str.c_str());
|
|
|
|
|
|
|
|
typedef std::multimap<std::string, std::string> headers_t;
|
|
|
|
headers_t const& headers = p.headers();
|
2012-10-09 06:51:04 +02:00
|
|
|
|
|
|
|
headers_t::const_iterator cookie_iter = headers.find("cookie");
|
|
|
|
if (cookie_iter != headers.end())
|
|
|
|
{
|
|
|
|
// we expect it to be hexadecimal
|
|
|
|
// if it isn't, it's not our cookie anyway
|
2016-06-20 17:32:06 +02:00
|
|
|
std::int32_t cookie = strtol(cookie_iter->second.c_str(), nullptr, 16);
|
2012-10-09 06:51:04 +02:00
|
|
|
if (cookie == m_cookie)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("<== LSD: ignoring packet (cookie matched our own): %x == %x"
|
2015-01-17 00:01:14 +01:00
|
|
|
, cookie, m_cookie);
|
2012-10-09 06:51:04 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-16 08:41:44 +01:00
|
|
|
std::pair<headers_t::const_iterator, headers_t::const_iterator> ihs
|
|
|
|
= headers.equal_range("infohash");
|
|
|
|
|
|
|
|
for (headers_t::const_iterator i = ihs.first; i != ihs.second; ++i)
|
2007-09-25 05:14:05 +02:00
|
|
|
{
|
2011-02-16 08:41:44 +01:00
|
|
|
std::string const& ih_str = i->second;
|
|
|
|
if (ih_str.size() != 40)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("<== LSD: invalid BT-SEARCH, invalid infohash: %s"
|
2015-01-17 00:01:14 +01:00
|
|
|
, ih_str.c_str());
|
2007-09-25 05:14:05 +02:00
|
|
|
#endif
|
2011-02-16 08:41:44 +01:00
|
|
|
continue;
|
|
|
|
}
|
2007-09-25 05:14:05 +02:00
|
|
|
|
2016-07-09 22:26:26 +02:00
|
|
|
sha1_hash ih(nullptr);
|
2016-06-04 16:01:43 +02:00
|
|
|
aux::from_hex(ih_str.c_str(), 40, ih.data());
|
2007-09-25 05:14:05 +02:00
|
|
|
|
2011-02-16 08:41:44 +01:00
|
|
|
if (!ih.is_all_zeros() && port != 0)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-03-30 01:25:25 +02:00
|
|
|
debug_log("<== LSD: %s:%d ih: %s"
|
2015-01-17 00:01:14 +01:00
|
|
|
, print_address(from.address()).c_str()
|
2011-02-16 08:41:44 +01:00
|
|
|
, port, ih_str.c_str());
|
2007-04-04 21:11:19 +02:00
|
|
|
#endif
|
2011-02-16 08:41:44 +01:00
|
|
|
// we got an announce, pass it on through the callback
|
2011-02-25 18:00:36 +01:00
|
|
|
TORRENT_TRY {
|
2011-02-16 08:41:44 +01:00
|
|
|
m_callback(tcp::endpoint(from.address(), port), ih);
|
2011-02-25 18:00:36 +01:00
|
|
|
} TORRENT_CATCH(std::exception&) {}
|
2011-02-16 08:41:44 +01:00
|
|
|
}
|
2007-04-04 21:11:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lsd::close()
|
|
|
|
{
|
2007-10-26 03:28:42 +02:00
|
|
|
m_socket.close();
|
2014-08-27 07:57:37 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
m_socket6.close();
|
|
|
|
#endif
|
2008-05-03 18:05:42 +02:00
|
|
|
error_code ec;
|
2007-12-30 00:30:39 +01:00
|
|
|
m_broadcast_timer.cancel(ec);
|
2007-11-18 05:11:47 +01:00
|
|
|
m_disabled = true;
|
2014-08-27 07:57:37 +02:00
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
m_disabled6 = true;
|
|
|
|
#endif
|
2007-11-18 05:11:47 +01:00
|
|
|
m_callback.clear();
|
2007-04-04 21:11:19 +02:00
|
|
|
}
|
|
|
|
|
2015-04-21 06:30:34 +02:00
|
|
|
} // libtorrent namespace
|
|
|
|
|
|
|
|
|