HandshakeExtensionMessage.cc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2009 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 "HandshakeExtensionMessage.h"
  36. #include "Peer.h"
  37. #include "util.h"
  38. #include "DlAbortEx.h"
  39. #include "LogFactory.h"
  40. #include "Logger.h"
  41. #include "message.h"
  42. #include "StringFormat.h"
  43. #include "bencode.h"
  44. #include "DownloadContext.h"
  45. #include "bittorrent_helper.h"
  46. #include "RequestGroup.h"
  47. #include "PieceStorage.h"
  48. namespace aria2 {
  49. const std::string HandshakeExtensionMessage::EXTENSION_NAME = "handshake";
  50. HandshakeExtensionMessage::HandshakeExtensionMessage():
  51. _tcpPort(0),
  52. _metadataSize(0),
  53. _logger(LogFactory::getInstance()) {}
  54. HandshakeExtensionMessage::~HandshakeExtensionMessage() {}
  55. std::string HandshakeExtensionMessage::getPayload()
  56. {
  57. BDE dict = BDE::dict();
  58. if(!_clientVersion.empty()) {
  59. dict["v"] = _clientVersion;
  60. }
  61. if(_tcpPort > 0) {
  62. dict["p"] = _tcpPort;
  63. }
  64. BDE extDict = BDE::dict();
  65. for(std::map<std::string, uint8_t>::const_iterator itr = _extensions.begin(),
  66. eoi = _extensions.end(); itr != eoi; ++itr) {
  67. const std::map<std::string, uint8_t>::value_type& vt = *itr;
  68. extDict[vt.first] = vt.second;
  69. }
  70. dict["m"] = extDict;
  71. if(_metadataSize) {
  72. dict["metadata_size"] = _metadataSize;
  73. }
  74. return bencode::encode(dict);
  75. }
  76. std::string HandshakeExtensionMessage::toString() const
  77. {
  78. std::string s = getExtensionName();
  79. if(!_clientVersion.empty()) {
  80. strappend(s, " client=", util::urlencode(_clientVersion));
  81. }
  82. if(_tcpPort > 0) {
  83. strappend(s, ", tcpPort=", util::uitos(_tcpPort));
  84. }
  85. if(_metadataSize) {
  86. strappend(s, ", metadataSize=", util::uitos(_metadataSize));
  87. }
  88. for(std::map<std::string, uint8_t>::const_iterator itr = _extensions.begin(),
  89. eoi = _extensions.end(); itr != eoi; ++itr) {
  90. const std::map<std::string, uint8_t>::value_type& vt = *itr;
  91. strappend(s, ", ", vt.first, "=", util::uitos(vt.second));
  92. }
  93. return s;
  94. }
  95. void HandshakeExtensionMessage::doReceivedAction()
  96. {
  97. if(_tcpPort > 0) {
  98. _peer->port = _tcpPort;
  99. _peer->setIncomingPeer(false);
  100. }
  101. for(std::map<std::string, uint8_t>::const_iterator itr = _extensions.begin(),
  102. eoi = _extensions.end(); itr != eoi; ++itr) {
  103. const std::map<std::string, uint8_t>::value_type& vt = *itr;
  104. _peer->setExtension(vt.first, vt.second);
  105. }
  106. BDE& attrs = _dctx->getAttribute(bittorrent::BITTORRENT);
  107. if(!attrs.containsKey(bittorrent::METADATA) &&
  108. !_peer->getExtensionMessageID("ut_metadata")) {
  109. // TODO In metadataGetMode, if peer don't support metadata
  110. // transfer, should we drop connection? There is a possibility
  111. // that peer can still tell us peers using PEX.
  112. throw DL_ABORT_EX("Peer doesn't support ut_metadata extension. Goodbye.");
  113. }
  114. if(_metadataSize > 0) {
  115. if(attrs.containsKey(bittorrent::METADATA_SIZE)) {
  116. if(_metadataSize != (size_t)attrs[bittorrent::METADATA_SIZE].i()) {
  117. throw DL_ABORT_EX("Wrong metadata_size. Which one is correct!?");
  118. }
  119. } else {
  120. attrs[bittorrent::METADATA_SIZE] = _metadataSize;
  121. _dctx->getFirstFileEntry()->setLength(_metadataSize);
  122. _dctx->markTotalLengthIsKnown();
  123. _dctx->getOwnerRequestGroup()->initPieceStorage();
  124. SharedHandle<PieceStorage> pieceStorage =
  125. _dctx->getOwnerRequestGroup()->getPieceStorage();
  126. pieceStorage->setEndGamePieceNum(0);
  127. }
  128. } else if(!attrs.containsKey(bittorrent::METADATA)) {
  129. throw DL_ABORT_EX("Peer didn't provide metadata_size."
  130. " It seems that it doesn't have whole metadata.");
  131. }
  132. }
  133. void HandshakeExtensionMessage::setPeer(const SharedHandle<Peer>& peer)
  134. {
  135. _peer = peer;
  136. }
  137. uint8_t HandshakeExtensionMessage::getExtensionMessageID(const std::string& name) const
  138. {
  139. std::map<std::string, uint8_t>::const_iterator i = _extensions.find(name);
  140. if(i == _extensions.end()) {
  141. return 0;
  142. } else {
  143. return (*i).second;
  144. }
  145. }
  146. HandshakeExtensionMessageHandle
  147. HandshakeExtensionMessage::create(const unsigned char* data, size_t length)
  148. {
  149. if(length < 1) {
  150. throw DL_ABORT_EX
  151. (StringFormat(MSG_TOO_SMALL_PAYLOAD_SIZE,
  152. EXTENSION_NAME.c_str(), length).str());
  153. }
  154. HandshakeExtensionMessageHandle msg(new HandshakeExtensionMessage());
  155. if(LogFactory::getInstance()->debug()) {
  156. LogFactory::getInstance()->debug
  157. ("Creating HandshakeExtensionMessage from %s",
  158. util::urlencode(data, length).c_str());
  159. }
  160. const BDE dict = bencode::decode(data+1, length-1);
  161. if(!dict.isDict()) {
  162. throw DL_ABORT_EX("Unexpected payload format for extended message handshake");
  163. }
  164. const BDE& port = dict["p"];
  165. if(port.isInteger() && 0 < port.i() && port.i() < 65536) {
  166. msg->_tcpPort = port.i();
  167. }
  168. const BDE& version = dict["v"];
  169. if(version.isString()) {
  170. msg->_clientVersion = version.s();
  171. }
  172. const BDE& extDict = dict["m"];
  173. if(extDict.isDict()) {
  174. for(BDE::Dict::const_iterator i = extDict.dictBegin(),
  175. eoi = extDict.dictEnd(); i != eoi; ++i) {
  176. if((*i).second.isInteger()) {
  177. msg->_extensions[(*i).first] = (*i).second.i();
  178. }
  179. }
  180. }
  181. const BDE& metadataSize = dict["metadata_size"];
  182. // Only accept metadata smaller than 1MiB
  183. if(metadataSize.isInteger() && metadataSize.i() <= 1024*1024) {
  184. msg->_metadataSize = metadataSize.i();
  185. }
  186. return msg;
  187. }
  188. } // namespace aria2