Changeset 13890
- Timestamp:
- Jan 27, 2013, 9:03:52 PM (8 years ago)
- Location:
- trunk/libtransmission
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/libtransmission/peer-mgr.c
r13879 r13890 183 183 184 184 /** @brief Opaque, per-torrent data structure for peer connection information */ 185 typedef struct tr_ torrent_peers185 typedef struct tr_swarm 186 186 { 187 187 tr_ptrArray outgoingHandshakes; /* tr_handshake */ … … 224 224 int endgame; 225 225 } 226 Torrent;226 tr_swarm; 227 227 228 228 struct tr_peerMgr … … 269 269 270 270 static inline void 271 torrentLock (Torrent * torrent)272 { 273 managerLock ( torrent->manager);271 swarmLock (tr_swarm * swarm) 272 { 273 managerLock (swarm->manager); 274 274 } 275 275 276 276 static inline void 277 torrentUnlock (Torrent * torrent)278 { 279 managerUnlock ( torrent->manager);277 swarmUnlock (tr_swarm * swarm) 278 { 279 managerUnlock (swarm->manager); 280 280 } 281 281 282 282 static inline int 283 torrentIsLocked (const Torrent * t)284 { 285 return tr_sessionIsLocked ( t->manager->session);283 swarmIsLocked (const tr_swarm * swarm) 284 { 285 return tr_sessionIsLocked (swarm->manager->session); 286 286 } 287 287 … … 341 341 } 342 342 343 static Torrent*344 getExisting Torrent(tr_peerMgr * manager,345 343 static tr_swarm * 344 getExistingSwarm (tr_peerMgr * manager, 345 const uint8_t * hash) 346 346 { 347 347 tr_torrent * tor = tr_torrentFindFromHash (manager->session, hash); 348 348 349 return tor == NULL ? NULL : tor-> torrentPeers;349 return tor == NULL ? NULL : tor->swarm; 350 350 } 351 351 … … 357 357 358 358 static struct peer_atom* 359 getExistingAtom (const Torrent * t,359 getExistingAtom (const tr_swarm * cswarm, 360 360 const tr_address * addr) 361 361 { 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); 364 364 } 365 365 366 366 static bool 367 peerIsInUse (const Torrent * ct, const struct peer_atom * atom)368 { 369 Torrent * t = (Torrent*) ct;370 371 assert ( torrentIsLocked (t));367 peerIsInUse (const tr_swarm * cs, const struct peer_atom * atom) 368 { 369 tr_swarm * s = (tr_swarm*) cs; 370 371 assert (swarmIsLocked (s)); 372 372 373 373 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); 376 376 } 377 377 … … 397 397 398 398 static tr_peer* 399 getPeer ( Torrent * torrent, struct peer_atom * atom)399 getPeer (tr_swarm * s, struct peer_atom * atom) 400 400 { 401 401 tr_peer * peer; 402 402 403 assert ( torrentIsLocked (torrent));403 assert (swarmIsLocked (s)); 404 404 405 405 peer = atom->peer; … … 408 408 { 409 409 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); 413 413 } 414 414 … … 416 416 } 417 417 418 static void peerDeclinedAllRequests ( Torrent*, const tr_peer *);418 static void peerDeclinedAllRequests (tr_swarm *, const tr_peer *); 419 419 420 420 void … … 423 423 assert (peer != NULL); 424 424 425 peerDeclinedAllRequests (tor-> torrentPeers, peer);425 peerDeclinedAllRequests (tor->swarm, peer); 426 426 427 427 if (peer->msgs != NULL) … … 442 442 443 443 static void 444 peerDelete ( Torrent * t, tr_peer * peer)445 { 446 tr_peerDestruct ( t->tor, peer);444 peerDelete (tr_swarm * s, tr_peer * peer) 445 { 446 tr_peerDestruct (s->tor, peer); 447 447 tr_free (peer); 448 448 } 449 449 450 static bool451 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)450 static inline bool 451 replicationExists (const tr_swarm * s) 452 { 453 return s->pieceReplication != NULL; 454 } 455 456 static void 457 replicationFree (tr_swarm * s) 458 { 459 tr_free (s->pieceReplication); 460 s->pieceReplication = NULL; 461 s->pieceReplicationSize = 0; 462 } 463 464 static void 465 replicationNew (tr_swarm * s) 466 466 { 467 467 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); 476 476 477 477 for (piece_i=0; piece_i<piece_count; ++piece_i) … … 484 484 ++r; 485 485 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 490 static void 491 swarmFree (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); 511 511 } 512 512 … … 514 514 515 515 static void 516 rebuildWebseedArray ( Torrent * t, tr_torrent * tor)516 rebuildWebseedArray (tr_swarm * s, tr_torrent * tor) 517 517 { 518 518 unsigned int i; … … 520 520 521 521 /* 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; 524 524 525 525 /* repopulate it */ 526 526 for (i = 0; i < inf->webseedCount; ++i) 527 527 { 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 533 static tr_swarm * 534 swarmNew (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; 549 549 } 550 550 … … 628 628 { 629 629 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); 632 632 for (i=0; i<n; ++i) 633 633 { 634 struct peer_atom * atom = tr_ptrArrayNth (& t->pool, i);634 struct peer_atom * atom = tr_ptrArrayNth (&s->pool, i); 635 635 atom->blocklisted = -1; 636 636 } … … 674 674 675 675 static void 676 atomSetSeed (const Torrent * t, struct peer_atom * atom)676 atomSetSeed (const tr_swarm * s, struct peer_atom * atom) 677 677 { 678 678 if (!atomIsSeed (atom)) 679 679 { 680 tordbg ( t, "marking peer %s as a seed", tr_atomAddrStr (atom));680 tordbg (s, "marking peer %s as a seed", tr_atomAddrStr (atom)); 681 681 682 682 atomSetSeedProbability (atom, 100); … … 690 690 { 691 691 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); 694 694 695 695 if (atom) … … 702 702 tr_peerMgrSetUtpSupported (tr_torrent * tor, const tr_address * addr) 703 703 { 704 struct peer_atom * atom = getExistingAtom (tor-> torrentPeers, addr);704 struct peer_atom * atom = getExistingAtom (tor->swarm, addr); 705 705 706 706 if (atom) … … 711 711 tr_peerMgrSetUtpFailed (tr_torrent *tor, const tr_address *addr, bool failed) 712 712 { 713 struct peer_atom * atom = getExistingAtom (tor-> torrentPeers, addr);713 struct peer_atom * atom = getExistingAtom (tor->swarm, addr); 714 714 715 715 if (atom) … … 723 723 *** There are two data structures associated with managing block requests: 724 724 *** 725 *** 1. Torrent::requests, an array of "struct block_request" which keeps725 *** 1. tr_swarm::requests, an array of "struct block_request" which keeps 726 726 *** track of which blocks have been requested, and when, and by which peers. 727 727 *** This is list is used for (a) cancelling requests that have been pending 728 728 *** for too long and (b) avoiding duplicate requests before endgame. 729 729 *** 730 *** 2. Torrent::pieces, an array of "struct weighted_piece" which lists the730 *** 2. tr_swarm::pieces, an array of "struct weighted_piece" which lists the 731 731 *** pieces that we want to request. It's used to decide which blocks to 732 732 *** return next when tr_peerMgrGetBlockRequests () is called. … … 740 740 compareReqByBlock (const void * va, const void * vb) 741 741 { 742 743 744 745 746 747 748 749 750 751 752 753 754 } 755 756 static void 757 requestListAdd ( Torrent * t, tr_block_index_t block, tr_peer * peer)758 { 759 760 761 762 if (t->requestCount + 1 >= t->requestAlloc)763 { 764 765 t->requestAlloc += CHUNK_SIZE;766 t->requests = tr_renew (struct block_request,767 t->requests, t->requestAlloc);768 } 769 770 771 772 773 774 775 776 777 778 const int pos = tr_lowerBound (&key, t->requests, t->requestCount,779 780 781 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 789 { 790 791 792 } 793 794 795 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 756 static void 757 requestListAdd (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);*/ 797 797 } 798 798 799 799 static struct block_request * 800 requestListLookup ( Torrent * t, tr_block_index_t block, const tr_peer * peer)801 { 802 803 804 805 806 return bsearch (&key, t->requests, t->requestCount,807 808 800 requestListLookup (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); 809 809 } 810 810 … … 814 814 */ 815 815 static void 816 getBlockRequestPeers ( Torrent * t, tr_block_index_t block,816 getBlockRequestPeers (tr_swarm * s, tr_block_index_t block, 817 817 tr_ptrArray * peerArr) 818 818 { 819 820 821 822 823 824 825 pos = tr_lowerBound (&key, t->requests, t->requestCount,826 827 828 829 830 831 for (i = pos; i < t->requestCount; ++i)832 { 833 if (t->requests[i].block != block)834 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); 836 836 } 837 837 } … … 840 840 decrementPendingReqCount (const struct block_request * b) 841 841 { 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 847 static void 848 requestListRemove (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", 865 866 (unsigned long)block, tr_atomAddrStr (peer->atom), t->requestCount);*/ 866 867 } … … 868 869 869 870 static int 870 countActiveWebseeds (const Torrent * t)871 { 872 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 877 878 879 880 871 countActiveWebseeds (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; 881 882 } 882 883 883 884 static bool 884 testForEndgame (const Torrent * t)885 { 886 887 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 900 t->endgame = 0;901 } 902 else if (!t->endgame) /* only recalculate when endgame first begins */903 { 904 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 909 910 911 912 913 914 numDownloading += countActiveWebseeds (t);915 916 917 t->endgame = t->requestCount / MAX (numDownloading, 1);885 testForEndgame (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 893 static void 894 updateEndgame (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); 918 919 } 919 920 } … … 927 928 928 929 static inline void 929 invalidatePieceSorting ( Torrent * t)930 { 931 t->pieceSortState = PIECES_UNSORTED;930 invalidatePieceSorting (tr_swarm * s) 931 { 932 s->pieceSortState = PIECES_UNSORTED; 932 933 } 933 934 … … 937 938 938 939 static void 939 setComparePieceByWeightTorrent ( Torrent * t)940 { 941 if (!replicationExists (t))942 replicationNew (t);943 944 weightTorrent = t->tor;945 weightReplication = t->pieceReplication;940 setComparePieceByWeightTorrent (tr_swarm * s) 941 { 942 if (!replicationExists (s)) 943 replicationNew (s); 944 945 weightTorrent = s->tor; 946 weightReplication = s->pieceReplication; 946 947 } 947 948 … … 951 952 comparePieceByWeight (const void * va, const void * vb) 952 953 { 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 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; 987 988 } 988 989 … … 990 991 comparePieceByIndex (const void * va, const void * vb) 991 992 { 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 1000 static void 1001 pieceListSort (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; 1015 1017 } 1016 1018 … … 1065 1067 1066 1068 static struct weighted_piece * 1067 pieceListLookup ( Torrent * t, tr_piece_index_t index)1068 { 1069 1070 1071 for (i=0; i<t->pieceCount; ++i)1072 if (t->pieces[i].index == index)1073 return &t->pieces[i];1074 1075 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 1102 1103 1104 1069 pieceListLookup (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 1080 static void 1081 pieceListRebuild (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); 1105 1107 } 1106 1108 1107 1108 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) 1110 1112 { 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++; 1125 1128 } 1126 1129 1127 tr_free (t->pieces);1130 tr_free (s->pieces); 1128 1131 } 1129 1132 1130 t->pieces = pieces;1131 t->pieceCount = pieceCount;1132 1133 pieceListSort (t, PIECES_SORTED_BY_WEIGHT);1134 1135 1136 1137 } 1138 } 1139 1140 static void 1141 pieceListRemovePiece ( Torrent * t, tr_piece_index_t piece)1142 { 1143 1144 1145 if ((p = pieceListLookup (t, piece)))1146 { 1147 const int pos = p - t->pieces;1148 1149 tr_removeElementFromArray (t->pieces,1150 1151 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 1143 static void 1144 pieceListRemovePiece (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) 1155 1158 { 1156 tr_free (t->pieces);1157 t->pieces = NULL;1159 tr_free (s->pieces); 1160 s->pieces = NULL; 1158 1161 } 1159 1162 } … … 1161 1164 1162 1165 static void 1163 pieceListResortPiece ( Torrent * t, struct weighted_piece * p)1164 { 1165 1166 1167 1168 1169 1170 1171 1172 pos = p - t->pieces;1173 setComparePieceByWeightTorrent (t);1174 1175 1176 if (isSorted && (pos < t->pieceCount - 1) && (comparePieceByWeight (p, p+1) > 0))1177 1178 1179 if (t->pieceSortState != PIECES_SORTED_BY_WEIGHT)1180 { 1181 pieceListSort (t, PIECES_SORTED_BY_WEIGHT);1182 1183 } 1184 1185 1186 1187 { 1188 1189 1190 1191 tr_removeElementFromArray (t->pieces,1192 1193 1194 t->pieceCount--);1195 1196 pos = tr_lowerBound (&tmp, t->pieces, t->pieceCount,1197 1198 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 1214 const tr_piece_index_t index = tr_torBlockPiece (t->tor, block);1215 1216 if (((p = pieceListLookup (t, index))) && (p->requestCount > 0))1217 { 1218 1219 pieceListResortPiece (t, p);1166 pieceListResortPiece (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 1213 static void 1214 pieceListRemoveRequest (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); 1220 1223 } 1221 1224 } … … 1233 1236 */ 1234 1237 static 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 1241 ++t->pieceReplication[index];1242 1243 1244 if (t->pieceSortState == PIECES_SORTED_BY_WEIGHT)1245 pieceListResortPiece (t, pieceListLookup (t, index));1238 tr_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)); 1246 1249 } 1247 1250 … … 1250 1253 */ 1251 1254 static void 1252 tr_incrReplicationFromBitfield ( Torrent * t, const tr_bitfield * b)1253 { 1254 1255 uint16_t * rep = t->pieceReplication;1256 const size_t n = t->tor->info.pieceCount;1257 1258 assert (replicationExists (t));1259 1260 1261 1262 1263 1264 if (t->pieceSortState == PIECES_SORTED_BY_WEIGHT)1265 invalidatePieceSorting (t);1255 tr_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); 1266 1269 } 1267 1270 … … 1270 1273 */ 1271 1274 static void 1272 tr_incrReplication ( Torrent * t)1273 { 1274 1275 const int n = t->pieceReplicationSize;1276 1277 assert (replicationExists (t));1278 assert (t->pieceReplicationSize == t->tor->info.pieceCount);1279 1280 1281 ++t->pieceReplication[i];1275 tr_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]; 1282 1285 } 1283 1286 … … 1286 1289 */ 1287 1290 static void 1288 tr_decrReplicationFromBitfield ( Torrent * t, const tr_bitfield * b)1289 { 1290 1291 const int n = t->pieceReplicationSize;1292 1293 assert (replicationExists (t));1294 assert (t->pieceReplicationSize == t->tor->info.pieceCount);1295 1296 1297 { 1298 1299 --t->pieceReplication[i];1300 } 1301 1302 { 1303 1304 1305 --t->pieceReplication[i];1306 1307 if (t->pieceSortState == PIECES_SORTED_BY_WEIGHT)1308 invalidatePieceSorting (t);1291 tr_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); 1309 1312 } 1310 1313 } … … 1317 1320 tr_peerMgrRebuildRequests (tr_torrent * tor) 1318 1321 { 1319 1320 1321 pieceListRebuild (tor->torrentPeers);1322 assert (tr_isTorrent (tor)); 1323 1324 pieceListRebuild (tor->swarm); 1322 1325 } 1323 1326 … … 1330 1333 bool get_intervals) 1331 1334 { 1332 1333 1334 Torrent * t;1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 t = tor->torrentPeers;1347 1348 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 1363 1364 1365 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)) 1366 1369 { 1367 1368 1369 1370 1371 1372 1373 1374 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) 1375 1378 { 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) 1381 1394 continue; 1382 1395 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) 1388 1413 { 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; 1406 1415 } 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]; 1411 1422 } 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; 1417 1428 } 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; 1427 1433 } 1428 1434 1429 1435 tr_ptrArrayDestruct (&peerArr, NULL); 1430 1436 } 1431 1437 } 1432 1438 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) 1443 1450 { 1444 1445 1446 1447 const int newpos = tr_lowerBound (&t->pieces[i], &t->pieces[i + 1],1448 t->pieceCount - (i + 1),1449 1450 1451 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) 1452 1459 { 1453 const struct weighted_piece piece = t->pieces[i];1454 memmove (&t->pieces[i],1455 &t->pieces[i + 1],1456 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; 1458 1465 } 1459 1466 } 1460 1467 } 1461 1468 1462 1463 1469 assertWeightedPiecesAreSorted (t); 1470 *numgot = got; 1464 1471 } 1465 1472 … … 1469 1476 tr_block_index_t block) 1470 1477 { 1471 const Torrent * t = tor->torrentPeers; 1472 return requestListLookup ((Torrent*)t, block, peer) != NULL; 1478 return requestListLookup ((tr_swarm*)tor->swarm, block, peer) != NULL; 1473 1479 } 1474 1480 … … 1491 1497 tor = NULL; 1492 1498 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); 1494 1500 if (cancel_buflen > 0) 1495 1501 cancel = tr_new (struct block_request, cancel_buflen); … … 1499 1505 while ((tor = tr_torrentNext (mgr->session, tor))) 1500 1506 { 1501 Torrent * t = tor->torrentPeers;1502 const int n = t->requestCount;1507 tr_swarm * s = tor->swarm; 1508 const int n = s->requestCount; 1503 1509 if (n > 0) 1504 1510 { … … 1508 1514 const struct block_request * end; 1509 1515 1510 for (it= t->requests, end=it+n; it!=end; ++it)1516 for (it=s->requests, end=it+n; it!=end; ++it) 1511 1517 { 1512 1518 if ((it->sentAt <= too_old) && it->peer->msgs && !tr_peerMsgsIsReadingBlock (it->peer->msgs, it->block)) … … 1514 1520 else 1515 1521 { 1516 if (it != & t->requests[keepCount])1517 t->requests[keepCount] = *it;1522 if (it != &s->requests[keepCount]) 1523 s->requests[keepCount] = *it; 1518 1524 keepCount++; 1519 1525 } … … 1521 1527 1522 1528 /* prune out the ones we aren't keeping */ 1523 t->requestCount = keepCount;1529 s->requestCount = keepCount; 1524 1530 1525 1531 /* send cancel messages for all the "cancel" ones */ … … 1534 1540 /* decrement the pending request counts for the timed-out blocks */ 1535 1541 for (it=cancel, end=it+cancelCount; it!=end; ++it) 1536 pieceListRemoveRequest ( t, it->block);1542 pieceListRemoveRequest (s, it->block); 1537 1543 } 1538 1544 } … … 1544 1550 1545 1551 static void 1546 addStrike ( Torrent * t, tr_peer * peer)1547 { 1548 tordbg (t, "increasing peer %s strike count to %d",1549 1550 1551 1552 { 1553 1554 1555 1556 tordbg (t, "banning peer %s", tr_atomAddrStr (atom));1557 } 1558 } 1559 1560 static void 1561 peerSuggestedPiece ( Torrent * tUNUSED,1552 addStrike (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 1566 static void 1567 peerSuggestedPiece (tr_swarm * s UNUSED, 1562 1568 tr_peer * peer UNUSED, 1563 1569 tr_piece_index_t pieceIndex UNUSED, … … 1609 1615 1610 1616 static void 1611 removeRequestFromTables ( Torrent * t, tr_block_index_t block, const tr_peer * peer)1612 { 1613 requestListRemove (t, block, peer);1614 pieceListRemoveRequest (t, block);1617 removeRequestFromTables (tr_swarm * s, tr_block_index_t block, const tr_peer * peer) 1618 { 1619 requestListRemove (s, block, peer); 1620 pieceListRemoveRequest (s, block); 1615 1621 } 1616 1622 … … 1618 1624 either way we need to remove all its requests */ 1619 1625 static void 1620 peerDeclinedAllRequests ( Torrent * t, const tr_peer * peer)1621 { 1622 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 1630 removeRequestFromTables (t, blocks[i], peer);1631 1632 1633 } 1634 1635 static void 1636 cancelAllRequestsForBlock ( struct tr_torrent_peers * t,1637 tr_block_index_t 1638 tr_peer 1626 peerDeclinedAllRequests (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 1641 static void 1642 cancelAllRequestsForBlock (tr_swarm * s, 1643 tr_block_index_t block, 1644 tr_peer * no_notify) 1639 1645 { 1640 1646 int i; … … 1644 1650 1645 1651 peerArr = TR_PTR_ARRAY_INIT; 1646 getBlockRequestPeers ( t, block, &peerArr);1652 getBlockRequestPeers (s, block, &peerArr); 1647 1653 peers = (tr_peer **) tr_ptrArrayPeek (&peerArr, &peerCount); 1648 1654 for (i=0; i<peerCount; ++i) … … 1656 1662 } 1657 1663 1658 removeRequestFromTables ( t, block, p);1664 removeRequestFromTables (s, block, p); 1659 1665 } 1660 1666 … … 1668 1674 int peerCount; 1669 1675 tr_peer ** peers; 1670 struct tr_torrent_peers * t = tor->torrentPeers;1676 tr_swarm * s = tor->swarm; 1671 1677 1672 1678 /* 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); 1675 1681 for (i=0; i<peerCount; ++i) 1676 1682 tr_peerMsgsHave (peers[i]->msgs, p); 1677 1683 1678 1684 /* 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 * v t)1685 { 1686 Torrent * t = vt;1687 1688 torrentLock (t);1689 1690 1691 1692 1693 { 1694 1685 pieceListRemovePiece (s, p); 1686 s->needsCompletenessCheck = true; 1687 } 1688 1689 static void 1690 peerCallbackFunc (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: 1695 1701 { 1696 1697 tr_torrent * tor = t->tor;1698 1699 1702 const time_t now = tr_time (); 1703 tr_torrent * tor = s->tor; 1704 1705 if (e->wasPieceData) 1700 1706 { 1701 1702 1703 1704 1707 tor->uploadedCur += e->length; 1708 tr_announcerAddBytes (tor, TR_ANN_UP, e->length); 1709 tr_torrentSetActivityDate (tor, now); 1710 tr_torrentSetDirty (tor); 1705 1711 } 1706 1712 1707 1708 1709 1710 1711 1712 1713 1714 1715 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; 1716 1722 } 1717 1723 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); 1722 1791 } 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; 1752 1802 } 1753 1803 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: 1772 1805 { 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; 1792 1812 } 1793 1813 1794 case TR_PEER_CLIENT_GOT_BLOCK: 1814 case TR_PEER_ERROR: 1815 if ((e->err == ERANGE) || (e->err == EMSGSIZE) || (e->err == ENOTCONN)) 1795 1816 { 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)); 1802 1821 } 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); 1823 1833 } 1824 1834 … … 1842 1852 1843 1853 static void 1844 ensureAtomExists ( Torrent * t,1854 ensureAtomExists (tr_swarm * s, 1845 1855 const tr_address * addr, 1846 1856 const tr_port port, … … 1849 1859 const uint8_t from) 1850 1860 { 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) 1866 1887 a->fromBest = from; 1867 a->shelf_date = tr_time () + getDefaultShelfLife (from) + jitter; 1868 a->blocklisted = -1;1888 1889 if (a->seedProbability == -1) 1869 1890 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; 1883 1893 } 1884 1894 } … … 1887 1897 getMaxPeerCount (const tr_torrent * tor) 1888 1898 { 1889 1899 return tor->maxConnectedPeers; 1890 1900 } 1891 1901 1892 1902 static int 1893 getPeerCount (const Torrent * t)1894 { 1895 return tr_ptrArraySize (&t->peers);/* + tr_ptrArraySize (&t->outgoingHandshakes); */1903 getPeerCount (const tr_swarm * s) 1904 { 1905 return tr_ptrArraySize (&s->peers);/* + tr_ptrArraySize (&t->outgoingHandshakes); */ 1896 1906 } 1897 1907 … … 1905 1915 void * vmanager) 1906 1916 { 1907 boolok = isConnected;1908 boolsuccess = false;1909 tr_portport;1910 1911 tr_peerMgr* manager = vmanager;1912 Torrent * t;1913 tr_handshake* ours;1914 1915 1916 1917 1918 t= tr_peerIoHasTorrentHash (io)1919 ? getExistingTorrent(manager, tr_peerIoGetTorrentHash (io))1920 1921 1922 1923 1924 1925 else if (t)1926 ours = tr_ptrArrayRemoveSorted (&t->outgoingHandshakes,1927 1928 1929 1930 1931 1932 1933 1934 if (t)1935 torrentLock (t);1936 1937 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) 1942 1952 { 1943 struct peer_atom * atom = getExistingAtom (t, addr);1944 1953 struct peer_atom * atom = getExistingAtom (s, addr); 1954 if (atom) 1945 1955 { 1946 1947 1948 1956 ++atom->numFails; 1957 1958 if (!readAnythingFromPeer) 1949 1959 { 1950 tordbg (t, "marking peer %s as unreachable... numFails is %d", tr_atomAddrStr (atom), (int)atom->numFails);1951 1960 tordbg (s, "marking peer %s as unreachable... numFails is %d", tr_atomAddrStr (atom), (int)atom->numFails); 1961 atom->flags2 |= MYFLAG_UNREACHABLE; 1952 1962 } 1953 1963 } 1954 1964 } 1955 1965 } 1956 1957 { 1958 1959 1960 ensureAtomExists (t, addr, port, 0, -1, TR_PEER_FROM_INCOMING);1961 atom = getExistingAtom (t, addr);1962 1963 1964 1965 1966 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)) 1967 1977 { 1968 1969 1978 atom->flags |= ADDED_F_CONNECTABLE; 1979 atom->flags2 &= ~MYFLAG_UNREACHABLE; 1970 1980 } 1971 1981 1972 1973 1974 1975 1976 1977 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) 1978 1988 { 1979 tordbg (t, "banned peer %s tried to reconnect",1980 1989 tordbg (s, "banned peer %s tried to reconnect", 1990 tr_atomAddrStr (atom)); 1981 1991 } 1982 else if (tr_peerIoIsIncoming (io) 1983 && (getPeerCount (t) >= getMaxPeerCount (t->tor))) 1984 1992 else if (tr_peerIoIsIncoming (io) && (getPeerCount (s) >= getMaxPeerCount (s->tor))) 1985 1993 { 1986 1994 } 1987 1995 else 1988 1996 { 1989 1990 1991 1997 tr_peer * peer = atom->peer; 1998 1999 if (peer) /* we already have this peer */ 1992 2000 { 1993 2001 } 1994 2002 else 1995 2003 { 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); 2004 2013 } 2005 2014 2006 2015 peer->io = tr_handshakeStealIO (handshake); /* this steals its refcount too, which is 2007 2016 balanced by our unref in peerDelete () */ 2008 tr_peerIoSetParent (peer->io, &t->tor->bandwidth);2009 tr_peerMsgsNew (t->tor, peer, peerCallbackFunc, t);2010 2011 2017 tr_peerIoSetParent (peer->io, &s->tor->bandwidth); 2018 tr_peerMsgsNew (s->tor, peer, peerCallbackFunc, s); 2019 2020 success = true; 2012 2021 } 2013 2022 } 2014 2023 } 2015 2024 2016 if (t)2017 torrentUnlock (t);2018 2019 2025 if (s != NULL) 2026 swarmUnlock (s); 2027 2028 return success; 2020 2029 } 2021 2030 2022 2031 void 2023 tr_peerMgrAddIncoming (tr_peerMgr * manager,2024 tr_address * addr,2025 tr_port port,2026 int socket,2032 tr_peerMgrAddIncoming (tr_peerMgr * manager, 2033 tr_address * addr, 2034 tr_port port, 2035 int socket, 2027 2036 struct UTPSocket * utp_socket) 2028 2037 { 2029 2030 2031 2032 2033 2034 2035 2036 2037 { 2038 2039 2040 2041 2042 2043 } 2044 2045 { 2046 2047 2048 2049 2050 } 2051 2052 { 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 } 2068 2069 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); 2070 2079 } 2071 2080 … … 2074 2083 const tr_pex * pex, int8_t seedProbability) 2075 2084 { 2076 2077 { 2078 Torrent * t = tor->torrentPeers;2079 managerLock (t->manager);2080 2081 if (!tr_sessionIsAddressBlocked (t->manager->session, &pex->addr))2082 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); 2086 2095 } 2087 2096 } … … 2090 2099 tr_peerMgrMarkAllAsSeeds (tr_torrent * tor) 2091 2100 { 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 2096 2097 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++); 2099 2108 } 2100 2109 2101 2110 tr_pex * 2102 tr_peerMgrCompactToPex (const void *compact,2111 tr_peerMgrCompactToPex (const void * compact, 2103 2112 size_t compactLen, 2104 2113 const uint8_t * added_f, 2105 2114 size_t added_f_len, 2106 size_t *pexCount)2107 { 2108 size_ti;2109 size_tn = compactLen / 6;2110 2111 tr_pex *pex = tr_new0 (tr_pex, n);2112 2113 for (i = 0; i <n; ++i)2114 { 2115 2116 2117 2118 2119 2120 } 2121 2122 2123 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; 2124 2133 } 2125 2134 … … 2131 2140 size_t * pexCount) 2132 2141 { 2133 size_ti;2134 size_tn = compactLen / 18;2135 2136 tr_pex *pex = tr_new0 (tr_pex, n);2137 2138 for (i = 0; i <n; ++i)2139 { 2140 2141 2142 2143 2144 2145 } 2146 2147 2148 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; 2149 2158 } 2150 2159 2151 2160 tr_pex * 2152 tr_peerMgrArrayToPex (const void * array,2153 size_t arrayLen,2161 tr_peerMgrArrayToPex (const void * array, 2162 size_t arrayLen, 2154 2163 size_t * pexCount) 2155 2164 { 2156 size_ti;2157 size_tn = 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 2164 2165 2166 2167 } 2168 2169 2170 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; 2171 2180 } 2172 2181 … … 2180 2189 int i; 2181 2190 int n; 2182 Torrent * t = tor->torrentPeers;2191 tr_swarm * s = tor->swarm; 2183 2192 const uint32_t byteCount = tr_torPieceCountBytes (tor, pieceIndex); 2184 2193 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); 2188 2197 2189 2198 if (tr_bitfieldHas (&peer->blame, pieceIndex)) 2190 2199 { 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", 2192 2201 tr_atomAddrStr(peer->atom), pieceIndex, (int)peer->strikes + 1); 2193 addStrike ( t, peer);2202 addStrike (s, peer); 2194 2203 } 2195 2204 } … … 2202 2211 tr_pexCompare (const void * va, const void * vb) 2203 2212 { 2204 const tr_pex * a = va;2205 const tr_pex * b = vb;2206 int i;2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 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; 2218 2227 } 2219 2228 … … 2222 2231 compareAtomsByUsefulness (const void * va, const void *vb) 2223 2232 { 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 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; 2238 2247 } 2239 2248 … … 2241 2250 isAtomInteresting (const tr_torrent * tor, struct peer_atom * atom) 2242 2251 { 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)) 2255 2256 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; 2256 2265 } 2257 2266 … … 2263 2272 int maxCount) 2264 2273 { 2265 2266 2267 2268 2269 const Torrent * t = tor->torrentPeers;2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 managerLock (t->manager);2280 2281 2282 2283 2284 2285 2286 { 2287 2288 const tr_peer ** peers = (const tr_peer **) tr_ptrArrayBase (&t->peers);2289 atomCount = tr_ptrArraySize (&t->peers);2290 2291 2292 2293 } 2294 2295 { 2296 2297 struct peer_atom ** atomBase = (struct peer_atom**) tr_ptrArrayBase (&t->pool);2298 n = tr_ptrArraySize (&t->pool);2299 2300 2301 2302 2303 } 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 { 2316 2317 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) 2318 2327 { 2319 2320 2321 2322 2323 2324 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; 2325 2334 } 2326 2335 } 2327 2336 2328 2329 2330 2331 2332 2333 2334 2335 managerUnlock (t->manager);2336 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; 2337 2346 } 2338 2347 … … 2345 2354 createTimer (tr_session * session, int msec, void (*callback)(int, short, void *), void * cbdata) 2346 2355 { 2347 2348 2349 2356 struct event * timer = evtimer_new (session->event_base, callback, cbdata); 2357 tr_timerAddMsec (timer, msec); 2358 return timer; 2350 2359 } 2351 2360 … … 2353 2362 ensureMgrTimersExist (struct tr_peerMgr * m) 2354 2363 { 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 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); 2366 2375 } 2367 2376 … … 2369 2378 tr_peerMgrStartTorrent (tr_torrent * tor) 2370 2379 { 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 2395 static void 2396 stopSwarm (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)); 2403 2413 } 2404 2414 … … 2406 2416 tr_peerMgrStopTorrent (tr_torrent * tor) 2407 2417 { 2408 2409 2410 2411 stopTorrent (tor->torrentPeers);2418 assert (tr_isTorrent (tor)); 2419 assert (tr_torrentIsLocked (tor)); 2420 2421 stopSwarm (tor->swarm); 2412 2422 } 2413 2423 … … 2415 2425 tr_peerMgrAddTorrent (tr_peerMgr * manager, tr_torrent * tor) 2416 2426 { 2417 2418 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); 2422 2432 } 2423 2433 … … 2425 2435 tr_peerMgrRemoveTorrent (tr_torrent * tor) 2426 2436 { 2427 2428 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); 2432 2442 } 2433 2443 … … 2435 2445 tr_peerUpdateProgress (tr_torrent * tor, tr_peer * peer) 2436 2446 { 2437 2438 2439 2440 { 2441 2442 } 2443 2444 { 2445 2446 } 2447 2448 { 2449 2450 2451 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)) 2452 2462 { 2453 2463 peer->progress = true_count / tor->info.pieceCount; 2454 2464 } 2455 2465 else /* without pieceCount, this result is only a best guess... */ 2456 2466 { 2457 2467 peer->progress = true_count / (have->bit_count + 1); 2458 2468 } 2459 2469 } 2460 2470 2461 2462 2463 2464 2465 2466 2467 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); 2469 2479 } 2470 2480 … … 2472 2482 tr_peerMgrOnTorrentGotMetainfo (tr_torrent * tor) 2473 2483 { 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]); 2488 2497 } 2489 2498 … … 2502 2511 { 2503 2512 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); 2506 2515 const float interval = tor->info.pieceCount / (float)tabCount; 2507 2516 const bool isSeed = tr_cpGetStatus (&tor->completion) == TR_SEED; … … 2542 2551 tr_peerMgrGetDesiredAvailable (const tr_torrent * tor) 2543 2552 { 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; 2579 2591 } 2580 2592 … … 2589 2601 int i; 2590 2602 int size; 2591 Torrent * t;2603 tr_swarm * s; 2592 2604 const tr_peer ** peers; 2593 2605 … … 2599 2611 *setmeWebseedsSendingToUs = 0; 2600 2612 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); 2604 2616 2605 2617 for (i=0; i<TR_PEER_FROM__MAX; ++i) … … 2625 2637 } 2626 2638 2627 *setmeWebseedsSendingToUs = countActiveWebseeds ( t);2639 *setmeWebseedsSendingToUs = countActiveWebseeds (s); 2628 2640 } 2629 2641 … … 2633 2645 unsigned int i; 2634 2646 unsigned int webseedCount; 2635 const Torrent * t;2647 const tr_swarm * s; 2636 2648 const tr_webseed ** webseeds; 2637 2649 double * ret = NULL; … … 2640 2652 assert (tr_isTorrent (tor)); 2641 2653 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); 2645 2657 ret = tr_new0 (double, webseedCount); 2646 2658 2647 assert ( t->manager != NULL);2659 assert (s->manager != NULL); 2648 2660 assert (webseedCount == tor->info.webseedCount); 2649 2661 … … 2672 2684 int size = 0; 2673 2685 tr_peer_stat * ret; 2674 const Torrent * t;2686 const tr_swarm * s; 2675 2687 const tr_peer ** peers; 2676 2688 const time_t now = tr_time (); … … 2678 2690 2679 2691 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); 2685 2697 ret = tr_new0 (tr_peer_stat, size); 2686 2698 … … 2720 2732 pch = stat->flagStr; 2721 2733 if (stat->isUTP) *pch++ = 'T'; 2722 if ( t->optimistic == peer) *pch++ = 'O';2734 if (s->optimistic == peer) *pch++ = 'O'; 2723 2735 if (stat->isDownloadingFrom) *pch++ = 'D'; 2724 2736 else if (stat->clientIsInterested) *pch++ = 'd'; … … 2746 2758 tr_peerMgrClearInterest (tr_torrent * tor) 2747 2759 { 2748 2749 Torrent * t = tor->torrentPeers;2750 const int peerCount = tr_ptrArraySize (&t->peers);2751 2752 2753 2754 2755 2756 { 2757 const tr_peer * peer = tr_ptrArrayNth (&t->peers, i);2758 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); 2759 2771 } 2760 2772 } … … 2784 2796 typedef enum 2785 2797 { 2786 2787 2788 2798 RECHOKE_STATE_GOOD, 2799 RECHOKE_STATE_UNTESTED, 2800 RECHOKE_STATE_BAD 2789 2801 } 2790 2802 tr_rechoke_state; … … 2792 2804 struct tr_rechoke_info 2793 2805 { 2794 2795 2796 2806 tr_peer * peer; 2807 int salt; 2808 int rechoke_state; 2797 2809 }; 2798 2810 … … 2800 2812 compare_rechoke_info (const void * va, const void * vb) 2801 2813 { 2802 2803 2804 2805 2806 2807 2808 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; 2809 2821 } 2810 2822 2811 2823 /* determines who we send "interested" messages to */ 2812 2824 static 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) 2825 rechokeDownloads (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) 2850 2922 { 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 2860 2955 } 2861 2956 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); 2956 2968 } 2957 2969 … … 2962 2974 struct ChokeData 2963 2975 { 2964 boolisInterested;2965 boolwasChoked;2966 boolisChoked;2967 intrate;2968 intsalt;2969 tr_peer *peer;2976 bool isInterested; 2977 bool wasChoked; 2978 bool isChoked; 2979 int rate; 2980 int salt; 2981 tr_peer * peer; 2970 2982 }; 2971 2983 … … 2973 2985 compareChoke (const void * va, const void * vb) 2974 2986 { 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 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; 2988 3000 } 2989 3001 … … 2992 3004 isNew (const tr_peer * peer) 2993 3005 { 2994 3006 return peer && peer->io && tr_peerIoGetAge (peer->io) < 45; 2995 3007 } 2996 3008 … … 2999 3011 getRate (const tr_torrent * tor, struct peer_atom * atom, uint64_t now) 3000 3012 { 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 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; 3018 3030 } 3019 3031 … … 3022 3034 const uint64_t now_msec, tr_direction dir) 3023 3035 { 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 3048 static void 3049 rechokeUploads (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 */ 3060 3075 { 3061 3076 tr_peerMsgsSetChoke (peer->msgs, true); 3062 3077 } 3063 3078 else if (chokeAll) /* choke everyone if we're not uploading */ 3064 3079 { 3065 3080 tr_peerMsgsSetChoke (peer->msgs, true); 3066 3081 } 3067 else if (peer != t->optimistic)3082 else if (peer != s->optimistic) 3068 3083 { 3069 3070 3071 3072 3073 n->rate = getRate (t->tor, atom, now);3074 3075 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; 3076 3091 } 3077 3092 } 3078 3093 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) 3111 3127 { 3112 3128 if (choke[i].isInterested) 3113 3129 { 3114 3115 3116 3117 3118 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]); 3119 3135 } 3120 3136 } 3121 3137 3122 3138 if ((n = tr_ptrArraySize (&randPool))) 3123 3139 { 3124 3125 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; 3128 3144 } 3129 3145 3130 3131 } 3132 3133 3134 3135 3136 3137 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); 3138 3154 } 3139 3155 … … 3141 3157 rechokePulse (int foo UNUSED, short bar UNUSED, void * vmgr) 3142 3158 { 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); 3155 3174 } 3156 3175 } 3157 3176 } 3158 3177 3159 3160 3178 tr_timerAddMsec (mgr->rechokeTimer, RECHOKE_PERIOD_MSEC); 3179 managerUnlock (mgr); 3161 3180 } 3162 3181 … … 3168 3187 3169 3188 static bool 3170 shouldPeerBeClosed (const Torrent * t,3189 shouldPeerBeClosed (const tr_swarm * s, 3171 3190 const tr_peer * peer, 3172 3191 int peerCount, 3173 3192 const time_t now) 3174 3193 { 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); 3183 3227 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 3234 static tr_peer ** 3235 getPeersToClose (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]; 3208 3250 } 3209 3251 } 3210 3252 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; 3233 3255 } 3234 3256 … … 3272 3294 3273 3295 static 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); 3296 removePeer (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 3315 static void 3316 closePeer (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 3343 static void 3344 removeAllPeers (tr_swarm * s) 3345 { 3346 while (!tr_ptrArrayEmpty (&s->peers)) 3347 removePeer (s, tr_ptrArrayNth (&s->peers, 0)); 3348 } 3349 3350 static void 3351 closeBadPeers (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); 3336 3363 } 3337 3364 } … … 3339 3366 struct peer_liveliness 3340 3367 { 3341 3342 3343 3344 3345 3346 3368 tr_peer * peer; 3369 void * clientData; 3370 time_t pieceDataTime; 3371 time_t time; 3372 int speed; 3373 bool doPurge; 3347 3374 }; 3348 3375 … … 3350 3377 comparePeerLiveliness (const void * va, const void * vb) 3351 3378 { 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 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; 3370 3397 } 3371 3398 … … 3377 3404 int (*compare)(const void *va, const void *vb)) 3378 3405 { 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); 3411 3439 } 3412 3440 … … 3414 3442 sortPeersByLiveliness (tr_peer ** peers, void ** clientData, int n, uint64_t now) 3415 3443 { 3416 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 3426 { 3427 void * base = tr_ptrArrayBase (&t->peers);3428 3429 3430 3431 closePeer (t, peers[--n]);3432 3444 sortPeersByLivelinessImpl (peers, clientData, n, now, comparePeerLiveliness); 3445 } 3446 3447 3448 static void 3449 enforceTorrentPeerLimit (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); 3433 3461 } 3434 3462 } … … 3437 3465 enforceSessionPeerLimit (tr_session * session, uint64_t now) 3438 3466 { 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; 3463 3493 } 3464 3494 } 3465 3495 3466 3467 sortPeersByLiveliness (peers, (void**)torrents, n, now);3468 3469 3470 3471 closePeer (torrents[n], peers[n]);3472 3473 3474 tr_free (torrents);3475 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); 3476 3506 } 3477 3507 } … … 3482 3512 reconnectPulse (int foo UNUSED, short bar UNUSED, void * vmgr) 3483 3513 { 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 enforceTorrentPeerLimit (tor->torrentPeers, now_msec);3498 3499 3500 3501 3502 3503 3504 3505 if (!tor->torrentPeers->isRunning)3506 removeAllPeers (tor->torrentPeers);3507 3508 closeBadPeers (tor->torrentPeers, now_sec);3509 3510 3511 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); 3512 3542 } 3513 3543 … … 3521 3551 pumpAllPeers (tr_peerMgr * mgr) 3522 3552 { 3523 3524 3525 3526 { 3527 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) 3531 3561 { 3532 tr_peer * peer = tr_ptrArrayNth (&t->peers, j);3533 3562 tr_peer * peer = tr_ptrArrayNth (&s->peers, j); 3563 tr_peerMsgsPulse (peer->msgs); 3534 3564 } 3535 3565 } … … 3572 3602 bandwidthPulse (int foo UNUSED, short bar UNUSED, void * vmgr) 3573 3603 { 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); 3597 3628 } 3598 3629 3599 3600 3601 3602 3603 } 3604 3605 3606 3607 3608 3609 3610 3611 3612 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); 3613 3644 } 3614 3645 … … 3620 3651 compareAtomPtrsByAddress (const void * va, const void *vb) 3621 3652 { 3622 3623 3624 3625 3626 3627 3628 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); 3629 3660 } 3630 3661 … … 3633 3664 compareAtomPtrsByShelfDate (const void * va, const void *vb) 3634 3665 { 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 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; 3656 3687 } 3657 3688 … … 3665 3696 atomPulse (int foo UNUSED, short bar UNUSED, void * vmgr) 3666 3697 { 3667 3668 3669 3670 3671 3672 { 3673 3674 Torrent * t = tor->torrentPeers;3675 3676 struct peer_atom ** atoms = (struct peer_atom**) tr_ptrArrayPeek (&t->pool, &atomCount);3677 3678 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 */ 3679 3710 { 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; 3693 3725 } 3694 3726 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++]; 3701 3734 } 3702 3735 3703 3704 3705 3706 3707 3708 tr_ptrArrayDestruct (&t->pool, NULL);3709 t->pool = TR_PTR_ARRAY_INIT;3710 3711 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 3717 3718 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); 3719 3752 } 3720 3753 } 3721 3754 3722 3723 3755 tr_timerAddMsec (mgr->atomTimer, ATOM_PERIOD_MSEC); 3756 managerUnlock (mgr); 3724 3757 } 3725 3758 … … 3734 3767 isPeerCandidate (const tr_torrent * tor, struct peer_atom * atom, const time_t now) 3735 3768 { 3736 3737 3738 3739 3740 3741 if (peerIsInUse (tor->torrentPeers, atom))3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 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; 3757 3790 } 3758 3791 3759 3792 struct peer_candidate 3760 3793 { 3761 3762 3763 3794 uint64_t score; 3795 tr_torrent * tor; 3796 struct peer_atom * atom; 3764 3797 }; 3765 3798 … … 3767 3800 torrentWasRecentlyStarted (const tr_torrent * tor) 3768 3801 { 3769 3802 return difftime (tr_time (), tor->startDate) < 120; 3770 3803 } 3771 3804 … … 3773 3806 addValToKey (uint64_t value, int width, uint64_t addme) 3774 3807 { 3775 3776 3777 3808 value = (value << (uint64_t)width); 3809 value |= addme; 3810 return value; 3778 3811 } 3779 3812 … … 3782 3815 getPeerCandidateScore (const tr_torrent * tor, const struct peer_atom * atom, uint8_t salt) 3783 3816 { 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; 3831 3865 } 3832 3866 … … 3864 3898 checkBestScoresComeFirst (const struct peer_candidate * candidates, int n, int k) 3865 3899 { 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 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; 3881 3915 } 3882 3916 #endif /* NDEBUG */ … … 3886 3920 getPeerCandidates (tr_session * session, int * candidateCount, int max) 3887 3921 { 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) 3936 3972 { 3937 3938 3939 3973 struct peer_atom * atom = atoms[i]; 3974 3975 if (isPeerCandidate (tor, atom, now)) 3940 3976 { 3941 3942 3943 3944 3945 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; 3946 3982 } 3947 3983 } 3948 3984 } 3949 3985 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 3994 static void 3995 initiateConnection (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; 4009 4042 } 4010 4043 … … 4013 4046 { 4014 4047 #if 0 4015 4016 4017 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), 4018 4051 (int)c->atom->seedProbability, 4019 4020 4052 tr_torrentIsPrivate (c->tor) ? "private" : "public", 4053 tr_torrentIsSeed (c->tor) ? "seed" : "downloader"); 4021 4054 #endif 4022 4055 4023 initiateConnection (mgr, c->tor->torrentPeers, c->atom);4056 initiateConnection (mgr, c->tor->swarm, c->atom); 4024 4057 } 4025 4058 … … 4027 4060 makeNewPeerConnections (struct tr_peerMgr * mgr, const int max) 4028 4061 { 4029 4030 4031 4032 4033 4034 4035 4036 4037 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 264 264 struct tr_bandwidth bandwidth; 265 265 266 struct tr_ torrent_peers * torrentPeers;266 struct tr_swarm * swarm; 267 267 268 268 float desiredRatio;
Note: See TracChangeset
for help on using the changeset viewer.