2022-01-20 18:27:56 +00:00
|
|
|
// This file Copyright © 2010-2022 Mnemosyne LLC.
|
2022-02-07 16:25:02 +00:00
|
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
2022-01-20 18:27:56 +00:00
|
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
|
|
// License text can be found in the licenses/ folder.
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-10-17 20:17:18 +00:00
|
|
|
#include <cerrno> /* errno, EAFNOSUPPORT */
|
2021-12-16 22:58:58 +00:00
|
|
|
#include <cstring> /* memset() */
|
2021-12-15 21:25:42 +00:00
|
|
|
#include <ctime>
|
2022-01-23 05:41:01 +00:00
|
|
|
#include <list>
|
|
|
|
#include <set>
|
2022-01-13 02:13:58 +00:00
|
|
|
#include <string_view>
|
2021-09-30 19:00:02 +00:00
|
|
|
#include <vector>
|
2011-03-16 18:04:23 +00:00
|
|
|
|
2011-03-13 00:18:11 +00:00
|
|
|
#include <event2/buffer.h>
|
|
|
|
#include <event2/dns.h>
|
|
|
|
#include <event2/util.h>
|
|
|
|
|
2020-08-11 18:11:55 +00:00
|
|
|
#define LIBTRANSMISSION_ANNOUNCER_MODULE
|
2017-11-14 20:21:28 +00:00
|
|
|
|
2011-03-13 00:18:11 +00:00
|
|
|
#include "transmission.h"
|
2011-03-17 18:51:31 +00:00
|
|
|
#include "announcer.h"
|
2011-03-13 00:18:11 +00:00
|
|
|
#include "announcer-common.h"
|
2017-04-21 07:40:57 +00:00
|
|
|
#include "crypto-utils.h" /* tr_rand_buffer() */
|
2013-01-25 23:34:20 +00:00
|
|
|
#include "log.h"
|
2011-03-13 00:18:11 +00:00
|
|
|
#include "peer-io.h"
|
2017-04-21 07:40:57 +00:00
|
|
|
#include "peer-mgr.h" /* tr_peerMgrCompactToPex() */
|
2021-10-22 02:40:55 +00:00
|
|
|
#include "session.h"
|
2017-06-08 07:24:12 +00:00
|
|
|
#include "tr-assert.h"
|
2011-03-13 00:18:11 +00:00
|
|
|
#include "tr-udp.h"
|
|
|
|
#include "utils.h"
|
|
|
|
|
2021-12-23 17:16:05 +00:00
|
|
|
#define dbgmsg(key, ...) tr_logAddDeepNamed(key.c_str(), __VA_ARGS__)
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-12-16 02:09:46 +00:00
|
|
|
using namespace std::literals;
|
|
|
|
|
2011-03-13 00:18:11 +00:00
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void tau_sockaddr_setport(struct sockaddr* sa, tr_port port)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
if (sa->sa_family == AF_INET)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
fix: gcc warnings in libtransmission/ and utils/ (#843)
* fix: __attribute__(__printf__) warnings
* fix: implicit fallthrough warning
* fixup! fix: implicit fallthrough warning
* fix: disable warnings for 3rd party code
Since we want to leave upstream code as-is
* fixup! fix: disable warnings for 3rd party code
* fixup! fix: disable warnings for 3rd party code
* silence spurious alignment warning
Xrefs
Discussion: https://stackoverflow.com/a/35554349
Macro inspiration: https://pagure.io/SSSD/sssd/blob/90ac46f71068d131391492360a8553bdd005b5a7/f/src/util/util_safealign.h#_35
* fixup! fix: disable warnings for 3rd party code
* fixup! fix: implicit fallthrough warning
* make uncrustify happy
* remove uncrustify-test.sh
that's probably off-topic for this PR
* fixup! fix: __attribute__(__printf__) warnings
* Update libtransmission/CMakeLists.txt
Co-Authored-By: ckerr <ckerr@github.com>
* fixup! silence spurious alignment warning
* use -w for DISABLE_WARNINGS in Clang
* refactor: fix libtransmission deprecation warnings
* fix: pthread_create's start_routine's return value
This was defined as `void` on non-Windows but should have been `void*`
* chore: uncrustify
* fix: add DISABLE_WARNINGS option for SunPro Studio
* fix "unused in lambda capture" warnings by clang++
* fix 'increases required alignment' warning
Caused from storing int16_t's in a char array.
* fix net.c 'increases required alignment' warning
The code passes in a `struct sockaddr_storage*` which is a padded struct
large enough for the necessary alignment. Unfortunately it was recast as
a `struct sockaddr*` which has less padding and a smaller alignment. The
warning occrred because of these differing alignments.
* make building quieter so warnings are more visible
* fixup! fix 'increases required alignment' warning
* Fix -Wcast-function-type warnings in GTK+ app code
https://gitlab.gnome.org/GNOME/gnome-terminal/issues/96 talks about both
the issue and its solution.
GCC 8's -Wcast-function-type, enabled by -Wextra, is problematic in glib
applications because it's idiomatic there to recast function signatures,
e.g. `g_slist_free(list, (GFunc)g_free, NULL);`.
Disabling the warning with pragmas causes "unrecognized pragma" warnings
on clang and older versions of gcc, and disabling the warning could miss
actual bugs. GCC defines `void (*)(void)` as a special case that matches
anything so we can silence warnings by double-casting through GCallback.
In the previous example, the warning is silenced by changing the code to
read `g_slist_free(list, (GFunc)(GCallback)g_free, NULL);`).
* fixup! fix "unused in lambda capture" warnings by clang++
* fixup! fix "unused in lambda capture" warnings by clang++
* fix two more libtransmission compiler warnings
* fix: in watchdir, use TR_ENABLE_ASSERTS not NDEBUG
2019-11-06 17:27:03 +00:00
|
|
|
TR_DISCARD_ALIGN(sa, struct sockaddr_in*)->sin_port = htons(port);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
else if (sa->sa_family == AF_INET6)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
fix: gcc warnings in libtransmission/ and utils/ (#843)
* fix: __attribute__(__printf__) warnings
* fix: implicit fallthrough warning
* fixup! fix: implicit fallthrough warning
* fix: disable warnings for 3rd party code
Since we want to leave upstream code as-is
* fixup! fix: disable warnings for 3rd party code
* fixup! fix: disable warnings for 3rd party code
* silence spurious alignment warning
Xrefs
Discussion: https://stackoverflow.com/a/35554349
Macro inspiration: https://pagure.io/SSSD/sssd/blob/90ac46f71068d131391492360a8553bdd005b5a7/f/src/util/util_safealign.h#_35
* fixup! fix: disable warnings for 3rd party code
* fixup! fix: implicit fallthrough warning
* make uncrustify happy
* remove uncrustify-test.sh
that's probably off-topic for this PR
* fixup! fix: __attribute__(__printf__) warnings
* Update libtransmission/CMakeLists.txt
Co-Authored-By: ckerr <ckerr@github.com>
* fixup! silence spurious alignment warning
* use -w for DISABLE_WARNINGS in Clang
* refactor: fix libtransmission deprecation warnings
* fix: pthread_create's start_routine's return value
This was defined as `void` on non-Windows but should have been `void*`
* chore: uncrustify
* fix: add DISABLE_WARNINGS option for SunPro Studio
* fix "unused in lambda capture" warnings by clang++
* fix 'increases required alignment' warning
Caused from storing int16_t's in a char array.
* fix net.c 'increases required alignment' warning
The code passes in a `struct sockaddr_storage*` which is a padded struct
large enough for the necessary alignment. Unfortunately it was recast as
a `struct sockaddr*` which has less padding and a smaller alignment. The
warning occrred because of these differing alignments.
* make building quieter so warnings are more visible
* fixup! fix 'increases required alignment' warning
* Fix -Wcast-function-type warnings in GTK+ app code
https://gitlab.gnome.org/GNOME/gnome-terminal/issues/96 talks about both
the issue and its solution.
GCC 8's -Wcast-function-type, enabled by -Wextra, is problematic in glib
applications because it's idiomatic there to recast function signatures,
e.g. `g_slist_free(list, (GFunc)g_free, NULL);`.
Disabling the warning with pragmas causes "unrecognized pragma" warnings
on clang and older versions of gcc, and disabling the warning could miss
actual bugs. GCC defines `void (*)(void)` as a special case that matches
anything so we can silence warnings by double-casting through GCallback.
In the previous example, the warning is silenced by changing the code to
read `g_slist_free(list, (GFunc)(GCallback)g_free, NULL);`).
* fixup! fix "unused in lambda capture" warnings by clang++
* fixup! fix "unused in lambda capture" warnings by clang++
* fix two more libtransmission compiler warnings
* fix: in watchdir, use TR_ENABLE_ASSERTS not NDEBUG
2019-11-06 17:27:03 +00:00
|
|
|
TR_DISCARD_ALIGN(sa, struct sockaddr_in6*)->sin6_port = htons(port);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2020-11-05 22:46:21 +00:00
|
|
|
static int tau_sendto(tr_session const* session, struct evutil_addrinfo* ai, tr_port port, void const* buf, size_t buflen)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-10-14 14:22:28 +00:00
|
|
|
auto sockfd = tr_socket_t{};
|
2011-03-28 13:37:46 +00:00
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (ai->ai_addr->sa_family == AF_INET)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2011-03-13 00:18:11 +00:00
|
|
|
sockfd = session->udp_socket;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2012-12-05 17:29:46 +00:00
|
|
|
else if (ai->ai_addr->sa_family == AF_INET6)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2011-03-13 00:18:11 +00:00
|
|
|
sockfd = session->udp6_socket;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
else
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2015-03-18 07:34:26 +00:00
|
|
|
sockfd = TR_BAD_SOCKET;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
if (sockfd == TR_BAD_SOCKET)
|
|
|
|
{
|
2011-03-13 00:18:11 +00:00
|
|
|
errno = EAFNOSUPPORT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
tau_sockaddr_setport(ai->ai_addr, port);
|
2021-09-12 17:41:49 +00:00
|
|
|
return sendto(sockfd, static_cast<char const*>(buf), buflen, 0, ai->ai_addr, ai->ai_addrlen);
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static uint32_t evbuffer_read_ntoh_32(struct evbuffer* buf)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-10-14 14:22:28 +00:00
|
|
|
auto val = uint32_t{};
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_remove(buf, &val, sizeof(uint32_t));
|
|
|
|
return ntohl(val);
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static uint64_t evbuffer_read_ntoh_64(struct evbuffer* buf)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-10-14 14:22:28 +00:00
|
|
|
auto val = uint64_t{};
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_remove(buf, &val, sizeof(uint64_t));
|
|
|
|
return tr_ntohll(val);
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/****
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
2021-10-06 14:26:07 +00:00
|
|
|
using tau_connection_t = uint64_t;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-10-21 00:39:05 +00:00
|
|
|
static auto constexpr TauConnectionTtlSecs = int{ 60 };
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-10-06 14:26:07 +00:00
|
|
|
using tau_transaction_t = uint32_t;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-24 19:07:55 +00:00
|
|
|
static tau_transaction_t tau_transaction_new()
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-10-14 14:22:28 +00:00
|
|
|
auto tmp = tau_transaction_t{};
|
2017-04-19 12:04:45 +00:00
|
|
|
tr_rand_buffer(&tmp, sizeof(tau_transaction_t));
|
2011-03-13 00:18:11 +00:00
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* used in the "action" field of a request */
|
2021-10-06 14:26:07 +00:00
|
|
|
enum tau_action_t
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
TAU_ACTION_CONNECT = 0,
|
2011-03-13 00:18:11 +00:00
|
|
|
TAU_ACTION_ANNOUNCE = 1,
|
2017-04-19 12:04:45 +00:00
|
|
|
TAU_ACTION_SCRAPE = 2,
|
|
|
|
TAU_ACTION_ERROR = 3
|
2021-10-06 14:26:07 +00:00
|
|
|
};
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static bool is_tau_response_message(tau_action_t action, size_t msglen)
|
2011-03-14 14:15:58 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
if (action == TAU_ACTION_CONNECT)
|
|
|
|
{
|
|
|
|
return msglen == 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action == TAU_ACTION_ANNOUNCE)
|
|
|
|
{
|
|
|
|
return msglen >= 20;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action == TAU_ACTION_SCRAPE)
|
|
|
|
{
|
|
|
|
return msglen >= 20;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (action == TAU_ACTION_ERROR)
|
|
|
|
{
|
|
|
|
return msglen >= 8;
|
|
|
|
}
|
|
|
|
|
2011-03-22 15:19:54 +00:00
|
|
|
return false;
|
2011-03-14 14:15:58 +00:00
|
|
|
}
|
|
|
|
|
2021-10-21 00:39:05 +00:00
|
|
|
static auto constexpr TauRequestTtl = int{ 60 };
|
2011-03-13 06:38:54 +00:00
|
|
|
|
2011-03-13 00:18:11 +00:00
|
|
|
/****
|
|
|
|
*****
|
|
|
|
***** SCRAPE
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
|
|
|
struct tau_scrape_request
|
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
void requestFinished()
|
|
|
|
{
|
|
|
|
if (callback != nullptr)
|
|
|
|
{
|
|
|
|
callback(&response, user_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void fail(bool did_connect, bool did_timeout, std::string_view errmsg)
|
|
|
|
{
|
|
|
|
response.did_connect = did_connect;
|
|
|
|
response.did_timeout = did_timeout;
|
|
|
|
response.errmsg = errmsg;
|
|
|
|
requestFinished();
|
|
|
|
}
|
|
|
|
|
|
|
|
void onResponse(tau_action_t action, evbuffer* buf)
|
|
|
|
{
|
|
|
|
response.did_connect = true;
|
|
|
|
response.did_timeout = false;
|
|
|
|
|
|
|
|
if (action == TAU_ACTION_SCRAPE)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < response.row_count; ++i)
|
|
|
|
{
|
|
|
|
if (evbuffer_get_length(buf) < sizeof(uint32_t) * 3)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto& row = response.rows[i];
|
|
|
|
row.seeders = evbuffer_read_ntoh_32(buf);
|
|
|
|
row.downloads = evbuffer_read_ntoh_32(buf);
|
|
|
|
row.leechers = evbuffer_read_ntoh_32(buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
requestFinished();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
size_t const buflen = evbuffer_get_length(buf);
|
|
|
|
auto const errmsg = action == TAU_ACTION_ERROR && buflen > 0 ?
|
|
|
|
std::string_view{ reinterpret_cast<char const*>(evbuffer_pullup(buf, -1)), buflen } :
|
|
|
|
_("Unknown error");
|
|
|
|
fail(true, false, errmsg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-30 19:00:02 +00:00
|
|
|
std::vector<uint8_t> payload;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
|
|
|
time_t sent_at;
|
2011-03-14 14:15:58 +00:00
|
|
|
time_t created_at;
|
2011-03-13 00:18:11 +00:00
|
|
|
tau_transaction_t transaction_id;
|
|
|
|
|
|
|
|
tr_scrape_response response;
|
2013-09-08 17:08:18 +00:00
|
|
|
tr_scrape_response_func callback;
|
2017-04-19 12:04:45 +00:00
|
|
|
void* user_data;
|
2011-03-13 00:18:11 +00:00
|
|
|
};
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
static tau_scrape_request make_tau_scrape_request(
|
2021-08-15 09:41:48 +00:00
|
|
|
tr_scrape_request const* in,
|
|
|
|
tr_scrape_response_func callback,
|
2017-04-19 12:04:45 +00:00
|
|
|
void* user_data)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
tau_transaction_t const transaction_id = tau_transaction_new();
|
2011-03-14 14:15:58 +00:00
|
|
|
|
|
|
|
/* build the payload */
|
2021-09-30 19:00:02 +00:00
|
|
|
auto* buf = evbuffer_new();
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_add_hton_32(buf, TAU_ACTION_SCRAPE);
|
|
|
|
evbuffer_add_hton_32(buf, transaction_id);
|
2017-05-13 22:38:31 +00:00
|
|
|
for (int i = 0; i < in->info_hash_count; ++i)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-11-04 00:55:04 +00:00
|
|
|
evbuffer_add(buf, std::data(in->info_hash[i]), std::size(in->info_hash[i]));
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2021-10-01 12:18:49 +00:00
|
|
|
auto const* const payload_begin = evbuffer_pullup(buf, -1);
|
|
|
|
auto const* const payload_end = payload_begin + evbuffer_get_length(buf);
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2011-03-14 14:15:58 +00:00
|
|
|
/* build the tau_scrape_request */
|
2021-09-30 19:00:02 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
auto req = tau_scrape_request{};
|
|
|
|
req.callback = callback;
|
|
|
|
req.created_at = tr_time();
|
|
|
|
req.transaction_id = transaction_id;
|
|
|
|
req.callback = callback;
|
|
|
|
req.user_data = user_data;
|
|
|
|
req.response.scrape_url = in->scrape_url;
|
|
|
|
req.response.row_count = in->info_hash_count;
|
|
|
|
req.payload.assign(payload_begin, payload_end);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
for (int i = 0; i < req.response.row_count; ++i)
|
2011-10-14 00:27:14 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
req.response.rows[i].seeders = -1;
|
|
|
|
req.response.rows[i].leechers = -1;
|
|
|
|
req.response.rows[i].downloads = -1;
|
|
|
|
req.response.rows[i].info_hash = in->info_hash[i];
|
2011-10-14 00:27:14 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2011-03-14 14:15:58 +00:00
|
|
|
/* cleanup */
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
2011-03-13 00:18:11 +00:00
|
|
|
return req;
|
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
/****
|
|
|
|
*****
|
|
|
|
***** ANNOUNCE
|
|
|
|
*****
|
|
|
|
****/
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
struct tau_announce_request
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
void requestFinished()
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
if (this->callback != nullptr)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
this->callback(&this->response, this->user_data);
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
2022-01-23 05:41:01 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
void fail(bool did_connect, bool did_timeout, std::string_view errmsg)
|
|
|
|
{
|
|
|
|
this->response.did_connect = did_connect;
|
|
|
|
this->response.did_timeout = did_timeout;
|
|
|
|
this->response.errmsg = errmsg;
|
|
|
|
this->requestFinished();
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
2022-01-23 05:41:01 +00:00
|
|
|
|
|
|
|
void onResponse(tau_action_t action, struct evbuffer* buf)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
size_t const buflen = evbuffer_get_length(buf);
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
this->response.did_connect = true;
|
|
|
|
this->response.did_timeout = false;
|
|
|
|
|
|
|
|
if (action == TAU_ACTION_ANNOUNCE && buflen >= 3 * sizeof(uint32_t))
|
|
|
|
{
|
|
|
|
response.interval = evbuffer_read_ntoh_32(buf);
|
|
|
|
response.leechers = evbuffer_read_ntoh_32(buf);
|
|
|
|
response.seeders = evbuffer_read_ntoh_32(buf);
|
|
|
|
response.pex = tr_peerMgrCompactToPex(evbuffer_pullup(buf, -1), evbuffer_get_length(buf), nullptr, 0);
|
|
|
|
requestFinished();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
auto const errmsg = action == TAU_ACTION_ERROR && buflen > 0 ?
|
|
|
|
std::string_view{ reinterpret_cast<char const*>(evbuffer_pullup(buf, -1)), buflen } :
|
|
|
|
_("Unknown error");
|
|
|
|
fail(true, false, errmsg);
|
|
|
|
}
|
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-10-01 12:18:49 +00:00
|
|
|
std::vector<uint8_t> payload;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
time_t created_at = 0;
|
|
|
|
time_t sent_at = 0;
|
|
|
|
tau_transaction_t transaction_id = 0;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
tr_announce_response response = {};
|
|
|
|
|
|
|
|
tr_announce_response_func callback = nullptr;
|
|
|
|
void* user_data = nullptr;
|
2011-03-13 00:18:11 +00:00
|
|
|
};
|
|
|
|
|
2021-10-06 14:26:07 +00:00
|
|
|
enum tau_announce_event
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
|
|
|
/* used in the "event" field of an announce request */
|
2017-04-19 12:04:45 +00:00
|
|
|
TAU_ANNOUNCE_EVENT_NONE = 0,
|
2011-03-13 06:38:54 +00:00
|
|
|
TAU_ANNOUNCE_EVENT_COMPLETED = 1,
|
2017-04-19 12:04:45 +00:00
|
|
|
TAU_ANNOUNCE_EVENT_STARTED = 2,
|
|
|
|
TAU_ANNOUNCE_EVENT_STOPPED = 3
|
2021-10-06 14:26:07 +00:00
|
|
|
};
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static tau_announce_event get_tau_announce_event(tr_announce_event e)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2012-12-05 17:29:46 +00:00
|
|
|
switch (e)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
case TR_ANNOUNCE_EVENT_COMPLETED:
|
|
|
|
return TAU_ANNOUNCE_EVENT_COMPLETED;
|
|
|
|
|
|
|
|
case TR_ANNOUNCE_EVENT_STARTED:
|
|
|
|
return TAU_ANNOUNCE_EVENT_STARTED;
|
|
|
|
|
|
|
|
case TR_ANNOUNCE_EVENT_STOPPED:
|
|
|
|
return TAU_ANNOUNCE_EVENT_STOPPED;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return TAU_ANNOUNCE_EVENT_NONE;
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
static tau_announce_request make_tau_announce_request(
|
2021-08-15 09:41:48 +00:00
|
|
|
tr_announce_request const* in,
|
|
|
|
tr_announce_response_func callback,
|
2017-04-19 12:04:45 +00:00
|
|
|
void* user_data)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
tau_transaction_t const transaction_id = tau_transaction_new();
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2011-03-14 14:15:58 +00:00
|
|
|
/* build the payload */
|
2021-10-01 12:18:49 +00:00
|
|
|
auto* buf = evbuffer_new();
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_add_hton_32(buf, TAU_ACTION_ANNOUNCE);
|
|
|
|
evbuffer_add_hton_32(buf, transaction_id);
|
2021-11-04 00:55:04 +00:00
|
|
|
evbuffer_add(buf, std::data(in->info_hash), std::size(in->info_hash));
|
2021-10-22 02:40:55 +00:00
|
|
|
evbuffer_add(buf, std::data(in->peer_id), std::size(in->peer_id));
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_add_hton_64(buf, in->down);
|
|
|
|
evbuffer_add_hton_64(buf, in->leftUntilComplete);
|
|
|
|
evbuffer_add_hton_64(buf, in->up);
|
|
|
|
evbuffer_add_hton_32(buf, get_tau_announce_event(in->event));
|
|
|
|
evbuffer_add_hton_32(buf, 0);
|
|
|
|
evbuffer_add_hton_32(buf, in->key);
|
|
|
|
evbuffer_add_hton_32(buf, in->numwant);
|
|
|
|
evbuffer_add_hton_16(buf, in->port);
|
2021-10-01 12:18:49 +00:00
|
|
|
auto const* const payload_begin = evbuffer_pullup(buf, -1);
|
|
|
|
auto const* const payload_end = payload_begin + evbuffer_get_length(buf);
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2011-03-14 14:15:58 +00:00
|
|
|
/* build the tau_announce_request */
|
2022-01-23 05:41:01 +00:00
|
|
|
auto req = tau_announce_request();
|
|
|
|
req.created_at = tr_time();
|
|
|
|
req.transaction_id = transaction_id;
|
|
|
|
req.callback = callback;
|
|
|
|
req.user_data = user_data;
|
|
|
|
req.payload.assign(payload_begin, payload_end);
|
|
|
|
req.response.seeders = -1;
|
|
|
|
req.response.leechers = -1;
|
|
|
|
req.response.downloads = -1;
|
|
|
|
req.response.info_hash = in->info_hash;
|
2011-03-14 14:15:58 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
2011-03-14 14:15:58 +00:00
|
|
|
return req;
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
/****
|
|
|
|
*****
|
|
|
|
***** TRACKERS
|
|
|
|
*****
|
|
|
|
****/
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
struct tau_tracker
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
[[nodiscard]] auto isIdle() const
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
return std::empty(announces) && std::empty(scrapes) && dns_request == nullptr;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
~tau_tracker()
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
if (this->addr != nullptr)
|
|
|
|
{
|
|
|
|
evutil_freeaddrinfo(this->addr);
|
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
2022-01-23 05:41:01 +00:00
|
|
|
|
|
|
|
void failAll(bool did_connect, bool did_timeout, std::string_view errmsg)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto& req : this->scrapes)
|
|
|
|
{
|
|
|
|
req.fail(did_connect, did_timeout, errmsg);
|
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto& req : this->announces)
|
|
|
|
{
|
|
|
|
req.fail(did_connect, did_timeout, errmsg);
|
|
|
|
}
|
|
|
|
|
|
|
|
this->scrapes.clear();
|
|
|
|
this->announces.clear();
|
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-10-01 11:29:53 +00:00
|
|
|
tr_session* const session;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-12-23 17:16:05 +00:00
|
|
|
tr_interned_string const key;
|
|
|
|
tr_interned_string const host;
|
2021-10-01 11:29:53 +00:00
|
|
|
int const port;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
evdns_getaddrinfo_request* dns_request = nullptr;
|
|
|
|
evutil_addrinfo* addr = nullptr;
|
2021-10-01 11:29:53 +00:00
|
|
|
time_t addr_expiration_time = 0;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-10-01 11:29:53 +00:00
|
|
|
time_t connecting_at = 0;
|
|
|
|
time_t connection_expiration_time = 0;
|
|
|
|
tau_connection_t connection_id = 0;
|
|
|
|
tau_transaction_t connection_transaction_id = 0;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-10-01 11:29:53 +00:00
|
|
|
time_t close_at = 0;
|
2011-03-17 18:51:31 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
std::list<tau_announce_request> announces;
|
|
|
|
std::list<tau_scrape_request> scrapes;
|
2021-10-01 11:29:53 +00:00
|
|
|
|
2021-12-23 17:16:05 +00:00
|
|
|
tau_tracker(tr_session* session_in, tr_interned_string key_in, tr_interned_string host_in, int port_in)
|
2021-10-01 11:29:53 +00:00
|
|
|
: session{ session_in }
|
2021-11-02 23:00:01 +00:00
|
|
|
, key{ key_in }
|
|
|
|
, host{ host_in }
|
2021-10-01 11:29:53 +00:00
|
|
|
, port{ port_in }
|
|
|
|
{
|
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
};
|
|
|
|
|
2022-02-07 04:28:36 +00:00
|
|
|
static void tau_tracker_upkeep(struct tau_tracker* /*tracker*/);
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void tau_tracker_on_dns(int errcode, struct evutil_addrinfo* addr, void* vtracker)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-09-12 17:41:49 +00:00
|
|
|
auto* tracker = static_cast<struct tau_tracker*>(vtracker);
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
tracker->dns_request = nullptr;
|
2022-02-18 00:38:11 +00:00
|
|
|
tracker->addr_expiration_time = tr_time() + 60 * 60; /* one hour */
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (errcode != 0)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-12-16 02:09:46 +00:00
|
|
|
auto const errmsg = tr_strvJoin("DNS Lookup failed: "sv, evutil_gai_strerror(errcode));
|
|
|
|
dbgmsg(tracker->key, "%s", errmsg.c_str());
|
2022-01-23 05:41:01 +00:00
|
|
|
tracker->failAll(false, false, errmsg.c_str());
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
dbgmsg(tracker->key, "DNS lookup succeeded");
|
2011-03-13 00:18:11 +00:00
|
|
|
tracker->addr = addr;
|
2017-04-19 12:04:45 +00:00
|
|
|
tau_tracker_upkeep(tracker);
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
static void tau_tracker_send_request(struct tau_tracker* tracker, void const* payload, size_t payload_len)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
struct evbuffer* buf = evbuffer_new();
|
|
|
|
dbgmsg(tracker->key, "sending request w/connection id %" PRIu64 "\n", tracker->connection_id);
|
|
|
|
evbuffer_add_hton_64(buf, tracker->connection_id);
|
2021-09-15 00:18:09 +00:00
|
|
|
evbuffer_add_reference(buf, payload, payload_len, nullptr, nullptr);
|
2020-09-10 23:50:46 +00:00
|
|
|
(void)tau_sendto(tracker->session, tracker->addr, tracker->port, evbuffer_pullup(buf, -1), evbuffer_get_length(buf));
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
template<typename T>
|
|
|
|
static void tau_tracker_send_requests(tau_tracker* tracker, std::list<T>& reqs)
|
2011-03-20 15:28:41 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
auto const now = tr_time();
|
2017-06-13 02:24:09 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto it = std::begin(reqs); it != std::end(reqs);)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
auto& req = *it;
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
if (req.sent_at != 0) // it's already been sent; we're awaiting a response
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
++it;
|
|
|
|
continue;
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
dbgmsg(tracker->key, "sending req %p", (void*)&req);
|
|
|
|
req.sent_at = now;
|
|
|
|
tau_tracker_send_request(tracker, std::data(req.payload), std::size(req.payload));
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
if (req.callback != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
++it;
|
|
|
|
continue;
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
2022-01-23 05:41:01 +00:00
|
|
|
|
|
|
|
// no response needed, so we can remove it now
|
|
|
|
it = reqs.erase(it);
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
static void tau_tracker_send_reqs(tau_tracker* tracker)
|
|
|
|
{
|
|
|
|
TR_ASSERT(tracker->dns_request == nullptr);
|
|
|
|
TR_ASSERT(tracker->connecting_at == 0);
|
|
|
|
TR_ASSERT(tracker->addr != nullptr);
|
|
|
|
TR_ASSERT(tracker->connection_expiration_time > tr_time());
|
|
|
|
|
|
|
|
tau_tracker_send_requests(tracker, tracker->announces);
|
|
|
|
tau_tracker_send_requests(tracker, tracker->scrapes);
|
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void on_tracker_connection_response(struct tau_tracker* tracker, tau_action_t action, struct evbuffer* buf)
|
2011-03-20 15:28:41 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
time_t const now = tr_time();
|
2011-03-20 15:28:41 +00:00
|
|
|
|
|
|
|
tracker->connecting_at = 0;
|
|
|
|
tracker->connection_transaction_id = 0;
|
|
|
|
|
2012-12-05 17:29:46 +00:00
|
|
|
if (action == TAU_ACTION_CONNECT)
|
2011-03-20 15:28:41 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
tracker->connection_id = evbuffer_read_ntoh_64(buf);
|
2021-10-21 00:39:05 +00:00
|
|
|
tracker->connection_expiration_time = now + TauConnectionTtlSecs;
|
2017-04-19 12:04:45 +00:00
|
|
|
dbgmsg(tracker->key, "Got a new connection ID from tracker: %" PRIu64, tracker->connection_id);
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
size_t const buflen = buf != nullptr ? evbuffer_get_length(buf) : 0;
|
2011-03-20 15:28:41 +00:00
|
|
|
|
2022-01-18 17:20:14 +00:00
|
|
|
auto const errmsg = action == TAU_ACTION_ERROR && buflen > 0 ?
|
|
|
|
std::string_view{ reinterpret_cast<char const*>(evbuffer_pullup(buf, -1)), buflen } :
|
|
|
|
std::string_view{ _("Connection failed") };
|
2011-03-20 15:28:41 +00:00
|
|
|
|
2022-01-18 17:20:14 +00:00
|
|
|
dbgmsg(tracker->key, "%" TR_PRIsv, TR_PRIsv_ARG(errmsg));
|
2022-01-23 05:41:01 +00:00
|
|
|
tracker->failAll(true, false, errmsg);
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
tau_tracker_upkeep(tracker);
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static void tau_tracker_timeout_reqs(struct tau_tracker* tracker)
|
2011-03-20 15:28:41 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
time_t const now = time(nullptr);
|
2017-05-01 15:47:49 +00:00
|
|
|
bool const cancel_all = tracker->close_at != 0 && (tracker->close_at <= now);
|
2011-03-20 15:28:41 +00:00
|
|
|
|
2021-10-21 00:39:05 +00:00
|
|
|
if (tracker->connecting_at != 0 && tracker->connecting_at + TauRequestTtl < now)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
on_tracker_connection_response(tracker, TAU_ACTION_ERROR, nullptr);
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
if (auto& reqs = tracker->announces; !std::empty(reqs))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto it = std::begin(reqs); it != std::end(reqs);)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
auto& req = *it;
|
|
|
|
if (cancel_all || req.created_at + TauRequestTtl < now)
|
|
|
|
{
|
|
|
|
dbgmsg(tracker->key, "timeout announce req %p", (void*)&req);
|
|
|
|
req.fail(false, true, "");
|
|
|
|
it = reqs.erase(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++it;
|
|
|
|
}
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
if (auto& reqs = tracker->scrapes; !std::empty(reqs))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto it = std::begin(reqs); it != std::end(reqs);)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
auto& req = *it;
|
|
|
|
if (cancel_all || req.created_at + TauRequestTtl < now)
|
|
|
|
{
|
|
|
|
dbgmsg(tracker->key, "timeout scrape req %p", &req);
|
|
|
|
req.fail(false, true, "");
|
|
|
|
it = reqs.erase(it);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++it;
|
|
|
|
}
|
2011-03-20 15:28:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-04 18:22:26 +00:00
|
|
|
static void tau_tracker_upkeep_ex(struct tau_tracker* tracker, bool timeout_reqs)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2017-04-20 16:02:19 +00:00
|
|
|
time_t const now = tr_time();
|
|
|
|
bool const closing = tracker->close_at != 0;
|
2011-03-13 00:18:11 +00:00
|
|
|
|
|
|
|
/* if the address info is too old, expire it */
|
2021-09-15 00:18:09 +00:00
|
|
|
if (tracker->addr != nullptr && (closing || tracker->addr_expiration_time <= now))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
dbgmsg(tracker->host, "Expiring old DNS result");
|
|
|
|
evutil_freeaddrinfo(tracker->addr);
|
2021-09-15 00:18:09 +00:00
|
|
|
tracker->addr = nullptr;
|
2022-02-18 00:38:11 +00:00
|
|
|
tracker->addr_expiration_time = 0;
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2011-03-13 06:38:54 +00:00
|
|
|
/* are there any requests pending? */
|
2022-01-23 05:41:01 +00:00
|
|
|
if (tracker->isIdle())
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2011-03-13 00:18:11 +00:00
|
|
|
return;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-02-18 00:38:11 +00:00
|
|
|
// if DNS lookup *recently* failed for this host, do nothing
|
|
|
|
if (tracker->addr == nullptr && now < tracker->addr_expiration_time)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-03-13 06:38:54 +00:00
|
|
|
/* if we don't have an address yet, try & get one now. */
|
2021-09-15 00:18:09 +00:00
|
|
|
if (!closing && tracker->addr == nullptr && tracker->dns_request == nullptr)
|
2011-03-13 06:38:54 +00:00
|
|
|
{
|
|
|
|
struct evutil_addrinfo hints;
|
2017-04-19 12:04:45 +00:00
|
|
|
memset(&hints, 0, sizeof(hints));
|
2011-03-13 06:38:54 +00:00
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
hints.ai_socktype = SOCK_DGRAM;
|
|
|
|
hints.ai_protocol = IPPROTO_UDP;
|
2017-04-19 12:04:45 +00:00
|
|
|
dbgmsg(tracker->host, "Trying a new DNS lookup");
|
2021-08-15 09:41:48 +00:00
|
|
|
tracker->dns_request = evdns_getaddrinfo(
|
|
|
|
tracker->session->evdns_base,
|
2022-02-09 03:30:45 +00:00
|
|
|
tr_strlower(tracker->host.sv()).c_str(),
|
2021-09-15 00:18:09 +00:00
|
|
|
nullptr,
|
2021-08-15 09:41:48 +00:00
|
|
|
&hints,
|
|
|
|
tau_tracker_on_dns,
|
2017-04-19 12:04:45 +00:00
|
|
|
tracker);
|
2011-03-13 00:18:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
dbgmsg(
|
|
|
|
tracker->key,
|
|
|
|
"addr %p -- connected %d (%zu %zu) -- connecting_at %zu",
|
|
|
|
(void*)tracker->addr,
|
|
|
|
(int)(tracker->connection_expiration_time > now),
|
|
|
|
(size_t)tracker->connection_expiration_time,
|
|
|
|
(size_t)now,
|
2017-04-19 12:04:45 +00:00
|
|
|
(size_t)tracker->connecting_at);
|
2011-03-20 15:28:41 +00:00
|
|
|
|
2011-03-13 00:18:11 +00:00
|
|
|
/* also need a valid connection ID... */
|
2021-09-15 00:18:09 +00:00
|
|
|
if (tracker->addr != nullptr && tracker->connection_expiration_time <= now && tracker->connecting_at == 0)
|
2011-03-13 06:38:54 +00:00
|
|
|
{
|
2017-04-19 12:04:45 +00:00
|
|
|
struct evbuffer* buf = evbuffer_new();
|
2011-03-20 15:28:41 +00:00
|
|
|
tracker->connecting_at = now;
|
2017-04-19 12:04:45 +00:00
|
|
|
tracker->connection_transaction_id = tau_transaction_new();
|
|
|
|
dbgmsg(tracker->key, "Trying to connect. Transaction ID is %u", tracker->connection_transaction_id);
|
|
|
|
evbuffer_add_hton_64(buf, 0x41727101980LL);
|
|
|
|
evbuffer_add_hton_32(buf, TAU_ACTION_CONNECT);
|
|
|
|
evbuffer_add_hton_32(buf, tracker->connection_transaction_id);
|
2020-09-12 13:17:18 +00:00
|
|
|
(void)tau_sendto(tracker->session, tracker->addr, tracker->port, evbuffer_pullup(buf, -1), evbuffer_get_length(buf));
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
2011-03-13 00:18:11 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-04 18:22:26 +00:00
|
|
|
if (timeout_reqs)
|
|
|
|
{
|
|
|
|
tau_tracker_timeout_reqs(tracker);
|
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2021-09-15 00:18:09 +00:00
|
|
|
if (tracker->addr != nullptr && tracker->connection_expiration_time > now)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
|
|
|
tau_tracker_send_reqs(tracker);
|
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2017-07-04 18:22:26 +00:00
|
|
|
static void tau_tracker_upkeep(struct tau_tracker* tracker)
|
|
|
|
{
|
|
|
|
tau_tracker_upkeep_ex(tracker, true);
|
|
|
|
}
|
|
|
|
|
2011-03-13 00:18:11 +00:00
|
|
|
/****
|
|
|
|
*****
|
|
|
|
***** SESSION
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
|
|
|
struct tr_announcer_udp
|
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
explicit tr_announcer_udp(tr_session* session_in)
|
|
|
|
: session{ session_in }
|
|
|
|
{
|
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
std::list<tau_tracker> trackers;
|
|
|
|
|
|
|
|
tr_session* const session;
|
2011-03-13 00:18:11 +00:00
|
|
|
};
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
static struct tr_announcer_udp* announcer_udp_get(tr_session* session)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
if (session->announcer_udp != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2011-03-13 00:18:11 +00:00
|
|
|
return session->announcer_udp;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
auto* const tau = new tr_announcer_udp(session);
|
2011-03-13 00:18:11 +00:00
|
|
|
session->announcer_udp = tau;
|
|
|
|
return tau;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Finds the tau_tracker struct that corresponds to this url.
|
|
|
|
If it doesn't exist yet, create one. */
|
2021-12-23 17:16:05 +00:00
|
|
|
static tau_tracker* tau_session_get_tracker(tr_announcer_udp* tau, tr_interned_string announce_url)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-11-02 23:00:01 +00:00
|
|
|
// build a lookup key for this tracker
|
2021-12-23 17:16:05 +00:00
|
|
|
auto const announce_sv = announce_url.sv();
|
2021-11-02 23:00:01 +00:00
|
|
|
auto parsed = tr_urlParseTracker(announce_sv);
|
|
|
|
TR_ASSERT(parsed);
|
|
|
|
if (!parsed)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2021-11-02 23:00:01 +00:00
|
|
|
// see if we already have it
|
|
|
|
auto const key = tr_announcerGetKey(*parsed);
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto& tracker : tau->trackers)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
if (tracker.key == key)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
return &tracker;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2021-11-02 23:00:01 +00:00
|
|
|
// we don't have it -- build a new one
|
2022-01-23 05:41:01 +00:00
|
|
|
tau->trackers.emplace_back(tau->session, key, tr_interned_string(parsed->host), parsed->port);
|
|
|
|
auto* const tracker = &tau->trackers.back();
|
2021-11-02 23:00:01 +00:00
|
|
|
dbgmsg(tracker->key, "New tau_tracker created");
|
2011-03-13 00:18:11 +00:00
|
|
|
return tracker;
|
|
|
|
}
|
|
|
|
|
|
|
|
/****
|
|
|
|
*****
|
|
|
|
***** PUBLIC API
|
|
|
|
*****
|
|
|
|
****/
|
|
|
|
|
2017-04-19 12:04:45 +00:00
|
|
|
void tr_tracker_udp_upkeep(tr_session* session)
|
2011-03-13 06:38:54 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
if (auto* const tau = session->announcer_udp; tau != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto& tracker : tau->trackers)
|
|
|
|
{
|
|
|
|
tau_tracker_upkeep(&tracker);
|
|
|
|
}
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 06:38:54 +00:00
|
|
|
}
|
|
|
|
|
2017-04-20 16:02:19 +00:00
|
|
|
bool tr_tracker_udp_is_idle(tr_session const* session)
|
2011-03-17 18:51:31 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
auto const* tau = session->announcer_udp;
|
2011-03-17 18:51:31 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
return tau == nullptr ||
|
|
|
|
std::all_of(std::begin(tau->trackers), std::end(tau->trackers), [](auto const& tracker) { return tracker.isIdle(); });
|
2011-03-17 18:51:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* drop dead now. */
|
2017-04-19 12:04:45 +00:00
|
|
|
void tr_tracker_udp_close(tr_session* session)
|
2011-03-17 18:51:31 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
if (auto* const tau = session->announcer_udp; tau != nullptr)
|
2011-03-17 18:51:31 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
session->announcer_udp = nullptr;
|
2022-01-23 05:41:01 +00:00
|
|
|
delete tau;
|
2011-03-17 18:51:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* start shutting down.
|
|
|
|
This doesn't destroy everything if there are requests,
|
|
|
|
but sets a deadline on how much longer to wait for the remaining ones */
|
2017-04-19 12:04:45 +00:00
|
|
|
void tr_tracker_udp_start_shutdown(tr_session* session)
|
2011-03-17 18:51:31 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
time_t const now = time(nullptr);
|
2011-03-17 18:51:31 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
if (auto* const tau = session->announcer_udp; tau != nullptr)
|
2011-03-17 18:51:31 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto& tracker : tau->trackers)
|
2011-03-17 18:51:31 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
if (tracker.dns_request != nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
evdns_getaddrinfo_cancel(tracker.dns_request);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
tracker.close_at = now + 3;
|
|
|
|
tau_tracker_upkeep(&tracker);
|
2011-03-17 18:51:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-03-17 04:16:19 +00:00
|
|
|
/* @brief process an incoming udp message if it's a tracker response.
|
|
|
|
* @return true if msg was a tracker response; false otherwise */
|
2017-04-20 16:02:19 +00:00
|
|
|
bool tau_handle_message(tr_session* session, uint8_t const* msg, size_t msglen)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2021-09-15 00:18:09 +00:00
|
|
|
if (session == nullptr || session->announcer_udp == nullptr)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2011-03-22 15:19:54 +00:00
|
|
|
return false;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
2017-04-30 16:25:26 +00:00
|
|
|
if (msglen < sizeof(uint32_t) * 2)
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2011-03-22 15:19:54 +00:00
|
|
|
return false;
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
2011-03-13 00:18:11 +00:00
|
|
|
|
2011-03-14 14:15:58 +00:00
|
|
|
/* extract the action_id and see if it makes sense */
|
2022-01-23 05:41:01 +00:00
|
|
|
auto* const buf = evbuffer_new();
|
2021-09-15 00:18:09 +00:00
|
|
|
evbuffer_add_reference(buf, msg, msglen, nullptr, nullptr);
|
2021-09-12 17:41:49 +00:00
|
|
|
auto const action_id = tau_action_t(evbuffer_read_ntoh_32(buf));
|
2017-04-19 12:04:45 +00:00
|
|
|
|
|
|
|
if (!is_tau_response_message(action_id, msglen))
|
|
|
|
{
|
|
|
|
evbuffer_free(buf);
|
2011-03-22 15:19:54 +00:00
|
|
|
return false;
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2011-03-14 14:15:58 +00:00
|
|
|
/* extract the transaction_id and look for a match */
|
2021-10-14 14:22:28 +00:00
|
|
|
struct tr_announcer_udp* const tau = session->announcer_udp;
|
|
|
|
tau_transaction_t const transaction_id = evbuffer_read_ntoh_32(buf);
|
2017-04-19 12:04:45 +00:00
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
for (auto& tracker : tau->trackers)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
// is it a connection response?
|
|
|
|
if (tracker.connecting_at != 0 && transaction_id == tracker.connection_transaction_id)
|
2011-03-13 00:18:11 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
dbgmsg(tracker.key, "%" PRIu32 " is my connection request!", transaction_id);
|
|
|
|
on_tracker_connection_response(&tracker, action_id, buf);
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
2011-03-22 15:19:54 +00:00
|
|
|
return true;
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
// is it a response to one of this tracker's announces?
|
|
|
|
if (auto& reqs = tracker.announces; !std::empty(reqs))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
auto it = std::find_if(
|
|
|
|
std::begin(reqs),
|
|
|
|
std::end(reqs),
|
|
|
|
[&transaction_id](auto const& req) { return req.transaction_id == transaction_id; });
|
|
|
|
if (it != std::end(reqs))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
dbgmsg(tracker.key, "%" PRIu32 " is an announce request!", transaction_id);
|
|
|
|
auto req = *it;
|
|
|
|
it = reqs.erase(it);
|
|
|
|
req.onResponse(action_id, buf);
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
2011-03-22 15:19:54 +00:00
|
|
|
return true;
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
// is it a response to one of this tracker's scrapes?
|
|
|
|
if (auto& reqs = tracker.scrapes; !std::empty(reqs))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
auto it = std::find_if(
|
|
|
|
std::begin(reqs),
|
|
|
|
std::end(reqs),
|
|
|
|
[&transaction_id](auto const& req) { return req.transaction_id == transaction_id; });
|
|
|
|
if (it != std::end(reqs))
|
2017-04-19 12:04:45 +00:00
|
|
|
{
|
2022-01-23 05:41:01 +00:00
|
|
|
dbgmsg(tracker.key, "%" PRIu32 " is a scrape request!", transaction_id);
|
|
|
|
auto req = *it;
|
|
|
|
it = reqs.erase(it);
|
|
|
|
req.onResponse(action_id, buf);
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
2011-03-22 15:19:54 +00:00
|
|
|
return true;
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no match... */
|
2017-04-19 12:04:45 +00:00
|
|
|
evbuffer_free(buf);
|
2011-03-22 15:19:54 +00:00
|
|
|
return false;
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
void tr_tracker_udp_announce(
|
|
|
|
tr_session* session,
|
|
|
|
tr_announce_request const* request,
|
|
|
|
tr_announce_response_func response_func,
|
2017-04-19 12:04:45 +00:00
|
|
|
void* user_data)
|
|
|
|
{
|
2021-11-02 23:00:01 +00:00
|
|
|
tr_announcer_udp* tau = announcer_udp_get(session);
|
|
|
|
tau_tracker* tracker = tau_session_get_tracker(tau, request->announce_url);
|
|
|
|
if (tracker == nullptr)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
tracker->announces.push_back(make_tau_announce_request(request, response_func, user_data));
|
2017-07-04 18:22:26 +00:00
|
|
|
tau_tracker_upkeep_ex(tracker, false);
|
2017-04-19 12:04:45 +00:00
|
|
|
}
|
|
|
|
|
2021-08-15 09:41:48 +00:00
|
|
|
void tr_tracker_udp_scrape(
|
|
|
|
tr_session* session,
|
|
|
|
tr_scrape_request const* request,
|
|
|
|
tr_scrape_response_func response_func,
|
2017-04-19 12:04:45 +00:00
|
|
|
void* user_data)
|
|
|
|
{
|
2021-11-02 23:00:01 +00:00
|
|
|
tr_announcer_udp* tau = announcer_udp_get(session);
|
|
|
|
tau_tracker* tracker = tau_session_get_tracker(tau, request->scrape_url);
|
|
|
|
if (tracker == nullptr)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-01-23 05:41:01 +00:00
|
|
|
tracker->scrapes.push_back(make_tau_scrape_request(request, response_func, user_data));
|
2017-07-04 18:22:26 +00:00
|
|
|
tau_tracker_upkeep_ex(tracker, false);
|
2011-03-13 00:18:11 +00:00
|
|
|
}
|