Browse Source

2009-01-12 Tatsuhiro Tsujikawa <t-tujikawa@users.sourceforge.net>

	Applied exit-status patch from Pascal Rigaux at Mandriva.  aria2
	now returns last error encountered in the HTTP/FTP downloads as
	a exit status value.  If all downloads finished successfully, 
	aria2 returns 0.  The error code is defined in
	src/DownloadResult.h.
	The error occurred in the download currently in progress is not
	reported as a last error.  If no error has encountered but there
	are in progress or waiting downloads, aria2 returns 7.
	
	* src/AbstractCommand.cc
	* src/DlAbortEx.h
	* src/DlRetryEx.h
	* src/DownloadCommand.cc
	* src/DownloadFailureException.h
	* src/DownloadResult.h
	* src/FtpNegotiationCommand.cc
	* src/HttpSkipResponseCommand.cc
	* src/Makefile.am
	* src/MultiUrlRequestInfo.cc
	* src/MultiUrlRequestInfo.h
	* src/RecoverableException.h
	* src/RequestGroup.cc
	* src/RequestGroup.h
	* src/RequestGroupMan.cc
	* src/RequestGroupMan.h
	* src/URIResult.cc
	* src/URIResult.h
	* src/main.cc
	* src/option_processing.cc
	* test/RequestGroupTest.cc
Tatsuhiro Tsujikawa 17 years ago
parent
commit
8a9d921465

+ 32 - 0
ChangeLog

@@ -1,3 +1,35 @@
+2009-01-12  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
+
+	Applied exit-status patch from Pascal Rigaux at Mandriva.  aria2
+	now returns last error encountered in the HTTP/FTP downloads as a
+	exit status value.  If all downloads finished successfully, aria2
+	returns 0.  The error code is defined in src/DownloadResult.h.
+	The error occurred in the download currently in progress is not
+	reported as a last error.  If no error has encountered but there
+	are in progress or waiting downloads, aria2 returns 7.
+	
+	* src/AbstractCommand.cc
+	* src/DlAbortEx.h
+	* src/DlRetryEx.h
+	* src/DownloadCommand.cc
+	* src/DownloadFailureException.h
+	* src/DownloadResult.h
+	* src/FtpNegotiationCommand.cc
+	* src/HttpSkipResponseCommand.cc
+	* src/Makefile.am
+	* src/MultiUrlRequestInfo.cc
+	* src/MultiUrlRequestInfo.h
+	* src/RecoverableException.h
+	* src/RequestGroup.cc
+	* src/RequestGroup.h
+	* src/RequestGroupMan.cc
+	* src/RequestGroupMan.h
+	* src/URIResult.cc
+	* src/URIResult.h
+	* src/main.cc
+	* src/option_processing.cc
+	* test/RequestGroupTest.cc
+
 2009-01-06  Tatsuhiro Tsujikawa  <t-tujikawa@users.sourceforge.net>
 
 	Applied AdaptiveURISelector patch from Aurelien Lefebvre.  This

+ 4 - 1
src/AbstractCommand.cc

@@ -149,13 +149,14 @@ bool AbstractCommand::execute() {
 						     req->getProtocol());
 	ss->setError();
 
-	throw DlRetryEx(EX_TIME_OUT);
+	throw DlRetryEx(EX_TIME_OUT, DownloadResult::TIME_OUT);
       }
       e->commands.push_back(this);
       return false;
     }
   } catch(DlAbortEx& err) {
     logger->error(MSG_DOWNLOAD_ABORTED, err, cuid, req->getUrl().c_str());
+    _requestGroup->addURIResult(req->getUrl(), err.getCode());
     onAbort();
     req->resetUrl();
     tryReserved();
@@ -174,6 +175,7 @@ bool AbstractCommand::execute() {
     if(isAbort) {
       logger->info(MSG_MAX_TRY, cuid, req->getTryCount());
       logger->error(MSG_DOWNLOAD_ABORTED, err, cuid, req->getUrl().c_str());
+      _requestGroup->addURIResult(req->getUrl(), err.getCode());
       tryReserved();
       return true;
     } else {
@@ -181,6 +183,7 @@ bool AbstractCommand::execute() {
     }
   } catch(DownloadFailureException& err) {
     logger->error(EX_EXCEPTION_CAUGHT, err);
+    _requestGroup->addURIResult(req->getUrl(), err.getCode());
     _requestGroup->setHaltRequested(true);
     return true;
   }

+ 2 - 0
src/DlAbortEx.h

@@ -50,6 +50,8 @@ public:
   DlAbortEx(const std::string& msg,
 	    const Exception& cause):RecoverableException(msg, cause) {}
   DlAbortEx(const RecoverableException& e):RecoverableException(e) {}
+  DlAbortEx(const std::string& msg, DownloadResult::RESULT code):
+    RecoverableException(msg, code) {}
 };
 
 } // namespace aria2

