AbstractCommand.cc 27 KB

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