Changeset 13890


Ignore:
Timestamp:
Jan 27, 2013, 9:03:52 PM (8 years ago)
Author:
jordan
Message:

(libT) rename internal struct 'tr_torrent_peers' as 'tr_swarm'

Location:
trunk/libtransmission
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/peer-mgr.c

    r13879 r13890  
    183183
    184184/** @brief Opaque, per-torrent data structure for peer connection information */
    185 typedef struct tr_torrent_peers
     185typedef struct tr_swarm
    186186{
    187187  tr_ptrArray                outgoingHandshakes; /* tr_handshake */
     
    224224  int                        endgame;
    225225}
    226 Torrent;
     226tr_swarm;
    227227
    228228struct tr_peerMgr
     
    269269
    270270static inline void
    271 torrentLock (Torrent * torrent)
    272 {
    273   managerLock (torrent->manager);
     271swarmLock (tr_swarm * swarm)
     272{
     273  managerLock (swarm->manager);
    274274}
    275275
    276276static inline void
    277 torrentUnlock (Torrent * torrent)
    278 {
    279   managerUnlock (torrent->manager);
     277swarmUnlock (tr_swarm * swarm)
     278{
     279  managerUnlock (swarm->manager);
    280280}
    281281
    282282static inline int
    283 torrentIsLocked (const Torrent * t)
    284 {
    285   return tr_sessionIsLocked (t->manager->session);
     283swarmIsLocked (const tr_swarm * swarm)
     284{
     285  return tr_sessionIsLocked (swarm->manager->session);
    286286}
    287287
     
    341341}
    342342
    343 static Torrent*
    344 getExistingTorrent (tr_peerMgr *    manager,
    345                     const uint8_t * hash)
     343static tr_swarm *
     344getExistingSwarm (tr_peerMgr *    manager,
     345                  const uint8_t * hash)
    346346{
    347347  tr_torrent * tor = tr_torrentFindFromHash (manager->session, hash);
    348348
    349   return tor == NULL ? NULL : tor->torrentPeers;
     349  return tor == NULL ? NULL : tor->swarm;
    350350}
    351351
     
    357357
    358358static struct peer_atom*
    359 getExistingAtom (const Torrent    * t,
     359getExistingAtom (const tr_swarm   * cswarm,
    360360                 const tr_address * addr)
    361361{
    362   Torrent * tt = (Torrent*)t;
    363   return tr_ptrArrayFindSorted (&tt->pool, addr, comparePeerAtomToAddress);
     362  tr_swarm * swarm = (tr_swarm*) cswarm;
     363  return tr_ptrArrayFindSorted (&swarm->pool, addr, comparePeerAtomToAddress);
    364364}
    365365
    366366static bool
    367 peerIsInUse (const Torrent * ct, const struct peer_atom * atom)
    368 {
    369   Torrent * t = (Torrent*) ct;
    370 
    371   assert (torrentIsLocked (t));
     367peerIsInUse (const tr_swarm * cs, const struct peer_atom * atom)
     368{
     369  tr_swarm * s = (tr_swarm*) cs;
     370
     371  assert (swarmIsLocked (s));
    372372
    373373  return (atom->peer != NULL)
    374       || getExistingHandshake (&t->outgoingHandshakes, &atom->addr)
    375       || getExistingHandshake (&t->manager->incomingHandshakes, &atom->addr);
     374      || getExistingHandshake (&s->outgoingHandshakes, &atom->addr)
     375      || getExistingHandshake (&s->manager->incomingHandshakes, &atom->addr);
    376376}
    377377
     
    397397
    398398static tr_peer*
    399 getPeer (Torrent * torrent, struct peer_atom * atom)
     399getPeer (tr_swarm * s, struct peer_atom * atom)
    400400{
    401401  tr_peer * peer;
    402402
    403   assert (torrentIsLocked (torrent));
     403  assert (swarmIsLocked (s));
    404404
    405405  peer = atom->peer;
     
    408408    {
    409409      peer = peerNew (atom);
    410       tr_bitfieldConstruct (&peer->have, torrent->tor->info.pieceCount);
    411       tr_bitfieldConstruct (&peer->blame, torrent->tor->blockCount);
    412       tr_ptrArrayInsertSorted (&torrent->peers, peer, peerCompare);
     410      tr_bitfieldConstruct (&peer->have, s->tor->info.pieceCount);
     411      tr_bitfieldConstruct (&peer->blame, s->tor->blockCount);
     412      tr_ptrArrayInsertSorted (&s->peers, peer, peerCompare);
    413413    }
    414414
     
    416416}
    417417
    418 static void peerDeclinedAllRequests (Torrent *, const tr_peer *);
     418static void peerDeclinedAllRequests (tr_swarm *, const tr_peer *);
    419419
    420420void
     
    423423  assert (peer != NULL);
    424424
    425   peerDeclinedAllRequests (tor->torrentPeers, peer);
     425  peerDeclinedAllRequests (tor->swarm, peer);
    426426
    427427  if (peer->msgs != NULL)
     
    442442
    443443static void
    444 peerDelete (Torrent * t, tr_peer * peer)
    445 {
    446   tr_peerDestruct (t->tor, peer);
     444peerDelete (tr_swarm * s, tr_peer * peer)
     445{
     446  tr_peerDestruct (s->tor, peer);
    447447  tr_free (peer);
    448448}
    449449
    450 static bool
    451 replicationExists (const Torrent * t)
    452 {
    453   return t->pieceReplication != NULL;
    454 }
    455 
    456 static void
    457 replicationFree (Torrent * t)
    458 {
    459   tr_free (t->pieceReplication);
    460   t->pieceReplication = NULL;
    461   t->pieceReplicationSize = 0;
    462 }
    463 
    464 static void
    465 replicationNew (Torrent * t)
     450static inline bool
     451replicationExists (const tr_swarm * s)
     452{
     453  return s->pieceReplication != NULL;
     454}
     455
     456static void
     457replicationFree (tr_swarm * s)
     458{
     459  tr_free (s->pieceReplication);
     460  s->pieceReplication = NULL;
     461  s->pieceReplicationSize = 0;
     462}
     463
     464static void
     465replicationNew (tr_swarm * s)
    466466{
    467467  tr_piece_index_t piece_i;
    468   const tr_piece_index_t piece_count = t->tor->info.pieceCount;
    469   tr_peer ** peers = (tr_peer**) tr_ptrArrayBase (&t->peers);
    470   const int peer_count = tr_ptrArraySize (&t->peers);
    471 
    472   assert (!replicationExists (t));
    473 
    474   t->pieceReplicationSize = piece_count;
    475   t->pieceReplication = tr_new0 (uint16_t, piece_count);
     468  const tr_piece_index_t piece_count = s->tor->info.pieceCount;
     469  tr_peer ** peers = (tr_peer**) tr_ptrArrayBase (&s->peers);
     470  const int peer_count = tr_ptrArraySize (&s->peers);
     471
     472  assert (!replicationExists (s));
     473
     474  s->pieceReplicationSize = piece_count;
     475  s->pieceReplication = tr_new0 (uint16_t, piece_count);
    476476
    477477  for (piece_i=0; piece_i<piece_count; ++piece_i)
     
    484484          ++r;
    485485
    486       t->pieceReplication[piece_i] = r;
    487     }
    488 }
    489 
    490 static void
    491 torrentFree (void * vt)
    492 {
    493   Torrent * t = vt;
    494 
    495   assert (t);
    496   assert (!t->isRunning);
    497   assert (torrentIsLocked (t));
    498   assert (tr_ptrArrayEmpty (&t->outgoingHandshakes));
    499   assert (tr_ptrArrayEmpty (&t->peers));
    500 
    501   tr_ptrArrayDestruct (&t->webseeds, (PtrArrayForeachFunc)tr_webseedFree);
    502   tr_ptrArrayDestruct (&t->pool, (PtrArrayForeachFunc)tr_free);
    503   tr_ptrArrayDestruct (&t->outgoingHandshakes, NULL);
    504   tr_ptrArrayDestruct (&t->peers, NULL);
    505 
    506   replicationFree (t);
    507 
    508   tr_free (t->requests);
    509   tr_free (t->pieces);
    510   tr_free (t);
     486      s->pieceReplication[piece_i] = r;
     487    }
     488}
     489
     490static void
     491swarmFree (void * vs)
     492{
     493  tr_swarm * s = vs;
     494
     495  assert (s);
     496  assert (!s->isRunning);
     497  assert (swarmIsLocked (s));
     498  assert (tr_ptrArrayEmpty (&s->outgoingHandshakes));
     499  assert (tr_ptrArrayEmpty (&s->peers));
     500
     501  tr_ptrArrayDestruct (&s->webseeds, (PtrArrayForeachFunc)tr_webseedFree);
     502  tr_ptrArrayDestruct (&s->pool, (PtrArrayForeachFunc)tr_free);
     503  tr_ptrArrayDestruct (&s->outgoingHandshakes, NULL);
     504  tr_ptrArrayDestruct (&s->peers, NULL);
     505
     506  replicationFree (s);
     507
     508  tr_free (s->requests);
     509  tr_free (s->pieces);
     510  tr_free (s);
    511511}
    512512
     
    514514
    515515static void
    516 rebuildWebseedArray (Torrent * t, tr_torrent * tor)
     516rebuildWebseedArray (tr_swarm * s, tr_torrent * tor)
    517517{
    518518  unsigned int i;
     
    520520
    521521  /* clear the array */
    522   tr_ptrArrayDestruct (&t->webseeds, (PtrArrayForeachFunc)tr_webseedFree);
    523   t->webseeds = TR_PTR_ARRAY_INIT;
     522  tr_ptrArrayDestruct (&s->webseeds, (PtrArrayForeachFunc)tr_webseedFree);
     523  s->webseeds = TR_PTR_ARRAY_INIT;
    524524
    525525  /* repopulate it */
    526526  for (i = 0; i < inf->webseedCount; ++i)
    527527    {
    528       tr_webseed * w = tr_webseedNew (tor, inf->webseeds[i], peerCallbackFunc, t);
    529       tr_ptrArrayAppend (&t->webseeds, w);
    530     }
    531 }
    532 
    533 static Torrent*
    534 torrentNew (tr_peerMgr * manager, tr_torrent * tor)
    535 {
    536   Torrent * t;
    537 
    538   t = tr_new0 (Torrent, 1);
    539   t->manager = manager;
    540   t->tor = tor;
    541   t->pool = TR_PTR_ARRAY_INIT;
    542   t->peers = TR_PTR_ARRAY_INIT;
    543   t->webseeds = TR_PTR_ARRAY_INIT;
    544   t->outgoingHandshakes = TR_PTR_ARRAY_INIT;
    545 
    546   rebuildWebseedArray (t, tor);
    547 
    548   return t;
     528      tr_webseed * w = tr_webseedNew (tor, inf->webseeds[i], peerCallbackFunc, s);
     529      tr_ptrArrayAppend (&s->webseeds, w);
     530    }
     531}
     532
     533static tr_swarm *
     534swarmNew (tr_peerMgr * manager, tr_torrent * tor)
     535{
     536  tr_swarm * s;
     537
     538  s = tr_new0 (tr_swarm, 1);
     539  s->manager = manager;
     540  s->tor = tor;
     541  s->pool = TR_PTR_ARRAY_INIT;
     542  s->peers = TR_PTR_ARRAY_INIT;
     543  s->webseeds = TR_PTR_ARRAY_INIT;
     544  s->outgoingHandshakes = TR_PTR_ARRAY_INIT;
     545
     546  rebuildWebseedArray (s, tor);
     547
     548  return s;
    549549}
    550550
     
    628628    {
    629629      int i;
    630       Torrent * t = tor->torrentPeers;
    631       const int n = tr_ptrArraySize (&t->pool);
     630      tr_swarm * s = tor->swarm;
     631      const int n = tr_ptrArraySize (&s->pool);
    632632      for (i=0; i<n; ++i)
    633633        {
    634           struct peer_atom * atom = tr_ptrArrayNth (&t->pool, i);
     634          struct peer_atom * atom = tr_ptrArrayNth (&s->pool, i);
    635635          atom->blocklisted = -1;
    636636        }
     
    674674
    675675static void
    676 atomSetSeed (const Torrent * t, struct peer_atom * atom)
     676atomSetSeed (const tr_swarm * s, struct peer_atom * atom)
    677677{
    678678  if (!atomIsSeed (atom))
    679679    {
    680       tordbg (t, "marking peer %s as a seed", tr_atomAddrStr (atom));
     680      tordbg (s, "marking peer %s as a seed", tr_atomAddrStr (atom));
    681681
    682682      atomSetSeedProbability (atom, 100);
     
    690690{
    691691  bool isSeed = false;
    692   const Torrent * t = tor->torrentPeers;
    693   const struct peer_atom * atom = getExistingAtom (t, addr);
     692  const tr_swarm * s = tor->swarm;
     693  const struct peer_atom * atom = getExistingAtom (s, addr);
    694694
    695695  if (atom)
     
    702702tr_peerMgrSetUtpSupported (tr_torrent * tor, const tr_address * addr)
    703703{
    704   struct peer_atom * atom = getExistingAtom (tor->torrentPeers, addr);
     704  struct peer_atom * atom = getExistingAtom (tor->swarm, addr);
    705705
    706706  if (atom)
     
    711711tr_peerMgrSetUtpFailed (tr_torrent *tor, const tr_address *addr, bool failed)
    712712{
    713   struct peer_atom * atom = getExistingAtom (tor->torrentPeers, addr);
     713  struct peer_atom * atom = getExistingAtom (tor->swarm, addr);
    714714
    715715  if (atom)
     
    723723*** There are two data structures associated with managing block requests:
    724724***
    725 *** 1. Torrent::requests, an array of "struct block_request" which keeps
     725*** 1. tr_swarm::requests, an array of "struct block_request" which keeps
    726726***    track of which blocks have been requested, and when, and by which peers.
    727727***    This is list is used for (a) cancelling requests that have been pending
    728728***    for too long and (b) avoiding duplicate requests before endgame.
    729729***
    730 *** 2. Torrent::pieces, an array of "struct weighted_piece" which lists the
     730*** 2. tr_swarm::pieces, an array of "struct weighted_piece" which lists the
    731731***    pieces that we want to request. It's used to decide which blocks to
    732732***    return next when tr_peerMgrGetBlockRequests () is called.
     
    740740compareReqByBlock (const void * va, const void * vb)
    741741{
    742     const struct block_request * a = va;
    743     const struct block_request * b = vb;
    744 
    745     /* primary key: block */
    746     if (a->block < b->block) return -1;
    747     if (a->block > b->block) return 1;
    748 
    749     /* secondary key: peer */
    750     if (a->peer < b->peer) return -1;
    751     if (a->peer > b->peer) return 1;
    752 
    753     return 0;
    754 }
    755 
    756 static void
    757 requestListAdd (Torrent * t, tr_block_index_t block, tr_peer * peer)
    758 {
    759     struct block_request key;
    760 
    761     /* ensure enough room is available... */
    762     if (t->requestCount + 1 >= t->requestAlloc)
    763     {
    764         const int CHUNK_SIZE = 128;
    765         t->requestAlloc += CHUNK_SIZE;
    766         t->requests = tr_renew (struct block_request,
    767                                 t->requests, t->requestAlloc);
    768     }
    769 
    770     /* populate the record we're inserting */
    771     key.block = block;
    772     key.peer = peer;
    773     key.sentAt = tr_time ();
    774 
    775     /* insert the request to our array... */
    776     {
    777         bool exact;
    778         const int pos = tr_lowerBound (&key, t->requests, t->requestCount,
    779                                        sizeof (struct block_request),
    780                                        compareReqByBlock, &exact);
    781         assert (!exact);
    782         memmove (t->requests + pos + 1,
    783                  t->requests + pos,
    784                  sizeof (struct block_request) * (t->requestCount++ - pos));
    785         t->requests[pos] = key;
    786     }
    787 
    788     if (peer != NULL)
    789     {
    790         ++peer->pendingReqsToPeer;
    791         assert (peer->pendingReqsToPeer >= 0);
    792     }
    793 
    794     /*fprintf (stderr, "added request of block %lu from peer %s... "
    795                        "there are now %d block\n",
    796                      (unsigned long)block, tr_atomAddrStr (peer->atom), t->requestCount);*/
     742  const struct block_request * a = va;
     743  const struct block_request * b = vb;
     744
     745  /* primary key: block */
     746  if (a->block < b->block) return -1;
     747  if (a->block > b->block) return 1;
     748
     749  /* secondary key: peer */
     750  if (a->peer < b->peer) return -1;
     751  if (a->peer > b->peer) return 1;
     752
     753  return 0;
     754}
     755
     756static void
     757requestListAdd (tr_swarm * s, tr_block_index_t block, tr_peer * peer)
     758{
     759  struct block_request key;
     760
     761  /* ensure enough room is available... */
     762  if (s->requestCount + 1 >= s->requestAlloc)
     763    {
     764      const int CHUNK_SIZE = 128;
     765      s->requestAlloc += CHUNK_SIZE;
     766      s->requests = tr_renew (struct block_request,
     767                              s->requests, s->requestAlloc);
     768    }
     769
     770  /* populate the record we're inserting */
     771  key.block = block;
     772  key.peer = peer;
     773  key.sentAt = tr_time ();
     774
     775  /* insert the request to our array... */
     776  {
     777    bool exact;
     778    const int pos = tr_lowerBound (&key, s->requests, s->requestCount,
     779                                   sizeof (struct block_request),
     780                                   compareReqByBlock, &exact);
     781    assert (!exact);
     782    memmove (s->requests + pos + 1,
     783             s->requests + pos,
     784             sizeof (struct block_request) * (s->requestCount++ - pos));
     785    s->requests[pos] = key;
     786  }
     787
     788  if (peer != NULL)
     789    {
     790      ++peer->pendingReqsToPeer;
     791      assert (peer->pendingReqsToPeer >= 0);
     792    }
     793
     794  /*fprintf (stderr, "added request of block %lu from peer %s... "
     795                     "there are now %d block\n",
     796                     (unsigned long)block, tr_atomAddrStr (peer->atom), s->requestCount);*/
    797797}
    798798
    799799static struct block_request *
    800 requestListLookup (Torrent * t, tr_block_index_t block, const tr_peer * peer)
    801 {
    802     struct block_request key;
    803     key.block = block;
    804     key.peer = (tr_peer*) peer;
    805 
    806     return bsearch (&key, t->requests, t->requestCount,
    807                     sizeof (struct block_request),
    808                     compareReqByBlock);
     800requestListLookup (tr_swarm * s, tr_block_index_t block, const tr_peer * peer)
     801{
     802  struct block_request key;
     803  key.block = block;
     804  key.peer = (tr_peer*) peer;
     805
     806  return bsearch (&key, s->requests, s->requestCount,
     807                  sizeof (struct block_request),
     808                  compareReqByBlock);
    809809}
    810810
     
    814814 */
    815815static void
    816 getBlockRequestPeers (Torrent * t, tr_block_index_t block,
     816getBlockRequestPeers (tr_swarm * s, tr_block_index_t block,
    817817                      tr_ptrArray * peerArr)
    818818{
    819     bool exact;
    820     int i, pos;
    821     struct block_request key;
    822 
    823     key.block = block;
    824     key.peer = NULL;
    825     pos = tr_lowerBound (&key, t->requests, t->requestCount,
    826                          sizeof (struct block_request),
    827                          compareReqByBlock, &exact);
    828 
    829     assert (!exact); /* shouldn't have a request with .peer == NULL */
    830 
    831     for (i = pos; i < t->requestCount; ++i)
    832     {
    833         if (t->requests[i].block != block)
    834             break;
    835         tr_ptrArrayAppend (peerArr, t->requests[i].peer);
     819  bool exact;
     820  int i, pos;
     821  struct block_request key;
     822
     823  key.block = block;
     824  key.peer = NULL;
     825  pos = tr_lowerBound (&key, s->requests, s->requestCount,
     826                       sizeof (struct block_request),
     827                       compareReqByBlock, &exact);
     828
     829  assert (!exact); /* shouldn't have a request with .peer == NULL */
     830
     831  for (i=pos; i<s->requestCount; ++i)
     832    {
     833      if (s->requests[i].block != block)
     834        break;
     835      tr_ptrArrayAppend (peerArr, s->requests[i].peer);
    836836    }
    837837}
     
    840840decrementPendingReqCount (const struct block_request * b)
    841841{
    842     if (b->peer != NULL)
    843         if (b->peer->pendingReqsToPeer > 0)
    844             --b->peer->pendingReqsToPeer;
    845 }
    846 
    847 static void
    848 requestListRemove (Torrent * t, tr_block_index_t block, const tr_peer * peer)
    849 {
    850     const struct block_request * b = requestListLookup (t, block, peer);
    851     if (b != NULL)
    852     {
    853         const int pos = b - t->requests;
    854         assert (pos < t->requestCount);
    855 
    856         decrementPendingReqCount (b);
    857 
    858         tr_removeElementFromArray (t->requests,
    859                                    pos,
    860                                    sizeof (struct block_request),
    861                                    t->requestCount--);
    862 
    863         /*fprintf (stderr, "removing request of block %lu from peer %s... "
    864                            "there are now %d block requests left\n",
     842  if (b->peer != NULL)
     843    if (b->peer->pendingReqsToPeer > 0)
     844      --b->peer->pendingReqsToPeer;
     845}
     846
     847static void
     848requestListRemove (tr_swarm * s, tr_block_index_t block, const tr_peer * peer)
     849{
     850  const struct block_request * b = requestListLookup (s, block, peer);
     851
     852  if (b != NULL)
     853    {
     854      const int pos = b - s->requests;
     855      assert (pos < s->requestCount);
     856
     857      decrementPendingReqCount (b);
     858
     859      tr_removeElementFromArray (s->requests,
     860                                 pos,
     861                                 sizeof (struct block_request),
     862                                 s->requestCount--);
     863
     864      /*fprintf (stderr, "removing request of block %lu from peer %s... "
     865                         "there are now %d block requests left\n",
    865866                         (unsigned long)block, tr_atomAddrStr (peer->atom), t->requestCount);*/
    866867    }
     
    868869
    869870static int
    870 countActiveWebseeds (const Torrent * t)
    871 {
    872     int activeCount = 0;
    873     const tr_webseed ** w = (const tr_webseed **) tr_ptrArrayBase (&t->webseeds);
    874     const tr_webseed ** const wend = w + tr_ptrArraySize (&t->webseeds);
    875 
    876     for (; w!=wend; ++w)
    877         if (tr_webseedIsActive (*w))
    878             ++activeCount;
    879 
    880     return activeCount;
     871countActiveWebseeds (const tr_swarm * s)
     872{
     873  int activeCount = 0;
     874  const tr_webseed ** w = (const tr_webseed **) tr_ptrArrayBase (&s->webseeds);
     875  const tr_webseed ** const wend = w + tr_ptrArraySize (&s->webseeds);
     876
     877  for (; w!=wend; ++w)
     878    if (tr_webseedIsActive (*w))
     879      ++activeCount;
     880
     881  return activeCount;
    881882}
    882883
    883884static bool
    884 testForEndgame (const Torrent * t)
    885 {
    886     /* we consider ourselves to be in endgame if the number of bytes
    887        we've got requested is >= the number of bytes left to download */
    888     return (t->requestCount * t->tor->blockSize)
    889                >= tr_cpLeftUntilDone (&t->tor->completion);
    890 }
    891 
    892 static void
    893 updateEndgame (Torrent * t)
    894 {
    895     assert (t->requestCount >= 0);
    896 
    897     if (!testForEndgame (t))
    898     {
    899         /* not in endgame */
    900         t->endgame = 0;
    901     }
    902     else if (!t->endgame) /* only recalculate when endgame first begins */
    903     {
    904         int numDownloading = 0;
    905         const tr_peer ** p = (const tr_peer **) tr_ptrArrayBase (&t->peers);
    906         const tr_peer ** const pend = p + tr_ptrArraySize (&t->peers);
    907 
    908         /* add the active bittorrent peers... */
    909         for (; p!=pend; ++p)
    910             if ((*p)->pendingReqsToPeer > 0)
    911                 ++numDownloading;
    912 
    913         /* add the active webseeds... */
    914         numDownloading += countActiveWebseeds (t);
    915 
    916         /* average number of pending requests per downloading peer */
    917         t->endgame = t->requestCount / MAX (numDownloading, 1);
     885testForEndgame (const tr_swarm * s)
     886{
     887  /* we consider ourselves to be in endgame if the number of bytes
     888     we've got requested is >= the number of bytes left to download */
     889  return (s->requestCount * s->tor->blockSize)
     890               >= tr_cpLeftUntilDone (&s->tor->completion);
     891}
     892
     893static void
     894updateEndgame (tr_swarm * s)
     895{
     896  assert (s->requestCount >= 0);
     897
     898  if (!testForEndgame (s))
     899    {
     900      /* not in endgame */
     901      s->endgame = 0;
     902    }
     903  else if (!s->endgame) /* only recalculate when endgame first begins */
     904    {
     905      int numDownloading = 0;
     906      const tr_peer ** p = (const tr_peer **) tr_ptrArrayBase (&s->peers);
     907      const tr_peer ** const pend = p + tr_ptrArraySize (&s->peers);
     908
     909      /* add the active bittorrent peers... */
     910      for (; p!=pend; ++p)
     911        if ((*p)->pendingReqsToPeer > 0)
     912          ++numDownloading;
     913
     914      /* add the active webseeds... */
     915      numDownloading += countActiveWebseeds (s);
     916
     917      /* average number of pending requests per downloading peer */
     918      s->endgame = s->requestCount / MAX (numDownloading, 1);
    918919    }
    919920}
     
    927928
    928929static inline void
    929 invalidatePieceSorting (Torrent * t)
    930 {
    931     t->pieceSortState = PIECES_UNSORTED;
     930invalidatePieceSorting (tr_swarm * s)
     931{
     932  s->pieceSortState = PIECES_UNSORTED;
    932933}
    933934
     
    937938
    938939static void
    939 setComparePieceByWeightTorrent (Torrent * t)
    940 {
    941     if (!replicationExists (t))
    942         replicationNew (t);
    943 
    944     weightTorrent = t->tor;
    945     weightReplication = t->pieceReplication;
     940setComparePieceByWeightTorrent (tr_swarm * s)
     941{
     942  if (!replicationExists (s))
     943    replicationNew (s);
     944
     945  weightTorrent = s->tor;
     946  weightReplication = s->pieceReplication;
    946947}
    947948
     
    951952comparePieceByWeight (const void * va, const void * vb)
    952953{
    953     const struct weighted_piece * a = va;
    954     const struct weighted_piece * b = vb;
    955     int ia, ib, missing, pending;
    956     const tr_torrent * tor = weightTorrent;
    957     const uint16_t * rep = weightReplication;
    958 
    959     /* primary key: weight */
    960     missing = tr_cpMissingBlocksInPiece (&tor->completion, a->index);
    961     pending = a->requestCount;
    962     ia = missing > pending ? missing - pending : (tor->blockCountInPiece + pending);
    963     missing = tr_cpMissingBlocksInPiece (&tor->completion, b->index);
    964     pending = b->requestCount;
    965     ib = missing > pending ? missing - pending : (tor->blockCountInPiece + pending);
    966     if (ia < ib) return -1;
    967     if (ia > ib) return 1;
    968 
    969     /* secondary key: higher priorities go first */
    970     ia = tor->info.pieces[a->index].priority;
    971     ib = tor->info.pieces[b->index].priority;
    972     if (ia > ib) return -1;
    973     if (ia < ib) return 1;
    974 
    975     /* tertiary key: rarest first. */
    976     ia = rep[a->index];
    977     ib = rep[b->index];
    978     if (ia < ib) return -1;
    979     if (ia > ib) return 1;
    980 
    981     /* quaternary key: random */
    982     if (a->salt < b->salt) return -1;
    983     if (a->salt > b->salt) return 1;
    984 
    985     /* okay, they're equal */
    986     return 0;
     954  const struct weighted_piece * a = va;
     955  const struct weighted_piece * b = vb;
     956  int ia, ib, missing, pending;
     957  const tr_torrent * tor = weightTorrent;
     958  const uint16_t * rep = weightReplication;
     959
     960  /* primary key: weight */
     961  missing = tr_cpMissingBlocksInPiece (&tor->completion, a->index);
     962  pending = a->requestCount;
     963  ia = missing > pending ? missing - pending : (tor->blockCountInPiece + pending);
     964  missing = tr_cpMissingBlocksInPiece (&tor->completion, b->index);
     965  pending = b->requestCount;
     966  ib = missing > pending ? missing - pending : (tor->blockCountInPiece + pending);
     967  if (ia < ib) return -1;
     968  if (ia > ib) return 1;
     969
     970  /* secondary key: higher priorities go first */
     971  ia = tor->info.pieces[a->index].priority;
     972  ib = tor->info.pieces[b->index].priority;
     973  if (ia > ib) return -1;
     974  if (ia < ib) return 1;
     975
     976  /* tertiary key: rarest first. */
     977  ia = rep[a->index];
     978  ib = rep[b->index];
     979  if (ia < ib) return -1;
     980  if (ia > ib) return 1;
     981
     982  /* quaternary key: random */
     983  if (a->salt < b->salt) return -1;
     984  if (a->salt > b->salt) return 1;
     985
     986  /* okay, they're equal */
     987  return 0;
    987988}
    988989
     
    990991comparePieceByIndex (const void * va, const void * vb)
    991992{
    992     const struct weighted_piece * a = va;
    993     const struct weighted_piece * b = vb;
    994     if (a->index < b->index) return -1;
    995     if (a->index > b->index) return 1;
    996     return 0;
    997 }
    998 
    999 static void
    1000 pieceListSort (Torrent * t, enum piece_sort_state state)
    1001 {
    1002     assert (state==PIECES_SORTED_BY_INDEX
    1003          || state==PIECES_SORTED_BY_WEIGHT);
    1004 
    1005 
    1006     if (state == PIECES_SORTED_BY_WEIGHT)
    1007     {
    1008         setComparePieceByWeightTorrent (t);
    1009         qsort (t->pieces, t->pieceCount, sizeof (struct weighted_piece), comparePieceByWeight);
    1010     }
    1011     else
    1012         qsort (t->pieces, t->pieceCount, sizeof (struct weighted_piece), comparePieceByIndex);
    1013 
    1014     t->pieceSortState = state;
     993  const struct weighted_piece * a = va;
     994  const struct weighted_piece * b = vb;
     995  if (a->index < b->index) return -1;
     996  if (a->index > b->index) return 1;
     997  return 0;
     998}
     999
     1000static void
     1001pieceListSort (tr_swarm * s, enum piece_sort_state state)
     1002{
     1003  assert (state==PIECES_SORTED_BY_INDEX
     1004       || state==PIECES_SORTED_BY_WEIGHT);
     1005
     1006  if (state == PIECES_SORTED_BY_WEIGHT)
     1007    {
     1008      setComparePieceByWeightTorrent (s);
     1009      qsort (s->pieces, s->pieceCount, sizeof (struct weighted_piece), comparePieceByWeight);
     1010    }
     1011  else
     1012    {
     1013      qsort (s->pieces, s->pieceCount, sizeof (struct weighted_piece), comparePieceByIndex);
     1014    }
     1015
     1016  s->pieceSortState = state;
    10151017}
    10161018
     
    10651067
    10661068static struct weighted_piece *
    1067 pieceListLookup (Torrent * t, tr_piece_index_t index)
    1068 {
    1069     int i;
    1070 
    1071     for (i=0; i<t->pieceCount; ++i)
    1072         if (t->pieces[i].index == index)
    1073             return &t->pieces[i];
    1074 
    1075     return NULL;
    1076 }
    1077 
    1078 static void
    1079 pieceListRebuild (Torrent * t)
    1080 {
    1081 
    1082     if (!tr_torrentIsSeed (t->tor))
    1083     {
    1084         tr_piece_index_t i;
    1085         tr_piece_index_t * pool;
    1086         tr_piece_index_t poolCount = 0;
    1087         const tr_torrent * tor = t->tor;
    1088         const tr_info * inf = tr_torrentInfo (tor);
    1089         struct weighted_piece * pieces;
    1090         int pieceCount;
    1091 
    1092         /* build the new list */
    1093         pool = tr_new (tr_piece_index_t, inf->pieceCount);
    1094         for (i=0; i<inf->pieceCount; ++i)
    1095             if (!inf->pieces[i].dnd)
    1096                 if (!tr_cpPieceIsComplete (&tor->completion, i))
    1097                     pool[poolCount++] = i;
    1098         pieceCount = poolCount;
    1099         pieces = tr_new0 (struct weighted_piece, pieceCount);
    1100         for (i=0; i<poolCount; ++i) {
    1101             struct weighted_piece * piece = pieces + i;
    1102             piece->index = pool[i];
    1103             piece->requestCount = 0;
    1104             piece->salt = tr_cryptoWeakRandInt (4096);
     1069pieceListLookup (tr_swarm * s, tr_piece_index_t index)
     1070{
     1071  int i;
     1072
     1073  for (i=0; i<s->pieceCount; ++i)
     1074    if (s->pieces[i].index == index)
     1075      return &s->pieces[i];
     1076
     1077  return NULL;
     1078}
     1079
     1080static void
     1081pieceListRebuild (tr_swarm * s)
     1082{
     1083  if (!tr_torrentIsSeed (s->tor))
     1084    {
     1085      tr_piece_index_t i;
     1086      tr_piece_index_t * pool;
     1087      tr_piece_index_t poolCount = 0;
     1088      const tr_torrent * tor = s->tor;
     1089      const tr_info * inf = tr_torrentInfo (tor);
     1090      struct weighted_piece * pieces;
     1091      int pieceCount;
     1092
     1093      /* build the new list */
     1094      pool = tr_new (tr_piece_index_t, inf->pieceCount);
     1095      for (i=0; i<inf->pieceCount; ++i)
     1096        if (!inf->pieces[i].dnd)
     1097          if (!tr_cpPieceIsComplete (&tor->completion, i))
     1098            pool[poolCount++] = i;
     1099      pieceCount = poolCount;
     1100      pieces = tr_new0 (struct weighted_piece, pieceCount);
     1101      for (i=0; i<poolCount; ++i)
     1102        {
     1103          struct weighted_piece * piece = pieces + i;
     1104          piece->index = pool[i];
     1105          piece->requestCount = 0;
     1106          piece->salt = tr_cryptoWeakRandInt (4096);
    11051107        }
    11061108
    1107         /* if we already had a list of pieces, merge it into
    1108          * the new list so we don't lose its requestCounts */
    1109         if (t->pieces != NULL)
     1109      /* if we already had a list of pieces, merge it into
     1110       * the new list so we don't lose its requestCounts */
     1111      if (s->pieces != NULL)
    11101112        {
    1111             struct weighted_piece * o = t->pieces;
    1112             struct weighted_piece * oend = o + t->pieceCount;
    1113             struct weighted_piece * n = pieces;
    1114             struct weighted_piece * nend = n + pieceCount;
    1115 
    1116             pieceListSort (t, PIECES_SORTED_BY_INDEX);
    1117 
    1118             while (o!=oend && n!=nend) {
    1119                 if (o->index < n->index)
    1120                     ++o;
    1121                 else if (o->index > n->index)
    1122                     ++n;
    1123                 else
    1124                     *n++ = *o++;
     1113          struct weighted_piece * o = s->pieces;
     1114          struct weighted_piece * oend = o + s->pieceCount;
     1115          struct weighted_piece * n = pieces;
     1116          struct weighted_piece * nend = n + pieceCount;
     1117
     1118          pieceListSort (s, PIECES_SORTED_BY_INDEX);
     1119
     1120          while (o!=oend && n!=nend)
     1121            {
     1122              if (o->index < n->index)
     1123                ++o;
     1124              else if (o->index > n->index)
     1125                ++n;
     1126              else
     1127                *n++ = *o++;
    11251128            }
    11261129
    1127             tr_free (t->pieces);
     1130          tr_free (s->pieces);
    11281131        }
    11291132
    1130         t->pieces = pieces;
    1131         t->pieceCount = pieceCount;
    1132 
    1133         pieceListSort (t, PIECES_SORTED_BY_WEIGHT);
    1134 
    1135         /* cleanup */
    1136         tr_free (pool);
    1137     }
    1138 }
    1139 
    1140 static void
    1141 pieceListRemovePiece (Torrent * t, tr_piece_index_t piece)
    1142 {
    1143     struct weighted_piece * p;
    1144 
    1145     if ((p = pieceListLookup (t, piece)))
    1146     {
    1147         const int pos = p - t->pieces;
    1148 
    1149         tr_removeElementFromArray (t->pieces,
    1150                                    pos,
    1151                                    sizeof (struct weighted_piece),
    1152                                    t->pieceCount--);
    1153 
    1154         if (t->pieceCount == 0)
     1133      s->pieces = pieces;
     1134      s->pieceCount = pieceCount;
     1135
     1136      pieceListSort (s, PIECES_SORTED_BY_WEIGHT);
     1137
     1138      /* cleanup */
     1139      tr_free (pool);
     1140    }
     1141}
     1142
     1143static void
     1144pieceListRemovePiece (tr_swarm * s, tr_piece_index_t piece)
     1145{
     1146  struct weighted_piece * p;
     1147
     1148  if ((p = pieceListLookup (s, piece)))
     1149    {
     1150      const int pos = p - s->pieces;
     1151
     1152      tr_removeElementFromArray (s->pieces,
     1153                                 pos,
     1154                                 sizeof (struct weighted_piece),
     1155                                 s->pieceCount--);
     1156
     1157      if (s->pieceCount == 0)
    11551158        {
    1156             tr_free (t->pieces);
    1157             t->pieces = NULL;
     1159          tr_free (s->pieces);
     1160          s->pieces = NULL;
    11581161        }
    11591162    }
     
    11611164
    11621165static void
    1163 pieceListResortPiece (Torrent * t, struct weighted_piece * p)
    1164 {
    1165     int pos;
    1166     bool isSorted = true;
    1167 
    1168     if (p == NULL)
    1169         return;
    1170 
    1171     /* is the torrent already sorted? */
    1172     pos = p - t->pieces;
    1173     setComparePieceByWeightTorrent (t);
    1174     if (isSorted && (pos > 0) && (comparePieceByWeight (p-1, p) > 0))
    1175         isSorted = false;
    1176     if (isSorted && (pos < t->pieceCount - 1) && (comparePieceByWeight (p, p+1) > 0))
    1177         isSorted = false;
    1178 
    1179     if (t->pieceSortState != PIECES_SORTED_BY_WEIGHT)
    1180     {
    1181        pieceListSort (t, PIECES_SORTED_BY_WEIGHT);
    1182        isSorted = true;
    1183     }
    1184 
    1185     /* if it's not sorted, move it around */
    1186     if (!isSorted)
    1187     {
    1188         bool exact;
    1189         const struct weighted_piece tmp = *p;
    1190 
    1191         tr_removeElementFromArray (t->pieces,
    1192                                    pos,
    1193                                    sizeof (struct weighted_piece),
    1194                                    t->pieceCount--);
    1195 
    1196         pos = tr_lowerBound (&tmp, t->pieces, t->pieceCount,
    1197                              sizeof (struct weighted_piece),
    1198                              comparePieceByWeight, &exact);
    1199 
    1200         memmove (&t->pieces[pos + 1],
    1201                  &t->pieces[pos],
    1202                  sizeof (struct weighted_piece) * (t->pieceCount++ - pos));
    1203 
    1204         t->pieces[pos] = tmp;
    1205     }
    1206 
    1207     assertWeightedPiecesAreSorted (t);
    1208 }
    1209 
    1210 static void
    1211 pieceListRemoveRequest (Torrent * t, tr_block_index_t block)
    1212 {
    1213     struct weighted_piece * p;
    1214     const tr_piece_index_t index = tr_torBlockPiece (t->tor, block);
    1215 
    1216     if (((p = pieceListLookup (t, index))) && (p->requestCount > 0))
    1217     {
    1218         --p->requestCount;
    1219         pieceListResortPiece (t, p);
     1166pieceListResortPiece (tr_swarm * s, struct weighted_piece * p)
     1167{
     1168  int pos;
     1169  bool isSorted = true;
     1170
     1171  if (p == NULL)
     1172    return;
     1173
     1174  /* is the torrent already sorted? */
     1175  pos = p - s->pieces;
     1176  setComparePieceByWeightTorrent (s);
     1177  if (isSorted && (pos > 0) && (comparePieceByWeight (p-1, p) > 0))
     1178    isSorted = false;
     1179  if (isSorted && (pos < s->pieceCount - 1) && (comparePieceByWeight (p, p+1) > 0))
     1180    isSorted = false;
     1181
     1182  if (s->pieceSortState != PIECES_SORTED_BY_WEIGHT)
     1183    {
     1184      pieceListSort (s, PIECES_SORTED_BY_WEIGHT);
     1185      isSorted = true;
     1186    }
     1187
     1188  /* if it's not sorted, move it around */
     1189  if (!isSorted)
     1190    {
     1191      bool exact;
     1192      const struct weighted_piece tmp = *p;
     1193
     1194      tr_removeElementFromArray (s->pieces,
     1195                                 pos,
     1196                                 sizeof (struct weighted_piece),
     1197                                 s->pieceCount--);
     1198
     1199      pos = tr_lowerBound (&tmp, s->pieces, s->pieceCount,
     1200                           sizeof (struct weighted_piece),
     1201                           comparePieceByWeight, &exact);
     1202
     1203      memmove (&s->pieces[pos + 1],
     1204               &s->pieces[pos],
     1205               sizeof (struct weighted_piece) * (s->pieceCount++ - pos));
     1206
     1207      s->pieces[pos] = tmp;
     1208    }
     1209
     1210  assertWeightedPiecesAreSorted (s);
     1211}
     1212
     1213static void
     1214pieceListRemoveRequest (tr_swarm * s, tr_block_index_t block)
     1215{
     1216  struct weighted_piece * p;
     1217  const tr_piece_index_t index = tr_torBlockPiece (s->tor, block);
     1218
     1219  if (((p = pieceListLookup (s, index))) && (p->requestCount > 0))
     1220    {
     1221      --p->requestCount;
     1222      pieceListResortPiece (s, p);
    12201223    }
    12211224}
     
    12331236 */
    12341237static void
    1235 tr_incrReplicationOfPiece (Torrent * t, const size_t index)
    1236 {
    1237     assert (replicationExists (t));
    1238     assert (t->pieceReplicationSize == t->tor->info.pieceCount);
    1239 
    1240     /* One more replication of this piece is present in the swarm */
    1241     ++t->pieceReplication[index];
    1242 
    1243     /* we only resort the piece if the list is already sorted */
    1244     if (t->pieceSortState == PIECES_SORTED_BY_WEIGHT)
    1245         pieceListResortPiece (t, pieceListLookup (t, index));
     1238tr_incrReplicationOfPiece (tr_swarm * s, const size_t index)
     1239{
     1240  assert (replicationExists (s));
     1241  assert (s->pieceReplicationSize == s->tor->info.pieceCount);
     1242
     1243  /* One more replication of this piece is present in the swarm */
     1244  ++s->pieceReplication[index];
     1245
     1246  /* we only resort the piece if the list is already sorted */
     1247  if (s->pieceSortState == PIECES_SORTED_BY_WEIGHT)
     1248    pieceListResortPiece (s, pieceListLookup (s, index));
    12461249}
    12471250
     
    12501253 */
    12511254static void
    1252 tr_incrReplicationFromBitfield (Torrent * t, const tr_bitfield * b)
    1253 {
    1254     size_t i;
    1255     uint16_t * rep = t->pieceReplication;
    1256     const size_t n = t->tor->info.pieceCount;
    1257 
    1258     assert (replicationExists (t));
    1259 
    1260     for (i=0; i<n; ++i)
    1261         if (tr_bitfieldHas (b, i))
    1262             ++rep[i];
    1263 
    1264     if (t->pieceSortState == PIECES_SORTED_BY_WEIGHT)
    1265         invalidatePieceSorting (t);
     1255tr_incrReplicationFromBitfield (tr_swarm * s, const tr_bitfield * b)
     1256{
     1257  size_t i;
     1258  uint16_t * rep = s->pieceReplication;
     1259  const size_t n = s->tor->info.pieceCount;
     1260
     1261  assert (replicationExists (s));
     1262
     1263  for (i=0; i<n; ++i)
     1264    if (tr_bitfieldHas (b, i))
     1265      ++rep[i];
     1266
     1267  if (s->pieceSortState == PIECES_SORTED_BY_WEIGHT)
     1268    invalidatePieceSorting (s);
    12661269}
    12671270
     
    12701273 */
    12711274static void
    1272 tr_incrReplication (Torrent * t)
    1273 {
    1274     int i;
    1275     const int n = t->pieceReplicationSize;
    1276 
    1277     assert (replicationExists (t));
    1278     assert (t->pieceReplicationSize == t->tor->info.pieceCount);
    1279 
    1280     for (i=0; i<n; ++i)
    1281         ++t->pieceReplication[i];
     1275tr_incrReplication (tr_swarm * s)
     1276{
     1277  int i;
     1278  const int n = s->pieceReplicationSize;
     1279
     1280  assert (replicationExists (s));
     1281  assert (s->pieceReplicationSize == s->tor->info.pieceCount);
     1282
     1283  for (i=0; i<n; ++i)
     1284    ++s->pieceReplication[i];
    12821285}
    12831286
     
    12861289 */
    12871290static void
    1288 tr_decrReplicationFromBitfield (Torrent * t, const tr_bitfield * b)
    1289 {
    1290     int i;
    1291     const int n = t->pieceReplicationSize;
    1292 
    1293     assert (replicationExists (t));
    1294     assert (t->pieceReplicationSize == t->tor->info.pieceCount);
    1295 
    1296     if (tr_bitfieldHasAll (b))
    1297     {
    1298         for (i=0; i<n; ++i)
    1299             --t->pieceReplication[i];
    1300     }
    1301     else if (!tr_bitfieldHasNone (b))
    1302     {
    1303         for (i=0; i<n; ++i)
    1304             if (tr_bitfieldHas (b, i))
    1305                 --t->pieceReplication[i];
    1306 
    1307         if (t->pieceSortState == PIECES_SORTED_BY_WEIGHT)
    1308             invalidatePieceSorting (t);
     1291tr_decrReplicationFromBitfield (tr_swarm * s, const tr_bitfield * b)
     1292{
     1293  int i;
     1294  const int n = s->pieceReplicationSize;
     1295
     1296  assert (replicationExists (s));
     1297  assert (s->pieceReplicationSize == s->tor->info.pieceCount);
     1298
     1299  if (tr_bitfieldHasAll (b))
     1300    {
     1301      for (i=0; i<n; ++i)
     1302        --s->pieceReplication[i];
     1303    }
     1304  else if (!tr_bitfieldHasNone (b))
     1305    {
     1306      for (i=0; i<n; ++i)
     1307        if (tr_bitfieldHas (b, i))
     1308          --s->pieceReplication[i];
     1309
     1310      if (s->pieceSortState == PIECES_SORTED_BY_WEIGHT)
     1311        invalidatePieceSorting (s);
    13091312    }
    13101313}
     
    13171320tr_peerMgrRebuildRequests (tr_torrent * tor)
    13181321{
    1319     assert (tr_isTorrent (tor));
    1320 
    1321     pieceListRebuild (tor->torrentPeers);
     1322  assert (tr_isTorrent (tor));
     1323
     1324  pieceListRebuild (tor->swarm);
    13221325}
    13231326
     
    13301333                           bool                   get_intervals)
    13311334{
    1332     int i;
    1333     int got;
    1334     Torrent * t;
    1335     struct weighted_piece * pieces;
    1336     const tr_bitfield * const have = &peer->have;
    1337 
    1338     /* sanity clause */
    1339     assert (tr_isTorrent (tor));
    1340     assert (peer->clientIsInterested);
    1341     assert (!peer->clientIsChoked);
    1342     assert (numwant > 0);
    1343 
    1344     /* walk through the pieces and find blocks that should be requested */
    1345     got = 0;
    1346     t = tor->torrentPeers;
    1347 
    1348     /* prep the pieces list */
    1349     if (t->pieces == NULL)
    1350         pieceListRebuild (t);
    1351 
    1352     if (t->pieceSortState != PIECES_SORTED_BY_WEIGHT)
    1353         pieceListSort (t, PIECES_SORTED_BY_WEIGHT);
    1354 
    1355     assertReplicationCountIsExact (t);
    1356     assertWeightedPiecesAreSorted (t);
    1357 
    1358     updateEndgame (t);
    1359     pieces = t->pieces;
    1360     for (i=0; i<t->pieceCount && got<numwant; ++i)
    1361     {
    1362         struct weighted_piece * p = pieces + i;
    1363 
    1364         /* if the peer has this piece that we want... */
    1365         if (tr_bitfieldHas (have, p->index))
     1335  int i;
     1336  int got;
     1337  tr_swarm * s;
     1338  struct weighted_piece * pieces;
     1339  const tr_bitfield * const have = &peer->have;
     1340
     1341  /* sanity clause */
     1342  assert (tr_isTorrent (tor));
     1343  assert (peer->clientIsInterested);
     1344  assert (!peer->clientIsChoked);
     1345  assert (numwant > 0);
     1346
     1347  /* walk through the pieces and find blocks that should be requested */
     1348  got = 0;
     1349  s = tor->swarm;
     1350
     1351  /* prep the pieces list */
     1352  if (s->pieces == NULL)
     1353    pieceListRebuild (s);
     1354
     1355  if (s->pieceSortState != PIECES_SORTED_BY_WEIGHT)
     1356    pieceListSort (s, PIECES_SORTED_BY_WEIGHT);
     1357
     1358  assertReplicationCountIsExact (s);
     1359  assertWeightedPiecesAreSorted (s);
     1360
     1361  updateEndgame (s);
     1362  pieces = s->pieces;
     1363  for (i=0; i<s->pieceCount && got<numwant; ++i)
     1364    {
     1365      struct weighted_piece * p = pieces + i;
     1366
     1367      /* if the peer has this piece that we want... */
     1368      if (tr_bitfieldHas (have, p->index))
    13661369        {
    1367             tr_block_index_t b;
    1368             tr_block_index_t first;
    1369             tr_block_index_t last;
    1370             tr_ptrArray peerArr = TR_PTR_ARRAY_INIT;
    1371 
    1372             tr_torGetPieceBlockRange (tor, p->index, &first, &last);
    1373 
    1374             for (b=first; b<=last && (got<numwant || (get_intervals && setme[2*got-1] == b-1)); ++b)
     1370          tr_block_index_t b;
     1371          tr_block_index_t first;
     1372          tr_block_index_t last;
     1373          tr_ptrArray peerArr = TR_PTR_ARRAY_INIT;
     1374
     1375          tr_torGetPieceBlockRange (tor, p->index, &first, &last);
     1376
     1377          for (b=first; b<=last && (got<numwant || (get_intervals && setme[2*got-1] == b-1)); ++b)
    13751378            {
    1376                 int peerCount;
    1377                 tr_peer ** peers;
    1378 
    1379                 /* don't request blocks we've already got */
    1380                 if (tr_cpBlockIsComplete (&tor->completion, b))
     1379              int peerCount;
     1380              tr_peer ** peers;
     1381
     1382              /* don't request blocks we've already got */
     1383              if (tr_cpBlockIsComplete (&tor->completion, b))
     1384                continue;
     1385
     1386              /* always add peer if this block has no peers yet */
     1387              tr_ptrArrayClear (&peerArr);
     1388              getBlockRequestPeers (s, b, &peerArr);
     1389              peers = (tr_peer **) tr_ptrArrayPeek (&peerArr, &peerCount);
     1390              if (peerCount != 0)
     1391                {
     1392                  /* don't make a second block request until the endgame */
     1393                  if (!s->endgame)
    13811394                    continue;
    13821395
    1383                 /* always add peer if this block has no peers yet */
    1384                 tr_ptrArrayClear (&peerArr);
    1385                 getBlockRequestPeers (t, b, &peerArr);
    1386                 peers = (tr_peer **) tr_ptrArrayPeek (&peerArr, &peerCount);
    1387                 if (peerCount != 0)
     1396                  /* don't have more than two peers requesting this block */
     1397                  if (peerCount > 1)
     1398                    continue;
     1399
     1400                  /* don't send the same request to the same peer twice */
     1401                  if (peer == peers[0])
     1402                    continue;
     1403
     1404                  /* in the endgame allow an additional peer to download a
     1405                     block but only if the peer seems to be handling requests
     1406                     relatively fast */
     1407                  if (peer->pendingReqsToPeer + numwant - got < s->endgame)
     1408                    continue;
     1409                }
     1410
     1411              /* update the caller's table */
     1412              if (!get_intervals)
    13881413                {
    1389                     /* don't make a second block request until the endgame */
    1390                     if (!t->endgame)
    1391                         continue;
    1392 
    1393                     /* don't have more than two peers requesting this block */
    1394                     if (peerCount > 1)
    1395                         continue;
    1396 
    1397                     /* don't send the same request to the same peer twice */
    1398                     if (peer == peers[0])
    1399                         continue;
    1400 
    1401                     /* in the endgame allow an additional peer to download a
    1402                        block but only if the peer seems to be handling requests
    1403                        relatively fast */
    1404                     if (peer->pendingReqsToPeer + numwant - got < t->endgame)
    1405                         continue;
     1414                  setme[got++] = b;
    14061415                }
    1407 
    1408                 /* update the caller's table */
    1409                 if (!get_intervals) {
    1410                     setme[got++] = b;
     1416              /* if intervals are requested two array entries are necessarry:
     1417                 one for the interval's starting block and one for its end block */
     1418              else if (got && setme[2 * got - 1] == b - 1 && b != first)
     1419                {
     1420                  /* expand the last interval */
     1421                  ++setme[2 * got - 1];
    14111422                }
    1412                 /* if intervals are requested two array entries are necessarry:
    1413                    one for the interval's starting block and one for its end block */
    1414                 else if (got && setme[2 * got - 1] == b - 1 && b != first) {
    1415                     /* expand the last interval */
    1416                     ++setme[2 * got - 1];
     1423              else
     1424                {
     1425                  /* begin a new interval */
     1426                  setme[2 * got] = setme[2 * got + 1] = b;
     1427                  ++got;
    14171428                }
    1418                 else {
    1419                     /* begin a new interval */
    1420                     setme[2 * got] = setme[2 * got + 1] = b;
    1421                     ++got;
    1422                 }
    1423 
    1424                 /* update our own tables */
    1425                 requestListAdd (t, b, peer);
    1426                 ++p->requestCount;
     1429
     1430              /* update our own tables */
     1431              requestListAdd (s, b, peer);
     1432              ++p->requestCount;
    14271433            }
    14281434
    1429             tr_ptrArrayDestruct (&peerArr, NULL);
     1435          tr_ptrArrayDestruct (&peerArr, NULL);
    14301436        }
    14311437    }
    14321438
    1433     /* In most cases we've just changed the weights of a small number of pieces.
    1434      * So rather than qsort ()ing the entire array, it's faster to apply an
    1435      * adaptive insertion sort algorithm. */
    1436     if (got > 0)
    1437     {
    1438         /* not enough requests || last piece modified */
    1439         if (i == t->pieceCount) --i;
    1440 
    1441         setComparePieceByWeightTorrent (t);
    1442         while (--i >= 0)
     1439  /* In most cases we've just changed the weights of a small number of pieces.
     1440   * So rather than qsort ()ing the entire array, it's faster to apply an
     1441   * adaptive insertion sort algorithm. */
     1442  if (got > 0)
     1443    {
     1444      /* not enough requests || last piece modified */
     1445      if (i == s->pieceCount)
     1446        --i;
     1447
     1448      setComparePieceByWeightTorrent (s);
     1449      while (--i >= 0)
    14431450        {
    1444             bool exact;
    1445 
    1446             /* relative position! */
    1447             const int newpos = tr_lowerBound (&t->pieces[i], &t->pieces[i + 1],
    1448                                               t->pieceCount - (i + 1),
    1449                                               sizeof (struct weighted_piece),
    1450                                               comparePieceByWeight, &exact);
    1451             if (newpos > 0)
     1451          bool exact;
     1452
     1453          /* relative position! */
     1454          const int newpos = tr_lowerBound (&s->pieces[i], &s->pieces[i + 1],
     1455                                            s->pieceCount - (i + 1),
     1456                                            sizeof (struct weighted_piece),
     1457                                            comparePieceByWeight, &exact);
     1458          if (newpos > 0)
    14521459            {
    1453                 const struct weighted_piece piece = t->pieces[i];
    1454                 memmove (&t->pieces[i],
    1455                          &t->pieces[i + 1],
    1456                          sizeof (struct weighted_piece) * (newpos));
    1457                 t->pieces[i + newpos] = piece;
     1460              const struct weighted_piece piece = s->pieces[i];
     1461              memmove (&s->pieces[i],
     1462                       &s->pieces[i + 1],
     1463                       sizeof (struct weighted_piece) * (newpos));
     1464              s->pieces[i + newpos] = piece;
    14581465            }
    14591466        }
    14601467    }
    14611468
    1462     assertWeightedPiecesAreSorted (t);
    1463     *numgot = got;
     1469  assertWeightedPiecesAreSorted (t);
     1470  *numgot = got;
    14641471}
    14651472
     
    14691476                          tr_block_index_t    block)
    14701477{
    1471     const Torrent * t = tor->torrentPeers;
    1472     return requestListLookup ((Torrent*)t, block, peer) != NULL;
     1478  return requestListLookup ((tr_swarm*)tor->swarm, block, peer) != NULL;
    14731479}
    14741480
     
    14911497    tor = NULL;
    14921498    while ((tor = tr_torrentNext (mgr->session, tor)))
    1493         cancel_buflen = MAX (cancel_buflen, tor->torrentPeers->requestCount);
     1499        cancel_buflen = MAX (cancel_buflen, tor->swarm->requestCount);
    14941500    if (cancel_buflen > 0)
    14951501        cancel = tr_new (struct block_request, cancel_buflen);
     
    14991505    while ((tor = tr_torrentNext (mgr->session, tor)))
    15001506    {
    1501         Torrent * t = tor->torrentPeers;
    1502         const int n = t->requestCount;
     1507        tr_swarm * s = tor->swarm;
     1508        const int n = s->requestCount;
    15031509        if (n > 0)
    15041510        {
     
    15081514            const struct block_request * end;
    15091515
    1510             for (it=t->requests, end=it+n; it!=end; ++it)
     1516            for (it=s->requests, end=it+n; it!=end; ++it)
    15111517            {
    15121518                if ((it->sentAt <= too_old) && it->peer->msgs && !tr_peerMsgsIsReadingBlock (it->peer->msgs, it->block))
     
    15141520                else
    15151521                {
    1516                     if (it != &t->requests[keepCount])
    1517                         t->requests[keepCount] = *it;
     1522                    if (it != &s->requests[keepCount])
     1523                        s->requests[keepCount] = *it;
    15181524                    keepCount++;
    15191525                }
     
    15211527
    15221528            /* prune out the ones we aren't keeping */
    1523             t->requestCount = keepCount;
     1529            s->requestCount = keepCount;
    15241530
    15251531            /* send cancel messages for all the "cancel" ones */
     
    15341540            /* decrement the pending request counts for the timed-out blocks */
    15351541            for (it=cancel, end=it+cancelCount; it!=end; ++it)
    1536                 pieceListRemoveRequest (t, it->block);
     1542                pieceListRemoveRequest (s, it->block);
    15371543        }
    15381544    }
     
    15441550
    15451551static void
    1546 addStrike (Torrent * t, tr_peer * peer)
    1547 {
    1548     tordbg (t, "increasing peer %s strike count to %d",
    1549             tr_atomAddrStr (peer->atom), peer->strikes + 1);
    1550 
    1551     if (++peer->strikes >= MAX_BAD_PIECES_PER_PEER)
    1552     {
    1553         struct peer_atom * atom = peer->atom;
    1554         atom->flags2 |= MYFLAG_BANNED;
    1555         peer->doPurge = 1;
    1556         tordbg (t, "banning peer %s", tr_atomAddrStr (atom));
    1557     }
    1558 }
    1559 
    1560 static void
    1561 peerSuggestedPiece (Torrent            * t UNUSED,
     1552addStrike (tr_swarm * s, tr_peer * peer)
     1553{
     1554  tordbg (s, "increasing peer %s strike count to %d",
     1555          tr_atomAddrStr (peer->atom), peer->strikes + 1);
     1556
     1557  if (++peer->strikes >= MAX_BAD_PIECES_PER_PEER)
     1558    {
     1559      struct peer_atom * atom = peer->atom;
     1560      atom->flags2 |= MYFLAG_BANNED;
     1561      peer->doPurge = 1;
     1562      tordbg (s, "banning peer %s", tr_atomAddrStr (atom));
     1563    }
     1564}
     1565
     1566static void
     1567peerSuggestedPiece (tr_swarm           * s UNUSED,
    15621568                    tr_peer            * peer UNUSED,
    15631569                    tr_piece_index_t     pieceIndex UNUSED,
     
    16091615
    16101616static void
    1611 removeRequestFromTables (Torrent * t, tr_block_index_t block, const tr_peer * peer)
    1612 {
    1613     requestListRemove (t, block, peer);
    1614     pieceListRemoveRequest (t, block);
     1617removeRequestFromTables (tr_swarm * s, tr_block_index_t block, const tr_peer * peer)
     1618{
     1619  requestListRemove (s, block, peer);
     1620  pieceListRemoveRequest (s, block);
    16151621}
    16161622
     
    16181624   either way we need to remove all its requests */
    16191625static void
    1620 peerDeclinedAllRequests (Torrent * t, const tr_peer * peer)
    1621 {
    1622     int i, n;
    1623     tr_block_index_t * blocks = tr_new (tr_block_index_t, t->requestCount);
    1624 
    1625     for (i=n=0; i<t->requestCount; ++i)
    1626         if (peer == t->requests[i].peer)
    1627             blocks[n++] = t->requests[i].block;
    1628 
    1629     for (i=0; i<n; ++i)
    1630         removeRequestFromTables (t, blocks[i], peer);
    1631 
    1632     tr_free (blocks);
    1633 }
    1634 
    1635 static void
    1636 cancelAllRequestsForBlock (struct tr_torrent_peers * t,
    1637                            tr_block_index_t          block,
    1638                            tr_peer                 * no_notify)
     1626peerDeclinedAllRequests (tr_swarm * s, const tr_peer * peer)
     1627{
     1628  int i, n;
     1629  tr_block_index_t * blocks = tr_new (tr_block_index_t, s->requestCount);
     1630
     1631  for (i=n=0; i<s->requestCount; ++i)
     1632    if (peer == s->requests[i].peer)
     1633      blocks[n++] = s->requests[i].block;
     1634
     1635  for (i=0; i<n; ++i)
     1636    removeRequestFromTables (s, blocks[i], peer);
     1637
     1638  tr_free (blocks);
     1639}
     1640
     1641static void
     1642cancelAllRequestsForBlock (tr_swarm          * s,
     1643                           tr_block_index_t    block,
     1644                           tr_peer           * no_notify)
    16391645{
    16401646  int i;
     
    16441650
    16451651  peerArr = TR_PTR_ARRAY_INIT;
    1646   getBlockRequestPeers (t, block, &peerArr);
     1652  getBlockRequestPeers (s, block, &peerArr);
    16471653  peers = (tr_peer **) tr_ptrArrayPeek (&peerArr, &peerCount);
    16481654  for (i=0; i<peerCount; ++i)
     
    16561662        }
    16571663
    1658       removeRequestFromTables (t, block, p);
     1664      removeRequestFromTables (s, block, p);
    16591665    }
    16601666
     
    16681674  int peerCount;
    16691675  tr_peer ** peers;
    1670   struct tr_torrent_peers * t = tor->torrentPeers;
     1676  tr_swarm * s = tor->swarm;
    16711677
    16721678  /* notify the peers that we now have this piece */
    1673   peerCount = tr_ptrArraySize (&t->peers);
    1674   peers = (tr_peer**) tr_ptrArrayBase (&t->peers);
     1679  peerCount = tr_ptrArraySize (&s->peers);
     1680  peers = (tr_peer**) tr_ptrArrayBase (&s->peers);
    16751681  for (i=0; i<peerCount; ++i)
    16761682    tr_peerMsgsHave (peers[i]->msgs, p);
    16771683
    16781684  /* bookkeeping */
    1679   pieceListRemovePiece (t, p);
    1680   t->needsCompletenessCheck = true;
    1681 }
    1682 
    1683 static void
    1684 peerCallbackFunc (tr_peer * peer, const tr_peer_event * e, void * vt)
    1685 {
    1686     Torrent * t = vt;
    1687 
    1688     torrentLock (t);
    1689 
    1690     assert (peer != NULL);
    1691 
    1692     switch (e->eventType)
    1693     {
    1694         case TR_PEER_PEER_GOT_DATA:
     1685  pieceListRemovePiece (s, p);
     1686  s->needsCompletenessCheck = true;
     1687}
     1688
     1689static void
     1690peerCallbackFunc (tr_peer * peer, const tr_peer_event * e, void * vs)
     1691{
     1692  tr_swarm * s = vs;
     1693
     1694  swarmLock (s);
     1695
     1696  assert (peer != NULL);
     1697
     1698  switch (e->eventType)
     1699    {
     1700      case TR_PEER_PEER_GOT_DATA:
    16951701        {
    1696             const time_t now = tr_time ();
    1697             tr_torrent * tor = t->tor;
    1698 
    1699             if (e->wasPieceData)
     1702          const time_t now = tr_time ();
     1703          tr_torrent * tor = s->tor;
     1704
     1705          if (e->wasPieceData)
    17001706            {
    1701                 tor->uploadedCur += e->length;
    1702                 tr_announcerAddBytes (tor, TR_ANN_UP, e->length);
    1703                 tr_torrentSetActivityDate (tor, now);
    1704                 tr_torrentSetDirty (tor);
     1707              tor->uploadedCur += e->length;
     1708              tr_announcerAddBytes (tor, TR_ANN_UP, e->length);
     1709              tr_torrentSetActivityDate (tor, now);
     1710              tr_torrentSetDirty (tor);
    17051711            }
    17061712
    1707             /* update the stats */
    1708             if (e->wasPieceData)
    1709                 tr_statsAddUploaded (tor->session, e->length);
    1710 
    1711             /* update our atom */
    1712             if (peer->atom && e->wasPieceData)
    1713                 peer->atom->piece_data_time = now;
    1714 
    1715             break;
     1713          /* update the stats */
     1714          if (e->wasPieceData)
     1715            tr_statsAddUploaded (tor->session, e->length);
     1716
     1717          /* update our atom */
     1718          if (peer->atom && e->wasPieceData)
     1719            peer->atom->piece_data_time = now;
     1720
     1721          break;
    17161722        }
    17171723
    1718         case TR_PEER_CLIENT_GOT_HAVE:
    1719             if (replicationExists (t)) {
    1720                 tr_incrReplicationOfPiece (t, e->pieceIndex);
    1721                 assertReplicationCountIsExact (t);
     1724      case TR_PEER_CLIENT_GOT_HAVE:
     1725        if (replicationExists (s))
     1726          {
     1727            tr_incrReplicationOfPiece (s, e->pieceIndex);
     1728            assertReplicationCountIsExact (s);
     1729          }
     1730        break;
     1731
     1732      case TR_PEER_CLIENT_GOT_HAVE_ALL:
     1733        if (replicationExists (s))
     1734          {
     1735            tr_incrReplication (s);
     1736            assertReplicationCountIsExact (s);
     1737          }
     1738        break;
     1739
     1740      case TR_PEER_CLIENT_GOT_HAVE_NONE:
     1741        /* noop */
     1742        break;
     1743
     1744      case TR_PEER_CLIENT_GOT_BITFIELD:
     1745        assert (e->bitfield != NULL);
     1746        if (replicationExists (s))
     1747          {
     1748            tr_incrReplicationFromBitfield (s, e->bitfield);
     1749            assertReplicationCountIsExact (s);
     1750          }
     1751        break;
     1752
     1753      case TR_PEER_CLIENT_GOT_REJ:
     1754        {
     1755          tr_block_index_t b = _tr_block (s->tor, e->pieceIndex, e->offset);
     1756          if (b < s->tor->blockCount)
     1757            removeRequestFromTables (s, b, peer);
     1758          else
     1759            tordbg (s, "Peer %s sent an out-of-range reject message",
     1760                    tr_atomAddrStr (peer->atom));
     1761          break;
     1762        }
     1763
     1764      case TR_PEER_CLIENT_GOT_CHOKE:
     1765        peerDeclinedAllRequests (s, peer);
     1766        break;
     1767
     1768      case TR_PEER_CLIENT_GOT_PORT:
     1769        if (peer->atom)
     1770          peer->atom->port = e->port;
     1771        break;
     1772
     1773      case TR_PEER_CLIENT_GOT_SUGGEST:
     1774        peerSuggestedPiece (s, peer, e->pieceIndex, false);
     1775        break;
     1776
     1777      case TR_PEER_CLIENT_GOT_ALLOWED_FAST:
     1778        peerSuggestedPiece (s, peer, e->pieceIndex, true);
     1779        break;
     1780
     1781      case TR_PEER_CLIENT_GOT_DATA:
     1782        {
     1783          const time_t now = tr_time ();
     1784          tr_torrent * tor = s->tor;
     1785
     1786          if (e->wasPieceData)
     1787            {
     1788              tor->downloadedCur += e->length;
     1789              tr_torrentSetActivityDate (tor, now);
     1790              tr_torrentSetDirty (tor);
    17221791            }
    1723             break;
    1724 
    1725         case TR_PEER_CLIENT_GOT_HAVE_ALL:
    1726             if (replicationExists (t)) {
    1727                 tr_incrReplication (t);
    1728                 assertReplicationCountIsExact (t);
    1729             }
    1730             break;
    1731 
    1732         case TR_PEER_CLIENT_GOT_HAVE_NONE:
    1733             /* noop */
    1734             break;
    1735 
    1736         case TR_PEER_CLIENT_GOT_BITFIELD:
    1737             assert (e->bitfield != NULL);
    1738             if (replicationExists (t)) {
    1739                 tr_incrReplicationFromBitfield (t, e->bitfield);
    1740                 assertReplicationCountIsExact (t);
    1741             }
    1742             break;
    1743 
    1744         case TR_PEER_CLIENT_GOT_REJ: {
    1745             tr_block_index_t b = _tr_block (t->tor, e->pieceIndex, e->offset);
    1746             if (b < t->tor->blockCount)
    1747                 removeRequestFromTables (t, b, peer);
    1748             else
    1749                 tordbg (t, "Peer %s sent an out-of-range reject message",
    1750                            tr_atomAddrStr (peer->atom));
    1751             break;
     1792
     1793          /* update the stats */
     1794          if (e->wasPieceData)
     1795            tr_statsAddDownloaded (tor->session, e->length);
     1796
     1797          /* update our atom */
     1798          if (peer->atom && e->wasPieceData)
     1799            peer->atom->piece_data_time = now;
     1800
     1801          break;
    17521802        }
    17531803
    1754         case TR_PEER_CLIENT_GOT_CHOKE:
    1755             peerDeclinedAllRequests (t, peer);
    1756             break;
    1757 
    1758         case TR_PEER_CLIENT_GOT_PORT:
    1759             if (peer->atom)
    1760                 peer->atom->port = e->port;
    1761             break;
    1762 
    1763         case TR_PEER_CLIENT_GOT_SUGGEST:
    1764             peerSuggestedPiece (t, peer, e->pieceIndex, false);
    1765             break;
    1766 
    1767         case TR_PEER_CLIENT_GOT_ALLOWED_FAST:
    1768             peerSuggestedPiece (t, peer, e->pieceIndex, true);
    1769             break;
    1770 
    1771         case TR_PEER_CLIENT_GOT_DATA:
     1804      case TR_PEER_CLIENT_GOT_BLOCK:
    17721805        {
    1773             const time_t now = tr_time ();
    1774             tr_torrent * tor = t->tor;
    1775 
    1776             if (e->wasPieceData)
    1777             {
    1778                 tor->downloadedCur += e->length;
    1779                 tr_torrentSetActivityDate (tor, now);
    1780                 tr_torrentSetDirty (tor);
    1781             }
    1782 
    1783             /* update the stats */
    1784             if (e->wasPieceData)
    1785                 tr_statsAddDownloaded (tor->session, e->length);
    1786 
    1787             /* update our atom */
    1788             if (peer->atom && e->wasPieceData)
    1789                 peer->atom->piece_data_time = now;
    1790 
    1791             break;
     1806          const tr_block_index_t block = _tr_block (s->tor, e->pieceIndex, e->offset);
     1807          cancelAllRequestsForBlock (s, block, peer);
     1808          tr_historyAdd (&peer->blocksSentToClient, tr_time(), 1);
     1809          pieceListResortPiece (s, pieceListLookup (s, e->pieceIndex));
     1810          tr_torrentGotBlock (s->tor, block);
     1811          break;
    17921812        }
    17931813
    1794         case TR_PEER_CLIENT_GOT_BLOCK:
     1814      case TR_PEER_ERROR:
     1815        if ((e->err == ERANGE) || (e->err == EMSGSIZE) || (e->err == ENOTCONN))
    17951816          {
    1796             const tr_block_index_t block = _tr_block (t->tor, e->pieceIndex, e->offset);
    1797             cancelAllRequestsForBlock (t, block, peer);
    1798             tr_historyAdd (&peer->blocksSentToClient, tr_time(), 1);
    1799             pieceListResortPiece (t, pieceListLookup (t, e->pieceIndex));
    1800             tr_torrentGotBlock (t->tor, block);
    1801             break;
     1817            /* some protocol error from the peer */
     1818            peer->doPurge = 1;
     1819            tordbg (s, "setting %s doPurge flag because we got an ERANGE, EMSGSIZE, or ENOTCONN error",
     1820                    tr_atomAddrStr (peer->atom));
    18021821          }
    1803 
    1804         case TR_PEER_ERROR:
    1805             if ((e->err == ERANGE) || (e->err == EMSGSIZE) || (e->err == ENOTCONN))
    1806             {
    1807                 /* some protocol error from the peer */
    1808                 peer->doPurge = 1;
    1809                 tordbg (t, "setting %s doPurge flag because we got an ERANGE, EMSGSIZE, or ENOTCONN error",
    1810                         tr_atomAddrStr (peer->atom));
    1811             }
    1812             else
    1813             {
    1814                 tordbg (t, "unhandled error: %s", tr_strerror (e->err));
    1815             }
    1816             break;
    1817 
    1818         default:
    1819             assert (0);
    1820     }
    1821 
    1822     torrentUnlock (t);
     1822        else
     1823          {
     1824            tordbg (s, "unhandled error: %s", tr_strerror (e->err));
     1825          }
     1826        break;
     1827
     1828      default:
     1829        assert (0);
     1830    }
     1831
     1832  swarmUnlock (s);
    18231833}
    18241834
     
    18421852
    18431853static void
    1844 ensureAtomExists (Torrent           * t,
     1854ensureAtomExists (tr_swarm          * s,
    18451855                  const tr_address  * addr,
    18461856                  const tr_port       port,
     
    18491859                  const uint8_t       from)
    18501860{
    1851     struct peer_atom * a;
    1852 
    1853     assert (tr_address_is_valid (addr));
    1854     assert (from < TR_PEER_FROM__MAX);
    1855 
    1856     a = getExistingAtom (t, addr);
    1857 
    1858     if (a == NULL)
    1859     {
    1860         const int jitter = tr_cryptoWeakRandInt (60*10);
    1861         a = tr_new0 (struct peer_atom, 1);
    1862         a->addr = *addr;
    1863         a->port = port;
    1864         a->flags = flags;
    1865         a->fromFirst = from;
     1861  struct peer_atom * a;
     1862
     1863  assert (tr_address_is_valid (addr));
     1864  assert (from < TR_PEER_FROM__MAX);
     1865
     1866  a = getExistingAtom (s, addr);
     1867
     1868  if (a == NULL)
     1869    {
     1870      const int jitter = tr_cryptoWeakRandInt (60*10);
     1871      a = tr_new0 (struct peer_atom, 1);
     1872      a->addr = *addr;
     1873      a->port = port;
     1874      a->flags = flags;
     1875      a->fromFirst = from;
     1876      a->fromBest = from;
     1877      a->shelf_date = tr_time () + getDefaultShelfLife (from) + jitter;
     1878      a->blocklisted = -1;
     1879      atomSetSeedProbability (a, seedProbability);
     1880      tr_ptrArrayInsertSorted (&s->pool, a, compareAtomsByAddress);
     1881
     1882      tordbg (s, "got a new atom: %s", tr_atomAddrStr (a));
     1883    }
     1884  else
     1885    {
     1886      if (from < a->fromBest)
    18661887        a->fromBest = from;
    1867         a->shelf_date = tr_time () + getDefaultShelfLife (from) + jitter;
    1868         a->blocklisted = -1;
     1888
     1889      if (a->seedProbability == -1)
    18691890        atomSetSeedProbability (a, seedProbability);
    1870         tr_ptrArrayInsertSorted (&t->pool, a, compareAtomsByAddress);
    1871 
    1872         tordbg (t, "got a new atom: %s", tr_atomAddrStr (a));
    1873     }
    1874     else
    1875     {
    1876         if (from < a->fromBest)
    1877             a->fromBest = from;
    1878 
    1879         if (a->seedProbability == -1)
    1880             atomSetSeedProbability (a, seedProbability);
    1881 
    1882         a->flags |= flags;
     1891
     1892      a->flags |= flags;
    18831893    }
    18841894}
     
    18871897getMaxPeerCount (const tr_torrent * tor)
    18881898{
    1889     return tor->maxConnectedPeers;
     1899  return tor->maxConnectedPeers;
    18901900}
    18911901
    18921902static int
    1893 getPeerCount (const Torrent * t)
    1894 {
    1895     return tr_ptrArraySize (&t->peers);/* + tr_ptrArraySize (&t->outgoingHandshakes); */
     1903getPeerCount (const tr_swarm * s)
     1904{
     1905  return tr_ptrArraySize (&s->peers);/* + tr_ptrArraySize (&t->outgoingHandshakes); */
    18961906}
    18971907
     
    19051915                   void          * vmanager)
    19061916{
    1907     bool              ok = isConnected;
    1908     bool              success = false;
    1909     tr_port            port;
    1910     const tr_address * addr;
    1911     tr_peerMgr      * manager = vmanager;
    1912     Torrent          * t;
    1913     tr_handshake    * ours;
    1914 
    1915     assert (io);
    1916     assert (tr_isBool (ok));
    1917 
    1918     t = tr_peerIoHasTorrentHash (io)
    1919         ? getExistingTorrent (manager, tr_peerIoGetTorrentHash (io))
    1920         : NULL;
    1921 
    1922     if (tr_peerIoIsIncoming (io))
    1923         ours = tr_ptrArrayRemoveSorted (&manager->incomingHandshakes,
    1924                                         handshake, handshakeCompare);
    1925     else if (t)
    1926         ours = tr_ptrArrayRemoveSorted (&t->outgoingHandshakes,
    1927                                         handshake, handshakeCompare);
    1928     else
    1929         ours = handshake;
    1930 
    1931     assert (ours);
    1932     assert (ours == handshake);
    1933 
    1934     if (t)
    1935         torrentLock (t);
    1936 
    1937     addr = tr_peerIoGetAddress (io, &port);
    1938 
    1939     if (!ok || !t || !t->isRunning)
    1940     {
    1941         if (t)
     1917  bool ok = isConnected;
     1918  bool success = false;
     1919  tr_port port;
     1920  const tr_address * addr;
     1921  tr_peerMgr * manager = vmanager;
     1922  tr_swarm  * s;
     1923  tr_handshake * ours;
     1924
     1925  assert (io);
     1926  assert (tr_isBool (ok));
     1927
     1928  s = tr_peerIoHasTorrentHash (io)
     1929    ? getExistingSwarm (manager, tr_peerIoGetTorrentHash (io))
     1930    : NULL;
     1931
     1932  if (tr_peerIoIsIncoming (io))
     1933    ours = tr_ptrArrayRemoveSorted (&manager->incomingHandshakes,
     1934                                    handshake, handshakeCompare);
     1935  else if (s)
     1936    ours = tr_ptrArrayRemoveSorted (&s->outgoingHandshakes,
     1937                                    handshake, handshakeCompare);
     1938  else
     1939    ours = handshake;
     1940
     1941  assert (ours);
     1942  assert (ours == handshake);
     1943
     1944  if (s)
     1945    swarmLock (s);
     1946
     1947  addr = tr_peerIoGetAddress (io, &port);
     1948
     1949  if (!ok || !s || !s->isRunning)
     1950    {
     1951      if (s)
    19421952        {
    1943             struct peer_atom * atom = getExistingAtom (t, addr);
    1944             if (atom)
     1953          struct peer_atom * atom = getExistingAtom (s, addr);
     1954          if (atom)
    19451955            {
    1946                 ++atom->numFails;
    1947 
    1948                 if (!readAnythingFromPeer)
     1956              ++atom->numFails;
     1957
     1958              if (!readAnythingFromPeer)
    19491959                {
    1950                     tordbg (t, "marking peer %s as unreachable... numFails is %d", tr_atomAddrStr (atom), (int)atom->numFails);
    1951                     atom->flags2 |= MYFLAG_UNREACHABLE;
     1960                  tordbg (s, "marking peer %s as unreachable... numFails is %d", tr_atomAddrStr (atom), (int)atom->numFails);
     1961                  atom->flags2 |= MYFLAG_UNREACHABLE;
    19521962                }
    19531963            }
    19541964        }
    19551965    }
    1956     else /* looking good */
    1957     {
    1958         struct peer_atom * atom;
    1959 
    1960         ensureAtomExists (t, addr, port, 0, -1, TR_PEER_FROM_INCOMING);
    1961         atom = getExistingAtom (t, addr);
    1962         atom->time = tr_time ();
    1963         atom->piece_data_time = 0;
    1964         atom->lastConnectionAt = tr_time ();
    1965 
    1966         if (!tr_peerIoIsIncoming (io))
     1966  else /* looking good */
     1967    {
     1968      struct peer_atom * atom;
     1969
     1970      ensureAtomExists (s, addr, port, 0, -1, TR_PEER_FROM_INCOMING);
     1971      atom = getExistingAtom (s, addr);
     1972      atom->time = tr_time ();
     1973      atom->piece_data_time = 0;
     1974      atom->lastConnectionAt = tr_time ();
     1975
     1976      if (!tr_peerIoIsIncoming (io))
    19671977        {
    1968             atom->flags |= ADDED_F_CONNECTABLE;
    1969             atom->flags2 &= ~MYFLAG_UNREACHABLE;
     1978          atom->flags |= ADDED_F_CONNECTABLE;
     1979          atom->flags2 &= ~MYFLAG_UNREACHABLE;
    19701980        }
    19711981
    1972         /* In principle, this flag specifies whether the peer groks uTP,
    1973            not whether it's currently connected over uTP. */
    1974         if (io->utp_socket)
    1975             atom->flags |= ADDED_F_UTP_FLAGS;
    1976 
    1977         if (atom->flags2 & MYFLAG_BANNED)
     1982      /* In principle, this flag specifies whether the peer groks uTP,
     1983         not whether it's currently connected over uTP. */
     1984      if (io->utp_socket)
     1985        atom->flags |= ADDED_F_UTP_FLAGS;
     1986
     1987      if (atom->flags2 & MYFLAG_BANNED)
    19781988        {
    1979             tordbg (t, "banned peer %s tried to reconnect",
    1980                     tr_atomAddrStr (atom));
     1989          tordbg (s, "banned peer %s tried to reconnect",
     1990                  tr_atomAddrStr (atom));
    19811991        }
    1982         else if (tr_peerIoIsIncoming (io)
    1983                && (getPeerCount (t) >= getMaxPeerCount (t->tor)))
    1984 
     1992      else if (tr_peerIoIsIncoming (io) && (getPeerCount (s) >= getMaxPeerCount (s->tor)))
    19851993        {
    19861994        }
    1987         else
     1995      else
    19881996        {
    1989             tr_peer * peer = atom->peer;
    1990 
    1991             if (peer) /* we already have this peer */
     1997          tr_peer * peer = atom->peer;
     1998
     1999          if (peer) /* we already have this peer */
    19922000            {
    19932001            }
    1994             else
     2002          else
    19952003            {
    1996                 peer = getPeer (t, atom);
    1997 
    1998                 if (!peer_id)
    1999                     peer->client = TR_KEY_NONE;
    2000                 else {
    2001                     char client[128];
    2002                     tr_clientForId (client, sizeof (client), peer_id);
    2003                     peer->client = tr_quark_new (client, -1);
     2004              peer = getPeer (s, atom);
     2005
     2006              if (!peer_id)
     2007                peer->client = TR_KEY_NONE;
     2008              else
     2009                {
     2010                  char client[128];
     2011                  tr_clientForId (client, sizeof (client), peer_id);
     2012                  peer->client = tr_quark_new (client, -1);
    20042013                }
    20052014
    2006                 peer->io = tr_handshakeStealIO (handshake); /* this steals its refcount too, which is
     2015              peer->io = tr_handshakeStealIO (handshake); /* this steals its refcount too, which is
    20072016                                                                balanced by our unref in peerDelete ()  */
    2008                 tr_peerIoSetParent (peer->io, &t->tor->bandwidth);
    2009                 tr_peerMsgsNew (t->tor, peer, peerCallbackFunc, t);
    2010 
    2011                 success = true;
     2017              tr_peerIoSetParent (peer->io, &s->tor->bandwidth);
     2018              tr_peerMsgsNew (s->tor, peer, peerCallbackFunc, s);
     2019
     2020              success = true;
    20122021            }
    20132022        }
    20142023    }
    20152024
    2016     if (t)
    2017         torrentUnlock (t);
    2018 
    2019     return success;
     2025  if (s != NULL)
     2026    swarmUnlock (s);
     2027
     2028  return success;
    20202029}
    20212030
    20222031void
    2023 tr_peerMgrAddIncoming (tr_peerMgr * manager,
    2024                        tr_address * addr,
    2025                        tr_port      port,
    2026                        int          socket,
     2032tr_peerMgrAddIncoming (tr_peerMgr       * manager,
     2033                       tr_address       * addr,
     2034                       tr_port            port,
     2035                       int                socket,
    20272036                       struct UTPSocket * utp_socket)
    20282037{
    2029     tr_session * session;
    2030 
    2031     managerLock (manager);
    2032 
    2033     assert (tr_isSession (manager->session));
    2034     session = manager->session;
    2035 
    2036     if (tr_sessionIsAddressBlocked (session, addr))
    2037     {
    2038         tr_logAddDebug ("Banned IP address \"%s\" tried to connect to us", tr_address_to_string (addr));
    2039         if (socket >= 0)
    2040             tr_netClose (session, socket);
    2041         else
    2042             UTP_Close (utp_socket);
    2043     }
    2044     else if (getExistingHandshake (&manager->incomingHandshakes, addr))
    2045     {
    2046         if (socket >= 0)
    2047             tr_netClose (session, socket);
    2048         else
    2049             UTP_Close (utp_socket);
    2050     }
    2051     else /* we don't have a connection to them yet... */
    2052     {
    2053         tr_peerIo *    io;
    2054         tr_handshake * handshake;
    2055 
    2056         io = tr_peerIoNewIncoming (session, &session->bandwidth, addr, port, socket, utp_socket);
    2057 
    2058         handshake = tr_handshakeNew (io,
    2059                                      session->encryptionMode,
    2060                                      myHandshakeDoneCB,
    2061                                      manager);
    2062 
    2063         tr_peerIoUnref (io); /* balanced by the implicit ref in tr_peerIoNewIncoming () */
    2064 
    2065         tr_ptrArrayInsertSorted (&manager->incomingHandshakes, handshake,
    2066                                  handshakeCompare);
    2067     }
    2068 
    2069     managerUnlock (manager);
     2038  tr_session * session;
     2039
     2040  managerLock (manager);
     2041
     2042  assert (tr_isSession (manager->session));
     2043  session = manager->session;
     2044
     2045  if (tr_sessionIsAddressBlocked (session, addr))
     2046    {
     2047      tr_logAddDebug ("Banned IP address \"%s\" tried to connect to us", tr_address_to_string (addr));
     2048      if (socket >= 0)
     2049        tr_netClose (session, socket);
     2050      else
     2051        UTP_Close (utp_socket);
     2052    }
     2053  else if (getExistingHandshake (&manager->incomingHandshakes, addr))
     2054    {
     2055      if (socket >= 0)
     2056        tr_netClose (session, socket);
     2057      else
     2058        UTP_Close (utp_socket);
     2059    }
     2060  else /* we don't have a connection to them yet... */
     2061    {
     2062      tr_peerIo *    io;
     2063      tr_handshake * handshake;
     2064
     2065      io = tr_peerIoNewIncoming (session, &session->bandwidth, addr, port, socket, utp_socket);
     2066
     2067      handshake = tr_handshakeNew (io,
     2068                                   session->encryptionMode,
     2069                                   myHandshakeDoneCB,
     2070                                   manager);
     2071
     2072      tr_peerIoUnref (io); /* balanced by the implicit ref in tr_peerIoNewIncoming () */
     2073
     2074      tr_ptrArrayInsertSorted (&manager->incomingHandshakes, handshake,
     2075                               handshakeCompare);
     2076    }
     2077
     2078  managerUnlock (manager);
    20702079}
    20712080
     
    20742083                  const tr_pex * pex, int8_t seedProbability)
    20752084{
    2076     if (tr_isPex (pex)) /* safeguard against corrupt data */
    2077     {
    2078         Torrent * t = tor->torrentPeers;
    2079         managerLock (t->manager);
    2080 
    2081         if (!tr_sessionIsAddressBlocked (t->manager->session, &pex->addr))
    2082             if (tr_address_is_valid_for_peers (&pex->addr, pex->port))
    2083                 ensureAtomExists (t, &pex->addr, pex->port, pex->flags, seedProbability, from);
    2084 
    2085         managerUnlock (t->manager);
     2085  if (tr_isPex (pex)) /* safeguard against corrupt data */
     2086    {
     2087      tr_swarm * s = tor->swarm;
     2088      managerLock (s->manager);
     2089
     2090      if (!tr_sessionIsAddressBlocked (s->manager->session, &pex->addr))
     2091        if (tr_address_is_valid_for_peers (&pex->addr, pex->port))
     2092          ensureAtomExists (s, &pex->addr, pex->port, pex->flags, seedProbability, from);
     2093
     2094      managerUnlock (s->manager);
    20862095    }
    20872096}
     
    20902099tr_peerMgrMarkAllAsSeeds (tr_torrent * tor)
    20912100{
    2092     Torrent * t = tor->torrentPeers;
    2093     const int n = tr_ptrArraySize (&t->pool);
    2094     struct peer_atom ** it = (struct peer_atom**) tr_ptrArrayBase (&t->pool);
    2095     struct peer_atom ** end = it + n;
    2096 
    2097     while (it != end)
    2098         atomSetSeed (t, *it++);
     2101  tr_swarm * s = tor->swarm;
     2102  const int n = tr_ptrArraySize (&s->pool);
     2103  struct peer_atom ** it = (struct peer_atom**) tr_ptrArrayBase (&s->pool);
     2104  struct peer_atom ** end = it + n;
     2105
     2106  while (it != end)
     2107    atomSetSeed (s, *it++);
    20992108}
    21002109
    21012110tr_pex *
    2102 tr_peerMgrCompactToPex (const void *    compact,
     2111tr_peerMgrCompactToPex (const void    * compact,
    21032112                        size_t          compactLen,
    21042113                        const uint8_t * added_f,
    21052114                        size_t          added_f_len,
    2106                         size_t *        pexCount)
    2107 {
    2108     size_t          i;
    2109     size_t          n = compactLen / 6;
    2110     const uint8_t * walk = compact;
    2111     tr_pex *        pex = tr_new0 (tr_pex, n);
    2112 
    2113     for (i = 0; i < n; ++i)
    2114     {
    2115         pex[i].addr.type = TR_AF_INET;
    2116         memcpy (&pex[i].addr.addr, walk, 4); walk += 4;
    2117         memcpy (&pex[i].port, walk, 2); walk += 2;
    2118         if (added_f && (n == added_f_len))
    2119             pex[i].flags = added_f[i];
    2120     }
    2121 
    2122     *pexCount = n;
    2123     return pex;
     2115                        size_t        * pexCount)
     2116{
     2117  size_t i;
     2118  size_t n = compactLen / 6;
     2119  const uint8_t * walk = compact;
     2120  tr_pex * pex = tr_new0 (tr_pex, n);
     2121
     2122  for (i=0; i<n; ++i)
     2123    {
     2124      pex[i].addr.type = TR_AF_INET;
     2125      memcpy (&pex[i].addr.addr, walk, 4); walk += 4;
     2126      memcpy (&pex[i].port, walk, 2); walk += 2;
     2127      if (added_f && (n == added_f_len))
     2128        pex[i].flags = added_f[i];
     2129    }
     2130
     2131  *pexCount = n;
     2132  return pex;
    21242133}
    21252134
     
    21312140                         size_t        * pexCount)
    21322141{
    2133     size_t          i;
    2134     size_t          n = compactLen / 18;
    2135     const uint8_t * walk = compact;
    2136     tr_pex *        pex = tr_new0 (tr_pex, n);
    2137 
    2138     for (i = 0; i < n; ++i)
    2139     {
    2140         pex[i].addr.type = TR_AF_INET6;
    2141         memcpy (&pex[i].addr.addr.addr6.s6_addr, walk, 16); walk += 16;
    2142         memcpy (&pex[i].port, walk, 2); walk += 2;
    2143         if (added_f && (n == added_f_len))
    2144             pex[i].flags = added_f[i];
    2145     }
    2146 
    2147     *pexCount = n;
    2148     return pex;
     2142  size_t i;
     2143  size_t n = compactLen / 18;
     2144  const uint8_t * walk = compact;
     2145  tr_pex * pex = tr_new0 (tr_pex, n);
     2146
     2147  for (i=0; i<n; ++i)
     2148    {
     2149      pex[i].addr.type = TR_AF_INET6;
     2150      memcpy (&pex[i].addr.addr.addr6.s6_addr, walk, 16); walk += 16;
     2151      memcpy (&pex[i].port, walk, 2); walk += 2;
     2152      if (added_f && (n == added_f_len))
     2153        pex[i].flags = added_f[i];
     2154    }
     2155
     2156  *pexCount = n;
     2157  return pex;
    21492158}
    21502159
    21512160tr_pex *
    2152 tr_peerMgrArrayToPex (const void * array,
    2153                       size_t       arrayLen,
     2161tr_peerMgrArrayToPex (const void  * array,
     2162                      size_t        arrayLen,
    21542163                      size_t      * pexCount)
    21552164{
    2156     size_t          i;
    2157     size_t          n = arrayLen / (sizeof (tr_address) + 2);
    2158     /*size_t          n = arrayLen / sizeof (tr_peerArrayElement);*/
    2159     const uint8_t * walk = array;
    2160     tr_pex        * pex = tr_new0 (tr_pex, n);
    2161 
    2162     for (i = 0 ; i < n ; i++) {
    2163         memcpy (&pex[i].addr, walk, sizeof (tr_address));
    2164         memcpy (&pex[i].port, walk + sizeof (tr_address), 2);
    2165         pex[i].flags = 0x00;
    2166         walk += sizeof (tr_address) + 2;
    2167     }
    2168 
    2169     *pexCount = n;
    2170     return pex;
     2165  size_t i;
     2166  size_t n = arrayLen / (sizeof (tr_address) + 2);
     2167  const uint8_t * walk = array;
     2168  tr_pex * pex = tr_new0 (tr_pex, n);
     2169
     2170  for (i=0 ; i<n ; ++i)
     2171    {
     2172      memcpy (&pex[i].addr, walk, sizeof (tr_address));
     2173      memcpy (&pex[i].port, walk + sizeof (tr_address), 2);
     2174      pex[i].flags = 0x00;
     2175      walk += sizeof (tr_address) + 2;
     2176    }
     2177
     2178  *pexCount = n;
     2179  return pex;
    21712180}
    21722181
     
    21802189  int i;
    21812190  int n;
    2182   Torrent * t = tor->torrentPeers;
     2191  tr_swarm * s = tor->swarm;
    21832192  const uint32_t byteCount = tr_torPieceCountBytes (tor, pieceIndex);
    21842193
    2185   for (i=0, n=tr_ptrArraySize(&t->peers); i!=n; ++i)
    2186     {
    2187       tr_peer * peer = tr_ptrArrayNth (&t->peers, i);
     2194  for (i=0, n=tr_ptrArraySize(&s->peers); i!=n; ++i)
     2195    {
     2196      tr_peer * peer = tr_ptrArrayNth (&s->peers, i);
    21882197
    21892198      if (tr_bitfieldHas (&peer->blame, pieceIndex))
    21902199        {
    2191           tordbg (t, "peer %s contributed to corrupt piece (%d); now has %d strikes",
     2200          tordbg (s, "peer %s contributed to corrupt piece (%d); now has %d strikes",
    21922201                  tr_atomAddrStr(peer->atom), pieceIndex, (int)peer->strikes + 1);
    2193           addStrike (t, peer);
     2202          addStrike (s, peer);
    21942203        }
    21952204    }
     
    22022211tr_pexCompare (const void * va, const void * vb)
    22032212{
    2204     const tr_pex * a = va;
    2205     const tr_pex * b = vb;
    2206     int i;
    2207 
    2208     assert (tr_isPex (a));
    2209     assert (tr_isPex (b));
    2210 
    2211     if ((i = tr_address_compare (&a->addr, &b->addr)))
    2212         return i;
    2213 
    2214     if (a->port != b->port)
    2215         return a->port < b->port ? -1 : 1;
    2216 
    2217     return 0;
     2213  int i;
     2214  const tr_pex * a = va;
     2215  const tr_pex * b = vb;
     2216
     2217  assert (tr_isPex (a));
     2218  assert (tr_isPex (b));
     2219
     2220  if ((i = tr_address_compare (&a->addr, &b->addr)))
     2221    return i;
     2222
     2223  if (a->port != b->port)
     2224    return a->port < b->port ? -1 : 1;
     2225
     2226  return 0;
    22182227}
    22192228
     
    22222231compareAtomsByUsefulness (const void * va, const void *vb)
    22232232{
    2224     const struct peer_atom * a = * (const struct peer_atom**) va;
    2225     const struct peer_atom * b = * (const struct peer_atom**) vb;
    2226 
    2227     assert (tr_isAtom (a));
    2228     assert (tr_isAtom (b));
    2229 
    2230     if (a->piece_data_time != b->piece_data_time)
    2231         return a->piece_data_time > b->piece_data_time ? -1 : 1;
    2232     if (a->fromBest != b->fromBest)
    2233         return a->fromBest < b->fromBest ? -1 : 1;
    2234     if (a->numFails != b->numFails)
    2235         return a->numFails < b->numFails ? -1 : 1;
    2236 
    2237     return 0;
     2233  const struct peer_atom * a = * (const struct peer_atom**) va;
     2234  const struct peer_atom * b = * (const struct peer_atom**) vb;
     2235
     2236  assert (tr_isAtom (a));
     2237  assert (tr_isAtom (b));
     2238
     2239  if (a->piece_data_time != b->piece_data_time)
     2240    return a->piece_data_time > b->piece_data_time ? -1 : 1;
     2241  if (a->fromBest != b->fromBest)
     2242    return a->fromBest < b->fromBest ? -1 : 1;
     2243  if (a->numFails != b->numFails)
     2244    return a->numFails < b->numFails ? -1 : 1;
     2245
     2246  return 0;
    22382247}
    22392248
     
    22412250isAtomInteresting (const tr_torrent * tor, struct peer_atom * atom)
    22422251{
    2243     if (tr_torrentIsSeed (tor) && atomIsSeed (atom))
    2244         return false;
    2245 
    2246     if (peerIsInUse (tor->torrentPeers, atom))
    2247         return true;
    2248 
    2249     if (isAtomBlocklisted (tor->session, atom))
    2250         return false;
    2251 
    2252     if (atom->flags2 & MYFLAG_BANNED)
    2253         return false;
    2254 
     2252  if (tr_torrentIsSeed (tor) && atomIsSeed (atom))
     2253    return false;
     2254
     2255  if (peerIsInUse (tor->swarm, atom))
    22552256    return true;
     2257
     2258  if (isAtomBlocklisted (tor->session, atom))
     2259    return false;
     2260
     2261  if (atom->flags2 & MYFLAG_BANNED)
     2262    return false;
     2263
     2264  return true;
    22562265}
    22572266
     
    22632272                    int            maxCount)
    22642273{
    2265     int i;
    2266     int n;
    2267     int count = 0;
    2268     int atomCount = 0;
    2269     const Torrent * t = tor->torrentPeers;
    2270     struct peer_atom ** atoms = NULL;
    2271     tr_pex * pex;
    2272     tr_pex * walk;
    2273 
    2274     assert (tr_isTorrent (tor));
    2275     assert (setme_pex != NULL);
    2276     assert (af==TR_AF_INET || af==TR_AF_INET6);
    2277     assert (list_mode==TR_PEERS_CONNECTED || list_mode==TR_PEERS_INTERESTING);
    2278 
    2279     managerLock (t->manager);
    2280 
    2281     /**
    2282     ***  build a list of atoms
    2283     **/
    2284 
    2285     if (list_mode == TR_PEERS_CONNECTED) /* connected peers only */
    2286     {
    2287         int i;
    2288         const tr_peer ** peers = (const tr_peer **) tr_ptrArrayBase (&t->peers);
    2289         atomCount = tr_ptrArraySize (&t->peers);
    2290         atoms = tr_new (struct peer_atom *, atomCount);
    2291         for (i=0; i<atomCount; ++i)
    2292             atoms[i] = peers[i]->atom;
    2293     }
    2294     else /* TR_PEERS_INTERESTING */
    2295     {
    2296         int i;
    2297         struct peer_atom ** atomBase = (struct peer_atom**) tr_ptrArrayBase (&t->pool);
    2298         n = tr_ptrArraySize (&t->pool);
    2299         atoms = tr_new (struct peer_atom *, n);
    2300         for (i=0; i<n; ++i)
    2301             if (isAtomInteresting (tor, atomBase[i]))
    2302                 atoms[atomCount++] = atomBase[i];
    2303     }
    2304 
    2305     qsort (atoms, atomCount, sizeof (struct peer_atom *), compareAtomsByUsefulness);
    2306 
    2307     /**
    2308     ***  add the first N of them into our return list
    2309     **/
    2310 
    2311     n = MIN (atomCount, maxCount);
    2312     pex = walk = tr_new0 (tr_pex, n);
    2313 
    2314     for (i=0; i<atomCount && count<n; ++i)
    2315     {
    2316         const struct peer_atom * atom = atoms[i];
    2317         if (atom->addr.type == af)
     2274  int i;
     2275  int n;
     2276  int count = 0;
     2277  int atomCount = 0;
     2278  const tr_swarm * s = tor->swarm;
     2279  struct peer_atom ** atoms = NULL;
     2280  tr_pex * pex;
     2281  tr_pex * walk;
     2282
     2283  assert (tr_isTorrent (tor));
     2284  assert (setme_pex != NULL);
     2285  assert (af==TR_AF_INET || af==TR_AF_INET6);
     2286  assert (list_mode==TR_PEERS_CONNECTED || list_mode==TR_PEERS_INTERESTING);
     2287
     2288  managerLock (s->manager);
     2289
     2290  /**
     2291  ***  build a list of atoms
     2292  **/
     2293
     2294  if (list_mode == TR_PEERS_CONNECTED) /* connected peers only */
     2295    {
     2296      int i;
     2297      const tr_peer ** peers = (const tr_peer **) tr_ptrArrayBase (&s->peers);
     2298      atomCount = tr_ptrArraySize (&s->peers);
     2299      atoms = tr_new (struct peer_atom *, atomCount);
     2300      for (i=0; i<atomCount; ++i)
     2301        atoms[i] = peers[i]->atom;
     2302    }
     2303  else /* TR_PEERS_INTERESTING */
     2304    {
     2305      int i;
     2306      struct peer_atom ** atomBase = (struct peer_atom**) tr_ptrArrayBase (&s->pool);
     2307      n = tr_ptrArraySize (&s->pool);
     2308      atoms = tr_new (struct peer_atom *, n);
     2309      for (i=0; i<n; ++i)
     2310        if (isAtomInteresting (tor, atomBase[i]))
     2311          atoms[atomCount++] = atomBase[i];
     2312    }
     2313
     2314  qsort (atoms, atomCount, sizeof (struct peer_atom *), compareAtomsByUsefulness);
     2315
     2316  /**
     2317  ***  add the first N of them into our return list
     2318  **/
     2319
     2320  n = MIN (atomCount, maxCount);
     2321  pex = walk = tr_new0 (tr_pex, n);
     2322
     2323  for (i=0; i<atomCount && count<n; ++i)
     2324    {
     2325      const struct peer_atom * atom = atoms[i];
     2326      if (atom->addr.type == af)
    23182327        {
    2319             assert (tr_address_is_valid (&atom->addr));
    2320             walk->addr = atom->addr;
    2321             walk->port = atom->port;
    2322             walk->flags = atom->flags;
    2323             ++count;
    2324             ++walk;
     2328          assert (tr_address_is_valid (&atom->addr));
     2329          walk->addr = atom->addr;
     2330          walk->port = atom->port;
     2331          walk->flags = atom->flags;
     2332          ++count;
     2333          ++walk;
    23252334        }
    23262335    }
    23272336
    2328     qsort (pex, count, sizeof (tr_pex), tr_pexCompare);
    2329 
    2330     assert ((walk - pex) == count);
    2331     *setme_pex = pex;
    2332 
    2333     /* cleanup */
    2334     tr_free (atoms);
    2335     managerUnlock (t->manager);
    2336     return count;
     2337  qsort (pex, count, sizeof (tr_pex), tr_pexCompare);
     2338
     2339  assert ((walk - pex) == count);
     2340  *setme_pex = pex;
     2341
     2342  /* cleanup */
     2343  tr_free (atoms);
     2344  managerUnlock (s->manager);
     2345  return count;
    23372346}
    23382347
     
    23452354createTimer (tr_session * session, int msec, void (*callback)(int, short, void *), void * cbdata)
    23462355{
    2347     struct event * timer = evtimer_new (session->event_base, callback, cbdata);
    2348     tr_timerAddMsec (timer, msec);
    2349     return timer;
     2356  struct event * timer = evtimer_new (session->event_base, callback, cbdata);
     2357  tr_timerAddMsec (timer, msec);
     2358  return timer;
    23502359}
    23512360
     
    23532362ensureMgrTimersExist (struct tr_peerMgr * m)
    23542363{
    2355     if (m->atomTimer == NULL)
    2356         m->atomTimer = createTimer (m->session, ATOM_PERIOD_MSEC, atomPulse, m);
    2357 
    2358     if (m->bandwidthTimer == NULL)
    2359         m->bandwidthTimer = createTimer (m->session, BANDWIDTH_PERIOD_MSEC, bandwidthPulse, m);
    2360 
    2361     if (m->rechokeTimer == NULL)
    2362         m->rechokeTimer = createTimer (m->session, RECHOKE_PERIOD_MSEC, rechokePulse, m);
    2363 
    2364     if (m->refillUpkeepTimer == NULL)
    2365         m->refillUpkeepTimer = createTimer (m->session, REFILL_UPKEEP_PERIOD_MSEC, refillUpkeep, m);
     2364  if (m->atomTimer == NULL)
     2365    m->atomTimer = createTimer (m->session, ATOM_PERIOD_MSEC, atomPulse, m);
     2366
     2367  if (m->bandwidthTimer == NULL)
     2368    m->bandwidthTimer = createTimer (m->session, BANDWIDTH_PERIOD_MSEC, bandwidthPulse, m);
     2369
     2370  if (m->rechokeTimer == NULL)
     2371    m->rechokeTimer = createTimer (m->session, RECHOKE_PERIOD_MSEC, rechokePulse, m);
     2372
     2373  if (m->refillUpkeepTimer == NULL)
     2374    m->refillUpkeepTimer = createTimer (m->session, REFILL_UPKEEP_PERIOD_MSEC, refillUpkeep, m);
    23662375}
    23672376
     
    23692378tr_peerMgrStartTorrent (tr_torrent * tor)
    23702379{
    2371     Torrent * t = tor->torrentPeers;
    2372 
    2373     assert (tr_isTorrent (tor));
    2374     assert (tr_torrentIsLocked (tor));
    2375 
    2376     ensureMgrTimersExist (t->manager);
    2377 
    2378     t->isRunning = true;
    2379     t->maxPeers = t->tor->maxConnectedPeers;
    2380     t->pieceSortState = PIECES_UNSORTED;
    2381 
    2382     rechokePulse (0, 0, t->manager);
    2383 }
    2384 
    2385 static void
    2386 stopTorrent (Torrent * t)
    2387 {
    2388     tr_peer * peer;
    2389 
    2390     t->isRunning = false;
    2391 
    2392     replicationFree (t);
    2393     invalidatePieceSorting (t);
    2394 
    2395     /* disconnect the peers. */
    2396     while ((peer = tr_ptrArrayPop (&t->peers)))
    2397         peerDelete (t, peer);
    2398 
    2399     /* disconnect the handshakes. handshakeAbort calls handshakeDoneCB (),
    2400      * which removes the handshake from t->outgoingHandshakes... */
    2401     while (!tr_ptrArrayEmpty (&t->outgoingHandshakes))
    2402         tr_handshakeAbort (tr_ptrArrayNth (&t->outgoingHandshakes, 0));
     2380  tr_swarm * s;
     2381
     2382  assert (tr_isTorrent (tor));
     2383  assert (tr_torrentIsLocked (tor));
     2384
     2385  s = tor->swarm;
     2386  ensureMgrTimersExist (s->manager);
     2387
     2388  s->isRunning = true;
     2389  s->maxPeers = tor->maxConnectedPeers;
     2390  s->pieceSortState = PIECES_UNSORTED;
     2391
     2392  rechokePulse (0, 0, s->manager);
     2393}
     2394
     2395static void
     2396stopSwarm (tr_swarm * swarm)
     2397{
     2398  tr_peer * peer;
     2399
     2400  swarm->isRunning = false;
     2401
     2402  replicationFree (swarm);
     2403  invalidatePieceSorting (swarm);
     2404
     2405  /* disconnect the peers. */
     2406  while ((peer = tr_ptrArrayPop (&swarm->peers)))
     2407    peerDelete (swarm, peer);
     2408
     2409  /* disconnect the handshakes. handshakeAbort calls handshakeDoneCB (),
     2410   * which removes the handshake from t->outgoingHandshakes... */
     2411  while (!tr_ptrArrayEmpty (&swarm->outgoingHandshakes))
     2412    tr_handshakeAbort (tr_ptrArrayNth (&swarm->outgoingHandshakes, 0));
    24032413}
    24042414
     
    24062416tr_peerMgrStopTorrent (tr_torrent * tor)
    24072417{
    2408     assert (tr_isTorrent (tor));
    2409     assert (tr_torrentIsLocked (tor));
    2410 
    2411     stopTorrent (tor->torrentPeers);
     2418  assert (tr_isTorrent (tor));
     2419  assert (tr_torrentIsLocked (tor));
     2420
     2421  stopSwarm (tor->swarm);
    24122422}
    24132423
     
    24152425tr_peerMgrAddTorrent (tr_peerMgr * manager, tr_torrent * tor)
    24162426{
    2417     assert (tr_isTorrent (tor));
    2418     assert (tr_torrentIsLocked (tor));
    2419     assert (tor->torrentPeers == NULL);
    2420 
    2421     tor->torrentPeers = torrentNew (manager, tor);
     2427  assert (tr_isTorrent (tor));
     2428  assert (tr_torrentIsLocked (tor));
     2429  assert (tor->swarm == NULL);
     2430
     2431  tor->swarm = swarmNew (manager, tor);
    24222432}
    24232433
     
    24252435tr_peerMgrRemoveTorrent (tr_torrent * tor)
    24262436{
    2427     assert (tr_isTorrent (tor));
    2428     assert (tr_torrentIsLocked (tor));
    2429 
    2430     stopTorrent (tor->torrentPeers);
    2431     torrentFree (tor->torrentPeers);
     2437  assert (tr_isTorrent (tor));
     2438  assert (tr_torrentIsLocked (tor));
     2439
     2440  stopSwarm (tor->swarm);
     2441  swarmFree (tor->swarm);
    24322442}
    24332443
     
    24352445tr_peerUpdateProgress (tr_torrent * tor, tr_peer * peer)
    24362446{
    2437     const tr_bitfield * have = &peer->have;
    2438 
    2439     if (tr_bitfieldHasAll (have))
    2440     {
    2441         peer->progress = 1.0;
    2442     }
    2443     else if (tr_bitfieldHasNone (have))
    2444     {
    2445         peer->progress = 0.0;
    2446     }
    2447     else
    2448     {
    2449         const float true_count = tr_bitfieldCountTrueBits (have);
    2450 
    2451         if (tr_torrentHasMetadata (tor))
     2447  const tr_bitfield * have = &peer->have;
     2448
     2449  if (tr_bitfieldHasAll (have))
     2450    {
     2451      peer->progress = 1.0;
     2452    }
     2453  else if (tr_bitfieldHasNone (have))
     2454    {
     2455      peer->progress = 0.0;
     2456    }
     2457  else
     2458    {
     2459      const float true_count = tr_bitfieldCountTrueBits (have);
     2460
     2461      if (tr_torrentHasMetadata (tor))
    24522462        {
    2453             peer->progress = true_count / tor->info.pieceCount;
     2463          peer->progress = true_count / tor->info.pieceCount;
    24542464        }
    2455         else /* without pieceCount, this result is only a best guess... */
     2465      else /* without pieceCount, this result is only a best guess... */
    24562466        {
    2457             peer->progress = true_count / (have->bit_count + 1);
     2467          peer->progress = true_count / (have->bit_count + 1);
    24582468        }
    24592469    }
    24602470
    2461     /* clamp the progress range */
    2462     if (peer->progress < 0.0)
    2463         peer->progress = 0.0;
    2464     if (peer->progress > 1.0)
    2465         peer->progress = 1.0;
    2466 
    2467     if (peer->atom && (peer->progress >= 1.0))
    2468         atomSetSeed (tor->torrentPeers, peer->atom);
     2471  /* clamp the progress range */
     2472  if (peer->progress < 0.0)
     2473    peer->progress = 0.0;
     2474  if (peer->progress > 1.0)
     2475    peer->progress = 1.0;
     2476
     2477  if (peer->atom && (peer->progress >= 1.0))
     2478    atomSetSeed (tor->swarm, peer->atom);
    24692479}
    24702480
     
    24722482tr_peerMgrOnTorrentGotMetainfo (tr_torrent * tor)
    24732483{
    2474     int i;
    2475     int peerCount;
    2476     tr_peer ** peers;
    2477 
    2478     /* the webseed list may have changed... */
    2479     rebuildWebseedArray (tor->torrentPeers, tor);
    2480 
    2481     /* some peer_msgs' progress fields may not be accurate if we
    2482        didn't have the metadata before now... so refresh them all... */
    2483     peerCount = tr_ptrArraySize (&tor->torrentPeers->peers);
    2484     peers = (tr_peer**) tr_ptrArrayBase (&tor->torrentPeers->peers);
    2485     for (i=0; i<peerCount; ++i)
    2486         tr_peerUpdateProgress (tor, peers[i]);
    2487 
     2484  int i;
     2485  int peerCount;
     2486  tr_peer ** peers;
     2487
     2488  /* the webseed list may have changed... */
     2489  rebuildWebseedArray (tor->swarm, tor);
     2490
     2491  /* some peer_msgs' progress fields may not be accurate if we
     2492     didn't have the metadata before now... so refresh them all... */
     2493  peerCount = tr_ptrArraySize (&tor->swarm->peers);
     2494  peers = (tr_peer**) tr_ptrArrayBase (&tor->swarm->peers);
     2495  for (i=0; i<peerCount; ++i)
     2496    tr_peerUpdateProgress (tor, peers[i]);
    24882497}
    24892498
     
    25022511    {
    25032512      tr_piece_index_t i;
    2504       const int peerCount = tr_ptrArraySize (&tor->torrentPeers->peers);
    2505       const tr_peer ** peers = (const tr_peer**) tr_ptrArrayBase (&tor->torrentPeers->peers);
     2513      const int peerCount = tr_ptrArraySize (&tor->swarm->peers);
     2514      const tr_peer ** peers = (const tr_peer**) tr_ptrArrayBase (&tor->swarm->peers);
    25062515      const float interval = tor->info.pieceCount / (float)tabCount;
    25072516      const bool isSeed = tr_cpGetStatus (&tor->completion) == TR_SEED;
     
    25422551tr_peerMgrGetDesiredAvailable (const tr_torrent * tor)
    25432552{
    2544     size_t i;
    2545     size_t n;
    2546     uint64_t desiredAvailable;
    2547     const Torrent * t = tor->torrentPeers;
    2548 
    2549     /* common shortcuts... */
    2550 
    2551     if (tr_torrentIsSeed (t->tor))
    2552         return 0;
    2553 
    2554     if (!tr_torrentHasMetadata (tor))
    2555         return 0;
    2556 
    2557     n = tr_ptrArraySize (&t->peers);
    2558     if (n == 0)
    2559         return 0;
    2560     else {
    2561         const tr_peer ** peers = (const tr_peer**) tr_ptrArrayBase (&t->peers);
    2562         for (i=0; i<n; ++i)
    2563             if (peers[i]->atom && atomIsSeed (peers[i]->atom))
    2564                 return tr_cpLeftUntilDone (&tor->completion);
    2565     }
    2566 
    2567     if (!t->pieceReplication || !t->pieceReplicationSize)
    2568         return 0;
    2569 
    2570     /* do it the hard way */
    2571 
    2572     desiredAvailable = 0;
    2573     for (i=0, n=MIN (tor->info.pieceCount, t->pieceReplicationSize); i<n; ++i)
    2574         if (!tor->info.pieces[i].dnd && (t->pieceReplication[i] > 0))
    2575             desiredAvailable += tr_cpMissingBytesInPiece (&t->tor->completion, i);
    2576 
    2577     assert (desiredAvailable <= tor->info.totalSize);
    2578     return desiredAvailable;
     2553  size_t i;
     2554  size_t n;
     2555  uint64_t desiredAvailable;
     2556  const tr_swarm * s = tor->swarm;
     2557
     2558  /* common shortcuts... */
     2559
     2560  if (tr_torrentIsSeed (s->tor))
     2561    return 0;
     2562
     2563  if (!tr_torrentHasMetadata (tor))
     2564    return 0;
     2565
     2566  n = tr_ptrArraySize (&s->peers);
     2567  if (n == 0)
     2568    {
     2569      return 0;
     2570    }
     2571  else
     2572    {
     2573      const tr_peer ** peers = (const tr_peer**) tr_ptrArrayBase (&s->peers);
     2574      for (i=0; i<n; ++i)
     2575        if (peers[i]->atom && atomIsSeed (peers[i]->atom))
     2576          return tr_cpLeftUntilDone (&tor->completion);
     2577    }
     2578
     2579  if (!s->pieceReplication || !s->pieceReplicationSize)
     2580    return 0;
     2581
     2582  /* do it the hard way */
     2583
     2584  desiredAvailable = 0;
     2585  for (i=0, n=MIN (tor->info.pieceCount, s->pieceReplicationSize); i<n; ++i)
     2586    if (!tor->info.pieces[i].dnd && (s->pieceReplication[i] > 0))
     2587      desiredAvailable += tr_cpMissingBytesInPiece (&s->tor->completion, i);
     2588
     2589  assert (desiredAvailable <= tor->info.totalSize);
     2590  return desiredAvailable;
    25792591}
    25802592
     
    25892601  int i;
    25902602  int size;
    2591   Torrent * t;
     2603  tr_swarm * s;
    25922604  const tr_peer ** peers;
    25932605
     
    25992611  *setmeWebseedsSendingToUs  = 0;
    26002612
    2601   t = tor->torrentPeers;
    2602   size = tr_ptrArraySize (&t->peers);
    2603   peers = (const tr_peer **) tr_ptrArrayBase (&t->peers);
     2613  s = tor->swarm;
     2614  size = tr_ptrArraySize (&s->peers);
     2615  peers = (const tr_peer **) tr_ptrArrayBase (&s->peers);
    26042616
    26052617  for (i=0; i<TR_PEER_FROM__MAX; ++i)
     
    26252637    }
    26262638
    2627   *setmeWebseedsSendingToUs = countActiveWebseeds (t);
     2639  *setmeWebseedsSendingToUs = countActiveWebseeds (s);
    26282640}
    26292641
     
    26332645  unsigned int i;
    26342646  unsigned int webseedCount;
    2635   const Torrent * t;
     2647  const tr_swarm * s;
    26362648  const tr_webseed ** webseeds;
    26372649  double * ret = NULL;
     
    26402652  assert (tr_isTorrent (tor));
    26412653
    2642   t = tor->torrentPeers;
    2643   webseedCount = tr_ptrArraySize (&t->webseeds);
    2644   webseeds = (const tr_webseed**) tr_ptrArrayBase (&t->webseeds);
     2654  s = tor->swarm;
     2655  webseedCount = tr_ptrArraySize (&s->webseeds);
     2656  webseeds = (const tr_webseed**) tr_ptrArrayBase (&s->webseeds);
    26452657  ret = tr_new0 (double, webseedCount);
    26462658
    2647   assert (t->manager != NULL);
     2659  assert (s->manager != NULL);
    26482660  assert (webseedCount == tor->info.webseedCount);
    26492661
     
    26722684  int size = 0;
    26732685  tr_peer_stat * ret;
    2674   const Torrent * t;
     2686  const tr_swarm * s;
    26752687  const tr_peer ** peers;
    26762688  const time_t now = tr_time ();
     
    26782690
    26792691  assert (tr_isTorrent (tor));
    2680   assert (tor->torrentPeers->manager != NULL);
    2681 
    2682   t = tor->torrentPeers;
    2683   peers = (const tr_peer**) tr_ptrArrayBase (&t->peers);
    2684   size = tr_ptrArraySize (&t->peers);
     2692  assert (tor->swarm->manager != NULL);
     2693
     2694  s = tor->swarm;
     2695  peers = (const tr_peer**) tr_ptrArrayBase (&s->peers);
     2696  size = tr_ptrArraySize (&s->peers);
    26852697  ret = tr_new0 (tr_peer_stat, size);
    26862698
     
    27202732      pch = stat->flagStr;
    27212733      if (stat->isUTP) *pch++ = 'T';
    2722       if (t->optimistic == peer) *pch++ = 'O';
     2734      if (s->optimistic == peer) *pch++ = 'O';
    27232735      if (stat->isDownloadingFrom) *pch++ = 'D';
    27242736      else if (stat->clientIsInterested) *pch++ = 'd';
     
    27462758tr_peerMgrClearInterest (tr_torrent * tor)
    27472759{
    2748     int i;
    2749     Torrent * t = tor->torrentPeers;
    2750     const int peerCount = tr_ptrArraySize (&t->peers);
    2751 
    2752     assert (tr_isTorrent (tor));
    2753     assert (tr_torrentIsLocked (tor));
    2754 
    2755     for (i=0; i<peerCount; ++i)
    2756     {
    2757         const tr_peer * peer = tr_ptrArrayNth (&t->peers, i);
    2758         tr_peerMsgsSetInterested (peer->msgs, false);
     2760  int i;
     2761  tr_swarm * s = tor->swarm;
     2762  const int peerCount = tr_ptrArraySize (&s->peers);
     2763
     2764  assert (tr_isTorrent (tor));
     2765  assert (tr_torrentIsLocked (tor));
     2766
     2767  for (i=0; i<peerCount; ++i)
     2768    {
     2769      const tr_peer * peer = tr_ptrArrayNth (&s->peers, i);
     2770      tr_peerMsgsSetInterested (peer->msgs, false);
    27592771    }
    27602772}
     
    27842796typedef enum
    27852797{
    2786     RECHOKE_STATE_GOOD,
    2787     RECHOKE_STATE_UNTESTED,
    2788     RECHOKE_STATE_BAD
     2798  RECHOKE_STATE_GOOD,
     2799  RECHOKE_STATE_UNTESTED,
     2800  RECHOKE_STATE_BAD
    27892801}
    27902802tr_rechoke_state;
     
    27922804struct tr_rechoke_info
    27932805{
    2794     tr_peer * peer;
    2795     int salt;
    2796     int rechoke_state;
     2806  tr_peer * peer;
     2807  int salt;
     2808  int rechoke_state;
    27972809};
    27982810
     
    28002812compare_rechoke_info (const void * va, const void * vb)
    28012813{
    2802     const struct tr_rechoke_info * a = va;
    2803     const struct tr_rechoke_info * b = vb;
    2804 
    2805     if (a->rechoke_state != b->rechoke_state)
    2806         return a->rechoke_state - b->rechoke_state;
    2807 
    2808     return a->salt - b->salt;
     2814  const struct tr_rechoke_info * a = va;
     2815  const struct tr_rechoke_info * b = vb;
     2816
     2817  if (a->rechoke_state != b->rechoke_state)
     2818    return a->rechoke_state - b->rechoke_state;
     2819
     2820  return a->salt - b->salt;
    28092821}
    28102822
    28112823/* determines who we send "interested" messages to */
    28122824static void
    2813 rechokeDownloads (Torrent * t)
    2814 {
    2815     int i;
    2816     int maxPeers = 0;
    2817     int rechoke_count = 0;
    2818     struct tr_rechoke_info * rechoke = NULL;
    2819     const int MIN_INTERESTING_PEERS = 5;
    2820     const int peerCount = tr_ptrArraySize (&t->peers);
    2821     const time_t now = tr_time ();
    2822 
    2823     /* some cases where this function isn't necessary */
    2824     if (tr_torrentIsSeed (t->tor))
    2825         return;
    2826     if (!tr_torrentIsPieceTransferAllowed (t->tor, TR_PEER_TO_CLIENT))
    2827         return;
    2828 
    2829     /* decide HOW MANY peers to be interested in */
    2830     {
    2831         int blocks = 0;
    2832         int cancels = 0;
    2833         time_t timeSinceCancel;
    2834 
    2835         /* Count up how many blocks & cancels each peer has.
    2836          *
    2837          * There are two situations where we send out cancels --
    2838          *
    2839          * 1. We've got unresponsive peers, which is handled by deciding
    2840          *    -which- peers to be interested in.
    2841          *
    2842          * 2. We've hit our bandwidth cap, which is handled by deciding
    2843          *    -how many- peers to be interested in.
    2844          *
    2845          * We're working on 2. here, so we need to ignore unresponsive
    2846          * peers in our calculations lest they confuse Transmission into
    2847          * thinking it's hit its bandwidth cap.
    2848          */
    2849         for (i=0; i<peerCount; ++i)
     2825rechokeDownloads (tr_swarm * s)
     2826{
     2827  int i;
     2828  int maxPeers = 0;
     2829  int rechoke_count = 0;
     2830  struct tr_rechoke_info * rechoke = NULL;
     2831  const int MIN_INTERESTING_PEERS = 5;
     2832  const int peerCount = tr_ptrArraySize (&s->peers);
     2833  const time_t now = tr_time ();
     2834
     2835  /* some cases where this function isn't necessary */
     2836  if (tr_torrentIsSeed (s->tor))
     2837    return;
     2838  if (!tr_torrentIsPieceTransferAllowed (s->tor, TR_PEER_TO_CLIENT))
     2839    return;
     2840
     2841  /* decide HOW MANY peers to be interested in */
     2842  {
     2843    int blocks = 0;
     2844    int cancels = 0;
     2845    time_t timeSinceCancel;
     2846
     2847    /* Count up how many blocks & cancels each peer has.
     2848     *
     2849     * There are two situations where we send out cancels --
     2850     *
     2851     * 1. We've got unresponsive peers, which is handled by deciding
     2852     *    -which- peers to be interested in.
     2853     *
     2854     * 2. We've hit our bandwidth cap, which is handled by deciding
     2855     *    -how many- peers to be interested in.
     2856     *
     2857     * We're working on 2. here, so we need to ignore unresponsive
     2858     * peers in our calculations lest they confuse Transmission into
     2859     * thinking it's hit its bandwidth cap.
     2860     */
     2861    for (i=0; i<peerCount; ++i)
     2862      {
     2863        const tr_peer * peer = tr_ptrArrayNth (&s->peers, i);
     2864        const int b = tr_historyGet (&peer->blocksSentToClient, now, CANCEL_HISTORY_SEC);
     2865        const int c = tr_historyGet (&peer->cancelsSentToPeer, now, CANCEL_HISTORY_SEC);
     2866
     2867        if (b == 0) /* ignore unresponsive peers, as described above */
     2868          continue;
     2869
     2870        blocks += b;
     2871        cancels += c;
     2872      }
     2873
     2874    if (cancels > 0)
     2875      {
     2876        /* cancelRate: of the block requests we've recently made, the percentage we cancelled.
     2877         * higher values indicate more congestion. */
     2878        const double cancelRate = cancels / (double)(cancels + blocks);
     2879        const double mult = 1 - MIN (cancelRate, 0.5);
     2880        maxPeers = s->interestedCount * mult;
     2881        tordbg (s, "cancel rate is %.3f -- reducing the "
     2882                   "number of peers we're interested in by %.0f percent",
     2883                   cancelRate, mult * 100);
     2884        s->lastCancel = now;
     2885      }
     2886
     2887    timeSinceCancel = now - s->lastCancel;
     2888    if (timeSinceCancel)
     2889      {
     2890        const int maxIncrease = 15;
     2891        const time_t maxHistory = 2 * CANCEL_HISTORY_SEC;
     2892        const double mult = MIN (timeSinceCancel, maxHistory) / (double) maxHistory;
     2893        const int inc = maxIncrease * mult;
     2894        maxPeers = s->maxPeers + inc;
     2895        tordbg (s, "time since last cancel is %li -- increasing the "
     2896                   "number of peers we're interested in by %d",
     2897                   timeSinceCancel, inc);
     2898      }
     2899  }
     2900
     2901  /* don't let the previous section's number tweaking go too far... */
     2902  if (maxPeers < MIN_INTERESTING_PEERS)
     2903    maxPeers = MIN_INTERESTING_PEERS;
     2904  if (maxPeers > s->tor->maxConnectedPeers)
     2905    maxPeers = s->tor->maxConnectedPeers;
     2906
     2907  s->maxPeers = maxPeers;
     2908
     2909  if (peerCount > 0)
     2910    {
     2911      bool * piece_is_interesting;
     2912      const tr_torrent * const tor = s->tor;
     2913      const int n = tor->info.pieceCount;
     2914
     2915      /* build a bitfield of interesting pieces... */
     2916      piece_is_interesting = tr_new (bool, n);
     2917      for (i=0; i<n; i++)
     2918        piece_is_interesting[i] = !tor->info.pieces[i].dnd && !tr_cpPieceIsComplete (&tor->completion, i);
     2919
     2920      /* decide WHICH peers to be interested in (based on their cancel-to-block ratio) */
     2921      for (i=0; i<peerCount; ++i)
    28502922        {
    2851             const tr_peer * peer = tr_ptrArrayNth (&t->peers, i);
    2852             const int b = tr_historyGet (&peer->blocksSentToClient, now, CANCEL_HISTORY_SEC);
    2853             const int c = tr_historyGet (&peer->cancelsSentToPeer, now, CANCEL_HISTORY_SEC);
    2854 
    2855             if (b == 0) /* ignore unresponsive peers, as described above */
    2856                 continue;
    2857 
    2858             blocks += b;
    2859             cancels += c;
     2923          tr_peer * peer = tr_ptrArrayNth (&s->peers, i);
     2924
     2925          if (!isPeerInteresting (s->tor, piece_is_interesting, peer))
     2926            {
     2927              tr_peerMsgsSetInterested (peer->msgs, false);
     2928            }
     2929          else
     2930            {
     2931              tr_rechoke_state rechoke_state;
     2932              const int blocks = tr_historyGet (&peer->blocksSentToClient, now, CANCEL_HISTORY_SEC);
     2933              const int cancels = tr_historyGet (&peer->cancelsSentToPeer, now, CANCEL_HISTORY_SEC);
     2934
     2935              if (!blocks && !cancels)
     2936                rechoke_state = RECHOKE_STATE_UNTESTED;
     2937              else if (!cancels)
     2938                rechoke_state = RECHOKE_STATE_GOOD;
     2939              else if (!blocks)
     2940                rechoke_state = RECHOKE_STATE_BAD;
     2941              else if ((cancels * 10) < blocks)
     2942                rechoke_state = RECHOKE_STATE_GOOD;
     2943              else
     2944                rechoke_state = RECHOKE_STATE_BAD;
     2945
     2946              if (rechoke == NULL)
     2947                rechoke = tr_new (struct tr_rechoke_info, peerCount);
     2948
     2949              rechoke[rechoke_count].peer = peer;
     2950              rechoke[rechoke_count].rechoke_state = rechoke_state;
     2951              rechoke[rechoke_count].salt = tr_cryptoWeakRandInt (INT_MAX);
     2952              rechoke_count++;
     2953            }
     2954
    28602955        }
    28612956
    2862         if (cancels > 0)
    2863         {
    2864             /* cancelRate: of the block requests we've recently made, the percentage we cancelled.
    2865              * higher values indicate more congestion. */
    2866             const double cancelRate = cancels / (double)(cancels + blocks);
    2867             const double mult = 1 - MIN (cancelRate, 0.5);
    2868             maxPeers = t->interestedCount * mult;
    2869             tordbg (t, "cancel rate is %.3f -- reducing the "
    2870                        "number of peers we're interested in by %.0f percent",
    2871                        cancelRate, mult * 100);
    2872             t->lastCancel = now;
    2873         }
    2874 
    2875         timeSinceCancel = now - t->lastCancel;
    2876         if (timeSinceCancel)
    2877         {
    2878             const int maxIncrease = 15;
    2879             const time_t maxHistory = 2 * CANCEL_HISTORY_SEC;
    2880             const double mult = MIN (timeSinceCancel, maxHistory) / (double) maxHistory;
    2881             const int inc = maxIncrease * mult;
    2882             maxPeers = t->maxPeers + inc;
    2883             tordbg (t, "time since last cancel is %li -- increasing the "
    2884                        "number of peers we're interested in by %d",
    2885                        timeSinceCancel, inc);
    2886         }
    2887     }
    2888 
    2889     /* don't let the previous section's number tweaking go too far... */
    2890     if (maxPeers < MIN_INTERESTING_PEERS)
    2891         maxPeers = MIN_INTERESTING_PEERS;
    2892     if (maxPeers > t->tor->maxConnectedPeers)
    2893         maxPeers = t->tor->maxConnectedPeers;
    2894 
    2895     t->maxPeers = maxPeers;
    2896 
    2897     if (peerCount > 0)
    2898     {
    2899         bool * piece_is_interesting;
    2900         const tr_torrent * const tor = t->tor;
    2901         const int n = tor->info.pieceCount;
    2902 
    2903         /* build a bitfield of interesting pieces... */
    2904         piece_is_interesting = tr_new (bool, n);
    2905         for (i=0; i<n; i++)
    2906             piece_is_interesting[i] = !tor->info.pieces[i].dnd && !tr_cpPieceIsComplete (&tor->completion, i);
    2907 
    2908         /* decide WHICH peers to be interested in (based on their cancel-to-block ratio) */
    2909         for (i=0; i<peerCount; ++i)
    2910         {
    2911             tr_peer * peer = tr_ptrArrayNth (&t->peers, i);
    2912 
    2913             if (!isPeerInteresting (t->tor, piece_is_interesting, peer))
    2914             {
    2915                 tr_peerMsgsSetInterested (peer->msgs, false);
    2916             }
    2917             else
    2918             {
    2919                 tr_rechoke_state rechoke_state;
    2920                 const int blocks = tr_historyGet (&peer->blocksSentToClient, now, CANCEL_HISTORY_SEC);
    2921                 const int cancels = tr_historyGet (&peer->cancelsSentToPeer, now, CANCEL_HISTORY_SEC);
    2922 
    2923                 if (!blocks && !cancels)
    2924                     rechoke_state = RECHOKE_STATE_UNTESTED;
    2925                 else if (!cancels)
    2926                     rechoke_state = RECHOKE_STATE_GOOD;
    2927                 else if (!blocks)
    2928                     rechoke_state = RECHOKE_STATE_BAD;
    2929                 else if ((cancels * 10) < blocks)
    2930                     rechoke_state = RECHOKE_STATE_GOOD;
    2931                 else
    2932                     rechoke_state = RECHOKE_STATE_BAD;
    2933 
    2934                 if (rechoke == NULL)
    2935                     rechoke = tr_new (struct tr_rechoke_info, peerCount);
    2936 
    2937                  rechoke[rechoke_count].peer = peer;
    2938                  rechoke[rechoke_count].rechoke_state = rechoke_state;
    2939                  rechoke[rechoke_count].salt = tr_cryptoWeakRandInt (INT_MAX);
    2940                  rechoke_count++;
    2941             }
    2942 
    2943         }
    2944 
    2945         tr_free (piece_is_interesting);
    2946     }
    2947 
    2948     /* now that we know which & how many peers to be interested in... update the peer interest */
    2949     qsort (rechoke, rechoke_count, sizeof (struct tr_rechoke_info), compare_rechoke_info);
    2950     t->interestedCount = MIN (maxPeers, rechoke_count);
    2951     for (i=0; i<rechoke_count; ++i)
    2952         tr_peerMsgsSetInterested (rechoke[i].peer->msgs, i<t->interestedCount);
    2953 
    2954     /* cleanup */
    2955     tr_free (rechoke);
     2957      tr_free (piece_is_interesting);
     2958    }
     2959
     2960  /* now that we know which & how many peers to be interested in... update the peer interest */
     2961  qsort (rechoke, rechoke_count, sizeof (struct tr_rechoke_info), compare_rechoke_info);
     2962  s->interestedCount = MIN (maxPeers, rechoke_count);
     2963  for (i=0; i<rechoke_count; ++i)
     2964    tr_peerMsgsSetInterested (rechoke[i].peer->msgs, i<s->interestedCount);
     2965
     2966  /* cleanup */
     2967  tr_free (rechoke);
    29562968}
    29572969
     
    29622974struct ChokeData
    29632975{
    2964     bool            isInterested;
    2965     bool            wasChoked;
    2966     bool            isChoked;
    2967     int             rate;
    2968     int             salt;
    2969     tr_peer *      peer;
     2976  bool      isInterested;
     2977  bool      wasChoked;
     2978  bool      isChoked;
     2979  int       rate;
     2980  int       salt;
     2981  tr_peer * peer;
    29702982};
    29712983
     
    29732985compareChoke (const void * va, const void * vb)
    29742986{
    2975     const struct ChokeData * a = va;
    2976     const struct ChokeData * b = vb;
    2977 
    2978     if (a->rate != b->rate) /* prefer higher overall speeds */
    2979         return a->rate > b->rate ? -1 : 1;
    2980 
    2981     if (a->wasChoked != b->wasChoked) /* prefer unchoked */
    2982         return a->wasChoked ? 1 : -1;
    2983 
    2984     if (a->salt != b->salt) /* random order */
    2985         return a->salt - b->salt;
    2986 
    2987     return 0;
     2987  const struct ChokeData * a = va;
     2988  const struct ChokeData * b = vb;
     2989
     2990  if (a->rate != b->rate) /* prefer higher overall speeds */
     2991    return a->rate > b->rate ? -1 : 1;
     2992
     2993  if (a->wasChoked != b->wasChoked) /* prefer unchoked */
     2994    return a->wasChoked ? 1 : -1;
     2995
     2996  if (a->salt != b->salt) /* random order */
     2997    return a->salt - b->salt;
     2998
     2999  return 0;
    29883000}
    29893001
     
    29923004isNew (const tr_peer * peer)
    29933005{
    2994     return peer && peer->io && tr_peerIoGetAge (peer->io) < 45;
     3006  return peer && peer->io && tr_peerIoGetAge (peer->io) < 45;
    29953007}
    29963008
     
    29993011getRate (const tr_torrent * tor, struct peer_atom * atom, uint64_t now)
    30003012{
    3001     unsigned int Bps;
    3002 
    3003     if (tr_torrentIsSeed (tor))
    3004         Bps = tr_peerGetPieceSpeed_Bps (atom->peer, now, TR_CLIENT_TO_PEER);
    3005 
    3006     /* downloading a private torrent... take upload speed into account
    3007      * because there may only be a small window of opportunity to share */
    3008     else if (tr_torrentIsPrivate (tor))
    3009         Bps = tr_peerGetPieceSpeed_Bps (atom->peer, now, TR_PEER_TO_CLIENT)
    3010             + tr_peerGetPieceSpeed_Bps (atom->peer, now, TR_CLIENT_TO_PEER);
    3011 
    3012     /* downloading a public torrent */
    3013     else
    3014         Bps = tr_peerGetPieceSpeed_Bps (atom->peer, now, TR_PEER_TO_CLIENT);
    3015 
    3016     /* convert it to bytes per second */
    3017     return Bps;
     3013  unsigned int Bps;
     3014
     3015  if (tr_torrentIsSeed (tor))
     3016    Bps = tr_peerGetPieceSpeed_Bps (atom->peer, now, TR_CLIENT_TO_PEER);
     3017
     3018  /* downloading a private torrent... take upload speed into account
     3019   * because there may only be a small window of opportunity to share */
     3020  else if (tr_torrentIsPrivate (tor))
     3021    Bps = tr_peerGetPieceSpeed_Bps (atom->peer, now, TR_PEER_TO_CLIENT)
     3022        + tr_peerGetPieceSpeed_Bps (atom->peer, now, TR_CLIENT_TO_PEER);
     3023
     3024  /* downloading a public torrent */
     3025  else
     3026    Bps = tr_peerGetPieceSpeed_Bps (atom->peer, now, TR_PEER_TO_CLIENT);
     3027
     3028  /* convert it to bytes per second */
     3029  return Bps;
    30183030}
    30193031
     
    30223034                     const uint64_t now_msec, tr_direction dir)
    30233035{
    3024     if (!tr_bandwidthIsLimited (b, dir))
    3025         return false;
    3026     else {
    3027         const unsigned int got = tr_bandwidthGetPieceSpeed_Bps (b, now_msec, dir);
    3028         const unsigned int want = tr_bandwidthGetDesiredSpeed_Bps (b, dir);
    3029         return got >= want;
    3030     }
    3031 }
    3032 
    3033 static void
    3034 rechokeUploads (Torrent * t, const uint64_t now)
    3035 {
    3036     int i, size, unchokedInterested;
    3037     const int peerCount = tr_ptrArraySize (&t->peers);
    3038     tr_peer ** peers = (tr_peer**) tr_ptrArrayBase (&t->peers);
    3039     struct ChokeData * choke = tr_new0 (struct ChokeData, peerCount);
    3040     const tr_session * session = t->manager->session;
    3041     const int chokeAll = !tr_torrentIsPieceTransferAllowed (t->tor, TR_CLIENT_TO_PEER);
    3042     const bool isMaxedOut = isBandwidthMaxedOut (&t->tor->bandwidth, now, TR_UP);
    3043 
    3044     assert (torrentIsLocked (t));
    3045 
    3046     /* an optimistic unchoke peer's "optimistic"
    3047      * state lasts for N calls to rechokeUploads (). */
    3048     if (t->optimisticUnchokeTimeScaler > 0)
    3049         t->optimisticUnchokeTimeScaler--;
    3050     else
    3051         t->optimistic = NULL;
    3052 
    3053     /* sort the peers by preference and rate */
    3054     for (i = 0, size = 0; i < peerCount; ++i)
    3055     {
    3056         tr_peer * peer = peers[i];
    3057         struct peer_atom * atom = peer->atom;
    3058 
    3059         if (peerIsSeed (peer)) /* choke seeds and partial seeds */
     3036  if (!tr_bandwidthIsLimited (b, dir))
     3037    {
     3038      return false;
     3039    }
     3040  else
     3041    {
     3042      const unsigned int got = tr_bandwidthGetPieceSpeed_Bps (b, now_msec, dir);
     3043      const unsigned int want = tr_bandwidthGetDesiredSpeed_Bps (b, dir);
     3044      return got >= want;
     3045    }
     3046}
     3047
     3048static void
     3049rechokeUploads (tr_swarm * s, const uint64_t now)
     3050{
     3051  int i, size, unchokedInterested;
     3052  const int peerCount = tr_ptrArraySize (&s->peers);
     3053  tr_peer ** peers = (tr_peer**) tr_ptrArrayBase (&s->peers);
     3054  struct ChokeData * choke = tr_new0 (struct ChokeData, peerCount);
     3055  const tr_session * session = s->manager->session;
     3056  const int chokeAll = !tr_torrentIsPieceTransferAllowed (s->tor, TR_CLIENT_TO_PEER);
     3057  const bool isMaxedOut = isBandwidthMaxedOut (&s->tor->bandwidth, now, TR_UP);
     3058
     3059  assert (swarmIsLocked (s));
     3060
     3061  /* an optimistic unchoke peer's "optimistic"
     3062   * state lasts for N calls to rechokeUploads (). */
     3063  if (s->optimisticUnchokeTimeScaler > 0)
     3064    s->optimisticUnchokeTimeScaler--;
     3065  else
     3066    s->optimistic = NULL;
     3067
     3068  /* sort the peers by preference and rate */
     3069  for (i=0, size=0; i<peerCount; ++i)
     3070    {
     3071      tr_peer * peer = peers[i];
     3072      struct peer_atom * atom = peer->atom;
     3073
     3074      if (peerIsSeed (peer)) /* choke seeds and partial seeds */
    30603075        {
    3061             tr_peerMsgsSetChoke (peer->msgs, true);
     3076          tr_peerMsgsSetChoke (peer->msgs, true);
    30623077        }
    3063         else if (chokeAll) /* choke everyone if we're not uploading */
     3078      else if (chokeAll) /* choke everyone if we're not uploading */
    30643079        {
    3065             tr_peerMsgsSetChoke (peer->msgs, true);
     3080          tr_peerMsgsSetChoke (peer->msgs, true);
    30663081        }
    3067         else if (peer != t->optimistic)
     3082      else if (peer != s->optimistic)
    30683083        {
    3069             struct ChokeData * n = &choke[size++];
    3070             n->peer         = peer;
    3071             n->isInterested = peer->peerIsInterested;
    3072             n->wasChoked    = peer->peerIsChoked;
    3073             n->rate         = getRate (t->tor, atom, now);
    3074             n->salt         = tr_cryptoWeakRandInt (INT_MAX);
    3075             n->isChoked     = true;
     3084          struct ChokeData * n = &choke[size++];
     3085          n->peer         = peer;
     3086          n->isInterested = peer->peerIsInterested;
     3087          n->wasChoked    = peer->peerIsChoked;
     3088          n->rate         = getRate (s->tor, atom, now);
     3089          n->salt         = tr_cryptoWeakRandInt (INT_MAX);
     3090          n->isChoked     = true;
    30763091        }
    30773092    }
    30783093
    3079     qsort (choke, size, sizeof (struct ChokeData), compareChoke);
    3080 
    3081     /**
    3082      * Reciprocation and number of uploads capping is managed by unchoking
    3083      * the N peers which have the best upload rate and are interested.
    3084      * This maximizes the client's download rate. These N peers are
    3085      * referred to as downloaders, because they are interested in downloading
    3086      * from the client.
    3087      *
    3088      * Peers which have a better upload rate (as compared to the downloaders)
    3089      * but aren't interested get unchoked. If they become interested, the
    3090      * downloader with the worst upload rate gets choked. If a client has
    3091      * a complete file, it uses its upload rate rather than its download
    3092      * rate to decide which peers to unchoke.
    3093      *
    3094      * If our bandwidth is maxed out, don't unchoke any more peers.
    3095      */
    3096     unchokedInterested = 0;
    3097     for (i=0; i<size && unchokedInterested<session->uploadSlotsPerTorrent; ++i) {
    3098         choke[i].isChoked = isMaxedOut ? choke[i].wasChoked : false;
    3099         if (choke[i].isInterested)
    3100             ++unchokedInterested;
    3101     }
    3102 
    3103     /* optimistic unchoke */
    3104     if (!t->optimistic && !isMaxedOut && (i<size))
    3105     {
    3106         int n;
    3107         struct ChokeData * c;
    3108         tr_ptrArray randPool = TR_PTR_ARRAY_INIT;
    3109 
    3110         for (; i<size; ++i)
     3094  qsort (choke, size, sizeof (struct ChokeData), compareChoke);
     3095
     3096  /**
     3097   * Reciprocation and number of uploads capping is managed by unchoking
     3098   * the N peers which have the best upload rate and are interested.
     3099   * This maximizes the client's download rate. These N peers are
     3100   * referred to as downloaders, because they are interested in downloading
     3101   * from the client.
     3102   *
     3103   * Peers which have a better upload rate (as compared to the downloaders)
     3104   * but aren't interested get unchoked. If they become interested, the
     3105   * downloader with the worst upload rate gets choked. If a client has
     3106   * a complete file, it uses its upload rate rather than its download
     3107   * rate to decide which peers to unchoke.
     3108   *
     3109   * If our bandwidth is maxed out, don't unchoke any more peers.
     3110   */
     3111  unchokedInterested = 0;
     3112  for (i=0; i<size && unchokedInterested<session->uploadSlotsPerTorrent; ++i)
     3113    {
     3114      choke[i].isChoked = isMaxedOut ? choke[i].wasChoked : false;
     3115      if (choke[i].isInterested)
     3116        ++unchokedInterested;
     3117    }
     3118
     3119  /* optimistic unchoke */
     3120  if (!s->optimistic && !isMaxedOut && (i<size))
     3121    {
     3122      int n;
     3123      struct ChokeData * c;
     3124      tr_ptrArray randPool = TR_PTR_ARRAY_INIT;
     3125
     3126      for (; i<size; ++i)
    31113127        {
    3112             if (choke[i].isInterested)
     3128          if (choke[i].isInterested)
    31133129            {
    3114                 const tr_peer * peer = choke[i].peer;
    3115                 int x = 1, y;
    3116                 if (isNew (peer)) x *= 3;
    3117                 for (y=0; y<x; ++y)
    3118                     tr_ptrArrayAppend (&randPool, &choke[i]);
     3130              const tr_peer * peer = choke[i].peer;
     3131              int x = 1, y;
     3132              if (isNew (peer)) x *= 3;
     3133              for (y=0; y<x; ++y)
     3134                tr_ptrArrayAppend (&randPool, &choke[i]);
    31193135            }
    31203136        }
    31213137
    3122         if ((n = tr_ptrArraySize (&randPool)))
     3138      if ((n = tr_ptrArraySize (&randPool)))
    31233139        {
    3124             c = tr_ptrArrayNth (&randPool, tr_cryptoWeakRandInt (n));
    3125             c->isChoked = false;
    3126             t->optimistic = c->peer;
    3127             t->optimisticUnchokeTimeScaler = OPTIMISTIC_UNCHOKE_MULTIPLIER;
     3140          c = tr_ptrArrayNth (&randPool, tr_cryptoWeakRandInt (n));
     3141          c->isChoked = false;
     3142          s->optimistic = c->peer;
     3143          s->optimisticUnchokeTimeScaler = OPTIMISTIC_UNCHOKE_MULTIPLIER;
    31283144        }
    31293145
    3130         tr_ptrArrayDestruct (&randPool, NULL);
    3131     }
    3132 
    3133     for (i=0; i<size; ++i)
    3134         tr_peerMsgsSetChoke (choke[i].peer->msgs, choke[i].isChoked);
    3135 
    3136     /* cleanup */
    3137     tr_free (choke);
     3146      tr_ptrArrayDestruct (&randPool, NULL);
     3147    }
     3148
     3149  for (i=0; i<size; ++i)
     3150    tr_peerMsgsSetChoke (choke[i].peer->msgs, choke[i].isChoked);
     3151
     3152  /* cleanup */
     3153  tr_free (choke);
    31383154}
    31393155
     
    31413157rechokePulse (int foo UNUSED, short bar UNUSED, void * vmgr)
    31423158{
    3143     tr_torrent * tor = NULL;
    3144     tr_peerMgr * mgr = vmgr;
    3145     const uint64_t now = tr_time_msec ();
    3146 
    3147     managerLock (mgr);
    3148 
    3149     while ((tor = tr_torrentNext (mgr->session, tor))) {
    3150         if (tor->isRunning) {
    3151             Torrent * t = tor->torrentPeers;
    3152             if (!tr_ptrArrayEmpty (&t->peers)) {
    3153                 rechokeUploads (t, now);
    3154                 rechokeDownloads (t);
     3159  tr_torrent * tor = NULL;
     3160  tr_peerMgr * mgr = vmgr;
     3161  const uint64_t now = tr_time_msec ();
     3162
     3163  managerLock (mgr);
     3164
     3165  while ((tor = tr_torrentNext (mgr->session, tor)))
     3166    {
     3167      if (tor->isRunning)
     3168        {
     3169          tr_swarm * s = tor->swarm;
     3170          if (!tr_ptrArrayEmpty (&s->peers))
     3171            {
     3172              rechokeUploads (s, now);
     3173              rechokeDownloads (s);
    31553174            }
    31563175        }
    31573176    }
    31583177
    3159     tr_timerAddMsec (mgr->rechokeTimer, RECHOKE_PERIOD_MSEC);
    3160     managerUnlock (mgr);
     3178  tr_timerAddMsec (mgr->rechokeTimer, RECHOKE_PERIOD_MSEC);
     3179  managerUnlock (mgr);
    31613180}
    31623181
     
    31683187
    31693188static bool
    3170 shouldPeerBeClosed (const Torrent    * t,
     3189shouldPeerBeClosed (const tr_swarm   * s,
    31713190                    const tr_peer    * peer,
    31723191                    int                peerCount,
    31733192                    const time_t       now)
    31743193{
    3175     const tr_torrent *       tor = t->tor;
    3176     const struct peer_atom * atom = peer->atom;
    3177 
    3178     /* if it's marked for purging, close it */
    3179     if (peer->doPurge)
    3180     {
    3181         tordbg (t, "purging peer %s because its doPurge flag is set",
    3182                 tr_atomAddrStr (atom));
     3194  const tr_torrent * tor = s->tor;
     3195  const struct peer_atom * atom = peer->atom;
     3196
     3197  /* if it's marked for purging, close it */
     3198  if (peer->doPurge)
     3199    {
     3200      tordbg (s, "purging peer %s because its doPurge flag is set",
     3201              tr_atomAddrStr (atom));
     3202      return true;
     3203    }
     3204
     3205  /* disconnect if we're both seeds and enough time has passed for PEX */
     3206  if (tr_torrentIsSeed (tor) && peerIsSeed (peer))
     3207    return !tr_torrentAllowsPex (tor) || (now-atom->time>=30);
     3208
     3209  /* disconnect if it's been too long since piece data has been transferred.
     3210   * this is on a sliding scale based on number of available peers... */
     3211  {
     3212    const int relaxStrictnessIfFewerThanN = (int)((getMaxPeerCount (tor) * 0.9) + 0.5);
     3213    /* if we have >= relaxIfFewerThan, strictness is 100%.
     3214     * if we have zero connections, strictness is 0% */
     3215    const float strictness = peerCount >= relaxStrictnessIfFewerThanN
     3216                           ? 1.0
     3217                           : peerCount / (float)relaxStrictnessIfFewerThanN;
     3218    const int lo = MIN_UPLOAD_IDLE_SECS;
     3219    const int hi = MAX_UPLOAD_IDLE_SECS;
     3220    const int limit = hi - ((hi - lo) * strictness);
     3221    const int idleTime = now - MAX (atom->time, atom->piece_data_time);
     3222/*fprintf (stderr, "strictness is %.3f, limit is %d seconds... time since connect is %d, time since piece is %d ... idleTime is %d, doPurge is %d\n", (double)strictness, limit, (int)(now - atom->time), (int)(now - atom->piece_data_time), idleTime, idleTime > limit);*/
     3223    if (idleTime > limit)
     3224      {
     3225        tordbg (s, "purging peer %s because it's been %d secs since we shared anything",
     3226                tr_atomAddrStr (atom), idleTime);
    31833227        return true;
    3184     }
    3185 
    3186     /* disconnect if we're both seeds and enough time has passed for PEX */
    3187     if (tr_torrentIsSeed (tor) && peerIsSeed (peer))
    3188         return !tr_torrentAllowsPex (tor) || (now-atom->time>=30);
    3189 
    3190     /* disconnect if it's been too long since piece data has been transferred.
    3191      * this is on a sliding scale based on number of available peers... */
    3192     {
    3193         const int relaxStrictnessIfFewerThanN = (int)((getMaxPeerCount (tor) * 0.9) + 0.5);
    3194         /* if we have >= relaxIfFewerThan, strictness is 100%.
    3195          * if we have zero connections, strictness is 0% */
    3196         const float strictness = peerCount >= relaxStrictnessIfFewerThanN
    3197                                ? 1.0
    3198                                : peerCount / (float)relaxStrictnessIfFewerThanN;
    3199         const int lo = MIN_UPLOAD_IDLE_SECS;
    3200         const int hi = MAX_UPLOAD_IDLE_SECS;
    3201         const int limit = hi - ((hi - lo) * strictness);
    3202         const int idleTime = now - MAX (atom->time, atom->piece_data_time);
    3203 /*fprintf (stderr, "strictness is %.3f, limit is %d seconds... time since connect is %d, time since piece is %d ... idleTime is %d, doPurge is %d\n", (double)strictness, limit, (int)(now - atom->time), (int)(now - atom->piece_data_time), idleTime, idleTime > limit);*/
    3204         if (idleTime > limit) {
    3205             tordbg (t, "purging peer %s because it's been %d secs since we shared anything",
    3206                        tr_atomAddrStr (atom), idleTime);
    3207             return true;
     3228      }
     3229  }
     3230
     3231  return false;
     3232}
     3233
     3234static tr_peer **
     3235getPeersToClose (tr_swarm * s, const time_t now_sec, int * setmeSize)
     3236{
     3237  int i, peerCount, outsize;
     3238  struct tr_peer ** ret = NULL;
     3239  tr_peer ** peers = (tr_peer**) tr_ptrArrayPeek (&s->peers, &peerCount);
     3240
     3241  assert (swarmIsLocked (s));
     3242
     3243  for (i=outsize=0; i<peerCount; ++i)
     3244    {
     3245      if (shouldPeerBeClosed (s, peers[i], peerCount, now_sec))
     3246        {
     3247          if (ret == NULL)
     3248            ret = tr_new (tr_peer *, peerCount);
     3249          ret[outsize++] = peers[i];
    32083250        }
    32093251    }
    32103252
    3211     return false;
    3212 }
    3213 
    3214 static tr_peer **
    3215 getPeersToClose (Torrent * t, const time_t now_sec, int * setmeSize)
    3216 {
    3217     int i, peerCount, outsize;
    3218     struct tr_peer ** ret = NULL;
    3219     tr_peer ** peers = (tr_peer**) tr_ptrArrayPeek (&t->peers, &peerCount);
    3220 
    3221     assert (torrentIsLocked (t));
    3222 
    3223     for (i = outsize = 0; i < peerCount; ++i) {
    3224         if (shouldPeerBeClosed (t, peers[i], peerCount, now_sec)) {
    3225             if (ret == NULL)
    3226                 ret = tr_new (tr_peer *, peerCount);
    3227             ret[outsize++] = peers[i];
    3228         }
    3229     }
    3230 
    3231     *setmeSize = outsize;
    3232     return ret;
     3253  *setmeSize = outsize;
     3254  return ret;
    32333255}
    32343256
     
    32723294
    32733295static void
    3274 removePeer (Torrent * t, tr_peer * peer)
    3275 {
    3276     tr_peer * removed;
    3277     struct peer_atom * atom = peer->atom;
    3278 
    3279     assert (torrentIsLocked (t));
    3280     assert (atom);
    3281 
    3282     atom->time = tr_time ();
    3283 
    3284     removed = tr_ptrArrayRemoveSorted (&t->peers, peer, peerCompare);
    3285 
    3286     if (replicationExists (t))
    3287         tr_decrReplicationFromBitfield (t, &peer->have);
    3288 
    3289     assert (removed == peer);
    3290     peerDelete (t, removed);
    3291 }
    3292 
    3293 static void
    3294 closePeer (Torrent * t, tr_peer * peer)
    3295 {
    3296     struct peer_atom * atom;
    3297 
    3298     assert (t != NULL);
    3299     assert (peer != NULL);
    3300 
    3301     atom = peer->atom;
    3302 
    3303     /* if we transferred piece data, then they might be good peers,
    3304        so reset their `numFails' weight to zero. otherwise we connected
    3305        to them fruitlessly, so mark it as another fail */
    3306     if (atom->piece_data_time) {
    3307         tordbg (t, "resetting atom %s numFails to 0", tr_atomAddrStr (atom));
    3308         atom->numFails = 0;
    3309     } else {
    3310         ++atom->numFails;
    3311         tordbg (t, "incremented atom %s numFails to %d", tr_atomAddrStr (atom), (int)atom->numFails);
    3312     }
    3313 
    3314     tordbg (t, "removing bad peer %s", tr_peerIoGetAddrStr (peer->io));
    3315     removePeer (t, peer);
    3316 }
    3317 
    3318 static void
    3319 removeAllPeers (Torrent * t)
    3320 {
    3321     while (!tr_ptrArrayEmpty (&t->peers))
    3322         removePeer (t, tr_ptrArrayNth (&t->peers, 0));
    3323 }
    3324 
    3325 static void
    3326 closeBadPeers (Torrent * t, const time_t now_sec)
    3327 {
    3328     if (!tr_ptrArrayEmpty (&t->peers))
    3329     {
    3330         int i;
    3331         int peerCount;
    3332         struct tr_peer ** peers = getPeersToClose (t, now_sec, &peerCount);
    3333         for (i=0; i<peerCount; ++i)
    3334             closePeer (t, peers[i]);
    3335         tr_free (peers);
     3296removePeer (tr_swarm * s, tr_peer * peer)
     3297{
     3298  tr_peer * removed;
     3299  struct peer_atom * atom = peer->atom;
     3300
     3301  assert (swarmIsLocked (s));
     3302  assert (atom);
     3303
     3304  atom->time = tr_time ();
     3305
     3306  removed = tr_ptrArrayRemoveSorted (&s->peers, peer, peerCompare);
     3307
     3308  if (replicationExists (s))
     3309    tr_decrReplicationFromBitfield (s, &peer->have);
     3310
     3311  assert (removed == peer);
     3312  peerDelete (s, removed);
     3313}
     3314
     3315static void
     3316closePeer (tr_swarm * s, tr_peer * peer)
     3317{
     3318  struct peer_atom * atom;
     3319
     3320  assert (s != NULL);
     3321  assert (peer != NULL);
     3322
     3323  atom = peer->atom;
     3324
     3325  /* if we transferred piece data, then they might be good peers,
     3326     so reset their `numFails' weight to zero. otherwise we connected
     3327     to them fruitlessly, so mark it as another fail */
     3328  if (atom->piece_data_time)
     3329    {
     3330      tordbg (s, "resetting atom %s numFails to 0", tr_atomAddrStr (atom));
     3331      atom->numFails = 0;
     3332    }
     3333  else
     3334    {
     3335      ++atom->numFails;
     3336      tordbg (s, "incremented atom %s numFails to %d", tr_atomAddrStr (atom), (int)atom->numFails);
     3337    }
     3338
     3339  tordbg (s, "removing bad peer %s", tr_peerIoGetAddrStr (peer->io));
     3340  removePeer (s, peer);
     3341}
     3342
     3343static void
     3344removeAllPeers (tr_swarm * s)
     3345{
     3346  while (!tr_ptrArrayEmpty (&s->peers))
     3347    removePeer (s, tr_ptrArrayNth (&s->peers, 0));
     3348}
     3349
     3350static void
     3351closeBadPeers (tr_swarm * s, const time_t now_sec)
     3352{
     3353  if (!tr_ptrArrayEmpty (&s->peers))
     3354    {
     3355      int i;
     3356      int peerCount;
     3357      struct tr_peer ** peers;
     3358
     3359      peers = getPeersToClose (s, now_sec, &peerCount);
     3360      for (i=0; i<peerCount; ++i)
     3361        closePeer (s, peers[i]);
     3362      tr_free (peers);
    33363363    }
    33373364}
     
    33393366struct peer_liveliness
    33403367{
    3341     tr_peer * peer;
    3342     void * clientData;
    3343     time_t pieceDataTime;
    3344     time_t time;
    3345     int speed;
    3346     bool doPurge;
     3368  tr_peer * peer;
     3369  void * clientData;
     3370  time_t pieceDataTime;
     3371  time_t time;
     3372  int speed;
     3373  bool doPurge;
    33473374};
    33483375
     
    33503377comparePeerLiveliness (const void * va, const void * vb)
    33513378{
    3352     const struct peer_liveliness * a = va;
    3353     const struct peer_liveliness * b = vb;
    3354 
    3355     if (a->doPurge != b->doPurge)
    3356         return a->doPurge ? 1 : -1;
    3357 
    3358     if (a->speed != b->speed) /* faster goes first */
    3359         return a->speed > b->speed ? -1 : 1;
    3360 
    3361     /* the one to give us data more recently goes first */
    3362     if (a->pieceDataTime != b->pieceDataTime)
    3363         return a->pieceDataTime > b->pieceDataTime ? -1 : 1;
    3364 
    3365     /* the one we connected to most recently goes first */
    3366     if (a->time != b->time)
    3367         return a->time > b->time ? -1 : 1;
    3368 
    3369     return 0;
     3379  const struct peer_liveliness * a = va;
     3380  const struct peer_liveliness * b = vb;
     3381
     3382  if (a->doPurge != b->doPurge)
     3383    return a->doPurge ? 1 : -1;
     3384
     3385  if (a->speed != b->speed) /* faster goes first */
     3386    return a->speed > b->speed ? -1 : 1;
     3387
     3388  /* the one to give us data more recently goes first */
     3389  if (a->pieceDataTime != b->pieceDataTime)
     3390    return a->pieceDataTime > b->pieceDataTime ? -1 : 1;
     3391
     3392  /* the one we connected to most recently goes first */
     3393  if (a->time != b->time)
     3394    return a->time > b->time ? -1 : 1;
     3395
     3396  return 0;
    33703397}
    33713398
     
    33773404                           int (*compare)(const void *va, const void *vb))
    33783405{
    3379     int i;
    3380     struct peer_liveliness *lives, *l;
    3381 
    3382     /* build a sortable array of peer + extra info */
    3383     lives = l = tr_new0 (struct peer_liveliness, n);
    3384     for (i=0; i<n; ++i, ++l)
    3385     {
    3386         tr_peer * p = peers[i];
    3387         l->peer = p;
    3388         l->doPurge = p->doPurge;
    3389         l->pieceDataTime = p->atom->piece_data_time;
    3390         l->time = p->atom->time;
    3391         l->speed = tr_peerGetPieceSpeed_Bps (p, now, TR_UP)
    3392                  + tr_peerGetPieceSpeed_Bps (p, now, TR_DOWN);
    3393         if (clientData)
    3394             l->clientData = clientData[i];
    3395     }
    3396 
    3397     /* sort 'em */
    3398     assert (n == (l - lives));
    3399     qsort (lives, n, sizeof (struct peer_liveliness), compare);
    3400 
    3401     /* build the peer array */
    3402     for (i=0, l=lives; i<n; ++i, ++l) {
    3403         peers[i] = l->peer;
    3404         if (clientData)
    3405             clientData[i] = l->clientData;
    3406     }
    3407     assert (n == (l - lives));
    3408 
    3409     /* cleanup */
    3410     tr_free (lives);
     3406  int i;
     3407  struct peer_liveliness *lives, *l;
     3408
     3409  /* build a sortable array of peer + extra info */
     3410  lives = l = tr_new0 (struct peer_liveliness, n);
     3411  for (i=0; i<n; ++i, ++l)
     3412    {
     3413      tr_peer * p = peers[i];
     3414      l->peer = p;
     3415      l->doPurge = p->doPurge;
     3416      l->pieceDataTime = p->atom->piece_data_time;
     3417      l->time = p->atom->time;
     3418      l->speed = tr_peerGetPieceSpeed_Bps (p, now, TR_UP)
     3419               + tr_peerGetPieceSpeed_Bps (p, now, TR_DOWN);
     3420      if (clientData)
     3421        l->clientData = clientData[i];
     3422    }
     3423
     3424  /* sort 'em */
     3425  assert (n == (l - lives));
     3426  qsort (lives, n, sizeof (struct peer_liveliness), compare);
     3427
     3428  /* build the peer array */
     3429  for (i=0, l=lives; i<n; ++i, ++l)
     3430    {
     3431      peers[i] = l->peer;
     3432      if (clientData)
     3433        clientData[i] = l->clientData;
     3434    }
     3435  assert (n == (l - lives));
     3436
     3437  /* cleanup */
     3438  tr_free (lives);
    34113439}
    34123440
     
    34143442sortPeersByLiveliness (tr_peer ** peers, void ** clientData, int n, uint64_t now)
    34153443{
    3416     sortPeersByLivelinessImpl (peers, clientData, n, now, comparePeerLiveliness);
    3417 }
    3418 
    3419 
    3420 static void
    3421 enforceTorrentPeerLimit (Torrent * t, uint64_t now)
    3422 {
    3423     int n = tr_ptrArraySize (&t->peers);
    3424     const int max = tr_torrentGetPeerLimit (t->tor);
    3425     if (n > max)
    3426     {
    3427         void * base = tr_ptrArrayBase (&t->peers);
    3428         tr_peer ** peers = tr_memdup (base, n*sizeof (tr_peer*));
    3429         sortPeersByLiveliness (peers, NULL, n, now);
    3430         while (n > max)
    3431             closePeer (t, peers[--n]);
    3432         tr_free (peers);
     3444  sortPeersByLivelinessImpl (peers, clientData, n, now, comparePeerLiveliness);
     3445}
     3446
     3447
     3448static void
     3449enforceTorrentPeerLimit (tr_swarm * s, uint64_t now)
     3450{
     3451  int n = tr_ptrArraySize (&s->peers);
     3452  const int max = tr_torrentGetPeerLimit (s->tor);
     3453  if (n > max)
     3454    {
     3455      void * base = tr_ptrArrayBase (&s->peers);
     3456      tr_peer ** peers = tr_memdup (base, n*sizeof (tr_peer*));
     3457      sortPeersByLiveliness (peers, NULL, n, now);
     3458      while (n > max)
     3459        closePeer (s, peers[--n]);
     3460      tr_free (peers);
    34333461    }
    34343462}
     
    34373465enforceSessionPeerLimit (tr_session * session, uint64_t now)
    34383466{
    3439     int n = 0;
    3440     tr_torrent * tor = NULL;
    3441     const int max = tr_sessionGetPeerLimit (session);
    3442 
    3443     /* count the total number of peers */
    3444     while ((tor = tr_torrentNext (session, tor)))
    3445         n += tr_ptrArraySize (&tor->torrentPeers->peers);
    3446 
    3447     /* if there are too many, prune out the worst */
    3448     if (n > max)
    3449     {
    3450         tr_peer ** peers = tr_new (tr_peer*, n);
    3451         Torrent ** torrents = tr_new (Torrent*, n);
    3452 
    3453         /* populate the peer array */
    3454         n = 0;
    3455         tor = NULL;
    3456         while ((tor = tr_torrentNext (session, tor))) {
    3457             int i;
    3458             Torrent * t = tor->torrentPeers;
    3459             const int tn = tr_ptrArraySize (&t->peers);
    3460             for (i=0; i<tn; ++i, ++n) {
    3461                 peers[n] = tr_ptrArrayNth (&t->peers, i);
    3462                 torrents[n] = t;
     3467  int n = 0;
     3468  tr_torrent * tor = NULL;
     3469  const int max = tr_sessionGetPeerLimit (session);
     3470
     3471  /* count the total number of peers */
     3472  while ((tor = tr_torrentNext (session, tor)))
     3473    n += tr_ptrArraySize (&tor->swarm->peers);
     3474
     3475  /* if there are too many, prune out the worst */
     3476  if (n > max)
     3477    {
     3478      tr_peer ** peers = tr_new (tr_peer*, n);
     3479      tr_swarm ** swarms = tr_new (tr_swarm*, n);
     3480
     3481      /* populate the peer array */
     3482      n = 0;
     3483      tor = NULL;
     3484      while ((tor = tr_torrentNext (session, tor)))
     3485        {
     3486          int i;
     3487          tr_swarm * s = tor->swarm;
     3488          const int tn = tr_ptrArraySize (&s->peers);
     3489          for (i=0; i<tn; ++i, ++n)
     3490            {
     3491              peers[n] = tr_ptrArrayNth (&s->peers, i);
     3492              swarms[n] = s;
    34633493            }
    34643494        }
    34653495
    3466         /* sort 'em */
    3467         sortPeersByLiveliness (peers, (void**)torrents, n, now);
    3468 
    3469         /* cull out the crappiest */
    3470         while (n-- > max)
    3471             closePeer (torrents[n], peers[n]);
    3472 
    3473         /* cleanup */
    3474         tr_free (torrents);
    3475         tr_free (peers);
     3496      /* sort 'em */
     3497      sortPeersByLiveliness (peers, (void**)swarms, n, now);
     3498
     3499      /* cull out the crappiest */
     3500      while (n-- > max)
     3501        closePeer (swarms[n], peers[n]);
     3502
     3503      /* cleanup */
     3504      tr_free (swarms);
     3505      tr_free (peers);
    34763506    }
    34773507}
     
    34823512reconnectPulse (int foo UNUSED, short bar UNUSED, void * vmgr)
    34833513{
    3484     tr_torrent * tor;
    3485     tr_peerMgr * mgr = vmgr;
    3486     const time_t now_sec = tr_time ();
    3487     const uint64_t now_msec = tr_time_msec ();
    3488 
    3489     /**
    3490     ***  enforce the per-session and per-torrent peer limits
    3491     **/
    3492 
    3493     /* if we're over the per-torrent peer limits, cull some peers */
    3494     tor = NULL;
    3495     while ((tor = tr_torrentNext (mgr->session, tor)))
    3496         if (tor->isRunning)
    3497             enforceTorrentPeerLimit (tor->torrentPeers, now_msec);
    3498 
    3499     /* if we're over the per-session peer limits, cull some peers */
    3500     enforceSessionPeerLimit (mgr->session, now_msec);
    3501 
    3502     /* remove crappy peers */
    3503     tor = NULL;
    3504     while ((tor = tr_torrentNext (mgr->session, tor)))
    3505         if (!tor->torrentPeers->isRunning)
    3506             removeAllPeers (tor->torrentPeers);
    3507         else
    3508             closeBadPeers (tor->torrentPeers, now_sec);
    3509 
    3510     /* try to make new peer connections */
    3511     makeNewPeerConnections (mgr, MAX_CONNECTIONS_PER_PULSE);
     3514  tr_torrent * tor;
     3515  tr_peerMgr * mgr = vmgr;
     3516  const time_t now_sec = tr_time ();
     3517  const uint64_t now_msec = tr_time_msec ();
     3518
     3519  /**
     3520  ***  enforce the per-session and per-torrent peer limits
     3521  **/
     3522
     3523  /* if we're over the per-torrent peer limits, cull some peers */
     3524  tor = NULL;
     3525  while ((tor = tr_torrentNext (mgr->session, tor)))
     3526    if (tor->isRunning)
     3527      enforceTorrentPeerLimit (tor->swarm, now_msec);
     3528
     3529  /* if we're over the per-session peer limits, cull some peers */
     3530  enforceSessionPeerLimit (mgr->session, now_msec);
     3531
     3532  /* remove crappy peers */
     3533  tor = NULL;
     3534  while ((tor = tr_torrentNext (mgr->session, tor)))
     3535    if (!tor->swarm->isRunning)
     3536      removeAllPeers (tor->swarm);
     3537    else
     3538      closeBadPeers (tor->swarm, now_sec);
     3539
     3540  /* try to make new peer connections */
     3541  makeNewPeerConnections (mgr, MAX_CONNECTIONS_PER_PULSE);
    35123542}
    35133543
     
    35213551pumpAllPeers (tr_peerMgr * mgr)
    35223552{
    3523     tr_torrent * tor = NULL;
    3524 
    3525     while ((tor = tr_torrentNext (mgr->session, tor)))
    3526     {
    3527         int j;
    3528         Torrent * t = tor->torrentPeers;
    3529 
    3530         for (j=0; j<tr_ptrArraySize (&t->peers); ++j)
     3553  tr_torrent * tor = NULL;
     3554
     3555  while ((tor = tr_torrentNext (mgr->session, tor)))
     3556    {
     3557      int j;
     3558      tr_swarm * s = tor->swarm;
     3559
     3560      for (j=0; j<tr_ptrArraySize (&s->peers); ++j)
    35313561        {
    3532             tr_peer * peer = tr_ptrArrayNth (&t->peers, j);
    3533             tr_peerMsgsPulse (peer->msgs);
     3562          tr_peer * peer = tr_ptrArrayNth (&s->peers, j);
     3563          tr_peerMsgsPulse (peer->msgs);
    35343564        }
    35353565    }
     
    35723602bandwidthPulse (int foo UNUSED, short bar UNUSED, void * vmgr)
    35733603{
    3574     tr_torrent * tor;
    3575     tr_peerMgr * mgr = vmgr;
    3576     tr_session * session = mgr->session;
    3577     managerLock (mgr);
    3578 
    3579     /* FIXME: this next line probably isn't necessary... */
    3580     pumpAllPeers (mgr);
    3581 
    3582     /* allocate bandwidth to the peers */
    3583     tr_bandwidthAllocate (&session->bandwidth, TR_UP, BANDWIDTH_PERIOD_MSEC);
    3584     tr_bandwidthAllocate (&session->bandwidth, TR_DOWN, BANDWIDTH_PERIOD_MSEC);
    3585 
    3586     /* torrent upkeep */
    3587     tor = NULL;
    3588     while ((tor = tr_torrentNext (session, tor)))
    3589     {
    3590         /* possibly stop torrents that have seeded enough */
    3591         tr_torrentCheckSeedLimit (tor);
    3592 
    3593         /* run the completeness check for any torrents that need it */
    3594         if (tor->torrentPeers->needsCompletenessCheck) {
    3595             tor->torrentPeers->needsCompletenessCheck  = false;
    3596             tr_torrentRecheckCompleteness (tor);
     3604  tr_torrent * tor;
     3605  tr_peerMgr * mgr = vmgr;
     3606  tr_session * session = mgr->session;
     3607  managerLock (mgr);
     3608
     3609  /* FIXME: this next line probably isn't necessary... */
     3610  pumpAllPeers (mgr);
     3611
     3612  /* allocate bandwidth to the peers */
     3613  tr_bandwidthAllocate (&session->bandwidth, TR_UP, BANDWIDTH_PERIOD_MSEC);
     3614  tr_bandwidthAllocate (&session->bandwidth, TR_DOWN, BANDWIDTH_PERIOD_MSEC);
     3615
     3616  /* torrent upkeep */
     3617  tor = NULL;
     3618  while ((tor = tr_torrentNext (session, tor)))
     3619    {
     3620      /* possibly stop torrents that have seeded enough */
     3621      tr_torrentCheckSeedLimit (tor);
     3622
     3623      /* run the completeness check for any torrents that need it */
     3624      if (tor->swarm->needsCompletenessCheck)
     3625        {
     3626          tor->swarm->needsCompletenessCheck  = false;
     3627          tr_torrentRecheckCompleteness (tor);
    35973628        }
    35983629
    3599         /* stop torrents that are ready to stop, but couldn't be stopped
    3600            earlier during the peer-io callback call chain */
    3601         if (tor->isStopping)
    3602             tr_torrentStop (tor);
    3603     }
    3604 
    3605     /* pump the queues */
    3606     queuePulse (session, TR_UP);
    3607     queuePulse (session, TR_DOWN);
    3608 
    3609     reconnectPulse (0, 0, mgr);
    3610 
    3611     tr_timerAddMsec (mgr->bandwidthTimer, BANDWIDTH_PERIOD_MSEC);
    3612     managerUnlock (mgr);
     3630      /* stop torrents that are ready to stop, but couldn't be stopped
     3631         earlier during the peer-io callback call chain */
     3632      if (tor->isStopping)
     3633        tr_torrentStop (tor);
     3634    }
     3635
     3636  /* pump the queues */
     3637  queuePulse (session, TR_UP);
     3638  queuePulse (session, TR_DOWN);
     3639
     3640  reconnectPulse (0, 0, mgr);
     3641
     3642  tr_timerAddMsec (mgr->bandwidthTimer, BANDWIDTH_PERIOD_MSEC);
     3643  managerUnlock (mgr);
    36133644}
    36143645
     
    36203651compareAtomPtrsByAddress (const void * va, const void *vb)
    36213652{
    3622     const struct peer_atom * a = * (const struct peer_atom**) va;
    3623     const struct peer_atom * b = * (const struct peer_atom**) vb;
    3624 
    3625     assert (tr_isAtom (a));
    3626     assert (tr_isAtom (b));
    3627 
    3628     return tr_address_compare (&a->addr, &b->addr);
     3653  const struct peer_atom * a = * (const struct peer_atom**) va;
     3654  const struct peer_atom * b = * (const struct peer_atom**) vb;
     3655
     3656  assert (tr_isAtom (a));
     3657  assert (tr_isAtom (b));
     3658
     3659  return tr_address_compare (&a->addr, &b->addr);
    36293660}
    36303661
     
    36333664compareAtomPtrsByShelfDate (const void * va, const void *vb)
    36343665{
    3635     time_t atime;
    3636     time_t btime;
    3637     const struct peer_atom * a = * (const struct peer_atom**) va;
    3638     const struct peer_atom * b = * (const struct peer_atom**) vb;
    3639     const int data_time_cutoff_secs = 60 * 60;
    3640     const time_t tr_now = tr_time ();
    3641 
    3642     assert (tr_isAtom (a));
    3643     assert (tr_isAtom (b));
    3644 
    3645     /* primary key: the last piece data time *if* it was within the last hour */
    3646     atime = a->piece_data_time; if (atime + data_time_cutoff_secs < tr_now) atime = 0;
    3647     btime = b->piece_data_time; if (btime + data_time_cutoff_secs < tr_now) btime = 0;
    3648     if (atime != btime)
    3649         return atime > btime ? -1 : 1;
    3650 
    3651     /* secondary key: shelf date. */
    3652     if (a->shelf_date != b->shelf_date)
    3653         return a->shelf_date > b->shelf_date ? -1 : 1;
    3654 
    3655     return 0;
     3666  time_t atime;
     3667  time_t btime;
     3668  const struct peer_atom * a = * (const struct peer_atom**) va;
     3669  const struct peer_atom * b = * (const struct peer_atom**) vb;
     3670  const int data_time_cutoff_secs = 60 * 60;
     3671  const time_t tr_now = tr_time ();
     3672
     3673  assert (tr_isAtom (a));
     3674  assert (tr_isAtom (b));
     3675
     3676  /* primary key: the last piece data time *if* it was within the last hour */
     3677  atime = a->piece_data_time; if (atime + data_time_cutoff_secs < tr_now) atime = 0;
     3678  btime = b->piece_data_time; if (btime + data_time_cutoff_secs < tr_now) btime = 0;
     3679  if (atime != btime)
     3680    return atime > btime ? -1 : 1;
     3681
     3682  /* secondary key: shelf date. */
     3683  if (a->shelf_date != b->shelf_date)
     3684    return a->shelf_date > b->shelf_date ? -1 : 1;
     3685
     3686  return 0;
    36563687}
    36573688
     
    36653696atomPulse (int foo UNUSED, short bar UNUSED, void * vmgr)
    36663697{
    3667     tr_torrent * tor = NULL;
    3668     tr_peerMgr * mgr = vmgr;
    3669     managerLock (mgr);
    3670 
    3671     while ((tor = tr_torrentNext (mgr->session, tor)))
    3672     {
    3673         int atomCount;
    3674         Torrent * t = tor->torrentPeers;
    3675         const int maxAtomCount = getMaxAtomCount (tor);
    3676         struct peer_atom ** atoms = (struct peer_atom**) tr_ptrArrayPeek (&t->pool, &atomCount);
    3677 
    3678         if (atomCount > maxAtomCount) /* we've got too many atoms... time to prune */
     3698  tr_torrent * tor = NULL;
     3699  tr_peerMgr * mgr = vmgr;
     3700  managerLock (mgr);
     3701
     3702  while ((tor = tr_torrentNext (mgr->session, tor)))
     3703    {
     3704      int atomCount;
     3705      tr_swarm * s = tor->swarm;
     3706      const int maxAtomCount = getMaxAtomCount (tor);
     3707      struct peer_atom ** atoms = (struct peer_atom**) tr_ptrArrayPeek (&s->pool, &atomCount);
     3708
     3709      if (atomCount > maxAtomCount) /* we've got too many atoms... time to prune */
    36793710        {
    3680             int i;
    3681             int keepCount = 0;
    3682             int testCount = 0;
    3683             struct peer_atom ** keep = tr_new (struct peer_atom*, atomCount);
    3684             struct peer_atom ** test = tr_new (struct peer_atom*, atomCount);
    3685 
    3686             /* keep the ones that are in use */
    3687             for (i=0; i<atomCount; ++i) {
    3688                 struct peer_atom * atom = atoms[i];
    3689                 if (peerIsInUse (t, atom))
    3690                     keep[keepCount++] = atom;
    3691                 else
    3692                     test[testCount++] = atom;
     3711          int i;
     3712          int keepCount = 0;
     3713          int testCount = 0;
     3714          struct peer_atom ** keep = tr_new (struct peer_atom*, atomCount);
     3715          struct peer_atom ** test = tr_new (struct peer_atom*, atomCount);
     3716
     3717          /* keep the ones that are in use */
     3718          for (i=0; i<atomCount; ++i)
     3719            {
     3720              struct peer_atom * atom = atoms[i];
     3721              if (peerIsInUse (s, atom))
     3722                keep[keepCount++] = atom;
     3723              else
     3724                test[testCount++] = atom;
    36933725            }
    36943726
    3695             /* if there's room, keep the best of what's left */
    3696             i = 0;
    3697             if (keepCount < maxAtomCount) {
    3698                 qsort (test, testCount, sizeof (struct peer_atom *), compareAtomPtrsByShelfDate);
    3699                 while (i<testCount && keepCount<maxAtomCount)
    3700                     keep[keepCount++] = test[i++];
     3727          /* if there's room, keep the best of what's left */
     3728          i = 0;
     3729          if (keepCount < maxAtomCount)
     3730            {
     3731              qsort (test, testCount, sizeof (struct peer_atom *), compareAtomPtrsByShelfDate);
     3732              while (i<testCount && keepCount<maxAtomCount)
     3733                keep[keepCount++] = test[i++];
    37013734            }
    37023735
    3703             /* free the culled atoms */
    3704             while (i<testCount)
    3705                 tr_free (test[i++]);
    3706 
    3707             /* rebuild Torrent.pool with what's left */
    3708             tr_ptrArrayDestruct (&t->pool, NULL);
    3709             t->pool = TR_PTR_ARRAY_INIT;
    3710             qsort (keep, keepCount, sizeof (struct peer_atom *), compareAtomPtrsByAddress);
    3711             for (i=0; i<keepCount; ++i)
    3712                 tr_ptrArrayAppend (&t->pool, keep[i]);
    3713 
    3714             tordbg (t, "max atom count is %d... pruned from %d to %d\n", maxAtomCount, atomCount, keepCount);
    3715 
    3716             /* cleanup */
    3717             tr_free (test);
    3718             tr_free (keep);
     3736          /* free the culled atoms */
     3737          while (i<testCount)
     3738            tr_free (test[i++]);
     3739
     3740          /* rebuild Torrent.pool with what's left */
     3741          tr_ptrArrayDestruct (&s->pool, NULL);
     3742          s->pool = TR_PTR_ARRAY_INIT;
     3743          qsort (keep, keepCount, sizeof (struct peer_atom *), compareAtomPtrsByAddress);
     3744          for (i=0; i<keepCount; ++i)
     3745            tr_ptrArrayAppend (&s->pool, keep[i]);
     3746
     3747          tordbg (s, "max atom count is %d... pruned from %d to %d\n", maxAtomCount, atomCount, keepCount);
     3748
     3749          /* cleanup */
     3750          tr_free (test);
     3751          tr_free (keep);
    37193752        }
    37203753    }
    37213754
    3722     tr_timerAddMsec (mgr->atomTimer, ATOM_PERIOD_MSEC);
    3723     managerUnlock (mgr);
     3755  tr_timerAddMsec (mgr->atomTimer, ATOM_PERIOD_MSEC);
     3756  managerUnlock (mgr);
    37243757}
    37253758
     
    37343767isPeerCandidate (const tr_torrent * tor, struct peer_atom * atom, const time_t now)
    37353768{
    3736     /* not if we're both seeds */
    3737     if (tr_torrentIsSeed (tor) && atomIsSeed (atom))
    3738         return false;
    3739 
    3740     /* not if we've already got a connection to them... */
    3741     if (peerIsInUse (tor->torrentPeers, atom))
    3742         return false;
    3743 
    3744     /* not if we just tried them already */
    3745     if ((now - atom->time) < getReconnectIntervalSecs (atom, now))
    3746         return false;
    3747 
    3748     /* not if they're blocklisted */
    3749     if (isAtomBlocklisted (tor->session, atom))
    3750         return false;
    3751 
    3752     /* not if they're banned... */
    3753     if (atom->flags2 & MYFLAG_BANNED)
    3754         return false;
    3755 
    3756     return true;
     3769  /* not if we're both seeds */
     3770  if (tr_torrentIsSeed (tor) && atomIsSeed (atom))
     3771    return false;
     3772
     3773  /* not if we've already got a connection to them... */
     3774  if (peerIsInUse (tor->swarm, atom))
     3775    return false;
     3776
     3777  /* not if we just tried them already */
     3778  if ((now - atom->time) < getReconnectIntervalSecs (atom, now))
     3779    return false;
     3780
     3781  /* not if they're blocklisted */
     3782  if (isAtomBlocklisted (tor->session, atom))
     3783    return false;
     3784
     3785  /* not if they're banned... */
     3786  if (atom->flags2 & MYFLAG_BANNED)
     3787    return false;
     3788
     3789  return true;
    37573790}
    37583791
    37593792struct peer_candidate
    37603793{
    3761     uint64_t score;
    3762     tr_torrent * tor;
    3763     struct peer_atom * atom;
     3794  uint64_t score;
     3795  tr_torrent * tor;
     3796  struct peer_atom * atom;
    37643797};
    37653798
     
    37673800torrentWasRecentlyStarted (const tr_torrent * tor)
    37683801{
    3769     return difftime (tr_time (), tor->startDate) < 120;
     3802  return difftime (tr_time (), tor->startDate) < 120;
    37703803}
    37713804
     
    37733806addValToKey (uint64_t value, int width, uint64_t addme)
    37743807{
    3775     value = (value << (uint64_t)width);
    3776     value |= addme;
    3777     return value;
     3808  value = (value << (uint64_t)width);
     3809  value |= addme;
     3810  return value;
    37783811}
    37793812
     
    37823815getPeerCandidateScore (const tr_torrent * tor, const struct peer_atom * atom, uint8_t salt)
    37833816{
    3784     uint64_t i;
    3785     uint64_t score = 0;
    3786     const bool failed = atom->lastConnectionAt < atom->lastConnectionAttemptAt;
    3787 
    3788     /* prefer peers we've connected to, or never tried, over peers we failed to connect to. */
    3789     i = failed ? 1 : 0;
    3790     score = addValToKey (score, 1, i);
    3791 
    3792     /* prefer the one we attempted least recently (to cycle through all peers) */
    3793     i = atom->lastConnectionAttemptAt;
    3794     score = addValToKey (score, 32, i);
    3795 
    3796     /* prefer peers belonging to a torrent of a higher priority */
    3797     switch (tr_torrentGetPriority (tor)) {
    3798         case TR_PRI_HIGH:    i = 0; break;
    3799         case TR_PRI_NORMAL:  i = 1; break;
    3800         case TR_PRI_LOW:     i = 2; break;
    3801     }
    3802     score = addValToKey (score, 4, i);
    3803 
    3804     /* prefer recently-started torrents */
    3805     i = torrentWasRecentlyStarted (tor) ? 0 : 1;
    3806     score = addValToKey (score, 1, i);
    3807 
    3808     /* prefer torrents we're downloading with */
    3809     i = tr_torrentIsSeed (tor) ? 1 : 0;
    3810     score = addValToKey (score, 1, i);
    3811 
    3812     /* prefer peers that are known to be connectible */
    3813     i = (atom->flags & ADDED_F_CONNECTABLE) ? 0 : 1;
    3814     score = addValToKey (score, 1, i);
    3815 
    3816     /* prefer peers that we might have a chance of uploading to...
    3817        so lower seed probability is better */
    3818     if (atom->seedProbability == 100) i = 101;
    3819     else if (atom->seedProbability == -1) i = 100;
    3820     else i = atom->seedProbability;
    3821     score = addValToKey (score, 8, i);
    3822 
    3823     /* Prefer peers that we got from more trusted sources.
    3824      * lower `fromBest' values indicate more trusted sources */
    3825     score = addValToKey (score, 4, atom->fromBest);
    3826 
    3827     /* salt */
    3828     score = addValToKey (score, 8, salt);
    3829 
    3830     return score;
     3817  uint64_t i;
     3818  uint64_t score = 0;
     3819  const bool failed = atom->lastConnectionAt < atom->lastConnectionAttemptAt;
     3820
     3821  /* prefer peers we've connected to, or never tried, over peers we failed to connect to. */
     3822  i = failed ? 1 : 0;
     3823  score = addValToKey (score, 1, i);
     3824
     3825  /* prefer the one we attempted least recently (to cycle through all peers) */
     3826  i = atom->lastConnectionAttemptAt;
     3827  score = addValToKey (score, 32, i);
     3828
     3829  /* prefer peers belonging to a torrent of a higher priority */
     3830  switch (tr_torrentGetPriority (tor))
     3831    {
     3832      case TR_PRI_HIGH:    i = 0; break;
     3833      case TR_PRI_NORMAL:  i = 1; break;
     3834      case TR_PRI_LOW:     i = 2; break;
     3835    }
     3836  score = addValToKey (score, 4, i);
     3837
     3838  /* prefer recently-started torrents */
     3839  i = torrentWasRecentlyStarted (tor) ? 0 : 1;
     3840  score = addValToKey (score, 1, i);
     3841
     3842  /* prefer torrents we're downloading with */
     3843  i = tr_torrentIsSeed (tor) ? 1 : 0;
     3844  score = addValToKey (score, 1, i);
     3845
     3846  /* prefer peers that are known to be connectible */
     3847  i = (atom->flags & ADDED_F_CONNECTABLE) ? 0 : 1;
     3848  score = addValToKey (score, 1, i);
     3849
     3850  /* prefer peers that we might have a chance of uploading to...
     3851  so lower seed probability is better */
     3852  if (atom->seedProbability == 100) i = 101;
     3853  else if (atom->seedProbability == -1) i = 100;
     3854  else i = atom->seedProbability;
     3855  score = addValToKey (score, 8, i);
     3856
     3857  /* Prefer peers that we got from more trusted sources.
     3858   * lower `fromBest' values indicate more trusted sources */
     3859  score = addValToKey (score, 4, atom->fromBest);
     3860
     3861  /* salt */
     3862  score = addValToKey (score, 8, salt);
     3863
     3864  return score;
    38313865}
    38323866
     
    38643898checkBestScoresComeFirst (const struct peer_candidate * candidates, int n, int k)
    38653899{
    3866     int i;
    3867     uint64_t worstFirstScore = 0;
    3868     const int x = MIN (n, k) - 1;
    3869 
    3870     for (i=0; i<x; i++)
    3871         if (worstFirstScore < candidates[i].score)
    3872             worstFirstScore = candidates[i].score;
    3873 
    3874     for (i=0; i<x; i++)
    3875         assert (candidates[i].score <= worstFirstScore);
    3876 
    3877     for (i=x+1; i<n; i++)
    3878         assert (candidates[i].score >= worstFirstScore);
    3879 
    3880     return true;
     3900  int i;
     3901  uint64_t worstFirstScore = 0;
     3902  const int x = MIN (n, k) - 1;
     3903
     3904  for (i=0; i<x; i++)
     3905    if (worstFirstScore < candidates[i].score)
     3906      worstFirstScore = candidates[i].score;
     3907
     3908  for (i=0; i<x; i++)
     3909    assert (candidates[i].score <= worstFirstScore);
     3910
     3911  for (i=x+1; i<n; i++)
     3912    assert (candidates[i].score >= worstFirstScore);
     3913
     3914  return true;
    38813915}
    38823916#endif /* NDEBUG */
     
    38863920getPeerCandidates (tr_session * session, int * candidateCount, int max)
    38873921{
    3888     int atomCount;
    3889     int peerCount;
    3890     tr_torrent * tor;
    3891     struct peer_candidate * candidates;
    3892     struct peer_candidate * walk;
    3893     const time_t now = tr_time ();
    3894     const uint64_t now_msec = tr_time_msec ();
    3895     /* leave 5% of connection slots for incoming connections -- ticket #2609 */
    3896     const int maxCandidates = tr_sessionGetPeerLimit (session) * 0.95;
    3897 
    3898     /* count how many peers and atoms we've got */
    3899     tor= NULL;
    3900     atomCount = 0;
    3901     peerCount = 0;
    3902     while ((tor = tr_torrentNext (session, tor))) {
    3903         atomCount += tr_ptrArraySize (&tor->torrentPeers->pool);
    3904         peerCount += tr_ptrArraySize (&tor->torrentPeers->peers);
    3905     }
    3906 
    3907     /* don't start any new handshakes if we're full up */
    3908     if (maxCandidates <= peerCount) {
    3909         *candidateCount = 0;
    3910         return NULL;
    3911     }
    3912 
    3913     /* allocate an array of candidates */
    3914     walk = candidates = tr_new (struct peer_candidate, atomCount);
    3915 
    3916     /* populate the candidate array */
    3917     tor = NULL;
    3918     while ((tor = tr_torrentNext (session, tor)))
    3919     {
    3920         int i, nAtoms;
    3921         struct peer_atom ** atoms;
    3922 
    3923         if (!tor->torrentPeers->isRunning)
    3924             continue;
    3925 
    3926         /* if we've already got enough peers in this torrent... */
    3927         if (tr_torrentGetPeerLimit (tor) <= tr_ptrArraySize (&tor->torrentPeers->peers))
    3928             continue;
    3929 
    3930         /* if we've already got enough speed in this torrent... */
    3931         if (tr_torrentIsSeed (tor) && isBandwidthMaxedOut (&tor->bandwidth, now_msec, TR_UP))
    3932             continue;
    3933 
    3934         atoms = (struct peer_atom**) tr_ptrArrayPeek (&tor->torrentPeers->pool, &nAtoms);
    3935         for (i=0; i<nAtoms; ++i)
     3922  int atomCount;
     3923  int peerCount;
     3924  tr_torrent * tor;
     3925  struct peer_candidate * candidates;
     3926  struct peer_candidate * walk;
     3927  const time_t now = tr_time ();
     3928  const uint64_t now_msec = tr_time_msec ();
     3929  /* leave 5% of connection slots for incoming connections -- ticket #2609 */
     3930  const int maxCandidates = tr_sessionGetPeerLimit (session) * 0.95;
     3931
     3932  /* count how many peers and atoms we've got */
     3933  tor= NULL;
     3934  atomCount = 0;
     3935  peerCount = 0;
     3936  while ((tor = tr_torrentNext (session, tor)))
     3937    {
     3938      atomCount += tr_ptrArraySize (&tor->swarm->pool);
     3939      peerCount += tr_ptrArraySize (&tor->swarm->peers);
     3940    }
     3941
     3942  /* don't start any new handshakes if we're full up */
     3943  if (maxCandidates <= peerCount)
     3944    {
     3945      *candidateCount = 0;
     3946      return NULL;
     3947    }
     3948
     3949  /* allocate an array of candidates */
     3950  walk = candidates = tr_new (struct peer_candidate, atomCount);
     3951
     3952  /* populate the candidate array */
     3953  tor = NULL;
     3954  while ((tor = tr_torrentNext (session, tor)))
     3955    {
     3956      int i, nAtoms;
     3957      struct peer_atom ** atoms;
     3958
     3959      if (!tor->swarm->isRunning)
     3960        continue;
     3961
     3962      /* if we've already got enough peers in this torrent... */
     3963      if (tr_torrentGetPeerLimit (tor) <= tr_ptrArraySize (&tor->swarm->peers))
     3964        continue;
     3965
     3966      /* if we've already got enough speed in this torrent... */
     3967      if (tr_torrentIsSeed (tor) && isBandwidthMaxedOut (&tor->bandwidth, now_msec, TR_UP))
     3968        continue;
     3969
     3970      atoms = (struct peer_atom**) tr_ptrArrayPeek (&tor->swarm->pool, &nAtoms);
     3971      for (i=0; i<nAtoms; ++i)
    39363972        {
    3937             struct peer_atom * atom = atoms[i];
    3938 
    3939             if (isPeerCandidate (tor, atom, now))
     3973          struct peer_atom * atom = atoms[i];
     3974
     3975          if (isPeerCandidate (tor, atom, now))
    39403976            {
    3941                 const uint8_t salt = tr_cryptoWeakRandInt (1024);
    3942                 walk->tor = tor;
    3943                 walk->atom = atom;
    3944                 walk->score = getPeerCandidateScore (tor, atom, salt);
    3945                 ++walk;
     3977              const uint8_t salt = tr_cryptoWeakRandInt (1024);
     3978              walk->tor = tor;
     3979              walk->atom = atom;
     3980              walk->score = getPeerCandidateScore (tor, atom, salt);
     3981              ++walk;
    39463982            }
    39473983        }
    39483984    }
    39493985
    3950     *candidateCount = walk - candidates;
    3951     if (walk != candidates)
    3952         selectPeerCandidates (candidates, walk-candidates, max);
    3953 
    3954     assert (checkBestScoresComeFirst (candidates, *candidateCount, max));
    3955 
    3956     return candidates;
    3957 }
    3958 
    3959 static void
    3960 initiateConnection (tr_peerMgr * mgr, Torrent * t, struct peer_atom * atom)
    3961 {
    3962     tr_peerIo * io;
    3963     const time_t now = tr_time ();
    3964     bool utp = tr_sessionIsUTPEnabled (mgr->session) && !atom->utp_failed;
    3965 
    3966     if (atom->fromFirst == TR_PEER_FROM_PEX)
    3967         /* PEX has explicit signalling for uTP support.  If an atom
    3968            originally came from PEX and doesn't have the uTP flag, skip the
    3969            uTP connection attempt.  Are we being optimistic here? */
    3970         utp = utp && (atom->flags & ADDED_F_UTP_FLAGS);
    3971 
    3972     tordbg (t, "Starting an OUTGOING%s connection with %s",
    3973             utp ? " µTP" : "",
    3974             tr_atomAddrStr (atom));
    3975 
    3976     io = tr_peerIoNewOutgoing (mgr->session,
    3977                                &mgr->session->bandwidth,
    3978                                &atom->addr,
    3979                                atom->port,
    3980                                t->tor->info.hash,
    3981                                t->tor->completeness == TR_SEED,
    3982                                utp);
    3983 
    3984     if (io == NULL)
    3985     {
    3986         tordbg (t, "peerIo not created; marking peer %s as unreachable",
    3987                 tr_atomAddrStr (atom));
    3988         atom->flags2 |= MYFLAG_UNREACHABLE;
    3989         atom->numFails++;
    3990     }
    3991     else
    3992     {
    3993         tr_handshake * handshake = tr_handshakeNew (io,
    3994                                                     mgr->session->encryptionMode,
    3995                                                     myHandshakeDoneCB,
    3996                                                     mgr);
    3997 
    3998         assert (tr_peerIoGetTorrentHash (io));
    3999 
    4000         tr_peerIoUnref (io); /* balanced by the initial ref
    4001                                  in tr_peerIoNewOutgoing () */
    4002 
    4003         tr_ptrArrayInsertSorted (&t->outgoingHandshakes, handshake,
    4004                                  handshakeCompare);
    4005     }
    4006 
    4007     atom->lastConnectionAttemptAt = now;
    4008     atom->time = now;
     3986  *candidateCount = walk - candidates;
     3987  if (walk != candidates)
     3988    selectPeerCandidates (candidates, walk-candidates, max);
     3989
     3990  assert (checkBestScoresComeFirst (candidates, *candidateCount, max));
     3991  return candidates;
     3992}
     3993
     3994static void
     3995initiateConnection (tr_peerMgr * mgr, tr_swarm * s, struct peer_atom * atom)
     3996{
     3997  tr_peerIo * io;
     3998  const time_t now = tr_time ();
     3999  bool utp = tr_sessionIsUTPEnabled (mgr->session) && !atom->utp_failed;
     4000
     4001  if (atom->fromFirst == TR_PEER_FROM_PEX)
     4002    /* PEX has explicit signalling for uTP support.  If an atom
     4003       originally came from PEX and doesn't have the uTP flag, skip the
     4004       uTP connection attempt.  Are we being optimistic here? */
     4005    utp = utp && (atom->flags & ADDED_F_UTP_FLAGS);
     4006
     4007  tordbg (s, "Starting an OUTGOING%s connection with %s",
     4008          utp ? " µTP" : "", tr_atomAddrStr (atom));
     4009
     4010  io = tr_peerIoNewOutgoing (mgr->session,
     4011                             &mgr->session->bandwidth,
     4012                             &atom->addr,
     4013                             atom->port,
     4014                             s->tor->info.hash,
     4015                             s->tor->completeness == TR_SEED,
     4016                             utp);
     4017
     4018  if (io == NULL)
     4019    {
     4020      tordbg (s, "peerIo not created; marking peer %s as unreachable", tr_atomAddrStr (atom));
     4021      atom->flags2 |= MYFLAG_UNREACHABLE;
     4022      atom->numFails++;
     4023    }
     4024  else
     4025    {
     4026      tr_handshake * handshake = tr_handshakeNew (io,
     4027                                                  mgr->session->encryptionMode,
     4028                                                  myHandshakeDoneCB,
     4029                                                  mgr);
     4030
     4031      assert (tr_peerIoGetTorrentHash (io));
     4032
     4033      tr_peerIoUnref (io); /* balanced by the initial ref
     4034                              in tr_peerIoNewOutgoing () */
     4035
     4036      tr_ptrArrayInsertSorted (&s->outgoingHandshakes, handshake,
     4037                               handshakeCompare);
     4038    }
     4039
     4040  atom->lastConnectionAttemptAt = now;
     4041  atom->time = now;
    40094042}
    40104043
     
    40134046{
    40144047#if 0
    4015     fprintf (stderr, "Starting an OUTGOING connection with %s - [%s] seedProbability==%d; %s, %s\n",
    4016              tr_atomAddrStr (c->atom),
    4017              tr_torrentName (c->tor),
     4048  fprintf (stderr, "Starting an OUTGOING connection with %s - [%s] seedProbability==%d; %s, %s\n",
     4049           tr_atomAddrStr (c->atom),
     4050           tr_torrentName (c->tor),
    40184051           (int)c->atom->seedProbability,
    4019              tr_torrentIsPrivate (c->tor) ? "private" : "public",
    4020              tr_torrentIsSeed (c->tor) ? "seed" : "downloader");
     4052           tr_torrentIsPrivate (c->tor) ? "private" : "public",
     4053           tr_torrentIsSeed (c->tor) ? "seed" : "downloader");
    40214054#endif
    40224055
    4023     initiateConnection (mgr, c->tor->torrentPeers, c->atom);
     4056  initiateConnection (mgr, c->tor->swarm, c->atom);
    40244057}
    40254058
     
    40274060makeNewPeerConnections (struct tr_peerMgr * mgr, const int max)
    40284061{
    4029     int i, n;
    4030     struct peer_candidate * candidates;
    4031 
    4032     candidates = getPeerCandidates (mgr->session, &n, max);
    4033 
    4034     for (i=0; i<n && i<max; ++i)
    4035         initiateCandidateConnection (mgr, &candidates[i]);
    4036 
    4037     tr_free (candidates);
    4038 }
     4062  int i, n;
     4063  struct peer_candidate * candidates;
     4064
     4065  candidates = getPeerCandidates (mgr->session, &n, max);
     4066
     4067  for (i=0; i<n && i<max; ++i)
     4068    initiateCandidateConnection (mgr, &candidates[i]);
     4069
     4070  tr_free (candidates);
     4071}
  • trunk/libtransmission/torrent.h

    r13879 r13890  
    264264    struct tr_bandwidth        bandwidth;
    265265
    266     struct tr_torrent_peers  * torrentPeers;
     266    struct tr_swarm          * swarm;
    267267
    268268    float                      desiredRatio;
Note: See TracChangeset for help on using the changeset viewer.