/* */ #include "AbstractCommand.h" #include "DlAbortEx.h" #include "DlRetryEx.h" #include "InitiateConnectionCommandFactory.h" #include #include "Util.h" #include "message.h" #include "SleepCommand.h" #include "prefs.h" AbstractCommand::AbstractCommand(int cuid, Request* req, DownloadEngine* e, const Socket* s): Command(cuid), req(req), e(e), checkSocketIsReadable(false), checkSocketIsWritable(false) { if(s != NULL) { socket = new Socket(*s); setReadCheckSocket(socket); } else { socket = NULL; } this->checkPoint.tv_sec = 0; this->checkPoint.tv_usec = 0; } AbstractCommand::~AbstractCommand() { setReadCheckSocket(NULL); setWriteCheckSocket(NULL); if(socket != NULL) { delete(socket); } } void AbstractCommand::updateCheckPoint() { gettimeofday(&checkPoint, NULL); } bool AbstractCommand::isTimeoutDetected() { struct timeval now; gettimeofday(&now, NULL); if(checkPoint.tv_sec == 0 && checkPoint.tv_usec == 0) { checkPoint = now; return false; } else { long long int elapsed = Util::difftv(now, checkPoint); if(elapsed >= e->option->getAsLLInt(PREF_TIMEOUT)*1000000) { return true; } else { return false; } } } bool AbstractCommand::execute() { try { if(checkSocketIsReadable && !readCheckTarget->isReadable(0) || checkSocketIsWritable && !writeCheckTarget->isWritable(0)) { if(isTimeoutDetected()) { throw new DlRetryEx(EX_TIME_OUT); } e->commands.push(this); return false; } updateCheckPoint(); Segment seg = { 0, 0, 0, false }; if(e->segmentMan->downloadStarted) { // get segment information in order to set Range header. if(!e->segmentMan->getSegment(seg, cuid)) { // no segment available e->logger->info(MSG_NO_SEGMENT_AVAILABLE, cuid); return true; } } return executeInternal(seg); } catch(DlAbortEx* err) { e->logger->error(MSG_DOWNLOAD_ABORTED, err, cuid); onAbort(err); delete(err); req->resetUrl(); return true; } catch(DlRetryEx* err) { e->logger->error(MSG_RESTARTING_DOWNLOAD, err, cuid); req->addTryCount(); bool isAbort = e->option->getAsInt(PREF_MAX_TRIES) != 0 && req->getTryCount() >= e->option->getAsInt(PREF_MAX_TRIES); if(isAbort) { onAbort(err); } delete(err); if(isAbort) { e->logger->error(MSG_MAX_TRY, cuid, req->getTryCount()); return true; } else { return prepareForRetry(e->option->getAsInt(PREF_RETRY_WAIT)); } } } bool AbstractCommand::prepareForRetry(int wait) { Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, e); if(wait == 0) { e->commands.push(command); } else { SleepCommand* scom = new SleepCommand(cuid, e, command, wait); e->commands.push(scom); } return true; } void AbstractCommand::onAbort(Exception* ex) { e->logger->debug(MSG_UNREGISTER_CUID, cuid); e->segmentMan->unregisterId(cuid); } void AbstractCommand::setReadCheckSocket(Socket* socket) { if(socket == NULL) { if(checkSocketIsReadable) { e->deleteSocketForReadCheck(readCheckTarget); checkSocketIsReadable = false; readCheckTarget = NULL; } } else { if(checkSocketIsReadable) { if(readCheckTarget != socket) { e->deleteSocketForReadCheck(readCheckTarget); e->addSocketForReadCheck(socket); readCheckTarget = socket; } } else { e->addSocketForReadCheck(socket); checkSocketIsReadable = true; readCheckTarget = socket; } } } void AbstractCommand::setWriteCheckSocket(Socket* socket) { if(socket == NULL) { if(checkSocketIsWritable) { e->deleteSocketForWriteCheck(writeCheckTarget); checkSocketIsWritable = false; writeCheckTarget = NULL; } } else { if(checkSocketIsWritable) { if(writeCheckTarget != socket) { e->deleteSocketForWriteCheck(writeCheckTarget); e->addSocketForWriteCheck(socket); writeCheckTarget = socket; } } else { e->addSocketForWriteCheck(socket); checkSocketIsWritable = true; writeCheckTarget = socket; } } }