diff --git a/ChangeLog b/ChangeLog index 62e56c01..b959afae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,155 @@ +2006-06-12 Tatsuhiro Tsujikawa + + To add Time class which represents a specific instant in time and + its precision is microseconds. Time checking procedures were rewritten + using this object. + + * src/Time.h: New class. + * src/Time.cc: New class. + * src/AbstractCommand.h + (updateCheckPoint): Removed. + (isTimeoutDetected): Removed. + (checkPoint): Changed the type to Time. + (timeout): New variable. + (setTimeout): New function. + * src/AbstractCommand.cc + (AbstractCommand): Removed the initialization of checkPoint. + Added the initialization of timeout. + (updateCheckPoint): Removed. + (isTimeoutDetected): Removed. + (execute): Use checkPoint.reset() and checkPoint.elapsed(). + * src/PeerChokeCommand.h + (checkPoint): Changed the type to Time. + * src/PeerChokeCommand.cc + (PeerChokeCommand): Removed the initialization of checkPoint. + (execute): Rewritten using Time object. + * src/TrackerWatcherCommand.h + (checkPoint): Changed the type to Time. + * src/TrackerWatcherCommand.cc + (TrackerWatcherCommand): Removed the initialization of checkPoint. + (execute): Rewritten. + * src/ConsoleDownloadEngine.h + (cp): Changed the type to Time. + (startup): Changed the type to Time. + * src/ConsoleDownloadEngine.cc + (initStatistics): Use cp.reset(), startup.reset(). + (calculateStatistics): Rewritten using Time object. + * src/PeerAbstractCommand.h + (updateCheckPoint): Removed. + (isTimeoutDetected): Removed. + (checkPoint): Changed the type to Time. + * src/PeerAbstractCommand.cc + (PeerAbstractCommand): Removed the initialization of checkPoint. + (updateCheckPoint): Removed. + (isTimeoutDetected): Removed. + (execute): Use checkPoint.reset() and checkPoint.elapsed(). + * src/PeerInteractionCommand.cc + (PeerInteractionCommand): Removed the initializations of struct + timeval variables. + * src/PeerInteractionCommand.h + (keepAliveCheckPoint): Changed the type to Time. + (chokeCheckPoint): Changed the type to Time. + (freqCheckPoint): Changed the type to Time. + (haveCheckTime): Changed the type to Time. + * src/PeerInteractionCommand.cc + (executeInternal): Rewritten using Time object. + (detectMessageFlooding): Rewritten using Time object. + (checkLongTimePeerChoking): Rewritten using Time object. + (sendKeepAlive): Rewritten using Time object. + (checkHave): Rewritten using Time object. + * src/SleepCommand.h + (checkPoint): Changed the type to Time. + * src/SleepCommand.cc + (SleepCommand): Removed the initialization of checkPoint. + (execute): Rewritten using Time object. + * src/TorrentAutoSaveCommand.h + (checkPoint): Changed the type to Time. + * src/TorrentAutoSaveCommand.cc + (TorrentAutoSaveCommand): Removed the initialization of checkPoint. + (execute): Rewritten. + * src/DownloadCommand.h + (sw): Changed the type to Time. + * src/DownloadCommand.cc + (DownloadCommand): Removed the initialization of sw. + (executeInternal): Rewritten. + * src/RequestSlot.h + (dispatchedTime): Changed the type to Time. + * src/RequestSlot.cc + (RequestSlot): Removed the call to setDispatchedTime(). + (setDispatchedTime): Rewirtten. + (isTimeout): Rewritten. + (getLatencyInMillis): Rewritten. + * src/TorrentDownloadEngine.h + (cp): Changed the type to Time[2]. + (startup): Changed the type to Time. + * src/TorrentDownloadEngine.cc + (initStatistics): Rewritten. + (calculateStatistics): Rewritten. + * src/DownloadEngine.cc + (run): Rewritten. + + To detect all attempts to connect to the tracker are failed: + + * src/AbstractCommand.cc + (execute): Increment e->segmentMan->errors if a command aborted. + * src/SegmentMan.h + (errors): New variable. + * src/SegmentMan.cc + (SegmentMan): Added the initialization of errors. + (init): Added the initialization of errors. + * src/TrackerWatcherCommand.cc + (execute): If e->segmentMan->errors > 0 then assume that the tracker + request was failed. + + To handle snubbed peers: + + * src/PeerChokeCommand.cc + (optUnchokingPeer): Snubbed peers don't get unchoked. + (execute): Snubbed peers don't get unchoked. + * src/PeerInteraction.h + (REQUEST_TIME_OUT): Changed the value from 120 to 60. + * src/PeerInteraction.cc + (checkRequestSlot): A peer get marked as "snubbed" if it doesn't send + back the requested 16k block in 60 seconds. + * src/PieceMessage.cc + (receivedAction): A peer's snubbed state is cleard if it sends + the requested 16k block in 60 seconds. + * src/Peer.h + (snubbing): New variable. + * src/Peer.cc + (resetStatus): Added snubbed = false. + + To fix the bug that causes have message is not sent: + + * src/PeerInteractionCommand.cc + (~PeerInteractionCommand): Removed e->torrentMan->unadvertisePiece(). + (FLOODING_CHECK_INTERVAL): New definition(temporal). + (detectMessageFlooding): Use FLOODING_CHECK_INTERVAL. + * src/TorrentMan.h + (HaveEntry): New class. + (advertisePiece): Rewritten. + (getAdvertisedPieceIndexes): Rewritten. + (Haves): Changed the type. + (getAdvertisedPieceIndexes): Added an argument. + + Others: + + * src/TorrentMan.h + (DEFAULT_ANNOUNCE_INTERVAL): Changed the value to 1800. + (DEFAULT_ANNOUNCE_MIN_INTERVAL): Changed the value to 1800. + * src/TorrentMan.cc + (getPeer): Don't check the number of connections here. + (setupInternal1): Changed peerId. + + * src/PeerInteractionCommand.h + (KEEP_ALIVE_INTERVAL): New definition. + (sendKeepAlive): Use KEEP_ALIVE_INTERVAL. + + * src/main.cc + (main): SA_ONESHOT was replaced with SA_RESETHAND. + + * src/DownloadEngine.h: Removed unnecessary header includes. + 2006-05-29 Tatsuhiro Tsujikawa To fix the bug that causes segfaults if a tracker returns a zero-length diff --git a/configure b/configure index 56e5b0c8..5a182bfa 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.59 for aria2c 0.5.0. +# Generated by GNU Autoconf 2.59 for aria2c 0.5.1. # # Report bugs to . # @@ -269,8 +269,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='aria2c' PACKAGE_TARNAME='aria2c' -PACKAGE_VERSION='0.5.0' -PACKAGE_STRING='aria2c 0.5.0' +PACKAGE_VERSION='0.5.1' +PACKAGE_STRING='aria2c 0.5.1' PACKAGE_BUGREPORT='tujikawa@rednoah.com' ac_unique_file="src/Socket.h" @@ -788,7 +788,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures aria2c 0.5.0 to adapt to many kinds of systems. +\`configure' configures aria2c 0.5.1 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -854,7 +854,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of aria2c 0.5.0:";; + short | recursive ) echo "Configuration of aria2c 0.5.1:";; esac cat <<\_ACEOF @@ -994,7 +994,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -aria2c configure 0.5.0 +aria2c configure 0.5.1 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. @@ -1008,7 +1008,7 @@ cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by aria2c $as_me 0.5.0, which was +It was created by aria2c $as_me 0.5.1, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ @@ -1651,7 +1651,7 @@ fi # Define the identity of the package. PACKAGE='aria2c' - VERSION='0.5.0' + VERSION='0.5.1' cat >>confdefs.h <<_ACEOF @@ -11528,7 +11528,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by aria2c $as_me 0.5.0, which was +This file was extended by aria2c $as_me 0.5.1, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -11591,7 +11591,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -aria2c config.status 0.5.0 +aria2c config.status 0.5.1 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.ac b/configure.ac index 67bc6ad6..9cef0b10 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. # AC_PREREQ(2.59) -AC_INIT(aria2c, 0.5.0, tujikawa@rednoah.com) +AC_INIT(aria2c, 0.5.1, tujikawa@rednoah.com) AM_INIT_AUTOMAKE() AM_PATH_CPPUNIT(1.10.2) AC_CONFIG_SRCDIR([src/Socket.h]) diff --git a/po/Makefile.in b/po/Makefile.in index 555883a9..74a735a9 100644 --- a/po/Makefile.in +++ b/po/Makefile.in @@ -9,7 +9,7 @@ # General Public License and is *not* in the public domain. PACKAGE = aria2c -VERSION = 0.5.0 +VERSION = 0.5.1 SHELL = /bin/sh diff --git a/src/AbstractCommand.cc b/src/AbstractCommand.cc index eb2d58a0..0de96354 100644 --- a/src/AbstractCommand.cc +++ b/src/AbstractCommand.cc @@ -27,7 +27,6 @@ #include "message.h" #include "SleepCommand.h" #include "prefs.h" -#include AbstractCommand::AbstractCommand(int cuid, Request* req, DownloadEngine* e, const Socket* s): Command(cuid), req(req), e(e), checkSocketIsReadable(false), checkSocketIsWritable(false) { @@ -38,8 +37,7 @@ AbstractCommand::AbstractCommand(int cuid, Request* req, DownloadEngine* e, cons } else { socket = NULL; } - this->checkPoint.tv_sec = 0; - this->checkPoint.tv_usec = 0; + timeout = this->e->option->getAsInt(PREF_TIMEOUT); } AbstractCommand::~AbstractCommand() { @@ -50,33 +48,12 @@ AbstractCommand::~AbstractCommand() { } } -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 { - int elapsed = Util::difftvsec(now, checkPoint); - if(elapsed >= e->option->getAsInt(PREF_TIMEOUT)) { - return true; - } else { - return false; - } - } -} - bool AbstractCommand::execute() { try { if(checkSocketIsReadable && readCheckTarget->isReadable(0) || checkSocketIsWritable && writeCheckTarget->isWritable(0) || !checkSocketIsReadable && !checkSocketIsWritable) { - - updateCheckPoint(); + checkPoint.reset(); Segment seg = { 0, 0, 0, false }; if(e->segmentMan->downloadStarted) { // get segment information in order to set Range header. @@ -88,7 +65,7 @@ bool AbstractCommand::execute() { } return executeInternal(seg); } else { - if(isTimeoutDetected()) { + if(checkPoint.elapsed(timeout)) { throw new DlRetryEx(EX_TIME_OUT); } e->commands.push_back(this); @@ -99,6 +76,7 @@ bool AbstractCommand::execute() { onAbort(err); delete(err); req->resetUrl(); + e->segmentMan->errors++; return true; } catch(DlRetryEx* err) { logger->error(MSG_RESTARTING_DOWNLOAD, err, cuid); @@ -111,6 +89,7 @@ bool AbstractCommand::execute() { delete(err); if(isAbort) { logger->error(MSG_MAX_TRY, cuid, req->getTryCount()); + e->segmentMan->errors++; return true; } else { return prepareForRetry(e->option->getAsInt(PREF_RETRY_WAIT)); diff --git a/src/AbstractCommand.h b/src/AbstractCommand.h index 7a69c88e..c4b3d91f 100644 --- a/src/AbstractCommand.h +++ b/src/AbstractCommand.h @@ -26,13 +26,12 @@ #include "Request.h" #include "DownloadEngine.h" #include "SegmentMan.h" -#include +#include "Time.h" class AbstractCommand : public Command { private: - void updateCheckPoint(); - bool isTimeoutDetected(); - struct timeval checkPoint; + Time checkPoint; + int timeout; protected: Request* req; DownloadEngine* e; @@ -44,6 +43,7 @@ protected: void setReadCheckSocket(Socket* socket); void setWriteCheckSocket(Socket* socket); + void setTimeout(int timeout) { this->timeout = timeout; } private: bool checkSocketIsReadable; bool checkSocketIsWritable; diff --git a/src/ConsoleDownloadEngine.cc b/src/ConsoleDownloadEngine.cc index 24941553..fb2c1bc8 100644 --- a/src/ConsoleDownloadEngine.cc +++ b/src/ConsoleDownloadEngine.cc @@ -40,14 +40,14 @@ void ConsoleDownloadEngine::sendStatistics(long long int currentSize, long long } void ConsoleDownloadEngine::initStatistics() { - cp.tv_sec = cp.tv_usec = 0; + cp.reset(); + startup.reset(); speed = 0; psize = 0; avgSpeed = 0; eta = 0; startupLength = 0; isStartupLengthSet = false; - gettimeofday(&startup, NULL); } void ConsoleDownloadEngine::calculateStatistics() { @@ -56,28 +56,24 @@ void ConsoleDownloadEngine::calculateStatistics() { startupLength = dlSize; isStartupLengthSet = true; } - struct timeval now; - gettimeofday(&now, NULL); - if(cp.tv_sec == 0 && cp.tv_usec == 0) { - cp = now; + int elapsed = cp.difference(); + if(elapsed >= 1) { + int nspeed = (int)((dlSize-psize)/elapsed); + speed = (nspeed+speed)/2; + cp.reset(); psize = dlSize; - } else { - int elapsed = Util::difftvsec(now, cp); - if(elapsed >= 1) { - int nspeed = (int)((dlSize-psize)/elapsed); - speed = (nspeed+speed)/2; - cp = now; - psize = dlSize; - avgSpeed = (int)((dlSize-startupLength)/Util::difftvsec(now, startup)); - if(avgSpeed < 0) { - avgSpeed = 0; - } else if(avgSpeed != 0 && segmentMan->totalSize > 0) { - eta = (segmentMan->totalSize-dlSize)/avgSpeed; - } - - sendStatistics(dlSize, segmentMan->totalSize); + int elapsedFromStartup = startup.difference(); + if(elapsedFromStartup > 0) { + avgSpeed = (int)((dlSize-startupLength)/elapsedFromStartup); } + if(avgSpeed < 0) { + avgSpeed = 0; + } else if(avgSpeed != 0 && segmentMan->totalSize > 0) { + eta = (segmentMan->totalSize-dlSize)/avgSpeed; + } + + sendStatistics(dlSize, segmentMan->totalSize); } } diff --git a/src/ConsoleDownloadEngine.h b/src/ConsoleDownloadEngine.h index cd986bb1..f708c008 100644 --- a/src/ConsoleDownloadEngine.h +++ b/src/ConsoleDownloadEngine.h @@ -23,14 +23,15 @@ #define _D_CONSOLE_DOWNLOAD_ENGINE_H_ #include "DownloadEngine.h" +#include "Time.h" class ConsoleDownloadEngine : public DownloadEngine { private: - struct timeval cp; + Time cp; long long int psize; int speed; // The time when startup - struct timeval startup; + Time startup; // The number of bytes downloaded at startup long long int startupLength; bool isStartupLengthSet; diff --git a/src/DownloadCommand.cc b/src/DownloadCommand.cc index b78cef10..98b117c6 100644 --- a/src/DownloadCommand.cc +++ b/src/DownloadCommand.cc @@ -27,10 +27,7 @@ #include "InitiateConnectionCommandFactory.h" #include "message.h" -DownloadCommand::DownloadCommand(int cuid, Request* req, DownloadEngine* e, const Socket* s):AbstractCommand(cuid, req, e, s), lastSize(0) { - sw.tv_sec = 0; - sw.tv_usec = 0; -} +DownloadCommand::DownloadCommand(int cuid, Request* req, DownloadEngine* e, const Socket* s):AbstractCommand(cuid, req, e, s), lastSize(0) {} DownloadCommand::~DownloadCommand() {} @@ -54,18 +51,11 @@ bool DownloadCommand::executeInternal(Segment seg) { seg.ds += bufSize; } // calculate downloading speed - struct timeval now; - gettimeofday(&now, NULL); - if(sw.tv_sec == 0 && sw.tv_usec == 0) { - sw = now; + int diff = sw.difference(); + if(diff >= 1) { + seg.speed = (int)((seg.ds-lastSize)/(diff*1.0)); + sw.reset(); lastSize = seg.ds; - } else { - int diff = Util::difftvsec(now, sw); - if(diff >= 1) { - seg.speed = (int)((seg.ds-lastSize)/(diff*1.0)); - sw = now; - lastSize = seg.ds; - } } if(e->segmentMan->totalSize != 0 && bufSize == 0) { throw new DlRetryEx(EX_GOT_EOF); diff --git a/src/DownloadCommand.h b/src/DownloadCommand.h index 2c3d50f6..b1f4d2a0 100644 --- a/src/DownloadCommand.h +++ b/src/DownloadCommand.h @@ -24,14 +24,13 @@ #include "AbstractCommand.h" #include "TransferEncoding.h" -#include -#include +#include "Time.h" using namespace std; class DownloadCommand : public AbstractCommand { private: - struct timeval sw; + Time sw; long long int lastSize; protected: bool executeInternal(Segment segment); diff --git a/src/DownloadEngine.cc b/src/DownloadEngine.cc index ecb6551c..e2bef95f 100644 --- a/src/DownloadEngine.cc +++ b/src/DownloadEngine.cc @@ -22,6 +22,7 @@ #include "DownloadEngine.h" #include "Util.h" #include "LogFactory.h" +#include "Time.h" #include #include #include @@ -48,15 +49,11 @@ void DownloadEngine::cleanQueue() { void DownloadEngine::run() { initStatistics(); - struct timeval cp; - cp.tv_sec = 0; - cp.tv_usec = 0; + Time cp; Sockets activeSockets; while(!commands.empty()) { - struct timeval now; - gettimeofday(&now, NULL); - if(Util::difftvsec(now, cp) >= 1) { - cp = now; + if(cp.elapsed(1)) { + cp.reset(); int max = commands.size(); for(int i = 0; i < max; i++) { Command* com = commands.front(); diff --git a/src/DownloadEngine.h b/src/DownloadEngine.h index ddfcf248..dd9d10fc 100644 --- a/src/DownloadEngine.h +++ b/src/DownloadEngine.h @@ -28,8 +28,6 @@ #include "common.h" #include "Logger.h" #include "Option.h" -#include -#include typedef deque Sockets; typedef deque Commands; diff --git a/src/Makefile.am b/src/Makefile.am index bb17bc6e..071d5c3e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -101,7 +101,8 @@ SRCS = Socket.cc Socket.h\ AllowedFastMessage.cc AllowedFastMessage.h\ SuggestPieceMessage.cc SuggestPieceMessage.h\ SimplePeerMessage.cc SimplePeerMessage.h\ - NullLogger.h + NullLogger.h\ + Time.cc Time.h noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\ diff --git a/src/Makefile.in b/src/Makefile.in index a113ed2d..630fb59d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -109,7 +109,7 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \ PortMessage.$(OBJEXT) HaveAllMessage.$(OBJEXT) \ HaveNoneMessage.$(OBJEXT) RejectMessage.$(OBJEXT) \ AllowedFastMessage.$(OBJEXT) SuggestPieceMessage.$(OBJEXT) \ - SimplePeerMessage.$(OBJEXT) + SimplePeerMessage.$(OBJEXT) Time.$(OBJEXT) am_libaria2c_a_OBJECTS = $(am__objects_1) libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" @@ -360,7 +360,8 @@ SRCS = Socket.cc Socket.h\ AllowedFastMessage.cc AllowedFastMessage.h\ SuggestPieceMessage.cc SuggestPieceMessage.h\ SimplePeerMessage.cc SimplePeerMessage.h\ - NullLogger.h + NullLogger.h\ + Time.cc Time.h noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) @@ -525,6 +526,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SplitFirstSegmentSplitter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SplitSlowestSegmentSplitter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Time.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentAutoSaveCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentConsoleDownloadEngine.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentDownloadEngine.Po@am__quote@ diff --git a/src/Peer.cc b/src/Peer.cc index 7d556f48..7df0d081 100644 --- a/src/Peer.cc +++ b/src/Peer.cc @@ -59,6 +59,7 @@ void Peer::resetStatus() { resetDeltaDownload(); chokingRequired = true; optUnchoking = false; + snubbing = false; fastExtensionEnabled = false; latency = DEFAULT_LATENCY; fastSet.clear(); diff --git a/src/Peer.h b/src/Peer.h index 53707cd5..5bc8a27a 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -46,6 +46,7 @@ public: int cuid; bool chokingRequired; bool optUnchoking; + bool snubbing; private: char peerId[PEER_ID_LENGTH]; BitfieldMan* bitfield; @@ -65,6 +66,7 @@ public: peerChoking(true), peerInterested(false), tryCount(0), error(0), cuid(0), chokingRequired(true), optUnchoking(false), + snubbing(false), bitfield(NULL), fastExtensionEnabled(false), peerUpload(0), peerDownload(0), @@ -107,8 +109,8 @@ public: void setAllBitfield(); /** - * operation = 1: set index-th bit 1 - * operation = 0: set index-th bit 0 + * operation = 1: set index-th bit to 1 + * operation = 0: set index-th bit to 0 */ void updateBitfield(int index, int operation); diff --git a/src/PeerAbstractCommand.cc b/src/PeerAbstractCommand.cc index 74a6617f..651c865f 100644 --- a/src/PeerAbstractCommand.cc +++ b/src/PeerAbstractCommand.cc @@ -25,7 +25,6 @@ #include "Util.h" #include "message.h" #include "prefs.h" -#include PeerAbstractCommand::PeerAbstractCommand(int cuid, Peer* peer, TorrentDownloadEngine* e, const Socket* s): Command(cuid), e(e), peer(peer), @@ -38,8 +37,6 @@ PeerAbstractCommand::PeerAbstractCommand(int cuid, Peer* peer, TorrentDownloadEn } else { socket = NULL; } - this->checkPoint.tv_sec = 0; - this->checkPoint.tv_usec = 0; timeout = e->option->getAsInt(PREF_TIMEOUT); e->torrentMan->connections++; } @@ -53,26 +50,6 @@ PeerAbstractCommand::~PeerAbstractCommand() { e->torrentMan->connections--; } -void PeerAbstractCommand::updateCheckPoint() { - gettimeofday(&checkPoint, NULL); -} - -bool PeerAbstractCommand::isTimeoutDetected() { - struct timeval now; - gettimeofday(&now, NULL); - if(checkPoint.tv_sec == 0 && checkPoint.tv_usec == 0) { - checkPoint = now; - return false; - } else { - int elapsed = Util::difftvsec(now, checkPoint); - if(elapsed >= timeout) { - return true; - } else { - return false; - } - } -} - bool PeerAbstractCommand::execute() { if(e->torrentMan->isHalt()) { return true; @@ -82,12 +59,9 @@ bool PeerAbstractCommand::execute() { e->getUploadSpeed() <= uploadLimit*1024) || checkSocketIsReadable && readCheckTarget->isReadable(0) || checkSocketIsWritable && writeCheckTarget->isWritable(0)) { - updateCheckPoint(); + checkPoint.reset(); } - if(isTimeoutDetected()) { - // TODO following 2 lines will be deleted. - checkPoint.tv_sec = 0; - checkPoint.tv_usec = 0; + if(checkPoint.elapsed(timeout)) { throw new DlRetryEx(EX_TIME_OUT); } return executeInternal(); diff --git a/src/PeerAbstractCommand.h b/src/PeerAbstractCommand.h index a6310c01..2458d31e 100644 --- a/src/PeerAbstractCommand.h +++ b/src/PeerAbstractCommand.h @@ -25,13 +25,11 @@ #include "Command.h" #include "Request.h" #include "TorrentDownloadEngine.h" -#include +#include "Time.h" class PeerAbstractCommand : public Command { private: - void updateCheckPoint(); - bool isTimeoutDetected(); - struct timeval checkPoint; + Time checkPoint; int timeout; protected: TorrentDownloadEngine* e; diff --git a/src/PeerChokeCommand.cc b/src/PeerChokeCommand.cc index bf7b363f..04fb481c 100644 --- a/src/PeerChokeCommand.cc +++ b/src/PeerChokeCommand.cc @@ -22,10 +22,7 @@ #include "PeerChokeCommand.h" #include "Util.h" -PeerChokeCommand::PeerChokeCommand(int cuid, int interval, TorrentDownloadEngine* e):Command(cuid), interval(interval), e(e), rotate(0) { - checkPoint.tv_sec = 0; - checkPoint.tv_usec = 0; -} +PeerChokeCommand::PeerChokeCommand(int cuid, int interval, TorrentDownloadEngine* e):Command(cuid), interval(interval), e(e), rotate(0) {} PeerChokeCommand::~PeerChokeCommand() {} @@ -41,23 +38,16 @@ void PeerChokeCommand::optUnchokingPeer(Peers& peers) const { return; } random_shuffle(peers.begin(), peers.end()); + int optUnchokCount = 1; for(Peers::iterator itr = peers.begin(); itr != peers.end(); itr++) { - (*itr)->optUnchoking = false; - } - Peer* peer = peers.front(); - peer->optUnchoking = true; - logger->debug("opt, unchoking %s, delta=%d", - peer->ipaddr.c_str(), peer->getDeltaUpload()); - if(e->torrentMan->isEndGame()) { - Peers::iterator itr = peers.begin()+1; - for(; itr != peers.end(); itr++) { - Peer* peer = *itr; - if(peer->amInterested && peer->peerInterested) { - peer->optUnchoking = true; - logger->debug("opt, unchoking %s, delta=%d", - peer->ipaddr.c_str(), peer->getDeltaUpload()); - break; - } + Peers::value_type peer = *itr; + if(optUnchokCount > 0 && !peer->snubbing) { + optUnchokCount--; + peer->optUnchoking = true; + logger->debug("opt, unchoking %s, delta=%d", + peer->ipaddr.c_str(), peer->getDeltaUpload()); + } else { + peer->optUnchoking = false; } } } @@ -96,10 +86,8 @@ bool PeerChokeCommand::execute() { if(e->torrentMan->isHalt()) { return true; } - struct timeval now; - gettimeofday(&now, NULL); - if(Util::difftvsec(now, checkPoint) >= interval) { - checkPoint = now; + if(checkPoint.elapsed(interval)) { + checkPoint.reset(); Peers peers = e->torrentMan->getActivePeers(); setAllPeerChoked(peers); if(e->torrentMan->downloadComplete()) { @@ -107,14 +95,14 @@ bool PeerChokeCommand::execute() { } else { orderByUploadRate(peers); } - int unchokingCount = peers.size() >= 4 ? 4 : peers.size(); - for(Peers::iterator itr = peers.begin(); unchokingCount > 0 && itr != peers.end(); ) { + int unchokingCount = 4;//peers.size() >= 4 ? 4 : peers.size(); + for(Peers::iterator itr = peers.begin(); itr != peers.end() && unchokingCount > 0; ) { Peer* peer = *itr; - if(peer->peerInterested) { + if(peer->peerInterested && !peer->snubbing) { + unchokingCount--; peer->chokingRequired = false; peer->optUnchoking = false; itr = peers.erase(itr); - unchokingCount--; logger->debug("cat01, unchoking %s, delta=%d", peer->ipaddr.c_str(), peer->getDeltaUpload()); } else { itr++; @@ -122,7 +110,7 @@ bool PeerChokeCommand::execute() { } for(Peers::iterator itr = peers.begin(); itr != peers.end(); ) { Peer* peer = *itr; - if(!peer->peerInterested) { + if(!peer->peerInterested && !peer->snubbing) { peer->chokingRequired = false; peer->optUnchoking = false; itr = peers.erase(itr); diff --git a/src/PeerChokeCommand.h b/src/PeerChokeCommand.h index e652f90f..16fdd701 100644 --- a/src/PeerChokeCommand.h +++ b/src/PeerChokeCommand.h @@ -24,13 +24,14 @@ #include "Command.h" #include "TorrentDownloadEngine.h" +#include "Time.h" class PeerChokeCommand : public Command { private: int interval; TorrentDownloadEngine* e; int rotate; - struct timeval checkPoint; + Time checkPoint; void orderByUploadRate(Peers& peers) const; void orderByDownloadRate(Peers& peers) const; diff --git a/src/PeerInteraction.cc b/src/PeerInteraction.cc index 90520248..93031501 100644 --- a/src/PeerInteraction.cc +++ b/src/PeerInteraction.cc @@ -231,6 +231,7 @@ void PeerInteraction::checkRequestSlot() { Piece& piece = getDownloadPiece(slot.getIndex()); piece.cancelBlock(slot.getBlockIndex()); itr = requestSlots.erase(itr); + peer->snubbing = true; } else { Piece piece = getDownloadPiece(slot.getIndex()); if(piece.hasBlock(slot.getBlockIndex()) || diff --git a/src/PeerInteraction.h b/src/PeerInteraction.h index 06a576d5..a6b239ea 100644 --- a/src/PeerInteraction.h +++ b/src/PeerInteraction.h @@ -43,7 +43,7 @@ #include "SuggestPieceMessage.h" #include "RequestSlot.h" -#define REQUEST_TIME_OUT 120 +#define REQUEST_TIME_OUT 60 #define ALLOWED_FAST_SET_SIZE 10 typedef deque RequestSlots; diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index aafeed58..e6b75b2a 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -41,12 +41,6 @@ PeerInteractionCommand::PeerInteractionCommand(int cuid, Peer* peer, e->torrentMan, this->peer); peerInteraction->setUploadLimit(e->option->getAsInt(PREF_UPLOAD_LIMIT)); setUploadLimit(e->option->getAsInt(PREF_UPLOAD_LIMIT)); - keepAliveCheckPoint.tv_sec = 0; - keepAliveCheckPoint.tv_usec = 0; - chokeCheckPoint.tv_sec = 0; - chokeCheckPoint.tv_usec = 0; - freqCheckPoint.tv_sec = 0; - freqCheckPoint.tv_usec = 0; chokeUnchokeCount = 0; haveCount = 0; keepAliveCount = 0; @@ -55,7 +49,6 @@ PeerInteractionCommand::PeerInteractionCommand(int cuid, Peer* peer, PeerInteractionCommand::~PeerInteractionCommand() { delete peerInteraction; - e->torrentMan->unadvertisePiece(cuid); e->torrentMan->deleteActivePeer(this->peer); } @@ -89,6 +82,7 @@ bool PeerInteractionCommand::executeInternal() { peer->ipaddr.c_str(), peer->port, handshakeMessage->toString().c_str()); delete handshakeMessage; + haveCheckTime.reset(); peerInteraction->sendBitfield(); peerInteraction->sendAllowedFast(); sequence = WIRED; @@ -105,6 +99,7 @@ bool PeerInteractionCommand::executeInternal() { handshakeMessage->toString().c_str()); delete handshakeMessage; peerInteraction->sendHandshake(); + haveCheckTime.reset(); peerInteraction->sendBitfield(); peerInteraction->sendAllowedFast(); sequence = WIRED; @@ -134,24 +129,19 @@ bool PeerInteractionCommand::executeInternal() { return false; } +#define FLOODING_CHECK_INTERVAL 5 + void PeerInteractionCommand::detectMessageFlooding() { - struct timeval now; - gettimeofday(&now, NULL); - if(freqCheckPoint.tv_sec == 0 && freqCheckPoint.tv_usec == 0) { - freqCheckPoint = now; - } else { - int elapsed = Util::difftvsec(now, freqCheckPoint); - if(elapsed >= 5) { - if(chokeUnchokeCount*1.0/elapsed >= 0.4 - //|| haveCount*1.0/elapsed >= 20.0 - || keepAliveCount*1.0/elapsed >= 1.0) { - throw new DlAbortEx("Flooding detected."); - } else { - chokeUnchokeCount = 0; - haveCount = 0; - keepAliveCount = 0; - freqCheckPoint = now; - } + if(freqCheckPoint.elapsed(FLOODING_CHECK_INTERVAL)) { + if(chokeUnchokeCount*1.0/FLOODING_CHECK_INTERVAL >= 0.4 + //|| haveCount*1.0/elapsed >= 20.0 + || keepAliveCount*1.0/FLOODING_CHECK_INTERVAL >= 1.0) { + throw new DlAbortEx("Flooding detected."); + } else { + chokeUnchokeCount = 0; + haveCount = 0; + keepAliveCount = 0; + freqCheckPoint.reset(); } } } @@ -160,21 +150,13 @@ void PeerInteractionCommand::checkLongTimePeerChoking() { if(e->torrentMan->downloadComplete()) { return; } - struct timeval now; - gettimeofday(&now, NULL); - if(chokeCheckPoint.tv_sec == 0 && chokeCheckPoint.tv_usec == 0) { - if(peer->amInterested && peer->peerChoking) { - chokeCheckPoint = now; + if(peer->amInterested && peer->peerChoking) { + if(chokeCheckPoint.elapsed(MAX_PEER_CHOKING_INTERVAL)) { + logger->info("CUID#%d - The peer is choking too long.", cuid); + peer->snubbing = true; } } else { - if(peer->amInterested && peer->peerChoking) { - if(Util::difftvsec(now, chokeCheckPoint) >= MAX_PEER_CHOKING_INTERVAL) { - throw new DlAbortEx("Too long choking."); - } - } else { - chokeCheckPoint.tv_sec = 0; - chokeCheckPoint.tv_usec = 0; - } + chokeCheckPoint.reset(); } } @@ -251,24 +233,19 @@ void PeerInteractionCommand::onAbort(Exception* ex) { } void PeerInteractionCommand::sendKeepAlive() { - if(keepAliveCheckPoint.tv_sec == 0 && keepAliveCheckPoint.tv_usec == 0) { - gettimeofday(&keepAliveCheckPoint, NULL); - } else { - struct timeval now; - gettimeofday(&now, NULL); - if(Util::difftvsec(now, keepAliveCheckPoint) >= 120) { - if(peerInteraction->countMessageInQueue() == 0) { - peerInteraction->addMessage(peerInteraction->createKeepAliveMessage()); - peerInteraction->sendMessages(e->getUploadSpeed()); - } - keepAliveCheckPoint = now; + if(keepAliveCheckPoint.elapsed(KEEP_ALIVE_INTERVAL)) { + if(peerInteraction->countMessageInQueue() == 0) { + peerInteraction->addMessage(peerInteraction->createKeepAliveMessage()); + peerInteraction->sendMessages(e->getUploadSpeed()); } + keepAliveCheckPoint.reset(); } } void PeerInteractionCommand::checkHave() { - e->torrentMan->unadvertisePiece(cuid); - PieceIndexes indexes = e->torrentMan->getAdvertisedPieceIndexes(cuid); + PieceIndexes indexes = + e->torrentMan->getAdvertisedPieceIndexes(cuid, haveCheckTime); + haveCheckTime.reset(); if(indexes.size() >= 20) { if(peer->isFastExtensionEnabled()) { if(e->torrentMan->hasAllPieces()) { diff --git a/src/PeerInteractionCommand.h b/src/PeerInteractionCommand.h index 95356fa1..9de8c9b7 100644 --- a/src/PeerInteractionCommand.h +++ b/src/PeerInteractionCommand.h @@ -25,19 +25,22 @@ #include "PeerAbstractCommand.h" #include "PeerConnection.h" #include "PeerInteraction.h" +#include "Time.h" using namespace std; -#define MAX_PEER_CHOKING_INTERVAL (3*60) +#define MAX_PEER_CHOKING_INTERVAL (1*60) +#define KEEP_ALIVE_INTERVAL 120 class PeerInteractionCommand : public PeerAbstractCommand { private: int sequence; PeerInteraction* peerInteraction; - struct timeval keepAliveCheckPoint; - struct timeval chokeCheckPoint; - struct timeval freqCheckPoint; + Time keepAliveCheckPoint; + Time chokeCheckPoint; + Time freqCheckPoint; + Time haveCheckTime; int chokeUnchokeCount; int haveCount; int keepAliveCount; diff --git a/src/PieceMessage.cc b/src/PieceMessage.cc index 4930204b..26ae4e69 100644 --- a/src/PieceMessage.cc +++ b/src/PieceMessage.cc @@ -59,6 +59,7 @@ void PieceMessage::receivedAction() { peer->addPeerUpload(blockLength); if(!RequestSlot::isNull(slot) && peerInteraction->hasDownloadPiece(slot.getIndex())) { + peer->snubbing = false; //logger->debug("CUID#%d - Latency=%d", cuid, slot.getLatencyInMillis()); peer->updateLatency(slot.getLatencyInMillis()); Piece& piece = peerInteraction->getDownloadPiece(slot.getIndex()); diff --git a/src/RequestSlot.cc b/src/RequestSlot.cc index 3cdd7957..310684ff 100644 --- a/src/RequestSlot.cc +++ b/src/RequestSlot.cc @@ -23,9 +23,7 @@ #include "Util.h" RequestSlot::RequestSlot(int index, int begin, int length, int blockIndex) - :index(index), begin(begin), length(length), blockIndex(blockIndex) { - setDispatchedTime(); -} + :index(index), begin(begin), length(length), blockIndex(blockIndex) {} RequestSlot::RequestSlot(const RequestSlot& requestSlot) { copy(requestSlot); @@ -49,17 +47,15 @@ void RequestSlot::copy(const RequestSlot& requestSlot) { RequestSlot RequestSlot::nullSlot(0, 0, 0, 0); void RequestSlot::setDispatchedTime() { - gettimeofday(&dispatchedTime, NULL); + dispatchedTime.reset(); } bool RequestSlot::isTimeout(int timeoutSec) const { - return getLatencyInMillis() > timeoutSec*1000; + return dispatchedTime.differenceInMillis() > timeoutSec*1000; } int RequestSlot::getLatencyInMillis() const { - struct timeval now; - gettimeofday(&now, NULL); - return Util::difftv(now, dispatchedTime)/1000; + return dispatchedTime.differenceInMillis(); } bool RequestSlot::isNull(const RequestSlot& requestSlot) { diff --git a/src/RequestSlot.h b/src/RequestSlot.h index a7e565ea..a4c02819 100644 --- a/src/RequestSlot.h +++ b/src/RequestSlot.h @@ -23,11 +23,11 @@ #define _D_REQUEST_SLOT_H_ #include "common.h" -#include +#include "Time.h" class RequestSlot { private: - struct timeval dispatchedTime; + Time dispatchedTime; int index; int begin; int length; diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 930b876c..96a5a682 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -34,6 +34,7 @@ SegmentMan::SegmentMan():totalSize(0), isSplittable(true), downloadStarted(false), + errors(0), dir("."), splitter(NULL), diskWriter(NULL) { @@ -241,6 +242,7 @@ void SegmentMan::init() { totalSize = 0; isSplittable = false; downloadStarted = false; + errors = 0; segments.clear(); diskWriter->closeFile(); } diff --git a/src/SegmentMan.h b/src/SegmentMan.h index f14be19f..aee97cde 100644 --- a/src/SegmentMan.h +++ b/src/SegmentMan.h @@ -84,6 +84,11 @@ public: */ string ufilename; + /** + * Represents the number of failures(usually, DlAbortEx) in downloads. + */ + int errors; + const Option* option; SegmentSplitter* splitter; DiskWriter* diskWriter; @@ -91,7 +96,7 @@ public: SegmentMan(); ~SegmentMan(); - // Initializes totalSize, isSplittable, downloadStarted. + // Initializes totalSize, isSplittable, downloadStarted, errors. // Clears command queue. Also, closes diskWriter. void init(); diff --git a/src/SleepCommand.cc b/src/SleepCommand.cc index c6dba6b9..5a71593c 100644 --- a/src/SleepCommand.cc +++ b/src/SleepCommand.cc @@ -23,9 +23,7 @@ #include "Util.h" SleepCommand::SleepCommand(int cuid, DownloadEngine* e, Command* nextCommand, int wait): - Command(cuid), engine(e), nextCommand(nextCommand), wait(wait) { - gettimeofday(&checkPoint, NULL); -} + Command(cuid), engine(e), nextCommand(nextCommand), wait(wait) {} SleepCommand::~SleepCommand() { if(nextCommand != NULL) { @@ -34,9 +32,7 @@ SleepCommand::~SleepCommand() { } bool SleepCommand::execute() { - struct timeval now; - gettimeofday(&now, NULL); - if(Util::difftvsec(now, checkPoint) >= wait) { + if(checkPoint.elapsed(wait)) { engine->commands.push_back(nextCommand); nextCommand = NULL; return true; diff --git a/src/SleepCommand.h b/src/SleepCommand.h index 6d75cd86..06310daa 100644 --- a/src/SleepCommand.h +++ b/src/SleepCommand.h @@ -24,14 +24,14 @@ #include "DownloadEngine.h" #include "Command.h" -#include +#include "Time.h" class SleepCommand:public Command { private: DownloadEngine* engine; Command* nextCommand; int wait; - struct timeval checkPoint; + Time checkPoint; public: SleepCommand(int cuid, DownloadEngine* e, Command* nextCommand, int wait); ~SleepCommand(); diff --git a/src/Time.cc b/src/Time.cc new file mode 100644 index 00000000..e3663c5c --- /dev/null +++ b/src/Time.cc @@ -0,0 +1,70 @@ +/* */ +#include "Time.h" +#include "Util.h" + +Time::Time() { + reset(); +} + +Time::Time(const Time& time) { + tv = time.tv; +} + +Time::~Time() {} + +Time& Time::operator=(const Time& time) { + if(this != &time) { + tv = time.tv; + } + return *this; +} + +void Time::reset() { + gettimeofday(&tv, 0); +} + +struct timeval Time::getCurrentTime() const { + struct timeval now; + gettimeofday(&now, 0); + return now; +} + +bool Time::elapsed(int sec) const { + return Util::difftvsec(getCurrentTime(), tv) >= sec; +} + +bool Time::elapsedInMillis(int millis) const { + return Util::difftv(getCurrentTime(), tv)/1000 >= millis; +} + +bool Time::isNewer(const Time& time) const { + return Util::difftvsec(this->tv, time.tv) > 0; +} + +int Time::difference() const { + return Util::difftvsec(getCurrentTime(), tv); +} + +long long int Time::differenceInMillis() const { + return Util::difftv(getCurrentTime(), tv)/1000; +} diff --git a/src/Time.h b/src/Time.h new file mode 100644 index 00000000..1a9eb470 --- /dev/null +++ b/src/Time.h @@ -0,0 +1,71 @@ +/* */ +#ifndef _D_TIME_H_ +#define _D_TIME_H_ + +#include "common.h" +#include + +class Time { +private: + struct timeval tv; + + struct timeval getCurrentTime() const; +public: + // The time value is initialized so that it represents the time at which + // this object was created. + Time(); + Time(const Time& time); + Time& operator=(const Time& time); + + ~Time(); + + // Makes this object's time value up to date. + void reset(); + + bool elapsed(int sec) const; + + bool elapsedInMillis(int millis) const; + + int difference() const; + long long int differenceInMillis() const; + + // Returns true if this object's time value is zero. + bool isZero() const { return tv.tv_sec == 0 && tv.tv_usec == 0; } + + long long int getTimeInMicros() const { + return tv.tv_sec*1000*1000+tv.tv_usec; + } + + long long int getTimeInMillis() const { + return tv.tv_sec*1000+tv.tv_usec/1000; + } + + // Returns this object's time value in seconds. + int getTime() const { + return tv.tv_sec; + } + + bool isNewer(const Time& time) const; +}; + +#endif // _D_TIME_H_ diff --git a/src/TorrentAutoSaveCommand.cc b/src/TorrentAutoSaveCommand.cc index 54471a6c..9d500671 100644 --- a/src/TorrentAutoSaveCommand.cc +++ b/src/TorrentAutoSaveCommand.cc @@ -22,21 +22,13 @@ #include "TorrentAutoSaveCommand.h" #include "Util.h" -TorrentAutoSaveCommand::TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval):Command(cuid), e(e), interval(interval) { - checkPoint.tv_sec = 0; - checkPoint.tv_usec = 0; -} +TorrentAutoSaveCommand::TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval):Command(cuid), e(e), interval(interval) {} TorrentAutoSaveCommand::~TorrentAutoSaveCommand() {} bool TorrentAutoSaveCommand::execute() { - if(e->torrentMan->downloadComplete() || e->torrentMan->isHalt()) { - return true; - } - struct timeval now; - gettimeofday(&now, NULL); - if(Util::difftvsec(now, checkPoint) >= interval) { - checkPoint = now; + if(checkPoint.elapsed(interval) || e->torrentMan->isHalt()) { + checkPoint.reset(); e->torrentMan->save(); if(e->torrentMan->isHalt()) { return true; diff --git a/src/TorrentAutoSaveCommand.h b/src/TorrentAutoSaveCommand.h index 6f6d99fa..a770f4c2 100644 --- a/src/TorrentAutoSaveCommand.h +++ b/src/TorrentAutoSaveCommand.h @@ -24,12 +24,13 @@ #include "Command.h" #include "TorrentDownloadEngine.h" +#include "Time.h" class TorrentAutoSaveCommand : public Command { private: TorrentDownloadEngine* e; int interval; - struct timeval checkPoint; + Time checkPoint; public: TorrentAutoSaveCommand(int cuid, TorrentDownloadEngine* e, int interval); ~TorrentAutoSaveCommand(); diff --git a/src/TorrentDownloadEngine.cc b/src/TorrentDownloadEngine.cc index b029c1f2..f5772c95 100644 --- a/src/TorrentDownloadEngine.cc +++ b/src/TorrentDownloadEngine.cc @@ -57,9 +57,9 @@ void TorrentDownloadEngine::initStatistics() { downloadSpeed = 0; uploadSpeed = 0; lastElapsed = 0; - gettimeofday(&cp[0], NULL); - gettimeofday(&cp[1], NULL); - gettimeofday(&startup, NULL); + cp[0].reset(); + cp[1].reset(); + startup.reset(); sessionDownloadLengthArray[0] = 0; sessionDownloadLengthArray[1] = 0; sessionUploadLengthArray[0] = 0; @@ -82,9 +82,7 @@ int TorrentDownloadEngine::calculateSpeed(long long int sessionLength, int elaps } void TorrentDownloadEngine::calculateStatistics() { - struct timeval now; - gettimeofday(&now, NULL); - int elapsed = Util::difftvsec(now, cp[currentCp]); + int elapsed = cp[currentCp].difference(); sessionDownloadLengthArray[0] += torrentMan->getDeltaDownloadLength(); sessionUploadLengthArray[0] += torrentMan->getDeltaUploadLength(); @@ -111,8 +109,11 @@ void TorrentDownloadEngine::calculateStatistics() { } if(elapsed-lastElapsed >= 1) { - avgSpeed = calculateSpeed(sessionDownloadLength, - Util::difftvsec(now, startup)); + int elapsedFromStartup = startup.difference(); + if(elapsedFromStartup > 0) { + avgSpeed = calculateSpeed(sessionDownloadLength, + elapsedFromStartup); + } if(avgSpeed < 0) { avgSpeed = 0; } else if(avgSpeed != 0) { @@ -126,7 +127,7 @@ void TorrentDownloadEngine::calculateStatistics() { if(elapsed > 15) { sessionDownloadLengthArray[currentCp] = 0; sessionUploadLengthArray[currentCp] = 0; - cp[currentCp] = now; + cp[currentCp].reset(); lastElapsed = 0; currentCp = currentCp ? 0 : 1; } diff --git a/src/TorrentDownloadEngine.h b/src/TorrentDownloadEngine.h index ba11fd2b..facbedf7 100644 --- a/src/TorrentDownloadEngine.h +++ b/src/TorrentDownloadEngine.h @@ -24,6 +24,7 @@ #include "DownloadEngine.h" #include "TorrentMan.h" +#include "Time.h" class TorrentDownloadEngine : public DownloadEngine { private: @@ -32,7 +33,7 @@ private: void initStatistics(); void calculateStatistics(); protected: - struct timeval cp[2]; + Time cp[2]; long long int sessionDownloadLengthArray[2]; long long int sessionUploadLengthArray[2]; int currentCp; @@ -43,7 +44,7 @@ protected: long long int selectedDownloadLengthDiff; long long int selectedTotalLength; // The time when startup - struct timeval startup; + Time startup; // The number of bytes downloaded since startup long long int sessionDownloadLength; // The average speed(bytes per second) since startup diff --git a/src/TorrentMan.cc b/src/TorrentMan.cc index 2a86ece9..b520224b 100644 --- a/src/TorrentMan.cc +++ b/src/TorrentMan.cc @@ -130,9 +130,6 @@ void TorrentMan::deleteOldErrorPeers() { } Peer* TorrentMan::getPeer() const { - if(connections > MAX_PEER_UPDATE) { - return Peer::nullPeer; - } for(Peers::const_iterator itr = peers.begin(); itr != peers.end(); itr++) { Peer* p = *itr; if(p->cuid == 0 && p->error < MAX_PEER_ERROR) { @@ -401,8 +398,8 @@ void TorrentMan::readFileEntry(FileEntries& fileEntries, Directory** pTopDir, co } void TorrentMan::setupInternal1(const string& metaInfoFile) { - peerId = "-A2****-"; - for(int i = 0; i < 12; i++) { + peerId = "-aria2-"; + for(int i = 0; i < 20-(int)peerId.size(); i++) { peerId += Util::itos((int)(((double)10)*random()/(RAND_MAX+1.0))); } @@ -652,3 +649,21 @@ void TorrentMan::onDownloadComplete() { finishSelectiveDownloadingMode(); } } + +void TorrentMan::advertisePiece(int cuid, int index) { + HaveEntry entry(cuid, index); + haves.push_back(entry); +}; + +PieceIndexes TorrentMan::getAdvertisedPieceIndexes(int myCuid, + Time lastCheckTime) const { + PieceIndexes indexes; + for(Haves::const_iterator itr = haves.begin(); itr != haves.end(); itr++) { + const Haves::value_type& have = *itr; + if(have.cuid == myCuid || lastCheckTime.isNewer(have.registeredTime)) { + continue; + } + indexes.push_back(have.index); + } + return indexes; + } diff --git a/src/TorrentMan.h b/src/TorrentMan.h index 77ecea9e..13a7d303 100644 --- a/src/TorrentMan.h +++ b/src/TorrentMan.h @@ -33,6 +33,7 @@ #include "FileEntry.h" #include "DiskAdaptor.h" #include "Request.h" +#include "Time.h" #include #include #include @@ -42,16 +43,26 @@ using namespace std; #define INFO_HASH_LENGTH 20 #define PEER_ID_LENGTH 20 -#define DEFAULT_ANNOUNCE_INTERVAL 300 -#define DEFAULT_ANNOUNCE_MIN_INTERVAL 300 +#define DEFAULT_ANNOUNCE_INTERVAL 1800 +#define DEFAULT_ANNOUNCE_MIN_INTERVAL 1800 #define MAX_PEERS 55 #define MAX_PEER_UPDATE 15 #define MAX_PEER_LIST_SIZE 250 #define END_GAME_PIECE_NUM 20 #define MAX_PEER_ERROR 5 +class HaveEntry { +public: + int cuid; + int index; + Time registeredTime; + HaveEntry(int cuid, int index): + cuid(cuid), + index(index) {} +}; + typedef deque Peers; -typedef multimap Haves; +typedef deque Haves; typedef deque PieceIndexes; typedef deque Pieces; @@ -164,26 +175,9 @@ public: string getPieceHash(int index) const; - void advertisePiece(int cuid, int index) { - Haves::value_type vt(cuid, index); - haves.insert(vt); - } + void advertisePiece(int cuid, int index); - PieceIndexes getAdvertisedPieceIndexes(int myCuid) const { - PieceIndexes indexes; - for(Haves::const_iterator itr = haves.begin(); itr != haves.end(); itr++) { - const Haves::value_type& have = *itr; - if(have.first == myCuid) { - continue; - } - indexes.push_back(have.second); - } - return indexes; - } - - void unadvertisePiece(int cuid) { - haves.erase(cuid); - } + PieceIndexes getAdvertisedPieceIndexes(int myCuid, Time lastCheckTime) const; long long int getTotalLength() const { return totalLength; } void setTotalLength(long long int length) { totalLength = length; } diff --git a/src/TrackerWatcherCommand.cc b/src/TrackerWatcherCommand.cc index 426119ab..a4875114 100644 --- a/src/TrackerWatcherCommand.cc +++ b/src/TrackerWatcherCommand.cc @@ -26,19 +26,21 @@ TrackerWatcherCommand::TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e, int interval): - Command(cuid), e(e), interval(interval) { - checkPoint.tv_sec = 0; - checkPoint.tv_usec = 0; -} + Command(cuid), e(e), interval(interval) {} TrackerWatcherCommand::~TrackerWatcherCommand() {} bool TrackerWatcherCommand::execute() { - struct timeval now; - gettimeofday(&now, NULL); + if(e->segmentMan->errors > 0) { + // we assume the tracker request has failed. + e->torrentMan->trackers = 0; + e->segmentMan->init(); + } if(e->torrentMan->trackers == 0 && - (Util::difftvsec(now, checkPoint) >= interval || e->torrentMan->isHalt())) { - checkPoint = now; + (e->torrentMan->connections < MAX_PEER_UPDATE || + e->torrentMan->isHalt() || + checkPoint.elapsed(interval))) { + checkPoint.reset(); e->torrentMan->req->resetTryCount(); int numWant = 50; if(e->torrentMan->connections >= MIN_PEERS || e->torrentMan->isHalt()) { @@ -90,7 +92,7 @@ bool TrackerWatcherCommand::execute() { Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(e->torrentMan->getNewCuid(), e->torrentMan->req, e); e->commands.push_back(command); e->torrentMan->trackers++; - logger->info("CUID#%d - creating new tracker request command #%d", cuid, + logger->info("CUID#%d - Creating new tracker request command #%d", cuid, command->getCuid()); if(e->torrentMan->isHalt()) { return true; diff --git a/src/TrackerWatcherCommand.h b/src/TrackerWatcherCommand.h index 0597a0a6..37708456 100644 --- a/src/TrackerWatcherCommand.h +++ b/src/TrackerWatcherCommand.h @@ -24,7 +24,7 @@ #include "Command.h" #include "TorrentDownloadEngine.h" -#include +#include "Time.h" #define MIN_PEERS 15 @@ -32,7 +32,7 @@ class TrackerWatcherCommand : public Command { private: TorrentDownloadEngine* e; int interval; - struct timeval checkPoint; + Time checkPoint; public: TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e, int interval); ~TrackerWatcherCommand(); diff --git a/src/main.cc b/src/main.cc index b7f75a6e..59f77978 100644 --- a/src/main.cc +++ b/src/main.cc @@ -647,8 +647,8 @@ int main(int argc, char* argv[]) { if(!torrentFile.empty() || followTorrent && readyToTorrentMode) { try { //op->put(PREF_MAX_TRIES, "0"); - setSignalHander(SIGINT, torrentHandler, SA_ONESHOT); - setSignalHander(SIGTERM, torrentHandler, SA_ONESHOT); + setSignalHander(SIGINT, torrentHandler, SA_RESETHAND); + setSignalHander(SIGTERM, torrentHandler, SA_RESETHAND); Request* req = new Request(); req->isTorrent = true;