RequestGroup.cc 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  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 "RequestGroup.h"
  36. #include <cassert>
  37. #include <algorithm>
  38. #include "PostDownloadHandler.h"
  39. #include "DownloadEngine.h"
  40. #include "DefaultSegmentManFactory.h"
  41. #include "SegmentMan.h"
  42. #include "NullProgressInfoFile.h"
  43. #include "Dependency.h"
  44. #include "prefs.h"
  45. #include "CreateRequestCommand.h"
  46. #include "File.h"
  47. #include "message.h"
  48. #include "util.h"
  49. #include "LogFactory.h"
  50. #include "Logger.h"
  51. #include "DiskAdaptor.h"
  52. #include "DiskWriterFactory.h"
  53. #include "RecoverableException.h"
  54. #include "StreamCheckIntegrityEntry.h"
  55. #include "CheckIntegrityCommand.h"
  56. #include "UnknownLengthPieceStorage.h"
  57. #include "DownloadContext.h"
  58. #include "DlAbortEx.h"
  59. #include "DownloadFailureException.h"
  60. #include "RequestGroupMan.h"
  61. #include "DefaultBtProgressInfoFile.h"
  62. #include "DefaultPieceStorage.h"
  63. #include "DownloadHandlerFactory.h"
  64. #include "MemoryBufferPreDownloadHandler.h"
  65. #include "DownloadHandlerConstants.h"
  66. #include "Option.h"
  67. #include "FileEntry.h"
  68. #include "Request.h"
  69. #include "FileAllocationIterator.h"
  70. #include "StringFormat.h"
  71. #include "A2STR.h"
  72. #include "URISelector.h"
  73. #include "InOrderURISelector.h"
  74. #include "PieceSelector.h"
  75. #include "a2functional.h"
  76. #include "SocketCore.h"
  77. #include "SimpleRandomizer.h"
  78. #ifdef ENABLE_MESSAGE_DIGEST
  79. # include "CheckIntegrityCommand.h"
  80. #endif // ENABLE_MESSAGE_DIGEST
  81. #ifdef ENABLE_BITTORRENT
  82. # include "bittorrent_helper.h"
  83. # include "BtRegistry.h"
  84. # include "BtCheckIntegrityEntry.h"
  85. # include "DefaultPeerStorage.h"
  86. # include "DefaultBtAnnounce.h"
  87. # include "BtRuntime.h"
  88. # include "BtSetup.h"
  89. # include "BtFileAllocationEntry.h"
  90. # include "BtPostDownloadHandler.h"
  91. # include "DHTSetup.h"
  92. # include "DHTRegistry.h"
  93. # include "BtMessageFactory.h"
  94. # include "BtRequestFactory.h"
  95. # include "BtMessageDispatcher.h"
  96. # include "BtMessageReceiver.h"
  97. # include "PeerConnection.h"
  98. # include "ExtensionMessageFactory.h"
  99. # include "DHTPeerAnnounceStorage.h"
  100. # include "DHTEntryPointNameResolveCommand.h"
  101. # include "LongestSequencePieceSelector.h"
  102. # include "PriorityPieceSelector.h"
  103. #endif // ENABLE_BITTORRENT
  104. #ifdef ENABLE_METALINK
  105. # include "MetalinkPostDownloadHandler.h"
  106. #endif // ENABLE_METALINK
  107. namespace aria2 {
  108. int32_t RequestGroup::_gidCounter = 0;
  109. const std::string RequestGroup::ACCEPT_METALINK = "application/metalink+xml";
  110. RequestGroup::RequestGroup(const SharedHandle<Option>& option):
  111. _gid(++_gidCounter),
  112. _option(new Option(*option.get())),
  113. _numConcurrentCommand(option->getAsInt(PREF_SPLIT)),
  114. _numStreamConnection(0),
  115. _numCommand(0),
  116. _segmentManFactory(new DefaultSegmentManFactory(_option.get())),
  117. _saveControlFile(true),
  118. _progressInfoFile(new NullProgressInfoFile()),
  119. _preLocalFileCheckEnabled(true),
  120. _haltRequested(false),
  121. _forceHaltRequested(false),
  122. _haltReason(RequestGroup::NONE),
  123. _uriSelector(new InOrderURISelector()),
  124. _lastModifiedTime(Time::null()),
  125. _fileNotFoundCount(0),
  126. _timeout(option->getAsInt(PREF_TIMEOUT)),
  127. _inMemoryDownload(false),
  128. _maxDownloadSpeedLimit(option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT)),
  129. _maxUploadSpeedLimit(option->getAsInt(PREF_MAX_UPLOAD_LIMIT)),
  130. _belongsToGID(0),
  131. _logger(LogFactory::getInstance())
  132. {
  133. _fileAllocationEnabled = _option->get(PREF_FILE_ALLOCATION) != V_NONE;
  134. // Add types to be sent as a Accept header value here.
  135. // It would be good to put this value in Option so that user can tweak
  136. // and add this list.
  137. // ACCEPT_METALINK is used for `transparent metalink'.
  138. addAcceptType(ACCEPT_METALINK);
  139. if(!_option->getAsBool(PREF_DRY_RUN)) {
  140. initializePreDownloadHandler();
  141. initializePostDownloadHandler();
  142. }
  143. }
  144. RequestGroup::~RequestGroup() {}
  145. const SegmentManHandle& RequestGroup::initSegmentMan()
  146. {
  147. _segmentMan = _segmentManFactory->createNewInstance(_downloadContext,
  148. _pieceStorage);
  149. return _segmentMan;
  150. }
  151. bool RequestGroup::downloadFinished() const
  152. {
  153. if(_pieceStorage.isNull()) {
  154. return false;
  155. } else {
  156. return _pieceStorage->downloadFinished();
  157. }
  158. }
  159. bool RequestGroup::allDownloadFinished() const
  160. {
  161. if(_pieceStorage.isNull()) {
  162. return false;
  163. } else {
  164. return _pieceStorage->allDownloadFinished();
  165. }
  166. }
  167. downloadresultcode::RESULT RequestGroup::downloadResult() const
  168. {
  169. if (downloadFinished())
  170. return downloadresultcode::FINISHED;
  171. else {
  172. if (_lastUriResult.isNull()) {
  173. if(_haltReason == RequestGroup::USER_REQUEST) {
  174. return downloadresultcode::IN_PROGRESS;
  175. } else {
  176. return downloadresultcode::UNKNOWN_ERROR;
  177. }
  178. } else {
  179. return _lastUriResult->getResult();
  180. }
  181. }
  182. }
  183. void RequestGroup::closeFile()
  184. {
  185. if(!_pieceStorage.isNull()) {
  186. _pieceStorage->getDiskAdaptor()->closeFile();
  187. }
  188. }
  189. void RequestGroup::createInitialCommand
  190. (std::deque<Command*>& commands, DownloadEngine* e)
  191. {
  192. #ifdef ENABLE_BITTORRENT
  193. {
  194. if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) {
  195. const BDE& torrentAttrs =
  196. _downloadContext->getAttribute(bittorrent::BITTORRENT);
  197. bool metadataGetMode = !torrentAttrs.containsKey(bittorrent::METADATA);
  198. if(_option->getAsBool(PREF_DRY_RUN)) {
  199. throw DOWNLOAD_FAILURE_EXCEPTION
  200. ("Cancel BitTorrent download in dry-run context.");
  201. }
  202. SharedHandle<BtRegistry> btRegistry = e->getBtRegistry();
  203. if(!btRegistry->getDownloadContext
  204. (torrentAttrs[bittorrent::INFO_HASH].s()).isNull()) {
  205. throw DOWNLOAD_FAILURE_EXCEPTION
  206. (StringFormat
  207. ("InfoHash %s is already registered.",
  208. bittorrent::getInfoHashString(_downloadContext).c_str()).str());
  209. }
  210. if(metadataGetMode) {
  211. // Use UnknownLengthPieceStorage.
  212. initPieceStorage();
  213. } else {
  214. if(e->_requestGroupMan->isSameFileBeingDownloaded(this)) {
  215. throw DOWNLOAD_FAILURE_EXCEPTION
  216. (StringFormat(EX_DUPLICATE_FILE_DOWNLOAD,
  217. _downloadContext->getBasePath().c_str()).str());
  218. }
  219. initPieceStorage();
  220. if(_downloadContext->getFileEntries().size() > 1) {
  221. _pieceStorage->setupFileFilter();
  222. }
  223. }
  224. SharedHandle<DefaultBtProgressInfoFile> progressInfoFile;
  225. if(!metadataGetMode) {
  226. progressInfoFile.reset(new DefaultBtProgressInfoFile(_downloadContext,
  227. _pieceStorage,
  228. _option.get()));
  229. }
  230. BtRuntimeHandle btRuntime(new BtRuntime());
  231. btRuntime->setMaxPeers(_option->getAsInt(PREF_BT_MAX_PEERS));
  232. _btRuntime = btRuntime;
  233. if(!progressInfoFile.isNull()) {
  234. progressInfoFile->setBtRuntime(btRuntime);
  235. }
  236. SharedHandle<DefaultPeerStorage> peerStorage
  237. (new DefaultPeerStorage(_option.get()));
  238. peerStorage->setBtRuntime(btRuntime);
  239. peerStorage->setPieceStorage(_pieceStorage);
  240. _peerStorage = peerStorage;
  241. if(!progressInfoFile.isNull()) {
  242. progressInfoFile->setPeerStorage(peerStorage);
  243. }
  244. SharedHandle<DefaultBtAnnounce> btAnnounce
  245. (new DefaultBtAnnounce(_downloadContext, _option.get()));
  246. btAnnounce->setBtRuntime(btRuntime);
  247. btAnnounce->setPieceStorage(_pieceStorage);
  248. btAnnounce->setPeerStorage(peerStorage);
  249. btAnnounce->setUserDefinedInterval
  250. (_option->getAsInt(PREF_BT_TRACKER_INTERVAL));
  251. btAnnounce->shuffleAnnounce();
  252. btRegistry->put(_gid,
  253. BtObject(_downloadContext,
  254. _pieceStorage,
  255. peerStorage,
  256. btAnnounce,
  257. btRuntime,
  258. (progressInfoFile.isNull()?
  259. _progressInfoFile:
  260. SharedHandle<BtProgressInfoFile>
  261. (progressInfoFile))));
  262. if(metadataGetMode) {
  263. if(_option->getAsBool(PREF_ENABLE_DHT)) {
  264. std::deque<Command*> dhtCommands;
  265. DHTSetup().setup(dhtCommands, e, _option.get());
  266. e->addCommand(dhtCommands);
  267. } else {
  268. _logger->notice("For BitTorrent Magnet URI, enabling DHT is strongly"
  269. " recommended. See --enable-dht option.");
  270. }
  271. SharedHandle<CheckIntegrityEntry> entry
  272. (new BtCheckIntegrityEntry(this));
  273. entry->onDownloadIncomplete(commands, e);
  274. return;
  275. }
  276. // Remove the control file if download file doesn't exist
  277. if(progressInfoFile->exists() && !_pieceStorage->getDiskAdaptor()->fileExists()) {
  278. progressInfoFile->removeFile();
  279. _logger->notice(MSG_REMOVED_DEFUNCT_CONTROL_FILE,
  280. progressInfoFile->getFilename().c_str(),
  281. _downloadContext->getBasePath().c_str());
  282. }
  283. {
  284. uint64_t actualFileSize = _pieceStorage->getDiskAdaptor()->size();
  285. if(actualFileSize == _downloadContext->getTotalLength()) {
  286. // First, make DiskAdaptor read-only mode to allow the
  287. // program to seed file in read-only media.
  288. _pieceStorage->getDiskAdaptor()->enableReadOnly();
  289. } else {
  290. // Open file in writable mode to allow the program
  291. // truncate the file to _downloadContext->getTotalLength()
  292. _logger->debug("File size not match. File is opened in writable mode."
  293. " Expected:%s Actual:%s",
  294. util::uitos(_downloadContext->getTotalLength()).c_str(),
  295. util::uitos(actualFileSize).c_str());
  296. }
  297. }
  298. // Call Load, Save and file allocation command here
  299. if(progressInfoFile->exists()) {
  300. // load .aria2 file if it exists.
  301. progressInfoFile->load();
  302. _pieceStorage->getDiskAdaptor()->openFile();
  303. } else {
  304. if(_pieceStorage->getDiskAdaptor()->fileExists()) {
  305. if(!_option->getAsBool(PREF_CHECK_INTEGRITY) &&
  306. !_option->getAsBool(PREF_ALLOW_OVERWRITE) &&
  307. !_option->getAsBool(PREF_BT_SEED_UNVERIFIED)) {
  308. // TODO we need this->haltRequested = true?
  309. throw DOWNLOAD_FAILURE_EXCEPTION
  310. (StringFormat
  311. (MSG_FILE_ALREADY_EXISTS,
  312. _downloadContext->getBasePath().c_str()).str());
  313. } else {
  314. _pieceStorage->getDiskAdaptor()->openFile();
  315. }
  316. if(_option->getAsBool(PREF_BT_SEED_UNVERIFIED)) {
  317. _pieceStorage->markAllPiecesDone();
  318. }
  319. } else {
  320. _pieceStorage->getDiskAdaptor()->openFile();
  321. }
  322. }
  323. _progressInfoFile = progressInfoFile;
  324. if(torrentAttrs[bittorrent::PRIVATE].i() == 0 &&
  325. _option->getAsBool(PREF_ENABLE_DHT)) {
  326. std::deque<Command*> commands;
  327. DHTSetup().setup(commands, e, _option.get());
  328. e->addCommand(commands);
  329. if(!torrentAttrs[bittorrent::NODES].empty() && DHTSetup::initialized()) {
  330. std::deque<std::pair<std::string, uint16_t> > entryPoints;
  331. const BDE& nodes = torrentAttrs[bittorrent::NODES];
  332. for(BDE::List::const_iterator i = nodes.listBegin();
  333. i != nodes.listEnd(); ++i) {
  334. std::pair<std::string, uint16_t> addr
  335. ((*i)[bittorrent::HOSTNAME].s(), (*i)[bittorrent::PORT].i());
  336. entryPoints.push_back(addr);
  337. }
  338. DHTEntryPointNameResolveCommand* command =
  339. new DHTEntryPointNameResolveCommand(e->newCUID(), e, entryPoints);
  340. command->setTaskQueue(DHTRegistry::_taskQueue);
  341. command->setTaskFactory(DHTRegistry::_taskFactory);
  342. command->setRoutingTable(DHTRegistry::_routingTable);
  343. command->setLocalNode(DHTRegistry::_localNode);
  344. e->commands.push_back(command);
  345. }
  346. }
  347. CheckIntegrityEntryHandle entry(new BtCheckIntegrityEntry(this));
  348. // --bt-seed-unverified=true is given and download has completed, skip
  349. // validation for piece hashes.
  350. if(_option->getAsBool(PREF_BT_SEED_UNVERIFIED) &&
  351. _pieceStorage->downloadFinished()) {
  352. entry->onDownloadFinished(commands, e);
  353. } else {
  354. processCheckIntegrityEntry(commands, entry, e);
  355. }
  356. return;
  357. }
  358. }
  359. #endif // ENABLE_BITTORRENT
  360. // TODO Currently, BitTorrent+WEB-Seeding is only way to download
  361. // multiple files in one RequestGroup. In this context, we don't
  362. // have BitTorrent, so add assertion here. This situation will be
  363. // changed if Metalink spec is formalized to support multi-file
  364. // torrent.
  365. assert(_downloadContext->getFileEntries().size() == 1);
  366. // TODO I assume here when totallength is set to DownloadContext and it is
  367. // not 0, then filepath is also set DownloadContext correctly....
  368. if(_option->getAsBool(PREF_DRY_RUN) ||
  369. _downloadContext->getTotalLength() == 0) {
  370. createNextCommand(commands, e, 1);
  371. }else {
  372. if(e->_requestGroupMan->isSameFileBeingDownloaded(this)) {
  373. throw DOWNLOAD_FAILURE_EXCEPTION
  374. (StringFormat(EX_DUPLICATE_FILE_DOWNLOAD,
  375. _downloadContext->getBasePath().c_str()).str());
  376. }
  377. adjustFilename
  378. (SharedHandle<BtProgressInfoFile>(new DefaultBtProgressInfoFile
  379. (_downloadContext,
  380. SharedHandle<PieceStorage>(),
  381. _option.get())));
  382. initPieceStorage();
  383. BtProgressInfoFileHandle infoFile
  384. (new DefaultBtProgressInfoFile(_downloadContext, _pieceStorage,
  385. _option.get()));
  386. if(!infoFile->exists() && downloadFinishedByFileLength()) {
  387. _pieceStorage->markAllPiecesDone();
  388. _logger->notice(MSG_DOWNLOAD_ALREADY_COMPLETED,
  389. _gid, _downloadContext->getBasePath().c_str());
  390. } else {
  391. loadAndOpenFile(infoFile);
  392. SharedHandle<CheckIntegrityEntry> checkIntegrityEntry
  393. (new StreamCheckIntegrityEntry(this));
  394. processCheckIntegrityEntry(commands, checkIntegrityEntry, e);
  395. }
  396. }
  397. }
  398. void RequestGroup::processCheckIntegrityEntry(std::deque<Command*>& commands,
  399. const CheckIntegrityEntryHandle& entry,
  400. DownloadEngine* e)
  401. {
  402. #ifdef ENABLE_MESSAGE_DIGEST
  403. if(_option->getAsBool(PREF_CHECK_INTEGRITY) &&
  404. entry->isValidationReady()) {
  405. entry->initValidator();
  406. entry->cutTrailingGarbage();
  407. // Don't save control file(.aria2 file) when user presses
  408. // control-c key while aria2 is checking hashes. If control file
  409. // doesn't exist when aria2 launched, the completed length in
  410. // saved control file will be 0 byte and this confuses user.
  411. // enableSaveControlFile() will be called after hash checking is
  412. // done. See CheckIntegrityCommand.
  413. disableSaveControlFile();
  414. e->_checkIntegrityMan->pushEntry(entry);
  415. } else
  416. #endif // ENABLE_MESSAGE_DIGEST
  417. {
  418. entry->onDownloadIncomplete(commands, e);
  419. }
  420. }
  421. void RequestGroup::initPieceStorage()
  422. {
  423. if(_downloadContext->knowsTotalLength()) {
  424. #ifdef ENABLE_BITTORRENT
  425. SharedHandle<DefaultPieceStorage> ps
  426. (new DefaultPieceStorage(_downloadContext, _option.get()));
  427. if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) {
  428. if(isUriSuppliedForRequsetFileEntry
  429. (_downloadContext->getFileEntries().begin(),
  430. _downloadContext->getFileEntries().end())) {
  431. // Use LongestSequencePieceSelector when HTTP/FTP/BitTorrent
  432. // integrated downloads. Currently multi-file integrated
  433. // download is not supported.
  434. _logger->debug("Using LongestSequencePieceSelector");
  435. ps->setPieceSelector
  436. (SharedHandle<PieceSelector>(new LongestSequencePieceSelector()));
  437. }
  438. if(_option->defined(PREF_BT_PRIORITIZE_PIECE)) {
  439. std::vector<size_t> result;
  440. util::parsePrioritizePieceRange
  441. (result, _option->get(PREF_BT_PRIORITIZE_PIECE),
  442. _downloadContext->getFileEntries(),
  443. _downloadContext->getPieceLength());
  444. if(!result.empty()) {
  445. std::random_shuffle(result.begin(), result.end(),
  446. *(SimpleRandomizer::getInstance().get()));
  447. SharedHandle<PriorityPieceSelector> priSelector
  448. (new PriorityPieceSelector(ps->getPieceSelector()));
  449. priSelector->setPriorityPiece(result.begin(), result.end());
  450. ps->setPieceSelector(priSelector);
  451. }
  452. }
  453. }
  454. #else // !ENABLE_BITTORRENT
  455. SharedHandle<DefaultPieceStorage> ps
  456. (new DefaultPieceStorage(_downloadContext, _option.get()));
  457. #endif // !ENABLE_BITTORRENT
  458. if(!_diskWriterFactory.isNull()) {
  459. ps->setDiskWriterFactory(_diskWriterFactory);
  460. }
  461. _pieceStorage = ps;
  462. } else {
  463. UnknownLengthPieceStorageHandle ps
  464. (new UnknownLengthPieceStorage(_downloadContext, _option.get()));
  465. if(!_diskWriterFactory.isNull()) {
  466. ps->setDiskWriterFactory(_diskWriterFactory);
  467. }
  468. _pieceStorage = ps;
  469. }
  470. _pieceStorage->initStorage();
  471. initSegmentMan();
  472. }
  473. bool RequestGroup::downloadFinishedByFileLength()
  474. {
  475. // assuming that a control file doesn't exist.
  476. if(!isPreLocalFileCheckEnabled() ||
  477. _option->getAsBool(PREF_ALLOW_OVERWRITE) ||
  478. (_option->getAsBool(PREF_CHECK_INTEGRITY) &&
  479. !_downloadContext->getPieceHashes().empty())) {
  480. return false;
  481. }
  482. if(!_downloadContext->knowsTotalLength()) {
  483. return false;
  484. }
  485. File outfile(getFirstFilePath());
  486. if(outfile.exists() && _downloadContext->getTotalLength() == outfile.size()) {
  487. return true;
  488. } else {
  489. return false;
  490. }
  491. }
  492. void RequestGroup::adjustFilename
  493. (const SharedHandle<BtProgressInfoFile>& infoFile)
  494. {
  495. if(!isPreLocalFileCheckEnabled()) {
  496. // OK, no need to care about filename.
  497. } else if(infoFile->exists()) {
  498. // Use current filename
  499. } else if(downloadFinishedByFileLength()) {
  500. // File was downloaded already, no need to change file name.
  501. } else {
  502. File outfile(getFirstFilePath());
  503. if(outfile.exists() && _option->getAsBool(PREF_CONTINUE) &&
  504. outfile.size() <= _downloadContext->getTotalLength()) {
  505. // File exists but user decided to resume it.
  506. } else {
  507. #ifdef ENABLE_MESSAGE_DIGEST
  508. if(outfile.exists() && _option->getAsBool(PREF_CHECK_INTEGRITY)) {
  509. // check-integrity existing file
  510. } else {
  511. #endif // ENABLE_MESSAGE_DIGEST
  512. shouldCancelDownloadForSafety();
  513. #ifdef ENABLE_MESSAGE_DIGEST
  514. }
  515. #endif // ENABLE_MESSAGE_DIGEST
  516. }
  517. }
  518. }
  519. void RequestGroup::loadAndOpenFile(const BtProgressInfoFileHandle& progressInfoFile)
  520. {
  521. try {
  522. if(!isPreLocalFileCheckEnabled()) {
  523. _pieceStorage->getDiskAdaptor()->initAndOpenFile();
  524. return;
  525. }
  526. // Remove the control file if download file doesn't exist
  527. if(progressInfoFile->exists() && !_pieceStorage->getDiskAdaptor()->fileExists()) {
  528. progressInfoFile->removeFile();
  529. _logger->notice(MSG_REMOVED_DEFUNCT_CONTROL_FILE,
  530. progressInfoFile->getFilename().c_str(),
  531. _downloadContext->getBasePath().c_str());
  532. }
  533. if(progressInfoFile->exists()) {
  534. progressInfoFile->load();
  535. _pieceStorage->getDiskAdaptor()->openExistingFile();
  536. } else {
  537. File outfile(getFirstFilePath());
  538. if(outfile.exists() && _option->getAsBool(PREF_CONTINUE) &&
  539. outfile.size() <= getTotalLength()) {
  540. _pieceStorage->getDiskAdaptor()->openExistingFile();
  541. _pieceStorage->markPiecesDone(outfile.size());
  542. } else {
  543. #ifdef ENABLE_MESSAGE_DIGEST
  544. if(outfile.exists() && _option->getAsBool(PREF_CHECK_INTEGRITY)) {
  545. _pieceStorage->getDiskAdaptor()->openExistingFile();
  546. } else {
  547. #endif // ENABLE_MESSAGE_DIGEST
  548. _pieceStorage->getDiskAdaptor()->initAndOpenFile();
  549. #ifdef ENABLE_MESSAGE_DIGEST
  550. }
  551. #endif // ENABLE_MESSAGE_DIGEST
  552. }
  553. }
  554. setProgressInfoFile(progressInfoFile);
  555. } catch(RecoverableException& e) {
  556. throw DOWNLOAD_FAILURE_EXCEPTION2
  557. (StringFormat(EX_DOWNLOAD_ABORTED).str(), e);
  558. }
  559. }
  560. // assuming that a control file does not exist
  561. void RequestGroup::shouldCancelDownloadForSafety()
  562. {
  563. if(_option->getAsBool(PREF_ALLOW_OVERWRITE)) {
  564. return;
  565. }
  566. File outfile(getFirstFilePath());
  567. if(outfile.exists()) {
  568. if(_option->getAsBool(PREF_AUTO_FILE_RENAMING)) {
  569. if(tryAutoFileRenaming()) {
  570. _logger->notice(MSG_FILE_RENAMED, getFirstFilePath().c_str());
  571. } else {
  572. throw DOWNLOAD_FAILURE_EXCEPTION
  573. (StringFormat("File renaming failed: %s",
  574. getFirstFilePath().c_str()).str());
  575. }
  576. } else {
  577. throw DOWNLOAD_FAILURE_EXCEPTION
  578. (StringFormat(MSG_FILE_ALREADY_EXISTS,
  579. getFirstFilePath().c_str()).str());
  580. }
  581. }
  582. }
  583. bool RequestGroup::tryAutoFileRenaming()
  584. {
  585. std::string filepath = getFirstFilePath();
  586. if(filepath.empty()) {
  587. return false;
  588. }
  589. for(unsigned int i = 1; i < 10000; ++i) {
  590. File newfile(strconcat(filepath, ".", util::uitos(i)));
  591. File ctrlfile(newfile.getPath()+DefaultBtProgressInfoFile::getSuffix());
  592. if(!newfile.exists() || (newfile.exists() && ctrlfile.exists())) {
  593. _downloadContext->getFirstFileEntry()->setPath(newfile.getPath());
  594. return true;
  595. }
  596. }
  597. return false;
  598. }
  599. void RequestGroup::createNextCommandWithAdj(std::deque<Command*>& commands,
  600. DownloadEngine* e, int numAdj)
  601. {
  602. int numCommand;
  603. if(getTotalLength() == 0) {
  604. numCommand = 1+numAdj;
  605. } else {
  606. numCommand = std::min(_downloadContext->getNumPieces(),
  607. _numConcurrentCommand);
  608. numCommand += numAdj;
  609. }
  610. if(numCommand > 0) {
  611. createNextCommand(commands, e, numCommand);
  612. }
  613. }
  614. void RequestGroup::createNextCommand(std::deque<Command*>& commands,
  615. DownloadEngine* e,
  616. unsigned int numCommand)
  617. {
  618. for(; numCommand--; ) {
  619. Command* command = new CreateRequestCommand(e->newCUID(), this, e);
  620. commands.push_back(command);
  621. }
  622. if(!commands.empty()) {
  623. e->setNoWait(true);
  624. }
  625. }
  626. std::string RequestGroup::getFirstFilePath() const
  627. {
  628. assert(!_downloadContext.isNull());
  629. if(inMemoryDownload()) {
  630. static const std::string DIR_MEMORY("[MEMORY]");
  631. return DIR_MEMORY+File(_downloadContext->getFirstFileEntry()->getPath()).getBasename();
  632. } else {
  633. return _downloadContext->getFirstFileEntry()->getPath();
  634. }
  635. }
  636. uint64_t RequestGroup::getTotalLength() const
  637. {
  638. if(_pieceStorage.isNull()) {
  639. return 0;
  640. } else {
  641. if(_pieceStorage->isSelectiveDownloadingMode()) {
  642. return _pieceStorage->getFilteredTotalLength();
  643. } else {
  644. return _pieceStorage->getTotalLength();
  645. }
  646. }
  647. }
  648. uint64_t RequestGroup::getCompletedLength() const
  649. {
  650. if(_pieceStorage.isNull()) {
  651. return 0;
  652. } else {
  653. if(_pieceStorage->isSelectiveDownloadingMode()) {
  654. return _pieceStorage->getFilteredCompletedLength();
  655. } else {
  656. return _pieceStorage->getCompletedLength();
  657. }
  658. }
  659. }
  660. void RequestGroup::validateFilename(const std::string& expectedFilename,
  661. const std::string& actualFilename) const
  662. {
  663. if(expectedFilename.empty()) {
  664. return;
  665. }
  666. if(expectedFilename != actualFilename) {
  667. throw DL_ABORT_EX(StringFormat(EX_FILENAME_MISMATCH,
  668. expectedFilename.c_str(),
  669. actualFilename.c_str()).str());
  670. }
  671. }
  672. void RequestGroup::validateTotalLength(uint64_t expectedTotalLength,
  673. uint64_t actualTotalLength) const
  674. {
  675. if(expectedTotalLength <= 0) {
  676. return;
  677. }
  678. if(expectedTotalLength != actualTotalLength) {
  679. throw DL_ABORT_EX
  680. (StringFormat(EX_SIZE_MISMATCH,
  681. util::itos(expectedTotalLength, true).c_str(),
  682. util::itos(actualTotalLength, true).c_str()).str());
  683. }
  684. }
  685. void RequestGroup::validateFilename(const std::string& actualFilename) const
  686. {
  687. validateFilename(_downloadContext->getFileEntries().front()->getBasename(), actualFilename);
  688. }
  689. void RequestGroup::validateTotalLength(uint64_t actualTotalLength) const
  690. {
  691. validateTotalLength(getTotalLength(), actualTotalLength);
  692. }
  693. void RequestGroup::increaseStreamConnection()
  694. {
  695. ++_numStreamConnection;
  696. }
  697. void RequestGroup::decreaseStreamConnection()
  698. {
  699. --_numStreamConnection;
  700. }
  701. unsigned int RequestGroup::getNumConnection() const
  702. {
  703. unsigned int numConnection = _numStreamConnection;
  704. #ifdef ENABLE_BITTORRENT
  705. if(!_btRuntime.isNull()) {
  706. numConnection += _btRuntime->getConnections();
  707. }
  708. #endif // ENABLE_BITTORRENT
  709. return numConnection;
  710. }
  711. void RequestGroup::increaseNumCommand()
  712. {
  713. ++_numCommand;
  714. }
  715. void RequestGroup::decreaseNumCommand()
  716. {
  717. --_numCommand;
  718. }
  719. TransferStat RequestGroup::calculateStat()
  720. {
  721. TransferStat stat;
  722. #ifdef ENABLE_BITTORRENT
  723. if(!_peerStorage.isNull()) {
  724. stat = _peerStorage->calculateStat();
  725. }
  726. #endif // ENABLE_BITTORRENT
  727. if(!_segmentMan.isNull()) {
  728. stat.setDownloadSpeed(stat.getDownloadSpeed()+_segmentMan->calculateDownloadSpeed());
  729. }
  730. return stat;
  731. }
  732. void RequestGroup::setHaltRequested(bool f, HaltReason haltReason)
  733. {
  734. _haltRequested = f;
  735. if(_haltRequested) {
  736. _haltReason = haltReason;
  737. }
  738. #ifdef ENABLE_BITTORRENT
  739. if(!_btRuntime.isNull()) {
  740. _btRuntime->setHalt(f);
  741. }
  742. #endif // ENABLE_BITTORRENT
  743. }
  744. void RequestGroup::setForceHaltRequested(bool f, HaltReason haltReason)
  745. {
  746. setHaltRequested(f, haltReason);
  747. _forceHaltRequested = f;
  748. }
  749. void RequestGroup::releaseRuntimeResource(DownloadEngine* e)
  750. {
  751. #ifdef ENABLE_BITTORRENT
  752. e->getBtRegistry()->remove(_gid);
  753. #endif // ENABLE_BITTORRENT
  754. if(!_pieceStorage.isNull()) {
  755. _pieceStorage->removeAdvertisedPiece(0);
  756. }
  757. _downloadContext->releaseRuntimeResource();
  758. }
  759. void RequestGroup::preDownloadProcessing()
  760. {
  761. _logger->debug("Finding PreDownloadHandler for path %s.",
  762. getFirstFilePath().c_str());
  763. try {
  764. for(PreDownloadHandlers::const_iterator itr = _preDownloadHandlers.begin();
  765. itr != _preDownloadHandlers.end(); ++itr) {
  766. if((*itr)->canHandle(this)) {
  767. (*itr)->execute(this);
  768. return;
  769. }
  770. }
  771. } catch(RecoverableException& ex) {
  772. _logger->error(EX_EXCEPTION_CAUGHT, ex);
  773. return;
  774. }
  775. _logger->debug("No PreDownloadHandler found.");
  776. return;
  777. }
  778. void RequestGroup::postDownloadProcessing
  779. (std::deque<SharedHandle<RequestGroup> >& groups)
  780. {
  781. _logger->debug("Finding PostDownloadHandler for path %s.",
  782. getFirstFilePath().c_str());
  783. try {
  784. for(PostDownloadHandlers::const_iterator itr = _postDownloadHandlers.begin();
  785. itr != _postDownloadHandlers.end(); ++itr) {
  786. if((*itr)->canHandle(this)) {
  787. (*itr)->getNextRequestGroups(groups, this);
  788. return;
  789. }
  790. }
  791. } catch(RecoverableException& ex) {
  792. _logger->error(EX_EXCEPTION_CAUGHT, ex);
  793. }
  794. _logger->debug("No PostDownloadHandler found.");
  795. }
  796. void RequestGroup::initializePreDownloadHandler()
  797. {
  798. #ifdef ENABLE_BITTORRENT
  799. if(_option->get(PREF_FOLLOW_TORRENT) == V_MEM) {
  800. _preDownloadHandlers.push_back(DownloadHandlerFactory::getBtPreDownloadHandler());
  801. }
  802. #endif // ENABLE_BITTORRENT
  803. #ifdef ENABLE_METALINK
  804. if(_option->get(PREF_FOLLOW_METALINK) == V_MEM) {
  805. _preDownloadHandlers.push_back(DownloadHandlerFactory::getMetalinkPreDownloadHandler());
  806. }
  807. #endif // ENABLE_METALINK
  808. }
  809. void RequestGroup::initializePostDownloadHandler()
  810. {
  811. #ifdef ENABLE_BITTORRENT
  812. if(_option->getAsBool(PREF_FOLLOW_TORRENT) ||
  813. _option->get(PREF_FOLLOW_TORRENT) == V_MEM) {
  814. _postDownloadHandlers.push_back(DownloadHandlerFactory::getBtPostDownloadHandler());
  815. }
  816. #endif // ENABLE_BITTORRENT
  817. #ifdef ENABLE_METALINK
  818. if(_option->getAsBool(PREF_FOLLOW_METALINK) ||
  819. _option->get(PREF_FOLLOW_METALINK) == V_MEM) {
  820. _postDownloadHandlers.push_back(DownloadHandlerFactory::getMetalinkPostDownloadHandler());
  821. }
  822. #endif // ENABLE_METALINK
  823. }
  824. bool RequestGroup::isDependencyResolved()
  825. {
  826. if(_dependency.isNull()) {
  827. return true;
  828. }
  829. return _dependency->resolve();
  830. }
  831. void RequestGroup::setSegmentManFactory(const SegmentManFactoryHandle& segmentManFactory)
  832. {
  833. _segmentManFactory = segmentManFactory;
  834. }
  835. void RequestGroup::dependsOn(const DependencyHandle& dep)
  836. {
  837. _dependency = dep;
  838. }
  839. void RequestGroup::setDiskWriterFactory(const DiskWriterFactoryHandle& diskWriterFactory)
  840. {
  841. _diskWriterFactory = diskWriterFactory;
  842. }
  843. void RequestGroup::addPostDownloadHandler(const PostDownloadHandlerHandle& handler)
  844. {
  845. _postDownloadHandlers.push_back(handler);
  846. }
  847. void RequestGroup::addPreDownloadHandler(const PreDownloadHandlerHandle& handler)
  848. {
  849. _preDownloadHandlers.push_back(handler);
  850. }
  851. void RequestGroup::clearPostDownloadHandler()
  852. {
  853. _postDownloadHandlers.clear();
  854. }
  855. void RequestGroup::clearPreDownloadHandler()
  856. {
  857. _preDownloadHandlers.clear();
  858. }
  859. void RequestGroup::setPieceStorage(const PieceStorageHandle& pieceStorage)
  860. {
  861. _pieceStorage = pieceStorage;
  862. }
  863. void RequestGroup::setProgressInfoFile(const BtProgressInfoFileHandle& progressInfoFile)
  864. {
  865. _progressInfoFile = progressInfoFile;
  866. }
  867. bool RequestGroup::needsFileAllocation() const
  868. {
  869. return isFileAllocationEnabled() &&
  870. (uint64_t)_option->getAsLLInt(PREF_NO_FILE_ALLOCATION_LIMIT) <= getTotalLength() &&
  871. !_pieceStorage->getDiskAdaptor()->fileAllocationIterator()->finished();
  872. }
  873. DownloadResultHandle RequestGroup::createDownloadResult() const
  874. {
  875. uint64_t sessionDownloadLength = 0;
  876. #ifdef ENABLE_BITTORRENT
  877. if(!_peerStorage.isNull()) {
  878. sessionDownloadLength +=
  879. _peerStorage->calculateStat().getSessionDownloadLength();
  880. }
  881. #endif // ENABLE_BITTORRENT
  882. if(!_segmentMan.isNull()) {
  883. sessionDownloadLength +=
  884. _segmentMan->calculateSessionDownloadLength();
  885. }
  886. return
  887. SharedHandle<DownloadResult>
  888. (new DownloadResult(_gid,
  889. _downloadContext->getFileEntries(),
  890. _inMemoryDownload,
  891. sessionDownloadLength,
  892. _downloadContext->calculateSessionTime(),
  893. downloadResult(),
  894. _followedByGIDs,
  895. _belongsToGID));
  896. }
  897. void RequestGroup::reportDownloadFinished()
  898. {
  899. _logger->notice(MSG_FILE_DOWNLOAD_COMPLETED,
  900. _downloadContext->getBasePath().c_str());
  901. _uriSelector->resetCounters();
  902. #ifdef ENABLE_BITTORRENT
  903. if(_downloadContext->hasAttribute(bittorrent::BITTORRENT)) {
  904. TransferStat stat = calculateStat();
  905. double shareRatio =
  906. ((stat.getAllTimeUploadLength()*10)/getCompletedLength())/10.0;
  907. const BDE& attrs = _downloadContext->getAttribute(bittorrent::BITTORRENT);
  908. if(attrs.containsKey(bittorrent::METADATA)) {
  909. _logger->notice(MSG_SHARE_RATIO_REPORT,
  910. shareRatio,
  911. util::abbrevSize(stat.getAllTimeUploadLength()).c_str(),
  912. util::abbrevSize(getCompletedLength()).c_str());
  913. }
  914. }
  915. #endif // ENABLE_BITTORRENT
  916. }
  917. void RequestGroup::addAcceptType(const std::string& type)
  918. {
  919. if(std::find(_acceptTypes.begin(), _acceptTypes.end(), type) == _acceptTypes.end()) {
  920. _acceptTypes.push_back(type);
  921. }
  922. }
  923. void RequestGroup::removeAcceptType(const std::string& type)
  924. {
  925. _acceptTypes.erase(std::remove(_acceptTypes.begin(), _acceptTypes.end(), type),
  926. _acceptTypes.end());
  927. }
  928. void RequestGroup::setURISelector(const SharedHandle<URISelector>& uriSelector)
  929. {
  930. _uriSelector = uriSelector;
  931. }
  932. void RequestGroup::applyLastModifiedTimeToLocalFiles()
  933. {
  934. if(!_pieceStorage.isNull() && _lastModifiedTime.good()) {
  935. time_t t = _lastModifiedTime.getTime();
  936. _logger->info("Applying Last-Modified time: %s in local time zone",
  937. ctime(&t));
  938. size_t n =
  939. _pieceStorage->getDiskAdaptor()->utime(Time(), _lastModifiedTime);
  940. _logger->info("Last-Modified attrs of %lu files were updated.",
  941. static_cast<unsigned long>(n));
  942. }
  943. }
  944. void RequestGroup::updateLastModifiedTime(const Time& time)
  945. {
  946. if(time.good() && _lastModifiedTime < time) {
  947. _lastModifiedTime = time;
  948. }
  949. }
  950. void RequestGroup::increaseAndValidateFileNotFoundCount()
  951. {
  952. ++_fileNotFoundCount;
  953. const unsigned int maxCount = _option->getAsInt(PREF_MAX_FILE_NOT_FOUND);
  954. if(maxCount > 0 && _fileNotFoundCount >= maxCount &&
  955. _segmentMan->calculateSessionDownloadLength() == 0) {
  956. throw DOWNLOAD_FAILURE_EXCEPTION2
  957. (StringFormat("Reached max-file-not-found count=%u", maxCount).str(),
  958. downloadresultcode::MAX_FILE_NOT_FOUND);
  959. }
  960. }
  961. void RequestGroup::markInMemoryDownload()
  962. {
  963. _inMemoryDownload = true;
  964. }
  965. void RequestGroup::setTimeout(time_t timeout)
  966. {
  967. _timeout = timeout;
  968. }
  969. bool RequestGroup::doesDownloadSpeedExceed()
  970. {
  971. return _maxDownloadSpeedLimit > 0 &&
  972. _maxDownloadSpeedLimit < calculateStat().getDownloadSpeed();
  973. }
  974. bool RequestGroup::doesUploadSpeedExceed()
  975. {
  976. return _maxUploadSpeedLimit > 0 &&
  977. _maxUploadSpeedLimit < calculateStat().getUploadSpeed();
  978. }
  979. void RequestGroup::setLastUriResult
  980. (const std::string uri, downloadresultcode::RESULT result)
  981. {
  982. _lastUriResult.reset(new URIResult(uri, result));
  983. }
  984. void RequestGroup::saveControlFile() const
  985. {
  986. if(_saveControlFile) {
  987. _progressInfoFile->save();
  988. }
  989. }
  990. void RequestGroup::removeControlFile() const
  991. {
  992. _progressInfoFile->removeFile();
  993. }
  994. void RequestGroup::setDownloadContext
  995. (const SharedHandle<DownloadContext>& downloadContext)
  996. {
  997. _downloadContext = downloadContext;
  998. if(!_downloadContext.isNull()) {
  999. _downloadContext->setOwnerRequestGroup(this);
  1000. }
  1001. }
  1002. } // namespace aria2