+ 2 - 0
src/DlRetryEx.h

@@ -50,6 +50,8 @@ public:
   DlRetryEx(const std::string& msg,
 	    const Exception& cause):RecoverableException(msg, cause) {}
   DlRetryEx(const DlRetryEx& e):RecoverableException(e) {}
+  DlRetryEx(const std::string& msg, DownloadResult::RESULT code):
+    RecoverableException(msg, code) {}
 };
 
 } // namespace aria2

+ 1 - 1
src/DownloadCommand.cc

@@ -243,7 +243,7 @@ void DownloadCommand::checkLowestDownloadSpeed() const
       throw DlAbortEx(StringFormat(EX_TOO_SLOW_DOWNLOAD_SPEED,
 				   nowSpeed,
 				   lowestDownloadSpeedLimit,
-				   req->getHost().c_str()).str());
+				   req->getHost().c_str()).str(), DownloadResult::TOO_SLOW_DOWNLOAD_SPEED);
     }
   }
 }

+ 6 - 2
src/DownloadFailureException.h

@@ -52,8 +52,12 @@ protected:
 public:
   DownloadFailureException(const std::string& msg):RecoverableException(msg) {}
   DownloadFailureException(const std::string& msg,
-			   const Exception& cause):RecoverableException(msg, cause) {}
-  DownloadFailureException(const DownloadFailureException& e):RecoverableException(e) {}
+			   const Exception& cause):
+    RecoverableException(msg, cause) {}
+  DownloadFailureException(const DownloadFailureException& e):
+    RecoverableException(e) {}
+  DownloadFailureException(const std::string& msg, DownloadResult::RESULT code):
+    RecoverableException(msg, code) {}
 };
 
 } // namespace aria2

+ 13 - 3
src/DownloadResult.h

@@ -36,18 +36,28 @@
 #define _D_DOWNLOAD_RESULT_H_
 
 #include "common.h"
-#include "SharedHandle.h"
+
 #include <stdint.h>
+
 #include <string>
 
