Prechádzať zdrojové kódy

2006-06-12 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

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.

Tatsuhiro Tsujikawa 19 rokov pred
rodič
commit
d380b7b6ab

+ 152 - 0
ChangeLog

@@ -1,3 +1,155 @@
+2006-06-12  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+	
+	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  <tujikawa at rednoah dot com>
 
 	To fix the bug that causes segfaults if a tracker returns a zero-length

+ 10 - 10
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 <tujikawa@rednoah.com>.
 #
@@ -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'`\\"
 

+ 1 - 1
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])

+ 1 - 1
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
 

+ 5 - 26
src/AbstractCommand.cc

@@ -27,7 +27,6 @@
 #include "message.h"
 #include "SleepCommand.h"
 #include "prefs.h"
-#include <sys/time.h>
 
 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));

+ 4 - 4
src/AbstractCommand.h

@@ -26,13 +26,12 @@
 #include "Request.h"
 #include "DownloadEngine.h"
 #include "SegmentMan.h"
-#include <sys/time.h>
+#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;

+ 17 - 21
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);
   }
 }
 

+ 3 - 2
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;

+ 5 - 15
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);

+ 2 - 3
src/DownloadCommand.h

@@ -24,14 +24,13 @@
 
 #include "AbstractCommand.h"
 #include "TransferEncoding.h"
-#include <sys/time.h>
-#include <string>
+#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);

+ 4 - 7
src/DownloadEngine.cc

@@ -22,6 +22,7 @@
 #include "DownloadEngine.h"
 #include "Util.h"
 #include "LogFactory.h"
+#include "Time.h"
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -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();

+ 0 - 2
src/DownloadEngine.h

@@ -28,8 +28,6 @@
 #include "common.h"
 #include "Logger.h"
 #include "Option.h"
-#include <sys/time.h>
-#include <deque>
 
 typedef deque<Socket*> Sockets;
 typedef deque<Command*> Commands;

+ 2 - 1
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@\

+ 4 - 2
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@

+ 1 - 0
src/Peer.cc

@@ -59,6 +59,7 @@ void Peer::resetStatus() {
   resetDeltaDownload();
   chokingRequired = true;
   optUnchoking = false;
+  snubbing = false;
   fastExtensionEnabled = false;
   latency = DEFAULT_LATENCY;
   fastSet.clear();

+ 4 - 2
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);
   

+ 2 - 28
src/PeerAbstractCommand.cc

@@ -25,7 +25,6 @@
 #include "Util.h"
 #include "message.h"
 #include "prefs.h"
-#include <sys/time.h>
 
 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();

+ 2 - 4
src/PeerAbstractCommand.h

@@ -25,13 +25,11 @@
 #include "Command.h"
 #include "Request.h"
 #include "TorrentDownloadEngine.h"
-#include <sys/time.h>
+#include "Time.h"
 
 class PeerAbstractCommand : public Command {
 private:
-  void updateCheckPoint();
-  bool isTimeoutDetected();
-  struct timeval checkPoint;
+  Time checkPoint;
   int timeout;
 protected:
   TorrentDownloadEngine* e;

+ 17 - 29
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);

+ 2 - 1
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;

+ 1 - 0
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()) ||

+ 1 - 1
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<RequestSlot> RequestSlots;

+ 27 - 50
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()) {

+ 7 - 4
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;

+ 1 - 0
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());

+ 4 - 8
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) {

+ 2 - 2
src/RequestSlot.h

@@ -23,11 +23,11 @@
 #define _D_REQUEST_SLOT_H_
 
 #include "common.h"
-#include <sys/time.h>
+#include "Time.h"
 
 class RequestSlot {
 private:
-  struct timeval dispatchedTime;
+  Time dispatchedTime;
   int index;
   int begin;
   int length;

+ 2 - 0
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();
 }

+ 6 - 1
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();
 

+ 2 - 6
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;

+ 2 - 2
src/SleepCommand.h

@@ -24,14 +24,14 @@
 
 #include "DownloadEngine.h"
 #include "Command.h"
-#include <sys/time.h>
+#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();

+ 70 - 0
src/Time.cc

@@ -0,0 +1,70 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* copyright --> */
+#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;
+}

+ 71 - 0
src/Time.h

@@ -0,0 +1,71 @@
+/* <!-- copyright */
+/*
+ * aria2 - a simple utility for downloading files faster
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+/* copyright --> */
+#ifndef _D_TIME_H_
+#define _D_TIME_H_
+
+#include "common.h"
+#include <sys/time.h>
+
+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_

+ 3 - 11
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;

+ 2 - 1
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();

+ 10 - 9
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;
   }

+ 3 - 2
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

+ 20 - 5
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;
+  }

+ 16 - 22
src/TorrentMan.h

@@ -33,6 +33,7 @@
 #include "FileEntry.h"
 #include "DiskAdaptor.h"
 #include "Request.h"
+#include "Time.h"
 #include <deque>
 #include <map>
 #include <string>
@@ -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<Peer*> Peers;
-typedef multimap<int, int> Haves;
+typedef deque<HaveEntry> Haves;
 typedef deque<int> PieceIndexes;
 typedef deque<Piece> 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; }

+ 11 - 9
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;

+ 2 - 2
src/TrackerWatcherCommand.h

@@ -24,7 +24,7 @@
 
 #include "Command.h"
 #include "TorrentDownloadEngine.h"
-#include <sys/time.h>
+#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();

+ 2 - 2
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;