DownloadCommand.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  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 "DownloadCommand.h"
  36. #include "Request.h"
  37. #include "RequestGroup.h"
  38. #include "DownloadEngine.h"
  39. #include "PeerStat.h"
  40. #include "TransferEncoding.h"
  41. #include "DlAbortEx.h"
  42. #include "DlRetryEx.h"
  43. #include "SegmentMan.h"
  44. #include "Segment.h"
  45. #include "Logger.h"
  46. #include "ChecksumCheckIntegrityEntry.h"
  47. #include "PieceStorage.h"
  48. #include "CheckIntegrityCommand.h"
  49. #include "DiskAdaptor.h"
  50. #include "CUIDCounter.h"
  51. #include "DownloadContext.h"
  52. #include "Option.h"
  53. #include "Util.h"
  54. #include "Socket.h"
  55. #include "message.h"
  56. #include "prefs.h"
  57. #ifdef ENABLE_MESSAGE_DIGEST
  58. #include "MessageDigestHelper.h"
  59. #endif // ENABLE_MESSAGE_DIGEST
  60. #include <cassert>
  61. namespace aria2 {
  62. DownloadCommand::DownloadCommand(int cuid,
  63. const RequestHandle& req,
  64. RequestGroup* requestGroup,
  65. DownloadEngine* e,
  66. const SocketHandle& s):
  67. AbstractCommand(cuid, req, requestGroup, e, s),
  68. peerStat(0),
  69. transferDecoder(0)
  70. {
  71. peerStat = _requestGroup->getSegmentMan()->getPeerStat(cuid);
  72. if(peerStat.isNull()) {
  73. peerStat = new PeerStat(cuid);
  74. _requestGroup->getSegmentMan()->registerPeerStat(peerStat);
  75. }
  76. peerStat->downloadStart();
  77. }
  78. DownloadCommand::~DownloadCommand() {
  79. assert(peerStat.get());
  80. peerStat->downloadStop();
  81. }
  82. bool DownloadCommand::executeInternal() {
  83. if(maxDownloadSpeedLimit > 0 &&
  84. maxDownloadSpeedLimit < _requestGroup->getSegmentMan()->calculateDownloadSpeed()) {
  85. e->commands.push_back(this);
  86. disableReadCheckSocket();
  87. return false;
  88. }
  89. setReadCheckSocket(socket);
  90. SegmentHandle segment = _segments.front();
  91. int32_t BUFSIZE = 16*1024;
  92. char buf[BUFSIZE];
  93. int32_t bufSize;
  94. if(segment->getLength() > 0 && segment->getLength()-segment->getWrittenLength() < BUFSIZE) {
  95. bufSize = segment->getLength()-segment->getWrittenLength();
  96. } else {
  97. bufSize = BUFSIZE;
  98. }
  99. socket->readData(buf, bufSize);
  100. if(transferDecoder.isNull()) {
  101. _requestGroup->getPieceStorage()->getDiskAdaptor()->writeData((const unsigned char*)buf, bufSize,
  102. segment->getPositionToWrite());
  103. //logger->debug("bufSize = %d, posToWrite = %lld", bufSize, segment->getPositionToWrite());
  104. segment->updateWrittenLength(bufSize);
  105. //logger->debug("overflow length = %d, next posToWrite = %lld", segment->getOverflowLength(), segment->getPositionToWrite());
  106. //logger->debug("%s", Util::toHex(segment->getPiece()->getBitfield(),
  107. //segment->getPiece()->getBitfieldLength()).c_str());
  108. //segment->writtenLength += bufSize;
  109. peerStat->updateDownloadLength(bufSize);
  110. } else {
  111. int32_t infbufSize = 16*1024;
  112. char infbuf[infbufSize];
  113. transferDecoder->inflate(infbuf, infbufSize, buf, bufSize);
  114. _requestGroup->getPieceStorage()->getDiskAdaptor()->writeData((const unsigned char*)infbuf, infbufSize,
  115. segment->getPositionToWrite());
  116. segment->updateWrittenLength(infbufSize);
  117. //segment->writtenLength += infbufSize;
  118. peerStat->updateDownloadLength(infbufSize);
  119. }
  120. if(_requestGroup->getTotalLength() != 0 && bufSize == 0) {
  121. throw new DlRetryEx(EX_GOT_EOF);
  122. }
  123. if(!transferDecoder.isNull() && transferDecoder->finished()
  124. || transferDecoder.isNull() && segment->complete()
  125. || bufSize == 0) {
  126. if(!transferDecoder.isNull()) transferDecoder->end();
  127. logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid);
  128. validatePieceHash(segment);
  129. checkLowestDownloadSpeed();
  130. // this unit is going to download another segment.
  131. return prepareForNextSegment();
  132. } else {
  133. checkLowestDownloadSpeed();
  134. e->commands.push_back(this);
  135. return false;
  136. }
  137. }
  138. void DownloadCommand::checkLowestDownloadSpeed() const
  139. {
  140. // calculate downloading speed
  141. if(peerStat->getDownloadStartTime().elapsed(startupIdleTime)) {
  142. int32_t nowSpeed = peerStat->calculateDownloadSpeed();
  143. if(lowestDownloadSpeedLimit > 0 && nowSpeed <= lowestDownloadSpeedLimit) {
  144. throw new DlAbortEx(EX_TOO_SLOW_DOWNLOAD_SPEED,
  145. nowSpeed,
  146. lowestDownloadSpeedLimit,
  147. req->getHost().c_str());
  148. }
  149. }
  150. }
  151. bool DownloadCommand::prepareForNextSegment() {
  152. if(_requestGroup->downloadFinished()) {
  153. #ifdef ENABLE_MESSAGE_DIGEST
  154. CheckIntegrityEntryHandle entry = new ChecksumCheckIntegrityEntry(_requestGroup);
  155. if(entry->isValidationReady()) {
  156. entry->initValidator();
  157. CheckIntegrityCommand* command =
  158. new CheckIntegrityCommand(CUIDCounterSingletonHolder::instance()->newID(), _requestGroup, e, entry);
  159. e->commands.push_back(command);
  160. }
  161. #endif // ENABLE_MESSAGE_DIGEST
  162. return true;
  163. } else {
  164. SegmentHandle tempSegment = _segments.front();
  165. SegmentHandle nextSegment =
  166. _requestGroup->getSegmentMan()->getSegment(cuid,
  167. tempSegment->getIndex()+1);
  168. if(!nextSegment.isNull() && nextSegment->getWrittenLength() == 0) {
  169. e->commands.push_back(this);
  170. return false;
  171. } else {
  172. return prepareForRetry(0);
  173. }
  174. }
  175. }
  176. void DownloadCommand::validatePieceHash(const SegmentHandle& segment)
  177. {
  178. #ifdef ENABLE_MESSAGE_DIGEST
  179. std::string expectedPieceHash =
  180. _requestGroup->getDownloadContext()->getPieceHash(segment->getIndex());
  181. if(e->option->get(PREF_REALTIME_CHUNK_CHECKSUM) == V_TRUE &&
  182. !expectedPieceHash.empty()) {
  183. std::string actualPieceHash =
  184. MessageDigestHelper::digest(_requestGroup->getDownloadContext()->getPieceHashAlgo(),
  185. _requestGroup->getPieceStorage()->getDiskAdaptor(),
  186. segment->getPosition(),
  187. segment->getLength());
  188. if(actualPieceHash == expectedPieceHash) {
  189. logger->info(MSG_GOOD_CHUNK_CHECKSUM, actualPieceHash.c_str());
  190. _requestGroup->getSegmentMan()->completeSegment(cuid, segment);
  191. } else {
  192. logger->info(EX_INVALID_CHUNK_CHECKSUM,
  193. segment->getIndex(),
  194. Util::llitos(segment->getPosition(), true).c_str(),
  195. expectedPieceHash.c_str(),
  196. actualPieceHash.c_str());
  197. segment->clear();
  198. _requestGroup->getSegmentMan()->cancelSegment(cuid);
  199. throw new DlRetryEx("Invalid checksum index=%d", segment->getIndex());
  200. }
  201. } else
  202. #endif // ENABLE_MESSAGE_DIGEST
  203. {
  204. _requestGroup->getSegmentMan()->completeSegment(cuid, segment);
  205. }
  206. }
  207. void DownloadCommand::setTransferDecoder(const TransferEncodingHandle& transferDecoder)
  208. {
  209. this->transferDecoder = transferDecoder;
  210. }
  211. } // namespace aria2