+#include "SharedHandle.h"
+
 namespace aria2 {
 
 class DownloadResult
 {
 public:
+  // RESULT is used as an exit status code.
   enum RESULT {
-    FINISHED,
-    NOT_YET,
+    FINISHED = 0,
+    UNKNOWN_ERROR = 1,
+    TIME_OUT = 2,
+    RESOURCE_NOT_FOUND = 3,
+    MAX_FILE_NOT_FOUND = 4,
+    TOO_SLOW_DOWNLOAD_SPEED = 5,
+    NETWORK_PROBLEM = 6,
+    IN_PROGRESS = 7,
   };
 
   int32_t gid;

+ 8 - 2
src/FtpNegotiationCommand.cc

@@ -261,7 +261,10 @@ bool FtpNegotiationCommand::recvCwd() {
   if(status != 250) {
     poolConnection();
     _requestGroup->increaseAndValidateFileNotFoundCount();
-    throw DlAbortEx(StringFormat(EX_BAD_STATUS, status).str());
+    if (status == 550)
+      throw DlAbortEx(MSG_RESOURCE_NOT_FOUND, DownloadResult::RESOURCE_NOT_FOUND);
+    else
+      throw DlAbortEx(StringFormat(EX_BAD_STATUS, status).str());
   }
   if(e->option->getAsBool(PREF_REMOTE_TIME)) {
     sequence = SEQ_SEND_MDTM;
@@ -544,7 +547,10 @@ bool FtpNegotiationCommand::recvRetr() {
   }
   if(status != 150 && status != 125) {
     _requestGroup->increaseAndValidateFileNotFoundCount();
-    throw DlAbortEx(StringFormat(EX_BAD_STATUS, status).str());
+    if (status == 550)
+      throw DlAbortEx(MSG_RESOURCE_NOT_FOUND, DownloadResult::RESOURCE_NOT_FOUND);
+    else
+      throw DlAbortEx(StringFormat(EX_BAD_STATUS, status).str());
   }
   if(e->option->getAsBool(PREF_FTP_PASV)) {
     sequence = SEQ_NEGOTIATION_COMPLETED;

+ 2 - 1
src/HttpSkipResponseCommand.cc

@@ -160,7 +160,8 @@ bool HttpSkipResponseCommand::processResponse()
     if(_httpResponse->getResponseStatus() == HttpHeader::S401) {
       throw DlAbortEx(EX_AUTH_FAILED);
     }else if(_httpResponse->getResponseStatus() == HttpHeader::S404) {
-      throw DlAbortEx(MSG_RESOURCE_NOT_FOUND);
+      throw DlAbortEx(MSG_RESOURCE_NOT_FOUND,
+		      DownloadResult::RESOURCE_NOT_FOUND);
     } else {
       throw DlAbortEx(StringFormat(EX_BAD_STATUS, Util::parseUInt(_httpResponse->getResponseStatus())).str());
     }

+ 3 - 2
src/Makefile.am

@@ -188,14 +188,15 @@ SRCS =  Socket.h\
 	ServerStat.cc ServerStat.h\
 	ServerStatMan.cc ServerStatMan.h\
 	URISelector.h\
- 	AdaptiveURISelector.cc AdaptiveURISelector.h\
+	AdaptiveURISelector.cc AdaptiveURISelector.h\
 	InOrderURISelector.cc InOrderURISelector.h\
 	ServerStatURISelector.cc ServerStatURISelector.h\
 	NsCookieParser.cc NsCookieParser.h\
 	CookieStorage.cc CookieStorage.h\
 	SocketBuffer.cc SocketBuffer.h\
 	OptionHandlerException.cc OptionHandlerException.h\
-	bencode.cc bencode.h
+	bencode.cc bencode.h\
+	URIResult.cc URIResult.h
 
 if ENABLE_SSL
 SRCS += TLSContext.h

+ 21 - 19
src/Makefile.in

@@ -411,10 +411,10 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	ServerStatURISelector.h NsCookieParser.cc NsCookieParser.h \
 	CookieStorage.cc CookieStorage.h SocketBuffer.cc \
 	SocketBuffer.h OptionHandlerException.cc \
-	OptionHandlerException.h bencode.cc bencode.h TLSContext.h \
-	LibgnutlsTLSContext.cc LibgnutlsTLSContext.h \
-	LibsslTLSContext.cc LibsslTLSContext.h GZipDecoder.cc \
-	GZipDecoder.h Sqlite3MozCookieParser.cc \
+	OptionHandlerException.h bencode.cc bencode.h URIResult.cc \
+	URIResult.h TLSContext.h LibgnutlsTLSContext.cc \
+	LibgnutlsTLSContext.h LibsslTLSContext.cc LibsslTLSContext.h \
+	GZipDecoder.cc GZipDecoder.h Sqlite3MozCookieParser.cc \
 	Sqlite3MozCookieParser.h AsyncNameResolver.cc \
 	AsyncNameResolver.h IteratableChunkChecksumValidator.cc \
 	IteratableChunkChecksumValidator.h \
@@ -802,13 +802,14 @@ am__objects_21 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
 	InOrderURISelector.$(OBJEXT) ServerStatURISelector.$(OBJEXT) \
 	NsCookieParser.$(OBJEXT) CookieStorage.$(OBJEXT) \
 	SocketBuffer.$(OBJEXT) OptionHandlerException.$(OBJEXT) \
-	bencode.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
-	$(am__objects_3) $(am__objects_4) $(am__objects_5) \
-	$(am__objects_6) $(am__objects_7) $(am__objects_8) \
-	$(am__objects_9) $(am__objects_10) $(am__objects_11) \
-	$(am__objects_12) $(am__objects_13) $(am__objects_14) \
-	$(am__objects_15) $(am__objects_16) $(am__objects_17) \
-	$(am__objects_18) $(am__objects_19) $(am__objects_20)
+	bencode.$(OBJEXT) URIResult.$(OBJEXT) $(am__objects_1) \
+	$(am__objects_2) $(am__objects_3) $(am__objects_4) \
+	$(am__objects_5) $(am__objects_6) $(am__objects_7) \
+	$(am__objects_8) $(am__objects_9) $(am__objects_10) \
+	$(am__objects_11) $(am__objects_12) $(am__objects_13) \
+	$(am__objects_14) $(am__objects_15) $(am__objects_16) \
+	$(am__objects_17) $(am__objects_18) $(am__objects_19) \
+	$(am__objects_20)
 am_libaria2c_a_OBJECTS = $(am__objects_21)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -1133,14 +1134,14 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
 	ServerStatURISelector.h NsCookieParser.cc NsCookieParser.h \
 	CookieStorage.cc CookieStorage.h SocketBuffer.cc \
 	SocketBuffer.h OptionHandlerException.cc \
-	OptionHandlerException.h bencode.cc bencode.h $(am__append_1) \
-	$(am__append_2) $(am__append_3) $(am__append_4) \
-	$(am__append_5) $(am__append_6) $(am__append_7) \
-	$(am__append_8) $(am__append_9) $(am__append_10) \
-	$(am__append_11) $(am__append_12) $(am__append_13) \
-	$(am__append_14) $(am__append_15) $(am__append_16) \
-	$(am__append_17) $(am__append_18) $(am__append_19) \
-	$(am__append_20)
+	OptionHandlerException.h bencode.cc bencode.h URIResult.cc \
+	URIResult.h $(am__append_1) $(am__append_2) $(am__append_3) \
+	$(am__append_4) $(am__append_5) $(am__append_6) \
+	$(am__append_7) $(am__append_8) $(am__append_9) \
+	$(am__append_10) $(am__append_11) $(am__append_12) \
+	$(am__append_13) $(am__append_14) $(am__append_15) \
+	$(am__append_16) $(am__append_17) $(am__append_18) \
+	$(am__append_19) $(am__append_20)
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@@ -1499,6 +1500,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimedHaltCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransferStat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/URIResult.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/URLMetalinkParserState.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnknownLengthPieceStorage.Po@am__quote@

+ 9 - 5
src/MultiUrlRequestInfo.cc

@@ -99,9 +99,9 @@ void MultiUrlRequestInfo::printMessageForContinue()
 	      << "\n";
 }
 
-int MultiUrlRequestInfo::execute()
+DownloadResult::RESULT MultiUrlRequestInfo::execute()
 {
-  int returnValue = 1;
+  DownloadResult::RESULT returnValue = DownloadResult::FINISHED;
   try {
     DownloadEngineHandle e =
       DownloadEngineFactory().newDownloadEngine(_option, _requestGroups);
@@ -190,10 +190,14 @@ int MultiUrlRequestInfo::execute()
     _summaryOut << std::flush;
 
     RequestGroupMan::DownloadStat s = e->_requestGroupMan->getDownloadStat();
-    if(s.allCompleted()) {
-      returnValue = 0;
-    } else {
+    if(!s.allCompleted()) {
       printMessageForContinue();
+      if(s.getLastErrorResult() == DownloadResult::FINISHED &&
+	 s.getInProgress() > 0) {
+	returnValue = DownloadResult::IN_PROGRESS;
+      } else {
+	returnValue = s.getLastErrorResult();
+      }
     }
   } catch(RecoverableException& e) {
     _logger->error(EX_EXCEPTION_CAUGHT, e);

+ 7 - 3
src/MultiUrlRequestInfo.h

@@ -36,10 +36,13 @@
 #define _D_MULTI_URL_REQUEST_INFO_H_
 
 #include "common.h"
-#include "SharedHandle.h"
+
 #include <deque>
 #include <iosfwd>
 
+#include "SharedHandle.h"
+#include "DownloadResult.h"
+
 namespace aria2 {
 
 class RequestGroup;
@@ -71,9 +74,10 @@ public:
   virtual ~MultiUrlRequestInfo();
 
   /**
-   * Returns 0 if all downloads have completed, otherwise returns 1.
+   * Returns FINISHED if all downloads have completed, otherwise returns the
+   * last download result.
    */
-  int execute();
+  DownloadResult::RESULT execute();
 };
 
 typedef SharedHandle<MultiUrlRequestInfo> MultiUrlRequestInfoHandle;

+ 20 - 4
src/RecoverableException.h

@@ -35,10 +35,14 @@
 #ifndef _D_RECOVERABLE_EXCEPTION_H_
 #define _D_RECOVERABLE_EXCEPTION_H_
 #include "Exception.h"
+#include "DownloadResult.h"
 
 namespace aria2 {
 
 class RecoverableException:public Exception {
+private:
+  DownloadResult::RESULT _code;
+
 protected:
   virtual SharedHandle<Exception> copy() const
   {
@@ -46,10 +50,22 @@ protected:
     return e;
   }
 public:
-  RecoverableException(const std::string& msg):Exception(msg) {}
-  RecoverableException(const std::string& msg,
-		       const Exception& cause):Exception(msg, cause) {}
-  RecoverableException(const RecoverableException& e):Exception(e) {}
+  RecoverableException(const std::string& msg):
+    Exception(msg),
+    _code(DownloadResult::UNKNOWN_ERROR) {}
+
+  RecoverableException(const std::string& msg, const Exception& cause):
+    Exception(msg, cause),
+    _code(DownloadResult::UNKNOWN_ERROR) {}
+
+  RecoverableException(const RecoverableException& e):
+    Exception(e),
+    _code(DownloadResult::UNKNOWN_ERROR) {}
+  
+  RecoverableException(const std::string& msg, DownloadResult::RESULT result):
+    Exception(msg), _code(result) {}
+
+  DownloadResult::RESULT getCode() const { return _code; }
 };
 
 } // namespace aria2

+ 26 - 5
src/RequestGroup.cc

@@ -64,7 +64,6 @@
 #include "RequestGroupMan.h"
 #include "DefaultBtProgressInfoFile.h"
 #include "DefaultPieceStorage.h"
-#include "DownloadResult.h"
 #include "DownloadHandlerFactory.h"
 #include "MemoryBufferPreDownloadHandler.h"
 #include "DownloadHandlerConstants.h"
@@ -171,6 +170,19 @@ bool RequestGroup::allDownloadFinished() const
   }
 }
 
+DownloadResult::RESULT RequestGroup::downloadResult() const
+{
+  if (downloadFinished())
+    return DownloadResult::FINISHED;
+  else {
+    if (_uriResults.empty()) {
+      return DownloadResult::UNKNOWN_ERROR;
+    } else {
+      return _uriResults.back().getResult();
+    }
+  }    
+}
+
 void RequestGroup::closeFile()
 {
   if(!_pieceStorage.isNull()) {
@@ -902,9 +914,7 @@ DownloadResultHandle RequestGroup::createDownloadResult() const
 			uris.size(),
 			sessionDownloadLength,
 			_downloadContext->calculateSessionTime(),
-			downloadFinished()?
-			DownloadResult::FINISHED :
-			DownloadResult::NOT_YET));
+			downloadResult()));
 }
 
 void RequestGroup::registerServerHost(const ServerHostHandle& serverHost)
@@ -1073,7 +1083,8 @@ void RequestGroup::increaseAndValidateFileNotFoundCount()
   if(maxCount > 0 && _fileNotFoundCount >= maxCount &&
      _segmentMan->calculateSessionDownloadLength() == 0) {
     throw DownloadFailureException
-      (StringFormat("Reached max-file-not-found count=%u", maxCount).str());
+      (StringFormat("Reached max-file-not-found count=%u", maxCount).str(),
+       DownloadResult::MAX_FILE_NOT_FOUND);
   }
 }
 
@@ -1097,4 +1108,14 @@ void RequestGroup::tuneDownloadCommand(DownloadCommand* command)
   _uriSelector->tuneDownloadCommand(_uris, command);
 }
 
