(libT) make the class hierarchy between tr_peer, tr_peerMsgs, and tr_webseed a little less ad-hoc

This commit is contained in:
Jordan Lee 2013-02-04 16:23:33 +00:00
parent 0c8c2b5bdd
commit 96691dd019
10 changed files with 1443 additions and 1234 deletions

View File

@ -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;
}

View File

@ -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

View File

@ -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 *);

View File

@ -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);

View File

@ -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));
}
}

View File

@ -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

View File

@ -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);
/* @} */

View File

@ -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;
}

View File

@ -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