FtpNegotiationCommand.cc 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  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 "FtpNegotiationCommand.h"
  36. #include <stdint.h>
  37. #include <cassert>
  38. #include <utility>
  39. #include <map>
  40. #include "Request.h"
  41. #include "DownloadEngine.h"
  42. #include "FtpConnection.h"
  43. #include "RequestGroup.h"
  44. #include "PieceStorage.h"
  45. #include "FtpDownloadCommand.h"
  46. #include "FileEntry.h"
  47. #include "DlAbortEx.h"
  48. #include "message.h"
  49. #include "prefs.h"
  50. #include "util.h"
  51. #include "Option.h"
  52. #include "Logger.h"
  53. #include "LogFactory.h"
  54. #include "Segment.h"
  55. #include "DownloadContext.h"
  56. #include "DefaultBtProgressInfoFile.h"
  57. #include "RequestGroupMan.h"
  58. #include "DownloadFailureException.h"
  59. #include "SocketCore.h"
  60. #include "fmt.h"
  61. #include "DiskAdaptor.h"
  62. #include "SegmentMan.h"
  63. #include "AuthConfigFactory.h"
  64. #include "AuthConfig.h"
  65. #include "a2functional.h"
  66. #include "URISelector.h"
  67. #include "HttpConnection.h"
  68. #include "HttpHeader.h"
  69. #include "HttpRequest.h"
  70. #include "HttpResponse.h"
  71. #include "DlRetryEx.h"
  72. #include "CheckIntegrityEntry.h"
  73. #include "error_code.h"
  74. #include "SocketRecvBuffer.h"
  75. #include "NullProgressInfoFile.h"
  76. #include "ChecksumCheckIntegrityEntry.h"
  77. namespace aria2 {
  78. FtpNegotiationCommand::FtpNegotiationCommand(
  79. cuid_t cuid, const std::shared_ptr<Request>& req,
  80. const std::shared_ptr<FileEntry>& fileEntry, RequestGroup* requestGroup,
  81. DownloadEngine* e, const std::shared_ptr<SocketCore>& socket, Seq seq,
  82. const std::string& baseWorkingDir)
  83. : AbstractCommand(cuid, req, fileEntry, requestGroup, e, socket),
  84. sequence_(seq),
  85. ftp_(std::make_shared<FtpConnection>(
  86. cuid, socket, req, e->getAuthConfigFactory()->createAuthConfig(
  87. req, requestGroup->getOption().get()),
  88. getOption().get())),
  89. pasvPort_(0)
  90. {
  91. ftp_->setBaseWorkingDir(baseWorkingDir);
  92. if (seq == SEQ_RECV_GREETING) {
  93. setTimeout(
  94. std::chrono::seconds(getOption()->getAsInt(PREF_CONNECT_TIMEOUT)));
  95. }
  96. setWriteCheckSocket(getSocket());
  97. }
  98. FtpNegotiationCommand::~FtpNegotiationCommand() = default;
  99. bool FtpNegotiationCommand::executeInternal()
  100. {
  101. auto segment = getSegments().empty() ? std::shared_ptr<Segment>()
  102. : getSegments().front();
  103. while (processSequence(segment))
  104. ;
  105. if (sequence_ == SEQ_RETRY) {
  106. return prepareForRetry(0);
  107. }
  108. else if (sequence_ == SEQ_NEGOTIATION_COMPLETED) {
  109. auto command = make_unique<FtpDownloadCommand>(
  110. getCuid(), getRequest(), getFileEntry(), getRequestGroup(), ftp_,
  111. getDownloadEngine(), dataSocket_, getSocket());
  112. command->setStartupIdleTime(
  113. std::chrono::seconds(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME)));
  114. command->setLowestDownloadSpeedLimit(
  115. getOption()->getAsInt(PREF_LOWEST_SPEED_LIMIT));
  116. if (getFileEntry()->isUniqueProtocol()) {
  117. getFileEntry()->removeURIWhoseHostnameIs(getRequest()->getHost());
  118. }
  119. getRequestGroup()->getURISelector()->tuneDownloadCommand(
  120. getFileEntry()->getRemainingUris(), command.get());
  121. getDownloadEngine()->addCommand(std::move(command));
  122. return true;
  123. }
  124. else if (sequence_ == SEQ_HEAD_OK ||
  125. sequence_ == SEQ_DOWNLOAD_ALREADY_COMPLETED) {
  126. return true;
  127. }
  128. else if (sequence_ == SEQ_FILE_PREPARATION) {
  129. if (getOption()->getAsBool(PREF_FTP_PASV)) {
  130. sequence_ = SEQ_PREPARE_PASV;
  131. }
  132. else {
  133. sequence_ = SEQ_PREPARE_PORT;
  134. }
  135. return false;
  136. }
  137. else if (sequence_ == SEQ_EXIT) {
  138. return true;
  139. }
  140. else {
  141. addCommandSelf();
  142. return false;
  143. }
  144. }
  145. bool FtpNegotiationCommand::recvGreeting()
  146. {
  147. setTimeout(getRequestGroup()->getTimeout());
  148. // socket->setBlockingMode();
  149. disableWriteCheckSocket();
  150. setReadCheckSocket(getSocket());
  151. int status = ftp_->receiveResponse();
  152. if (status == 0) {
  153. return false;
  154. }
  155. if (status != 220) {
  156. throw DL_ABORT_EX2(EX_CONNECTION_FAILED, error_code::FTP_PROTOCOL_ERROR);
  157. }
  158. sequence_ = SEQ_SEND_USER;
  159. return true;
  160. }
  161. bool FtpNegotiationCommand::sendUser()
  162. {
  163. if (ftp_->sendUser()) {
  164. disableWriteCheckSocket();
  165. sequence_ = SEQ_RECV_USER;
  166. }
  167. else {
  168. setWriteCheckSocket(getSocket());
  169. }
  170. return false;
  171. }
  172. bool FtpNegotiationCommand::recvUser()
  173. {
  174. int status = ftp_->receiveResponse();
  175. switch (status) {
  176. case 0:
  177. return false;
  178. case 230:
  179. sequence_ = SEQ_SEND_TYPE;
  180. break;
  181. case 331:
  182. sequence_ = SEQ_SEND_PASS;
  183. break;
  184. default:
  185. throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
  186. error_code::FTP_PROTOCOL_ERROR);
  187. }
  188. return true;
  189. }
  190. bool FtpNegotiationCommand::sendPass()
  191. {
  192. if (ftp_->sendPass()) {
  193. disableWriteCheckSocket();
  194. sequence_ = SEQ_RECV_PASS;
  195. }
  196. else {
  197. setWriteCheckSocket(getSocket());
  198. }
  199. return false;
  200. }
  201. bool FtpNegotiationCommand::recvPass()
  202. {
  203. int status = ftp_->receiveResponse();
  204. if (status == 0) {
  205. return false;
  206. }
  207. if (status != 230) {
  208. throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
  209. error_code::FTP_PROTOCOL_ERROR);
  210. }
  211. sequence_ = SEQ_SEND_TYPE;
  212. return true;
  213. }
  214. bool FtpNegotiationCommand::sendType()
  215. {
  216. if (ftp_->sendType()) {
  217. disableWriteCheckSocket();
  218. sequence_ = SEQ_RECV_TYPE;
  219. }
  220. else {
  221. setWriteCheckSocket(getSocket());
  222. }
  223. return false;
  224. }
  225. bool FtpNegotiationCommand::recvType()
  226. {
  227. int status = ftp_->receiveResponse();
  228. if (status == 0) {
  229. return false;
  230. }
  231. if (status != 200) {
  232. throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
  233. error_code::FTP_PROTOCOL_ERROR);
  234. }
  235. sequence_ = SEQ_SEND_PWD;
  236. return true;
  237. }
  238. bool FtpNegotiationCommand::sendPwd()
  239. {
  240. if (ftp_->sendPwd()) {
  241. disableWriteCheckSocket();
  242. sequence_ = SEQ_RECV_PWD;
  243. }
  244. else {
  245. setWriteCheckSocket(getSocket());
  246. }
  247. return false;
  248. }
  249. bool FtpNegotiationCommand::recvPwd()
  250. {
  251. std::string pwd;
  252. int status = ftp_->receivePwdResponse(pwd);
  253. if (status == 0) {
  254. return false;
  255. }
  256. if (status != 257) {
  257. throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
  258. error_code::FTP_PROTOCOL_ERROR);
  259. }
  260. ftp_->setBaseWorkingDir(pwd);
  261. A2_LOG_INFO(fmt("CUID#%" PRId64 " - base working directory is '%s'",
  262. getCuid(), pwd.c_str()));
  263. sequence_ = SEQ_SEND_CWD_PREP;
  264. return true;
  265. }
  266. bool FtpNegotiationCommand::sendCwdPrep()
  267. {
  268. // Calling setReadCheckSocket() is needed when the socket is reused,
  269. setReadCheckSocket(getSocket());
  270. cwdDirs_.push_front(ftp_->getBaseWorkingDir());
  271. util::split(getRequest()->getDir().begin(), getRequest()->getDir().end(),
  272. std::back_inserter(cwdDirs_), '/');
  273. sequence_ = SEQ_SEND_CWD;
  274. return true;
  275. }
  276. bool FtpNegotiationCommand::sendCwd()
  277. {
  278. if (ftp_->sendCwd(cwdDirs_.front())) {
  279. disableWriteCheckSocket();
  280. sequence_ = SEQ_RECV_CWD;
  281. }
  282. else {
  283. setWriteCheckSocket(getSocket());
  284. }
  285. return false;
  286. }
  287. bool FtpNegotiationCommand::recvCwd()
  288. {
  289. int status = ftp_->receiveResponse();
  290. if (status == 0) {
  291. return false;
  292. }
  293. if (status != 250) {
  294. poolConnection();
  295. getRequestGroup()->increaseAndValidateFileNotFoundCount();
  296. if (status == 550)
  297. throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
  298. error_code::RESOURCE_NOT_FOUND);
  299. else
  300. throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
  301. error_code::FTP_PROTOCOL_ERROR);
  302. }
  303. cwdDirs_.pop_front();
  304. if (cwdDirs_.empty()) {
  305. if (getOption()->getAsBool(PREF_REMOTE_TIME)) {
  306. sequence_ = SEQ_SEND_MDTM;
  307. }
  308. else {
  309. sequence_ = SEQ_SEND_SIZE;
  310. }
  311. }
  312. else {
  313. sequence_ = SEQ_SEND_CWD;
  314. }
  315. return true;
  316. }
  317. bool FtpNegotiationCommand::sendMdtm()
  318. {
  319. if (ftp_->sendMdtm()) {
  320. disableWriteCheckSocket();
  321. sequence_ = SEQ_RECV_MDTM;
  322. }
  323. else {
  324. setWriteCheckSocket(getSocket());
  325. }
  326. return false;
  327. }
  328. bool FtpNegotiationCommand::recvMdtm()
  329. {
  330. Time lastModifiedTime = Time::null();
  331. int status = ftp_->receiveMdtmResponse(lastModifiedTime);
  332. if (status == 0) {
  333. return false;
  334. }
  335. if (status == 213) {
  336. if (lastModifiedTime.good()) {
  337. getRequestGroup()->updateLastModifiedTime(lastModifiedTime);
  338. A2_LOG_DEBUG(fmt("MDTM result was parsed as: %s",
  339. lastModifiedTime.toHTTPDate().c_str()));
  340. }
  341. else {
  342. A2_LOG_DEBUG("MDTM response was returned, but it seems not to be"
  343. " a time value as in specified in RFC3659.");
  344. }
  345. }
  346. else {
  347. A2_LOG_INFO(fmt("CUID#%" PRId64 " - MDTM command failed.", getCuid()));
  348. }
  349. sequence_ = SEQ_SEND_SIZE;
  350. return true;
  351. }
  352. bool FtpNegotiationCommand::sendSize()
  353. {
  354. if (ftp_->sendSize()) {
  355. disableWriteCheckSocket();
  356. sequence_ = SEQ_RECV_SIZE;
  357. }
  358. else {
  359. setWriteCheckSocket(getSocket());
  360. }
  361. return false;
  362. }
  363. bool FtpNegotiationCommand::onFileSizeDetermined(int64_t totalLength)
  364. {
  365. getFileEntry()->setLength(totalLength);
  366. if (getFileEntry()->getPath().empty()) {
  367. auto suffixPath = util::createSafePath(
  368. util::percentDecode(std::begin(getRequest()->getFile()),
  369. std::end(getRequest()->getFile())));
  370. getFileEntry()->setPath(
  371. util::applyDir(getOption()->get(PREF_DIR), suffixPath));
  372. getFileEntry()->setSuffixPath(suffixPath);
  373. }
  374. getRequestGroup()->preDownloadProcessing();
  375. if (totalLength == 0) {
  376. if (getOption()->getAsBool(PREF_FTP_PASV)) {
  377. sequence_ = SEQ_PREPARE_PASV;
  378. }
  379. else {
  380. sequence_ = SEQ_PREPARE_PORT;
  381. }
  382. if (getOption()->getAsBool(PREF_DRY_RUN)) {
  383. getRequestGroup()->initPieceStorage();
  384. onDryRunFileFound();
  385. return false;
  386. }
  387. if (getDownloadContext()->knowsTotalLength() &&
  388. getRequestGroup()->downloadFinishedByFileLength()) {
  389. // TODO Known issue: if .aria2 file exists, it will not be
  390. // deleted on successful verification, because .aria2 file is
  391. // not loaded. See also
  392. // HttpResponseCommand::handleOtherEncoding()
  393. getRequestGroup()->initPieceStorage();
  394. if (getDownloadContext()->isChecksumVerificationNeeded()) {
  395. A2_LOG_DEBUG("Zero length file exists. Verify checksum.");
  396. auto entry =
  397. make_unique<ChecksumCheckIntegrityEntry>(getRequestGroup());
  398. entry->initValidator();
  399. getPieceStorage()->getDiskAdaptor()->openExistingFile();
  400. getDownloadEngine()->getCheckIntegrityMan()->pushEntry(
  401. std::move(entry));
  402. sequence_ = SEQ_EXIT;
  403. }
  404. else {
  405. getPieceStorage()->markAllPiecesDone();
  406. getDownloadContext()->setChecksumVerified(true);
  407. sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED;
  408. A2_LOG_NOTICE(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED,
  409. GroupId::toHex(getRequestGroup()->getGID()).c_str(),
  410. getRequestGroup()->getFirstFilePath().c_str()));
  411. }
  412. poolConnection();
  413. return false;
  414. }
  415. getRequestGroup()->adjustFilename(std::make_shared<NullProgressInfoFile>());
  416. getRequestGroup()->initPieceStorage();
  417. getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
  418. if (getDownloadContext()->knowsTotalLength()) {
  419. A2_LOG_DEBUG("File length becomes zero and it means download completed.");
  420. // TODO Known issue: if .aria2 file exists, it will not be
  421. // deleted on successful verification, because .aria2 file is
  422. // not loaded. See also
  423. // HttpResponseCommand::handleOtherEncoding()
  424. if (getDownloadContext()->isChecksumVerificationNeeded()) {
  425. A2_LOG_DEBUG("Verify checksum for zero-length file");
  426. auto entry =
  427. make_unique<ChecksumCheckIntegrityEntry>(getRequestGroup());
  428. entry->initValidator();
  429. getDownloadEngine()->getCheckIntegrityMan()->pushEntry(
  430. std::move(entry));
  431. sequence_ = SEQ_EXIT;
  432. }
  433. else {
  434. sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED;
  435. getPieceStorage()->markAllPiecesDone();
  436. }
  437. poolConnection();
  438. return false;
  439. }
  440. // We have to make sure that command that has Request object must
  441. // have segment after PieceStorage is initialized. See
  442. // AbstractCommand::execute()
  443. getSegmentMan()->getSegmentWithIndex(getCuid(), 0);
  444. return true;
  445. }
  446. else {
  447. auto progressInfoFile = std::make_shared<DefaultBtProgressInfoFile>(
  448. getDownloadContext(), nullptr, getOption().get());
  449. getRequestGroup()->adjustFilename(progressInfoFile);
  450. getRequestGroup()->initPieceStorage();
  451. if (getOption()->getAsBool(PREF_DRY_RUN)) {
  452. onDryRunFileFound();
  453. return false;
  454. }
  455. auto checkIntegrityEntry = getRequestGroup()->createCheckIntegrityEntry();
  456. if (!checkIntegrityEntry) {
  457. sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED;
  458. poolConnection();
  459. return false;
  460. }
  461. // We have to make sure that command that has Request object must
  462. // have segment after PieceStorage is initialized. See
  463. // AbstractCommand::execute()
  464. getSegmentMan()->getSegmentWithIndex(getCuid(), 0);
  465. checkIntegrityEntry->pushNextCommand(std::unique_ptr<Command>(this));
  466. prepareForNextAction(std::move(checkIntegrityEntry));
  467. disableReadCheckSocket();
  468. }
  469. return false;
  470. }
  471. bool FtpNegotiationCommand::recvSize()
  472. {
  473. int64_t size = 0;
  474. int status = ftp_->receiveSizeResponse(size);
  475. if (status == 0) {
  476. return false;
  477. }
  478. if (status == 213) {
  479. if (size > std::numeric_limits<a2_off_t>::max()) {
  480. throw DL_ABORT_EX2(fmt(EX_TOO_LARGE_FILE, size),
  481. error_code::FTP_PROTOCOL_ERROR);
  482. }
  483. if (!getPieceStorage()) {
  484. sequence_ = SEQ_FILE_PREPARATION;
  485. return onFileSizeDetermined(size);
  486. }
  487. else {
  488. getRequestGroup()->validateTotalLength(getFileEntry()->getLength(), size);
  489. }
  490. }
  491. else {
  492. A2_LOG_INFO(fmt("CUID#%" PRId64
  493. " - The remote FTP Server doesn't recognize SIZE"
  494. " command. Continue.",
  495. getCuid()));
  496. // Even if one of the other servers waiting in the queue supports SIZE
  497. // command, resuming and segmented downloading are disabled when the first
  498. // contacted FTP server doesn't support it.
  499. if (!getPieceStorage()) {
  500. getDownloadContext()->markTotalLengthIsUnknown();
  501. return onFileSizeDetermined(0);
  502. }
  503. // TODO Skipping RequestGroup::validateTotalLength(0) here will allow
  504. // wrong file to be downloaded if user-specified URL is wrong.
  505. }
  506. if (getOption()->getAsBool(PREF_FTP_PASV)) {
  507. sequence_ = SEQ_PREPARE_PASV;
  508. }
  509. else {
  510. sequence_ = SEQ_PREPARE_PORT;
  511. }
  512. return true;
  513. }
  514. void FtpNegotiationCommand::afterFileAllocation()
  515. {
  516. setReadCheckSocket(getSocket());
  517. }
  518. bool FtpNegotiationCommand::preparePort()
  519. {
  520. afterFileAllocation();
  521. if (getSocket()->getAddressFamily() == AF_INET6) {
  522. sequence_ = SEQ_PREPARE_SERVER_SOCKET_EPRT;
  523. }
  524. else {
  525. sequence_ = SEQ_PREPARE_SERVER_SOCKET;
  526. }
  527. return true;
  528. }
  529. bool FtpNegotiationCommand::prepareServerSocketEprt()
  530. {
  531. serverSocket_ = ftp_->createServerSocket();
  532. sequence_ = SEQ_SEND_EPRT;
  533. return true;
  534. }
  535. bool FtpNegotiationCommand::prepareServerSocket()
  536. {
  537. serverSocket_ = ftp_->createServerSocket();
  538. sequence_ = SEQ_SEND_PORT;
  539. return true;
  540. }
  541. bool FtpNegotiationCommand::sendEprt()
  542. {
  543. if (ftp_->sendEprt(serverSocket_)) {
  544. disableWriteCheckSocket();
  545. sequence_ = SEQ_RECV_EPRT;
  546. }
  547. else {
  548. setWriteCheckSocket(getSocket());
  549. }
  550. return false;
  551. }
  552. bool FtpNegotiationCommand::recvEprt()
  553. {
  554. int status = ftp_->receiveResponse();
  555. if (status == 0) {
  556. return false;
  557. }
  558. if (status == 200) {
  559. sequence_ = SEQ_SEND_REST;
  560. }
  561. else {
  562. sequence_ = SEQ_PREPARE_SERVER_SOCKET;
  563. }
  564. return true;
  565. }
  566. bool FtpNegotiationCommand::sendPort()
  567. {
  568. if (ftp_->sendPort(serverSocket_)) {
  569. disableWriteCheckSocket();
  570. sequence_ = SEQ_RECV_PORT;
  571. }
  572. else {
  573. setWriteCheckSocket(getSocket());
  574. }
  575. return false;
  576. }
  577. bool FtpNegotiationCommand::recvPort()
  578. {
  579. int status = ftp_->receiveResponse();
  580. if (status == 0) {
  581. return false;
  582. }
  583. if (status != 200) {
  584. throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
  585. error_code::FTP_PROTOCOL_ERROR);
  586. }
  587. sequence_ = SEQ_SEND_REST;
  588. return true;
  589. }
  590. bool FtpNegotiationCommand::preparePasv()
  591. {
  592. afterFileAllocation();
  593. if (getSocket()->getAddressFamily() == AF_INET6) {
  594. sequence_ = SEQ_SEND_EPSV;
  595. }
  596. else {
  597. sequence_ = SEQ_SEND_PASV;
  598. }
  599. return true;
  600. }
  601. bool FtpNegotiationCommand::sendEpsv()
  602. {
  603. if (ftp_->sendEpsv()) {
  604. disableWriteCheckSocket();
  605. sequence_ = SEQ_RECV_EPSV;
  606. }
  607. else {
  608. setWriteCheckSocket(getSocket());
  609. }
  610. return true;
  611. }
  612. bool FtpNegotiationCommand::recvEpsv()
  613. {
  614. uint16_t port;
  615. int status = ftp_->receiveEpsvResponse(port);
  616. if (status == 0) {
  617. return false;
  618. }
  619. if (status == 229) {
  620. pasvPort_ = port;
  621. return preparePasvConnect();
  622. }
  623. else {
  624. sequence_ = SEQ_SEND_PASV;
  625. return true;
  626. }
  627. }
  628. bool FtpNegotiationCommand::sendPasv()
  629. {
  630. if (ftp_->sendPasv()) {
  631. disableWriteCheckSocket();
  632. sequence_ = SEQ_RECV_PASV;
  633. }
  634. else {
  635. setWriteCheckSocket(getSocket());
  636. }
  637. return false;
  638. }
  639. bool FtpNegotiationCommand::recvPasv()
  640. {
  641. std::pair<std::string, uint16_t> dest;
  642. int status = ftp_->receivePasvResponse(dest);
  643. if (status == 0) {
  644. return false;
  645. }
  646. if (status != 227) {
  647. throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
  648. error_code::FTP_PROTOCOL_ERROR);
  649. }
  650. pasvPort_ = dest.second;
  651. ;
  652. return preparePasvConnect();
  653. }
  654. bool FtpNegotiationCommand::preparePasvConnect()
  655. {
  656. if (isProxyDefined()) {
  657. sequence_ = SEQ_RESOLVE_PROXY;
  658. return true;
  659. }
  660. else {
  661. auto endpoint = getSocket()->getPeerInfo();
  662. // make a data connection to the server.
  663. A2_LOG_INFO(fmt(MSG_CONNECTING_TO_SERVER, getCuid(), endpoint.addr.c_str(),
  664. pasvPort_));
  665. dataSocket_ = std::make_shared<SocketCore>();
  666. dataSocket_->establishConnection(endpoint.addr, pasvPort_, false);
  667. disableReadCheckSocket();
  668. setWriteCheckSocket(dataSocket_);
  669. sequence_ = SEQ_SEND_REST_PASV;
  670. return false;
  671. }
  672. }
  673. bool FtpNegotiationCommand::resolveProxy()
  674. {
  675. std::shared_ptr<Request> proxyReq = createProxyRequest();
  676. std::vector<std::string> addrs;
  677. proxyAddr_ = resolveHostname(addrs, proxyReq->getHost(), proxyReq->getPort());
  678. if (proxyAddr_.empty()) {
  679. return false;
  680. }
  681. A2_LOG_INFO(fmt(MSG_CONNECTING_TO_SERVER, getCuid(), proxyAddr_.c_str(),
  682. proxyReq->getPort()));
  683. dataSocket_ = std::make_shared<SocketCore>();
  684. dataSocket_->establishConnection(proxyAddr_, proxyReq->getPort());
  685. disableReadCheckSocket();
  686. setWriteCheckSocket(dataSocket_);
  687. auto socketRecvBuffer = std::make_shared<SocketRecvBuffer>(dataSocket_);
  688. http_ = std::make_shared<HttpConnection>(getCuid(), dataSocket_,
  689. socketRecvBuffer);
  690. sequence_ = SEQ_SEND_TUNNEL_REQUEST;
  691. return false;
  692. }
  693. bool FtpNegotiationCommand::sendTunnelRequest()
  694. {
  695. if (http_->sendBufferIsEmpty()) {
  696. if (dataSocket_->isReadable(0)) {
  697. std::string error = getSocket()->getSocketError();
  698. if (!error.empty()) {
  699. std::shared_ptr<Request> proxyReq = createProxyRequest();
  700. getDownloadEngine()->markBadIPAddress(proxyReq->getHost(), proxyAddr_,
  701. proxyReq->getPort());
  702. std::string nextProxyAddr = getDownloadEngine()->findCachedIPAddress(
  703. proxyReq->getHost(), proxyReq->getPort());
  704. if (nextProxyAddr.empty()) {
  705. getDownloadEngine()->removeCachedIPAddress(proxyReq->getHost(),
  706. proxyReq->getPort());
  707. throw DL_RETRY_EX(
  708. fmt(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()));
  709. }
  710. else {
  711. A2_LOG_INFO(fmt(MSG_CONNECT_FAILED_AND_RETRY, getCuid(),
  712. proxyAddr_.c_str(), proxyReq->getPort()));
  713. proxyAddr_ = nextProxyAddr;
  714. A2_LOG_INFO(fmt(MSG_CONNECTING_TO_SERVER, getCuid(),
  715. proxyAddr_.c_str(), proxyReq->getPort()));
  716. dataSocket_->establishConnection(proxyAddr_, proxyReq->getPort());
  717. return false;
  718. }
  719. }
  720. }
  721. auto httpRequest = make_unique<HttpRequest>();
  722. httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT));
  723. auto req = std::make_shared<Request>();
  724. // Construct fake URI in order to use HttpRequest
  725. std::pair<std::string, uint16_t> dataAddr;
  726. uri::UriStruct us;
  727. us.protocol = "ftp";
  728. us.host = getRequest()->getHost();
  729. us.port = pasvPort_;
  730. us.ipv6LiteralAddress = getRequest()->isIPv6LiteralAddress();
  731. if (!req->setUri(uri::construct(us))) {
  732. throw DL_RETRY_EX("Something wrong with FTP URI");
  733. }
  734. httpRequest->setRequest(req);
  735. httpRequest->setProxyRequest(createProxyRequest());
  736. http_->sendProxyRequest(std::move(httpRequest));
  737. }
  738. else {
  739. http_->sendPendingData();
  740. }
  741. if (http_->sendBufferIsEmpty()) {
  742. disableWriteCheckSocket();
  743. setReadCheckSocket(dataSocket_);
  744. sequence_ = SEQ_RECV_TUNNEL_RESPONSE;
  745. return false;
  746. }
  747. else {
  748. setWriteCheckSocket(dataSocket_);
  749. return false;
  750. }
  751. }
  752. bool FtpNegotiationCommand::recvTunnelResponse()
  753. {
  754. std::shared_ptr<HttpResponse> httpResponse = http_->receiveResponse();
  755. if (!httpResponse) {
  756. return false;
  757. }
  758. if (httpResponse->getStatusCode() != 200) {
  759. throw DL_RETRY_EX(EX_PROXY_CONNECTION_FAILED);
  760. }
  761. sequence_ = SEQ_SEND_REST_PASV;
  762. return true;
  763. }
  764. bool FtpNegotiationCommand::sendRestPasv(
  765. const std::shared_ptr<Segment>& segment)
  766. {
  767. // dataSocket_->setBlockingMode();
  768. // Check connection is made properly
  769. if (dataSocket_->isReadable(0)) {
  770. std::string error = dataSocket_->getSocketError();
  771. throw DL_ABORT_EX2(fmt(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()),
  772. error_code::FTP_PROTOCOL_ERROR);
  773. }
  774. setReadCheckSocket(getSocket());
  775. disableWriteCheckSocket();
  776. return sendRest(segment);
  777. }
  778. bool FtpNegotiationCommand::sendRest(const std::shared_ptr<Segment>& segment)
  779. {
  780. if (ftp_->sendRest(segment)) {
  781. disableWriteCheckSocket();
  782. sequence_ = SEQ_RECV_REST;
  783. }
  784. else {
  785. setWriteCheckSocket(getSocket());
  786. }
  787. return false;
  788. }
  789. bool FtpNegotiationCommand::recvRest(const std::shared_ptr<Segment>& segment)
  790. {
  791. int status = ftp_->receiveResponse();
  792. if (status == 0) {
  793. return false;
  794. }
  795. // If we receive negative response and requested file position is not 0,
  796. // then throw exception here.
  797. if (status != 350) {
  798. if (segment && segment->getPositionToWrite() != 0) {
  799. throw DL_ABORT_EX2("FTP server doesn't support resuming.",
  800. error_code::CANNOT_RESUME);
  801. }
  802. }
  803. sequence_ = SEQ_SEND_RETR;
  804. return true;
  805. }
  806. bool FtpNegotiationCommand::sendRetr()
  807. {
  808. if (ftp_->sendRetr()) {
  809. disableWriteCheckSocket();
  810. sequence_ = SEQ_RECV_RETR;
  811. }
  812. else {
  813. setWriteCheckSocket(getSocket());
  814. }
  815. return false;
  816. }
  817. bool FtpNegotiationCommand::recvRetr()
  818. {
  819. int status = ftp_->receiveResponse();
  820. if (status == 0) {
  821. return false;
  822. }
  823. if (status != 150 && status != 125) {
  824. getRequestGroup()->increaseAndValidateFileNotFoundCount();
  825. if (status == 550)
  826. throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND,
  827. error_code::RESOURCE_NOT_FOUND);
  828. else
  829. throw DL_ABORT_EX2(fmt(EX_BAD_STATUS, status),
  830. error_code::FTP_PROTOCOL_ERROR);
  831. }
  832. if (getOption()->getAsBool(PREF_FTP_PASV)) {
  833. sequence_ = SEQ_NEGOTIATION_COMPLETED;
  834. return false;
  835. }
  836. else {
  837. disableReadCheckSocket();
  838. setReadCheckSocket(serverSocket_);
  839. sequence_ = SEQ_WAIT_CONNECTION;
  840. return false;
  841. }
  842. }
  843. bool FtpNegotiationCommand::waitConnection()
  844. {
  845. disableReadCheckSocket();
  846. setReadCheckSocket(getSocket());
  847. dataSocket_ = serverSocket_->acceptConnection();
  848. sequence_ = SEQ_NEGOTIATION_COMPLETED;
  849. return false;
  850. }
  851. bool FtpNegotiationCommand::processSequence(
  852. const std::shared_ptr<Segment>& segment)
  853. {
  854. bool doNextSequence = true;
  855. switch (sequence_) {
  856. case SEQ_RECV_GREETING:
  857. return recvGreeting();
  858. case SEQ_SEND_USER:
  859. return sendUser();
  860. case SEQ_RECV_USER:
  861. return recvUser();
  862. case SEQ_SEND_PASS:
  863. return sendPass();
  864. case SEQ_RECV_PASS:
  865. return recvPass();
  866. case SEQ_SEND_TYPE:
  867. return sendType();
  868. case SEQ_RECV_TYPE:
  869. return recvType();
  870. case SEQ_SEND_PWD:
  871. return sendPwd();
  872. case SEQ_RECV_PWD:
  873. return recvPwd();
  874. case SEQ_SEND_CWD_PREP:
  875. return sendCwdPrep();
  876. case SEQ_SEND_CWD:
  877. return sendCwd();
  878. case SEQ_RECV_CWD:
  879. return recvCwd();
  880. case SEQ_SEND_MDTM:
  881. return sendMdtm();
  882. case SEQ_RECV_MDTM:
  883. return recvMdtm();
  884. case SEQ_SEND_SIZE:
  885. return sendSize();
  886. case SEQ_RECV_SIZE:
  887. return recvSize();
  888. case SEQ_PREPARE_PORT:
  889. return preparePort();
  890. case SEQ_PREPARE_SERVER_SOCKET_EPRT:
  891. return prepareServerSocketEprt();
  892. case SEQ_SEND_EPRT:
  893. return sendEprt();
  894. case SEQ_RECV_EPRT:
  895. return recvEprt();
  896. case SEQ_PREPARE_SERVER_SOCKET:
  897. return prepareServerSocket();
  898. case SEQ_SEND_PORT:
  899. return sendPort();
  900. case SEQ_RECV_PORT:
  901. return recvPort();
  902. case SEQ_PREPARE_PASV:
  903. return preparePasv();
  904. case SEQ_SEND_EPSV:
  905. return sendEpsv();
  906. case SEQ_RECV_EPSV:
  907. return recvEpsv();
  908. case SEQ_SEND_PASV:
  909. return sendPasv();
  910. case SEQ_RECV_PASV:
  911. return recvPasv();
  912. case SEQ_RESOLVE_PROXY:
  913. return resolveProxy();
  914. case SEQ_SEND_TUNNEL_REQUEST:
  915. return sendTunnelRequest();
  916. case SEQ_RECV_TUNNEL_RESPONSE:
  917. return recvTunnelResponse();
  918. case SEQ_SEND_REST_PASV:
  919. return sendRestPasv(segment);
  920. case SEQ_SEND_REST:
  921. return sendRest(segment);
  922. case SEQ_RECV_REST:
  923. return recvRest(segment);
  924. case SEQ_SEND_RETR:
  925. return sendRetr();
  926. case SEQ_RECV_RETR:
  927. return recvRetr();
  928. case SEQ_WAIT_CONNECTION:
  929. return waitConnection();
  930. default:
  931. abort();
  932. }
  933. return doNextSequence;
  934. }
  935. void FtpNegotiationCommand::poolConnection() const
  936. {
  937. if (getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION)) {
  938. // Store ftp_->getBaseWorkingDir() as options
  939. getDownloadEngine()->poolSocket(getRequest(), ftp_->getUser(),
  940. createProxyRequest(), getSocket(),
  941. ftp_->getBaseWorkingDir());
  942. }
  943. }
  944. void FtpNegotiationCommand::onDryRunFileFound()
  945. {
  946. getPieceStorage()->markAllPiecesDone();
  947. getDownloadContext()->setChecksumVerified(true);
  948. poolConnection();
  949. sequence_ = SEQ_HEAD_OK;
  950. }
  951. } // namespace aria2