+void RequestGroup::addURIResult(std::string uri, DownloadResult::RESULT result)
+{
+  _uriResults.push_back(URIResult(uri, result));
+}
+
+const std::deque<URIResult>& RequestGroup::getURIResults() const
+{
+  return _uriResults;
+}
+
 } // namespace aria2

+ 16 - 0
src/RequestGroup.h

@@ -44,6 +44,8 @@
 #include "TransferStat.h"
 #include "TimeA2.h"
 #include "Request.h"
+#include "DownloadResult.h"
+#include "URIResult.h"
 
 namespace aria2 {
 
@@ -112,6 +114,10 @@ private:
 
   bool _forceHaltRequested;
 
+  // URIResult is stored in the ascending order of the time when its result is
+  // available.
+  std::deque<URIResult> _uriResults;
+
   bool _singleHostMultiConnectionEnabled;
 
   std::deque<SharedHandle<PreDownloadHandler> > _preDownloadHandlers;
@@ -154,6 +160,12 @@ private:
 
   bool tryAutoFileRenaming();
 
+  // Returns the result code of this RequestGroup.
+  // If the download finished, then returns DownloadResult::FINISHED.
+  // If the download didn't finish and error result is available in _uriResults,
+  // then last result code is returned.
+  // Otherwise returns DownloadResult::UNKNOWN_ERROR.
+  DownloadResult::RESULT downloadResult() const;
 public:
   RequestGroup(const Option* option, const std::deque<std::string>& uris);
 
@@ -311,6 +323,10 @@ public:
     return _forceHaltRequested;
   }
 
