/* */ #include "FtpNegotiationCommand.h" #include #include #include #include #include "Request.h" #include "DownloadEngine.h" #include "FtpConnection.h" #include "RequestGroup.h" #include "PieceStorage.h" #include "FtpDownloadCommand.h" #include "FileEntry.h" #include "DlAbortEx.h" #include "message.h" #include "prefs.h" #include "util.h" #include "Option.h" #include "Logger.h" #include "Segment.h" #include "DownloadContext.h" #include "DefaultBtProgressInfoFile.h" #include "RequestGroupMan.h" #include "DownloadFailureException.h" #include "Socket.h" #include "StringFormat.h" #include "DiskAdaptor.h" #include "SegmentMan.h" #include "AuthConfigFactory.h" #include "AuthConfig.h" #include "a2functional.h" #include "URISelector.h" #include "HttpConnection.h" #include "HttpHeader.h" #include "HttpRequest.h" #include "HttpResponse.h" #include "DlRetryEx.h" #include "CookieStorage.h" #include "ServerStatMan.h" #include "FileAllocationEntry.h" #include "CheckIntegrityEntry.h" namespace aria2 { FtpNegotiationCommand::FtpNegotiationCommand (cuid_t cuid, const SharedHandle& req, const SharedHandle& fileEntry, RequestGroup* requestGroup, DownloadEngine* e, const SocketHandle& socket, Seq seq, const std::string& baseWorkingDir): AbstractCommand(cuid, req, fileEntry, requestGroup, e, socket), sequence_(seq), ftp_(new FtpConnection(cuid, socket, req, e->getAuthConfigFactory()->createAuthConfig (req, requestGroup->getOption().get()), getOption().get())) { ftp_->setBaseWorkingDir(baseWorkingDir); if(seq == SEQ_RECV_GREETING) { setTimeout(getOption()->getAsInt(PREF_CONNECT_TIMEOUT)); } disableReadCheckSocket(); setWriteCheckSocket(getSocket()); } FtpNegotiationCommand::~FtpNegotiationCommand() {} bool FtpNegotiationCommand::executeInternal() { while(processSequence(getSegments().front())); if(sequence_ == SEQ_RETRY) { return prepareForRetry(0); } else if(sequence_ == SEQ_NEGOTIATION_COMPLETED) { FtpDownloadCommand* command = new FtpDownloadCommand (getCuid(), getRequest(), getFileEntry(), getRequestGroup(), ftp_, getDownloadEngine(), dataSocket_, getSocket()); command->setStartupIdleTime(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME)); command->setLowestDownloadSpeedLimit (getOption()->getAsInt(PREF_LOWEST_SPEED_LIMIT)); if(getFileEntry()->isUniqueProtocol()) { getFileEntry()->removeURIWhoseHostnameIs(getRequest()->getHost()); } getRequestGroup()->getURISelector()->tuneDownloadCommand (getFileEntry()->getRemainingUris(), command); getDownloadEngine()->addCommand(command); return true; } else if(sequence_ == SEQ_HEAD_OK || sequence_ == SEQ_DOWNLOAD_ALREADY_COMPLETED) { return true; } else if(sequence_ == SEQ_FILE_PREPARATION) { if(getOption()->getAsBool(PREF_FTP_PASV)) { sequence_ = SEQ_PREPARE_PASV; } else { sequence_ = SEQ_PREPARE_PORT; } return false; } else if(sequence_ == SEQ_EXIT) { return true; } else { getDownloadEngine()->addCommand(this); return false; } } bool FtpNegotiationCommand::recvGreeting() { if(!checkIfConnectionEstablished (getSocket(), getRequest()->getConnectedHostname(), getRequest()->getConnectedAddr(), getRequest()->getConnectedPort())) { sequence_ = SEQ_EXIT; return false; } setTimeout(getRequestGroup()->getTimeout()); //socket->setBlockingMode(); disableWriteCheckSocket(); setReadCheckSocket(getSocket()); unsigned int status = ftp_->receiveResponse(); if(status == 0) { return false; } if(status != 220) { throw DL_ABORT_EX(EX_CONNECTION_FAILED); } sequence_ = SEQ_SEND_USER; return true; } bool FtpNegotiationCommand::sendUser() { if(ftp_->sendUser()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_USER; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvUser() { unsigned int status = ftp_->receiveResponse(); switch(status) { case 0: return false; case 230: sequence_ = SEQ_SEND_TYPE; break; case 331: sequence_ = SEQ_SEND_PASS; break; default: throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); } return true; } bool FtpNegotiationCommand::sendPass() { if(ftp_->sendPass()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_PASS; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvPass() { unsigned int status = ftp_->receiveResponse(); if(status == 0) { return false; } if(status != 230) { throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); } sequence_ = SEQ_SEND_TYPE; return true; } bool FtpNegotiationCommand::sendType() { if(ftp_->sendType()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_TYPE; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvType() { unsigned int status = ftp_->receiveResponse(); if(status == 0) { return false; } if(status != 200) { throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); } sequence_ = SEQ_SEND_PWD; return true; } bool FtpNegotiationCommand::sendPwd() { if(ftp_->sendPwd()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_PWD; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvPwd() { std::string pwd; unsigned int status = ftp_->receivePwdResponse(pwd); if(status == 0) { return false; } if(status != 257) { throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); } ftp_->setBaseWorkingDir(pwd); if(getLogger()->info()) { getLogger()->info("CUID#%s - base working directory is '%s'", util::itos(getCuid()).c_str(), pwd.c_str()); } sequence_ = SEQ_SEND_CWD_PREP; return true; } bool FtpNegotiationCommand::sendCwdPrep() { // Calling setReadCheckSocket() is needed when the socket is reused, setReadCheckSocket(getSocket()); util::split(getRequest()->getDir(), std::back_inserter(cwdDirs_), A2STR::SLASH_C); cwdDirs_.push_front(ftp_->getBaseWorkingDir()); sequence_ = SEQ_SEND_CWD; return true; } bool FtpNegotiationCommand::sendCwd() { if(ftp_->sendCwd(cwdDirs_.front())) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_CWD; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvCwd() { unsigned int status = ftp_->receiveResponse(); if(status == 0) { return false; } if(status != 250) { poolConnection(); getRequestGroup()->increaseAndValidateFileNotFoundCount(); if (status == 550) throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND, downloadresultcode::RESOURCE_NOT_FOUND); else throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); } cwdDirs_.pop_front(); if(cwdDirs_.empty()) { if(getOption()->getAsBool(PREF_REMOTE_TIME)) { sequence_ = SEQ_SEND_MDTM; } else { sequence_ = SEQ_SEND_SIZE; } } else { sequence_ = SEQ_SEND_CWD; } return true; } bool FtpNegotiationCommand::sendMdtm() { if(ftp_->sendMdtm()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_MDTM; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvMdtm() { Time lastModifiedTime = Time::null(); unsigned int status = ftp_->receiveMdtmResponse(lastModifiedTime); if(status == 0) { return false; } if(status == 213) { if(lastModifiedTime.good()) { getRequestGroup()->updateLastModifiedTime(lastModifiedTime); time_t t = lastModifiedTime.getTime(); struct tm* tms = gmtime(&t); // returned struct is statically allocated. if(tms) { if(getLogger()->debug()) { getLogger()->debug("MDTM result was parsed as: %s GMT", asctime(tms)); } } else { if(getLogger()->debug()) { getLogger()->debug("gmtime() failed for MDTM result."); } } } else { if(getLogger()->debug()) { getLogger()->debug("MDTM response was returned, but it seems not to be" " a time value as in specified in RFC3659."); } } } else { if(getLogger()->info()) { getLogger()->info("CUID#%s - MDTM command failed.", util::itos(getCuid()).c_str()); } } sequence_ = SEQ_SEND_SIZE; return true; } bool FtpNegotiationCommand::sendSize() { if(ftp_->sendSize()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_SIZE; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::onFileSizeDetermined(uint64_t totalLength) { getFileEntry()->setLength(totalLength); if(getFileEntry()->getPath().empty()) { getFileEntry()->setPath (util::createSafePath (getDownloadContext()->getDir(), util::percentDecode(getRequest()->getFile()))); } getRequestGroup()->preDownloadProcessing(); if(getDownloadEngine()->getRequestGroupMan()-> isSameFileBeingDownloaded(getRequestGroup())) { throw DOWNLOAD_FAILURE_EXCEPTION (StringFormat(EX_DUPLICATE_FILE_DOWNLOAD, getRequestGroup()->getFirstFilePath().c_str()).str()); } if(totalLength == 0) { if(getOption()->getAsBool(PREF_FTP_PASV)) { sequence_ = SEQ_PREPARE_PASV; } else { sequence_ = SEQ_PREPARE_PORT; } if(getOption()->getAsBool(PREF_DRY_RUN)) { getRequestGroup()->initPieceStorage(); onDryRunFileFound(); return false; } if(getDownloadContext()->knowsTotalLength() && getRequestGroup()->downloadFinishedByFileLength()) { // TODO If metalink file does not contain size and it contains // hash and file is not zero length, but remote server says the // file size is 0, no hash check is performed in the current // implementation. See also // HttpResponseCommand::handleOtherEncoding() getRequestGroup()->initPieceStorage(); getPieceStorage()->markAllPiecesDone(); getDownloadContext()->setChecksumVerified(true); sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED; getLogger()->notice(MSG_DOWNLOAD_ALREADY_COMPLETED, util::itos(getRequestGroup()->getGID()).c_str(), getRequestGroup()->getFirstFilePath().c_str()); poolConnection(); return false; } getRequestGroup()->shouldCancelDownloadForSafety(); getRequestGroup()->initPieceStorage(); getPieceStorage()->getDiskAdaptor()->initAndOpenFile(); if(getDownloadContext()->knowsTotalLength()) { sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED; getPieceStorage()->markAllPiecesDone(); poolConnection(); return false; } // We have to make sure that command that has Request object must // have segment after PieceStorage is initialized. See // AbstractCommand::execute() getSegmentMan()->getSegmentWithIndex(getCuid(), 0); return true; } else { getRequestGroup()->adjustFilename (SharedHandle (new DefaultBtProgressInfoFile (getDownloadContext(), SharedHandle(), getOption().get()))); getRequestGroup()->initPieceStorage(); if(getOption()->getAsBool(PREF_DRY_RUN)) { onDryRunFileFound(); return false; } SharedHandle checkIntegrityEntry = getRequestGroup()->createCheckIntegrityEntry(); if(checkIntegrityEntry.isNull()) { sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED; poolConnection(); return false; } checkIntegrityEntry->pushNextCommand(this); // We have to make sure that command that has Request object must // have segment after PieceStorage is initialized. See // AbstractCommand::execute() getSegmentMan()->getSegmentWithIndex(getCuid(), 0); prepareForNextAction(checkIntegrityEntry); disableReadCheckSocket(); } return false; } bool FtpNegotiationCommand::recvSize() { uint64_t size = 0; unsigned int status = ftp_->receiveSizeResponse(size); if(status == 0) { return false; } if(status == 213) { if(size > INT64_MAX) { throw DL_ABORT_EX (StringFormat(EX_TOO_LARGE_FILE, util::uitos(size, true).c_str()).str()); } if(getPieceStorage().isNull()) { sequence_ = SEQ_FILE_PREPARATION; return onFileSizeDetermined(size); } else { getRequestGroup()->validateTotalLength(getFileEntry()->getLength(), size); } } else { if(getLogger()->info()) { getLogger()->info("CUID#%s - The remote FTP Server doesn't recognize SIZE" " command. Continue.", util::itos(getCuid()).c_str()); } // Even if one of the other servers waiting in the queue supports SIZE // command, resuming and segmented downloading are disabled when the first // contacted FTP server doesn't support it. if(getPieceStorage().isNull()) { getDownloadContext()->markTotalLengthIsUnknown(); return onFileSizeDetermined(0); } // TODO Skipping RequestGroup::validateTotalLength(0) here will allow // wrong file to be downloaded if user-specified URL is wrong. } if(getOption()->getAsBool(PREF_FTP_PASV)) { sequence_ = SEQ_PREPARE_PASV; } else { sequence_ = SEQ_PREPARE_PORT; } return true; } void FtpNegotiationCommand::afterFileAllocation() { setReadCheckSocket(getSocket()); } bool FtpNegotiationCommand::preparePort() { afterFileAllocation(); if(getSocket()->getAddressFamily() == AF_INET6) { sequence_ = SEQ_PREPARE_SERVER_SOCKET_EPRT; } else { sequence_ = SEQ_PREPARE_SERVER_SOCKET; } return true; } bool FtpNegotiationCommand::prepareServerSocketEprt() { serverSocket_ = ftp_->createServerSocket(); sequence_ = SEQ_SEND_EPRT; return true; } bool FtpNegotiationCommand::prepareServerSocket() { serverSocket_ = ftp_->createServerSocket(); sequence_ = SEQ_SEND_PORT; return true; } bool FtpNegotiationCommand::sendEprt() { if(ftp_->sendEprt(serverSocket_)) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_EPRT; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvEprt() { unsigned int status = ftp_->receiveResponse(); if(status == 0) { return false; } if(status == 200) { sequence_ = SEQ_SEND_REST; } else { sequence_ = SEQ_PREPARE_SERVER_SOCKET; } return true; } bool FtpNegotiationCommand::sendPort() { if(ftp_->sendPort(serverSocket_)) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_PORT; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvPort() { unsigned int status = ftp_->receiveResponse(); if(status == 0) { return false; } if(status != 200) { throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); } sequence_ = SEQ_SEND_REST; return true; } bool FtpNegotiationCommand::preparePasv() { afterFileAllocation(); if(getSocket()->getAddressFamily() == AF_INET6) { sequence_ = SEQ_SEND_EPSV; } else { sequence_ = SEQ_SEND_PASV; } return true; } bool FtpNegotiationCommand::sendEpsv() { if(ftp_->sendEpsv()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_EPSV; } else { setWriteCheckSocket(getSocket()); } return true; } bool FtpNegotiationCommand::recvEpsv() { uint16_t port; unsigned int status = ftp_->receiveEpsvResponse(port); if(status == 0) { return false; } if(status == 229) { std::pair peerInfo; getSocket()->getPeerInfo(peerInfo); peerInfo.second = port; dataConnAddr_ = peerInfo; return preparePasvConnect(); } else { sequence_ = SEQ_SEND_PASV; return true; } } bool FtpNegotiationCommand::sendPasv() { if(ftp_->sendPasv()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_PASV; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvPasv() { std::pair dest; unsigned int status = ftp_->receivePasvResponse(dest); if(status == 0) { return false; } if(status != 227) { throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); } dataConnAddr_ = dest; return preparePasvConnect(); } bool FtpNegotiationCommand::preparePasvConnect() { // TODO Should we check to see that dataConnAddr_.first is not in // noProxy list? if(isProxyDefined()) { sequence_ = SEQ_RESOLVE_PROXY; return true; } else { // make a data connection to the server. if(getLogger()->info()) { getLogger()->info(MSG_CONNECTING_TO_SERVER, util::itos(getCuid()).c_str(), dataConnAddr_.first.c_str(), dataConnAddr_.second); } dataSocket_.reset(new SocketCore()); dataSocket_->establishConnection(dataConnAddr_.first, dataConnAddr_.second); disableReadCheckSocket(); setWriteCheckSocket(dataSocket_); sequence_ = SEQ_SEND_REST_PASV; return false; } } bool FtpNegotiationCommand::resolveProxy() { SharedHandle proxyReq = createProxyRequest(); std::vector addrs; proxyAddr_ = resolveHostname (addrs, proxyReq->getHost(), proxyReq->getPort()); if(proxyAddr_.empty()) { return false; } if(getLogger()->info()) { getLogger()->info(MSG_CONNECTING_TO_SERVER, util::itos(getCuid()).c_str(), proxyAddr_.c_str(), proxyReq->getPort()); } dataSocket_.reset(new SocketCore()); dataSocket_->establishConnection(proxyAddr_, proxyReq->getPort()); disableReadCheckSocket(); setWriteCheckSocket(dataSocket_); http_.reset(new HttpConnection(getCuid(), dataSocket_)); sequence_ = SEQ_SEND_TUNNEL_REQUEST; return false; } bool FtpNegotiationCommand::sendTunnelRequest() { if(http_->sendBufferIsEmpty()) { if(dataSocket_->isReadable(0)) { std::string error = getSocket()->getSocketError(); if(!error.empty()) { SharedHandle proxyReq = createProxyRequest(); getDownloadEngine()->markBadIPAddress(proxyReq->getHost(), proxyAddr_,proxyReq->getPort()); std::string nextProxyAddr = getDownloadEngine()->findCachedIPAddress (proxyReq->getHost(), proxyReq->getPort()); if(nextProxyAddr.empty()) { getDownloadEngine()->removeCachedIPAddress(proxyReq->getHost(), proxyReq->getPort()); throw DL_RETRY_EX (StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()).str()); } else { if(getLogger()->info()) { getLogger()->info(MSG_CONNECT_FAILED_AND_RETRY, util::itos(getCuid()).c_str(), proxyAddr_.c_str(), proxyReq->getPort()); } proxyAddr_ = nextProxyAddr; if(getLogger()->info()) { getLogger()->info(MSG_CONNECTING_TO_SERVER, util::itos(getCuid()).c_str(), proxyAddr_.c_str(), proxyReq->getPort()); } dataSocket_->establishConnection(proxyAddr_, proxyReq->getPort()); return false; } } } SharedHandle httpRequest(new HttpRequest()); httpRequest->setUserAgent(getOption()->get(PREF_USER_AGENT)); SharedHandle req(new Request()); // Construct fake URI in order to use HttpRequest req->setUri(strconcat("ftp://", dataConnAddr_.first, A2STR::COLON_C, util::uitos(dataConnAddr_.second))); httpRequest->setRequest(req); httpRequest->setProxyRequest(createProxyRequest()); http_->sendProxyRequest(httpRequest); } else { http_->sendPendingData(); } if(http_->sendBufferIsEmpty()) { disableWriteCheckSocket(); setReadCheckSocket(dataSocket_); sequence_ = SEQ_RECV_TUNNEL_RESPONSE; return false; } else { setWriteCheckSocket(dataSocket_); return false; } } bool FtpNegotiationCommand::recvTunnelResponse() { SharedHandle httpResponse = http_->receiveResponse(); if(httpResponse.isNull()) { return false; } if(httpResponse->getResponseStatus() != HttpHeader::S200) { throw DL_RETRY_EX(EX_PROXY_CONNECTION_FAILED); } sequence_ = SEQ_SEND_REST_PASV; return true; } bool FtpNegotiationCommand::sendRestPasv(const SharedHandle& segment) { //dataSocket_->setBlockingMode(); // Check connection is made properly if(dataSocket_->isReadable(0)) { std::string error = dataSocket_->getSocketError(); throw DL_ABORT_EX (StringFormat(MSG_ESTABLISHING_CONNECTION_FAILED, error.c_str()).str()); } setReadCheckSocket(getSocket()); disableWriteCheckSocket(); return sendRest(segment); } bool FtpNegotiationCommand::sendRest(const SharedHandle& segment) { if(ftp_->sendRest(segment)) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_REST; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvRest(const SharedHandle& segment) { unsigned int status = ftp_->receiveResponse(); if(status == 0) { return false; } // If we recieve negative response and requested file position is not 0, // then throw exception here. if(status != 350) { if(!segment.isNull() && segment->getPositionToWrite() != 0) { throw DL_ABORT_EX2("FTP server doesn't support resuming.", downloadresultcode::CANNOT_RESUME); } } sequence_ = SEQ_SEND_RETR; return true; } bool FtpNegotiationCommand::sendRetr() { if(ftp_->sendRetr()) { disableWriteCheckSocket(); sequence_ = SEQ_RECV_RETR; } else { setWriteCheckSocket(getSocket()); } return false; } bool FtpNegotiationCommand::recvRetr() { unsigned int status = ftp_->receiveResponse(); if(status == 0) { return false; } if(status != 150 && status != 125) { getRequestGroup()->increaseAndValidateFileNotFoundCount(); if (status == 550) throw DL_ABORT_EX2(MSG_RESOURCE_NOT_FOUND, downloadresultcode::RESOURCE_NOT_FOUND); else throw DL_ABORT_EX(StringFormat(EX_BAD_STATUS, status).str()); } if(getOption()->getAsBool(PREF_FTP_PASV)) { sequence_ = SEQ_NEGOTIATION_COMPLETED; return false; } else { disableReadCheckSocket(); setReadCheckSocket(serverSocket_); sequence_ = SEQ_WAIT_CONNECTION; return false; } } bool FtpNegotiationCommand::waitConnection() { disableReadCheckSocket(); setReadCheckSocket(getSocket()); dataSocket_.reset(serverSocket_->acceptConnection()); dataSocket_->setNonBlockingMode(); sequence_ = SEQ_NEGOTIATION_COMPLETED; return false; } bool FtpNegotiationCommand::processSequence (const SharedHandle& segment) { bool doNextSequence = true; switch(sequence_) { case SEQ_RECV_GREETING: return recvGreeting(); case SEQ_SEND_USER: return sendUser(); case SEQ_RECV_USER: return recvUser(); case SEQ_SEND_PASS: return sendPass(); case SEQ_RECV_PASS: return recvPass(); case SEQ_SEND_TYPE: return sendType(); case SEQ_RECV_TYPE: return recvType(); case SEQ_SEND_PWD: return sendPwd(); case SEQ_RECV_PWD: return recvPwd(); case SEQ_SEND_CWD_PREP: return sendCwdPrep(); case SEQ_SEND_CWD: return sendCwd(); case SEQ_RECV_CWD: return recvCwd(); case SEQ_SEND_MDTM: return sendMdtm(); case SEQ_RECV_MDTM: return recvMdtm(); case SEQ_SEND_SIZE: return sendSize(); case SEQ_RECV_SIZE: return recvSize(); case SEQ_PREPARE_PORT: return preparePort(); case SEQ_PREPARE_SERVER_SOCKET_EPRT: return prepareServerSocketEprt(); case SEQ_SEND_EPRT: return sendEprt(); case SEQ_RECV_EPRT: return recvEprt(); case SEQ_PREPARE_SERVER_SOCKET: return prepareServerSocket(); case SEQ_SEND_PORT: return sendPort(); case SEQ_RECV_PORT: return recvPort(); case SEQ_PREPARE_PASV: return preparePasv(); case SEQ_SEND_EPSV: return sendEpsv(); case SEQ_RECV_EPSV: return recvEpsv(); case SEQ_SEND_PASV: return sendPasv(); case SEQ_RECV_PASV: return recvPasv(); case SEQ_RESOLVE_PROXY: return resolveProxy(); case SEQ_SEND_TUNNEL_REQUEST: return sendTunnelRequest(); case SEQ_RECV_TUNNEL_RESPONSE: return recvTunnelResponse(); case SEQ_SEND_REST_PASV: return sendRestPasv(segment); case SEQ_SEND_REST: return sendRest(segment); case SEQ_RECV_REST: return recvRest(segment); case SEQ_SEND_RETR: return sendRetr(); case SEQ_RECV_RETR: return recvRetr(); case SEQ_WAIT_CONNECTION: return waitConnection(); default: abort(); } return doNextSequence; } void FtpNegotiationCommand::poolConnection() const { if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION)) { std::map options; options["baseWorkingDir"] = ftp_->getBaseWorkingDir(); getDownloadEngine()->poolSocket(getRequest(), ftp_->getUser(), createProxyRequest(), getSocket(), options); } } void FtpNegotiationCommand::onDryRunFileFound() { getPieceStorage()->markAllPiecesDone(); getDownloadContext()->setChecksumVerified(true); poolConnection(); sequence_ = SEQ_HEAD_OK; } } // namespace aria2