PeerChokeCommand.cc 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - a simple utility for downloading files faster
  4. *
  5. * Copyright (C) 2006 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20. */
  21. /* copyright --> */
  22. #include "PeerChokeCommand.h"
  23. #include "Util.h"
  24. PeerChokeCommand::PeerChokeCommand(int cuid, int interval, TorrentDownloadEngine* e):Command(cuid), interval(interval), e(e), rotate(0) {
  25. checkPoint.tv_sec = 0;
  26. checkPoint.tv_usec = 0;
  27. }
  28. PeerChokeCommand::~PeerChokeCommand() {}
  29. void PeerChokeCommand::setAllPeerChoked(Peers& peers) const {
  30. for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
  31. Peer* peer = *itr;
  32. peer->chokingRequired = true;
  33. }
  34. }
  35. void PeerChokeCommand::optUnchokingPeer(Peers& peers) const {
  36. if(peers.empty()) {
  37. return;
  38. }
  39. random_shuffle(peers.begin(), peers.end());
  40. for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
  41. (*itr)->optUnchoking = false;
  42. }
  43. Peer* peer = peers.front();
  44. peer->optUnchoking = true;
  45. logger->debug("opt, unchoking %s, delta=%d",
  46. peer->ipaddr.c_str(), peer->getDeltaUpload());
  47. if(e->torrentMan->isEndGame()) {
  48. Peers::iterator itr = peers.begin()+1;
  49. for(; itr != peers.end(); itr++) {
  50. Peer* peer = *itr;
  51. if(peer->amInterested && peer->peerInterested) {
  52. peer->optUnchoking = true;
  53. logger->debug("opt, unchoking %s, delta=%d",
  54. peer->ipaddr.c_str(), peer->getDeltaUpload());
  55. break;
  56. }
  57. }
  58. }
  59. }
  60. void PeerChokeCommand::setAllPeerResetDelta(Peers& peers) const {
  61. for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) {
  62. Peer* peer = *itr;
  63. peer->resetDeltaUpload();
  64. peer->resetDeltaDownload();
  65. }
  66. }
  67. class UploadFaster {
  68. public:
  69. bool operator() (const Peer* left, const Peer* right) const {
  70. return left->getDeltaUpload() > right->getDeltaUpload();
  71. }
  72. };
  73. void PeerChokeCommand::orderByUploadRate(Peers& peers) const {
  74. sort(peers.begin(), peers.end(), UploadFaster());
  75. }
  76. class DownloadFaster {
  77. public:
  78. bool operator() (const Peer* left, const Peer* right) const {
  79. return left->getDeltaDownload() > right->getDeltaDownload();
  80. }
  81. };
  82. void PeerChokeCommand::orderByDownloadRate(Peers& peers) const {
  83. sort(peers.begin(), peers.end(), UploadFaster());
  84. }
  85. bool PeerChokeCommand::execute() {
  86. if(e->torrentMan->isHalt()) {
  87. return true;
  88. }
  89. struct timeval now;
  90. gettimeofday(&now, NULL);
  91. if(Util::difftvsec(now, checkPoint) >= interval) {
  92. checkPoint = now;
  93. Peers peers = e->torrentMan->getActivePeers();
  94. setAllPeerChoked(peers);
  95. if(e->torrentMan->downloadComplete()) {
  96. orderByDownloadRate(peers);
  97. } else {
  98. orderByUploadRate(peers);
  99. }
  100. int unchokingCount = peers.size() >= 4 ? 4 : peers.size();
  101. for(Peers::iterator itr = peers.begin(); unchokingCount > 0 && itr != peers.end(); ) {
  102. Peer* peer = *itr;
  103. if(peer->peerInterested) {
  104. peer->chokingRequired = false;
  105. peer->optUnchoking = false;
  106. itr = peers.erase(itr);
  107. unchokingCount--;
  108. logger->debug("cat01, unchoking %s, delta=%d", peer->ipaddr.c_str(), peer->getDeltaUpload());
  109. } else {
  110. itr++;
  111. }
  112. }
  113. for(Peers::iterator itr = peers.begin(); itr != peers.end(); ) {
  114. Peer* peer = *itr;
  115. if(!peer->peerInterested) {
  116. peer->chokingRequired = false;
  117. peer->optUnchoking = false;
  118. itr = peers.erase(itr);
  119. logger->debug("cat02, unchoking %s, delta=%d", peer->ipaddr.c_str(), peer->getDeltaUpload());
  120. break;
  121. } else {
  122. itr++;
  123. }
  124. }
  125. if(rotate%3 == 0) {
  126. optUnchokingPeer(peers);
  127. rotate = 0;
  128. }
  129. rotate++;
  130. setAllPeerResetDelta(e->torrentMan->getActivePeers());
  131. }
  132. e->commands.push_back(this);
  133. return false;
  134. }