+  void addURIResult(std::string uri, DownloadResult::RESULT result);
+
+  const std::deque<URIResult>& getURIResults() const;
+
   void dependsOn(const SharedHandle<Dependency>& dep);
 
   bool isDependencyResolved();

+ 4 - 6
src/RequestGroupMan.cc

@@ -377,16 +377,17 @@ void RequestGroupMan::closeFile()
 
 RequestGroupMan::DownloadStat RequestGroupMan::getDownloadStat() const
 {
-  DownloadStat stat;
   size_t finished = 0;
   size_t error = 0;
   size_t inprogress = 0;
+  DownloadResult::RESULT lastError = DownloadResult::FINISHED;
   for(std::deque<SharedHandle<DownloadResult> >::const_iterator itr = _downloadResults.begin();
       itr != _downloadResults.end(); ++itr) {
     if((*itr)->result == DownloadResult::FINISHED) {
       ++finished;
     } else {
       ++error;
+      lastError = (*itr)->result;
     }
   }
   for(RequestGroups::const_iterator itr = _requestGroups.begin();
@@ -398,11 +399,8 @@ RequestGroupMan::DownloadStat RequestGroupMan::getDownloadStat() const
       ++inprogress;
     }
   }
-  stat.setCompleted(finished);
-  stat.setError(error);
-  stat.setInProgress(inprogress);
-  stat.setWaiting(_reservedGroups.size());
-  return stat;
+  return DownloadStat(finished, error, inprogress, _reservedGroups.size(),
+		      lastError);
 }
 
 void RequestGroupMan::showDownloadResults(std::ostream& o) const

+ 27 - 8
src/RequestGroupMan.h

@@ -36,12 +36,15 @@
 #define _D_REQUEST_GROUP_MAN_H_
 
 #include "common.h"
