diff --git a/ChangeLog b/ChangeLog index bd256344..b7af66e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,100 @@ +2006-08-27 Tatsuhiro Tsujikawa + + To add --seed-time and --seed-ratio command-line option: + * src/Option.h (getAsDouble): New function. + * src/Option.cc (getAsDouble): New function. + * src/SeedCheckCommand.h: New class. + * src/SeedCheckCommand.cc: New class. + * src/DownloadEngineFactory.cc + (SeedCheckCommand.h): Included. + (UnionSeedCriteria.h): Included. + (TimeSeedCriteria.h): Included. + (ShareRatioSeedCriteria.h): Included. + (newTorrentConsoleEngine): Added the processing of seed option. + * src/SeedCriteria.h: New class. + * src/ShareRatioSeedCriteria.h: New class. + * src/TimeSeedCriteria.h: New class. + * src/UnionSeedCriteria.h: New class. + * src/prefs.h + (PREF_SEED_TIME): New definition. + (PREF_SEED_RATIO): New definition. + * src/main.cc + (showUsage): Added --seed-time and --seed-ratio option. + (main): Added --seed-time and --seed-ratio option. + Made default log file name "/dev/null". + * src/SharedHandle.h + (SharedHandle): Copy constructor. Made it assignable from the + SharedHandle of the subclasses. + (operator=): Made it assignable from the SharedHandle of the + subclasses. + (getRefCount): New function. + + To add notice log level and the switch to write log to stdout. This + switch is configurable per log level. + * src/Logger.h + (notice): New function. + (LEVEL): Added NOTICE. Assigned an explicit value to each log level + constant. + * src/LogFactory.cc + (getInstance): The use of NullLogger was removed. A log message with + notice log level was made written to stdout along with log file. + * src/NullLogger.h + (notice): New function. + * src/SimpleLogger.h + (writeHeader): Added the 'file' argument. + (writeLog): Added the 'file' argument. + (writeFile): New function. + (stdoutField): New variable. + (SimpleLogger): Removed the default constructor. + (SimpleLogger): Made the default value of logfile 0. + (debug): Added 'virtual' keyword. + (info): Added 'virtual' keyword. + (warn): Added 'virtual' keyword. + (error): Added 'virtual' keyword. + (notice): New function. + (setStdout): New function. + * src/SimpleLogger.cc + (WRITE_LOG): Replaced writeLog with writeFile. + (WRITE_LOG_EX): Replaced writeLog with writeFile. + (SimpleLogger): Removed the default constructor. + (setStdout): New function. + (writeLog): Added the handling of NOTICE log level. + (writeFile): New function. + (notice): New function. + + * src/TorrentMan.h: Updated doc. + + * src/BitfieldMan.h: Updated doc. + + * src/TrackerWatcherCommand.cc + (execute): Return true if error occurred in the request to the tracker + and halt is requested. + + * src/TrackerUpdateCommand.cc + (execute): Return true if error occurred in the request to the tracker + and halt is requested. + + * src/TorrentConsoleDownloadEngine.h + (onSelectiveDownloadingCompletes): Removed. + * src/TorrentConsoleDownloadEngine.cc + (onSelectiveDownloadingCompletes): Removed. + * src/TorrentDownloadEngine.h + (onEndOfRun): Added 'virtual' keyword. + (afterEachIteration): Removed. + (onSelectiveDownloadingCompletes): Removed. + * src/TorrentDownloadEngine.cc + (onEndOfRun): Removed filenameFixed. + (afterEachIteration): Removed. + * src/TorrentMan.cc + (completePiece): Call onDownloadComplete here. + (onDownloadComplete): Added 2 log messages. + 2006-08-21 Tatsuhiro Tsujikawa To fix compilation problem on gcc4.1.1(patch#1542283 by tizianomueller) * src/NameResolver.h: Added the prototype declaration of callback(). To support c-ares library: - * src/AbstractCommand.cc: Replaced HAVE_LIBARES with ENABLE_ASYNC_DNS * src/FeatureConfig.cc: Replaced HAVE_LIBARES with ENABLE_ASYNC_DNS * src/FtpInitiateConnectionCommand.h: @@ -26,7 +116,6 @@ To fix the bug that causes compilation failure with metalink-support disabled(bug#1543587): - * src/main.cc: Fixed with the patch by tizianomueller. * Release 0.7.2 diff --git a/TODO b/TODO index 4ecbf3d1..72ce760d 100644 --- a/TODO +++ b/TODO @@ -13,4 +13,7 @@ * List available os, version, etc for metalink * ipv6(RFC2428 for ftp) * Add some criteria to stop seeding. -* Add silent mode. \ No newline at end of file +* Add silent mode. +* Add NOTIFY log level. A message categorized in this level is printed in + a console along with a log file. +* Do onDownloadComplete in TorrentMan::completePiece(). \ No newline at end of file diff --git a/src/BitfieldMan.h b/src/BitfieldMan.h index 4723c13a..369c3fd8 100644 --- a/src/BitfieldMan.h +++ b/src/BitfieldMan.h @@ -156,6 +156,9 @@ public: void setAllBit(); void addFilter(long long int offset, long long int length); + /** + * Clears filter and disables filter + */ void clearFilter(); void enableFilter(); diff --git a/src/DownloadEngineFactory.cc b/src/DownloadEngineFactory.cc index 52da662c..6c094592 100644 --- a/src/DownloadEngineFactory.cc +++ b/src/DownloadEngineFactory.cc @@ -31,8 +31,12 @@ # include "TrackerWatcherCommand.h" # include "TrackerUpdateCommand.h" # include "TorrentAutoSaveCommand.h" +# include "SeedCheckCommand.h" # include "PeerChokeCommand.h" # include "HaveEraseCommand.h" +# include "UnionSeedCriteria.h" +# include "TimeSeedCriteria.h" +# include "ShareRatioSeedCriteria.h" #endif // ENABLE_BITTORRENT ConsoleDownloadEngine* @@ -117,7 +121,19 @@ DownloadEngineFactory::newTorrentConsoleEngine(const Option* op, te, 10)); te->commands.push_back(new HaveEraseCommand(te->torrentMan->getNewCuid(), te, 10)); - + + SharedHandle unionCri = new UnionSeedCriteria(); + if(op->defined(PREF_SEED_TIME)) { + unionCri->addSeedCriteria(new TimeSeedCriteria(op->getAsInt(PREF_SEED_TIME)*60)); + } + if(op->defined(PREF_SEED_RATIO)) { + unionCri->addSeedCriteria(new ShareRatioSeedCriteria(op->getAsDouble(PREF_SEED_RATIO), te->torrentMan)); + } + if(unionCri->getSeedCriterion().size() > 0) { + te->commands.push_back(new SeedCheckCommand(te->torrentMan->getNewCuid(), + te, + unionCri)); + } return te; } #endif // ENABLE_BITTORRENT diff --git a/src/LogFactory.cc b/src/LogFactory.cc index 8bb5780f..c11009e1 100644 --- a/src/LogFactory.cc +++ b/src/LogFactory.cc @@ -21,20 +21,16 @@ /* copyright --> */ #include "LogFactory.h" #include "SimpleLogger.h" -#include "NullLogger.h" string LogFactory::filename; Logger* LogFactory::logger = NULL; Logger* LogFactory::getInstance() { if(logger == NULL) { - if(filename.empty()) { - logger = new NullLogger(); - } else { - SimpleLogger* slogger = new SimpleLogger(); - slogger->openFile(filename); - logger = slogger; - } + SimpleLogger* slogger = new SimpleLogger(); + slogger->openFile(filename); + slogger->setStdout(Logger::NOTICE, true); + logger = slogger; } return logger; } diff --git a/src/Logger.h b/src/Logger.h index ae533288..11412bca 100644 --- a/src/Logger.h +++ b/src/Logger.h @@ -35,16 +35,19 @@ public: virtual void debug(const char* msg, Exception* ex, ...) const = 0; virtual void info(const char* msg, ...) const = 0; virtual void info(const char* msg, Exception* ex, ...) const = 0; + virtual void notice(const char* msg, ...) const = 0; + virtual void notice(const char* msg, Exception* ex, ...) const = 0; virtual void warn(const char* msg, ...) const = 0; virtual void warn(const char* msg, Exception* ex, ...) const = 0; virtual void error(const char* msg, ...) const = 0; virtual void error(const char* msg, Exception* ex, ...) const = 0; enum LEVEL { - DEBUG, - INFO, - WARN, - ERROR + DEBUG = 1 << 0, + INFO = 1 << 1, + NOTICE = 1 << 2, + WARN = 1 << 3, + ERROR = 1 << 4, }; }; diff --git a/src/Makefile.am b/src/Makefile.am index 779fba0b..3ed2ba80 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -116,7 +116,12 @@ SRCS += MetaEntry.h\ SimplePeerMessage.cc SimplePeerMessage.h\ PeerMessageFactory.cc PeerMessageFactory.h\ HaveEraseCommand.cc HaveEraseCommand.h\ - TorrentRequestInfo.cc TorrentRequestInfo.h + TorrentRequestInfo.cc TorrentRequestInfo.h\ + SeedCriteria.h\ + TimeSeedCriteria.h\ + ShareRatioSeedCriteria.h\ + UnionSeedCriteria.h\ + SeedCheckCommand.cc SeedCheckCommand.h endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/src/Makefile.in b/src/Makefile.in index ac77a8e1..e1df1f2e 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -93,7 +93,12 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ SimplePeerMessage.cc SimplePeerMessage.h\ @ENABLE_BITTORRENT_TRUE@ PeerMessageFactory.cc PeerMessageFactory.h\ @ENABLE_BITTORRENT_TRUE@ HaveEraseCommand.cc HaveEraseCommand.h\ -@ENABLE_BITTORRENT_TRUE@ TorrentRequestInfo.cc TorrentRequestInfo.h +@ENABLE_BITTORRENT_TRUE@ TorrentRequestInfo.cc TorrentRequestInfo.h\ +@ENABLE_BITTORRENT_TRUE@ SeedCriteria.h\ +@ENABLE_BITTORRENT_TRUE@ TimeSeedCriteria.h\ +@ENABLE_BITTORRENT_TRUE@ ShareRatioSeedCriteria.h\ +@ENABLE_BITTORRENT_TRUE@ UnionSeedCriteria.h\ +@ENABLE_BITTORRENT_TRUE@ SeedCheckCommand.cc SeedCheckCommand.h @ENABLE_METALINK_TRUE@am__append_3 = Metalinker.cc Metalinker.h\ @ENABLE_METALINK_TRUE@ MetalinkEntry.cc MetalinkEntry.h\ @@ -197,8 +202,10 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ SuggestPieceMessage.cc SuggestPieceMessage.h \ SimplePeerMessage.cc SimplePeerMessage.h PeerMessageFactory.cc \ PeerMessageFactory.h HaveEraseCommand.cc HaveEraseCommand.h \ - TorrentRequestInfo.cc TorrentRequestInfo.h Metalinker.cc \ - Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ + TorrentRequestInfo.cc TorrentRequestInfo.h SeedCriteria.h \ + TimeSeedCriteria.h ShareRatioSeedCriteria.h \ + UnionSeedCriteria.h SeedCheckCommand.cc SeedCheckCommand.h \ + Metalinker.cc Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \ Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h \ MetalinkRequestInfo.cc MetalinkRequestInfo.h @@ -251,7 +258,8 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ SimplePeerMessage.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerMessageFactory.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ HaveEraseCommand.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TorrentRequestInfo.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ TorrentRequestInfo.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ SeedCheckCommand.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntry.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkResource.$(OBJEXT) \ @@ -646,6 +654,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Request.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestSlot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SeedCheckCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentSplitter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitor.Po@am__quote@ diff --git a/src/NullLogger.h b/src/NullLogger.h index e5cd69b4..657b10b1 100644 --- a/src/NullLogger.h +++ b/src/NullLogger.h @@ -34,6 +34,8 @@ public: virtual void debug(const char* msg, Exception* ex, ...) const {} virtual void info(const char* msg, ...) const {} virtual void info(const char* msg, Exception* ex, ...) const {} + virtual void notice(const char* msg, ...) const {} + virtual void notice(const char* msg, Exception* ex, ...) const {} virtual void warn(const char* msg, ...) const {} virtual void warn(const char* msg, Exception* ex, ...) const {} virtual void error(const char* msg, ...) const {} diff --git a/src/Option.cc b/src/Option.cc index 20555f7e..1b319dee 100644 --- a/src/Option.cc +++ b/src/Option.cc @@ -69,3 +69,12 @@ bool Option::getAsBool(const string& name) const { return false; } } + +double Option::getAsDouble(const string& name) const { + string value = get(name); + if(value == "") { + return 0.0; + } else { + return strtod(value.c_str(), 0); + } +} diff --git a/src/Option.h b/src/Option.h index a0fa8f40..5b1ffbc5 100644 --- a/src/Option.h +++ b/src/Option.h @@ -41,6 +41,7 @@ public: int getAsInt(const string& name) const; long long int getAsLLInt(const string& name) const; bool getAsBool(const string& name) const; + double getAsDouble(const string& name) const; }; #endif // _D_OPTION_H_ diff --git a/src/SeedCheckCommand.cc b/src/SeedCheckCommand.cc new file mode 100644 index 00000000..6f94a979 --- /dev/null +++ b/src/SeedCheckCommand.cc @@ -0,0 +1,47 @@ +/* */ +#include "SeedCheckCommand.h" + +bool SeedCheckCommand::execute() { + if(e->torrentMan->isHalt()) { + return true; + } + if(!seedCriteria.get()) { + return false; + } + if(checkPoint.elapsed(1)) { + if(!checkStarted) { + if(e->torrentMan->downloadComplete()) { + checkStarted = true; + seedCriteria->reset(); + } + } + if(checkStarted) { + if(seedCriteria->evaluate()) { + logger->notice("CUID#%d - Seeding is over.", cuid); + e->torrentMan->setHalt(true); + } + } + } + e->commands.push_back(this); + return false; +} diff --git a/src/SeedCheckCommand.h b/src/SeedCheckCommand.h new file mode 100644 index 00000000..3811e49b --- /dev/null +++ b/src/SeedCheckCommand.h @@ -0,0 +1,53 @@ +/* */ +#ifndef _D_SEED_CHECK_COMMAND_H_ +#define _D_SEED_CHECK_COMMAND_H_ + +#include "Command.h" +#include "TorrentDownloadEngine.h" +#include "TimeA2.h" +#include "SeedCriteria.h" + +class SeedCheckCommand : public Command { +private: + TorrentDownloadEngine* e; + Time checkPoint; + SeedCriteriaHandle seedCriteria; + bool checkStarted; +public: + SeedCheckCommand(int cuid, TorrentDownloadEngine* e, + SeedCriteriaHandle seedCriteria) + :Command(cuid), + e(e), + seedCriteria(seedCriteria), + checkStarted(false) {} + + virtual ~SeedCheckCommand() {} + + virtual bool execute(); + + void setSeedCriteria(SeedCriteriaHandle seedCriteria) { + this->seedCriteria = seedCriteria; + } +}; + +#endif // _D_SEED_CHECK_COMMAND_H_ diff --git a/src/SeedCriteria.h b/src/SeedCriteria.h new file mode 100644 index 00000000..fe681c66 --- /dev/null +++ b/src/SeedCriteria.h @@ -0,0 +1,47 @@ +/* */ +#ifndef _D_SEED_CRITERIA_H_ +#define _D_SEED_CRITERIA_H_ + +#include "common.h" +#include "SharedHandle.h" + +class SeedCriteria { +public: + virtual ~SeedCriteria() {} + + /** + * Returns true if criteria is met. + */ + virtual bool evaluate() = 0; + + /** + * Used for reseting status. + */ + virtual void reset() = 0; +}; + +typedef SharedHandle SeedCriteriaHandle; + +typedef deque SeedCriterion; + +#endif // _D_SEED_CRITERIA_H_ diff --git a/src/ShareRatioSeedCriteria.h b/src/ShareRatioSeedCriteria.h new file mode 100644 index 00000000..364c637d --- /dev/null +++ b/src/ShareRatioSeedCriteria.h @@ -0,0 +1,57 @@ +/* */ +#ifndef _D_SHARE_RATIO_SEED_CRITERIA_H_ +#define _D_SHARE_RATIO_SEED_CRITERIA_H_ + +#include "SeedCriteria.h" +#include "TorrentMan.h" + +class ShareRatioSeedCriteria : public SeedCriteria { +private: + double ratio; + TorrentMan* torrentMan; +public: + ShareRatioSeedCriteria(double ratio, TorrentMan* torrentMan) + :ratio(ratio), + torrentMan(torrentMan) {} + virtual ~ShareRatioSeedCriteria() {} + + virtual void reset() {} + + virtual bool evaluate() { + if(torrentMan->getDownloadLength() == 0) { + return false; + } + return ratio <= + ((double)torrentMan->getUploadLength())/torrentMan->getDownloadLength(); + } + + void setRatio(double ratio) { + this->ratio = ratio; + } + + double getRatio() const { + return ratio; + } +}; + +#endif // _D_SHARE_RATIO_SEED_CRITERIA_H_ diff --git a/src/SharedHandle.h b/src/SharedHandle.h index 5219765f..69da6f8a 100644 --- a/src/SharedHandle.h +++ b/src/SharedHandle.h @@ -47,7 +47,9 @@ private: public: SharedHandle():obj(new T()), ucount(new int(1)) {} SharedHandle(T* obj):obj(obj), ucount(new int(1)) {} - SharedHandle(const SharedHandle& t):obj(t.obj), ucount(t.ucount) { + + template + SharedHandle(const SharedHandle& t):obj(t.get()), ucount(t.getRefCount()) { ++*ucount; } @@ -58,14 +60,15 @@ public: } } - SharedHandle& operator=(const SharedHandle& t) { - ++*t.ucount; + template + SharedHandle& operator=(const SharedHandle& t) { + ++*t.getRefCount(); if(--*ucount == 0) { delete obj; delete ucount; } - obj = t.obj; - ucount = t.ucount; + obj = t.get(); + ucount = t.getRefCount(); return *this; } @@ -76,6 +79,10 @@ public: T* get() const { return obj; } + + int* getRefCount() const { + return ucount; + } }; template diff --git a/src/SimpleLogger.cc b/src/SimpleLogger.cc index 3f49cb05..451613df 100644 --- a/src/SimpleLogger.cc +++ b/src/SimpleLogger.cc @@ -31,20 +31,16 @@ #define WRITE_LOG(LEVEL, MSG) \ va_list ap;\ va_start(ap, MSG);\ -writeLog(Logger::LEVEL, MSG, ap);\ +writeFile(Logger::LEVEL, MSG, ap);\ va_end(ap); #define WRITE_LOG_EX(LEVEL, MSG, EX) \ va_list ap;\ va_start(ap, EX);\ -writeLog(Logger::LEVEL, MSG, ap, EX);\ +writeFile(Logger::LEVEL, MSG, ap, EX);\ va_end(ap); -SimpleLogger::SimpleLogger():file(NULL) {} - -SimpleLogger::SimpleLogger(FILE* logfile) { - file = logfile; -} +SimpleLogger::SimpleLogger(FILE* logfile):file(logfile), stdoutField(0) {} SimpleLogger::~SimpleLogger() { closeFile(); @@ -63,17 +59,28 @@ void SimpleLogger::closeFile() { } } -void SimpleLogger::writeHeader(string date, string level) const { +void SimpleLogger::setStdout(int level, bool enabled) { + if(enabled) { + stdoutField |= level; + } else { + stdoutField &= ~level; + } +} + +void SimpleLogger::writeHeader(FILE* file, string date, string level) const { fprintf(file, "%s - %s - ", date.c_str(), level.c_str()); } -void SimpleLogger::writeLog(int level, const char* msg, va_list ap, Exception* e) const +void SimpleLogger::writeLog(FILE* file, int level, const char* msg, va_list ap, Exception* e) const { string levelStr; switch(level) { case Logger::DEBUG: levelStr = "DEBUG"; break; + case Logger::NOTICE: + levelStr = "NOTICE"; + break; case Logger::WARN: levelStr = "WARN"; break; @@ -88,15 +95,23 @@ void SimpleLogger::writeLog(int level, const char* msg, va_list ap, Exception* e char datestr[26]; ctime_r(&now, datestr); datestr[strlen(datestr)-1] = '\0'; - writeHeader(datestr, levelStr); + writeHeader(file, datestr, levelStr); vfprintf(file, string(Util::replace(msg, "\r", "")+"\n").c_str(), ap); if(e != NULL) { - writeHeader(datestr, levelStr); + writeHeader(file, datestr, levelStr); fprintf(file, "exception: %s\n", Util::replace(e->getMsg(), "\r", "").c_str()); } fflush(file); } +void SimpleLogger::writeFile(int level, const char* msg, va_list ap, Exception* e) const { + writeLog(file, level, msg, ap, e); + if(stdoutField&level) { + fprintf(stdout, "\n"); + writeLog(stdout, level, msg, ap, e); + } +} + void SimpleLogger::debug(const char* msg, ...) const { WRITE_LOG(DEBUG, msg); } @@ -113,6 +128,14 @@ void SimpleLogger::info(const char* msg, Exception* e, ...) const { WRITE_LOG_EX(INFO, msg, e); } +void SimpleLogger::notice(const char* msg, ...) const { + WRITE_LOG(NOTICE, msg); +} + +void SimpleLogger::notice(const char* msg, Exception* e, ...) const { + WRITE_LOG_EX(INFO, msg, e); +} + void SimpleLogger::warn(const char* msg, ...) const { WRITE_LOG(WARN, msg); } diff --git a/src/SimpleLogger.h b/src/SimpleLogger.h index ceb2ba15..190adb0b 100644 --- a/src/SimpleLogger.h +++ b/src/SimpleLogger.h @@ -26,24 +26,29 @@ class SimpleLogger:public Logger { private: - void writeHeader(string date, string level) const; - void writeLog(int level, const char* msg, va_list ap, Exception* e = NULL) const; + void writeFile(int level, const char* msg, va_list ap, Exception* e = 0) const; + void writeHeader(FILE* file, string date, string level) const; + void writeLog(FILE* file, int level, const char* msg, va_list ap, Exception* e = 0) const; FILE* file; + int stdoutField; public: - SimpleLogger(); - SimpleLogger(FILE* logfile); + SimpleLogger(FILE* logfile = 0); ~SimpleLogger(); void openFile(const string& filename); void closeFile(); - void debug(const char* msg, ...) const; - void debug(const char* msg, Exception* ex, ...) const; - void info(const char* msg, ...) const; - void info(const char* msg, Exception* ex, ...) const; - void warn(const char* msg, ...) const; - void warn(const char* msg, Exception* ex, ...) const; - void error(const char* msg, ...) const; - void error(const char* msg, Exception* ex, ...) const; + virtual void debug(const char* msg, ...) const; + virtual void debug(const char* msg, Exception* ex, ...) const; + virtual void info(const char* msg, ...) const; + virtual void info(const char* msg, Exception* ex, ...) const; + virtual void notice(const char* msg, ...) const; + virtual void notice(const char* msg, Exception* ex, ...) const; + virtual void warn(const char* msg, ...) const; + virtual void warn(const char* msg, Exception* ex, ...) const; + virtual void error(const char* msg, ...) const; + virtual void error(const char* msg, Exception* ex, ...) const; + + void setStdout(int level, bool enabled); }; #endif // _D_SIMPLE_LOGGER_H_ diff --git a/src/TimeSeedCriteria.h b/src/TimeSeedCriteria.h new file mode 100644 index 00000000..07c1776f --- /dev/null +++ b/src/TimeSeedCriteria.h @@ -0,0 +1,54 @@ +/* */ +#ifndef _D_TIME_SEED_CRITERIA_H_ +#define _D_TIME_SEED_CRITERIA_H_ + +#include "SeedCriteria.h" +#include "TimeA2.h" + +class TimeSeedCriteria : public SeedCriteria { +private: + // How much time the client does seeding in seconds. + int duration; + Time watch; +public: + TimeSeedCriteria(int duration):duration(duration) {} + virtual ~TimeSeedCriteria() {} + + virtual void reset() { + watch.reset(); + } + + virtual bool evaluate() { + return watch.elapsed(duration); + } + + void setDuration(int duration) { + this->duration = duration; + } + + int getDuration() const { + return duration; + } +}; + +#endif // _D_TIME_SEED_CRITERIA_H_ diff --git a/src/TorrentConsoleDownloadEngine.cc b/src/TorrentConsoleDownloadEngine.cc index d00257c0..74d02f03 100644 --- a/src/TorrentConsoleDownloadEngine.cc +++ b/src/TorrentConsoleDownloadEngine.cc @@ -26,11 +26,6 @@ TorrentConsoleDownloadEngine::TorrentConsoleDownloadEngine() {} TorrentConsoleDownloadEngine::~TorrentConsoleDownloadEngine() {} -void TorrentConsoleDownloadEngine::onSelectiveDownloadingCompletes() { - printf("\nDownload of selected files has completed.\n"); - fflush(stdout); -} - void TorrentConsoleDownloadEngine::sendStatistics() { printf("\r "); printf("\r"); diff --git a/src/TorrentConsoleDownloadEngine.h b/src/TorrentConsoleDownloadEngine.h index d487303d..686e0db4 100644 --- a/src/TorrentConsoleDownloadEngine.h +++ b/src/TorrentConsoleDownloadEngine.h @@ -27,7 +27,6 @@ class TorrentConsoleDownloadEngine : public TorrentDownloadEngine { protected: virtual void sendStatistics(); - void onSelectiveDownloadingCompletes(); public: TorrentConsoleDownloadEngine(); ~TorrentConsoleDownloadEngine(); diff --git a/src/TorrentDownloadEngine.cc b/src/TorrentDownloadEngine.cc index f5772c95..fb6c382b 100644 --- a/src/TorrentDownloadEngine.cc +++ b/src/TorrentDownloadEngine.cc @@ -33,26 +33,13 @@ TorrentDownloadEngine::~TorrentDownloadEngine() { void TorrentDownloadEngine::onEndOfRun() { torrentMan->diskAdaptor->closeFile(); - if(filenameFixed && torrentMan->downloadComplete()) { + if(torrentMan->downloadComplete()) { torrentMan->remove(); } else { torrentMan->save(); } } -void TorrentDownloadEngine::afterEachIteration() { - if(!filenameFixed && torrentMan->downloadComplete()) { - if(torrentMan->isSelectiveDownloadingMode()) { - onSelectiveDownloadingCompletes(); - } - logger->info("The download was complete."); - torrentMan->onDownloadComplete(); - if(torrentMan->downloadComplete()) { - filenameFixed = true; - } - } -} - void TorrentDownloadEngine::initStatistics() { downloadSpeed = 0; uploadSpeed = 0; diff --git a/src/TorrentDownloadEngine.h b/src/TorrentDownloadEngine.h index a2ecc634..563b970c 100644 --- a/src/TorrentDownloadEngine.h +++ b/src/TorrentDownloadEngine.h @@ -55,9 +55,7 @@ protected: long long int totalLength; int calculateSpeed(long long int sessionLength, int elapsed); - void onEndOfRun(); - void afterEachIteration(); - virtual void onSelectiveDownloadingCompletes() = 0; + virtual void onEndOfRun(); virtual void sendStatistics() = 0; public: TorrentDownloadEngine(); diff --git a/src/TorrentMan.cc b/src/TorrentMan.cc index 5704bdd5..0ef41347 100644 --- a/src/TorrentMan.cc +++ b/src/TorrentMan.cc @@ -277,12 +277,18 @@ void TorrentMan::completePiece(const Piece& piece) { if(!hasPiece(piece.getIndex())) { addDownloadLength(piece.getLength()); } - bitfield->setBit(piece.getIndex()); - bitfield->unsetUseBit(piece.getIndex()); deleteUsedPiece(piece); if(!isEndGame()) { reduceUsedPieces(100); } + if(downloadComplete()) { + return; + } + bitfield->setBit(piece.getIndex()); + bitfield->unsetUseBit(piece.getIndex()); + if(downloadComplete()) { + onDownloadComplete(); + } } void TorrentMan::cancelPiece(const Piece& piece) { @@ -647,7 +653,10 @@ void TorrentMan::onDownloadComplete() { save(); diskAdaptor->onDownloadComplete(); if(isSelectiveDownloadingMode()) { + logger->notice("Download of selected files has completed."); finishSelectiveDownloadingMode(); + } else { + logger->info("The download has completed."); } } diff --git a/src/TorrentMan.h b/src/TorrentMan.h index 219e7483..1f49366a 100644 --- a/src/TorrentMan.h +++ b/src/TorrentMan.h @@ -151,7 +151,17 @@ public: void syncPiece(Piece& piece); bool hasPiece(int index) const; void initBitfield(); + /** + * Returns true if the number of missing block is less than or equal to + * END_GAME_PIECE_NUM. + * If file filter is enabled, only a range specified by the filter is + * concerned. + */ bool isEndGame() const; + /** + * Returns true if download has completed. If file filter is enabled, + * returns true if download of a range specified by the filter has completed. + */ bool downloadComplete() const; bool hasAllPieces() const; void setBitfield(unsigned char* bitfield, int len); @@ -176,7 +186,7 @@ public: string getPieceHash(int index) const; - // Addes piece index to advertise to other commands. They send have message + // Adds piece index to advertise to other commands. They send have message // based on this information. void advertisePiece(int cuid, int index); diff --git a/src/TrackerUpdateCommand.cc b/src/TrackerUpdateCommand.cc index 49fe6f3a..09d44ec8 100644 --- a/src/TrackerUpdateCommand.cc +++ b/src/TrackerUpdateCommand.cc @@ -66,6 +66,9 @@ char* TrackerUpdateCommand::getTrackerResponse(int& trackerResponseLength) { } bool TrackerUpdateCommand::execute() { + if(e->segmentMan->errors > 0 && e->torrentMan->isHalt()) { + return true; + } if(!e->segmentMan->finished()) { return prepareForRetry(); } diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc index 1c334ac3..7e4cbe67 100644 --- a/src/TrackerWatcherCommand.cc +++ b/src/TrackerWatcherCommand.cc @@ -37,6 +37,9 @@ TrackerWatcherCommand::~TrackerWatcherCommand() {} bool TrackerWatcherCommand::execute() { if(e->segmentMan->errors > 0) { + if(e->torrentMan->isHalt()) { + return true; + } // we assume the tracker request has failed. e->torrentMan->trackers = 0; e->segmentMan->init(); @@ -62,6 +65,7 @@ bool TrackerWatcherCommand::execute() { e->torrentMan->req->setTrackerEvent(Request::AFTER_COMPLETED); } else { if(e->torrentMan->req->getTrackerEvent() == Request::STARTED) { + // in case where download had completed when aria2c started. e->torrentMan->req->setTrackerEvent(Request::AFTER_COMPLETED); } else if(e->torrentMan->req->getTrackerEvent() != Request::AFTER_COMPLETED) { e->torrentMan->req->setTrackerEvent(Request::COMPLETED); diff --git a/src/UnionSeedCriteria.h b/src/UnionSeedCriteria.h new file mode 100644 index 00000000..04f4c403 --- /dev/null +++ b/src/UnionSeedCriteria.h @@ -0,0 +1,69 @@ +/* */ +#ifndef _D_UNION_SEED_CRITERIA_H_ +#define _D_UNION_SEED_CRITERIA_H_ + +#include "SeedCriteria.h" + +class UnionSeedCriteria : public SeedCriteria { +private: + SeedCriterion criterion; + + class Reset { + public: + void operator()(SeedCriteriaHandle cri) { + cri->reset(); + } + }; + + class Eval { + public: + bool operator()(SeedCriteriaHandle cri) { + return cri->evaluate(); + } + }; +public: + UnionSeedCriteria() {} + virtual ~UnionSeedCriteria() {} + + + virtual void reset() { + for_each(criterion.begin(), criterion.end(), Reset()); + } + + virtual bool evaluate() { + SeedCriterion::iterator itr = find_if(criterion.begin(), + criterion.end(), + Eval()); + return itr != criterion.end(); + } + + void addSeedCriteria(SeedCriteriaHandle cri) { + criterion.push_back(cri); + } + + const SeedCriterion& getSeedCriterion() const { + return criterion; + } +}; + +#endif // _D_UNION_SEED_CRITERIA_H_ diff --git a/src/main.cc b/src/main.cc index 6eae3e97..58436990 100644 --- a/src/main.cc +++ b/src/main.cc @@ -175,6 +175,12 @@ void showUsage() { " ',' like \"3,6\".\n" " You can also use '-' to specify rangelike \"1-5\".\n" " ',' and '-' can be used together.") << endl; + cout << _(" --seed-time=MINUTES Specify seeding time in minutes. See also\n" + " --seed-ratio option.") << endl; + cout << _(" --seed-ratio=RATIO Specify seed share ratio. 1.0 is encouraged.\n" + " If --seed-time option is specified along with\n" + " this option, seeding ends when at least one of\n" + " the condition is met.") << endl; #endif // ENABLE_BITTORRENT #ifdef ENABLE_METALINK cout << _(" -M, --metalink-file=METALINK_FILE The file path to .metalink file.") << endl; @@ -332,6 +338,8 @@ int main(int argc, char* argv[]) { { "direct-file-mapping", required_argument, &lopt, 19 }, { "upload-limit", required_argument, &lopt, 20 }, { "select-file", required_argument, &lopt, 21 }, + { "seed-time", required_argument, &lopt, 22 }, + { "seed-ratio", required_argument, &lopt, 23 }, #endif // ENABLE_BITTORRENT #ifdef ENABLE_METALINK { "metalink-file", required_argument, NULL, 'M' }, @@ -492,6 +500,26 @@ int main(int argc, char* argv[]) { case 21: op->put(PREF_SELECT_FILE, optarg); break; + case 22: { + int seedTime = (int)strtol(optarg, NULL, 10); + if(seedTime < 0) { + cerr << _("seed-time must be greater than or equal to 0.") << endl; + showUsage(); + exit(EXIT_FAILURE); + } + op->put(PREF_SEED_TIME, Util::itos(seedTime)); + break; + } + case 23: { + double ratio = (int)strtod(optarg, NULL); + if(ratio < 0.0) { + cerr << _("seed-ratio must be greater than or equal to 0.0.") << endl; + showUsage(); + exit(EXIT_FAILURE); + } + op->put(PREF_SEED_RATIO, optarg); + break; + } case 100: op->put(PREF_METALINK_VERSION, optarg); break; @@ -637,6 +665,8 @@ int main(int argc, char* argv[]) { LogFactory::setLogFile("/dev/stdout"); } else if(op->get(PREF_LOG).size()) { LogFactory::setLogFile(op->get(PREF_LOG)); + } else { + LogFactory::setLogFile("/dev/null"); } // make sure logger is configured properly. try { diff --git a/src/prefs.h b/src/prefs.h index 83fcaba7..9c3e040a 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -122,6 +122,10 @@ #define PREF_FOLLOW_TORRENT "follow_torrent" // values: 1*digit *( (,|-) 1*digit) #define PREF_SELECT_FILE "select_file" +// values: 1*digit +#define PREF_SEED_TIME "seed_time" +// values: 1*digit ['.' [ 1*digit ] ] +#define PREF_SEED_RATIO "seed_ratio" /** * Metalink related preferences diff --git a/test/Makefile.am b/test/Makefile.am index 99486411..49465030 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -35,7 +35,9 @@ aria2c_SOURCES = AllTest.cc\ Xml2MetalinkProcessorTest.cc\ MetalinkerTest.cc\ MetalinkEntryTest.cc\ - FeatureConfigTest.cc + FeatureConfigTest.cc\ + ShareRatioSeedCriteriaTest.cc\ + TimeSeedCriteriaTest.cc #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_LDFLAGS = ${CPPUNIT_LIBS} diff --git a/test/Makefile.in b/test/Makefile.in index 2016423f..52718918 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -74,7 +74,9 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \ RejectMessageTest.$(OBJEXT) AllowedFastMessageTest.$(OBJEXT) \ SuggestPieceMessageTest.$(OBJEXT) \ Xml2MetalinkProcessorTest.$(OBJEXT) MetalinkerTest.$(OBJEXT) \ - MetalinkEntryTest.$(OBJEXT) FeatureConfigTest.$(OBJEXT) + MetalinkEntryTest.$(OBJEXT) FeatureConfigTest.$(OBJEXT) \ + ShareRatioSeedCriteriaTest.$(OBJEXT) \ + TimeSeedCriteriaTest.$(OBJEXT) aria2c_OBJECTS = $(am_aria2c_OBJECTS) am__DEPENDENCIES_1 = aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1) @@ -263,7 +265,9 @@ aria2c_SOURCES = AllTest.cc\ Xml2MetalinkProcessorTest.cc\ MetalinkerTest.cc\ MetalinkEntryTest.cc\ - FeatureConfigTest.cc + FeatureConfigTest.cc\ + ShareRatioSeedCriteriaTest.cc\ + TimeSeedCriteriaTest.cc #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_LDFLAGS = ${CPPUNIT_LIBS} @@ -355,7 +359,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitorTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShareRatioSeedCriteriaTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnchokeMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@ diff --git a/test/ShareRatioSeedCriteriaTest.cc b/test/ShareRatioSeedCriteriaTest.cc new file mode 100644 index 00000000..9e11e117 --- /dev/null +++ b/test/ShareRatioSeedCriteriaTest.cc @@ -0,0 +1,31 @@ +#include "ShareRatioSeedCriteria.h" + +#include + +class ShareRatioSeedCriteriaTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(ShareRatioSeedCriteriaTest); + CPPUNIT_TEST(testEvaluate); + CPPUNIT_TEST_SUITE_END(); + +public: + void testEvaluate(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(ShareRatioSeedCriteriaTest); + +void ShareRatioSeedCriteriaTest::testEvaluate() { + TorrentMan torrentMan; + torrentMan.setDownloadLength(4294967296LL); + torrentMan.setUploadLength(4294967296LL); + + ShareRatioSeedCriteria cri(1.0, &torrentMan); + CPPUNIT_ASSERT(cri.evaluate()); + + cri.setRatio(2.0); + CPPUNIT_ASSERT(!cri.evaluate()); + // check div by zero + torrentMan.setDownloadLength(0); + CPPUNIT_ASSERT(!cri.evaluate()); +} diff --git a/test/TimeSeedCriteriaTest.cc b/test/TimeSeedCriteriaTest.cc new file mode 100644 index 00000000..f7464e89 --- /dev/null +++ b/test/TimeSeedCriteriaTest.cc @@ -0,0 +1,25 @@ +#include "TimeSeedCriteria.h" + +#include + +class TimeSeedCriteriaTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(TimeSeedCriteriaTest); + CPPUNIT_TEST(testEvaluate); + CPPUNIT_TEST_SUITE_END(); + +public: + void testEvaluate(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(TimeSeedCriteriaTest); + +void TimeSeedCriteriaTest::testEvaluate() { + TimeSeedCriteria cri(1); + sleep(1); + CPPUNIT_ASSERT(cri.evaluate()); + cri.reset(); + cri.setDuration(10); + CPPUNIT_ASSERT(!cri.evaluate()); +}