refactor: add tr_peer_id_t (#2004)

* refactor: move handshake_done args into a convenience struct

* refactor: move peer_id from peerIo to tr_handshake

tr_handshake is a short-term object and tr_peerIo is long-term, so this
effectively narrows the scope of this field.

* chore: remove unused field tr_peerIo.isEncrypted

* refactor: add tr_peer_id_t type to hold peer ids.

this is a 'using' alias to a std::array<> so that code passing peer-ids
around doesn't have to memcmp / memcpy PEER_ID_LEN anymore. Also removes
the now-unused PEER_ID_LEN macro.
This commit is contained in:
Charles Kerr 2021-10-21 21:40:55 -05:00 committed by GitHub
parent 3b019ada3d
commit b491da0ce4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 134 additions and 171 deletions

View File

@ -15,7 +15,6 @@
#include <string>
#include "transmission.h" /* SHA_DIGEST_LENGTH */
#include "session.h" /* PEER_ID_LEN */
/***
**** SCRAPE
@ -158,7 +157,7 @@ struct tr_announce_request
/* the torrent's peer id.
* this changes when a torrent is stopped -> restarted. */
char peer_id[PEER_ID_LEN];
tr_peer_id_t peer_id;
/* the torrent's info_hash */
uint8_t info_hash[SHA_DIGEST_LENGTH];

View File

@ -65,7 +65,7 @@ static char* announce_url_new(tr_session const* session, tr_announce_request con
req->url,
strchr(req->url, '?') != nullptr ? '&' : '?',
escaped_info_hash,
TR_ARG_TUPLE(PEER_ID_LEN, PEER_ID_LEN, req->peer_id),
TR_ARG_TUPLE(int(std::size(req->peer_id)), int(std::size(req->peer_id)), std::data(req->peer_id)),
req->port,
req->up,
req->down,

View File

@ -24,6 +24,7 @@
#include "peer-io.h"
#include "peer-mgr.h" /* tr_peerMgrCompactToPex() */
#include "ptrarray.h"
#include "session.h"
#include "tr-assert.h"
#include "tr-udp.h"
#include "utils.h"
@ -317,7 +318,7 @@ static struct tau_announce_request* tau_announce_request_new(
evbuffer_add_hton_32(buf, TAU_ACTION_ANNOUNCE);
evbuffer_add_hton_32(buf, transaction_id);
evbuffer_add(buf, in->info_hash, SHA_DIGEST_LENGTH);
evbuffer_add(buf, in->peer_id, PEER_ID_LEN);
evbuffer_add(buf, std::data(in->peer_id), std::size(in->peer_id));
evbuffer_add_hton_64(buf, in->down);
evbuffer_add_hton_64(buf, in->leftUntilComplete);
evbuffer_add_hton_64(buf, in->up);

View File

@ -935,7 +935,7 @@ static tr_announce_request* announce_request_new(
req->url = tr_strdup(tier->currentTracker->announce);
req->tracker_id_str = tr_strdup(tier->currentTracker->tracker_id_str);
memcpy(req->info_hash, tor->info.hash, SHA_DIGEST_LENGTH);
memcpy(req->peer_id, tr_torrentGetPeerId(tor), PEER_ID_LEN);
req->peer_id = tr_torrentGetPeerId(tor);
req->up = tier->byteCounts[TR_ANN_UP];
req->down = tier->byteCounts[TR_ANN_DOWN];
req->corrupt = tier->byteCounts[TR_ANN_CORRUPT];

View File

@ -6,6 +6,7 @@
*
*/
#include <algorithm>
#include <cerrno>
#include <cstring> /* strcmp(), strlen(), strncmp() */
@ -105,7 +106,6 @@ enum handshake_state_t
struct tr_handshake
{
bool haveReadAnythingFromPeer;
bool havePeerID;
bool haveSentBitTorrentHandshake;
tr_peerIo* io;
tr_crypto* crypto;
@ -118,9 +118,12 @@ struct tr_handshake
uint32_t crypto_select;
uint32_t crypto_provide;
uint8_t myReq1[SHA_DIGEST_LENGTH];
handshakeDoneCB doneCB;
void* doneUserData;
struct event* timeout_timer;
std::optional<tr_peer_id_t> peer_id;
tr_handshake_done_func done_func;
void* done_func_user_data;
};
/**
@ -173,19 +176,17 @@ static bool buildHandshakeMessage(tr_handshake* handshake, uint8_t* buf)
{
uint8_t const* const torrent_hash = tr_cryptoGetTorrentHash(handshake->crypto);
tr_torrent* const tor = torrent_hash == nullptr ? nullptr : tr_torrentFindFromHash(handshake->session, torrent_hash);
unsigned char const* const peer_id = tor == nullptr ? nullptr : tr_torrentGetPeerId(tor);
bool const success = peer_id != nullptr;
bool const success = tor != nullptr;
if (success)
{
uint8_t* walk = buf;
memcpy(walk, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN);
walk += HANDSHAKE_NAME_LEN;
walk = std::copy_n(HANDSHAKE_NAME, HANDSHAKE_NAME_LEN, walk);
memset(walk, 0, HANDSHAKE_FLAGS_LEN);
HANDSHAKE_SET_LTEP(walk);
HANDSHAKE_SET_FASTEXT(walk);
/* Note that this doesn't depend on whether the torrent is private.
* We don't accept DHT peers for a private torrent,
* but we participate in the DHT regardless. */
@ -193,13 +194,14 @@ static bool buildHandshakeMessage(tr_handshake* handshake, uint8_t* buf)
{
HANDSHAKE_SET_DHT(walk);
}
walk += HANDSHAKE_FLAGS_LEN;
memcpy(walk, torrent_hash, SHA_DIGEST_LENGTH);
walk += SHA_DIGEST_LENGTH;
memcpy(walk, peer_id, PEER_ID_LEN);
TR_ASSERT(walk + PEER_ID_LEN - buf == HANDSHAKE_SIZE);
walk = std::copy_n(torrent_hash, SHA_DIGEST_LENGTH, walk);
auto const& peer_id = tr_torrentGetPeerId(tor);
std::copy_n(std::data(peer_id), std::size(peer_id), walk);
TR_ASSERT(walk + std::size(peer_id) - buf == HANDSHAKE_SIZE);
}
return success;
@ -220,8 +222,6 @@ static handshake_parse_err_t parseHandshake(tr_handshake* handshake, struct evbu
uint8_t name[HANDSHAKE_NAME_LEN];
uint8_t reserved[HANDSHAKE_FLAGS_LEN];
uint8_t hash[SHA_DIGEST_LENGTH];
tr_torrent* tor;
uint8_t peer_id[PEER_ID_LEN];
dbgmsg(handshake, "payload: need %d, got %zu", HANDSHAKE_SIZE, evbuffer_get_length(inbuf));
@ -252,17 +252,16 @@ static handshake_parse_err_t parseHandshake(tr_handshake* handshake, struct evbu
return HANDSHAKE_BAD_TORRENT;
}
/* peer_id */
tr_peerIoReadBytes(handshake->io, inbuf, peer_id, sizeof(peer_id));
tr_peerIoSetPeersId(handshake->io, peer_id);
// peer_id
auto peer_id = tr_peer_id_t{};
tr_peerIoReadBytes(handshake->io, inbuf, std::data(peer_id), std::size(peer_id));
handshake->peer_id = peer_id;
/* peer id */
handshake->havePeerID = true;
dbgmsg(handshake, "peer-id is [%*.*s]", TR_ARG_TUPLE(PEER_ID_LEN, PEER_ID_LEN, peer_id));
dbgmsg(handshake, "peer-id is [%*.*s]", TR_ARG_TUPLE(int(std::size(peer_id)), int(std::size(peer_id)), std::data(peer_id)));
tor = tr_torrentFindFromHash(handshake->session, hash);
if (memcmp(peer_id, tr_torrentGetPeerId(tor), PEER_ID_LEN) == 0)
auto* const tor = tr_torrentFindFromHash(handshake->session, hash);
if (peer_id == tr_torrentGetPeerId(tor))
{
dbgmsg(handshake, "streuth! we've connected to ourselves.");
return HANDSHAKE_PEER_IS_SELF;
@ -694,26 +693,22 @@ static ReadState readHandshake(tr_handshake* handshake, struct evbuffer* inbuf)
static ReadState readPeerId(tr_handshake* handshake, struct evbuffer* inbuf)
{
bool connected_to_self;
char client[128];
uint8_t peer_id[PEER_ID_LEN];
tr_torrent* tor;
if (evbuffer_get_length(inbuf) < PEER_ID_LEN)
// read the peer_id
auto peer_id = tr_peer_id_t{};
if (evbuffer_get_length(inbuf) < std::size(peer_id))
{
return READ_LATER;
}
tr_peerIoReadBytes(handshake->io, inbuf, std::data(peer_id), std::size(peer_id));
handshake->peer_id = peer_id;
/* peer id */
tr_peerIoReadBytes(handshake->io, inbuf, peer_id, PEER_ID_LEN);
tr_peerIoSetPeersId(handshake->io, peer_id);
handshake->havePeerID = true;
tr_clientForId(client, sizeof(client), peer_id);
char client[128] = {};
tr_clientForId(client, sizeof(client), std::data(peer_id));
dbgmsg(handshake, "peer-id is [%s] ... isIncoming is %d", client, tr_peerIoIsIncoming(handshake->io));
/* if we've somehow connected to ourselves, don't keep the connection */
tor = tr_torrentFindFromHash(handshake->session, tr_peerIoGetTorrentHash(handshake->io));
connected_to_self = tor != nullptr && memcmp(peer_id, tr_torrentGetPeerId(tor), PEER_ID_LEN) == 0;
// if we've somehow connected to ourselves, don't keep the connection
auto* const tor = tr_torrentFindFromHash(handshake->session, tr_peerIoGetTorrentHash(handshake->io));
bool const connected_to_self = peer_id == tr_torrentGetPeerId(tor);
return tr_handshakeDone(handshake, !connected_to_self);
}
@ -1089,15 +1084,14 @@ static ReadState canRead(tr_peerIo* io, void* vhandshake, size_t* piece)
static bool fireDoneFunc(tr_handshake* handshake, bool isConnected)
{
uint8_t const* peer_id = (isConnected && handshake->havePeerID) ? tr_peerIoGetPeersId(handshake->io) : nullptr;
bool const success = (*handshake->doneCB)(
handshake,
handshake->io,
handshake->haveReadAnythingFromPeer,
isConnected,
peer_id,
handshake->doneUserData);
auto result = tr_handshake_result{};
result.handshake = handshake;
result.io = handshake->io;
result.readAnythingFromPeer = handshake->haveReadAnythingFromPeer;
result.isConnected = isConnected;
result.userData = handshake->done_func_user_data;
result.peer_id = handshake->peer_id;
bool const success = (*handshake->done_func)(result);
return success;
}
@ -1114,15 +1108,11 @@ static void tr_handshakeFree(tr_handshake* handshake)
static ReadState tr_handshakeDone(tr_handshake* handshake, bool isOK)
{
bool success;
dbgmsg(handshake, "handshakeDone: %s", isOK ? "connected" : "aborting");
tr_peerIoSetIOFuncs(handshake->io, nullptr, nullptr, nullptr, nullptr);
success = fireDoneFunc(handshake, isOK);
bool const success = fireDoneFunc(handshake, isOK);
tr_handshakeFree(handshake);
return success ? READ_LATER : READ_ERR;
}
@ -1200,7 +1190,11 @@ static void handshakeTimeout([[maybe_unused]] evutil_socket_t s, [[maybe_unused]
tr_handshakeAbort(static_cast<tr_handshake*>(handshake));
}
tr_handshake* tr_handshakeNew(tr_peerIo* io, tr_encryption_mode encryptionMode, handshakeDoneCB doneCB, void* doneUserData)
tr_handshake* tr_handshakeNew(
tr_peerIo* io,
tr_encryption_mode encryptionMode,
tr_handshake_done_func done_func,
void* done_func_user_data)
{
tr_handshake* handshake;
tr_session* session = tr_peerIoGetSession(io);
@ -1209,8 +1203,8 @@ tr_handshake* tr_handshakeNew(tr_peerIo* io, tr_encryption_mode encryptionMode,
handshake->io = io;
handshake->crypto = tr_peerIoGetCrypto(io);
handshake->encryptionMode = encryptionMode;
handshake->doneCB = doneCB;
handshake->doneUserData = doneUserData;
handshake->done_func = done_func;
handshake->done_func_user_data = done_func_user_data;
handshake->session = session;
handshake->timeout_timer = evtimer_new(session->event_base, handshakeTimeout, handshake);
tr_timerAdd(handshake->timeout_timer, HANDSHAKE_TIMEOUT_SEC, 0);

View File

@ -12,6 +12,8 @@
#error only libtransmission should #include this header.
#endif
#include <optional>
#include "transmission.h"
#include "net.h"
@ -24,17 +26,25 @@ class tr_peerIo;
freed when the handshake is completed. */
struct tr_handshake;
/* returns true on success, false on error */
using handshakeDoneCB = bool (*)(
struct tr_handshake* handshake,
tr_peerIo* io,
bool readAnythingFromPeer,
bool isConnected,
uint8_t const* peerId,
void* userData);
struct tr_handshake_result
{
struct tr_handshake* handshake;
tr_peerIo* io;
bool readAnythingFromPeer;
bool isConnected;
void* userData;
std::optional<tr_peer_id_t> peer_id;
};
/** @brief instantiate a new handshake */
tr_handshake* tr_handshakeNew(tr_peerIo* io, tr_encryption_mode encryptionMode, handshakeDoneCB doneCB, void* doneUserData);
/* returns true on success, false on error */
using tr_handshake_done_func = bool (*)(tr_handshake_result const& result);
/** @brief create a new handshake */
tr_handshake* tr_handshakeNew(
tr_peerIo* io,
tr_encryption_mode encryption_mode,
tr_handshake_done_func when_done,
void* when_done_user_data);
tr_address const* tr_handshakeGetAddr(struct tr_handshake const* handshake, tr_port* port);

View File

@ -1041,26 +1041,6 @@ bool tr_peerIoHasTorrentHash(tr_peerIo const* io)
***
**/
void tr_peerIoSetPeersId(tr_peerIo* io, uint8_t const* peer_id)
{
TR_ASSERT(tr_isPeerIo(io));
if (peer_id == nullptr)
{
memset(io->peerId, '\0', sizeof(io->peerId));
io->peerIdIsSet = false;
}
else
{
memcpy(io->peerId, peer_id, sizeof(io->peerId));
io->peerIdIsSet = true;
}
}
/**
***
**/
static unsigned int getDesiredOutputBufferSize(tr_peerIo const* io, uint64_t now)
{
/* this is all kind of arbitrary, but what seems to work well is

View File

@ -16,8 +16,6 @@
***
**/
#include <assert.h>
#include <event2/buffer.h>
#include "transmission.h"
@ -116,9 +114,6 @@ public:
// TODO: use std::shared_ptr instead of manual refcounting?
int refCount = 1;
// TODO(ckerr): I think this can be moved to tr_handshake
uint8_t peerId[SHA_DIGEST_LENGTH] = {};
short int pendingEvents = 0;
tr_port const port;
@ -129,9 +124,6 @@ public:
bool dhtSupported = false;
bool extendedProtocolSupported = false;
bool fastExtensionSupported = false;
bool isEncrypted = false;
// TODO(ckerr): I think this can be moved to tr_handshake
bool peerIdIsSet = false;
bool utpSupported = false;
};
@ -246,20 +238,6 @@ static inline int tr_peerIoGetAge(tr_peerIo const* io)
***
**/
void tr_peerIoSetPeersId(tr_peerIo* io, uint8_t const* peer_id);
constexpr uint8_t const* tr_peerIoGetPeersId(tr_peerIo const* io)
{
TR_ASSERT(tr_isPeerIo(io));
TR_ASSERT(io->peerIdIsSet);
return io->peerId;
}
/**
***
**/
void tr_peerIoSetIOFuncs(tr_peerIo* io, tr_can_read_cb readcb, tr_did_write_cb writecb, tr_net_error_cb errcb, void* user_data);
void tr_peerIoClear(tr_peerIo* io);

View File

@ -1931,28 +1931,22 @@ static void createBitTorrentPeer(tr_torrent* tor, tr_peerIo* io, struct peer_ato
}
/* FIXME: this is kind of a mess. */
static bool myHandshakeDoneCB(
tr_handshake* handshake,
tr_peerIo* io,
bool readAnythingFromPeer,
bool isConnected,
uint8_t const* peer_id,
void* vmanager)
static bool on_handshake_done(tr_handshake_result const& result)
{
TR_ASSERT(io != nullptr);
TR_ASSERT(result.io != nullptr);
bool ok = isConnected;
bool ok = result.isConnected;
bool success = false;
auto* manager = static_cast<tr_peerMgr*>(vmanager);
tr_swarm* s = tr_peerIoHasTorrentHash(io) ? getExistingSwarm(manager, tr_peerIoGetTorrentHash(io)) : nullptr;
auto* manager = static_cast<tr_peerMgr*>(result.userData);
tr_swarm* s = tr_peerIoHasTorrentHash(result.io) ? getExistingSwarm(manager, tr_peerIoGetTorrentHash(result.io)) : nullptr;
if (tr_peerIoIsIncoming(io))
if (tr_peerIoIsIncoming(result.io))
{
tr_ptrArrayRemoveSortedPointer(&manager->incomingHandshakes, handshake, handshakeCompare);
tr_ptrArrayRemoveSortedPointer(&manager->incomingHandshakes, result.handshake, handshakeCompare);
}
else if (s != nullptr)
{
tr_ptrArrayRemoveSortedPointer(&s->outgoingHandshakes, handshake, handshakeCompare);
tr_ptrArrayRemoveSortedPointer(&s->outgoingHandshakes, result.handshake, handshakeCompare);
}
if (s != nullptr)
@ -1961,7 +1955,7 @@ static bool myHandshakeDoneCB(
}
auto port = tr_port{};
tr_address const* const addr = tr_peerIoGetAddress(io, &port);
tr_address const* const addr = tr_peerIoGetAddress(result.io, &port);
if (!ok || s == nullptr || !s->isRunning)
{
@ -1973,7 +1967,7 @@ static bool myHandshakeDoneCB(
{
++atom->numFails;
if (!readAnythingFromPeer)
if (!result.readAnythingFromPeer)
{
tordbg(s, "marking peer %s as unreachable... numFails is %d", tr_atomAddrStr(atom), (int)atom->numFails);
atom->flags2 |= MyflagUnreachable;
@ -1989,7 +1983,7 @@ static bool myHandshakeDoneCB(
atom->piece_data_time = 0;
atom->lastConnectionAt = tr_time();
if (!tr_peerIoIsIncoming(io))
if (!tr_peerIoIsIncoming(result.io))
{
atom->flags |= ADDED_F_CONNECTABLE;
atom->flags2 &= ~MyflagUnreachable;
@ -1997,7 +1991,7 @@ static bool myHandshakeDoneCB(
/* In principle, this flag specifies whether the peer groks uTP,
not whether it's currently connected over uTP. */
if (io->socket.type == TR_PEER_SOCKET_TYPE_UTP)
if (result.io->socket.type == TR_PEER_SOCKET_TYPE_UTP)
{
atom->flags |= ADDED_F_UTP_FLAGS;
}
@ -2006,7 +2000,7 @@ static bool myHandshakeDoneCB(
{
tordbg(s, "banned peer %s tried to reconnect", tr_atomAddrStr(atom));
}
else if (tr_peerIoIsIncoming(io) && getPeerCount(s) >= getMaxPeerCount(s->tor))
else if (tr_peerIoIsIncoming(result.io) && getPeerCount(s) >= getMaxPeerCount(s->tor))
{
/* too many peers already */
}
@ -2021,14 +2015,15 @@ static bool myHandshakeDoneCB(
else
{
auto client = tr_quark{ TR_KEY_NONE };
if (peer_id != nullptr)
if (result.peer_id)
{
char buf[128];
client = tr_quark_new(tr_clientForId(buf, sizeof(buf), peer_id));
char buf[128] = {};
tr_clientForId(buf, sizeof(buf), std::data(*result.peer_id));
client = tr_quark_new(buf);
}
/* this steals its refcount too, which is balanced by our unref in peerDelete() */
tr_peerIo* stolen = tr_handshakeStealIO(handshake);
tr_peerIo* stolen = tr_handshakeStealIO(result.handshake);
tr_peerIoSetParent(stolen, s->tor->bandwidth);
createBitTorrentPeer(s->tor, stolen, atom, client);
@ -2089,7 +2084,7 @@ void tr_peerMgrAddIncoming(tr_peerMgr* manager, tr_address* addr, tr_port port,
else /* we don't have a connection to them yet... */
{
tr_peerIo* const io = tr_peerIoNewIncoming(session, session->bandwidth, addr, port, socket);
tr_handshake* const handshake = tr_handshakeNew(io, session->encryptionMode, myHandshakeDoneCB, manager);
tr_handshake* const handshake = tr_handshakeNew(io, session->encryptionMode, on_handshake_done, manager);
tr_peerIoUnref(io); /* balanced by the implicit ref in tr_peerIoNewIncoming() */
@ -4216,7 +4211,7 @@ static void initiateConnection(tr_peerMgr* mgr, tr_swarm* s, struct peer_atom* a
}
else
{
tr_handshake* handshake = tr_handshakeNew(io, mgr->session->encryptionMode, myHandshakeDoneCB, mgr);
tr_handshake* handshake = tr_handshakeNew(io, mgr->session->encryptionMode, on_handshake_done, mgr);
TR_ASSERT(tr_peerIoGetTorrentHash(io));

View File

@ -83,27 +83,30 @@ static tr_port getRandomPort(tr_session* s)
characters, where x is the major version number, y is the
minor version number, z is the maintenance number, and b
designates beta (Azureus-style) */
void tr_peerIdInit(uint8_t* buf)
tr_peer_id_t tr_peerIdInit()
{
int total = 0;
// TODO: use a string_view
char const* pool = "0123456789abcdefghijklmnopqrstuvwxyz";
int const base = 36;
auto peer_id = tr_peer_id_t{};
auto* it = std::data(peer_id);
memcpy(buf, PEERID_PREFIX, 8);
// starts with -TRXXXX-
auto constexpr Prefix = std::string_view{ PEERID_PREFIX };
auto const* const end = it + std::size(peer_id);
it = std::copy_n(std::data(Prefix), std::size(Prefix), it);
tr_rand_buffer(buf + 8, 11);
for (int i = 8; i < 19; ++i)
// remainder is randomly-generated characters
auto constexpr Pool = std::string_view{ "0123456789abcdefghijklmnopqrstuvwxyz" };
auto total = int{ 0 };
tr_rand_buffer(it, end - it);
while (it + 1 < end)
{
int const val = buf[i] % base;
int const val = *it % std::size(Pool);
total += val;
buf[i] = pool[val];
*it++ = Pool[val];
}
int const val = total % std::size(Pool) != 0 ? std::size(Pool) - total % std::size(Pool) : 0;
*it = Pool[val];
int const val = total % base != 0 ? base - total % base : 0;
buf[19] = pool[val];
buf[20] = '\0';
return peer_id;
}
/***

View File

@ -45,12 +45,7 @@ enum tr_auto_switch_state_t
TR_AUTO_SWITCH_OFF,
};
enum
{
PEER_ID_LEN = 20
};
void tr_peerIdInit(uint8_t* setme);
tr_peer_id_t tr_peerIdInit();
struct event_base;
struct evdns_base;

View File

@ -155,10 +155,10 @@ bool tr_torrentIsPieceTransferAllowed(tr_torrent const* tor, tr_direction direct
****
***/
static constexpr void tr_torrentUnsetPeerId(tr_torrent* tor)
static void tr_torrentUnsetPeerId(tr_torrent* tor)
{
/* triggers a rebuild next time tr_torrentGetPeerId() is called */
*tor->peer_id = '\0';
// triggers a rebuild next time tr_torrentGetPeerId() is called
tor->peer_id.reset();
}
static int peerIdTTL(tr_torrent const* tor)
@ -167,18 +167,18 @@ static int peerIdTTL(tr_torrent const* tor)
return ctime == 0 ? 0 : (int)difftime(ctime + tor->session->peer_id_ttl_hours * 3600, tr_time());
}
unsigned char const* tr_torrentGetPeerId(tr_torrent* tor)
tr_peer_id_t const& tr_torrentGetPeerId(tr_torrent* tor)
{
bool const needs_new_peer_id = (*tor->peer_id == '\0') || // doesn't have one
bool const needs_new_peer_id = !tor->peer_id || // doesn't have one
(!tr_torrentIsPrivate(tor) && (peerIdTTL(tor) <= 0)); // has one but it's expired
if (needs_new_peer_id)
{
tr_peerIdInit(tor->peer_id);
tor->peer_id = tr_peerIdInit();
tor->peer_id_creation_time = tr_time();
}
return tor->peer_id;
return *tor->peer_id;
}
/***

View File

@ -12,6 +12,7 @@
#error only libtransmission should #include this header.
#endif
#include <optional>
#include <string>
#include <string_view>
#include <unordered_set>
@ -154,7 +155,7 @@ struct tr_torrent
* peer_id that was registered by the peer. The peer_id from the tracker
* and in the handshake are expected to match.
*/
unsigned char peer_id[PEER_ID_LEN + 1];
std::optional<tr_peer_id_t> peer_id;
time_t peer_id_creation_time;
@ -426,7 +427,7 @@ time_t tr_torrentGetFileMTime(tr_torrent const* tor, tr_file_index_t i);
uint64_t tr_torrentGetCurrentSizeOnDisk(tr_torrent const* tor);
unsigned char const* tr_torrentGetPeerId(tr_torrent* tor);
tr_peer_id_t const& tr_torrentGetPeerId(tr_torrent* tor);
static inline uint64_t tr_torrentGetLeftUntilDone(tr_torrent const* tor)
{

View File

@ -8,6 +8,9 @@
#pragma once
#include <array>
#include <cstddef>
/***
****
***/
@ -119,3 +122,11 @@
// Mostly to enforce better formatting
#define TR_ARG_TUPLE(...) __VA_ARGS__
auto inline constexpr PEER_ID_LEN = size_t{ 20 };
// https://www.bittorrent.org/beps/bep_0003.html
// A string of length 20 which this downloader uses as its id. Each
// downloader generates its own id at random at the start of a new
// download. This value will also almost certainly have to be escaped.
using tr_peer_id_t = std::array<char, 20>;

View File

@ -28,14 +28,10 @@ TEST(Session, peerId)
for (int i = 0; i < 100000; ++i)
{
// get a new peer-id
auto buf = std::array<uint8_t, PEER_ID_LEN + 1>{};
tr_peerIdInit(buf.data());
// confirm that it has the right length
EXPECT_EQ(PEER_ID_LEN, strlen(reinterpret_cast<char const*>(buf.data())));
auto const buf = tr_peerIdInit();
// confirm that it begins with peer_id_prefix
auto const peer_id = std::string(reinterpret_cast<char const*>(buf.data()), PEER_ID_LEN);
auto const peer_id = std::string_view(reinterpret_cast<char const*>(buf.data()), PEER_ID_LEN);
EXPECT_EQ(peer_id_prefix, peer_id.substr(0, peer_id_prefix.size()));
// confirm that its total is evenly divisible by 36