-#include "SharedHandle.h"
-#include "TransferStat.h"
+
 #include <string>
 #include <deque>
 #include <iosfwd>
 
+#include "SharedHandle.h"
+#include "DownloadResult.h"
+#include "TransferStat.h"
+
 namespace aria2 {
 
 class DownloadEngine;
@@ -117,18 +120,34 @@ public:
     size_t _error;
     size_t _inProgress;
     size_t _waiting;
+    DownloadResult::RESULT _lastErrorResult;
   public:
-    DownloadStat():_completed(0), _error(0), _inProgress(0), _waiting(0) {}
-
-    void setCompleted(size_t c) { _completed = c; }
-    void setError(size_t c) { _error = c; }
-    void setInProgress(size_t c) { _inProgress = c; }
-    void setWaiting(size_t c) { _waiting = c; }
+    DownloadStat(size_t completed,
+		 size_t error,
+		 size_t inProgress,
+		 size_t waiting,
+		 DownloadResult::RESULT lastErrorResult =
+		 DownloadResult::FINISHED):
+      _completed(completed),
+      _error(error),
+      _inProgress(inProgress),
+      _waiting(waiting),
+      _lastErrorResult(lastErrorResult) {}
+
+    DownloadResult::RESULT getLastErrorResult() const
+    {
+      return _lastErrorResult;
+    }
 
     bool allCompleted() const
     {
       return _error == 0 && _inProgress == 0 && _waiting == 0;
     }
+
+    size_t getInProgress() const
+    {
+      return _inProgress;
+    }
   };
 
   DownloadStat getDownloadStat() const;

+ 52 - 0
src/URIResult.cc

@@ -0,0 +1,52 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#include "URIResult.h"
+
+namespace aria2 {
+
+URIResult::URIResult(const std::string& uri, DownloadResult::RESULT result):
+  _uri(uri), _result(result) {}
+
+const std::string& URIResult::getURI() const
+{
+  return _uri;
+}
+
+DownloadResult::RESULT URIResult::getResult() const
+{
+  return _result;
+}
+
+} // namespace aria2

+ 62 - 0
src/URIResult.h

@@ -0,0 +1,62 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_URI_RESULT_H_
+#define _D_URI_RESULT_H_
+
+#include "common.h"
+
+#include <string>
+
+#include "DownloadResult.h"
+
+namespace aria2 {
+
+// This class stores URI and its result code as a consequence of the download.
+class URIResult {
+private:
+  std::string _uri;
+
+  DownloadResult::RESULT _result;
+public:
+  URIResult(const std::string& uri, DownloadResult::RESULT result);
+
+  const std::string& getURI() const;
+
+  DownloadResult::RESULT getResult() const;
+};
+
+} // namespace aria2
+
+#endif // _D_URI_RESULT_H_

+ 8 - 12
src/main.cc

@@ -157,7 +157,7 @@ static void showFiles(const std::deque<std::string>& uris, const Option* op)
 
 extern Option* option_processing(int argc, char* const argv[]);
 
