AbstractCommand.cc 28 KB

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