UTPexExtensionMessage.cc 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "UTPexExtensionMessage.h"
  36. #include "Peer.h"
  37. #include "util.h"
  38. #include "bittorrent_helper.h"
  39. #include "PeerStorage.h"
  40. #include "DlAbortEx.h"
  41. #include "message.h"
  42. #include "fmt.h"
  43. #include "bencode2.h"
  44. #include "a2functional.h"
  45. #include "wallclock.h"
  46. namespace aria2 {
  47. namespace {
  48. // This is the hard limit of the number of "fresh peer" and "dropped
  49. // peer". This number is treated as the sum of IPv4 and IPv6 peers.
  50. const size_t DEFAULT_MAX_FRESH_PEER = 50;
  51. const size_t DEFAULT_MAX_DROPPED_PEER = 50;
  52. } // namespace
  53. const std::string UTPexExtensionMessage::EXTENSION_NAME = "ut_pex";
  54. UTPexExtensionMessage::UTPexExtensionMessage(uint8_t extensionMessageID):
  55. extensionMessageID_(extensionMessageID),
  56. interval_(DEFAULT_INTERVAL),
  57. maxFreshPeer_(DEFAULT_MAX_FRESH_PEER),
  58. maxDroppedPeer_(DEFAULT_MAX_DROPPED_PEER) {}
  59. UTPexExtensionMessage::~UTPexExtensionMessage() {}
  60. std::string UTPexExtensionMessage::getPayload()
  61. {
  62. std::pair<std::pair<std::string, std::string>,
  63. std::pair<std::string, std::string> > freshPeerPair =
  64. createCompactPeerListAndFlag(freshPeers_);
  65. std::pair<std::pair<std::string, std::string>,
  66. std::pair<std::string, std::string> > droppedPeerPair =
  67. createCompactPeerListAndFlag(droppedPeers_);
  68. Dict dict;
  69. if(!freshPeerPair.first.first.empty()) {
  70. dict.put("added", freshPeerPair.first.first);
  71. dict.put("added.f", freshPeerPair.first.second);
  72. }
  73. if(!droppedPeerPair.first.first.empty()) {
  74. dict.put("dropped", droppedPeerPair.first.first);
  75. }
  76. if(!freshPeerPair.second.first.empty()) {
  77. dict.put("added6", freshPeerPair.second.first);
  78. dict.put("added6.f", freshPeerPair.second.second);
  79. }
  80. if(!droppedPeerPair.second.first.empty()) {
  81. dict.put("dropped6", droppedPeerPair.second.first);
  82. }
  83. return bencode2::encode(&dict);
  84. }
  85. std::pair<std::pair<std::string, std::string>,
  86. std::pair<std::string, std::string> >
  87. UTPexExtensionMessage::createCompactPeerListAndFlag
  88. (const std::vector<SharedHandle<Peer> >& peers)
  89. {
  90. std::string addrstring;
  91. std::string flagstring;
  92. std::string addrstring6;
  93. std::string flagstring6;
  94. for(std::vector<SharedHandle<Peer> >::const_iterator itr = peers.begin(),
  95. eoi = peers.end(); itr != eoi; ++itr) {
  96. unsigned char compact[COMPACT_LEN_IPV6];
  97. int compactlen = bittorrent::packcompact
  98. (compact, (*itr)->getIPAddress(), (*itr)->getPort());
  99. if(compactlen == COMPACT_LEN_IPV4) {
  100. addrstring.append(&compact[0], &compact[compactlen]);
  101. flagstring += (*itr)->isSeeder() ? 0x02u : 0x00u;
  102. } else if(compactlen == COMPACT_LEN_IPV6) {
  103. addrstring6.append(&compact[0], &compact[compactlen]);
  104. flagstring6 += (*itr)->isSeeder() ? 0x02u : 0x00u;
  105. }
  106. }
  107. return std::make_pair(std::make_pair(addrstring, flagstring),
  108. std::make_pair(addrstring6, flagstring6));
  109. }
  110. std::string UTPexExtensionMessage::toString() const
  111. {
  112. return strconcat("ut_pex added=", util::uitos(freshPeers_.size()),
  113. ", dropped=", util::uitos(droppedPeers_.size()));
  114. }
  115. void UTPexExtensionMessage::doReceivedAction()
  116. {
  117. peerStorage_->addPeer(freshPeers_);
  118. peerStorage_->addPeer(droppedPeers_);
  119. }
  120. bool UTPexExtensionMessage::addFreshPeer(const SharedHandle<Peer>& peer)
  121. {
  122. if(!peer->isIncomingPeer() &&
  123. peer->getFirstContactTime().difference(global::wallclock) < interval_) {
  124. freshPeers_.push_back(peer);
  125. return true;
  126. } else {
  127. return false;
  128. }
  129. }
  130. bool UTPexExtensionMessage::freshPeersAreFull() const
  131. {
  132. return freshPeers_.size() >= maxFreshPeer_;
  133. }
  134. bool UTPexExtensionMessage::addDroppedPeer(const SharedHandle<Peer>& peer)
  135. {
  136. if(!peer->isIncomingPeer() &&
  137. peer->getBadConditionStartTime().
  138. difference(global::wallclock) < interval_) {
  139. droppedPeers_.push_back(peer);
  140. return true;
  141. } else {
  142. return false;
  143. }
  144. }
  145. bool UTPexExtensionMessage::droppedPeersAreFull() const
  146. {
  147. return droppedPeers_.size() >= maxDroppedPeer_;
  148. }
  149. void UTPexExtensionMessage::setMaxFreshPeer(size_t maxFreshPeer)
  150. {
  151. maxFreshPeer_ = maxFreshPeer;
  152. }
  153. void UTPexExtensionMessage::setMaxDroppedPeer(size_t maxDroppedPeer)
  154. {
  155. maxDroppedPeer_ = maxDroppedPeer;
  156. }
  157. void UTPexExtensionMessage::setPeerStorage
  158. (const SharedHandle<PeerStorage>& peerStorage)
  159. {
  160. peerStorage_ = peerStorage;
  161. }
  162. UTPexExtensionMessageHandle
  163. UTPexExtensionMessage::create(const unsigned char* data, size_t len)
  164. {
  165. if(len < 1) {
  166. throw DL_ABORT_EX(fmt(MSG_TOO_SMALL_PAYLOAD_SIZE,
  167. EXTENSION_NAME.c_str(),
  168. static_cast<unsigned long>(len)));
  169. }
  170. UTPexExtensionMessageHandle msg(new UTPexExtensionMessage(*data));
  171. SharedHandle<ValueBase> decoded = bencode2::decode(data+1, len-1);
  172. const Dict* dict = asDict(decoded);
  173. if(dict) {
  174. const String* added = asString(dict->get("added"));
  175. if(added) {
  176. bittorrent::extractPeer
  177. (added, AF_INET, std::back_inserter(msg->freshPeers_));
  178. }
  179. const String* dropped = asString(dict->get("dropped"));
  180. if(dropped) {
  181. bittorrent::extractPeer
  182. (dropped, AF_INET, std::back_inserter(msg->droppedPeers_));
  183. }
  184. const String* added6 = asString(dict->get("added6"));
  185. if(added6) {
  186. bittorrent::extractPeer
  187. (added6, AF_INET6, std::back_inserter(msg->freshPeers_));
  188. }
  189. const String* dropped6 = asString(dict->get("dropped6"));
  190. if(dropped6) {
  191. bittorrent::extractPeer
  192. (dropped6, AF_INET6, std::back_inserter(msg->droppedPeers_));
  193. }
  194. }
  195. return msg;
  196. }
  197. } // namespace aria2