-int main(int argc, char* argv[])
+DownloadResult::RESULT main(int argc, char* argv[])
 {
   Option* op = option_processing(argc, argv);
   std::deque<std::string> args(argv+optind, argv+argc);
@@ -175,7 +175,7 @@ int main(int argc, char* argv[])
   if(op->getAsBool(PREF_QUIET)) {
     LogFactory::setConsoleOutput(false);
   }
-  int32_t exitStatus = EXIT_SUCCESS;
+  DownloadResult::RESULT exitStatus = DownloadResult::FINISHED;
   try {
     Logger* logger = LogFactory::getInstance();
     logger->info("<<--- --- --- ---");
@@ -191,13 +191,12 @@ int main(int argc, char* argv[])
 #ifdef SIGPIPE
     Util::setGlobalSignalHandler(SIGPIPE, SIG_IGN, 0);
 #endif
-    int32_t returnValue = 0;
     std::deque<SharedHandle<RequestGroup> > requestGroups;
 #ifdef ENABLE_BITTORRENT
     if(!op->blank(PREF_TORRENT_FILE)) {
       if(op->get(PREF_SHOW_FILES) == V_TRUE) {
 	showTorrentFile(op->get(PREF_TORRENT_FILE));
-	return EXIT_SUCCESS;
+	return exitStatus;
       } else {
 	createRequestGroupForBitTorrent(requestGroups, op, args);
       }
@@ -208,7 +207,7 @@ int main(int argc, char* argv[])
       if(!op->blank(PREF_METALINK_FILE)) {
 	if(op->get(PREF_SHOW_FILES) == V_TRUE) {
 	  showMetalinkFile(op->get(PREF_METALINK_FILE), op);
-	  return EXIT_SUCCESS;
+	  return exitStatus;
 	} else {
 	  createRequestGroupForMetalink(requestGroups, op);
 	}
@@ -228,15 +227,12 @@ int main(int argc, char* argv[])
     if(requestGroups.empty()) {
       std::cout << MSG_NO_FILES_TO_DOWNLOAD << std::endl;
     } else {
-      returnValue = MultiUrlRequestInfo(requestGroups, op, getStatCalc(op),
-					getSummaryOut(op)).execute();
-    }
-    if(returnValue == 1) {
-      exitStatus = EXIT_FAILURE;
+      exitStatus = MultiUrlRequestInfo(requestGroups, op, getStatCalc(op),
+				       getSummaryOut(op)).execute();
     }
   } catch(Exception& ex) {
     std::cerr << EX_EXCEPTION_CAUGHT << "\n" << ex.stackTrace() << std::endl;
-    exitStatus = EXIT_FAILURE;
+    exitStatus = DownloadResult::UNKNOWN_ERROR;
   }
   delete op;
   LogFactory::release();
@@ -248,7 +244,7 @@ int main(int argc, char* argv[])
 int main(int argc, char* argv[]) {
   aria2::Platform platform;
 
-  int r = aria2::main(argc, argv);
+  aria2::DownloadResult::RESULT r = aria2::main(argc, argv);
 
   return r;
 }

+ 16 - 15
src/option_processing.cc

@@ -53,6 +53,7 @@
 #include "File.h"
 #include "StringFormat.h"
 #include "OptionHandlerException.h"
+#include "DownloadResult.h"
 
 extern char* optarg;
 extern int optind, opterr, optopt;
@@ -107,7 +108,7 @@ Option* option_processing(int argc, char* const argv[])
     oparser.parseDefaultValues(op);
   } catch(Exception& e) {
     std::cerr << e.stackTrace();
-    exit(EXIT_FAILURE);
+    exit(DownloadResult::UNKNOWN_ERROR);
   }
 
   while(1) {
@@ -254,12 +255,12 @@ Option* option_processing(int argc, char* const argv[])
 	std::cout << "--http-proxy-user was deprecated. See --http-proxy,"
 		  << " --https-proxy, --ftp-proxy, --all-proxy options."
 		  << std::endl;
-	exit(EXIT_FAILURE);
+	exit(DownloadResult::UNKNOWN_ERROR);
       case 5: 
 	std::cout << "--http-proxy-passwd was deprecated. See --http-proxy,"
 		  << " --https-proxy, --ftp-proxy, --all-proxy options."
 		  << std::endl;
-	exit(EXIT_FAILURE);
+	exit(DownloadResult::UNKNOWN_ERROR);
       case 6:
 	cmdstream << PREF_HTTP_AUTH_SCHEME << "=" << optarg << "\n";
 	break;
@@ -282,12 +283,12 @@ Option* option_processing(int argc, char* const argv[])
 	std::cout << "--ftp-via-http-proxy was deprecated."
 		  << " Use --http-proxy-method option instead."
 		  << std::endl;
-	exit(EXIT_FAILURE);
+	exit(DownloadResult::UNKNOWN_ERROR);
       case 14:
 	std::cout << "--http-proxy-method was deprecated."
 		  << " Use --proxy-method option instead."
 		  << std::endl;
-	exit(EXIT_FAILURE);
+	exit(DownloadResult::UNKNOWN_ERROR);
       case 15:
 	cmdstream << PREF_LISTEN_PORT << "=" << optarg << "\n";
 	break;
@@ -553,7 +554,7 @@ Option* option_processing(int argc, char* const argv[])
       break;
     case 'v':
       showVersion();
-      exit(EXIT_SUCCESS);
+      exit(DownloadResult::FINISHED);
     case 'h':
       {
 	std::string category;
@@ -563,11 +564,11 @@ Option* option_processing(int argc, char* const argv[])
 	  category = optarg;
 	}
 	showUsage(category, oparser);
-	exit(EXIT_SUCCESS);
+	exit(DownloadResult::FINISHED);
       }
     default:
       showUsage(TAG_HELP, oparser);
-      exit(EXIT_FAILURE);
+      exit(DownloadResult::UNKNOWN_ERROR);
     }
   }
 
@@ -588,18 +589,18 @@ Option* option_processing(int argc, char* const argv[])
 		    << "Usage:" << "\n"
 		    << oparser.findByName(e.getOptionName())->getDescription()
 		    << std::endl;
-	  exit(EXIT_FAILURE);
+	  exit(DownloadResult::UNKNOWN_ERROR);
 	} catch(Exception& e) {
 	  std::cerr << "Parse error in " << cfname << "\n"
 		    << e.stackTrace() << std::endl;
-	  exit(EXIT_FAILURE);
+	  exit(DownloadResult::UNKNOWN_ERROR);
 	}
       } else if(!ucfname.empty()) {
 	std::cerr << StringFormat("Configuration file %s is not found.",
 				  cfname.c_str())
 		  << "\n";
 	showUsage(TAG_HELP, oparser);
-	exit(EXIT_FAILURE);
+	exit(DownloadResult::UNKNOWN_ERROR);
       }
     }
     // Override configuration with environment variables.
