AbstractCommand.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859
  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 "AbstractCommand.h"
  36. #include <algorithm>
  37. #include "Request.h"
  38. #include "DownloadEngine.h"
  39. #include "Option.h"
  40. #include "PeerStat.h"
  41. #include "SegmentMan.h"
  42. #include "Logger.h"
  43. #include "Segment.h"
  44. #include "DlAbortEx.h"
  45. #include "DlRetryEx.h"
  46. #include "DownloadFailureException.h"
  47. #include "CreateRequestCommand.h"
  48. #include "InitiateConnectionCommandFactory.h"
  49. #include "SleepCommand.h"
  50. #ifdef ENABLE_ASYNC_DNS
  51. #include "AsyncNameResolver.h"
  52. #endif // ENABLE_ASYNC_DNS
  53. #include "StreamCheckIntegrityEntry.h"
  54. #include "PieceStorage.h"
  55. #include "Socket.h"
  56. #include "message.h"
  57. #include "prefs.h"
  58. #include "StringFormat.h"
  59. #include "ServerStat.h"
  60. #include "RequestGroupMan.h"
  61. #include "A2STR.h"
  62. #include "util.h"
  63. #include "LogFactory.h"
  64. #include "DownloadContext.h"
  65. #include "wallclock.h"
  66. #include "NameResolver.h"
  67. #include "ServerStatMan.h"
  68. #include "FileAllocationEntry.h"
  69. #ifdef ENABLE_MESSAGE_DIGEST
  70. # include "ChecksumCheckIntegrityEntry.h"
  71. #endif // ENABLE_MESSAGE_DIGEST
  72. namespace aria2 {
  73. AbstractCommand::AbstractCommand(cuid_t cuid,
  74. const SharedHandle<Request>& req,
  75. const SharedHandle<FileEntry>& fileEntry,
  76. RequestGroup* requestGroup,
  77. DownloadEngine* e,
  78. const SocketHandle& s,
  79. bool incNumConnection):
  80. Command(cuid), checkPoint_(global::wallclock),
  81. timeout_(requestGroup->getTimeout()),
  82. requestGroup_(requestGroup),
  83. req_(req), fileEntry_(fileEntry), e_(e), socket_(s),
  84. checkSocketIsReadable_(false), checkSocketIsWritable_(false),
  85. nameResolverCheck_(false),
  86. incNumConnection_(incNumConnection)
  87. {
  88. if(!socket_.isNull() && socket_->isOpen()) {
  89. setReadCheckSocket(socket_);
  90. }
  91. if(incNumConnection_) {
  92. requestGroup->increaseStreamConnection();
  93. }
  94. requestGroup_->increaseStreamCommand();
  95. requestGroup_->increaseNumCommand();
  96. }
  97. AbstractCommand::~AbstractCommand() {
  98. disableReadCheckSocket();
  99. disableWriteCheckSocket();
  100. #ifdef ENABLE_ASYNC_DNS
  101. disableNameResolverCheck(asyncNameResolver_);
  102. #endif // ENABLE_ASYNC_DNS
  103. requestGroup_->decreaseNumCommand();
  104. requestGroup_->decreaseStreamCommand();
  105. if(incNumConnection_) {
  106. requestGroup_->decreaseStreamConnection();
  107. }
  108. }
  109. bool AbstractCommand::execute() {
  110. if(getLogger()->debug()) {
  111. getLogger()->debug("CUID#%s - socket: read:%d, write:%d, hup:%d, err:%d",
  112. util::itos(getCuid()).c_str(),
  113. readEventEnabled(),
  114. writeEventEnabled(),
  115. hupEventEnabled(),
  116. errorEventEnabled());
  117. }
  118. try {
  119. if(requestGroup_->downloadFinished() || requestGroup_->isHaltRequested()) {
  120. return true;
  121. }
  122. if(!req_.isNull() && req_->removalRequested()) {
  123. if(getLogger()->debug()) {
  124. getLogger()->debug
  125. ("CUID#%s - Discard original URI=%s because it is requested.",
  126. util::itos(getCuid()).c_str(), req_->getUri().c_str());
  127. }
  128. return prepareForRetry(0);
  129. }
  130. if(!getPieceStorage().isNull()) {
  131. segments_.clear();
  132. getSegmentMan()->getInFlightSegment(segments_, getCuid());
  133. if(!req_.isNull() && segments_.empty()) {
  134. // This command previously has assigned segments, but it is
  135. // canceled. So discard current request chain. Plus, if no
  136. // segment is available when http pipelining is used.
  137. if(getLogger()->debug()) {
  138. getLogger()->debug("CUID#%s - It seems previously assigned segments"
  139. " are canceled. Restart.",
  140. util::itos(getCuid()).c_str());
  141. }
  142. // Request::isPipeliningEnabled() == true means aria2
  143. // accessed the remote server and discovered that the server
  144. // supports pipelining.
  145. if(!req_.isNull() && req_->isPipeliningEnabled()) {
  146. e_->poolSocket(req_, createProxyRequest(), socket_);
  147. }
  148. return prepareForRetry(0);
  149. }
  150. // TODO it is not needed to check other PeerStats every time.
  151. // Find faster Request when no segment is available.
  152. if(!req_.isNull() && fileEntry_->countPooledRequest() > 0 &&
  153. !getPieceStorage()->hasMissingUnusedPiece()) {
  154. SharedHandle<Request> fasterRequest = fileEntry_->findFasterRequest(req_);
  155. if(!fasterRequest.isNull()) {
  156. if(getLogger()->info()) {
  157. getLogger()->info("CUID#%s - Use faster Request hostname=%s, port=%u",
  158. util::itos(getCuid()).c_str(),
  159. fasterRequest->getHost().c_str(),
  160. fasterRequest->getPort());
  161. }
  162. // Cancel current Request object and use faster one.
  163. fileEntry_->removeRequest(req_);
  164. Command* command =
  165. InitiateConnectionCommandFactory::createInitiateConnectionCommand
  166. (getCuid(), fasterRequest, fileEntry_, requestGroup_, e_);
  167. e_->setNoWait(true);
  168. e_->addCommand(command);
  169. return true;
  170. }
  171. }
  172. }
  173. if((checkSocketIsReadable_ && readEventEnabled()) ||
  174. (checkSocketIsWritable_ && writeEventEnabled()) ||
  175. hupEventEnabled() ||
  176. #ifdef ENABLE_ASYNC_DNS
  177. (nameResolverCheck_ && nameResolveFinished()) ||
  178. #endif // ENABLE_ASYNC_DNS
  179. (!checkSocketIsReadable_ && !checkSocketIsWritable_ &&
  180. !nameResolverCheck_)) {
  181. checkPoint_ = global::wallclock;
  182. if(!getPieceStorage().isNull()) {
  183. if(req_.isNull() || req_->getMaxPipelinedRequest() == 1 ||
  184. // Why the following condition is necessary? That's because
  185. // For single file download, SegmentMan::getSegment(cuid)
  186. // is more efficient.
  187. getDownloadContext()->getFileEntries().size() == 1) {
  188. size_t maxSegments = req_.isNull()?1:req_->getMaxPipelinedRequest();
  189. size_t minSplitSize = calculateMinSplitSize();
  190. while(segments_.size() < maxSegments) {
  191. SharedHandle<Segment> segment =
  192. getSegmentMan()->getSegment(getCuid(), minSplitSize);
  193. if(segment.isNull()) {
  194. break;
  195. } else {
  196. segments_.push_back(segment);
  197. }
  198. }
  199. if(segments_.empty()) {
  200. // TODO socket could be pooled here if pipelining is
  201. // enabled... Hmm, I don't think if pipelining is enabled
  202. // it does not go here.
  203. if(getLogger()->info()) {
  204. getLogger()->info(MSG_NO_SEGMENT_AVAILABLE,
  205. util::itos(getCuid()).c_str());
  206. }
  207. // When all segments are ignored in SegmentMan, there are
  208. // no URIs available, so don't retry.
  209. if(getSegmentMan()->allSegmentsIgnored()) {
  210. if(getLogger()->debug()) {
  211. getLogger()->debug("All segments are ignored.");
  212. }
  213. return true;
  214. } else {
  215. return prepareForRetry(1);
  216. }
  217. }
  218. } else {
  219. // For multi-file downloads
  220. size_t minSplitSize = calculateMinSplitSize();
  221. size_t maxSegments = req_->getMaxPipelinedRequest();
  222. if(segments_.size() < maxSegments) {
  223. getSegmentMan()->getSegment
  224. (segments_, getCuid(), minSplitSize, fileEntry_, maxSegments);
  225. }
  226. if(segments_.empty()) {
  227. return prepareForRetry(0);
  228. }
  229. }
  230. }
  231. return executeInternal();
  232. } else if(errorEventEnabled()) {
  233. throw DL_RETRY_EX
  234. (StringFormat(MSG_NETWORK_PROBLEM,
  235. socket_->getSocketError().c_str()).str());
  236. } else {
  237. if(checkPoint_.difference(global::wallclock) >= timeout_) {
  238. // timeout triggers ServerStat error state.
  239. SharedHandle<ServerStat> ss =
  240. e_->getRequestGroupMan()->getOrCreateServerStat(req_->getHost(),
  241. req_->getProtocol());
  242. ss->setError();
  243. throw DL_RETRY_EX2(EX_TIME_OUT, downloadresultcode::TIME_OUT);
  244. }
  245. e_->addCommand(this);
  246. return false;
  247. }
  248. } catch(DlAbortEx& err) {
  249. if(req_.isNull()) {
  250. if(getLogger()->debug()) {
  251. getLogger()->debug(EX_EXCEPTION_CAUGHT, err);
  252. }
  253. } else {
  254. getLogger()->error
  255. (MSG_DOWNLOAD_ABORTED,
  256. DL_ABORT_EX2(StringFormat
  257. ("URI=%s", req_->getCurrentUri().c_str()).str(),err),
  258. util::itos(getCuid()).c_str(), req_->getUri().c_str());
  259. fileEntry_->addURIResult(req_->getUri(), err.getCode());
  260. requestGroup_->setLastUriResult(req_->getUri(), err.getCode());
  261. if(err.getCode() == downloadresultcode::CANNOT_RESUME) {
  262. requestGroup_->increaseResumeFailureCount();
  263. }
  264. }
  265. onAbort();
  266. tryReserved();
  267. return true;
  268. } catch(DlRetryEx& err) {
  269. assert(!req_.isNull());
  270. if(getLogger()->info()) {
  271. getLogger()->info
  272. (MSG_RESTARTING_DOWNLOAD,
  273. DL_RETRY_EX2(StringFormat
  274. ("URI=%s", req_->getCurrentUri().c_str()).str(),
  275. err),
  276. util::itos(getCuid()).c_str(), req_->getUri().c_str());
  277. }
  278. req_->addTryCount();
  279. req_->resetRedirectCount();
  280. const unsigned int maxTries = getOption()->getAsInt(PREF_MAX_TRIES);
  281. bool isAbort = maxTries != 0 && req_->getTryCount() >= maxTries;
  282. if(isAbort) {
  283. if(getLogger()->info()) {
  284. getLogger()->info(MSG_MAX_TRY,
  285. util::itos(getCuid()).c_str(), req_->getTryCount());
  286. }
  287. getLogger()->error(MSG_DOWNLOAD_ABORTED, err,
  288. util::itos(getCuid()).c_str(),
  289. req_->getUri().c_str());
  290. fileEntry_->addURIResult(req_->getUri(), err.getCode());
  291. requestGroup_->setLastUriResult(req_->getUri(), err.getCode());
  292. if(err.getCode() == downloadresultcode::CANNOT_RESUME) {
  293. requestGroup_->increaseResumeFailureCount();
  294. }
  295. onAbort();
  296. tryReserved();
  297. return true;
  298. } else {
  299. return prepareForRetry(0);
  300. }
  301. } catch(DownloadFailureException& err) {
  302. getLogger()->error(EX_EXCEPTION_CAUGHT, err);
  303. if(!req_.isNull()) {
  304. fileEntry_->addURIResult(req_->getUri(), err.getCode());
  305. requestGroup_->setLastUriResult(req_->getUri(), err.getCode());
  306. }
  307. requestGroup_->setHaltRequested(true);
  308. return true;
  309. }
  310. }
  311. void AbstractCommand::tryReserved() {
  312. if(getDownloadContext()->getFileEntries().size() == 1) {
  313. const SharedHandle<FileEntry>& entry =
  314. getDownloadContext()->getFirstFileEntry();
  315. // Don't create new command if currently file length is unknown
  316. // and there are no URI left. Because file length is unknown, we
  317. // can assume that there are no in-flight request object.
  318. if(entry->getLength() == 0 && entry->getRemainingUris().empty()) {
  319. if(getLogger()->debug()) {
  320. getLogger()->debug("CUID#%s - Not trying next request."
  321. " No reserved/pooled request is remaining and"
  322. " total length is still unknown.",
  323. util::itos(getCuid()).c_str());
  324. }
  325. return;
  326. }
  327. }
  328. if(getLogger()->debug()) {
  329. getLogger()->debug("CUID#%s - Trying reserved/pooled request.",
  330. util::itos(getCuid()).c_str());
  331. }
  332. std::vector<Command*> commands;
  333. requestGroup_->createNextCommand(commands, e_, 1);
  334. e_->setNoWait(true);
  335. e_->addCommand(commands);
  336. }
  337. bool AbstractCommand::prepareForRetry(time_t wait) {
  338. if(!getPieceStorage().isNull()) {
  339. getSegmentMan()->cancelSegment(getCuid());
  340. }
  341. if(!req_.isNull()) {
  342. fileEntry_->poolRequest(req_);
  343. if(getLogger()->debug()) {
  344. getLogger()->debug("CUID#%s - Pooling request URI=%s",
  345. util::itos(getCuid()).c_str(), req_->getUri().c_str());
  346. }
  347. if(!getSegmentMan().isNull()) {
  348. getSegmentMan()->recognizeSegmentFor(fileEntry_);
  349. }
  350. }
  351. Command* command = new CreateRequestCommand(getCuid(), requestGroup_, e_);
  352. if(wait == 0) {
  353. e_->setNoWait(true);
  354. e_->addCommand(command);
  355. } else {
  356. SleepCommand* scom = new SleepCommand(getCuid(), e_, requestGroup_,
  357. command, wait);
  358. e_->addCommand(scom);
  359. }
  360. return true;
  361. }
  362. void AbstractCommand::onAbort() {
  363. if(!req_.isNull()) {
  364. // TODO This might be a problem if the failure is caused by proxy.
  365. e_->getRequestGroupMan()->getOrCreateServerStat
  366. (req_->getHost(), req_->getProtocol())->setError();
  367. fileEntry_->removeIdenticalURI(req_->getUri());
  368. fileEntry_->removeRequest(req_);
  369. }
  370. if(getLogger()->debug()) {
  371. getLogger()->debug("CUID#%s - Aborting download",
  372. util::itos(getCuid()).c_str());
  373. }
  374. if(!getPieceStorage().isNull()) {
  375. getSegmentMan()->cancelSegment(getCuid());
  376. // Don't do following process if BitTorrent is involved or files
  377. // in DownloadContext is more than 1. The latter condition is
  378. // limitation of current implementation.
  379. if(!getOption()->getAsBool(PREF_ALWAYS_RESUME) &&
  380. !fileEntry_.isNull() &&
  381. getSegmentMan()->calculateSessionDownloadLength() == 0 &&
  382. !requestGroup_->p2pInvolved() &&
  383. getDownloadContext()->getFileEntries().size() == 1) {
  384. const int maxTries = getOption()->getAsInt(PREF_MAX_RESUME_FAILURE_TRIES);
  385. if((maxTries > 0 && requestGroup_->getResumeFailureCount() >= maxTries)||
  386. fileEntry_->emptyRequestUri()) {
  387. // Local file exists, but given servers(or at least contacted
  388. // ones) doesn't support resume. Let's restart download from
  389. // scratch.
  390. getLogger()->notice("CUID#%s - Failed to resume download."
  391. " Download from scratch.",
  392. util::itos(getCuid()).c_str());
  393. if(getLogger()->debug()) {
  394. getLogger()->debug
  395. ("CUID#%s - Gathering URIs that has CANNOT_RESUME error",
  396. util::itos(getCuid()).c_str());
  397. }
  398. // Set PREF_ALWAYS_RESUME to V_TRUE to avoid repeating this
  399. // process.
  400. getOption()->put(PREF_ALWAYS_RESUME, V_TRUE);
  401. std::deque<URIResult> res;
  402. fileEntry_->extractURIResult(res, downloadresultcode::CANNOT_RESUME);
  403. if(!res.empty()) {
  404. getSegmentMan()->cancelAllSegments();
  405. getSegmentMan()->eraseSegmentWrittenLengthMemo();
  406. getPieceStorage()->markPiecesDone(0);
  407. std::vector<std::string> uris;
  408. uris.reserve(res.size());
  409. std::transform(res.begin(), res.end(), std::back_inserter(uris),
  410. std::mem_fun_ref(&URIResult::getURI));
  411. if(getLogger()->debug()) {
  412. getLogger()->debug("CUID#%s - %lu URIs found.",
  413. util::itos(getCuid()).c_str(),
  414. static_cast<unsigned long int>(uris.size()));
  415. }
  416. fileEntry_->addUris(uris.begin(), uris.end());
  417. getSegmentMan()->recognizeSegmentFor(fileEntry_);
  418. }
  419. }
  420. }
  421. }
  422. }
  423. void AbstractCommand::disableReadCheckSocket() {
  424. if(checkSocketIsReadable_) {
  425. e_->deleteSocketForReadCheck(readCheckTarget_, this);
  426. checkSocketIsReadable_ = false;
  427. readCheckTarget_.reset();
  428. }
  429. }
  430. void AbstractCommand::setReadCheckSocket(const SocketHandle& socket) {
  431. if(!socket->isOpen()) {
  432. disableReadCheckSocket();
  433. } else {
  434. if(checkSocketIsReadable_) {
  435. if(readCheckTarget_ != socket) {
  436. e_->deleteSocketForReadCheck(readCheckTarget_, this);
  437. e_->addSocketForReadCheck(socket, this);
  438. readCheckTarget_ = socket;
  439. }
  440. } else {
  441. e_->addSocketForReadCheck(socket, this);
  442. checkSocketIsReadable_ = true;
  443. readCheckTarget_ = socket;
  444. }
  445. }
  446. }
  447. void AbstractCommand::setReadCheckSocketIf
  448. (const SharedHandle<SocketCore>& socket, bool pred)
  449. {
  450. if(pred) {
  451. setReadCheckSocket(socket);
  452. } else {
  453. disableReadCheckSocket();
  454. }
  455. }
  456. void AbstractCommand::disableWriteCheckSocket() {
  457. if(checkSocketIsWritable_) {
  458. e_->deleteSocketForWriteCheck(writeCheckTarget_, this);
  459. checkSocketIsWritable_ = false;
  460. writeCheckTarget_.reset();
  461. }
  462. }
  463. void AbstractCommand::setWriteCheckSocket(const SocketHandle& socket) {
  464. if(!socket->isOpen()) {
  465. disableWriteCheckSocket();
  466. } else {
  467. if(checkSocketIsWritable_) {
  468. if(writeCheckTarget_ != socket) {
  469. e_->deleteSocketForWriteCheck(writeCheckTarget_, this);
  470. e_->addSocketForWriteCheck(socket, this);
  471. writeCheckTarget_ = socket;
  472. }
  473. } else {
  474. e_->addSocketForWriteCheck(socket, this);
  475. checkSocketIsWritable_ = true;
  476. writeCheckTarget_ = socket;
  477. }
  478. }
  479. }
  480. void AbstractCommand::setWriteCheckSocketIf
  481. (const SharedHandle<SocketCore>& socket, bool pred)
  482. {
  483. if(pred) {
  484. setWriteCheckSocket(socket);
  485. } else {
  486. disableWriteCheckSocket();
  487. }
  488. }
  489. // Returns proxy option value for the given protocol.
  490. static const std::string& getProxyOptionFor
  491. (const std::string& proxyPref, const SharedHandle<Option>& option)
  492. {
  493. if(option->defined(proxyPref)) {
  494. return option->get(proxyPref);
  495. } else {
  496. return option->get(PREF_ALL_PROXY);
  497. }
  498. }
  499. // Returns proxy URI for given protocol. If no proxy URI is defined,
  500. // then returns an empty string.
  501. static const std::string& getProxyUri
  502. (const std::string& protocol, const SharedHandle<Option>& option)
  503. {
  504. if(protocol == Request::PROTO_HTTP) {
  505. return getProxyOptionFor(PREF_HTTP_PROXY, option);
  506. } else if(protocol == Request::PROTO_HTTPS) {
  507. return getProxyOptionFor(PREF_HTTPS_PROXY, option);
  508. } else if(protocol == Request::PROTO_FTP) {
  509. return getProxyOptionFor(PREF_FTP_PROXY, option);
  510. } else {
  511. return A2STR::NIL;
  512. }
  513. }
  514. // Returns true if proxy is defined for the given protocol. Otherwise
  515. // returns false.
  516. static bool isProxyRequest
  517. (const std::string& protocol, const SharedHandle<Option>& option)
  518. {
  519. const std::string& proxyUri = getProxyUri(protocol, option);
  520. return !proxyUri.empty() && Request().setUri(proxyUri);
  521. }
  522. class DomainMatch {
  523. private:
  524. std::string hostname_;
  525. public:
  526. DomainMatch(const std::string& hostname):hostname_(hostname) {}
  527. bool operator()(const std::string& domain) const
  528. {
  529. if(util::startsWith(domain, A2STR::DOT_C)) {
  530. return util::endsWith(hostname_, domain);
  531. } else {
  532. return util::endsWith(hostname_, A2STR::DOT_C+domain);
  533. }
  534. }
  535. };
  536. static bool inNoProxy(const SharedHandle<Request>& req,
  537. const std::string& noProxy)
  538. {
  539. std::vector<std::string> entries;
  540. util::split(noProxy, std::back_inserter(entries), ",", true);
  541. if(entries.empty()) {
  542. return false;
  543. }
  544. DomainMatch domainMatch(A2STR::DOT_C+req->getHost());
  545. for(std::vector<std::string>::const_iterator i = entries.begin(),
  546. eoi = entries.end(); i != eoi; ++i) {
  547. std::string::size_type slashpos = (*i).find('/');
  548. if(slashpos == std::string::npos) {
  549. if(util::isNumericHost(*i)) {
  550. if(req->getHost() == *i) {
  551. return true;
  552. }
  553. } else if(domainMatch(*i)) {
  554. return true;
  555. }
  556. } else {
  557. if(!util::isNumericHost(req->getHost())) {
  558. // TODO We don't resolve hostname here. More complete
  559. // implementation is that we should first resolve
  560. // hostname(which may result in several IP addresses) and
  561. // evaluates against all of them
  562. continue;
  563. }
  564. std::string ip = (*i).substr(0, slashpos);
  565. uint32_t bits;
  566. if(!util::parseUIntNoThrow(bits, (*i).substr(slashpos+1))) {
  567. continue;
  568. }
  569. if(util::inSameCidrBlock(ip, req->getHost(), bits)) {
  570. return true;
  571. }
  572. }
  573. }
  574. return false;
  575. }
  576. bool AbstractCommand::isProxyDefined() const
  577. {
  578. return isProxyRequest(req_->getProtocol(), getOption()) &&
  579. !inNoProxy(req_, getOption()->get(PREF_NO_PROXY));
  580. }
  581. SharedHandle<Request> AbstractCommand::createProxyRequest() const
  582. {
  583. SharedHandle<Request> proxyRequest;
  584. if(inNoProxy(req_, getOption()->get(PREF_NO_PROXY))) {
  585. return proxyRequest;
  586. }
  587. std::string proxy = getProxyUri(req_->getProtocol(), getOption());
  588. if(!proxy.empty()) {
  589. proxyRequest.reset(new Request());
  590. if(proxyRequest->setUri(proxy)) {
  591. if(getLogger()->debug()) {
  592. getLogger()->debug("CUID#%s - Using proxy",
  593. util::itos(getCuid()).c_str());
  594. }
  595. } else {
  596. if(getLogger()->debug()) {
  597. getLogger()->debug("CUID#%s - Failed to parse proxy string",
  598. util::itos(getCuid()).c_str());
  599. }
  600. proxyRequest.reset();
  601. }
  602. }
  603. return proxyRequest;
  604. }
  605. #ifdef ENABLE_ASYNC_DNS
  606. bool AbstractCommand::isAsyncNameResolverInitialized() const
  607. {
  608. return !asyncNameResolver_.isNull();
  609. }
  610. void AbstractCommand::initAsyncNameResolver(const std::string& hostname)
  611. {
  612. int family;
  613. if(getOption()->getAsBool(PREF_ENABLE_ASYNC_DNS6)) {
  614. family = AF_UNSPEC;
  615. } else {
  616. family = AF_INET;
  617. }
  618. asyncNameResolver_.reset(new AsyncNameResolver(family));
  619. if(getLogger()->info()) {
  620. getLogger()->info(MSG_RESOLVING_HOSTNAME,
  621. util::itos(getCuid()).c_str(), hostname.c_str());
  622. }
  623. asyncNameResolver_->resolve(hostname);
  624. setNameResolverCheck(asyncNameResolver_);
  625. }
  626. bool AbstractCommand::asyncResolveHostname()
  627. {
  628. switch(asyncNameResolver_->getStatus()) {
  629. case AsyncNameResolver::STATUS_SUCCESS:
  630. disableNameResolverCheck(asyncNameResolver_);
  631. return true;
  632. case AsyncNameResolver::STATUS_ERROR:
  633. disableNameResolverCheck(asyncNameResolver_);
  634. if(!isProxyRequest(req_->getProtocol(), getOption())) {
  635. e_->getRequestGroupMan()->getOrCreateServerStat
  636. (req_->getHost(), req_->getProtocol())->setError();
  637. }
  638. throw DL_ABORT_EX
  639. (StringFormat(MSG_NAME_RESOLUTION_FAILED,
  640. util::itos(getCuid()).c_str(),
  641. asyncNameResolver_->getHostname().c_str(),
  642. asyncNameResolver_->getError().c_str()).str());
  643. default:
  644. return false;
  645. }
  646. }
  647. const std::vector<std::string>& AbstractCommand::getResolvedAddresses()
  648. {
  649. return asyncNameResolver_->getResolvedAddresses();
  650. }
  651. void AbstractCommand::setNameResolverCheck
  652. (const SharedHandle<AsyncNameResolver>& resolver) {
  653. if(!resolver.isNull()) {
  654. nameResolverCheck_ = true;
  655. e_->addNameResolverCheck(resolver, this);
  656. }
  657. }
  658. void AbstractCommand::disableNameResolverCheck
  659. (const SharedHandle<AsyncNameResolver>& resolver) {
  660. if(!resolver.isNull()) {
  661. nameResolverCheck_ = false;
  662. e_->deleteNameResolverCheck(resolver, this);
  663. }
  664. }
  665. bool AbstractCommand::nameResolveFinished() const {
  666. return
  667. asyncNameResolver_->getStatus() == AsyncNameResolver::STATUS_SUCCESS ||
  668. asyncNameResolver_->getStatus() == AsyncNameResolver::STATUS_ERROR;
  669. }
  670. #endif // ENABLE_ASYNC_DNS
  671. std::string AbstractCommand::resolveHostname
  672. (std::vector<std::string>& addrs, const std::string& hostname, uint16_t port)
  673. {
  674. if(util::isNumericHost(hostname)) {
  675. addrs.push_back(hostname);
  676. return hostname;
  677. }
  678. e_->findAllCachedIPAddresses(std::back_inserter(addrs), hostname, port);
  679. std::string ipaddr;
  680. if(addrs.empty()) {
  681. #ifdef ENABLE_ASYNC_DNS
  682. if(getOption()->getAsBool(PREF_ASYNC_DNS)) {
  683. if(!isAsyncNameResolverInitialized()) {
  684. initAsyncNameResolver(hostname);
  685. }
  686. if(asyncResolveHostname()) {
  687. addrs = getResolvedAddresses();
  688. } else {
  689. return A2STR::NIL;
  690. }
  691. } else
  692. #endif // ENABLE_ASYNC_DNS
  693. {
  694. NameResolver res;
  695. res.setSocktype(SOCK_STREAM);
  696. if(e_->getOption()->getAsBool(PREF_DISABLE_IPV6)) {
  697. res.setFamily(AF_INET);
  698. }
  699. res.resolve(addrs, hostname);
  700. }
  701. if(getLogger()->info()) {
  702. getLogger()->info(MSG_NAME_RESOLUTION_COMPLETE,
  703. util::itos(getCuid()).c_str(),
  704. hostname.c_str(),
  705. strjoin(addrs.begin(), addrs.end(), ", ").c_str());
  706. }
  707. for(std::vector<std::string>::const_iterator i = addrs.begin(),
  708. eoi = addrs.end(); i != eoi; ++i) {
  709. e_->cacheIPAddress(hostname, *i, port);
  710. }
  711. ipaddr = e_->findCachedIPAddress(hostname, port);
  712. } else {
  713. ipaddr = addrs.front();
  714. if(getLogger()->info()) {
  715. getLogger()->info(MSG_DNS_CACHE_HIT,
  716. util::itos(getCuid()).c_str(), hostname.c_str(),
  717. strjoin(addrs.begin(), addrs.end(), ", ").c_str());
  718. }
  719. }
  720. return ipaddr;
  721. }
  722. // nextCommand is going to be managed by CheckIntegrityEntry which is
  723. // created in side this function. Don't release nextCommand after this
  724. // function call.
  725. void AbstractCommand::prepareForNextAction(Command* nextCommand)
  726. {
  727. #ifdef ENABLE_MESSAGE_DIGEST
  728. if(requestGroup_->downloadFinished() &&
  729. getDownloadContext()->isChecksumVerificationNeeded()) {
  730. if(getLogger()->info()) {
  731. getLogger()->info(MSG_HASH_CHECK_NOT_DONE);
  732. }
  733. SharedHandle<CheckIntegrityEntry> entry
  734. (new ChecksumCheckIntegrityEntry(requestGroup_));
  735. if(entry->isValidationReady()) {
  736. delete nextCommand;
  737. entry->initValidator();
  738. entry->cutTrailingGarbage();
  739. e_->getCheckIntegrityMan()->pushEntry(entry);
  740. return;
  741. }
  742. }
  743. #endif // ENABLE_MESSAGE_DIGEST
  744. SharedHandle<CheckIntegrityEntry> entry
  745. (new StreamCheckIntegrityEntry(requestGroup_, nextCommand));
  746. std::vector<Command*>* commands = new std::vector<Command*>();
  747. auto_delete_container<std::vector<Command*> > commandsDel(commands);
  748. requestGroup_->processCheckIntegrityEntry(*commands, entry, e_);
  749. e_->addCommand(*commands);
  750. commands->clear();
  751. e_->setNoWait(true);
  752. }
  753. bool AbstractCommand::checkIfConnectionEstablished
  754. (const SharedHandle<SocketCore>& socket,
  755. const std::string& connectedHostname,
  756. const std::string& connectedAddr,
  757. uint16_t connectedPort)
  758. {
  759. if(socket->isReadable(0)) {
  760. std::string error = socket->getSocketError();
  761. if(!error.empty()) {
  762. // See also InitiateConnectionCommand::executeInternal()
  763. e_->markBadIPAddress(connectedHostname, connectedAddr, connectedPort);
  764. if(!e_->findCachedIPAddress(connectedHostname, connectedPort).empty()) {
  765. if(getLogger()->info()) {
  766. getLogger()->info(MSG_CONNECT_FAILED_AND_RETRY,
  767. util::itos(getCuid()).c_str(),
  768. connectedAddr.c_str(), connectedPort);
  769. }
  770. Command* command =
  771. InitiateConnectionCommandFactory::createInitiateConnectionCommand
  772. (getCuid(), req_, fileEntry_, requestGroup_, e_);
  773. e_->setNoWait(true);
  774. e_->addCommand(command);
  775. return false;
  776. }
  777. e_->removeCachedIPAddress(connectedHostname, connectedPort);
  778. // Don't set error if proxy server is used and its method is GET.
  779. if(resolveProxyMethod(req_->getProtocol()) != V_GET ||
  780. !isProxyRequest(req_->getProtocol(), getOption())) {
  781. e_->getRequestGroupMan()->getOrCreateServerStat
  782. (req_->getHost(), req_->getProtocol())->setError();
  783. }
  784. throw DL_RETRY_EX
  785. (StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()).str());
  786. }
  787. }
  788. return true;
  789. }
  790. const std::string& AbstractCommand::resolveProxyMethod
  791. (const std::string& protocol) const
  792. {
  793. if(getOption()->get(PREF_PROXY_METHOD) == V_TUNNEL ||
  794. Request::PROTO_HTTPS == protocol) {
  795. return V_TUNNEL;
  796. } else {
  797. return V_GET;
  798. }
  799. }
  800. const SharedHandle<Option>& AbstractCommand::getOption() const
  801. {
  802. return requestGroup_->getOption();
  803. }
  804. void AbstractCommand::createSocket()
  805. {
  806. socket_.reset(new SocketCore());
  807. }
  808. size_t AbstractCommand::calculateMinSplitSize() const
  809. {
  810. if(!req_.isNull() && req_->isPipeliningEnabled()) {
  811. return getDownloadContext()->getPieceLength();
  812. } else {
  813. return getOption()->getAsInt(PREF_MIN_SPLIT_SIZE);
  814. }
  815. }
  816. } // namespace aria2