AbstractCommand.cc 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  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. // When DNS query was timeout, req_->getConnectedAddr() is
  238. // empty.
  239. if(!req_->getConnectedAddr().empty()) {
  240. // Purging IP address cache to renew IP address.
  241. A2_LOG_DEBUG(fmt("CUID#%lld - Marking IP address %s as bad",
  242. getCuid(),
  243. req_->getConnectedAddr().c_str()));
  244. e_->markBadIPAddress(req_->getConnectedHostname(),
  245. req_->getConnectedAddr(),
  246. req_->getConnectedPort());
  247. }
  248. if(e_->findCachedIPAddress
  249. (req_->getConnectedHostname(), req_->getConnectedPort()).empty()) {
  250. A2_LOG_DEBUG(fmt("CUID#%lld - All IP addresses were marked bad."
  251. " Removing Entry.",
  252. getCuid()));
  253. e_->removeCachedIPAddress
  254. (req_->getConnectedHostname(), req_->getConnectedPort());
  255. }
  256. throw DL_RETRY_EX2(EX_TIME_OUT, error_code::TIME_OUT);
  257. }
  258. e_->addCommand(this);
  259. return false;
  260. }
  261. } catch(DlAbortEx& err) {
  262. if(!req_) {
  263. A2_LOG_DEBUG_EX(EX_EXCEPTION_CAUGHT, err);
  264. } else {
  265. A2_LOG_ERROR_EX(fmt(MSG_DOWNLOAD_ABORTED,
  266. getCuid(),
  267. req_->getUri().c_str()),
  268. DL_ABORT_EX2(fmt("URI=%s", req_->getCurrentUri().c_str()),
  269. err));
  270. fileEntry_->addURIResult(req_->getUri(), err.getErrorCode());
  271. requestGroup_->setLastErrorCode(err.getErrorCode());
  272. if(err.getErrorCode() == error_code::CANNOT_RESUME) {
  273. requestGroup_->increaseResumeFailureCount();
  274. }
  275. }
  276. onAbort();
  277. tryReserved();
  278. return true;
  279. } catch(DlRetryEx& err) {
  280. assert(req_);
  281. A2_LOG_INFO_EX(fmt(MSG_RESTARTING_DOWNLOAD,
  282. getCuid(), req_->getUri().c_str()),
  283. DL_RETRY_EX2(fmt("URI=%s", req_->getCurrentUri().c_str()),
  284. err));
  285. req_->addTryCount();
  286. req_->resetRedirectCount();
  287. req_->resetUri();
  288. const unsigned int maxTries = getOption()->getAsInt(PREF_MAX_TRIES);
  289. bool isAbort = maxTries != 0 && req_->getTryCount() >= maxTries;
  290. if(isAbort) {
  291. A2_LOG_INFO(fmt(MSG_MAX_TRY,
  292. getCuid(),
  293. req_->getTryCount()));
  294. A2_LOG_ERROR_EX(fmt(MSG_DOWNLOAD_ABORTED,
  295. getCuid(),
  296. req_->getUri().c_str()),
  297. err);
  298. fileEntry_->addURIResult(req_->getUri(), err.getErrorCode());
  299. requestGroup_->setLastErrorCode(err.getErrorCode());
  300. if(err.getErrorCode() == error_code::CANNOT_RESUME) {
  301. requestGroup_->increaseResumeFailureCount();
  302. }
  303. onAbort();
  304. tryReserved();
  305. return true;
  306. } else {
  307. Timer wakeTime(global::wallclock);
  308. wakeTime.advance(getOption()->getAsInt(PREF_RETRY_WAIT));
  309. req_->setWakeTime(wakeTime);
  310. return prepareForRetry(0);
  311. }
  312. } catch(DownloadFailureException& err) {
  313. A2_LOG_ERROR_EX(EX_EXCEPTION_CAUGHT, err);
  314. requestGroup_->setLastErrorCode(err.getErrorCode());
  315. if(req_) {
  316. fileEntry_->addURIResult(req_->getUri(), err.getErrorCode());
  317. }
  318. requestGroup_->setHaltRequested(true);
  319. return true;
  320. }
  321. }
  322. void AbstractCommand::tryReserved() {
  323. if(getDownloadContext()->getFileEntries().size() == 1) {
  324. const SharedHandle<FileEntry>& entry =
  325. getDownloadContext()->getFirstFileEntry();
  326. // Don't create new command if currently file length is unknown
  327. // and there are no URI left. Because file length is unknown, we
  328. // can assume that there are no in-flight request object.
  329. if(entry->getLength() == 0 && entry->getRemainingUris().empty()) {
  330. A2_LOG_DEBUG(fmt("CUID#%lld - Not trying next request."
  331. " No reserved/pooled request is remaining and"
  332. " total length is still unknown.",
  333. getCuid()));
  334. return;
  335. }
  336. }
  337. A2_LOG_DEBUG(fmt("CUID#%lld - Trying reserved/pooled request.",
  338. getCuid()));
  339. std::vector<Command*> commands;
  340. requestGroup_->createNextCommand(commands, e_, 1);
  341. e_->setNoWait(true);
  342. e_->addCommand(commands);
  343. }
  344. bool AbstractCommand::prepareForRetry(time_t wait) {
  345. if(getPieceStorage()) {
  346. getSegmentMan()->cancelSegment(getCuid());
  347. }
  348. if(req_) {
  349. // Reset persistentConnection and maxPipelinedRequest to handle
  350. // the situation where remote server returns Connection: close
  351. // after several pipelined requests.
  352. req_->supportsPersistentConnection(true);
  353. req_->setMaxPipelinedRequest(1);
  354. fileEntry_->poolRequest(req_);
  355. A2_LOG_DEBUG(fmt("CUID#%lld - Pooling request URI=%s",
  356. getCuid(), req_->getUri().c_str()));
  357. if(getSegmentMan()) {
  358. getSegmentMan()->recognizeSegmentFor(fileEntry_);
  359. }
  360. }
  361. Command* command = new CreateRequestCommand(getCuid(), requestGroup_, e_);
  362. if(wait == 0) {
  363. e_->setNoWait(true);
  364. e_->addCommand(command);
  365. } else {
  366. SleepCommand* scom = new SleepCommand(getCuid(), e_, requestGroup_,
  367. command, wait);
  368. e_->addCommand(scom);
  369. }
  370. return true;
  371. }
  372. void AbstractCommand::onAbort() {
  373. if(req_) {
  374. fileEntry_->removeIdenticalURI(req_->getUri());
  375. fileEntry_->removeRequest(req_);
  376. }
  377. A2_LOG_DEBUG(fmt("CUID#%lld - Aborting download",
  378. getCuid()));
  379. if(getPieceStorage()) {
  380. getSegmentMan()->cancelSegment(getCuid());
  381. // Don't do following process if BitTorrent is involved or files
  382. // in DownloadContext is more than 1. The latter condition is
  383. // limitation of current implementation.
  384. if(!getOption()->getAsBool(PREF_ALWAYS_RESUME) &&
  385. fileEntry_ &&
  386. getSegmentMan()->calculateSessionDownloadLength() == 0 &&
  387. !requestGroup_->p2pInvolved() &&
  388. getDownloadContext()->getFileEntries().size() == 1) {
  389. const int maxTries = getOption()->getAsInt(PREF_MAX_RESUME_FAILURE_TRIES);
  390. if((maxTries > 0 && requestGroup_->getResumeFailureCount() >= maxTries)||
  391. fileEntry_->emptyRequestUri()) {
  392. // Local file exists, but given servers(or at least contacted
  393. // ones) doesn't support resume. Let's restart download from
  394. // scratch.
  395. A2_LOG_NOTICE(fmt("CUID#%lld - Failed to resume download."
  396. " Download from scratch.",
  397. getCuid()));
  398. A2_LOG_DEBUG(fmt("CUID#%lld - Gathering URIs that has CANNOT_RESUME"
  399. " error",
  400. getCuid()));
  401. // Set PREF_ALWAYS_RESUME to A2_V_TRUE to avoid repeating this
  402. // process.
  403. getOption()->put(PREF_ALWAYS_RESUME, A2_V_TRUE);
  404. std::deque<URIResult> res;
  405. fileEntry_->extractURIResult(res, error_code::CANNOT_RESUME);
  406. if(!res.empty()) {
  407. getSegmentMan()->cancelAllSegments();
  408. getSegmentMan()->eraseSegmentWrittenLengthMemo();
  409. getPieceStorage()->markPiecesDone(0);
  410. std::vector<std::string> uris;
  411. uris.reserve(res.size());
  412. std::transform(res.begin(), res.end(), std::back_inserter(uris),
  413. std::mem_fun_ref(&URIResult::getURI));
  414. A2_LOG_DEBUG(fmt("CUID#%lld - %lu URIs found.",
  415. getCuid(),
  416. static_cast<unsigned long int>(uris.size())));
  417. fileEntry_->addUris(uris.begin(), uris.end());
  418. getSegmentMan()->recognizeSegmentFor(fileEntry_);
  419. }
  420. }
  421. }
  422. }
  423. }
  424. void AbstractCommand::disableReadCheckSocket() {
  425. if(checkSocketIsReadable_) {
  426. e_->deleteSocketForReadCheck(readCheckTarget_, this);
  427. checkSocketIsReadable_ = false;
  428. readCheckTarget_.reset();
  429. }
  430. }
  431. void AbstractCommand::setReadCheckSocket(const SocketHandle& socket) {
  432. if(!socket->isOpen()) {
  433. disableReadCheckSocket();
  434. } else {
  435. if(checkSocketIsReadable_) {
  436. if(*readCheckTarget_ != *socket) {
  437. e_->deleteSocketForReadCheck(readCheckTarget_, this);
  438. e_->addSocketForReadCheck(socket, this);
  439. readCheckTarget_ = socket;
  440. }
  441. } else {
  442. e_->addSocketForReadCheck(socket, this);
  443. checkSocketIsReadable_ = true;
  444. readCheckTarget_ = socket;
  445. }
  446. }
  447. }
  448. void AbstractCommand::setReadCheckSocketIf
  449. (const SharedHandle<SocketCore>& socket, bool pred)
  450. {
  451. if(pred) {
  452. setReadCheckSocket(socket);
  453. } else {
  454. disableReadCheckSocket();
  455. }
  456. }
  457. void AbstractCommand::disableWriteCheckSocket() {
  458. if(checkSocketIsWritable_) {
  459. e_->deleteSocketForWriteCheck(writeCheckTarget_, this);
  460. checkSocketIsWritable_ = false;
  461. writeCheckTarget_.reset();
  462. }
  463. }
  464. void AbstractCommand::setWriteCheckSocket(const SocketHandle& socket) {
  465. if(!socket->isOpen()) {
  466. disableWriteCheckSocket();
  467. } else {
  468. if(checkSocketIsWritable_) {
  469. if(*writeCheckTarget_ != *socket) {
  470. e_->deleteSocketForWriteCheck(writeCheckTarget_, this);
  471. e_->addSocketForWriteCheck(socket, this);
  472. writeCheckTarget_ = socket;
  473. }
  474. } else {
  475. e_->addSocketForWriteCheck(socket, this);
  476. checkSocketIsWritable_ = true;
  477. writeCheckTarget_ = socket;
  478. }
  479. }
  480. }
  481. void AbstractCommand::setWriteCheckSocketIf
  482. (const SharedHandle<SocketCore>& socket, bool pred)
  483. {
  484. if(pred) {
  485. setWriteCheckSocket(socket);
  486. } else {
  487. disableWriteCheckSocket();
  488. }
  489. }
  490. namespace {
  491. // Returns proxy option value for the given protocol.
  492. const std::string& getProxyOptionFor
  493. (const std::string& proxyPref, const SharedHandle<Option>& option)
  494. {
  495. if(option->defined(proxyPref)) {
  496. return option->get(proxyPref);
  497. } else {
  498. return option->get(PREF_ALL_PROXY);
  499. }
  500. }
  501. } // namespace
  502. namespace {
  503. // Returns proxy URI for given protocol. If no proxy URI is defined,
  504. // then returns an empty string.
  505. const std::string& getProxyUri
  506. (const std::string& protocol, const SharedHandle<Option>& option)
  507. {
  508. if(protocol == Request::PROTO_HTTP) {
  509. return getProxyOptionFor(PREF_HTTP_PROXY, option);
  510. } else if(protocol == Request::PROTO_HTTPS) {
  511. return getProxyOptionFor(PREF_HTTPS_PROXY, option);
  512. } else if(protocol == Request::PROTO_FTP) {
  513. return getProxyOptionFor(PREF_FTP_PROXY, option);
  514. } else {
  515. return A2STR::NIL;
  516. }
  517. }
  518. } // namespace
  519. namespace {
  520. // Returns true if proxy is defined for the given protocol. Otherwise
  521. // returns false.
  522. bool isProxyRequest
  523. (const std::string& protocol, const SharedHandle<Option>& option)
  524. {
  525. const std::string& proxyUri = getProxyUri(protocol, option);
  526. uri::UriStruct us;
  527. return !proxyUri.empty() && uri::parse(us, proxyUri);
  528. }
  529. } // namespace
  530. namespace {
  531. class DomainMatch {
  532. private:
  533. std::string hostname_;
  534. public:
  535. DomainMatch(const std::string& hostname):hostname_(hostname) {}
  536. bool operator()(const std::string& domain) const
  537. {
  538. if(util::startsWith(domain, A2STR::DOT_C)) {
  539. return util::endsWith(hostname_, domain);
  540. } else {
  541. return util::endsWith(hostname_, A2STR::DOT_C+domain);
  542. }
  543. }
  544. };
  545. } // namespace
  546. namespace {
  547. bool inNoProxy(const SharedHandle<Request>& req,
  548. const std::string& noProxy)
  549. {
  550. std::vector<std::string> entries;
  551. util::split(noProxy, std::back_inserter(entries), ",", true);
  552. if(entries.empty()) {
  553. return false;
  554. }
  555. DomainMatch domainMatch(A2STR::DOT_C+req->getHost());
  556. for(std::vector<std::string>::const_iterator i = entries.begin(),
  557. eoi = entries.end(); i != eoi; ++i) {
  558. std::string::size_type slashpos = (*i).find('/');
  559. if(slashpos == std::string::npos) {
  560. if(util::isNumericHost(*i)) {
  561. if(req->getHost() == *i) {
  562. return true;
  563. }
  564. } else if(domainMatch(*i)) {
  565. return true;
  566. }
  567. } else {
  568. if(!util::isNumericHost(req->getHost())) {
  569. // TODO We don't resolve hostname here. More complete
  570. // implementation is that we should first resolve
  571. // hostname(which may result in several IP addresses) and
  572. // evaluates against all of them
  573. continue;
  574. }
  575. std::string ip = (*i).substr(0, slashpos);
  576. uint32_t bits;
  577. if(!util::parseUIntNoThrow(bits, (*i).substr(slashpos+1))) {
  578. continue;
  579. }
  580. if(util::inSameCidrBlock(ip, req->getHost(), bits)) {
  581. return true;
  582. }
  583. }
  584. }
  585. return false;
  586. }
  587. } // namespace
  588. bool AbstractCommand::isProxyDefined() const
  589. {
  590. return isProxyRequest(req_->getProtocol(), getOption()) &&
  591. !inNoProxy(req_, getOption()->get(PREF_NO_PROXY));
  592. }
  593. SharedHandle<Request> AbstractCommand::createProxyRequest() const
  594. {
  595. SharedHandle<Request> proxyRequest;
  596. if(inNoProxy(req_, getOption()->get(PREF_NO_PROXY))) {
  597. return proxyRequest;
  598. }
  599. std::string proxy = getProxyUri(req_->getProtocol(), getOption());
  600. if(!proxy.empty()) {
  601. proxyRequest.reset(new Request());
  602. if(proxyRequest->setUri(proxy)) {
  603. A2_LOG_DEBUG(fmt("CUID#%lld - Using proxy", getCuid()));
  604. } else {
  605. A2_LOG_DEBUG(fmt("CUID#%lld - Failed to parse proxy string",
  606. getCuid()));
  607. proxyRequest.reset();
  608. }
  609. }
  610. return proxyRequest;
  611. }
  612. #ifdef ENABLE_ASYNC_DNS
  613. bool AbstractCommand::isAsyncNameResolverInitialized() const
  614. {
  615. return asyncNameResolver_;
  616. }
  617. void AbstractCommand::initAsyncNameResolver(const std::string& hostname)
  618. {
  619. int family;
  620. if(getOption()->getAsBool(PREF_ENABLE_ASYNC_DNS6)) {
  621. family = AF_UNSPEC;
  622. } else {
  623. family = AF_INET;
  624. }
  625. asyncNameResolver_.reset
  626. (new AsyncNameResolver(family, e_->getAsyncDNSServers()));
  627. A2_LOG_INFO(fmt(MSG_RESOLVING_HOSTNAME,
  628. getCuid(),
  629. hostname.c_str()));
  630. asyncNameResolver_->resolve(hostname);
  631. setNameResolverCheck(asyncNameResolver_);
  632. }
  633. bool AbstractCommand::asyncResolveHostname()
  634. {
  635. switch(asyncNameResolver_->getStatus()) {
  636. case AsyncNameResolver::STATUS_SUCCESS:
  637. disableNameResolverCheck(asyncNameResolver_);
  638. return true;
  639. case AsyncNameResolver::STATUS_ERROR:
  640. disableNameResolverCheck(asyncNameResolver_);
  641. if(!isProxyRequest(req_->getProtocol(), getOption())) {
  642. e_->getRequestGroupMan()->getOrCreateServerStat
  643. (req_->getHost(), req_->getProtocol())->setError();
  644. }
  645. throw DL_ABORT_EX2
  646. (fmt(MSG_NAME_RESOLUTION_FAILED,
  647. getCuid(),
  648. asyncNameResolver_->getHostname().c_str(),
  649. asyncNameResolver_->getError().c_str()),
  650. error_code::NAME_RESOLVE_ERROR);
  651. default:
  652. return false;
  653. }
  654. }
  655. const std::vector<std::string>& AbstractCommand::getResolvedAddresses()
  656. {
  657. return asyncNameResolver_->getResolvedAddresses();
  658. }
  659. void AbstractCommand::setNameResolverCheck
  660. (const SharedHandle<AsyncNameResolver>& resolver) {
  661. if(resolver) {
  662. nameResolverCheck_ = true;
  663. e_->addNameResolverCheck(resolver, this);
  664. }
  665. }
  666. void AbstractCommand::disableNameResolverCheck
  667. (const SharedHandle<AsyncNameResolver>& resolver) {
  668. if(resolver) {
  669. nameResolverCheck_ = false;
  670. e_->deleteNameResolverCheck(resolver, this);
  671. }
  672. }
  673. bool AbstractCommand::nameResolveFinished() const {
  674. return
  675. asyncNameResolver_->getStatus() == AsyncNameResolver::STATUS_SUCCESS ||
  676. asyncNameResolver_->getStatus() == AsyncNameResolver::STATUS_ERROR;
  677. }
  678. #endif // ENABLE_ASYNC_DNS
  679. std::string AbstractCommand::resolveHostname
  680. (std::vector<std::string>& addrs, const std::string& hostname, uint16_t port)
  681. {
  682. if(util::isNumericHost(hostname)) {
  683. addrs.push_back(hostname);
  684. return hostname;
  685. }
  686. e_->findAllCachedIPAddresses(std::back_inserter(addrs), hostname, port);
  687. std::string ipaddr;
  688. if(addrs.empty()) {
  689. #ifdef ENABLE_ASYNC_DNS
  690. if(getOption()->getAsBool(PREF_ASYNC_DNS)) {
  691. if(!isAsyncNameResolverInitialized()) {
  692. initAsyncNameResolver(hostname);
  693. }
  694. if(asyncResolveHostname()) {
  695. addrs = getResolvedAddresses();
  696. } else {
  697. return A2STR::NIL;
  698. }
  699. } else
  700. #endif // ENABLE_ASYNC_DNS
  701. {
  702. NameResolver res;
  703. res.setSocktype(SOCK_STREAM);
  704. if(e_->getOption()->getAsBool(PREF_DISABLE_IPV6)) {
  705. res.setFamily(AF_INET);
  706. }
  707. res.resolve(addrs, hostname);
  708. }
  709. A2_LOG_INFO(fmt(MSG_NAME_RESOLUTION_COMPLETE,
  710. getCuid(),
  711. hostname.c_str(),
  712. strjoin(addrs.begin(), addrs.end(), ", ").c_str()));
  713. for(std::vector<std::string>::const_iterator i = addrs.begin(),
  714. eoi = addrs.end(); i != eoi; ++i) {
  715. e_->cacheIPAddress(hostname, *i, port);
  716. }
  717. ipaddr = e_->findCachedIPAddress(hostname, port);
  718. } else {
  719. ipaddr = addrs.front();
  720. A2_LOG_INFO(fmt(MSG_DNS_CACHE_HIT,
  721. getCuid(),
  722. hostname.c_str(),
  723. strjoin(addrs.begin(), addrs.end(), ", ").c_str()));
  724. }
  725. return ipaddr;
  726. }
  727. void AbstractCommand::prepareForNextAction
  728. (const SharedHandle<CheckIntegrityEntry>& checkEntry)
  729. {
  730. std::vector<Command*>* commands = new std::vector<Command*>();
  731. auto_delete_container<std::vector<Command*> > commandsDel(commands);
  732. requestGroup_->processCheckIntegrityEntry(*commands, checkEntry, e_);
  733. e_->addCommand(*commands);
  734. commands->clear();
  735. e_->setNoWait(true);
  736. }
  737. bool AbstractCommand::checkIfConnectionEstablished
  738. (const SharedHandle<SocketCore>& socket,
  739. const std::string& connectedHostname,
  740. const std::string& connectedAddr,
  741. uint16_t connectedPort)
  742. {
  743. if(socket->isReadable(0)) {
  744. std::string error = socket->getSocketError();
  745. if(!error.empty()) {
  746. // See also InitiateConnectionCommand::executeInternal()
  747. e_->markBadIPAddress(connectedHostname, connectedAddr, connectedPort);
  748. if(!e_->findCachedIPAddress(connectedHostname, connectedPort).empty()) {
  749. A2_LOG_INFO(fmt(MSG_CONNECT_FAILED_AND_RETRY,
  750. getCuid(),
  751. connectedAddr.c_str(), connectedPort));
  752. Command* command =
  753. InitiateConnectionCommandFactory::createInitiateConnectionCommand
  754. (getCuid(), req_, fileEntry_, requestGroup_, e_);
  755. e_->setNoWait(true);
  756. e_->addCommand(command);
  757. return false;
  758. }
  759. e_->removeCachedIPAddress(connectedHostname, connectedPort);
  760. // Don't set error if proxy server is used and its method is GET.
  761. if(resolveProxyMethod(req_->getProtocol()) != V_GET ||
  762. !isProxyRequest(req_->getProtocol(), getOption())) {
  763. e_->getRequestGroupMan()->getOrCreateServerStat
  764. (req_->getHost(), req_->getProtocol())->setError();
  765. }
  766. throw DL_RETRY_EX
  767. (fmt(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()));
  768. }
  769. }
  770. return true;
  771. }
  772. const std::string& AbstractCommand::resolveProxyMethod
  773. (const std::string& protocol) const
  774. {
  775. if(getOption()->get(PREF_PROXY_METHOD) == V_TUNNEL ||
  776. Request::PROTO_HTTPS == protocol) {
  777. return V_TUNNEL;
  778. } else {
  779. return V_GET;
  780. }
  781. }
  782. const SharedHandle<Option>& AbstractCommand::getOption() const
  783. {
  784. return requestGroup_->getOption();
  785. }
  786. void AbstractCommand::createSocket()
  787. {
  788. socket_.reset(new SocketCore());
  789. }
  790. size_t AbstractCommand::calculateMinSplitSize() const
  791. {
  792. if(req_ && req_->isPipeliningEnabled()) {
  793. return getDownloadContext()->getPieceLength();
  794. } else {
  795. return getOption()->getAsInt(PREF_MIN_SPLIT_SIZE);
  796. }
  797. }
  798. void AbstractCommand::setRequest(const SharedHandle<Request>& request)
  799. {
  800. req_ = request;
  801. }
  802. void AbstractCommand::setFileEntry(const SharedHandle<FileEntry>& fileEntry)
  803. {
  804. fileEntry_ = fileEntry;
  805. }
  806. void AbstractCommand::setSocket(const SharedHandle<SocketCore>& s)
  807. {
  808. socket_ = s;
  809. }
  810. const SharedHandle<DownloadContext>& AbstractCommand::getDownloadContext() const
  811. {
  812. return requestGroup_->getDownloadContext();
  813. }
  814. const SharedHandle<SegmentMan>& AbstractCommand::getSegmentMan() const
  815. {
  816. return requestGroup_->getSegmentMan();
  817. }
  818. const SharedHandle<PieceStorage>& AbstractCommand::getPieceStorage() const
  819. {
  820. return requestGroup_->getPieceStorage();
  821. }
  822. void AbstractCommand::checkSocketRecvBuffer()
  823. {
  824. if(!socketRecvBuffer_->bufferEmpty()) {
  825. setStatus(Command::STATUS_ONESHOT_REALTIME);
  826. e_->setNoWait(true);
  827. }
  828. }
  829. } // namespace aria2