@@ -616,11 +617,11 @@ Option* option_processing(int argc, char* const argv[])
 		<< "Usage:" << "\n"
 		<< oparser.findByName(e.getOptionName())->getDescription()
 		<< std::endl;
-      exit(EXIT_FAILURE);
+      exit(DownloadResult::UNKNOWN_ERROR);
     } catch(Exception& e) {
       std::cerr << e.stackTrace() << std::endl;
       showUsage(TAG_HELP, oparser);
-      exit(EXIT_FAILURE);
+      exit(DownloadResult::UNKNOWN_ERROR);
     }
   }
   if(
@@ -634,14 +635,14 @@ Option* option_processing(int argc, char* const argv[])
     if(optind == argc) {
       std::cerr << MSG_URI_REQUIRED << std::endl;
       showUsage(TAG_HELP, oparser);
-      exit(EXIT_FAILURE);
+      exit(DownloadResult::UNKNOWN_ERROR);
     }
   }
 #ifdef HAVE_DAEMON
   if(op->getAsBool(PREF_DAEMON)) {
     if(daemon(1, 1) < 0) {
       perror(MSG_DAEMON_FAILED);
-      exit(EXIT_FAILURE);
+      exit(DownloadResult::UNKNOWN_ERROR);
     }
   }
 #endif // HAVE_DAEMON

+ 46 - 0
test/RequestGroupTest.cc

@@ -6,6 +6,7 @@
 #include "Option.h"
 #include "SingleFileDownloadContext.h"
 #include "FileEntry.h"
+#include "PieceStorage.h"
 
 namespace aria2 {
 
@@ -15,6 +16,7 @@ class RequestGroupTest : public CppUnit::TestFixture {
   CPPUNIT_TEST(testRegisterSearchRemove);
   CPPUNIT_TEST(testRemoveURIWhoseHostnameIs);
   CPPUNIT_TEST(testGetFilePath);
+  CPPUNIT_TEST(testCreateDownloadResult);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -24,6 +26,7 @@ public:
   void testRegisterSearchRemove();
   void testRemoveURIWhoseHostnameIs();
   void testGetFilePath();
+  void testCreateDownloadResult();
 };
 
 
@@ -93,4 +96,47 @@ void RequestGroupTest::testGetFilePath()
   CPPUNIT_ASSERT_EQUAL(std::string("[MEMORY]myfile"), group.getFilePath());
 }
 
+void RequestGroupTest::testCreateDownloadResult()
+{
+  SharedHandle<SingleFileDownloadContext> ctx
+    (new SingleFileDownloadContext(1024, 1024*1024, "myfile"));
+  ctx->setDir("/tmp");
+  Option op;
+  std::deque<std::string> uris;
+  uris.push_back("http://first/file");
+  uris.push_back("http://second/file");
+
+  RequestGroup group(&op, uris);
+  group.setDownloadContext(ctx);
+  group.initPieceStorage();
+  {
+    SharedHandle<DownloadResult> result = group.createDownloadResult();
+  
+    CPPUNIT_ASSERT_EQUAL(std::string("/tmp/myfile"), result->filePath);
+    CPPUNIT_ASSERT_EQUAL((uint64_t)1024*1024, result->totalLength);
+    CPPUNIT_ASSERT_EQUAL(std::string("http://first/file"), result->uri);
+    CPPUNIT_ASSERT_EQUAL((size_t)2, result->numUri);
+    CPPUNIT_ASSERT_EQUAL((uint64_t)0, result->sessionDownloadLength);
+    CPPUNIT_ASSERT_EQUAL((time_t)0, result->sessionTime);
+    // result is UNKNOWN_ERROR if download has not completed and no specific
+    // error has been reported
+    CPPUNIT_ASSERT_EQUAL(DownloadResult::UNKNOWN_ERROR, result->result);
+  }
+  {
+    group.addURIResult("http://first/file", DownloadResult::TIME_OUT);
+    group.addURIResult("http://second/file",DownloadResult::RESOURCE_NOT_FOUND);
+  
+    SharedHandle<DownloadResult> result = group.createDownloadResult();
+
+    CPPUNIT_ASSERT_EQUAL(DownloadResult::RESOURCE_NOT_FOUND, result->result);
+  }
+  {
+    group.getPieceStorage()->markAllPiecesDone();
+
+    SharedHandle<DownloadResult> result = group.createDownloadResult();
+
+    CPPUNIT_ASSERT_EQUAL(DownloadResult::FINISHED, result->result);
+  }
+}
+
 } // namespace aria2