UTPexExtensionMessage.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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 char UTPexExtensionMessage::EXTENSION_NAME[] = "ut_pex";
  54. constexpr std::chrono::minutes UTPexExtensionMessage::DEFAULT_INTERVAL;
  55. UTPexExtensionMessage::UTPexExtensionMessage(uint8_t extensionMessageID)
  56. : extensionMessageID_{extensionMessageID},
  57. peerStorage_{nullptr},
  58. interval_{DEFAULT_INTERVAL},
  59. maxFreshPeer_{DEFAULT_MAX_FRESH_PEER},
  60. maxDroppedPeer_{DEFAULT_MAX_DROPPED_PEER}
  61. {
  62. }
  63. std::string UTPexExtensionMessage::getPayload()
  64. {
  65. auto freshPeerPair = createCompactPeerListAndFlag(freshPeers_);
  66. auto droppedPeerPair = createCompactPeerListAndFlag(droppedPeers_);
  67. Dict dict;
  68. if (!freshPeerPair.first.first.empty()) {
  69. dict.put("added", freshPeerPair.first.first);
  70. dict.put("added.f", freshPeerPair.first.second);
  71. }
  72. if (!droppedPeerPair.first.first.empty()) {
  73. dict.put("dropped", droppedPeerPair.first.first);
  74. }
  75. if (!freshPeerPair.second.first.empty()) {
  76. dict.put("added6", freshPeerPair.second.first);
  77. dict.put("added6.f", freshPeerPair.second.second);
  78. }
  79. if (!droppedPeerPair.second.first.empty()) {
  80. dict.put("dropped6", droppedPeerPair.second.first);
  81. }
  82. return bencode2::encode(&dict);
  83. }
  84. std::pair<std::pair<std::string, std::string>,
  85. std::pair<std::string, std::string>>
  86. UTPexExtensionMessage::createCompactPeerListAndFlag(
  87. const std::vector<std::shared_ptr<Peer>>& peers)
  88. {
  89. std::string addrstring;
  90. std::string flagstring;
  91. std::string addrstring6;
  92. std::string flagstring6;
  93. for (auto itr = std::begin(peers), eoi = std::end(peers); itr != eoi; ++itr) {
  94. unsigned char compact[COMPACT_LEN_IPV6];
  95. int compactlen = bittorrent::packcompact(compact, (*itr)->getIPAddress(),
  96. (*itr)->getPort());
  97. if (compactlen == COMPACT_LEN_IPV4) {
  98. addrstring.append(&compact[0], &compact[compactlen]);
  99. flagstring += (*itr)->isSeeder() ? 0x02u : 0x00u;
  100. }
  101. else if (compactlen == COMPACT_LEN_IPV6) {
  102. addrstring6.append(&compact[0], &compact[compactlen]);
  103. flagstring6 += (*itr)->isSeeder() ? 0x02u : 0x00u;
  104. }
  105. }
  106. return std::make_pair(
  107. std::make_pair(std::move(addrstring), std::move(flagstring)),
  108. std::make_pair(std::move(addrstring6), std::move(flagstring6)));
  109. }
  110. std::string UTPexExtensionMessage::toString() const
  111. {
  112. return fmt("ut_pex added=%lu, dropped=%lu",
  113. static_cast<unsigned long>(freshPeers_.size()),
  114. static_cast<unsigned long>(droppedPeers_.size()));
  115. }
  116. void UTPexExtensionMessage::doReceivedAction()
  117. {
  118. peerStorage_->addPeer(freshPeers_);
  119. peerStorage_->addPeer(droppedPeers_);
  120. }
  121. bool UTPexExtensionMessage::addFreshPeer(const std::shared_ptr<Peer>& peer)
  122. {
  123. if (!peer->isIncomingPeer() &&
  124. peer->getFirstContactTime().difference(global::wallclock()) < interval_) {
  125. freshPeers_.push_back(peer);
  126. return true;
  127. }
  128. else {
  129. return false;
  130. }
  131. }
  132. const std::vector<std::shared_ptr<Peer>>&
  133. UTPexExtensionMessage::getFreshPeers() const
  134. {
  135. return freshPeers_;
  136. }
  137. bool UTPexExtensionMessage::freshPeersAreFull() const
  138. {
  139. return freshPeers_.size() >= maxFreshPeer_;
  140. }
  141. bool UTPexExtensionMessage::addDroppedPeer(const std::shared_ptr<Peer>& peer)
  142. {
  143. if (!peer->isIncomingPeer() &&
  144. peer->getDropStartTime().difference(global::wallclock()) < interval_) {
  145. droppedPeers_.push_back(peer);
  146. return true;
  147. }
  148. else {
  149. return false;
  150. }
  151. }
  152. const std::vector<std::shared_ptr<Peer>>&
  153. UTPexExtensionMessage::getDroppedPeers() const
  154. {
  155. return droppedPeers_;
  156. }
  157. bool UTPexExtensionMessage::droppedPeersAreFull() const
  158. {
  159. return droppedPeers_.size() >= maxDroppedPeer_;
  160. }
  161. void UTPexExtensionMessage::setMaxFreshPeer(size_t maxFreshPeer)
  162. {
  163. maxFreshPeer_ = maxFreshPeer;
  164. }
  165. void UTPexExtensionMessage::setMaxDroppedPeer(size_t maxDroppedPeer)
  166. {
  167. maxDroppedPeer_ = maxDroppedPeer;
  168. }
  169. void UTPexExtensionMessage::setPeerStorage(PeerStorage* peerStorage)
  170. {
  171. peerStorage_ = peerStorage;
  172. }
  173. std::unique_ptr<UTPexExtensionMessage>
  174. UTPexExtensionMessage::create(const unsigned char* data, size_t len)
  175. {
  176. if (len < 1) {
  177. throw DL_ABORT_EX(fmt(MSG_TOO_SMALL_PAYLOAD_SIZE, EXTENSION_NAME,
  178. static_cast<unsigned long>(len)));
  179. }
  180. auto msg = make_unique<UTPexExtensionMessage>(*data);
  181. auto decoded = bencode2::decode(data + 1, len - 1);
  182. const Dict* dict = downcast<Dict>(decoded);
  183. if (dict) {
  184. const String* added = downcast<String>(dict->get("added"));
  185. if (added) {
  186. bittorrent::extractPeer(added, AF_INET,
  187. std::back_inserter(msg->freshPeers_));
  188. }
  189. const String* dropped = downcast<String>(dict->get("dropped"));
  190. if (dropped) {
  191. bittorrent::extractPeer(dropped, AF_INET,
  192. std::back_inserter(msg->droppedPeers_));
  193. }
  194. const String* added6 = downcast<String>(dict->get("added6"));
  195. if (added6) {
  196. bittorrent::extractPeer(added6, AF_INET6,
  197. std::back_inserter(msg->freshPeers_));
  198. }
  199. const String* dropped6 = downcast<String>(dict->get("dropped6"));
  200. if (dropped6) {
  201. bittorrent::extractPeer(dropped6, AF_INET6,
  202. std::back_inserter(msg->droppedPeers_));
  203. }
  204. }
  205. return msg;
  206. }
  207. } // namespace aria2