// This file Copyright © 2010-2022 Mnemosyne LLC. // It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only), // or any future license endorsed by Mnemosyne LLC. // License text can be found in the licenses/ folder. #pragma once #ifndef __TRANSMISSION__ #error only libtransmission should #include this header. #endif #include // size_t #include // uint32_t #include #include #include #include "transmission.h" #include "interned-string.h" #include "net.h" struct tr_announcer; struct tr_torrent_announcer; /** * *** Tracker Publish / Subscribe * **/ enum TrackerEventType { TR_TRACKER_WARNING, TR_TRACKER_ERROR, TR_TRACKER_ERROR_CLEAR, TR_TRACKER_PEERS, TR_TRACKER_COUNTS, }; struct tr_pex; /** @brief Notification object to tell listeners about announce or scrape occurrences */ struct tr_tracker_event { /* what type of event this is */ TrackerEventType messageType; /* for TR_TRACKER_WARNING and TR_TRACKER_ERROR */ std::string_view text; tr_interned_string announce_url; /* for TR_TRACKER_PEERS */ std::vector pex; /* for TR_TRACKER_PEERS and TR_TRACKER_COUNTS */ int leechers; int seeders; }; using tr_tracker_callback = void (*)(tr_torrent* tor, tr_tracker_event const* event, void* client_data); /** *** Session ctor/dtor **/ void tr_announcerInit(tr_session*); void tr_announcerClose(tr_session*); /** *** For torrent customers **/ struct tr_torrent_announcer* tr_announcerAddTorrent(tr_torrent* torrent, tr_tracker_callback callback, void* callback_data); void tr_announcerResetTorrent(struct tr_announcer*, tr_torrent*); void tr_announcerRemoveTorrent(struct tr_announcer*, tr_torrent*); void tr_announcerChangeMyPort(tr_torrent*); bool tr_announcerCanManualAnnounce(tr_torrent const*); void tr_announcerManualAnnounce(tr_torrent*); void tr_announcerTorrentStarted(tr_torrent*); void tr_announcerTorrentStopped(tr_torrent*); void tr_announcerTorrentCompleted(tr_torrent*); enum { TR_ANN_UP, TR_ANN_DOWN, TR_ANN_CORRUPT }; void tr_announcerAddBytes(tr_torrent*, int type, uint32_t n_bytes); time_t tr_announcerNextManualAnnounce(tr_torrent const*); tr_tracker_view tr_announcerTracker(tr_torrent const* torrent, size_t nth); size_t tr_announcerTrackerCount(tr_torrent const* tor); /// ANNOUNCE enum tr_announce_event { /* Note: the ordering of this enum's values is important to * announcer.c's tr_tier.announce_event_priority. If changing * the enum, ensure announcer.c is compatible with the change. */ TR_ANNOUNCE_EVENT_NONE, TR_ANNOUNCE_EVENT_STARTED, TR_ANNOUNCE_EVENT_COMPLETED, TR_ANNOUNCE_EVENT_STOPPED, }; std::string_view tr_announce_event_get_string(tr_announce_event); struct tr_announce_request { tr_announce_event event = {}; bool partial_seed = false; /* the port we listen for incoming peers on */ tr_port port; /* per-session key */ int key = 0; /* the number of peers we'd like to get back in the response */ int numwant = 0; /* the number of bytes we uploaded since the last 'started' event */ uint64_t up = 0; /* the number of good bytes we downloaded since the last 'started' event */ uint64_t down = 0; /* the number of bad bytes we downloaded since the last 'started' event */ uint64_t corrupt = 0; /* the total size of the torrent minus the number of bytes completed */ uint64_t leftUntilComplete = 0; /* the tracker's announce URL */ tr_interned_string announce_url; /* key generated by and returned from an http tracker. * see tr_announce_response.tracker_id_str */ std::string tracker_id; /* the torrent's peer id. * this changes when a torrent is stopped -> restarted. */ tr_peer_id_t peer_id; /* the torrent's info_hash */ tr_sha1_digest_t info_hash; /* the name to use when deep logging is enabled */ char log_name[128]; }; struct tr_announce_response { /* the torrent's info hash */ tr_sha1_digest_t info_hash = {}; /* whether or not we managed to connect to the tracker */ bool did_connect = false; /* whether or not the scrape timed out */ bool did_timeout = false; /* preferred interval between announces. * transmission treats this as the interval for periodic announces */ int interval = 0; /* minimum interval between announces. (optional) * transmission treats this as the min interval for manual announces */ int min_interval = 0; /* how many peers are seeding this torrent */ int seeders = -1; /* how many peers are downloading this torrent */ int leechers = -1; /* how many times this torrent has been downloaded */ int downloads = -1; /* IPv4 peers that we acquired from the tracker */ std::vector pex; /* IPv6 peers that we acquired from the tracker */ std::vector pex6; /* human-readable error string on failure, or nullptr */ std::string errmsg; /* human-readable warning string or nullptr */ std::string warning; /* key generated by and returned from an http tracker. * if this is provided, subsequent http announces must include this. */ std::string tracker_id; /* tracker extension that returns the client's public IP address. * https://www.bittorrent.org/beps/bep_0024.html */ std::optional external_ip; }; using tr_announce_response_func = void (*)(tr_announce_response const* response, void* userdata); /// SCRAPE /* pick a number small enough for common tracker software: * - ocelot has no upper bound * - opentracker has an upper bound of 64 * - udp protocol has an upper bound of 74 * - xbtt has no upper bound * * This is only an upper bound: if the tracker complains about * length, announcer will incrementally lower the batch size. */ auto inline constexpr TR_MULTISCRAPE_MAX = 60; struct tr_scrape_request { /* the scrape URL */ tr_interned_string scrape_url; /* the name to use when deep logging is enabled */ char log_name[128]; /* info hashes of the torrents to scrape */ std::array info_hash; /* how many hashes to use in the info_hash field */ int info_hash_count = 0; }; struct tr_scrape_response_row { /* the torrent's info_hash */ tr_sha1_digest_t info_hash; /* how many peers are seeding this torrent */ int seeders = 0; /* how many peers are downloading this torrent */ int leechers = 0; /* how many times this torrent has been downloaded */ int downloads = 0; /* the number of active downloaders in the swarm. * this is a BEP 21 extension that some trackers won't support. * http://www.bittorrent.org/beps/bep_0021.html#tracker-scrapes */ int downloaders = 0; }; struct tr_scrape_response { /* whether or not we managed to connect to the tracker */ bool did_connect = false; /* whether or not the scrape timed out */ bool did_timeout = false; /* how many info hashes are in the 'rows' field */ int row_count; /* the individual torrents' scrape results */ std::array rows; /* the raw scrape url */ tr_interned_string scrape_url; /* human-readable error string on failure, or nullptr */ std::string errmsg; /* minimum interval (in seconds) allowed between scrapes. * this is an unofficial extension that some trackers won't support. */ int min_request_interval; }; using tr_scrape_response_func = void (*)(tr_scrape_response const* response, void* user_data); /// UDP ANNOUNCER class tr_announcer_udp { public: class Mediator { public: virtual ~Mediator() noexcept = default; virtual void sendto(void const* buf, size_t buflen, sockaddr const* addr, socklen_t addrlen) = 0; [[nodiscard]] virtual std::optional announceIP() const = 0; }; virtual ~tr_announcer_udp() noexcept = default; [[nodiscard]] static std::unique_ptr create(Mediator&); [[nodiscard]] virtual bool isIdle() const noexcept = 0; virtual void announce(tr_announce_request const& request, tr_announce_response_func response_func, void* user_data) = 0; virtual void scrape(tr_scrape_request const& request, tr_scrape_response_func response_func, void* user_data) = 0; virtual void upkeep() = 0; virtual void startShutdown() = 0; // @brief process an incoming udp message if it's a tracker response. // @return true if msg was a tracker response; false otherwise virtual bool handleMessage(uint8_t const* msg, size_t msglen) = 0; };