(libT) make the class hierarchy between tr_peer, tr_peerMsgs, and tr_webseed a little less ad-hoc
This commit is contained in:
parent
0c8c2b5bdd
commit
96691dd019
|
@ -143,7 +143,7 @@ decodeBitCometClient (char * buf, size_t buflen, const uint8_t * id)
|
|||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
char *
|
||||
tr_clientForId (char * buf, size_t buflen, const void * id_in)
|
||||
{
|
||||
const uint8_t * id = id_in;
|
||||
|
@ -151,7 +151,7 @@ tr_clientForId (char * buf, size_t buflen, const void * id_in)
|
|||
*buf = '\0';
|
||||
|
||||
if (!id)
|
||||
return;
|
||||
return buf;
|
||||
|
||||
/* Azureus-style */
|
||||
if (id[0] == '-' && id[7] == '-')
|
||||
|
@ -308,7 +308,7 @@ tr_clientForId (char * buf, size_t buflen, const void * id_in)
|
|||
}
|
||||
|
||||
if (*buf)
|
||||
return;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* uTorrent will replace the trailing dash with an extra digit for longer version numbers */
|
||||
|
@ -331,7 +331,7 @@ tr_clientForId (char * buf, size_t buflen, const void * id_in)
|
|||
}
|
||||
|
||||
if (*buf)
|
||||
return;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Mainline */
|
||||
|
@ -339,11 +339,11 @@ tr_clientForId (char * buf, size_t buflen, const void * id_in)
|
|||
{
|
||||
if (*id=='M') mainline_style (buf, buflen, "BitTorrent", id);
|
||||
if (*id=='Q') mainline_style (buf, buflen, "Queen Bee", id);
|
||||
if (*buf) return;
|
||||
if (*buf) return buf;
|
||||
}
|
||||
|
||||
if (decodeBitCometClient (buf, buflen, id))
|
||||
return;
|
||||
return buf;
|
||||
|
||||
/* Clients with no version */
|
||||
if (!memcmp (id, "AZ2500BT", 8)) no_version (buf, buflen, "BitTyrant (Azureus Mod)");
|
||||
|
@ -440,7 +440,7 @@ tr_clientForId (char * buf, size_t buflen, const void * id_in)
|
|||
if (name)
|
||||
{
|
||||
tr_snprintf (buf, buflen, "%s %d.%d.%d", name, a, b, c);
|
||||
return;
|
||||
return buf;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -461,4 +461,6 @@ tr_clientForId (char * buf, size_t buflen, const void * id_in)
|
|||
*walk = '\0';
|
||||
tr_strlcpy (buf, out, buflen);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,6 @@
|
|||
* @brief parse a peer-id into a human-readable client name and version number
|
||||
* @ingroup utils
|
||||
*/
|
||||
void tr_clientForId (char * buf, size_t buflen, const void * peer_id);
|
||||
char* tr_clientForId (char * buf, size_t buflen, const void * peer_id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,9 @@
|
|||
* @{
|
||||
*/
|
||||
|
||||
struct tr_peer;
|
||||
struct tr_swarm;
|
||||
|
||||
enum
|
||||
{
|
||||
/* this is the maximum size of a block request.
|
||||
|
@ -72,11 +75,30 @@ tr_peer_event;
|
|||
|
||||
extern const tr_peer_event TR_PEER_EVENT_INIT;
|
||||
|
||||
typedef void tr_peer_callback (struct tr_peer * peer,
|
||||
const tr_peer_event * event,
|
||||
void * client_data);
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
typedef void (*tr_peer_destruct_func)(struct tr_peer * peer);
|
||||
typedef bool (*tr_peer_is_transferring_pieces_func)(const struct tr_peer * peer,
|
||||
uint64_t now,
|
||||
tr_direction direction,
|
||||
unsigned int * Bps);
|
||||
struct tr_peer_virtual_funcs
|
||||
{
|
||||
tr_peer_destruct_func destruct;
|
||||
tr_peer_is_transferring_pieces_func is_transferring_pieces;
|
||||
};
|
||||
|
||||
/**
|
||||
* State information about a connected peer.
|
||||
*
|
||||
* @see struct peer_atom
|
||||
* @see tr_peermsgs
|
||||
* @see tr_peerMsgs
|
||||
*/
|
||||
typedef struct tr_peer
|
||||
{
|
||||
|
@ -84,22 +106,6 @@ typedef struct tr_peer
|
|||
NOTE: private to peer-mgr.c */
|
||||
bool doPurge;
|
||||
|
||||
/* Whether or not we've choked this peer.
|
||||
Only applies to BitTorrent peers */
|
||||
bool peerIsChoked;
|
||||
|
||||
/* whether or not the peer has indicated it will download from us.
|
||||
Only applies to BitTorrent peers */
|
||||
bool peerIsInterested;
|
||||
|
||||
/* whether or the peer is choking us.
|
||||
Only applies to BitTorrent peers */
|
||||
bool clientIsChoked;
|
||||
|
||||
/* whether or not we've indicated to the peer that we would download from them if unchoked.
|
||||
Only applies to BitTorrent peers */
|
||||
bool clientIsInterested;
|
||||
|
||||
/* number of bad pieces they've contributed to */
|
||||
uint8_t strikes;
|
||||
|
||||
|
@ -109,11 +115,11 @@ typedef struct tr_peer
|
|||
/* how many requests we've made and are currently awaiting a response for */
|
||||
int pendingReqsToPeer;
|
||||
|
||||
struct tr_peerIo * io;
|
||||
|
||||
/* Hook to private peer-mgr information */
|
||||
struct peer_atom * atom;
|
||||
|
||||
struct tr_swarm * swarm;
|
||||
|
||||
/** how complete the peer's copy of the torrent is. [0.0...1.0] */
|
||||
float progress;
|
||||
|
||||
|
@ -124,21 +130,21 @@ typedef struct tr_peer
|
|||
For BitTorrent peers, this is the app name derived from the `v' string in LTEP's handshake dictionary */
|
||||
tr_quark client;
|
||||
|
||||
time_t chokeChangedAt;
|
||||
|
||||
tr_recentHistory blocksSentToClient;
|
||||
tr_recentHistory blocksSentToPeer;
|
||||
|
||||
tr_recentHistory cancelsSentToClient;
|
||||
tr_recentHistory cancelsSentToPeer;
|
||||
|
||||
struct tr_peermsgs * msgs;
|
||||
const struct tr_peer_virtual_funcs * funcs;
|
||||
}
|
||||
tr_peer;
|
||||
|
||||
typedef void tr_peer_callback (struct tr_peer * peer,
|
||||
const tr_peer_event * event,
|
||||
void * client_data);
|
||||
|
||||
void tr_peerConstruct (struct tr_peer * peer, const tr_torrent * tor);
|
||||
|
||||
void tr_peerDestruct (struct tr_peer * peer);
|
||||
|
||||
|
||||
/** Update the tr_peer.progress field based on the 'have' bitset. */
|
||||
void tr_peerUpdateProgress (tr_torrent * tor, struct tr_peer *);
|
||||
|
|
|
@ -90,7 +90,7 @@ typedef struct tr_peerIo
|
|||
|
||||
tr_port port;
|
||||
int socket;
|
||||
struct UTPSocket *utp_socket;
|
||||
struct UTPSocket * utp_socket;
|
||||
|
||||
int refCount;
|
||||
|
||||
|
@ -138,13 +138,13 @@ tr_peerIo* tr_peerIoNewIncoming (tr_session * session,
|
|||
int socket,
|
||||
struct UTPSocket * utp_socket);
|
||||
|
||||
void tr_peerIoRefImpl (const char * file,
|
||||
void tr_peerIoRefImpl (const char * file,
|
||||
int line,
|
||||
tr_peerIo * io);
|
||||
|
||||
#define tr_peerIoRef(io) tr_peerIoRefImpl (__FILE__, __LINE__, (io));
|
||||
|
||||
void tr_peerIoUnrefImpl (const char * file,
|
||||
void tr_peerIoUnrefImpl (const char * file,
|
||||
int line,
|
||||
tr_peerIo * io);
|
||||
|
||||
|
|
|
@ -114,7 +114,7 @@ const tr_peer_event TR_PEER_EVENT_INIT = { 0, 0, NULL, 0, 0, 0, 0 };
|
|||
* for banned peers.
|
||||
*
|
||||
* @see tr_peer
|
||||
* @see tr_peermsgs
|
||||
* @see tr_peerMsgs
|
||||
*/
|
||||
struct peer_atom
|
||||
{
|
||||
|
@ -186,13 +186,13 @@ typedef struct tr_swarm
|
|||
{
|
||||
tr_ptrArray outgoingHandshakes; /* tr_handshake */
|
||||
tr_ptrArray pool; /* struct peer_atom */
|
||||
tr_ptrArray peers; /* tr_peer */
|
||||
tr_ptrArray peers; /* tr_peerMsgs */
|
||||
tr_ptrArray webseeds; /* tr_webseed */
|
||||
|
||||
tr_torrent * tor;
|
||||
struct tr_peerMgr * manager;
|
||||
|
||||
tr_peer * optimistic; /* the optimistic peer, or NULL if none */
|
||||
tr_peerMsgs * optimistic; /* the optimistic peer, or NULL if none */
|
||||
int optimisticUnchokeTimeScaler;
|
||||
|
||||
bool isRunning;
|
||||
|
@ -251,6 +251,74 @@ struct tr_peerMgr
|
|||
} \
|
||||
while (0)
|
||||
|
||||
/**
|
||||
*** tr_peer virtual functions
|
||||
**/
|
||||
|
||||
static bool
|
||||
tr_peerIsTransferringPieces (const tr_peer * peer,
|
||||
uint64_t now,
|
||||
tr_direction direction,
|
||||
unsigned int * Bps)
|
||||
{
|
||||
assert (peer != NULL);
|
||||
assert (peer->funcs != NULL);
|
||||
|
||||
return (*peer->funcs->is_transferring_pieces)(peer, now, direction, Bps);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
tr_peerGetPieceSpeed_Bps (const tr_peer * peer,
|
||||
uint64_t now,
|
||||
tr_direction direction)
|
||||
{
|
||||
unsigned int Bps = 0;
|
||||
tr_peerIsTransferringPieces (peer, now, direction, &Bps);
|
||||
return Bps;
|
||||
}
|
||||
|
||||
static void
|
||||
tr_peerFree (tr_peer * peer)
|
||||
{
|
||||
assert (peer != NULL);
|
||||
assert (peer->funcs != NULL);
|
||||
|
||||
(*peer->funcs->destruct)(peer);
|
||||
|
||||
tr_free (peer);
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerConstruct (tr_peer * peer, const tr_torrent * tor)
|
||||
{
|
||||
assert (peer != NULL);
|
||||
assert (tr_isTorrent (tor));
|
||||
|
||||
memset (peer, 0, sizeof (tr_peer));
|
||||
|
||||
peer->client = TR_KEY_NONE;
|
||||
peer->swarm = tor->swarm;
|
||||
tr_bitfieldConstruct (&peer->have, tor->info.pieceCount);
|
||||
tr_bitfieldConstruct (&peer->blame, tor->blockCount);
|
||||
}
|
||||
|
||||
static void peerDeclinedAllRequests (tr_swarm *, const tr_peer *);
|
||||
|
||||
void
|
||||
tr_peerDestruct (tr_peer * peer)
|
||||
{
|
||||
assert (peer != NULL);
|
||||
|
||||
if (peer->swarm != NULL)
|
||||
peerDeclinedAllRequests (peer->swarm, peer);
|
||||
|
||||
tr_bitfieldDestruct (&peer->have);
|
||||
tr_bitfieldDestruct (&peer->blame);
|
||||
|
||||
if (peer->atom)
|
||||
peer->atom->peer = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
***
|
||||
**/
|
||||
|
@ -375,78 +443,6 @@ peerIsInUse (const tr_swarm * cs, const struct peer_atom * atom)
|
|||
|| getExistingHandshake (&s->manager->incomingHandshakes, &atom->addr);
|
||||
}
|
||||
|
||||
void
|
||||
tr_peerConstruct (tr_peer * peer)
|
||||
{
|
||||
memset (peer, 0, sizeof (tr_peer));
|
||||
|
||||
peer->have = TR_BITFIELD_INIT;
|
||||
}
|
||||
|
||||
static tr_peer*
|
||||
peerNew (struct peer_atom * atom)
|
||||
{
|
||||
tr_peer * peer = tr_new (tr_peer, 1);
|
||||
tr_peerConstruct (peer);
|
||||
|
||||
peer->atom = atom;
|
||||
atom->peer = peer;
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
static tr_peer*
|
||||
getPeer (tr_swarm * s, struct peer_atom * atom)
|
||||
{
|
||||
tr_peer * peer;
|
||||
|
||||
assert (swarmIsLocked (s));
|
||||
|
||||
peer = atom->peer;
|
||||
|
||||
if (peer == NULL)
|
||||
{
|
||||
peer = peerNew (atom);
|
||||
tr_bitfieldConstruct (&peer->have, s->tor->info.pieceCount);
|
||||
tr_bitfieldConstruct (&peer->blame, s->tor->blockCount);
|
||||
tr_ptrArrayInsertSorted (&s->peers, peer, peerCompare);
|
||||
}
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
static void peerDeclinedAllRequests (tr_swarm *, const tr_peer *);
|
||||
|
||||
void
|
||||
tr_peerDestruct (tr_torrent * tor, tr_peer * peer)
|
||||
{
|
||||
assert (peer != NULL);
|
||||
|
||||
peerDeclinedAllRequests (tor->swarm, peer);
|
||||
|
||||
if (peer->msgs != NULL)
|
||||
tr_peerMsgsFree (peer->msgs);
|
||||
|
||||
if (peer->io)
|
||||
{
|
||||
tr_peerIoClear (peer->io);
|
||||
tr_peerIoUnref (peer->io); /* balanced by the ref in handshakeDoneCB () */
|
||||
}
|
||||
|
||||
tr_bitfieldDestruct (&peer->have);
|
||||
tr_bitfieldDestruct (&peer->blame);
|
||||
|
||||
if (peer->atom)
|
||||
peer->atom->peer = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
peerDelete (tr_swarm * s, tr_peer * peer)
|
||||
{
|
||||
tr_peerDestruct (s->tor, peer);
|
||||
tr_free (peer);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
replicationExists (const tr_swarm * s)
|
||||
{
|
||||
|
@ -466,8 +462,7 @@ replicationNew (tr_swarm * s)
|
|||
{
|
||||
tr_piece_index_t piece_i;
|
||||
const tr_piece_index_t piece_count = s->tor->info.pieceCount;
|
||||
tr_peer ** peers = (tr_peer**) tr_ptrArrayBase (&s->peers);
|
||||
const int peer_count = tr_ptrArraySize (&s->peers);
|
||||
const int n = tr_ptrArraySize (&s->peers);
|
||||
|
||||
assert (!replicationExists (s));
|
||||
|
||||
|
@ -479,9 +474,12 @@ replicationNew (tr_swarm * s)
|
|||
int peer_i;
|
||||
uint16_t r = 0;
|
||||
|
||||
for (peer_i=0; peer_i<peer_count; ++peer_i)
|
||||
if (tr_bitfieldHas (&peers[peer_i]->have, piece_i))
|
||||
++r;
|
||||
for (peer_i=0; peer_i<n; ++peer_i)
|
||||
{
|
||||
tr_peer * peer = tr_ptrArrayNth (&s->peers, peer_i);
|
||||
if (tr_bitfieldHas (&peer->have, piece_i))
|
||||
++r;
|
||||
}
|
||||
|
||||
s->pieceReplication[piece_i] = r;
|
||||
}
|
||||
|
@ -498,7 +496,7 @@ swarmFree (void * vs)
|
|||
assert (tr_ptrArrayEmpty (&s->outgoingHandshakes));
|
||||
assert (tr_ptrArrayEmpty (&s->peers));
|
||||
|
||||
tr_ptrArrayDestruct (&s->webseeds, (PtrArrayForeachFunc)tr_webseedFree);
|
||||
tr_ptrArrayDestruct (&s->webseeds, (PtrArrayForeachFunc)tr_peerFree);
|
||||
tr_ptrArrayDestruct (&s->pool, (PtrArrayForeachFunc)tr_free);
|
||||
tr_ptrArrayDestruct (&s->outgoingHandshakes, NULL);
|
||||
tr_ptrArrayDestruct (&s->peers, NULL);
|
||||
|
@ -519,11 +517,11 @@ rebuildWebseedArray (tr_swarm * s, tr_torrent * tor)
|
|||
const tr_info * inf = &tor->info;
|
||||
|
||||
/* clear the array */
|
||||
tr_ptrArrayDestruct (&s->webseeds, (PtrArrayForeachFunc)tr_webseedFree);
|
||||
tr_ptrArrayDestruct (&s->webseeds, (PtrArrayForeachFunc)tr_peerFree);
|
||||
s->webseeds = TR_PTR_ARRAY_INIT;
|
||||
|
||||
/* repopulate it */
|
||||
for (i = 0; i < inf->webseedCount; ++i)
|
||||
for (i=0; i<inf->webseedCount; ++i)
|
||||
{
|
||||
tr_webseed * w = tr_webseedNew (tor, inf->webseeds[i], peerCallbackFunc, s);
|
||||
tr_ptrArrayAppend (&s->webseeds, w);
|
||||
|
@ -598,18 +596,18 @@ tr_peerMgrFree (tr_peerMgr * manager)
|
|||
}
|
||||
|
||||
static int
|
||||
clientIsDownloadingFrom (const tr_torrent * tor, const tr_peer * peer)
|
||||
clientIsDownloadingFrom (const tr_torrent * tor, const tr_peerMsgs * p)
|
||||
{
|
||||
if (!tr_torrentHasMetadata (tor))
|
||||
return true;
|
||||
|
||||
return peer->clientIsInterested && !peer->clientIsChoked;
|
||||
return tr_peerMsgsIsClientInterested (p) && !tr_peerMsgsIsClientChoked (p);
|
||||
}
|
||||
|
||||
static int
|
||||
clientIsUploadingTo (const tr_peer * peer)
|
||||
clientIsUploadingTo (const tr_peerMsgs * p)
|
||||
{
|
||||
return peer->peerIsInterested && !peer->peerIsChoked;
|
||||
return tr_peerMsgsIsPeerInterested (p) && !tr_peerMsgsIsPeerChoked (p);
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -868,14 +866,15 @@ requestListRemove (tr_swarm * s, tr_block_index_t block, const tr_peer * peer)
|
|||
}
|
||||
|
||||
static int
|
||||
countActiveWebseeds (const tr_swarm * s)
|
||||
countActiveWebseeds (tr_swarm * s)
|
||||
{
|
||||
int i;
|
||||
int activeCount = 0;
|
||||
const tr_webseed ** w = (const tr_webseed **) tr_ptrArrayBase (&s->webseeds);
|
||||
const tr_webseed ** const wend = w + tr_ptrArraySize (&s->webseeds);
|
||||
const int n = tr_ptrArraySize (&s->webseeds);
|
||||
const uint64_t now = tr_time_msec ();
|
||||
|
||||
for (; w!=wend; ++w)
|
||||
if (tr_webseedIsActive (*w))
|
||||
for (i=0; i<n; ++i)
|
||||
if (tr_peerIsTransferringPieces (tr_ptrArrayNth(&s->webseeds,i), now, TR_DOWN, NULL))
|
||||
++activeCount;
|
||||
|
||||
return activeCount;
|
||||
|
@ -902,14 +901,17 @@ updateEndgame (tr_swarm * s)
|
|||
}
|
||||
else if (!s->endgame) /* only recalculate when endgame first begins */
|
||||
{
|
||||
int i;
|
||||
int numDownloading = 0;
|
||||
const tr_peer ** p = (const tr_peer **) tr_ptrArrayBase (&s->peers);
|
||||
const tr_peer ** const pend = p + tr_ptrArraySize (&s->peers);
|
||||
const int n = tr_ptrArraySize (&s->peers);
|
||||
|
||||
/* add the active bittorrent peers... */
|
||||
for (; p!=pend; ++p)
|
||||
if ((*p)->pendingReqsToPeer > 0)
|
||||
++numDownloading;
|
||||
for (i=0; i<n; ++i)
|
||||
{
|
||||
const tr_peer * p = tr_ptrArrayNth (&s->peers, i);
|
||||
if (p->pendingReqsToPeer > 0)
|
||||
++numDownloading;
|
||||
}
|
||||
|
||||
/* add the active webseeds... */
|
||||
numDownloading += countActiveWebseeds (s);
|
||||
|
@ -1340,8 +1342,6 @@ tr_peerMgrGetNextRequests (tr_torrent * tor,
|
|||
|
||||
/* sanity clause */
|
||||
assert (tr_isTorrent (tor));
|
||||
assert (peer->clientIsInterested);
|
||||
assert (!peer->clientIsChoked);
|
||||
assert (numwant > 0);
|
||||
|
||||
/* walk through the pieces and find blocks that should be requested */
|
||||
|
@ -1515,7 +1515,9 @@ refillUpkeep (int foo UNUSED, short bar UNUSED, void * vmgr)
|
|||
|
||||
for (it=s->requests, end=it+n; it!=end; ++it)
|
||||
{
|
||||
if ((it->sentAt <= too_old) && it->peer->msgs && !tr_peerMsgsIsReadingBlock (it->peer->msgs, it->block))
|
||||
tr_peerMsgs * msgs = PEER_MSGS(it->peer);
|
||||
|
||||
if ((msgs !=NULL) && (it->sentAt <= too_old) && !tr_peerMsgsIsReadingBlock (msgs, it->block))
|
||||
cancel[cancelCount++] = *it;
|
||||
else
|
||||
{
|
||||
|
@ -1529,11 +1531,15 @@ refillUpkeep (int foo UNUSED, short bar UNUSED, void * vmgr)
|
|||
s->requestCount = keepCount;
|
||||
|
||||
/* send cancel messages for all the "cancel" ones */
|
||||
for (it=cancel, end=it+cancelCount; it!=end; ++it) {
|
||||
if ((it->peer != NULL) && (it->peer->msgs != NULL)) {
|
||||
tr_historyAdd (&it->peer->cancelsSentToPeer, now, 1);
|
||||
tr_peerMsgsCancel (it->peer->msgs, it->block);
|
||||
decrementPendingReqCount (it);
|
||||
for (it=cancel, end=it+cancelCount; it!=end; ++it)
|
||||
{
|
||||
tr_peerMsgs * msgs = PEER_MSGS(it->peer);
|
||||
|
||||
if (msgs != NULL)
|
||||
{
|
||||
tr_historyAdd (&it->peer->cancelsSentToPeer, now, 1);
|
||||
tr_peerMsgsCancel (msgs, it->block);
|
||||
decrementPendingReqCount (it);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1655,10 +1661,10 @@ cancelAllRequestsForBlock (tr_swarm * s,
|
|||
{
|
||||
tr_peer * p = peers[i];
|
||||
|
||||
if ((p != no_notify) && (p->msgs != NULL))
|
||||
if ((p != no_notify) && (p != NULL))
|
||||
{
|
||||
tr_historyAdd (&p->cancelsSentToPeer, tr_time (), 1);
|
||||
tr_peerMsgsCancel (p->msgs, block);
|
||||
tr_peerMsgsCancel (PEER_MSGS(p), block);
|
||||
}
|
||||
|
||||
removeRequestFromTables (s, block, p);
|
||||
|
@ -1670,19 +1676,21 @@ cancelAllRequestsForBlock (tr_swarm * s,
|
|||
void
|
||||
tr_peerMgrPieceCompleted (tr_torrent * tor, tr_piece_index_t p)
|
||||
{
|
||||
int i;
|
||||
bool pieceCameFromPeers = false;
|
||||
tr_swarm * const s = tor->swarm;
|
||||
const tr_peer ** peer = (const tr_peer **) tr_ptrArrayBase (&s->peers);
|
||||
const tr_peer ** const pend = peer + tr_ptrArraySize (&s->peers);
|
||||
const int n = tr_ptrArraySize (&s->peers);
|
||||
|
||||
/* walk through our peers */
|
||||
for ( ; peer!=pend; ++peer)
|
||||
for (i=0; i<n; ++i)
|
||||
{
|
||||
tr_peer * peer = tr_ptrArrayNth (&s->peers, i);
|
||||
|
||||
/* notify the peer that we now have this piece */
|
||||
tr_peerMsgsHave ((*peer)->msgs, p);
|
||||
tr_peerMsgsHave (PEER_MSGS(peer), p);
|
||||
|
||||
if (!pieceCameFromPeers)
|
||||
pieceCameFromPeers = tr_bitfieldHas (&(*peer)->blame, p);
|
||||
pieceCameFromPeers = tr_bitfieldHas (&peer->blame, p);
|
||||
}
|
||||
|
||||
if (pieceCameFromPeers) /* webseed downloads don't belong in announce totals */
|
||||
|
@ -1901,6 +1909,31 @@ getPeerCount (const tr_swarm * s)
|
|||
return tr_ptrArraySize (&s->peers);/* + tr_ptrArraySize (&t->outgoingHandshakes); */
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
createBitTorrentPeer (tr_torrent * tor,
|
||||
struct tr_peerIo * io,
|
||||
struct peer_atom * atom,
|
||||
tr_quark client)
|
||||
{
|
||||
tr_peer * peer;
|
||||
tr_swarm * swarm;
|
||||
|
||||
assert (atom != NULL);
|
||||
assert (tr_isTorrent (tor));
|
||||
assert (tor->swarm != NULL);
|
||||
|
||||
swarm = tor->swarm;
|
||||
|
||||
peer = (tr_peer*) tr_peerMsgsNew (tor, io, peerCallbackFunc, swarm);
|
||||
peer->atom = atom;
|
||||
peer->client = client;
|
||||
atom->peer = peer;
|
||||
|
||||
tr_ptrArrayInsertSorted (&swarm->peers, peer, peerCompare);
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: this is kind of a mess. */
|
||||
static bool
|
||||
myHandshakeDoneCB (tr_handshake * handshake,
|
||||
|
@ -1997,21 +2030,19 @@ myHandshakeDoneCB (tr_handshake * handshake,
|
|||
}
|
||||
else
|
||||
{
|
||||
peer = getPeer (s, atom);
|
||||
tr_quark client;
|
||||
tr_peerIo * io;
|
||||
char buf[128];
|
||||
|
||||
if (!peer_id)
|
||||
peer->client = TR_KEY_NONE;
|
||||
if (peer_id != NULL)
|
||||
client = tr_quark_new (tr_clientForId (buf, sizeof (buf), peer_id), -1);
|
||||
else
|
||||
{
|
||||
char client[128];
|
||||
tr_clientForId (client, sizeof (client), peer_id);
|
||||
peer->client = tr_quark_new (client, -1);
|
||||
}
|
||||
client = TR_KEY_NONE;
|
||||
|
||||
peer->io = tr_handshakeStealIO (handshake); /* this steals its refcount too, which is
|
||||
balanced by our unref in peerDelete () */
|
||||
tr_peerIoSetParent (peer->io, &s->tor->bandwidth);
|
||||
tr_peerMsgsNew (s->tor, peer, peerCallbackFunc, s);
|
||||
io = tr_handshakeStealIO (handshake); /* this steals its refcount too, which is
|
||||
balanced by our unref in peerDelete () */
|
||||
tr_peerIoSetParent (io, &s->tor->bandwidth);
|
||||
createBitTorrentPeer (s->tor, io, atom, client);
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
@ -2400,7 +2431,7 @@ stopSwarm (tr_swarm * swarm)
|
|||
|
||||
/* disconnect the peers. */
|
||||
while ((peer = tr_ptrArrayPop (&swarm->peers)))
|
||||
peerDelete (swarm, peer);
|
||||
tr_peerFree (peer);
|
||||
|
||||
/* disconnect the handshakes. handshakeAbort calls handshakeDoneCB (),
|
||||
* which removes the handshake from t->outgoingHandshakes... */
|
||||
|
@ -2533,13 +2564,13 @@ tr_peerMgrTorrentAvailability (const tr_torrent * tor,
|
|||
static bool
|
||||
peerIsSeed (const tr_peer * peer)
|
||||
{
|
||||
if (peer->progress >= 1.0)
|
||||
return true;
|
||||
if (peer->progress >= 1.0)
|
||||
return true;
|
||||
|
||||
if (peer->atom && atomIsSeed (peer->atom))
|
||||
return true;
|
||||
if (peer->atom && atomIsSeed (peer->atom))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* count how many bytes we want that connected peers have */
|
||||
|
@ -2595,9 +2626,8 @@ tr_peerMgrTorrentStats (tr_torrent * tor,
|
|||
int * setmePeersFrom)
|
||||
{
|
||||
int i;
|
||||
int size;
|
||||
int n;
|
||||
tr_swarm * s;
|
||||
const tr_peer ** peers;
|
||||
|
||||
assert (tr_isTorrent (tor));
|
||||
|
||||
|
@ -2607,28 +2637,27 @@ tr_peerMgrTorrentStats (tr_torrent * tor,
|
|||
*setmeWebseedsSendingToUs = 0;
|
||||
|
||||
s = tor->swarm;
|
||||
size = tr_ptrArraySize (&s->peers);
|
||||
peers = (const tr_peer **) tr_ptrArrayBase (&s->peers);
|
||||
n = tr_ptrArraySize (&s->peers);
|
||||
|
||||
for (i=0; i<TR_PEER_FROM__MAX; ++i)
|
||||
setmePeersFrom[i] = 0;
|
||||
|
||||
for (i=0; i<size; ++i)
|
||||
for (i=0; i<n; ++i)
|
||||
{
|
||||
const tr_peer * peer = peers[i];
|
||||
tr_peer * peer = tr_ptrArrayNth (&s->peers, i);
|
||||
tr_peerMsgs * msgs = PEER_MSGS (peer);
|
||||
const struct peer_atom * atom = peer->atom;
|
||||
|
||||
if (peer->io == NULL) /* not connected */
|
||||
continue;
|
||||
assert (msgs != NULL);
|
||||
|
||||
++*setmePeersConnected;
|
||||
|
||||
++setmePeersFrom[atom->fromFirst];
|
||||
|
||||
if (clientIsDownloadingFrom (tor, peer))
|
||||
if (clientIsDownloadingFrom (tor, msgs))
|
||||
++*setmePeersSendingToUs;
|
||||
|
||||
if (clientIsUploadingTo (peer))
|
||||
if (clientIsUploadingTo (msgs))
|
||||
++*setmePeersGettingFromUs;
|
||||
}
|
||||
|
||||
|
@ -2639,26 +2668,24 @@ double*
|
|||
tr_peerMgrWebSpeeds_KBps (const tr_torrent * tor)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int webseedCount;
|
||||
const tr_swarm * s;
|
||||
const tr_webseed ** webseeds;
|
||||
tr_swarm * s;
|
||||
unsigned int n;
|
||||
double * ret = NULL;
|
||||
const uint64_t now = tr_time_msec ();
|
||||
|
||||
assert (tr_isTorrent (tor));
|
||||
|
||||
s = tor->swarm;
|
||||
webseedCount = tr_ptrArraySize (&s->webseeds);
|
||||
webseeds = (const tr_webseed**) tr_ptrArrayBase (&s->webseeds);
|
||||
ret = tr_new0 (double, webseedCount);
|
||||
n = tr_ptrArraySize (&s->webseeds);
|
||||
ret = tr_new0 (double, n);
|
||||
|
||||
assert (s->manager != NULL);
|
||||
assert (webseedCount == tor->info.webseedCount);
|
||||
assert (n == tor->info.webseedCount);
|
||||
|
||||
for (i=0; i<webseedCount; ++i)
|
||||
for (i=0; i<n; ++i)
|
||||
{
|
||||
unsigned int Bps;
|
||||
if (tr_webseedGetSpeed_Bps (webseeds[i], now, &Bps))
|
||||
unsigned int Bps = 0;
|
||||
if (tr_peerIsTransferringPieces (tr_ptrArrayNth(&s->webseeds,i), now, TR_DOWN, &Bps))
|
||||
ret[i] = Bps / (double)tr_speed_K;
|
||||
else
|
||||
ret[i] = -1.0;
|
||||
|
@ -2667,12 +2694,6 @@ tr_peerMgrWebSpeeds_KBps (const tr_torrent * tor)
|
|||
return ret;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
tr_peerGetPieceSpeed_Bps (const tr_peer * peer, uint64_t now, tr_direction direction)
|
||||
{
|
||||
return peer->io ? tr_peerIoGetPieceSpeed_Bps (peer->io, now, direction) : 0.0;
|
||||
}
|
||||
|
||||
struct tr_peer_stat *
|
||||
tr_peerMgrPeerStats (const tr_torrent * tor, int * setmeCount)
|
||||
{
|
||||
|
@ -2680,7 +2701,7 @@ tr_peerMgrPeerStats (const tr_torrent * tor, int * setmeCount)
|
|||
int size = 0;
|
||||
tr_peer_stat * ret;
|
||||
const tr_swarm * s;
|
||||
const tr_peer ** peers;
|
||||
tr_peer ** peers;
|
||||
const time_t now = tr_time ();
|
||||
const uint64_t now_msec = tr_time_msec ();
|
||||
|
||||
|
@ -2688,14 +2709,15 @@ tr_peerMgrPeerStats (const tr_torrent * tor, int * setmeCount)
|
|||
assert (tor->swarm->manager != NULL);
|
||||
|
||||
s = tor->swarm;
|
||||
peers = (const tr_peer**) tr_ptrArrayBase (&s->peers);
|
||||
peers = (tr_peer**) tr_ptrArrayBase (&s->peers);
|
||||
size = tr_ptrArraySize (&s->peers);
|
||||
ret = tr_new0 (tr_peer_stat, size);
|
||||
|
||||
for (i=0; i<size; ++i)
|
||||
{
|
||||
char * pch;
|
||||
const tr_peer * peer = peers[i];
|
||||
tr_peer * peer = peers[i];
|
||||
tr_peerMsgs * msgs = PEER_MSGS (peer);
|
||||
const struct peer_atom * atom = peer->atom;
|
||||
tr_peer_stat * stat = ret + i;
|
||||
|
||||
|
@ -2704,17 +2726,17 @@ tr_peerMgrPeerStats (const tr_torrent * tor, int * setmeCount)
|
|||
stat->port = ntohs (peer->atom->port);
|
||||
stat->from = atom->fromFirst;
|
||||
stat->progress = peer->progress;
|
||||
stat->isUTP = peer->io->utp_socket != NULL;
|
||||
stat->isEncrypted = tr_peerIoIsEncrypted (peer->io) ? 1 : 0;
|
||||
stat->isUTP = tr_peerMsgsIsUtpConnection (msgs);
|
||||
stat->isEncrypted = tr_peerMsgsIsEncrypted (msgs);
|
||||
stat->rateToPeer_KBps = toSpeedKBps (tr_peerGetPieceSpeed_Bps (peer, now_msec, TR_CLIENT_TO_PEER));
|
||||
stat->rateToClient_KBps = toSpeedKBps (tr_peerGetPieceSpeed_Bps (peer, now_msec, TR_PEER_TO_CLIENT));
|
||||
stat->peerIsChoked = peer->peerIsChoked;
|
||||
stat->peerIsInterested = peer->peerIsInterested;
|
||||
stat->clientIsChoked = peer->clientIsChoked;
|
||||
stat->clientIsInterested = peer->clientIsInterested;
|
||||
stat->isIncoming = tr_peerIoIsIncoming (peer->io);
|
||||
stat->isDownloadingFrom = clientIsDownloadingFrom (tor, peer);
|
||||
stat->isUploadingTo = clientIsUploadingTo (peer);
|
||||
stat->peerIsChoked = tr_peerMsgsIsPeerChoked (msgs);
|
||||
stat->peerIsInterested = tr_peerMsgsIsPeerInterested (msgs);
|
||||
stat->clientIsChoked = tr_peerMsgsIsClientChoked (msgs);
|
||||
stat->clientIsInterested = tr_peerMsgsIsClientInterested (msgs);
|
||||
stat->isIncoming = tr_peerMsgsIsIncomingConnection (msgs);
|
||||
stat->isDownloadingFrom = clientIsDownloadingFrom (tor, msgs);
|
||||
stat->isUploadingTo = clientIsUploadingTo (msgs);
|
||||
stat->isSeed = peerIsSeed (peer);
|
||||
|
||||
stat->blocksToPeer = tr_historyGet (&peer->blocksSentToPeer, now, CANCEL_HISTORY_SEC);
|
||||
|
@ -2727,7 +2749,7 @@ tr_peerMgrPeerStats (const tr_torrent * tor, int * setmeCount)
|
|||
|
||||
pch = stat->flagStr;
|
||||
if (stat->isUTP) *pch++ = 'T';
|
||||
if (s->optimistic == peer) *pch++ = 'O';
|
||||
if (s->optimistic == msgs) *pch++ = 'O';
|
||||
if (stat->isDownloadingFrom) *pch++ = 'D';
|
||||
else if (stat->clientIsInterested) *pch++ = 'd';
|
||||
if (stat->isUploadingTo) *pch++ = 'U';
|
||||
|
@ -2761,10 +2783,7 @@ tr_peerMgrClearInterest (tr_torrent * tor)
|
|||
assert (tr_torrentIsLocked (tor));
|
||||
|
||||
for (i=0; i<peerCount; ++i)
|
||||
{
|
||||
const tr_peer * peer = tr_ptrArrayNth (&s->peers, i);
|
||||
tr_peerMsgsSetInterested (peer->msgs, false);
|
||||
}
|
||||
tr_peerMsgsSetInterested (tr_ptrArrayNth (&s->peers, i), false);
|
||||
}
|
||||
|
||||
/* does this peer have any pieces that we want? */
|
||||
|
@ -2920,7 +2939,7 @@ rechokeDownloads (tr_swarm * s)
|
|||
|
||||
if (!isPeerInteresting (s->tor, piece_is_interesting, peer))
|
||||
{
|
||||
tr_peerMsgsSetInterested (peer->msgs, false);
|
||||
tr_peerMsgsSetInterested (PEER_MSGS(peer), false);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2957,7 +2976,7 @@ rechokeDownloads (tr_swarm * s)
|
|||
qsort (rechoke, rechoke_count, sizeof (struct tr_rechoke_info), compare_rechoke_info);
|
||||
s->interestedCount = MIN (maxPeers, rechoke_count);
|
||||
for (i=0; i<rechoke_count; ++i)
|
||||
tr_peerMsgsSetInterested (rechoke[i].peer->msgs, i<s->interestedCount);
|
||||
tr_peerMsgsSetInterested (PEER_MSGS(rechoke[i].peer), i<s->interestedCount);
|
||||
|
||||
/* cleanup */
|
||||
tr_free (rechoke);
|
||||
|
@ -2969,12 +2988,12 @@ rechokeDownloads (tr_swarm * s)
|
|||
|
||||
struct ChokeData
|
||||
{
|
||||
bool isInterested;
|
||||
bool wasChoked;
|
||||
bool isChoked;
|
||||
int rate;
|
||||
int salt;
|
||||
tr_peer * peer;
|
||||
bool isInterested;
|
||||
bool wasChoked;
|
||||
bool isChoked;
|
||||
int rate;
|
||||
int salt;
|
||||
tr_peerMsgs * msgs;
|
||||
};
|
||||
|
||||
static int
|
||||
|
@ -2996,10 +3015,10 @@ compareChoke (const void * va, const void * vb)
|
|||
}
|
||||
|
||||
/* is this a new connection? */
|
||||
static int
|
||||
isNew (const tr_peer * peer)
|
||||
static bool
|
||||
isNew (const tr_peerMsgs * msgs)
|
||||
{
|
||||
return peer && peer->io && tr_peerIoGetAge (peer->io) < 45;
|
||||
return (msgs != NULL) && (tr_peerMsgsGetConnectionAge (msgs) < 45);
|
||||
}
|
||||
|
||||
/* get a rate for deciding which peers to choke and unchoke. */
|
||||
|
@ -3065,22 +3084,24 @@ rechokeUploads (tr_swarm * s, const uint64_t now)
|
|||
for (i=0, size=0; i<peerCount; ++i)
|
||||
{
|
||||
tr_peer * peer = peers[i];
|
||||
tr_peerMsgs * msgs = PEER_MSGS (peer);
|
||||
|
||||
struct peer_atom * atom = peer->atom;
|
||||
|
||||
if (peerIsSeed (peer)) /* choke seeds and partial seeds */
|
||||
{
|
||||
tr_peerMsgsSetChoke (peer->msgs, true);
|
||||
tr_peerMsgsSetChoke (PEER_MSGS(peer), true);
|
||||
}
|
||||
else if (chokeAll) /* choke everyone if we're not uploading */
|
||||
{
|
||||
tr_peerMsgsSetChoke (peer->msgs, true);
|
||||
tr_peerMsgsSetChoke (PEER_MSGS(peer), true);
|
||||
}
|
||||
else if (peer != s->optimistic)
|
||||
else if (msgs != s->optimistic)
|
||||
{
|
||||
struct ChokeData * n = &choke[size++];
|
||||
n->peer = peer;
|
||||
n->isInterested = peer->peerIsInterested;
|
||||
n->wasChoked = peer->peerIsChoked;
|
||||
n->msgs = msgs;
|
||||
n->isInterested = tr_peerMsgsIsPeerInterested (msgs);
|
||||
n->wasChoked = tr_peerMsgsIsPeerChoked (msgs);
|
||||
n->rate = getRate (s->tor, atom, now);
|
||||
n->salt = tr_cryptoWeakRandInt (INT_MAX);
|
||||
n->isChoked = true;
|
||||
|
@ -3123,9 +3144,9 @@ rechokeUploads (tr_swarm * s, const uint64_t now)
|
|||
{
|
||||
if (choke[i].isInterested)
|
||||
{
|
||||
const tr_peer * peer = choke[i].peer;
|
||||
const tr_peerMsgs * msgs = choke[i].msgs;
|
||||
int x = 1, y;
|
||||
if (isNew (peer)) x *= 3;
|
||||
if (isNew (msgs)) x *= 3;
|
||||
for (y=0; y<x; ++y)
|
||||
tr_ptrArrayAppend (&randPool, &choke[i]);
|
||||
}
|
||||
|
@ -3135,7 +3156,7 @@ rechokeUploads (tr_swarm * s, const uint64_t now)
|
|||
{
|
||||
c = tr_ptrArrayNth (&randPool, tr_cryptoWeakRandInt (n));
|
||||
c->isChoked = false;
|
||||
s->optimistic = c->peer;
|
||||
s->optimistic = c->msgs;
|
||||
s->optimisticUnchokeTimeScaler = OPTIMISTIC_UNCHOKE_MULTIPLIER;
|
||||
}
|
||||
|
||||
|
@ -3143,7 +3164,7 @@ rechokeUploads (tr_swarm * s, const uint64_t now)
|
|||
}
|
||||
|
||||
for (i=0; i<size; ++i)
|
||||
tr_peerMsgsSetChoke (choke[i].peer->msgs, choke[i].isChoked);
|
||||
tr_peerMsgsSetChoke (choke[i].msgs, choke[i].isChoked);
|
||||
|
||||
/* cleanup */
|
||||
tr_free (choke);
|
||||
|
@ -3305,7 +3326,7 @@ removePeer (tr_swarm * s, tr_peer * peer)
|
|||
tr_decrReplicationFromBitfield (s, &peer->have);
|
||||
|
||||
assert (removed == peer);
|
||||
peerDelete (s, removed);
|
||||
tr_peerFree (removed);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -3332,7 +3353,7 @@ closePeer (tr_swarm * s, tr_peer * peer)
|
|||
tordbg (s, "incremented atom %s numFails to %d", tr_atomAddrStr (atom), (int)atom->numFails);
|
||||
}
|
||||
|
||||
tordbg (s, "removing bad peer %s", tr_peerIoGetAddrStr (peer->io));
|
||||
tordbg (s, "removing bad peer %s", tr_atomAddrStr (peer->atom));
|
||||
removePeer (s, peer);
|
||||
}
|
||||
|
||||
|
@ -3554,10 +3575,7 @@ pumpAllPeers (tr_peerMgr * mgr)
|
|||
tr_swarm * s = tor->swarm;
|
||||
|
||||
for (j=0; j<tr_ptrArraySize (&s->peers); ++j)
|
||||
{
|
||||
tr_peer * peer = tr_ptrArrayNth (&s->peers, j);
|
||||
tr_peerMsgsPulse (peer->msgs);
|
||||
}
|
||||
tr_peerMsgsPulse (tr_ptrArrayNth (&s->peers, j));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,140 +65,134 @@ typedef struct tr_pex
|
|||
}
|
||||
tr_pex;
|
||||
|
||||
|
||||
struct tr_peerIo;
|
||||
struct tr_peermsgs;
|
||||
|
||||
/* opaque forward declaration */
|
||||
struct peer_atom;
|
||||
|
||||
void tr_peerConstruct (struct tr_peer * peer);
|
||||
|
||||
void tr_peerDestruct (tr_torrent * tor, struct tr_peer * peer);
|
||||
|
||||
struct tr_peerIo;
|
||||
struct tr_peerMsgs;
|
||||
struct tr_swarm;
|
||||
|
||||
static inline bool
|
||||
tr_isPex (const tr_pex * pex)
|
||||
{
|
||||
return pex && tr_address_is_valid (&pex->addr);
|
||||
return pex && tr_address_is_valid (&pex->addr);
|
||||
}
|
||||
|
||||
const tr_address * tr_peerAddress (const tr_peer *);
|
||||
|
||||
int tr_pexCompare (const void * a, const void * b);
|
||||
|
||||
tr_peerMgr* tr_peerMgrNew (tr_session *);
|
||||
tr_peerMgr * tr_peerMgrNew (tr_session * session);
|
||||
|
||||
void tr_peerMgrFree (tr_peerMgr * manager);
|
||||
void tr_peerMgrFree (tr_peerMgr * manager);
|
||||
|
||||
bool tr_peerMgrPeerIsSeed (const tr_torrent * tor,
|
||||
const tr_address * addr);
|
||||
bool tr_peerMgrPeerIsSeed (const tr_torrent * tor,
|
||||
const tr_address * addr);
|
||||
|
||||
void tr_peerMgrSetUtpSupported (tr_torrent * tor,
|
||||
const tr_address * addr);
|
||||
void tr_peerMgrSetUtpSupported (tr_torrent * tor,
|
||||
const tr_address * addr);
|
||||
|
||||
void tr_peerMgrSetUtpFailed (tr_torrent *tor,
|
||||
const tr_address *addr,
|
||||
bool failed);
|
||||
void tr_peerMgrSetUtpFailed (tr_torrent * tor,
|
||||
const tr_address * addr,
|
||||
bool failed);
|
||||
|
||||
void tr_peerMgrGetNextRequests (tr_torrent * torrent,
|
||||
tr_peer * peer,
|
||||
int numwant,
|
||||
tr_block_index_t * setme,
|
||||
int * numgot,
|
||||
bool get_intervals);
|
||||
void tr_peerMgrGetNextRequests (tr_torrent * torrent,
|
||||
tr_peer * peer,
|
||||
int numwant,
|
||||
tr_block_index_t * setme,
|
||||
int * numgot,
|
||||
bool get_intervals);
|
||||
|
||||
bool tr_peerMgrDidPeerRequest (const tr_torrent * torrent,
|
||||
const tr_peer * peer,
|
||||
tr_block_index_t block);
|
||||
bool tr_peerMgrDidPeerRequest (const tr_torrent * torrent,
|
||||
const tr_peer * peer,
|
||||
tr_block_index_t block);
|
||||
|
||||
void tr_peerMgrRebuildRequests (tr_torrent * torrent);
|
||||
void tr_peerMgrRebuildRequests (tr_torrent * torrent);
|
||||
|
||||
void tr_peerMgrAddIncoming (tr_peerMgr * manager,
|
||||
tr_address * addr,
|
||||
tr_port port,
|
||||
int socket,
|
||||
struct UTPSocket *utp_socket);
|
||||
void tr_peerMgrAddIncoming (tr_peerMgr * manager,
|
||||
tr_address * addr,
|
||||
tr_port port,
|
||||
int socket,
|
||||
struct UTPSocket * utp_socket);
|
||||
|
||||
tr_pex * tr_peerMgrCompactToPex (const void * compact,
|
||||
size_t compactLen,
|
||||
const uint8_t * added_f,
|
||||
size_t added_f_len,
|
||||
size_t * setme_pex_count);
|
||||
tr_pex * tr_peerMgrCompactToPex (const void * compact,
|
||||
size_t compactLen,
|
||||
const uint8_t * added_f,
|
||||
size_t added_f_len,
|
||||
size_t * setme_pex_count);
|
||||
|
||||
tr_pex * tr_peerMgrCompact6ToPex (const void * compact,
|
||||
size_t compactLen,
|
||||
const uint8_t * added_f,
|
||||
size_t added_f_len,
|
||||
size_t * pexCount);
|
||||
tr_pex * tr_peerMgrCompact6ToPex (const void * compact,
|
||||
size_t compactLen,
|
||||
const uint8_t * added_f,
|
||||
size_t added_f_len,
|
||||
size_t * pexCount);
|
||||
|
||||
tr_pex * tr_peerMgrArrayToPex (const void * array,
|
||||
size_t arrayLen,
|
||||
size_t * setme_pex_count);
|
||||
tr_pex * tr_peerMgrArrayToPex (const void * array,
|
||||
size_t arrayLen,
|
||||
size_t * setme_pex_count);
|
||||
|
||||
/**
|
||||
* @param seedProbability [0..100] for likelihood that the peer is a seed; -1 for unknown
|
||||
*/
|
||||
void tr_peerMgrAddPex (tr_torrent * tor,
|
||||
uint8_t from,
|
||||
const tr_pex * pex,
|
||||
int8_t seedProbability);
|
||||
void tr_peerMgrAddPex (tr_torrent * tor,
|
||||
uint8_t from,
|
||||
const tr_pex * pex,
|
||||
int8_t seedProbability);
|
||||
|
||||
void tr_peerMgrMarkAllAsSeeds (tr_torrent * tor);
|
||||
void tr_peerMgrMarkAllAsSeeds (tr_torrent * tor);
|
||||
|
||||
enum
|
||||
{
|
||||
TR_PEERS_CONNECTED,
|
||||
TR_PEERS_INTERESTING
|
||||
TR_PEERS_CONNECTED,
|
||||
TR_PEERS_INTERESTING
|
||||
};
|
||||
|
||||
int tr_peerMgrGetPeers (tr_torrent * tor,
|
||||
tr_pex ** setme_pex,
|
||||
uint8_t address_type,
|
||||
uint8_t peer_list_mode,
|
||||
int max_peer_count);
|
||||
int tr_peerMgrGetPeers (tr_torrent * tor,
|
||||
tr_pex ** setme_pex,
|
||||
uint8_t address_type,
|
||||
uint8_t peer_list_mode,
|
||||
int max_peer_count);
|
||||
|
||||
void tr_peerMgrStartTorrent (tr_torrent * tor);
|
||||
void tr_peerMgrStartTorrent (tr_torrent * tor);
|
||||
|
||||
void tr_peerMgrStopTorrent (tr_torrent * tor);
|
||||
void tr_peerMgrStopTorrent (tr_torrent * tor);
|
||||
|
||||
void tr_peerMgrAddTorrent (tr_peerMgr * manager,
|
||||
struct tr_torrent * tor);
|
||||
void tr_peerMgrAddTorrent (tr_peerMgr * manager,
|
||||
struct tr_torrent * tor);
|
||||
|
||||
void tr_peerMgrRemoveTorrent (tr_torrent * tor);
|
||||
void tr_peerMgrRemoveTorrent (tr_torrent * tor);
|
||||
|
||||
void tr_peerMgrTorrentAvailability (const tr_torrent * tor,
|
||||
int8_t * tab,
|
||||
unsigned int tabCount);
|
||||
void tr_peerMgrTorrentAvailability (const tr_torrent * tor,
|
||||
int8_t * tab,
|
||||
unsigned int tabCount);
|
||||
|
||||
uint64_t tr_peerMgrGetDesiredAvailable (const tr_torrent * tor);
|
||||
uint64_t tr_peerMgrGetDesiredAvailable (const tr_torrent * tor);
|
||||
|
||||
void tr_peerMgrOnTorrentGotMetainfo (tr_torrent * tor);
|
||||
void tr_peerMgrOnTorrentGotMetainfo (tr_torrent * tor);
|
||||
|
||||
void tr_peerMgrOnBlocklistChanged (tr_peerMgr * manager);
|
||||
void tr_peerMgrOnBlocklistChanged (tr_peerMgr * manager);
|
||||
|
||||
void tr_peerMgrTorrentStats (tr_torrent * tor,
|
||||
int * setmePeersConnected,
|
||||
int * setmeWebseedsSendingToUs,
|
||||
int * setmePeersSendingToUs,
|
||||
int * setmePeersGettingFromUs,
|
||||
int * setmePeersFrom); /* TR_PEER_FROM__MAX */
|
||||
void tr_peerMgrTorrentStats (tr_torrent * tor,
|
||||
int * setmePeersConnected,
|
||||
int * setmeWebseedsSendingToUs,
|
||||
int * setmePeersSendingToUs,
|
||||
int * setmePeersGettingFromUs,
|
||||
int * setmePeersFrom); /* TR_PEER_FROM__MAX */
|
||||
|
||||
struct tr_peer_stat* tr_peerMgrPeerStats (const tr_torrent * tor,
|
||||
int * setmeCount);
|
||||
struct tr_peer_stat * tr_peerMgrPeerStats (const tr_torrent * tor,
|
||||
int * setmeCount);
|
||||
|
||||
double* tr_peerMgrWebSpeeds_KBps (const tr_torrent * tor);
|
||||
double * tr_peerMgrWebSpeeds_KBps (const tr_torrent * tor);
|
||||
|
||||
unsigned int tr_peerGetPieceSpeed_Bps (const tr_peer * peer,
|
||||
uint64_t now,
|
||||
tr_direction direction);
|
||||
|
||||
unsigned int tr_peerGetPieceSpeed_Bps (const tr_peer * peer,
|
||||
uint64_t now,
|
||||
tr_direction direction);
|
||||
void tr_peerMgrClearInterest (tr_torrent * tor);
|
||||
|
||||
void tr_peerMgrClearInterest (tr_torrent * tor);
|
||||
void tr_peerMgrGotBadPiece (tr_torrent * tor,
|
||||
tr_piece_index_t pieceIndex);
|
||||
|
||||
void tr_peerMgrGotBadPiece (tr_torrent * tor, tr_piece_index_t pieceIndex);
|
||||
|
||||
void tr_peerMgrPieceCompleted (tr_torrent * tor, tr_piece_index_t pieceIndex);
|
||||
void tr_peerMgrPieceCompleted (tr_torrent * tor,
|
||||
tr_piece_index_t pieceIndex);
|
||||
|
||||
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -11,7 +11,7 @@
|
|||
*/
|
||||
|
||||
#ifndef __TRANSMISSION__
|
||||
#error only libtransmission should #include this header.
|
||||
#error only libtransmission should #include this header.
|
||||
#endif
|
||||
|
||||
#ifndef TR_PEER_MSGS_H
|
||||
|
@ -23,6 +23,7 @@
|
|||
struct tr_address;
|
||||
struct tr_bitfield;
|
||||
struct tr_peer;
|
||||
struct tr_peerIo;
|
||||
struct tr_torrent;
|
||||
|
||||
/**
|
||||
|
@ -30,37 +31,57 @@ struct tr_torrent;
|
|||
* @{
|
||||
*/
|
||||
|
||||
typedef struct tr_peermsgs tr_peermsgs;
|
||||
typedef struct tr_peerMsgs tr_peerMsgs;
|
||||
|
||||
tr_peermsgs* tr_peerMsgsNew (struct tr_torrent * torrent,
|
||||
struct tr_peer * peer,
|
||||
tr_peer_callback * callback,
|
||||
void * callback_data);
|
||||
#define PEER_MSGS(o) (tr_peerMsgsCast(o))
|
||||
|
||||
void tr_peerMsgsSetChoke (tr_peermsgs * msgs,
|
||||
bool peerIsChoked);
|
||||
bool tr_isPeerMsgs (const void * msgs);
|
||||
|
||||
int tr_peerMsgsIsReadingBlock (const tr_peermsgs * msgs,
|
||||
tr_block_index_t block);
|
||||
tr_peerMsgs* tr_peerMsgsCast (void * msgs);
|
||||
|
||||
void tr_peerMsgsSetInterested (tr_peermsgs * msgs,
|
||||
bool clientIsInterested);
|
||||
tr_peerMsgs* tr_peerMsgsNew (struct tr_torrent * torrent,
|
||||
struct tr_peerIo * io,
|
||||
tr_peer_callback * callback,
|
||||
void * callback_data);
|
||||
|
||||
void tr_peerMsgsHave (tr_peermsgs * msgs,
|
||||
uint32_t pieceIndex);
|
||||
bool tr_peerMsgsIsPeerChoked (const tr_peerMsgs * msgs);
|
||||
|
||||
void tr_peerMsgsPulse (tr_peermsgs * msgs);
|
||||
bool tr_peerMsgsIsPeerInterested (const tr_peerMsgs * msgs);
|
||||
|
||||
void tr_peerMsgsCancel (tr_peermsgs * msgs,
|
||||
tr_block_index_t block);
|
||||
bool tr_peerMsgsIsClientChoked (const tr_peerMsgs * msgs);
|
||||
|
||||
void tr_peerMsgsFree (tr_peermsgs * msgs);
|
||||
bool tr_peerMsgsIsClientInterested (const tr_peerMsgs * msgs);
|
||||
|
||||
size_t tr_generateAllowedSet (tr_piece_index_t * setmePieces,
|
||||
size_t desiredSetSize,
|
||||
size_t pieceCount,
|
||||
const uint8_t * infohash,
|
||||
const struct tr_address * addr);
|
||||
time_t tr_peerMsgsGetConnectionAge (const tr_peerMsgs * msgs);
|
||||
|
||||
bool tr_peerMsgsIsUtpConnection (const tr_peerMsgs * msgs);
|
||||
|
||||
bool tr_peerMsgsIsEncrypted (const tr_peerMsgs * msgs);
|
||||
|
||||
bool tr_peerMsgsIsIncomingConnection (const tr_peerMsgs * msgs);
|
||||
|
||||
void tr_peerMsgsSetChoke (tr_peerMsgs * msgs,
|
||||
bool peerIsChoked);
|
||||
|
||||
int tr_peerMsgsIsReadingBlock (const tr_peerMsgs * msgs,
|
||||
tr_block_index_t block);
|
||||
|
||||
void tr_peerMsgsSetInterested (tr_peerMsgs * msgs,
|
||||
bool clientIsInterested);
|
||||
|
||||
void tr_peerMsgsHave (tr_peerMsgs * msgs,
|
||||
uint32_t pieceIndex);
|
||||
|
||||
void tr_peerMsgsPulse (tr_peerMsgs * msgs);
|
||||
|
||||
void tr_peerMsgsCancel (tr_peerMsgs * msgs,
|
||||
tr_block_index_t block);
|
||||
|
||||
size_t tr_generateAllowedSet (tr_piece_index_t * setmePieces,
|
||||
size_t desiredSetSize,
|
||||
size_t pieceCount,
|
||||
const uint8_t * infohash,
|
||||
const struct tr_address * addr);
|
||||
|
||||
|
||||
/* @} */
|
||||
|
|
|
@ -29,75 +29,51 @@
|
|||
|
||||
struct tr_webseed_task
|
||||
{
|
||||
struct evbuffer * content;
|
||||
struct tr_webseed * webseed;
|
||||
tr_block_index_t block;
|
||||
tr_piece_index_t piece_index;
|
||||
uint32_t piece_offset;
|
||||
uint32_t length;
|
||||
tr_block_index_t blocks_done;
|
||||
uint32_t block_size;
|
||||
struct tr_web_task * web_task;
|
||||
long response_code;
|
||||
bool dead;
|
||||
struct evbuffer * content;
|
||||
struct tr_webseed * webseed;
|
||||
tr_session * session;
|
||||
tr_block_index_t block;
|
||||
tr_piece_index_t piece_index;
|
||||
uint32_t piece_offset;
|
||||
uint32_t length;
|
||||
tr_block_index_t blocks_done;
|
||||
uint32_t block_size;
|
||||
struct tr_web_task * web_task;
|
||||
long response_code;
|
||||
};
|
||||
|
||||
struct tr_webseed
|
||||
{
|
||||
tr_peer parent;
|
||||
tr_bandwidth bandwidth;
|
||||
tr_session * session;
|
||||
tr_peer_callback * callback;
|
||||
void * callback_data;
|
||||
tr_list * tasks;
|
||||
struct event * timer;
|
||||
char * base_url;
|
||||
size_t base_url_len;
|
||||
int torrent_id;
|
||||
bool is_stopping;
|
||||
int consecutive_failures;
|
||||
int retry_tickcount;
|
||||
int retry_challenge;
|
||||
int idle_connections;
|
||||
int active_transfers;
|
||||
char ** file_urls;
|
||||
tr_peer parent;
|
||||
tr_bandwidth bandwidth;
|
||||
tr_session * session;
|
||||
tr_peer_callback * callback;
|
||||
void * callback_data;
|
||||
tr_list * tasks;
|
||||
struct event * timer;
|
||||
char * base_url;
|
||||
size_t base_url_len;
|
||||
int torrent_id;
|
||||
int consecutive_failures;
|
||||
int retry_tickcount;
|
||||
int retry_challenge;
|
||||
int idle_connections;
|
||||
int active_transfers;
|
||||
char ** file_urls;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TR_IDLE_TIMER_MSEC = 2000,
|
||||
TR_IDLE_TIMER_MSEC = 2000,
|
||||
|
||||
FAILURE_RETRY_INTERVAL = 150,
|
||||
FAILURE_RETRY_INTERVAL = 150,
|
||||
|
||||
MAX_CONSECUTIVE_FAILURES = 5,
|
||||
MAX_CONSECUTIVE_FAILURES = 5,
|
||||
|
||||
MAX_WEBSEED_CONNECTIONS = 4
|
||||
MAX_WEBSEED_CONNECTIONS = 4
|
||||
};
|
||||
|
||||
static void
|
||||
webseed_free (struct tr_webseed * w)
|
||||
{
|
||||
tr_torrent * tor = tr_torrentFindFromId (w->session, w->torrent_id);
|
||||
const tr_info * inf = tr_torrentInfo (tor);
|
||||
tr_file_index_t i;
|
||||
|
||||
/* if we have an array of file URLs, free it */
|
||||
if (w->file_urls != NULL) {
|
||||
for (i=0; i<inf->fileCount; ++i)
|
||||
tr_free (w->file_urls[i]);
|
||||
tr_free (w->file_urls);
|
||||
}
|
||||
|
||||
/* webseed destruct */
|
||||
event_free (w->timer);
|
||||
tr_bandwidthDestruct (&w->bandwidth);
|
||||
tr_free (w->base_url);
|
||||
|
||||
/* parent class destruct */
|
||||
tr_peerDestruct (tor, &w->parent);
|
||||
|
||||
tr_free (w);
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -110,44 +86,50 @@ publish (tr_webseed * w, tr_peer_event * e)
|
|||
}
|
||||
|
||||
static void
|
||||
fire_client_got_rejs (tr_torrent * tor, tr_webseed * w,
|
||||
tr_block_index_t block, tr_block_index_t count)
|
||||
fire_client_got_rejs (tr_torrent * tor,
|
||||
tr_webseed * w,
|
||||
tr_block_index_t block,
|
||||
tr_block_index_t count)
|
||||
{
|
||||
tr_block_index_t i;
|
||||
tr_peer_event e = TR_PEER_EVENT_INIT;
|
||||
e.eventType = TR_PEER_CLIENT_GOT_REJ;
|
||||
tr_torrentGetBlockLocation (tor, block, &e.pieceIndex, &e.offset, &e.length);
|
||||
for (i = 1; i <= count; i++) {
|
||||
if (i == count)
|
||||
e.length = tr_torBlockCountBytes (tor, block + count - 1);
|
||||
publish (w, &e);
|
||||
e.offset += e.length;
|
||||
tr_block_index_t i;
|
||||
tr_peer_event e = TR_PEER_EVENT_INIT;
|
||||
e.eventType = TR_PEER_CLIENT_GOT_REJ;
|
||||
tr_torrentGetBlockLocation (tor, block, &e.pieceIndex, &e.offset, &e.length);
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
if (i == count)
|
||||
e.length = tr_torBlockCountBytes (tor, block + count - 1);
|
||||
publish (w, &e);
|
||||
e.offset += e.length;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fire_client_got_blocks (tr_torrent * tor, tr_webseed * w,
|
||||
tr_block_index_t block, tr_block_index_t count)
|
||||
fire_client_got_blocks (tr_torrent * tor,
|
||||
tr_webseed * w,
|
||||
tr_block_index_t block,
|
||||
tr_block_index_t count)
|
||||
{
|
||||
tr_block_index_t i;
|
||||
tr_peer_event e = TR_PEER_EVENT_INIT;
|
||||
e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
|
||||
tr_torrentGetBlockLocation (tor, block, &e.pieceIndex, &e.offset, &e.length);
|
||||
for (i = 1; i <= count; i++) {
|
||||
if (i == count)
|
||||
e.length = tr_torBlockCountBytes (tor, block + count - 1);
|
||||
publish (w, &e);
|
||||
e.offset += e.length;
|
||||
tr_block_index_t i;
|
||||
tr_peer_event e = TR_PEER_EVENT_INIT;
|
||||
e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
|
||||
tr_torrentGetBlockLocation (tor, block, &e.pieceIndex, &e.offset, &e.length);
|
||||
for (i = 1; i <= count; i++)
|
||||
{
|
||||
if (i == count)
|
||||
e.length = tr_torBlockCountBytes (tor, block + count - 1);
|
||||
publish (w, &e);
|
||||
e.offset += e.length;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fire_client_got_piece_data (tr_webseed * w, uint32_t length)
|
||||
{
|
||||
tr_peer_event e = TR_PEER_EVENT_INIT;
|
||||
e.eventType = TR_PEER_CLIENT_GOT_PIECE_DATA;
|
||||
e.length = length;
|
||||
publish (w, &e);
|
||||
tr_peer_event e = TR_PEER_EVENT_INIT;
|
||||
e.eventType = TR_PEER_CLIENT_GOT_PIECE_DATA;
|
||||
e.length = length;
|
||||
publish (w, &e);
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -156,43 +138,45 @@ fire_client_got_piece_data (tr_webseed * w, uint32_t length)
|
|||
|
||||
struct write_block_data
|
||||
{
|
||||
struct tr_webseed * webseed;
|
||||
struct evbuffer * content;
|
||||
tr_piece_index_t piece_index;
|
||||
tr_block_index_t block_index;
|
||||
tr_block_index_t count;
|
||||
uint32_t block_offset;
|
||||
tr_session * session;
|
||||
int torrent_id;
|
||||
struct tr_webseed * webseed;
|
||||
struct evbuffer * content;
|
||||
tr_piece_index_t piece_index;
|
||||
tr_block_index_t block_index;
|
||||
tr_block_index_t count;
|
||||
uint32_t block_offset;
|
||||
};
|
||||
|
||||
static void
|
||||
write_block_func (void * vdata)
|
||||
{
|
||||
struct write_block_data * data = vdata;
|
||||
struct tr_webseed * w = data->webseed;
|
||||
struct evbuffer * buf = data->content;
|
||||
struct tr_torrent * tor;
|
||||
struct write_block_data * data = vdata;
|
||||
struct tr_webseed * w = data->webseed;
|
||||
struct evbuffer * buf = data->content;
|
||||
struct tr_torrent * tor;
|
||||
|
||||
tor = tr_torrentFindFromId (w->session, w->torrent_id);
|
||||
if (tor)
|
||||
tor = tr_torrentFindFromId (data->session, data->torrent_id);
|
||||
if (tor != NULL)
|
||||
{
|
||||
const uint32_t block_size = tor->blockSize;
|
||||
uint32_t len = evbuffer_get_length (buf);
|
||||
const uint32_t offset_end = data->block_offset + len;
|
||||
tr_cache * cache = w->session->cache;
|
||||
const tr_piece_index_t piece = data->piece_index;
|
||||
const uint32_t block_size = tor->blockSize;
|
||||
uint32_t len = evbuffer_get_length (buf);
|
||||
const uint32_t offset_end = data->block_offset + len;
|
||||
tr_cache * cache = data->session->cache;
|
||||
const tr_piece_index_t piece = data->piece_index;
|
||||
|
||||
while (len > 0)
|
||||
while (len > 0)
|
||||
{
|
||||
const uint32_t bytes_this_pass = MIN (len, block_size);
|
||||
tr_cacheWriteBlock (cache, tor, piece, offset_end - len, bytes_this_pass, buf);
|
||||
len -= bytes_this_pass;
|
||||
const uint32_t bytes_this_pass = MIN (len, block_size);
|
||||
tr_cacheWriteBlock (cache, tor, piece, offset_end - len, bytes_this_pass, buf);
|
||||
len -= bytes_this_pass;
|
||||
}
|
||||
|
||||
fire_client_got_blocks (tor, w, data->block_index, data->count);
|
||||
fire_client_got_blocks (tor, w, data->block_index, data->count);
|
||||
}
|
||||
|
||||
evbuffer_free (buf);
|
||||
tr_free (data);
|
||||
evbuffer_free (buf);
|
||||
tr_free (data);
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -201,34 +185,37 @@ write_block_func (void * vdata)
|
|||
|
||||
struct connection_succeeded_data
|
||||
{
|
||||
struct tr_webseed * webseed;
|
||||
char * real_url;
|
||||
tr_piece_index_t piece_index;
|
||||
uint32_t piece_offset;
|
||||
struct tr_webseed * webseed;
|
||||
char * real_url;
|
||||
tr_piece_index_t piece_index;
|
||||
uint32_t piece_offset;
|
||||
};
|
||||
|
||||
static void
|
||||
connection_succeeded (void * vdata)
|
||||
{
|
||||
tr_torrent * tor;
|
||||
struct connection_succeeded_data * data = vdata;
|
||||
struct tr_webseed * w = data->webseed;
|
||||
tr_torrent * tor;
|
||||
struct connection_succeeded_data * data = vdata;
|
||||
struct tr_webseed * w = data->webseed;
|
||||
|
||||
if (++w->active_transfers >= w->retry_challenge && w->retry_challenge)
|
||||
/* the server seems to be accepting more connections now */
|
||||
w->consecutive_failures = w->retry_tickcount = w->retry_challenge = 0;
|
||||
if (++w->active_transfers >= w->retry_challenge && w->retry_challenge)
|
||||
/* the server seems to be accepting more connections now */
|
||||
w->consecutive_failures = w->retry_tickcount = w->retry_challenge = 0;
|
||||
|
||||
if (data->real_url &&
|
||||
(tor = tr_torrentFindFromId (w->session, w->torrent_id)))
|
||||
if (data->real_url && (tor = tr_torrentFindFromId (w->session, w->torrent_id)))
|
||||
{
|
||||
uint64_t file_offset;
|
||||
tr_file_index_t file_index;
|
||||
uint64_t file_offset;
|
||||
tr_file_index_t file_index;
|
||||
|
||||
tr_ioFindFileLocation (tor, data->piece_index, data->piece_offset,
|
||||
&file_index, &file_offset);
|
||||
tr_free (w->file_urls[file_index]);
|
||||
w->file_urls[file_index] = data->real_url;
|
||||
tr_ioFindFileLocation (tor, data->piece_index, data->piece_offset,
|
||||
&file_index, &file_offset);
|
||||
tr_free (w->file_urls[file_index]);
|
||||
w->file_urls[file_index] = data->real_url;
|
||||
data->real_url = NULL;
|
||||
}
|
||||
|
||||
tr_free (data->real_url);
|
||||
tr_free (data);
|
||||
}
|
||||
|
||||
/***
|
||||
|
@ -240,145 +227,139 @@ on_content_changed (struct evbuffer * buf,
|
|||
const struct evbuffer_cb_info * info,
|
||||
void * vtask)
|
||||
{
|
||||
uint32_t len;
|
||||
const size_t n_added = info->n_added;
|
||||
struct tr_webseed_task * task = vtask;
|
||||
struct tr_webseed * w = task->webseed;
|
||||
const size_t n_added = info->n_added;
|
||||
struct tr_webseed_task * task = vtask;
|
||||
tr_session * session = task->session;
|
||||
|
||||
if (n_added <= 0)
|
||||
return;
|
||||
tr_sessionLock (session);
|
||||
|
||||
if (!w->is_stopping)
|
||||
if (!task->dead && (n_added>0))
|
||||
{
|
||||
tr_bandwidthUsed (&w->bandwidth, TR_DOWN, n_added, true, tr_time_msec ());
|
||||
fire_client_got_piece_data (w, n_added);
|
||||
}
|
||||
uint32_t len;
|
||||
struct tr_webseed * w = task->webseed;
|
||||
|
||||
len = evbuffer_get_length (buf);
|
||||
tr_bandwidthUsed (&w->bandwidth, TR_DOWN, n_added, true, tr_time_msec ());
|
||||
fire_client_got_piece_data (w, n_added);
|
||||
len = evbuffer_get_length (buf);
|
||||
|
||||
if (!task->response_code)
|
||||
{
|
||||
tr_webGetTaskInfo (task->web_task, TR_WEB_GET_CODE, &task->response_code);
|
||||
|
||||
if (task->response_code == 206)
|
||||
if (!task->response_code)
|
||||
{
|
||||
const char * url;
|
||||
struct connection_succeeded_data * data;
|
||||
tr_webGetTaskInfo (task->web_task, TR_WEB_GET_CODE, &task->response_code);
|
||||
|
||||
url = NULL;
|
||||
tr_webGetTaskInfo (task->web_task, TR_WEB_GET_REAL_URL, &url);
|
||||
if (task->response_code == 206)
|
||||
{
|
||||
const char * url;
|
||||
struct connection_succeeded_data * data;
|
||||
|
||||
data = tr_new (struct connection_succeeded_data, 1);
|
||||
data->webseed = w;
|
||||
data->real_url = tr_strdup (url);
|
||||
data->piece_index = task->piece_index;
|
||||
data->piece_offset = task->piece_offset
|
||||
+ (task->blocks_done * task->block_size)
|
||||
+ (len - 1);
|
||||
url = NULL;
|
||||
tr_webGetTaskInfo (task->web_task, TR_WEB_GET_REAL_URL, &url);
|
||||
|
||||
/* processing this uses a tr_torrent pointer,
|
||||
so push the work to the libevent thread... */
|
||||
tr_runInEventThread (w->session, connection_succeeded, data);
|
||||
data = tr_new (struct connection_succeeded_data, 1);
|
||||
data->webseed = w;
|
||||
data->real_url = tr_strdup (url);
|
||||
data->piece_index = task->piece_index;
|
||||
data->piece_offset = task->piece_offset + (task->blocks_done * task->block_size) + (len - 1);
|
||||
|
||||
/* processing this uses a tr_torrent pointer,
|
||||
so push the work to the libevent thread... */
|
||||
tr_runInEventThread (w->session, connection_succeeded, data);
|
||||
}
|
||||
}
|
||||
|
||||
if ((task->response_code == 206) && (len >= task->block_size))
|
||||
{
|
||||
/* once we've got at least one full block, save it */
|
||||
|
||||
struct write_block_data * data;
|
||||
const uint32_t block_size = task->block_size;
|
||||
const tr_block_index_t completed = len / block_size;
|
||||
|
||||
data = tr_new (struct write_block_data, 1);
|
||||
data->webseed = task->webseed;
|
||||
data->piece_index = task->piece_index;
|
||||
data->block_index = task->block + task->blocks_done;
|
||||
data->count = completed;
|
||||
data->block_offset = task->piece_offset + task->blocks_done * block_size;
|
||||
data->content = evbuffer_new ();
|
||||
data->torrent_id = w->torrent_id;
|
||||
data->session = w->session;
|
||||
|
||||
/* we don't use locking on this evbuffer so we must copy out the data
|
||||
that will be needed when writing the block in a different thread */
|
||||
evbuffer_remove_buffer (task->content, data->content,
|
||||
block_size * completed);
|
||||
|
||||
tr_runInEventThread (w->session, write_block_func, data);
|
||||
task->blocks_done += completed;
|
||||
}
|
||||
}
|
||||
|
||||
if ((task->response_code == 206) && (len >= task->block_size))
|
||||
{
|
||||
/* once we've got at least one full block, save it */
|
||||
|
||||
struct write_block_data * data;
|
||||
const uint32_t block_size = task->block_size;
|
||||
const tr_block_index_t completed = len / block_size;
|
||||
|
||||
data = tr_new (struct write_block_data, 1);
|
||||
data->webseed = task->webseed;
|
||||
data->piece_index = task->piece_index;
|
||||
data->block_index = task->block + task->blocks_done;
|
||||
data->count = completed;
|
||||
data->block_offset = task->piece_offset + task->blocks_done * block_size;
|
||||
data->content = evbuffer_new ();
|
||||
|
||||
/* we don't use locking on this evbuffer so we must copy out the data
|
||||
that will be needed when writing the block in a different thread */
|
||||
evbuffer_remove_buffer (task->content, data->content,
|
||||
block_size * completed);
|
||||
|
||||
tr_runInEventThread (w->session, write_block_func, data);
|
||||
task->blocks_done += completed;
|
||||
}
|
||||
tr_sessionUnlock (session);
|
||||
}
|
||||
|
||||
static void task_request_next_chunk (struct tr_webseed_task * task);
|
||||
|
||||
static bool
|
||||
webseed_has_tasks (const tr_webseed * w)
|
||||
{
|
||||
return w->tasks != NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_idle (tr_webseed * w)
|
||||
{
|
||||
tr_torrent * tor = tr_torrentFindFromId (w->session, w->torrent_id);
|
||||
int want, running_tasks = tr_list_size (w->tasks);
|
||||
int want;
|
||||
int running_tasks = tr_list_size (w->tasks);
|
||||
tr_torrent * tor = tr_torrentFindFromId (w->session, w->torrent_id);
|
||||
|
||||
if (w->consecutive_failures >= MAX_CONSECUTIVE_FAILURES) {
|
||||
want = w->idle_connections;
|
||||
|
||||
if (w->retry_tickcount >= FAILURE_RETRY_INTERVAL) {
|
||||
/* some time has passed since our connection attempts failed. try again */
|
||||
++want;
|
||||
/* if this challenge is fulfilled we will reset consecutive_failures */
|
||||
w->retry_challenge = running_tasks + want;
|
||||
}
|
||||
}
|
||||
else {
|
||||
want = MAX_WEBSEED_CONNECTIONS - running_tasks;
|
||||
w->retry_challenge = running_tasks + w->idle_connections + 1;
|
||||
}
|
||||
|
||||
if (w->is_stopping && !webseed_has_tasks (w))
|
||||
if (w->consecutive_failures >= MAX_CONSECUTIVE_FAILURES)
|
||||
{
|
||||
webseed_free (w);
|
||||
}
|
||||
else if (!w->is_stopping && tor
|
||||
&& tor->isRunning
|
||||
&& !tr_torrentIsSeed (tor)
|
||||
&& want)
|
||||
{
|
||||
int i;
|
||||
int got = 0;
|
||||
tr_block_index_t * blocks = NULL;
|
||||
want = w->idle_connections;
|
||||
|
||||
blocks = tr_new (tr_block_index_t, want*2);
|
||||
tr_peerMgrGetNextRequests (tor, &w->parent, want, blocks, &got, true);
|
||||
|
||||
w->idle_connections -= MIN (w->idle_connections, got);
|
||||
if (w->retry_tickcount >= FAILURE_RETRY_INTERVAL && got == want)
|
||||
w->retry_tickcount = 0;
|
||||
|
||||
for (i=0; i<got; ++i)
|
||||
if (w->retry_tickcount >= FAILURE_RETRY_INTERVAL)
|
||||
{
|
||||
const tr_block_index_t b = blocks[i*2];
|
||||
const tr_block_index_t be = blocks[i*2+1];
|
||||
struct tr_webseed_task * task = tr_new (struct tr_webseed_task, 1);
|
||||
task->webseed = w;
|
||||
task->block = b;
|
||||
task->piece_index = tr_torBlockPiece (tor, b);
|
||||
task->piece_offset = (tor->blockSize * b)
|
||||
- (tor->info.pieceSize * task->piece_index);
|
||||
task->length = (be - b) * tor->blockSize + tr_torBlockCountBytes (tor, be);
|
||||
task->blocks_done = 0;
|
||||
task->response_code = 0;
|
||||
task->block_size = tor->blockSize;
|
||||
task->content = evbuffer_new ();
|
||||
evbuffer_add_cb (task->content, on_content_changed, task);
|
||||
tr_list_append (&w->tasks, task);
|
||||
task_request_next_chunk (task);
|
||||
/* some time has passed since our connection attempts failed. try again */
|
||||
++want;
|
||||
/* if this challenge is fulfilled we will reset consecutive_failures */
|
||||
w->retry_challenge = running_tasks + want;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
want = MAX_WEBSEED_CONNECTIONS - running_tasks;
|
||||
w->retry_challenge = running_tasks + w->idle_connections + 1;
|
||||
}
|
||||
|
||||
if (tor && tor->isRunning && !tr_torrentIsSeed (tor) && want)
|
||||
{
|
||||
int i;
|
||||
int got = 0;
|
||||
tr_block_index_t * blocks = NULL;
|
||||
|
||||
blocks = tr_new (tr_block_index_t, want*2);
|
||||
tr_peerMgrGetNextRequests (tor, &w->parent, want, blocks, &got, true);
|
||||
|
||||
w->idle_connections -= MIN (w->idle_connections, got);
|
||||
if (w->retry_tickcount >= FAILURE_RETRY_INTERVAL && got == want)
|
||||
w->retry_tickcount = 0;
|
||||
|
||||
for (i=0; i<got; ++i)
|
||||
{
|
||||
const tr_block_index_t b = blocks[i*2];
|
||||
const tr_block_index_t be = blocks[i*2+1];
|
||||
struct tr_webseed_task * task;
|
||||
|
||||
task = tr_new0 (struct tr_webseed_task, 1);
|
||||
task->session = tor->session;
|
||||
task->webseed = w;
|
||||
task->block = b;
|
||||
task->piece_index = tr_torBlockPiece (tor, b);
|
||||
task->piece_offset = (tor->blockSize * b) - (tor->info.pieceSize * task->piece_index);
|
||||
task->length = (be - b) * tor->blockSize + tr_torBlockCountBytes (tor, be);
|
||||
task->blocks_done = 0;
|
||||
task->response_code = 0;
|
||||
task->block_size = tor->blockSize;
|
||||
task->content = evbuffer_new ();
|
||||
evbuffer_add_cb (task->content, on_content_changed, task);
|
||||
tr_list_append (&w->tasks, task);
|
||||
task_request_next_chunk (task);
|
||||
}
|
||||
|
||||
tr_free (blocks);
|
||||
tr_free (blocks);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -392,67 +373,77 @@ web_response_func (tr_session * session,
|
|||
size_t response_byte_count UNUSED,
|
||||
void * vtask)
|
||||
{
|
||||
struct tr_webseed_task * t = vtask;
|
||||
tr_webseed * w = t->webseed;
|
||||
tr_torrent * tor = tr_torrentFindFromId (session, w->torrent_id);
|
||||
const int success = (response_code == 206);
|
||||
tr_webseed * w;
|
||||
tr_torrent * tor;
|
||||
struct tr_webseed_task * t = vtask;
|
||||
const int success = (response_code == 206);
|
||||
|
||||
if (tor)
|
||||
if (t->dead)
|
||||
{
|
||||
/* active_transfers was only increased if the connection was successful */
|
||||
if (t->response_code == 206)
|
||||
--w->active_transfers;
|
||||
evbuffer_free (t->content);
|
||||
tr_free (t);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
w = t->webseed;
|
||||
tor = tr_torrentFindFromId (session, w->torrent_id);
|
||||
if (tor != NULL)
|
||||
{
|
||||
/* active_transfers was only increased if the connection was successful */
|
||||
if (t->response_code == 206)
|
||||
--w->active_transfers;
|
||||
|
||||
if (!success)
|
||||
{
|
||||
const tr_block_index_t blocks_remain = (t->length + tor->blockSize - 1)
|
||||
const tr_block_index_t blocks_remain = (t->length + tor->blockSize - 1)
|
||||
/ tor->blockSize - t->blocks_done;
|
||||
|
||||
if (blocks_remain)
|
||||
fire_client_got_rejs (tor, w, t->block + t->blocks_done, blocks_remain);
|
||||
if (blocks_remain)
|
||||
fire_client_got_rejs (tor, w, t->block + t->blocks_done, blocks_remain);
|
||||
|
||||
if (t->blocks_done)
|
||||
++w->idle_connections;
|
||||
else if (++w->consecutive_failures >= MAX_CONSECUTIVE_FAILURES && !w->retry_tickcount)
|
||||
/* now wait a while until retrying to establish a connection */
|
||||
++w->retry_tickcount;
|
||||
if (t->blocks_done)
|
||||
++w->idle_connections;
|
||||
else if (++w->consecutive_failures >= MAX_CONSECUTIVE_FAILURES && !w->retry_tickcount)
|
||||
/* now wait a while until retrying to establish a connection */
|
||||
++w->retry_tickcount;
|
||||
|
||||
tr_list_remove_data (&w->tasks, t);
|
||||
evbuffer_free (t->content);
|
||||
tr_free (t);
|
||||
tr_list_remove_data (&w->tasks, t);
|
||||
evbuffer_free (t->content);
|
||||
tr_free (t);
|
||||
}
|
||||
else
|
||||
{
|
||||
const uint32_t bytes_done = t->blocks_done * tor->blockSize;
|
||||
const uint32_t buf_len = evbuffer_get_length (t->content);
|
||||
const uint32_t bytes_done = t->blocks_done * tor->blockSize;
|
||||
const uint32_t buf_len = evbuffer_get_length (t->content);
|
||||
|
||||
if (bytes_done + buf_len < t->length)
|
||||
if (bytes_done + buf_len < t->length)
|
||||
{
|
||||
/* request finished successfully but there's still data missing. that
|
||||
means we've reached the end of a file and need to request the next one */
|
||||
t->response_code = 0;
|
||||
task_request_next_chunk (t);
|
||||
/* request finished successfully but there's still data missing. that
|
||||
means we've reached the end of a file and need to request the next one */
|
||||
t->response_code = 0;
|
||||
task_request_next_chunk (t);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buf_len) {
|
||||
/* on_content_changed () will not write a block if it is smaller than
|
||||
the torrent's block size, i.e. the torrent's very last block */
|
||||
tr_cacheWriteBlock (session->cache, tor,
|
||||
t->piece_index, t->piece_offset + bytes_done,
|
||||
buf_len, t->content);
|
||||
if (buf_len)
|
||||
{
|
||||
/* on_content_changed () will not write a block if it is smaller than
|
||||
the torrent's block size, i.e. the torrent's very last block */
|
||||
tr_cacheWriteBlock (session->cache, tor,
|
||||
t->piece_index, t->piece_offset + bytes_done,
|
||||
buf_len, t->content);
|
||||
|
||||
fire_client_got_blocks (tor, t->webseed,
|
||||
t->block + t->blocks_done, 1);
|
||||
fire_client_got_blocks (tor, t->webseed,
|
||||
t->block + t->blocks_done, 1);
|
||||
}
|
||||
|
||||
++w->idle_connections;
|
||||
++w->idle_connections;
|
||||
|
||||
tr_list_remove_data (&w->tasks, t);
|
||||
evbuffer_free (t->content);
|
||||
tr_free (t);
|
||||
tr_list_remove_data (&w->tasks, t);
|
||||
evbuffer_free (t->content);
|
||||
tr_free (t);
|
||||
|
||||
on_idle (w);
|
||||
on_idle (w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -461,75 +452,57 @@ web_response_func (tr_session * session,
|
|||
static struct evbuffer *
|
||||
make_url (tr_webseed * w, const tr_file * file)
|
||||
{
|
||||
struct evbuffer * buf = evbuffer_new ();
|
||||
struct evbuffer * buf = evbuffer_new ();
|
||||
|
||||
evbuffer_add (buf, w->base_url, w->base_url_len);
|
||||
evbuffer_add (buf, w->base_url, w->base_url_len);
|
||||
|
||||
/* if url ends with a '/', add the torrent name */
|
||||
if (w->base_url[w->base_url_len - 1] == '/' && file->name)
|
||||
tr_http_escape (buf, file->name, strlen (file->name), false);
|
||||
/* if url ends with a '/', add the torrent name */
|
||||
if (w->base_url[w->base_url_len - 1] == '/' && file->name)
|
||||
tr_http_escape (buf, file->name, strlen (file->name), false);
|
||||
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void
|
||||
task_request_next_chunk (struct tr_webseed_task * t)
|
||||
{
|
||||
tr_webseed * w = t->webseed;
|
||||
tr_torrent * tor = tr_torrentFindFromId (w->session, w->torrent_id);
|
||||
if (tor != NULL)
|
||||
tr_webseed * w = t->webseed;
|
||||
tr_torrent * tor = tr_torrentFindFromId (w->session, w->torrent_id);
|
||||
if (tor != NULL)
|
||||
{
|
||||
char range[64];
|
||||
char ** urls = t->webseed->file_urls;
|
||||
char range[64];
|
||||
char ** urls = t->webseed->file_urls;
|
||||
|
||||
const tr_info * inf = tr_torrentInfo (tor);
|
||||
const uint64_t remain = t->length - t->blocks_done * tor->blockSize
|
||||
- evbuffer_get_length (t->content);
|
||||
const tr_info * inf = tr_torrentInfo (tor);
|
||||
const uint64_t remain = t->length - t->blocks_done * tor->blockSize
|
||||
- evbuffer_get_length (t->content);
|
||||
|
||||
const uint64_t total_offset = tr_pieceOffset (tor, t->piece_index,
|
||||
t->piece_offset,
|
||||
t->length - remain);
|
||||
const tr_piece_index_t step_piece = total_offset / inf->pieceSize;
|
||||
const uint64_t step_piece_offset
|
||||
= total_offset - (inf->pieceSize * step_piece);
|
||||
const uint64_t total_offset = tr_pieceOffset (tor, t->piece_index,
|
||||
t->piece_offset,
|
||||
t->length - remain);
|
||||
const tr_piece_index_t step_piece = total_offset / inf->pieceSize;
|
||||
const uint64_t step_piece_offset = total_offset - (inf->pieceSize * step_piece);
|
||||
|
||||
tr_file_index_t file_index;
|
||||
const tr_file * file;
|
||||
uint64_t file_offset;
|
||||
uint64_t this_pass;
|
||||
tr_file_index_t file_index;
|
||||
const tr_file * file;
|
||||
uint64_t file_offset;
|
||||
uint64_t this_pass;
|
||||
|
||||
tr_ioFindFileLocation (tor, step_piece, step_piece_offset,
|
||||
&file_index, &file_offset);
|
||||
file = &inf->files[file_index];
|
||||
this_pass = MIN (remain, file->length - file_offset);
|
||||
tr_ioFindFileLocation (tor, step_piece, step_piece_offset,
|
||||
&file_index, &file_offset);
|
||||
file = &inf->files[file_index];
|
||||
this_pass = MIN (remain, file->length - file_offset);
|
||||
|
||||
if (!urls[file_index])
|
||||
urls[file_index] = evbuffer_free_to_str (make_url (t->webseed, file));
|
||||
if (!urls[file_index])
|
||||
urls[file_index] = evbuffer_free_to_str (make_url (t->webseed, file));
|
||||
|
||||
tr_snprintf (range, sizeof range, "%"PRIu64"-%"PRIu64,
|
||||
file_offset, file_offset + this_pass - 1);
|
||||
t->web_task = tr_webRunWithBuffer (w->session, urls[file_index],
|
||||
range, NULL, web_response_func, t, t->content);
|
||||
tr_snprintf (range, sizeof range, "%"PRIu64"-%"PRIu64,
|
||||
file_offset, file_offset + this_pass - 1);
|
||||
t->web_task = tr_webRunWithBuffer (w->session, urls[file_index],
|
||||
range, NULL, web_response_func, t, t->content);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
tr_webseedGetSpeed_Bps (const tr_webseed * w,
|
||||
uint64_t now,
|
||||
unsigned int * setme_Bps)
|
||||
{
|
||||
const bool is_active = webseed_has_tasks (w);
|
||||
*setme_Bps = is_active ? tr_bandwidthGetPieceSpeed_Bps (&w->bandwidth, now, TR_DOWN) : 0;
|
||||
return is_active;
|
||||
}
|
||||
|
||||
bool
|
||||
tr_webseedIsActive (const tr_webseed * w)
|
||||
{
|
||||
unsigned int Bps = 0;
|
||||
return tr_webseedGetSpeed_Bps (w, tr_time_msec (), &Bps) && (Bps > 0);
|
||||
}
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
@ -537,53 +510,114 @@ tr_webseedIsActive (const tr_webseed * w)
|
|||
static void
|
||||
webseed_timer_func (evutil_socket_t foo UNUSED, short bar UNUSED, void * vw)
|
||||
{
|
||||
tr_webseed * w = vw;
|
||||
if (w->retry_tickcount)
|
||||
++w->retry_tickcount;
|
||||
on_idle (w);
|
||||
tr_timerAddMsec (w->timer, TR_IDLE_TIMER_MSEC);
|
||||
tr_webseed * w = vw;
|
||||
|
||||
if (w->retry_tickcount)
|
||||
++w->retry_tickcount;
|
||||
|
||||
on_idle (w);
|
||||
|
||||
tr_timerAddMsec (w->timer, TR_IDLE_TIMER_MSEC);
|
||||
}
|
||||
|
||||
/***
|
||||
**** tr_peer virtual functions
|
||||
***/
|
||||
|
||||
static bool
|
||||
webseed_is_transferring_pieces (const tr_peer * peer,
|
||||
uint64_t now,
|
||||
tr_direction direction,
|
||||
unsigned int * setme_Bps)
|
||||
{
|
||||
unsigned int Bps = 0;
|
||||
bool is_active = false;
|
||||
|
||||
if (direction == TR_DOWN)
|
||||
{
|
||||
const tr_webseed * w = (const tr_webseed *) peer;
|
||||
is_active = w->tasks != NULL;
|
||||
Bps = tr_bandwidthGetPieceSpeed_Bps (&w->bandwidth, now, direction);
|
||||
}
|
||||
|
||||
if (setme_Bps != NULL)
|
||||
*setme_Bps = Bps;
|
||||
|
||||
return is_active;
|
||||
}
|
||||
|
||||
static void
|
||||
webseed_destruct (tr_peer * peer)
|
||||
{
|
||||
tr_list * l;
|
||||
tr_webseed * w = (tr_webseed *) peer;
|
||||
|
||||
/* flag all the pending tasks as dead */
|
||||
for (l=w->tasks; l!=NULL; l=l->next)
|
||||
{
|
||||
struct tr_webseed_task * task = l->data;
|
||||
task->dead = true;
|
||||
}
|
||||
tr_list_free (&w->tasks, NULL);
|
||||
|
||||
/* if we have an array of file URLs, free it */
|
||||
if (w->file_urls != NULL)
|
||||
{
|
||||
tr_file_index_t i;
|
||||
tr_torrent * tor = tr_torrentFindFromId (w->session, w->torrent_id);
|
||||
const tr_info * inf = tr_torrentInfo (tor);
|
||||
|
||||
for (i=0; i<inf->fileCount; ++i)
|
||||
tr_free (w->file_urls[i]);
|
||||
tr_free (w->file_urls);
|
||||
}
|
||||
|
||||
/* webseed destruct */
|
||||
event_free (w->timer);
|
||||
tr_bandwidthDestruct (&w->bandwidth);
|
||||
tr_free (w->base_url);
|
||||
|
||||
/* parent class destruct */
|
||||
tr_peerDestruct (&w->parent);
|
||||
}
|
||||
|
||||
static const struct tr_peer_virtual_funcs my_funcs =
|
||||
{
|
||||
.destruct = webseed_destruct,
|
||||
.is_transferring_pieces = webseed_is_transferring_pieces
|
||||
};
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
||||
tr_webseed*
|
||||
tr_webseedNew (struct tr_torrent * tor,
|
||||
const char * url,
|
||||
tr_peer_callback * callback,
|
||||
void * callback_data)
|
||||
{
|
||||
tr_webseed * w = tr_new0 (tr_webseed, 1);
|
||||
tr_peer * peer = &w->parent;
|
||||
const tr_info * inf = tr_torrentInfo (tor);
|
||||
tr_webseed * w = tr_new0 (tr_webseed, 1);
|
||||
tr_peer * peer = &w->parent;
|
||||
const tr_info * inf = tr_torrentInfo (tor);
|
||||
|
||||
/* construct parent class */
|
||||
tr_peerConstruct (peer);
|
||||
peer->peerIsChoked = true;
|
||||
peer->clientIsInterested = !tr_torrentIsSeed (tor);
|
||||
peer->client = TR_KEY_webseeds;
|
||||
tr_bitfieldSetHasAll (&peer->have);
|
||||
tr_peerUpdateProgress (tor, peer);
|
||||
/* construct parent class */
|
||||
tr_peerConstruct (peer, tor);
|
||||
peer->client = TR_KEY_webseeds;
|
||||
peer->funcs = &my_funcs;
|
||||
tr_bitfieldSetHasAll (&peer->have);
|
||||
tr_peerUpdateProgress (tor, peer);
|
||||
|
||||
w->torrent_id = tr_torrentId (tor);
|
||||
w->session = tor->session;
|
||||
w->base_url_len = strlen (url);
|
||||
w->base_url = tr_strndup (url, w->base_url_len);
|
||||
w->callback = callback;
|
||||
w->callback_data = callback_data;
|
||||
w->file_urls = tr_new0 (char *, inf->fileCount);
|
||||
//tr_rcConstruct (&w->download_rate);
|
||||
tr_bandwidthConstruct (&w->bandwidth, tor->session, &tor->bandwidth);
|
||||
w->timer = evtimer_new (w->session->event_base, webseed_timer_func, w);
|
||||
tr_timerAddMsec (w->timer, TR_IDLE_TIMER_MSEC);
|
||||
return w;
|
||||
}
|
||||
|
||||
void
|
||||
tr_webseedFree (tr_webseed * w)
|
||||
{
|
||||
if (w)
|
||||
{
|
||||
if (webseed_has_tasks (w))
|
||||
w->is_stopping = true;
|
||||
else
|
||||
webseed_free (w);
|
||||
}
|
||||
w->torrent_id = tr_torrentId (tor);
|
||||
w->session = tor->session;
|
||||
w->base_url_len = strlen (url);
|
||||
w->base_url = tr_strndup (url, w->base_url_len);
|
||||
w->callback = callback;
|
||||
w->callback_data = callback_data;
|
||||
w->file_urls = tr_new0 (char *, inf->fileCount);
|
||||
//tr_rcConstruct (&w->download_rate);
|
||||
tr_bandwidthConstruct (&w->bandwidth, tor->session, &tor->bandwidth);
|
||||
w->timer = evtimer_new (w->session->event_base, webseed_timer_func, w);
|
||||
tr_timerAddMsec (w->timer, TR_IDLE_TIMER_MSEC);
|
||||
return w;
|
||||
}
|
||||
|
|
|
@ -26,15 +26,4 @@ tr_webseed* tr_webseedNew (struct tr_torrent * torrent,
|
|||
tr_peer_callback * callback,
|
||||
void * callback_data);
|
||||
|
||||
void tr_webseedFree (tr_webseed *);
|
||||
|
||||
/** @return true if a request is being processed, or false if idle */
|
||||
bool tr_webseedGetSpeed_Bps (const tr_webseed * w,
|
||||
uint64_t now,
|
||||
unsigned int * setme_Bps);
|
||||
|
||||
/** @return true if a request is being processed, or false if idle */
|
||||
bool tr_webseedIsActive (const tr_webseed * w);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue