Forráskód Böngészése

2006-09-19 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	To rewrite segment download mechanism for HTTP/FTP download.
	Use BitfieldMan to manage segment download.
	* src/HttpResponseCommand.h
	(executeInternal): Pass the reference of segment.
	* src/AbstractCommand.cc
	(prepareForRetry): Call segmentMan->cancelSegment here.
	(onAbort): Call segmentMan->cancelSegment here.
	* src/HttpDownloadCommand.cc
	(prepareForNextSegment): New function.
	* src/DownloadEngineFactory.cc
	(newConsoleEngine): Removed splitter.
	(newTorrentConsoleEngine): Removed splitter.
	* src/Request.h
	(segment): Renamed from seg.
	* src/FtpInitiateConnectionCommand.h
	(executeInternal): Pass the reference of segment.
	* src/AbstractCommand.h
	(executeInternal): Pass the reference of segment.
	* src/pref.h
	(PREF_SEGMENT_SIZE): New definition.
	* src/HttpProxyRequestCommand.h
	(executeInternal): Pass the reference of segment.
	* src/HttpResponseCommand.cc
	(checkResponse): Allowed status 206 when a request range starts 
0.
	(handleDefaultEncoding): Rewritten the code related to Segment.
	(handleOtherEncoding): Rewritten the code related to Segment.
	* src/SegmentMan.h
	(SegmentEntry): New class.
	(SegmentEntries): New type definition.
	(bitfield): New variable.
	(usedSegmentEntries): New variable.
	(onNullBitfield): New function.
	(checkoutSegment): New function.
	(segments): Removed.
	(splitter): Removed.
	(unregisterId): Removed.
	(getSegment): New function(overload)
	(getDownloadedSize): Removed.
	(cancelSegment): New function.
	(completeSegment): New function.
	(initBitfield): New function.
	(hasSegment): New function.
	(getDownloadLength): New function.
	* src/BitfieldMan.h
	(getStartIndex): New function.
	(getEndIndex): New function.
	(getMissingUnusedIndex): New function(overload).
	(getSparseMissingUnusedIndex): New function.	
	* src/BitfieldMan.cc
	(getMissingIndexRandomly): Handle the last byte of bitfield 
properly.
	(getMissingUnusedIndex): New function(overload).
	(Range): New class.
	(getStartIndex): New function.
	(getEndIndex): New function.
	(getSparseMissingUnusedIndex): New function.
	(isBitSetInternal): Return false if the given index is less than 
0.
	* src/HttpInitiateConnectionCommand.h
	(executeInternal): Pass the reference of segment.
	* src/FtpNegotiateCommand.h
	(executeInternal): Pass the reference of segment.
	* src/FtpNegotiateCommand.cc
	(recvSize): Initialize bitfield here.
	* src/FtpTunnelResponseCommand.h
	(executeInternal): Pass the reference of segment.
	* src/HttpConnection.cc
	(createRequest): Rewritten range header processing.
	* src/DownloadCommand.h
	(executeInternal): Pass the reference of segment.
	(prepareForRetry): Removed.
	(prepareForNextSegment): Added an argument segment. Made it a 
virtual
	function.
	* src/main.cc
	(main): Set the initial value of PREF_SEGMENT_SIZE to 1MB.
	* src/SegmentMan.cc
	(SegmentMan): Added bitfield. Removed splitter.
	(~SegmentMan): Added bitfield. Removed splitter.
	(unregisterId): Removed.
	(getSegment): Rewritten.
	(updateSegment): Rewritten.
	(save): Rewritten.
	(read): Rewritten.
	(finished): Rewritten.
	(getDownloadedSize): Removed.
	(initBitfield): New function.
	(FindSegmentEntryByIndex): New function object.
	(FindSegmentEntryByCuid): New function object.
	(checkoutSegment): New function.
	(onNullBitfield): New function.
	(getSegment): New function(overload).
	(CancelSegment): New function object.
	(cancelSegment): New function.
	(completeSegment): New function.
	(hasSegment): New function.
	(getDownloadLength): New function.
	* src/FtpInitiateConnectionCommand.cc
	(executeInternal): Load .aria2 file after hostname resolution 
finishes.
	* src/Segment.h: Rewritten.
	* src/Segment.cc (operator<<): New function.
	* src/HttpDownloadCommand.h
	(prepareForNextSegment): New function.
	* src/Request.cc
	(resetUrl): Made segment null.
	* src/DownloadEngine.cc
	(~DownloadEngine): Call cleanQueue before deleting segmentMan.
	* src/HttpProxyRequestCommand.h
	(executeInternal): Pass the reference of segment.
	* src/DownloadCommand.cc
	(executeInternal): Rewritten the code related to Segment.
	(prepareForRetry): Removed.
	(prepareForNextSegment): Rewritten.
	* src/FtpTunnelResponseCommand.h
	(executeInternal): Pass the reference of segment.
	
	To add HTTP 1.1 persistent connection support(experimental)
	* src/HttpRequestCommand.cc
	(executeInternal): Disable keep alive if it is disabled by
	configuration.
	* src/Request.h
	(keepAlive): New variable.
	(isKeepAlive): New function.
	(setKeepAlive): New function.
	* src/pref.h
	(PREF_HTTP_KEEP_ALIVE): New definition.
	* src/HttpResponseCommand.cc
	(executeInternal): Check the remote server supports keep alive.
	* src/HttpConnection.cc
	(createRequest): Send "Connection: close" only if keep alive is
	disabled.
	* src/main.cc
	(main):
	Set the initial value(false) of PREF_KEEP_ALIVE to false.

	To add max download speed limit:
	* src/pref.h
	(PREF_MAX_SPEED_LIMIT): New definition.
	* src/PeerInteractionCommand.cc
	(executeInternal): Added max download speed limit. Not tested 
yet.
	* src/SegmentMan.h
	(PeerStats): New type definition.
	(peerStats): New variable.
	(registerPeerStat): New function.
	(FindPeerStat): New function object.
	(getPeerStat): New function.
	(calculateDownloadSpeed): New function.
	* src/SpeedCalc.h: New class.
	* src/SpeedCalc.cc: New class.
	* src/main.cc
	(main):
	Set the initial value of PREF_MAX_SPEED_LIMIT to 0(which means 
the
	download speed is not restricted).
	* src/PeerStat.h: New class.
	* src/SegmentMan.cc
	(registerPeerStat): New function.
	(calculateDownloadSpeed): New function.
	* src/DownloadCommand.cc
	(STARTUP_IDLE_TIME): New definition.
	(DownloadCommand): Register peerStat to segmentMan. Call 
peerStat->
	downloadStart.
	(~DownloadCommand): Call peerStat->downloadStop.
	(executeInternal): Added download speed limitter. Rewritten 
lowest
	speed limitter.

	* src/HttpConnection.cc
	(receiveResponse): Fixed: eohIndex[headerBuf] -> 
headerBuf[eohIndex].
	
	* src/AbstractCommand.cc
	(resolveHostname): Throw DlAbortEx if a name resolution failes.
	Added hostname to the error message.
	
	* src/ConsoleDownloadEngine.cc
	(calculateStatistics): Initialize psize with dlSize.

	* src/PieceMessage.cc
	(receivedAction): Do not call peerInteraction->abortPiece here.
	(onGotWrongPiece): Call peerInteraction->abortPiece here.

	* src/BitfieldMan.h
	(clearAllUseBit): New function.
	(setAllUseBit): New function.
	* src/BitfieldMan.cc
	(clearAllBit): Do not clear useBitfield here.
	(clearAllUseBit): New function.
	(setAllUseBit): New function.
	* src/Piece.cc
	(clearAllBlock): Call bitfield->clearAllUseBit().
Tatsuhiro Tsujikawa 19 éve
szülő
commit
2fb9b5be97
55 módosított fájl, 1268 hozzáadás és 334 törlés
  1. 188 0
      ChangeLog
  2. 7 1
      TODO
  3. 10 10
      configure
  4. 1 1
      configure.ac
  5. 12 7
      src/AbstractCommand.cc
  6. 1 1
      src/AbstractCommand.h
  7. 100 3
      src/BitfieldMan.cc
  8. 14 0
      src/BitfieldMan.h
  9. 2 1
      src/ConsoleDownloadEngine.cc
  10. 62 29
      src/DownloadCommand.cc
  11. 2 3
      src/DownloadCommand.h
  12. 1 1
      src/DownloadEngine.cc
  13. 0 5
      src/DownloadEngineFactory.cc
  14. 1 1
      src/FtpConnection.cc
  15. 2 1
      src/FtpDownloadCommand.cc
  16. 12 12
      src/FtpInitiateConnectionCommand.cc
  17. 1 1
      src/FtpInitiateConnectionCommand.h
  18. 3 1
      src/FtpNegotiationCommand.cc
  19. 1 1
      src/FtpNegotiationCommand.h
  20. 1 1
      src/FtpTunnelRequestCommand.cc
  21. 1 1
      src/FtpTunnelRequestCommand.h
  22. 1 1
      src/FtpTunnelResponseCommand.cc
  23. 1 1
      src/FtpTunnelResponseCommand.h
  24. 13 4
      src/HttpConnection.cc
  25. 19 4
      src/HttpDownloadCommand.cc
  26. 2 0
      src/HttpDownloadCommand.h
  27. 1 1
      src/HttpInitiateConnectionCommand.cc
  28. 1 1
      src/HttpInitiateConnectionCommand.h
  29. 1 1
      src/HttpProxyRequestCommand.cc
  30. 1 1
      src/HttpProxyRequestCommand.h
  31. 1 1
      src/HttpProxyResponseCommand.cc
  32. 1 1
      src/HttpProxyResponseCommand.h
  33. 7 4
      src/HttpRequestCommand.cc
  34. 1 1
      src/HttpRequestCommand.h
  35. 21 12
      src/HttpResponseCommand.cc
  36. 1 1
      src/HttpResponseCommand.h
  37. 4 5
      src/Makefile.am
  38. 38 45
      src/Makefile.in
  39. 5 1
      src/PeerInteractionCommand.cc
  40. 90 0
      src/PeerStat.h
  41. 1 0
      src/Piece.cc
  42. 1 1
      src/PieceMessage.cc
  43. 2 5
      src/Request.cc
  44. 5 3
      src/Request.h
  45. 31 0
      src/Segment.cc
  46. 40 21
      src/Segment.h
  47. 271 100
      src/SegmentMan.cc
  48. 97 33
      src/SegmentMan.h
  49. 82 0
      src/SpeedCalc.cc
  50. 59 0
      src/SpeedCalc.h
  51. 3 1
      src/main.cc
  52. 7 1
      src/prefs.h
  53. 28 0
      test/BitfieldManTest.cc
  54. 3 1
      test/Makefile.am
  55. 7 2
      test/Makefile.in

+ 188 - 0
ChangeLog

@@ -1,3 +1,191 @@
+2006-09-19  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	To rewrite segment download mechanism for HTTP/FTP download.
+	Use BitfieldMan to manage segment download.
+	* src/HttpResponseCommand.h
+	(executeInternal): Pass the reference of segment.
+	* src/AbstractCommand.cc
+	(prepareForRetry): Call segmentMan->cancelSegment here.
+	(onAbort): Call segmentMan->cancelSegment here.
+	* src/HttpDownloadCommand.cc
+	(prepareForNextSegment): New function.
+	* src/DownloadEngineFactory.cc
+	(newConsoleEngine): Removed splitter.
+	(newTorrentConsoleEngine): Removed splitter.
+	* src/Request.h
+	(segment): Renamed from seg.
+	* src/FtpInitiateConnectionCommand.h
+	(executeInternal): Pass the reference of segment.
+	* src/AbstractCommand.h
+	(executeInternal): Pass the reference of segment.
+	* src/pref.h
+	(PREF_SEGMENT_SIZE): New definition.
+	* src/HttpProxyRequestCommand.h
+	(executeInternal): Pass the reference of segment.
+	* src/HttpResponseCommand.cc
+	(checkResponse): Allowed status 206 when a request range starts 0.
+	(handleDefaultEncoding): Rewritten the code related to Segment.
+	(handleOtherEncoding): Rewritten the code related to Segment.
+	* src/SegmentMan.h
+	(SegmentEntry): New class.
+	(SegmentEntries): New type definition.
+	(bitfield): New variable.
+	(usedSegmentEntries): New variable.
+	(onNullBitfield): New function.
+	(checkoutSegment): New function.
+	(segments): Removed.
+	(splitter): Removed.
+	(unregisterId): Removed.
+	(getSegment): New function(overload)
+	(getDownloadedSize): Removed.
+	(cancelSegment): New function.
+	(completeSegment): New function.
+	(initBitfield): New function.
+	(hasSegment): New function.
+	(getDownloadLength): New function.
+	* src/BitfieldMan.h
+	(getStartIndex): New function.
+	(getEndIndex): New function.
+	(getMissingUnusedIndex): New function(overload).
+	(getSparseMissingUnusedIndex): New function.	
+	* src/BitfieldMan.cc
+	(getMissingIndexRandomly): Handle the last byte of bitfield properly.
+	(getMissingUnusedIndex): New function(overload).
+	(Range): New class.
+	(getStartIndex): New function.
+	(getEndIndex): New function.
+	(getSparseMissingUnusedIndex): New function.
+	(isBitSetInternal): Return false if the given index is less than 0.
+	* src/HttpInitiateConnectionCommand.h
+	(executeInternal): Pass the reference of segment.
+	* src/FtpNegotiateCommand.h
+	(executeInternal): Pass the reference of segment.
+	* src/FtpNegotiateCommand.cc
+	(recvSize): Initialize bitfield here.
+	* src/FtpTunnelResponseCommand.h
+	(executeInternal): Pass the reference of segment.
+	* src/HttpConnection.cc
+	(createRequest): Rewritten range header processing.
+	* src/DownloadCommand.h
+	(executeInternal): Pass the reference of segment.
+	(prepareForRetry): Removed.
+	(prepareForNextSegment): Added an argument segment. Made it a virtual
+	function.
+	* src/main.cc
+	(main): Set the initial value of PREF_SEGMENT_SIZE to 1MB.
+	* src/SegmentMan.cc
+	(SegmentMan): Added bitfield. Removed splitter.
+	(~SegmentMan): Added bitfield. Removed splitter.
+	(unregisterId): Removed.
+	(getSegment): Rewritten.
+	(updateSegment): Rewritten.
+	(save): Rewritten.
+	(read): Rewritten.
+	(finished): Rewritten.
+	(getDownloadedSize): Removed.
+	(initBitfield): New function.
+	(FindSegmentEntryByIndex): New function object.
+	(FindSegmentEntryByCuid): New function object.
+	(checkoutSegment): New function.
+	(onNullBitfield): New function.
+	(getSegment): New function(overload).
+	(CancelSegment): New function object.
+	(cancelSegment): New function.
+	(completeSegment): New function.
+	(hasSegment): New function.
+	(getDownloadLength): New function.
+	* src/FtpInitiateConnectionCommand.cc
+	(executeInternal): Load .aria2 file after hostname resolution finishes.
+	* src/Segment.h: Rewritten.
+	* src/Segment.cc (operator<<): New function.
+	* src/HttpDownloadCommand.h
+	(prepareForNextSegment): New function.
+	* src/Request.cc
+	(resetUrl): Made segment null.
+	* src/DownloadEngine.cc
+	(~DownloadEngine): Call cleanQueue before deleting segmentMan.
+	* src/HttpProxyRequestCommand.h
+	(executeInternal): Pass the reference of segment.
+	* src/DownloadCommand.cc
+	(executeInternal): Rewritten the code related to Segment.
+	(prepareForRetry): Removed.
+	(prepareForNextSegment): Rewritten.
+	* src/FtpTunnelResponseCommand.h
+	(executeInternal): Pass the reference of segment.
+	
+	To add HTTP 1.1 persistent connection support(experimental)
+	* src/HttpRequestCommand.cc
+	(executeInternal): Disable keep alive if it is disabled by
+	configuration.
+	* src/Request.h
+	(keepAlive): New variable.
+	(isKeepAlive): New function.
+	(setKeepAlive): New function.
+	* src/pref.h
+	(PREF_HTTP_KEEP_ALIVE): New definition.
+	* src/HttpResponseCommand.cc
+	(executeInternal): Check the remote server supports keep alive.
+	* src/HttpConnection.cc
+	(createRequest): Send "Connection: close" only if keep alive is
+	disabled.
+	* src/main.cc
+	(main):
+	Set the initial value(false) of PREF_KEEP_ALIVE to false.
+
+	To add max download speed limit:
+	* src/pref.h
+	(PREF_MAX_SPEED_LIMIT): New definition.
+	* src/PeerInteractionCommand.cc
+	(executeInternal): Added max download speed limit. Not tested yet.
+	* src/SegmentMan.h
+	(PeerStats): New type definition.
+	(peerStats): New variable.
+	(registerPeerStat): New function.
+	(FindPeerStat): New function object.
+	(getPeerStat): New function.
+	(calculateDownloadSpeed): New function.
+	* src/SpeedCalc.h: New class.
+	* src/SpeedCalc.cc: New class.
+	* src/main.cc
+	(main):
+	Set the initial value of PREF_MAX_SPEED_LIMIT to 0(which means the
+	download speed is not restricted).
+	* src/PeerStat.h: New class.
+	* src/SegmentMan.cc
+	(registerPeerStat): New function.
+	(calculateDownloadSpeed): New function.
+	* src/DownloadCommand.cc
+	(STARTUP_IDLE_TIME): New definition.
+	(DownloadCommand): Register peerStat to segmentMan. Call peerStat->
+	downloadStart.
+	(~DownloadCommand): Call peerStat->downloadStop.
+	(executeInternal): Added download speed limitter. Rewritten lowest
+	speed limitter.
+
+	* src/HttpConnection.cc
+	(receiveResponse): Fixed: eohIndex[headerBuf] -> headerBuf[eohIndex].
+	
+	* src/AbstractCommand.cc
+	(resolveHostname): Throw DlAbortEx if a name resolution failes.
+	Added hostname to the error message.
+	
+	* src/ConsoleDownloadEngine.cc
+	(calculateStatistics): Initialize psize with dlSize.
+
+	* src/PieceMessage.cc
+	(receivedAction): Do not call peerInteraction->abortPiece here.
+	(onGotWrongPiece): Call peerInteraction->abortPiece here.
+
+	* src/BitfieldMan.h
+	(clearAllUseBit): New function.
+	(setAllUseBit): New function.
+	* src/BitfieldMan.cc
+	(clearAllBit): Do not clear useBitfield here.
+	(clearAllUseBit): New function.
+	(setAllUseBit): New function.
+	* src/Piece.cc
+	(clearAllBlock): Call bitfield->clearAllUseBit().
+
 2006-08-28  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	To make filename URL-decoded:

+ 7 - 1
TODO

@@ -13,5 +13,11 @@
 * List available os, version, etc for metalink
 * ipv6(RFC2428 for ftp)
 * Add silent mode.
-* Add upload speed limit command-line option.
 * Save URLs and command-line arguments to .aria2 file.
+* Add multi-file metalink support.
+* Add a control port for GUI frontend
+
+0.8.0
+
+* Add a statement for the permission to link with OpenSSL.
+* Add upload speed limit command-line option(not tested for torrent yet).

+ 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.7.3.
+# Generated by GNU Autoconf 2.59 for aria2c 0.8.0.
 #
 # 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.7.3'
-PACKAGE_STRING='aria2c 0.7.3'
+PACKAGE_VERSION='0.8.0'
+PACKAGE_STRING='aria2c 0.8.0'
 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.7.3 to adapt to many kinds of systems.
+\`configure' configures aria2c 0.8.0 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.7.3:";;
+     short | recursive ) echo "Configuration of aria2c 0.8.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1004,7 +1004,7 @@ fi
 test -n "$ac_init_help" && exit 0
 if $ac_init_version; then
   cat <<\_ACEOF
-aria2c configure 0.7.3
+aria2c configure 0.8.0
 generated by GNU Autoconf 2.59
 
 Copyright (C) 2003 Free Software Foundation, Inc.
@@ -1018,7 +1018,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.7.3, which was
+It was created by aria2c $as_me 0.8.0, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   $ $0 $@
@@ -1661,7 +1661,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='aria2c'
- VERSION='0.7.3'
+ VERSION='0.8.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -12227,7 +12227,7 @@ _ASBOX
 } >&5
 cat >&5 <<_CSEOF
 
-This file was extended by aria2c $as_me 0.7.3, which was
+This file was extended by aria2c $as_me 0.8.0, which was
 generated by GNU Autoconf 2.59.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -12290,7 +12290,7 @@ _ACEOF
 
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-aria2c config.status 0.7.3
+aria2c config.status 0.8.0
 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.7.3, tujikawa@rednoah.com)
+AC_INIT(aria2c, 0.8.0, tujikawa@rednoah.com)
 AM_INIT_AUTOMAKE()
 AM_PATH_CPPUNIT(1.10.2)
 AC_CONFIG_SRCDIR([src/Socket.h])

+ 12 - 7
src/AbstractCommand.cc

@@ -48,16 +48,18 @@ bool AbstractCommand::execute() {
        checkSocketIsWritable && writeCheckTarget->isWritable(0) ||
        !checkSocketIsReadable && !checkSocketIsWritable) {
       checkPoint.reset();
-      Segment seg = { 0, 0, 0, false };
+      if(e->segmentMan->finished()) {
+	logger->debug("CUID#%d - finished.", cuid);
+	return true;
+      }
+      Segment segment;
       if(e->segmentMan->downloadStarted) {
-	// get segment information in order to set Range header.
-	if(!e->segmentMan->getSegment(seg, cuid)) {
-	  // no segment available
+	if(!e->segmentMan->getSegment(segment, cuid)) {
 	  logger->info(MSG_NO_SEGMENT_AVAILABLE, cuid);
 	  return true;
 	}
       }
-      return executeInternal(seg);
+      return executeInternal(segment);
     } else {
       if(checkPoint.elapsed(timeout)) {
 	throw new DlRetryEx(EX_TIME_OUT);
@@ -103,6 +105,7 @@ void AbstractCommand::tryReserved() {
 }
 
 bool AbstractCommand::prepareForRetry(int wait) {
+  e->segmentMan->cancelSegment(cuid);
   Command* command = InitiateConnectionCommandFactory::createInitiateConnectionCommand(cuid, req, e);
   if(wait == 0) {
     e->commands.push_back(command);
@@ -115,7 +118,8 @@ bool AbstractCommand::prepareForRetry(int wait) {
 
 void AbstractCommand::onAbort(Exception* ex) {
   logger->debug(MSG_UNREGISTER_CUID, cuid);
-  e->segmentMan->unregisterId(cuid);
+  //e->segmentMan->unregisterId(cuid);
+  e->segmentMan->cancelSegment(cuid);
 }
 
 void AbstractCommand::disableReadCheckSocket() {
@@ -193,7 +197,8 @@ bool AbstractCommand::resolveHostname(const string& hostname,
     return true;
     break;
   case NameResolver::STATUS_ERROR:
-    throw new DlRetryEx("CUID#%d - Name resolution failed:%s", cuid,
+    throw new DlAbortEx("CUID#%d - Name resolution for %s failed:%s", cuid,
+			hostname.c_str(),
 			resolver->getError().c_str());
   default:
     return false;

+ 1 - 1
src/AbstractCommand.h

@@ -40,7 +40,7 @@ protected:
   void tryReserved();
   virtual bool prepareForRetry(int wait);
   virtual void onAbort(Exception* ex);
-  virtual bool executeInternal(Segment segment) = 0;
+  virtual bool executeInternal(Segment& segment) = 0;
 
   void setReadCheckSocket(const SocketHandle& socket);
   void setWriteCheckSocket(const SocketHandle& socket);

+ 100 - 3
src/BitfieldMan.cc

@@ -95,8 +95,20 @@ BitfieldMan::getMissingIndexRandomly(const unsigned char* bitfield,
 {
   int byte = (int)(((double)bitfieldLength)*random()/(RAND_MAX+1.0));
 
+  unsigned char lastMask = 0;
+  int lastByteLength = totalLength%(blockLength*8);
+  int lastBlockCount = DIV_FLOOR(lastByteLength, blockLength);
+  for(int i = 0; i < lastBlockCount; i++) {
+    lastMask >>= 1;
+    lastMask |= 0x80;
+  }
   for(int i = 0; i < bitfieldLength; i++) {
-    unsigned char mask = 0xff;
+    unsigned char mask;
+    if(byte == bitfieldLength-1) {
+      mask = lastMask;
+    } else {
+      mask = 0xff;
+    }
     if(bitfield[byte]&mask) {
       int index = byte*8+getNthBitIndex(bitfield[byte], 1);
       return index;
@@ -207,6 +219,82 @@ int BitfieldMan::getMissingIndex() const {
   return index;
 }
 
+int BitfieldMan::getMissingUnusedIndex() const {
+  unsigned char* tempBitfield = new unsigned char[bitfieldLength];
+  memset(tempBitfield, 0xff, bitfieldLength);
+  int index = getMissingUnusedIndex(tempBitfield, bitfieldLength);
+  delete [] tempBitfield;
+  return index;
+}
+
+// [startIndex, endIndex)
+class Range {
+public:
+  int startIndex;
+  int endIndex;
+  Range(int startIndex = 0, int endIndex = 0):startIndex(startIndex),
+					      endIndex(endIndex) {}
+  
+  int getSize() const {
+    return endIndex-startIndex;
+  }
+
+  int getMidIndex() const {
+    return (endIndex-startIndex)/2+startIndex;
+  }
+
+  bool operator<(const Range& range) const {
+    return getSize() < range.getSize();
+  }
+};
+
+int BitfieldMan::getStartIndex(int index) const {
+  while(index < blocks &&
+	(isUseBitSet(index) || isBitSet(index))) {
+    index++;
+  }
+  if(blocks <= index) {
+    return -1;
+  } else {
+    return index;
+  }
+}
+
+int BitfieldMan::getEndIndex(int index) const {
+  while(index < blocks &&
+	(!isUseBitSet(index) && !isBitSet(index))) {
+    index++;
+  }
+  return index;
+}
+
+int BitfieldMan::getSparseMissingUnusedIndex() const {
+  Range maxRange;
+  int index = 0;
+  int blocks = countBlock();
+  Range currentRange;
+  while(index < blocks) {
+    currentRange.startIndex = getStartIndex(index);
+    if(currentRange.startIndex == -1) {
+      break;
+    }
+    currentRange.endIndex = getEndIndex(currentRange.startIndex);
+    if(maxRange < currentRange) {
+      maxRange = currentRange;
+    }
+    index = currentRange.endIndex;
+  }
+  if(maxRange.getSize()) {
+    if(maxRange.startIndex == 0) {
+      return 0;
+    } else {
+      return maxRange.getMidIndex();
+    }
+  } else {
+    return -1;
+  }
+}
+
 BlockIndexes BitfieldMan::getAllMissingIndexes() const {
   BlockIndexes missingIndexes;
   for(int i = 0; i < bitfieldLength; i++) {
@@ -317,7 +405,7 @@ bool BitfieldMan::isAllBitSet() const {
 }
 
 bool BitfieldMan::isBitSetInternal(const unsigned char* bitfield, int index) const {
-  if(blocks <= index) { return false; }
+  if(index < 0 || blocks <= index) { return false; }
   unsigned char mask = 128 >> index%8;
   return (bitfield[index/8] & mask) != 0;
 }
@@ -340,7 +428,6 @@ void BitfieldMan::setBitfield(const unsigned char* bitfield, int bitfieldLength)
 
 void BitfieldMan::clearAllBit() {
   memset(this->bitfield, 0, this->bitfieldLength);
-  memset(this->useBitfield, 0, this->bitfieldLength);
 }
 
 void BitfieldMan::setAllBit() {
@@ -349,6 +436,16 @@ void BitfieldMan::setAllBit() {
   }
 }
 
+void BitfieldMan::clearAllUseBit() {
+  memset(this->useBitfield, 0, this->bitfieldLength);
+}
+
+void BitfieldMan::setAllUseBit() {
+  for(int i = 0; i < blocks; i++) {
+    setUseBit(i);
+  }
+}
+
 bool BitfieldMan::setFilterBit(int index) {
   return setBitInternal(filterBitfield, index, true);
 }

+ 14 - 0
src/BitfieldMan.h

@@ -43,6 +43,9 @@ private:
   bool isBitSetInternal(const unsigned char* bitfield, int index) const;
   bool setBitInternal(unsigned char* bitfield, int index, bool on);
   bool setFilterBit(int index);
+
+  int getStartIndex(int index) const;
+  int getEndIndex(int index) const;
 public:
   BitfieldMan(int blockLength, long long int totalLength);
   BitfieldMan(const BitfieldMan& bitfieldMan);
@@ -116,6 +119,14 @@ public:
    * affected by filter
    */
   int getMissingUnusedIndex(const unsigned char* bitfield, int len) const;
+  /**
+   * affected by filter
+   */
+  int getMissingUnusedIndex() const;
+  /**
+   * affected by filter
+   */
+  int getSparseMissingUnusedIndex() const;
   /**
    * affected by filter
    */
@@ -155,6 +166,9 @@ public:
   void clearAllBit();
   void setAllBit();
 
+  void clearAllUseBit();
+  void setAllUseBit();
+
   void addFilter(long long int offset, long long int length);
   /**
    * Clears filter and disables filter

+ 2 - 1
src/ConsoleDownloadEngine.cc

@@ -51,9 +51,10 @@ void ConsoleDownloadEngine::initStatistics() {
 }
 
 void ConsoleDownloadEngine::calculateStatistics() {
-  long long int dlSize = segmentMan->getDownloadedSize();
+  long long int dlSize = segmentMan->getDownloadLength();
   if(!isStartupLengthSet && dlSize > 0) {
     startupLength = dlSize;
+    psize = dlSize;
     isStartupLengthSet = true;
   }
   int elapsed = cp.difference();

+ 62 - 29
src/DownloadCommand.cc

@@ -29,14 +29,30 @@
 #include "prefs.h"
 #include <sys/time.h>
 
+#define STARTUP_IDLE_TIME 10
+
 DownloadCommand::DownloadCommand(int cuid, Request* req, DownloadEngine* e,
 				 const SocketHandle& s):
   AbstractCommand(cuid, req, e, s), lastSize(0) {
+  PeerStatHandle peerStat = PeerStatHandle(new PeerStat(cuid));
+  peerStat->downloadStart();
+  this->e->segmentMan->registerPeerStat(peerStat);
 }
 
-DownloadCommand::~DownloadCommand() {}
+DownloadCommand::~DownloadCommand() {
+  PeerStatHandle peerStat = e->segmentMan->getPeerStat(cuid);
+  assert(peerStat.get());
+  peerStat->downloadStop();
+}
 
-bool DownloadCommand::executeInternal(Segment seg) {
+bool DownloadCommand::executeInternal(Segment& segment) {
+  int maxSpeedLimit = e->option->getAsInt(PREF_MAX_SPEED_LIMIT);
+  if(maxSpeedLimit > 0 &&
+     maxSpeedLimit < e->segmentMan->calculateDownloadSpeed()) {
+    usleep(1);
+    e->commands.push_back(this);
+    return false;
+  }
   TransferEncoding* te = NULL;
   if(transferEncoding.size()) {
     te = getTransferEncoding(transferEncoding);
@@ -45,61 +61,78 @@ bool DownloadCommand::executeInternal(Segment seg) {
   int bufSize = 4096;
   char buf[bufSize];
   socket->readData(buf, bufSize);
+  PeerStatHandle peerStat = e->segmentMan->getPeerStat(cuid);
+  assert(peerStat.get());
   if(te != NULL) {
     int infbufSize = 4096;
     char infbuf[infbufSize];
     te->inflate(infbuf, infbufSize, buf, bufSize);
-    e->segmentMan->diskWriter->writeData(infbuf, infbufSize, seg.sp+seg.ds);
-    seg.ds += infbufSize;
+    e->segmentMan->diskWriter->writeData(infbuf, infbufSize,
+					 segment.getPosition()+segment.writtenLength);
+    segment.writtenLength += infbufSize;
+    peerStat->updateDownloadLength(infbufSize);
   } else {
-    e->segmentMan->diskWriter->writeData(buf, bufSize, seg.sp+seg.ds);
-    seg.ds += bufSize;
+    e->segmentMan->diskWriter->writeData(buf, bufSize,
+					 segment.getPosition()+segment.writtenLength);
+    segment.writtenLength += bufSize;
+    peerStat->updateDownloadLength(bufSize);
   }
   // calculate downloading speed
-  int diff = sw.difference();
-  if(diff >= 1) {
-    seg.speed = (int)((seg.ds-lastSize)/(diff*1.0));
-    sw.reset();
-    lastSize = seg.ds;
+  if(/*sw.elapsed(1) >= 1 && */peerStat->getDownloadStartTime().elapsed(STARTUP_IDLE_TIME)) {
     int lowestLimit = e->option->getAsInt(PREF_LOWEST_SPEED_LIMIT);
-    if(lowestLimit > 0 && seg.speed <= lowestLimit) {
+    int nowSpeed = peerStat->calculateDownloadSpeed();
+    if(lowestLimit > 0 &&  nowSpeed <= lowestLimit) {
       throw new DlAbortEx("CUID#%d - Too slow Downloading speed: %d <= %d(B/s)",
 			  cuid,
-			  seg.speed,
+			  nowSpeed,
 			  lowestLimit);
     }
+    //sw.reset();
   }
   if(e->segmentMan->totalSize != 0 && bufSize == 0) {
     throw new DlRetryEx(EX_GOT_EOF);
   }
   if(te != NULL && te->finished()
-     || te == NULL && seg.ds >= seg.ep-seg.sp+1
+     || te == NULL && segment.complete()
      || bufSize == 0) {
     if(te != NULL) te->end();
     logger->info(MSG_DOWNLOAD_COMPLETED, cuid);
-    seg.ds = seg.ep-seg.sp+1;
-    seg.finish = true;
-    e->segmentMan->updateSegment(seg);
+    e->segmentMan->completeSegment(cuid, segment);
     // this unit is going to download another segment.
-    return prepareForNextSegment();
+    return prepareForNextSegment(segment);
   } else {
-    e->segmentMan->updateSegment(seg);
+    e->segmentMan->updateSegment(cuid, segment);
     e->commands.push_back(this);
     return false;
   }
   
 }
 
-bool DownloadCommand::prepareForRetry(int wait) {
-  //req->resetUrl();
-  return AbstractCommand::prepareForRetry(wait);
-}
-
-bool DownloadCommand::prepareForNextSegment() {
-  req->resetUrl();
-  if(!e->segmentMan->finished()) {
-    return AbstractCommand::prepareForRetry(0);
-  } else {
+bool DownloadCommand::prepareForNextSegment(const Segment& currentSegment) {
+  if(e->segmentMan->finished()) {
     return true;
+  } else {
+    // Merge segment with next segment, if segment.index+1 == nextSegment.index
+    Segment tempSegment = currentSegment;
+    while(1) {
+      Segment nextSegment;
+      if(e->segmentMan->getSegment(nextSegment, cuid, tempSegment.index+1)) {
+	if(nextSegment.writtenLength > 0) {
+	  return prepareForRetry(0);
+	}
+	nextSegment.writtenLength = tempSegment.writtenLength-tempSegment.length;
+	if(nextSegment.complete()) {
+	  e->segmentMan->completeSegment(cuid, nextSegment);
+	  tempSegment = nextSegment;
+	} else {
+	  e->segmentMan->updateSegment(cuid, nextSegment);
+	  e->commands.push_back(this);
+	  return false;
+	}
+      } else {
+	break;
+      }
+    }
+    return prepareForRetry(0);
   }
 }

+ 2 - 3
src/DownloadCommand.h

@@ -33,10 +33,9 @@ private:
   Time sw;
   long long int lastSize;
 protected:
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
 
-  bool prepareForRetry(int wait);
-  bool prepareForNextSegment();
+  virtual bool prepareForNextSegment(const Segment& currentSegment);
 public:
   DownloadCommand(int cuid, Request* req, DownloadEngine* e,
 		  const SocketHandle& s);

+ 1 - 1
src/DownloadEngine.cc

@@ -37,8 +37,8 @@ DownloadEngine::DownloadEngine():noWait(false), segmentMan(0) {
 }
 
 DownloadEngine::~DownloadEngine() {
-  delete segmentMan;
   cleanQueue();
+  delete segmentMan;
 }
 
 void DownloadEngine::cleanQueue() {

+ 0 - 5
src/DownloadEngineFactory.cc

@@ -22,7 +22,6 @@
 #include "DownloadEngineFactory.h"
 #include "prefs.h"
 #include "DefaultDiskWriter.h"
-#include "SplitSlowestSegmentSplitter.h"
 #include "InitiateConnectionCommandFactory.h"
 #include "ByteArrayDiskWriter.h"
 #include "Util.h"
@@ -51,8 +50,6 @@ DownloadEngineFactory::newConsoleEngine(const Option* op,
   e->segmentMan->dir = op->get(PREF_DIR);
   e->segmentMan->ufilename = op->get(PREF_OUT);
   e->segmentMan->option = op;
-  e->segmentMan->splitter = new SplitSlowestSegmentSplitter();
-  e->segmentMan->splitter->setMinSegmentSize(op->getAsLLInt(PREF_MIN_SEGMENT_SIZE));
   e->segmentMan->reserved = reserved;
   
   int cuidCounter = 1;
@@ -79,8 +76,6 @@ DownloadEngineFactory::newTorrentConsoleEngine(const Option* op,
   te->segmentMan = new SegmentMan();
   te->segmentMan->diskWriter = byteArrayDiskWriter;
   te->segmentMan->option = op;
-  te->segmentMan->splitter = new SplitSlowestSegmentSplitter();
-  te->segmentMan->splitter->setMinSegmentSize(op->getAsLLInt(PREF_MIN_SEGMENT_SIZE));
   te->torrentMan = new TorrentMan();
   te->torrentMan->setStoreDir(op->get(PREF_DIR));
   te->torrentMan->option = op;

+ 1 - 1
src/FtpConnection.cc

@@ -97,7 +97,7 @@ SocketHandle FtpConnection::sendPort() const {
 }
 
 void FtpConnection::sendRest(const Segment& segment) const {
-  string request = "REST "+Util::llitos(segment.sp+segment.ds)+"\r\n";
+  string request = "REST "+Util::llitos(segment.getPosition()+segment.writtenLength)+"\r\n";
   logger->info(MSG_SENDING_REQUEST, cuid, request.c_str());
   socket->writeData(request);
 }

+ 2 - 1
src/FtpDownloadCommand.cc

@@ -25,7 +25,8 @@ FtpDownloadCommand::FtpDownloadCommand(int cuid, Request* req,
 				       DownloadEngine* e,
 				       const SocketHandle& dataSocket,
 				       const SocketHandle& ctrlSocket)
-  :DownloadCommand(cuid, req, e, dataSocket), ctrlSocket(ctrlSocket) {}
+  :DownloadCommand(cuid, req, e, dataSocket),
+   ctrlSocket(ctrlSocket) {}
 
 FtpDownloadCommand::~FtpDownloadCommand() {}
 

+ 12 - 12
src/FtpInitiateConnectionCommand.cc

@@ -43,18 +43,7 @@ FtpInitiateConnectionCommand::~FtpInitiateConnectionCommand() {
 #endif // ENABLE_ASYNC_DNS
 }
 
-bool FtpInitiateConnectionCommand::executeInternal(Segment segment) {
-  if(!e->segmentMan->downloadStarted) {
-    e->segmentMan->filename = Util::urldecode(req->getFile());
-    bool segFileExists = e->segmentMan->segmentFileExists();
-    if(segFileExists) {
-      e->segmentMan->load();
-      e->segmentMan->diskWriter->openExistingFile(e->segmentMan->getFilePath());
-      e->segmentMan->downloadStarted = true;
-    } else {
-      e->segmentMan->diskWriter->initAndOpenFile(e->segmentMan->getFilePath());
-    }
-  }
+bool FtpInitiateConnectionCommand::executeInternal(Segment& segment) {
   string hostname;
   if(useHttpProxy()) {
     hostname = e->option->get(PREF_HTTP_PROXY_HOST);
@@ -71,6 +60,17 @@ bool FtpInitiateConnectionCommand::executeInternal(Segment segment) {
     }
   }
 #endif // ENABLE_ASYNC_DNS
+  if(!e->segmentMan->downloadStarted) {
+    e->segmentMan->filename = Util::urldecode(req->getFile());
+    bool segFileExists = e->segmentMan->segmentFileExists();
+    if(segFileExists) {
+      e->segmentMan->load();
+      e->segmentMan->diskWriter->openExistingFile(e->segmentMan->getFilePath());
+      e->segmentMan->downloadStarted = true;
+    } else {
+      e->segmentMan->diskWriter->initAndOpenFile(e->segmentMan->getFilePath());
+    }
+  }
   Command* command;
   if(useHttpProxy()) {
     logger->info(MSG_CONNECTING_TO_SERVER, cuid,

+ 1 - 1
src/FtpInitiateConnectionCommand.h

@@ -33,7 +33,7 @@ private:
   bool useHttpProxyGet() const;
   bool useHttpProxyConnect() const;
 protected:
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
 public:
   FtpInitiateConnectionCommand(int cuid, Request* req, DownloadEngine* e);
   ~FtpInitiateConnectionCommand();

+ 3 - 1
src/FtpNegotiationCommand.cc

@@ -40,7 +40,7 @@ FtpNegotiationCommand::~FtpNegotiationCommand() {
   delete ftp;
 }
 
-bool FtpNegotiationCommand::executeInternal(Segment segment) {
+bool FtpNegotiationCommand::executeInternal(Segment& segment) {
   while(processSequence(segment));
   if(sequence == SEQ_RETRY) {
     return prepareForRetry(0);
@@ -170,6 +170,8 @@ bool FtpNegotiationCommand::recvSize() {
   if(!e->segmentMan->downloadStarted) {
     e->segmentMan->downloadStarted = true;
     e->segmentMan->totalSize = size;
+    e->segmentMan->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE),
+				e->segmentMan->totalSize);
   } else if(e->segmentMan->totalSize != size) {
     throw new DlAbortEx(EX_SIZE_MISMATCH, e->segmentMan->totalSize, size);
   }

+ 1 - 1
src/FtpNegotiationCommand.h

@@ -78,7 +78,7 @@ private:
   int sequence;
   FtpConnection* ftp;
 protected:
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
 public:
   FtpNegotiationCommand(int cuid, Request* req, DownloadEngine* e,
 			const SocketHandle& s);

+ 1 - 1
src/FtpTunnelRequestCommand.cc

@@ -33,7 +33,7 @@ FtpTunnelRequestCommand::FtpTunnelRequestCommand(int cuid, Request* req,
 
 FtpTunnelRequestCommand::~FtpTunnelRequestCommand() {}
 
-bool FtpTunnelRequestCommand::executeInternal(Segment segment) {
+bool FtpTunnelRequestCommand::executeInternal(Segment& segment) {
   socket->setBlockingMode();
   HttpConnection httpConnection(cuid, socket, req, e->option);
   httpConnection.sendProxyRequest();

+ 1 - 1
src/FtpTunnelRequestCommand.h

@@ -26,7 +26,7 @@
 
 class FtpTunnelRequestCommand : public AbstractCommand {
 protected:
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
 public:
   FtpTunnelRequestCommand(int cuid, Request* req, DownloadEngine* e,
 			  const SocketHandle& s);

+ 1 - 1
src/FtpTunnelResponseCommand.cc

@@ -35,7 +35,7 @@ FtpTunnelResponseCommand::~FtpTunnelResponseCommand() {
   delete http;
 }
 
-bool FtpTunnelResponseCommand::executeInternal(Segment segment) {
+bool FtpTunnelResponseCommand::executeInternal(Segment& segment) {
   HttpHeader headers;
   int status = http->receiveResponse(headers);
   if(status == 0) {

+ 1 - 1
src/FtpTunnelResponseCommand.h

@@ -29,7 +29,7 @@ class FtpTunnelResponseCommand : public AbstractCommand {
 private:
   HttpConnection* http;
 protected:
-    bool executeInternal(Segment segment);
+    bool executeInternal(Segment& segment);
 public:
   FtpTunnelResponseCommand(int cuid, Request* req, DownloadEngine* e,
 			   const SocketHandle& s);

+ 13 - 4
src/HttpConnection.cc

@@ -71,14 +71,23 @@ string HttpConnection::createRequest(const Segment& segment) const {
      ((req->getDir() == "/" ? "/" : req->getDir()+"/")+req->getFile()))+
     string(" HTTP/1.1\r\n")+
     "User-Agent: "+USER_AGENT+"\r\n"+
-    "Connection: close\r\n"+
+    // use persistent connection
+    //"Connection: close\r\n"+
     "Accept: */*\r\n"+        /* */
     "Host: "+getHost(req->getHost(), req->getPort())+"\r\n"+
     "Pragma: no-cache\r\n"+
     "Cache-Control: no-cache\r\n";
-  if(segment.sp+segment.ds > 0) {
+  if(!req->isKeepAlive()) {
+    request += "Connection: close\r\n";
+  }
+  if(segment.length > 0) {
     request += "Range: bytes="+
-      Util::llitos(segment.sp+segment.ds)+"-"+Util::llitos(segment.ep)+"\r\n";
+      Util::llitos(segment.getPosition()+segment.writtenLength);
+    request += "-";
+    if(req->isKeepAlive()) {
+      request += Util::llitos(segment.getPosition()+segment.length-1);
+    }
+    request += "\r\n";
   }
   if(useProxy() && useProxyAuth() && useProxyGet()) {
     request += "Proxy-Connection: close\r\n";
@@ -144,7 +153,7 @@ int HttpConnection::receiveResponse(HttpHeader& headers) {
     socket->readData(headerBuf+headerBufLength, size);
     headerBufLength += size;
   } else {
-    if(eohIndex[headerBuf] == '\n') {
+    if(headerBuf[eohIndex] == '\n') {
       // for crapping non-standard HTTP server
       delimiterSwitch = 1;
     } else {

+ 19 - 4
src/HttpDownloadCommand.cc

@@ -20,14 +20,15 @@
  */
 /* copyright --> */
 #include "HttpDownloadCommand.h"
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <algorithm>
 #include "DlRetryEx.h"
 #include "HttpRequestCommand.h"
 #include "Util.h"
 #include "ChunkedEncoding.h"
+#include "message.h"
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <algorithm>
 
 using namespace std;
 
@@ -49,3 +50,17 @@ HttpDownloadCommand::~HttpDownloadCommand() {
 TransferEncoding* HttpDownloadCommand::getTransferEncoding(const string& name) {
   return transferEncodings[name];
 }
+
+bool HttpDownloadCommand::prepareForNextSegment(const Segment& currentSegment) {
+  if(e->segmentMan->finished()) {
+    return true;
+  } else {
+    if(req->isKeepAlive()) {
+      Command* command = new HttpRequestCommand(cuid, req, e, socket);
+      e->commands.push_back(command);
+      return true;
+    } else {
+      return DownloadCommand::prepareForNextSegment(currentSegment);
+    }
+  }
+}

+ 2 - 0
src/HttpDownloadCommand.h

@@ -36,6 +36,8 @@ using namespace std;
 class HttpDownloadCommand:public DownloadCommand {
 private:
   map<string, TransferEncoding*> transferEncodings;
+protected:
+  virtual bool prepareForNextSegment(const Segment& currentSegment);
 public:
   HttpDownloadCommand(int cuid, Request* req, DownloadEngine* e,
 		      const SocketHandle& s);

+ 1 - 1
src/HttpInitiateConnectionCommand.cc

@@ -43,7 +43,7 @@ HttpInitiateConnectionCommand::~HttpInitiateConnectionCommand() {
 #endif // ENABLE_ASYNC_DNS
 }
 
-bool HttpInitiateConnectionCommand::executeInternal(Segment segment) {
+bool HttpInitiateConnectionCommand::executeInternal(Segment& segment) {
   string hostname;
   if(useProxy()) {
     hostname = e->option->get(PREF_HTTP_PROXY_HOST);

+ 1 - 1
src/HttpInitiateConnectionCommand.h

@@ -41,7 +41,7 @@ protected:
    * Whether or not the connection is established successfully is
    * evaluated by RequestCommand.
    */
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
 public:
   HttpInitiateConnectionCommand(int cuid, Request* req, DownloadEngine* e);
   ~HttpInitiateConnectionCommand();

+ 1 - 1
src/HttpProxyRequestCommand.cc

@@ -33,7 +33,7 @@ HttpProxyRequestCommand::HttpProxyRequestCommand(int cuid, Request* req,
 
 HttpProxyRequestCommand::~HttpProxyRequestCommand() {}
 
-bool HttpProxyRequestCommand::executeInternal(Segment segment) {
+bool HttpProxyRequestCommand::executeInternal(Segment& segment) {
   socket->setBlockingMode();
   HttpConnection httpConnection(cuid, socket, req, e->option);
   httpConnection.sendProxyRequest();

+ 1 - 1
src/HttpProxyRequestCommand.h

@@ -26,7 +26,7 @@
 
 class HttpProxyRequestCommand : public AbstractCommand {
 protected:
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
 public:
   HttpProxyRequestCommand(int cuid, Request* req, DownloadEngine* e,
 			  const SocketHandle& s);

+ 1 - 1
src/HttpProxyResponseCommand.cc

@@ -35,7 +35,7 @@ HttpProxyResponseCommand::~HttpProxyResponseCommand() {
   delete http;
 }
 
-bool HttpProxyResponseCommand::executeInternal(Segment segment) {
+bool HttpProxyResponseCommand::executeInternal(Segment& segment) {
   HttpHeader headers;
   int status = http->receiveResponse(headers);
   if(status == 0) {

+ 1 - 1
src/HttpProxyResponseCommand.h

@@ -29,7 +29,7 @@ class HttpProxyResponseCommand : public AbstractCommand {
 private:
   HttpConnection* http;
 protected:
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
 public:
   HttpProxyResponseCommand(int cuid, Request* req, DownloadEngine* e,
 			   const SocketHandle& s);

+ 7 - 4
src/HttpRequestCommand.cc

@@ -22,6 +22,7 @@
 #include "HttpRequestCommand.h"
 #include "HttpResponseCommand.h"
 #include "HttpConnection.h"
+#include "prefs.h"
 
 HttpRequestCommand::HttpRequestCommand(int cuid, Request* req,
 				       DownloadEngine* e,
@@ -33,15 +34,17 @@ HttpRequestCommand::HttpRequestCommand(int cuid, Request* req,
 
 HttpRequestCommand::~HttpRequestCommand() {}
 
-bool HttpRequestCommand::executeInternal(Segment seg) {
+bool HttpRequestCommand::executeInternal(Segment& segment) {
   socket->setBlockingMode();
   if(req->getProtocol() == "https") {
     socket->initiateSecureConnection();
   }
+  if(!e->option->getAsBool(PREF_HTTP_KEEP_ALIVE)) {
+    req->setKeepAlive(false);
+  }
   HttpConnection http(cuid, socket, req, e->option);
-  // set seg to request in order to remember the request range
-  req->seg = seg;
-  http.sendRequest(seg);
+  req->segment = segment;
+  http.sendRequest(segment);
 
   Command* command = getNextCommand();
   e->commands.push_back(command);

+ 1 - 1
src/HttpRequestCommand.h

@@ -26,7 +26,7 @@
 
 class HttpRequestCommand:public AbstractCommand {
 protected:
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
   Command* getNextCommand() const;
 public:
   HttpRequestCommand(int cuid, Request* req, DownloadEngine* e,

+ 21 - 12
src/HttpResponseCommand.cc

@@ -26,6 +26,7 @@
 #include "HttpInitiateConnectionCommand.h"
 #include "message.h"
 #include "Util.h"
+#include "prefs.h"
 #include <sys/types.h>
 #include <unistd.h>
 
@@ -40,8 +41,8 @@ HttpResponseCommand::~HttpResponseCommand() {
   delete http;
 }
 
-bool HttpResponseCommand::executeInternal(Segment seg) {
-  if(req->seg.sp != seg.sp) {
+bool HttpResponseCommand::executeInternal(Segment& segment) {
+  if(req->segment != segment) {
     logger->info(MSG_SEGMENT_CHANGED, cuid);
     return prepareForRetry(0);
   }
@@ -53,8 +54,12 @@ bool HttpResponseCommand::executeInternal(Segment seg) {
     return false;
   }
   // check HTTP status number
-  checkResponse(status, seg);
+  checkResponse(status, segment);
   retrieveCookie(headers);
+  // check whether the server supports persistent connections.
+  if(Util::toLower(headers.getFirst("Connection")).find("close") != string::npos) {
+    req->setKeepAlive(false);
+  }
   // check whether Location header exists. If it does, update request object
   // with redirected URL.
   // then establish a connection to the new host and port
@@ -64,7 +69,8 @@ bool HttpResponseCommand::executeInternal(Segment seg) {
   if(!e->segmentMan->downloadStarted) {
     string transferEncoding;
     if(headers.defined("Transfer-Encoding")) {
-      return handleOtherEncoding(headers.getFirst("Transfer-Encoding"), headers);
+      return handleOtherEncoding(headers.getFirst("Transfer-Encoding"),
+				 headers);
     } else {
       return handleDefaultEncoding(headers);
     }
@@ -82,8 +88,8 @@ void HttpResponseCommand::checkResponse(int status, const Segment& segment) {
     throw new DlAbortEx(EX_AUTH_FAILED);
   }
   if(!(300 <= status && status < 400 ||
-       (segment.sp+segment.ds == 0 && status == 200)
-       || (segment.sp+segment.ds > 0 &&  status == 206))) {
+       (segment.getPosition()+segment.writtenLength == 0 && (status == 200 || status == 206)) ||
+       (segment.getPosition()+segment.writtenLength > 0 &&  status == 206))) {
     throw new DlRetryEx(EX_BAD_STATUS, status);
   }
 }
@@ -112,6 +118,8 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpHeader& headers) {
   if(req->isTorrent) {
     long long int size = headers.getFirstAsLLInt("Content-Length");
     e->segmentMan->totalSize = size;
+    e->segmentMan->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE),
+				e->segmentMan->totalSize);
     e->segmentMan->isSplittable = false;
     e->segmentMan->downloadStarted = true;
     e->segmentMan->diskWriter->initAndOpenFile("/tmp/aria2"+Util::itos(getpid()));
@@ -134,11 +142,10 @@ bool HttpResponseCommand::handleDefaultEncoding(const HttpHeader& headers) {
     return prepareForRetry(0);
   } else {
     e->segmentMan->totalSize = size;
-    Segment seg;
-    e->segmentMan->getSegment(seg, cuid);	
+    e->segmentMan->initBitfield(e->option->getAsInt(PREF_SEGMENT_SIZE),
+				e->segmentMan->totalSize);
     e->segmentMan->diskWriter->initAndOpenFile(e->segmentMan->getFilePath());
-    createHttpDownloadCommand();
-    return true;
+    return prepareForRetry(0);
   }
 }
 
@@ -148,8 +155,10 @@ bool HttpResponseCommand::handleOtherEncoding(const string& transferEncoding, co
   e->segmentMan->isSplittable = false;
   e->segmentMan->filename = determinFilename(headers);
   e->segmentMan->totalSize = 0;
-  Segment seg;
-  e->segmentMan->getSegment(seg, cuid);	
+  // disable keep-alive
+  req->setKeepAlive(false);
+  Segment segment;
+  e->segmentMan->getSegment(segment, cuid);	
   e->segmentMan->diskWriter->initAndOpenFile(e->segmentMan->getFilePath());
   createHttpDownloadCommand(transferEncoding);
   return true;

+ 1 - 1
src/HttpResponseCommand.h

@@ -39,7 +39,7 @@ private:
   string determinFilename(const HttpHeader& headers);
   HttpConnection* http;
 protected:
-  bool executeInternal(Segment segment);
+  bool executeInternal(Segment& segment);
 public:
   HttpResponseCommand(int cuid, Request* req, DownloadEngine* e,
 		      const SocketHandle& s);

+ 4 - 5
src/Makefile.am

@@ -23,11 +23,8 @@ SRCS =  Socket.h\
 	SleepCommand.cc SleepCommand.h\
 	DownloadEngine.cc DownloadEngine.h\
 	ConsoleDownloadEngine.cc ConsoleDownloadEngine.h\
-	Segment.h\
+	Segment.cc Segment.h\
 	SegmentMan.cc SegmentMan.h\
-	SegmentSplitter.cc SegmentSplitter.h\
-	SplitFirstSegmentSplitter.cc SplitFirstSegmentSplitter.h\
-	SplitSlowestSegmentSplitter.cc SplitSlowestSegmentSplitter.h\
 	Util.cc Util.h\
 	Request.cc Request.h\
 	common.h\
@@ -55,7 +52,9 @@ SRCS =  Socket.h\
 	FeatureConfig.cc FeatureConfig.h\
 	DownloadEngineFactory.cc DownloadEngineFactory.h\
 	RequestInfo.h\
-	UrlRequestInfo.cc UrlRequestInfo.h
+	UrlRequestInfo.cc UrlRequestInfo.h\
+	SpeedCalc.cc SpeedCalc.h\
+	PeerStat.h
 
 if ENABLE_ASYNC_DNS
 SRCS += NameResolver.cc NameResolver.h

+ 38 - 45
src/Makefile.in

@@ -151,26 +151,24 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
 	FtpTunnelRequestCommand.h FtpTunnelResponseCommand.cc \
 	FtpTunnelResponseCommand.h SleepCommand.cc SleepCommand.h \
 	DownloadEngine.cc DownloadEngine.h ConsoleDownloadEngine.cc \
-	ConsoleDownloadEngine.h Segment.h SegmentMan.cc SegmentMan.h \
-	SegmentSplitter.cc SegmentSplitter.h \
-	SplitFirstSegmentSplitter.cc SplitFirstSegmentSplitter.h \
-	SplitSlowestSegmentSplitter.cc SplitSlowestSegmentSplitter.h \
-	Util.cc Util.h Request.cc Request.h common.h message.h \
-	Exception.h DlAbortEx.h DlRetryEx.h Logger.h SimpleLogger.cc \
-	SimpleLogger.h TransferEncoding.h ChunkedEncoding.cc \
-	ChunkedEncoding.h DiskWriter.h DefaultDiskWriter.cc \
-	DefaultDiskWriter.h PreAllocationDiskWriter.cc \
-	PreAllocationDiskWriter.h AbstractDiskWriter.cc \
-	AbstractDiskWriter.h File.cc File.h Option.cc Option.h \
-	Base64.cc Base64.h CookieBox.cc CookieBox.h messageDigest.h \
-	LogFactory.cc LogFactory.h NullLogger.h TimeA2.cc TimeA2.h \
-	SharedHandle.h FeatureConfig.cc FeatureConfig.h \
-	DownloadEngineFactory.cc DownloadEngineFactory.h RequestInfo.h \
-	UrlRequestInfo.cc UrlRequestInfo.h NameResolver.cc \
-	NameResolver.h MetaEntry.h Data.cc Data.h Dictionary.cc \
-	Dictionary.h List.cc List.h MetaFileUtil.cc MetaFileUtil.h \
-	MetaEntryVisitor.h ShaVisitor.cc ShaVisitor.h TorrentMan.cc \
-	TorrentMan.h PeerConnection.cc PeerConnection.h \
+	ConsoleDownloadEngine.h Segment.cc Segment.h SegmentMan.cc \
+	SegmentMan.h Util.cc Util.h Request.cc Request.h common.h \
+	message.h Exception.h DlAbortEx.h DlRetryEx.h Logger.h \
+	SimpleLogger.cc SimpleLogger.h TransferEncoding.h \
+	ChunkedEncoding.cc ChunkedEncoding.h DiskWriter.h \
+	DefaultDiskWriter.cc DefaultDiskWriter.h \
+	PreAllocationDiskWriter.cc PreAllocationDiskWriter.h \
+	AbstractDiskWriter.cc AbstractDiskWriter.h File.cc File.h \
+	Option.cc Option.h Base64.cc Base64.h CookieBox.cc CookieBox.h \
+	messageDigest.h LogFactory.cc LogFactory.h NullLogger.h \
+	TimeA2.cc TimeA2.h SharedHandle.h FeatureConfig.cc \
+	FeatureConfig.h DownloadEngineFactory.cc \
+	DownloadEngineFactory.h RequestInfo.h UrlRequestInfo.cc \
+	UrlRequestInfo.h SpeedCalc.cc SpeedCalc.h PeerStat.h \
+	NameResolver.cc NameResolver.h MetaEntry.h Data.cc Data.h \
+	Dictionary.cc Dictionary.h List.cc List.h MetaFileUtil.cc \
+	MetaFileUtil.h MetaEntryVisitor.h ShaVisitor.cc ShaVisitor.h \
+	TorrentMan.cc TorrentMan.h PeerConnection.cc PeerConnection.h \
 	PeerMessageUtil.cc PeerMessageUtil.h PeerAbstractCommand.cc \
 	PeerAbstractCommand.h PeerInitiateConnectionCommand.cc \
 	PeerInitiateConnectionCommand.h PeerInteractionCommand.cc \
@@ -280,17 +278,15 @@ am__objects_4 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
 	FtpTunnelRequestCommand.$(OBJEXT) \
 	FtpTunnelResponseCommand.$(OBJEXT) SleepCommand.$(OBJEXT) \
 	DownloadEngine.$(OBJEXT) ConsoleDownloadEngine.$(OBJEXT) \
-	SegmentMan.$(OBJEXT) SegmentSplitter.$(OBJEXT) \
-	SplitFirstSegmentSplitter.$(OBJEXT) \
-	SplitSlowestSegmentSplitter.$(OBJEXT) Util.$(OBJEXT) \
+	Segment.$(OBJEXT) SegmentMan.$(OBJEXT) Util.$(OBJEXT) \
 	Request.$(OBJEXT) SimpleLogger.$(OBJEXT) \
 	ChunkedEncoding.$(OBJEXT) DefaultDiskWriter.$(OBJEXT) \
 	PreAllocationDiskWriter.$(OBJEXT) AbstractDiskWriter.$(OBJEXT) \
 	File.$(OBJEXT) Option.$(OBJEXT) Base64.$(OBJEXT) \
 	CookieBox.$(OBJEXT) LogFactory.$(OBJEXT) TimeA2.$(OBJEXT) \
 	FeatureConfig.$(OBJEXT) DownloadEngineFactory.$(OBJEXT) \
-	UrlRequestInfo.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
-	$(am__objects_3)
+	UrlRequestInfo.$(OBJEXT) SpeedCalc.$(OBJEXT) $(am__objects_1) \
+	$(am__objects_2) $(am__objects_3)
 am_libaria2c_a_OBJECTS = $(am__objects_4)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -472,23 +468,21 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \
 	FtpTunnelRequestCommand.h FtpTunnelResponseCommand.cc \
 	FtpTunnelResponseCommand.h SleepCommand.cc SleepCommand.h \
 	DownloadEngine.cc DownloadEngine.h ConsoleDownloadEngine.cc \
-	ConsoleDownloadEngine.h Segment.h SegmentMan.cc SegmentMan.h \
-	SegmentSplitter.cc SegmentSplitter.h \
-	SplitFirstSegmentSplitter.cc SplitFirstSegmentSplitter.h \
-	SplitSlowestSegmentSplitter.cc SplitSlowestSegmentSplitter.h \
-	Util.cc Util.h Request.cc Request.h common.h message.h \
-	Exception.h DlAbortEx.h DlRetryEx.h Logger.h SimpleLogger.cc \
-	SimpleLogger.h TransferEncoding.h ChunkedEncoding.cc \
-	ChunkedEncoding.h DiskWriter.h DefaultDiskWriter.cc \
-	DefaultDiskWriter.h PreAllocationDiskWriter.cc \
-	PreAllocationDiskWriter.h AbstractDiskWriter.cc \
-	AbstractDiskWriter.h File.cc File.h Option.cc Option.h \
-	Base64.cc Base64.h CookieBox.cc CookieBox.h messageDigest.h \
-	LogFactory.cc LogFactory.h NullLogger.h TimeA2.cc TimeA2.h \
-	SharedHandle.h FeatureConfig.cc FeatureConfig.h \
-	DownloadEngineFactory.cc DownloadEngineFactory.h RequestInfo.h \
-	UrlRequestInfo.cc UrlRequestInfo.h $(am__append_1) \
-	$(am__append_2) $(am__append_3)
+	ConsoleDownloadEngine.h Segment.cc Segment.h SegmentMan.cc \
+	SegmentMan.h Util.cc Util.h Request.cc Request.h common.h \
+	message.h Exception.h DlAbortEx.h DlRetryEx.h Logger.h \
+	SimpleLogger.cc SimpleLogger.h TransferEncoding.h \
+	ChunkedEncoding.cc ChunkedEncoding.h DiskWriter.h \
+	DefaultDiskWriter.cc DefaultDiskWriter.h \
+	PreAllocationDiskWriter.cc PreAllocationDiskWriter.h \
+	AbstractDiskWriter.cc AbstractDiskWriter.h File.cc File.h \
+	Option.cc Option.h Base64.cc Base64.h CookieBox.cc CookieBox.h \
+	messageDigest.h LogFactory.cc LogFactory.h NullLogger.h \
+	TimeA2.cc TimeA2.h SharedHandle.h FeatureConfig.cc \
+	FeatureConfig.h DownloadEngineFactory.cc \
+	DownloadEngineFactory.h RequestInfo.h UrlRequestInfo.cc \
+	UrlRequestInfo.h SpeedCalc.cc SpeedCalc.h PeerStat.h \
+	$(am__append_1) $(am__append_2) $(am__append_3)
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@@ -655,15 +649,14 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestSlot.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SeedCheckCommand.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Segment.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentMan.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentSplitter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleLogger.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimplePeerMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SleepCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketCore.Po@am__quote@
-@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)/SpeedCalc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeA2.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentAutoSaveCommand.Po@am__quote@

+ 5 - 1
src/PeerInteractionCommand.cc

@@ -127,7 +127,11 @@ bool PeerInteractionCommand::executeInternal() {
     }
     receiveMessages();
 
-    peerInteraction->addRequests();
+    int maxSpeedLimit = e->option->getAsInt(PREF_MAX_SPEED_LIMIT);
+    if(maxSpeedLimit == 0 ||
+       maxSpeedLimit > 0 && maxSpeedLimit <= e->getDownloadSpeed()) {
+      peerInteraction->addRequests();
+    }
     peerInteraction->sendMessages(e->getUploadSpeed());
     break;
   }

+ 90 - 0
src/PeerStat.h

@@ -0,0 +1,90 @@
+/* <!-- 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_PEER_STAT_H_
+#define _D_PEER_STAT_H_
+
+#include "common.h"
+#include "SpeedCalc.h"
+#include "SharedHandle.h"
+
+class PeerStat {
+public:
+  enum STATUS {
+    IDLE,
+    ACTIVE
+  };
+private:
+  int cuid;
+  SpeedCalc downloadSpeed;
+  Time downloadStartTime;
+  STATUS status;
+public:
+
+  PeerStat(int cuid):cuid(cuid), status(IDLE) {}
+
+  ~PeerStat() {}
+
+  /**
+   * Returns current download speed in byte per sec.
+   */
+  int calculateDownloadSpeed() {
+    return downloadSpeed.calculateSpeed();
+  }
+
+  void updateDownloadLength(int bytes) {
+    downloadSpeed.update(bytes);
+  }
+
+  int getMaxSpeed() const {
+    return downloadSpeed.getMaxSpeed();
+  }
+
+  void reset() {
+    downloadSpeed.reset();
+    downloadStartTime.reset();
+  }
+
+  void downloadStart() {
+    reset();
+    status = ACTIVE;
+  }
+
+  void downloadStop() {
+    status = IDLE;
+  }
+
+  const Time& getDownloadStartTime() const {
+    return downloadStartTime;
+  }
+
+  STATUS getStatus() const {
+    return status;
+  }
+
+  int getCuid() const {
+    return cuid;
+  }
+};
+
+typedef SharedHandle<PeerStat> PeerStatHandle;
+
+#endif // _D_PEER_STAT_H_

+ 1 - 0
src/Piece.cc

@@ -30,6 +30,7 @@ void Piece::completeBlock(int blockIndex) {
 
 void Piece::clearAllBlock() {
   bitfield->clearAllBit();
+  bitfield->clearAllUseBit();
 }
 
 void Piece::setAllBlock() {

+ 1 - 1
src/PieceMessage.cc

@@ -81,7 +81,6 @@ void PieceMessage::receivedAction() {
 	onGotNewPiece(piece);
       } else {
 	onGotWrongPiece(piece);
-	peerInteraction->abortPiece(piece);
       }
     }
   }
@@ -212,6 +211,7 @@ void PieceMessage::onGotWrongPiece(Piece& piece) {
   erasePieceOnDisk(piece);
   piece.clearAllBlock();
   torrentMan->updatePiece(piece);
+  peerInteraction->abortPiece(piece);
 }
 
 void PieceMessage::erasePieceOnDisk(const Piece& piece) {

+ 2 - 5
src/Request.cc

@@ -23,11 +23,7 @@
 #include "Util.h"
 #include "FeatureConfig.h"
 
-Request::Request():port(0), tryCount(0), isTorrent(false) {
-  seg.sp = 0;
-  seg.ep = 0;
-  seg.ds = 0;
-  seg.finish = false;
+Request::Request():port(0), tryCount(0), keepAlive(true), isTorrent(false) {
   cookieBox = new CookieBox();
 }
 
@@ -42,6 +38,7 @@ bool Request::setUrl(const string& url) {
 
 bool Request::resetUrl() {
   previousUrl = referer;
+  segment = Segment();
   return setUrl(url);
 }
 

+ 5 - 3
src/Request.h

@@ -23,8 +23,8 @@
 #define _D_REQUEST_H_
 #include <string>
 #include <map>
-#include <Segment.h>
 #include "CookieBox.h"
+#include "Segment.h"
 #include "common.h"
 
 using namespace std;
@@ -59,9 +59,10 @@ private:
   string file;
   int tryCount;
   int trackerEvent;
+  bool keepAlive;
   bool parseUrl(const string& url);
 public:
-  Segment seg;
+  Segment segment;
   CookieBox* cookieBox;
   bool isTorrent;
 public:
@@ -91,7 +92,8 @@ public:
   int getPort() const { return port; }
   string getDir() const { return dir; }
   string getFile() const { return file;}
-
+  bool isKeepAlive() const { return keepAlive; }
+  void setKeepAlive(bool keepAlive) { this->keepAlive = keepAlive; }
   void setTrackerEvent(int event) { trackerEvent = event; }
   int getTrackerEvent() const { return trackerEvent; }
 

+ 31 - 0
src/Segment.cc

@@ -0,0 +1,31 @@
+/* <!-- 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 "Segment.h"
+
+ostream& operator<<(ostream& o, const Segment& segment) {
+  o << "index = " << segment.index << ", ";
+  o << "length = " << segment.length << ", ";
+  o << "segmentLength = " << segment.segmentLength << ", ";
+  o << "writtenLength = " << segment.writtenLength;
+  return o;
+}

+ 40 - 21
src/Segment.h

@@ -27,27 +27,46 @@
 
 using namespace std;
 
-/**
- * Segment represents a download segment.
- * sp, ep is a offset from a begining of a file.
- * Therefore, if a file size is x, then 0 <= sp <= ep <= x-1.
- * sp, ep is used in Http Range header.
- * e.g. Range: bytes=sp-ep
- * ds is downloaded bytes.
- * If a download of this segement is complete, finish must be set to true.
- */
-typedef struct {
-  int cuid;
-  long long int sp;
-  long long int ep;
-  long long int ds;
-  int speed;
-  bool finish;
-} Segment;
-
-typedef deque<Segment> Segments;
-
-#define SEGMENT_EQUAL(X, Y) (X.cuid == Y.cuid && X.sp == Y.sp && X.ep == Y.ep && X.ds == Y.ds && X.finish == Y.finish ? true : false)
+class Segment {
+public:
+  int index;
+  int length;
+  int segmentLength;
+  int writtenLength;
+
+  Segment(int index, int length, int segmentLength, int writtenLength = 0)
+    :index(index), length(length), segmentLength(segmentLength),
+     writtenLength(writtenLength) {}
+
+  Segment():index(-1), length(0), segmentLength(0), writtenLength(0) {}
+
+  bool complete() const {
+    return length <= writtenLength;
+  }
+
+  bool isNull() const {
+    return index == -1;
+  }
+
+  long long int getPosition() const {
+    return ((long long int)index)*segmentLength;
+  }
+
+  bool operator==(const Segment& segment) const {
+    return index == segment.index &&
+      length == segment.length &&
+      segmentLength == segment.segmentLength &&
+      writtenLength == segment.writtenLength;
+  }
+
+  bool operator!=(const Segment& segment) const {
+    return !(*this == segment);
+  }
+
+  friend ostream& operator<<(ostream& o, const Segment& segment);
+};
+
+ostream& operator<<(ostream& o, const Segment& segment);
 
 #endif // _D_SEGMENT_H_
 

+ 271 - 100
src/SegmentMan.cc

@@ -31,88 +31,21 @@
 #include <unistd.h>
 #include <errno.h>
 
-SegmentMan::SegmentMan():totalSize(0),
+SegmentMan::SegmentMan():bitfield(0),
+			 totalSize(0),
 			 isSplittable(true), 
 			 downloadStarted(false),
 			 dir("."),
 			 errors(0),
-			 splitter(NULL),
-			 diskWriter(NULL) {
+			 diskWriter(0) {
   logger = LogFactory::getInstance();
 }
 
 SegmentMan::~SegmentMan() {
-  if(splitter != NULL) {
-    delete splitter;
-  }
-  if(diskWriter != NULL) {
-    delete diskWriter;
-  }
+  delete bitfield;
+  delete diskWriter;
 }
 
-void SegmentMan::unregisterId(int cuid) {
-  for(Segments::iterator itr = segments.begin(); itr != segments.end(); itr++) {
-    if((*itr).cuid == cuid) {
-      cuid = 0;
-    }
-  }
-}
-
-bool SegmentMan::getSegment(Segment& seg, int cuid) {
-  //Segment s = { 0, 0, 0, false };
-
-  if(segments.empty()) {
-    logger->debug(string("assign new segment { sp = 0, ep = "+(totalSize == 0 ? "0" : Util::llitos(totalSize-1))+" } to cuid "+Util::llitos(cuid)).c_str());
-    //seg = { cuid, 0, totalSize == 0 ? 0 : totalSize-1, 0, false };
-    seg.cuid = cuid;
-    seg.sp = 0;
-    seg.ep = totalSize == 0 ? 0 : totalSize-1;
-    seg.ds = 0;
-    seg.speed = 0;
-    seg.finish = false;
-    segments.push_back(seg);
-    return true;
-  }
-  for(Segments::iterator itr = segments.begin(); itr != segments.end(); itr++) {
-    if((*itr).cuid == cuid && !(*itr).finish) {
-//       logger->debug("return an existing segment { "
-// 		    "sp = "+Util::ulitos((*itr).sp)+", "+
-// 		    "ep = "+Util::ulitos((*itr).ep)+", "
-// 		    "ds = "+Util::ulitos((*itr).ds)+" } to "+
-// 		    "cuid "+Util::ulitos((*itr).cuid));
-      seg = *itr;
-      return true;
-    }
-  }
-  if(!isSplittable) {
-    return false;
-  }
-  for(Segments::iterator itr = segments.begin(); itr != segments.end(); itr++) {
-    Segment& s = *itr;
-    if(s.finish) {
-      continue;
-    }
-    if(s.cuid == 0) {
-      s.cuid = cuid;
-      seg = s;
-      return true;
-    }
-  }
-  return splitter->splitSegment(seg, cuid, segments);
-}
-
-void SegmentMan::updateSegment(const Segment& segment) {
-  for(Segments::iterator itr = segments.begin(); itr != segments.end(); itr++) {
-    if((*itr).cuid == segment.cuid && 
-       (*itr).sp == segment.sp &&
-       (*itr).ep == segment.ep) {
-      *itr = segment;
-      break;
-    }
-  } 
-}
-
-
 bool SegmentMan::segmentFileExists() const {
   if(!isSplittable) {
     return false;
@@ -144,10 +77,6 @@ void SegmentMan::load() {
 			segFilename.c_str(), strerror(errno));
   }
   logger->info(MSG_LOADED_SEGMENT_FILE);
-  for(Segments::iterator itr = segments.begin(); itr != segments.end();
-      itr++) {
-    (*itr).cuid = 0;
-  }
 }
 
 void SegmentMan::save() const {
@@ -161,8 +90,32 @@ void SegmentMan::save() const {
     if(fwrite(&totalSize, sizeof(totalSize), 1, segFile) < 1) {
       throw string("writeError");
     }
-    for(Segments::const_iterator itr = segments.begin(); itr != segments.end(); itr++) {
-      if(fwrite(&*itr, sizeof(Segment), 1, segFile) < 1) {
+    int segmentLength = bitfield->getBlockLength();
+    if(fwrite(&segmentLength, sizeof(segmentLength), 1, segFile) < 1) {
+      throw string("writeError");
+    }
+    if(bitfield) {
+      int bitfieldLength = bitfield->getBitfieldLength();
+      if(fwrite(&bitfieldLength, sizeof(bitfieldLength), 1, segFile) < 1) {
+	throw string("writeError");
+      }
+      if(fwrite(bitfield->getBitfield(), bitfield->getBitfieldLength(),
+		1, segFile) < 1) {
+	throw string("writeError");
+      }					 
+    } else {
+      int i = 0;
+      if(fwrite(&i, sizeof(i), 1, segFile) < 1) {
+	throw string("writeError");
+      }
+    }
+    int usedSegmentCount = usedSegmentEntries.size();
+    if(fwrite(&usedSegmentCount, sizeof(usedSegmentCount), 1, segFile) < 1) {
+      throw string("writeError");
+    }
+    for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin();
+	itr != usedSegmentEntries.end(); itr++) {
+      if(fwrite(&itr->segment, sizeof(Segment), 1, segFile) < 1) {
 	throw string("writeError");
       }
     }
@@ -189,16 +142,35 @@ void SegmentMan::read(FILE* file) {
   if(fread(&totalSize, sizeof(totalSize), 1, file) < 1) {
     throw string("readError");
   }
-  while(1) {
+  int segmentSize;
+  if(fread(&segmentSize, sizeof(segmentSize), 1, file) < 1) {
+    throw string("readError");
+  }
+  int bitfieldLength;
+  if(fread(&bitfieldLength, sizeof(bitfieldLength), 1, file) < 1) {
+    throw string("readError");
+  }
+  if(bitfieldLength > 0) {
+    initBitfield(segmentSize, totalSize);
+    unsigned char* savedBitfield = new unsigned char[bitfield->getBitfieldLength()];
+    if(fread(savedBitfield, bitfield->getBitfieldLength(), 1, file) < 1) {
+      delete [] savedBitfield;
+      throw string("readError");
+    } else {
+      bitfield->setBitfield(savedBitfield, bitfield->getBitfieldLength());
+      delete [] savedBitfield;
+    }
+  }
+  int segmentCount;
+  if(fread(&segmentCount, sizeof(segmentCount), 1, file) < 1) {
+    throw string("readError");
+  }
+  while(segmentCount--) {
     Segment seg;
     if(fread(&seg, sizeof(Segment), 1, file) < 1) {
-      if(ferror(file)) {
-	throw string("readError");
-      } else if(feof(file)) {
-	break;
-      }
+      throw string("readError");
     }
-    segments.push_back(seg);
+    usedSegmentEntries.push_back(SegmentEntry(0, seg));
   }
 }
 
@@ -213,15 +185,14 @@ void SegmentMan::remove() const {
 }
 
 bool SegmentMan::finished() const {
-  if(!downloadStarted || segments.size() == 0) {
+  if(!downloadStarted) {
     return false;
   }
-  for(Segments::const_iterator itr = segments.begin(); itr != segments.end(); itr++) {
-    if(!(*itr).finish) {
-      return false;
-    }
+  if(!bitfield) {
+    return false;
   }
-  return true;
+  assert(bitfield);
+  return bitfield->isAllBitSet();
 }
 
 void SegmentMan::removeIfFinished() const {
@@ -230,19 +201,219 @@ void SegmentMan::removeIfFinished() const {
   }
 }
 
-long long int SegmentMan::getDownloadedSize() const {
-  long long int size = 0;
-  for(Segments::const_iterator itr = segments.begin(); itr != segments.end(); itr++) {
-    size += (*itr).ds;
-  }
-  return size;
-}
-
 void SegmentMan::init() {
   totalSize = 0;
   isSplittable = false;
   downloadStarted = false;
   errors = 0;
-  segments.clear();
+  //segments.clear();
+  usedSegmentEntries.clear();
+  delete bitfield;
+  peerStats.clear();
   diskWriter->closeFile();
+  
+}
+
+void SegmentMan::initBitfield(int segmentLength, long long int totalLength) {
+  this->bitfield = new BitfieldMan(segmentLength, totalLength);
+}
+
+class FindSegmentEntryByIndex {
+private:
+  int index;
+public:
+  FindSegmentEntryByIndex(int index):index(index) {}
+  
+  bool operator()(const SegmentEntry& entry) {
+    return entry.segment.index == index;
+  }
+};
+
+class FindSegmentEntryByCuid {
+private:
+  int cuid;
+public:
+  FindSegmentEntryByCuid(int cuid):cuid(cuid) {}
+
+  bool operator()(const SegmentEntry& entry) {
+    return entry.cuid == cuid;
+  }
+};
+
+Segment SegmentMan::checkoutSegment(int cuid, int index) {
+  logger->debug("Attach segment#%d to CUID#%d.", index, cuid);
+  bitfield->setUseBit(index);
+
+  SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
+					 usedSegmentEntries.end(),
+					 FindSegmentEntryByIndex(index));
+  Segment segment;
+  if(itr == usedSegmentEntries.end()) {
+    segment = Segment(index, bitfield->getBlockLength(index),
+		       bitfield->getBlockLength());
+    SegmentEntry entry(cuid, segment);
+    usedSegmentEntries.push_back(entry);
+  } else {
+    (*itr).cuid = cuid;
+    segment = (*itr).segment;
+  }
+
+  logger->debug("index=%d, length=%d, segmentLength=%d, writtenLength=%d",
+		segment.index, segment.length, segment.segmentLength,
+		segment.writtenLength);
+  return segment;
+}
+
+bool SegmentMan::onNullBitfield(Segment& segment, int cuid) {
+  if(usedSegmentEntries.size() == 0) {
+    segment = Segment(0, 0, 0);
+    usedSegmentEntries.push_back(SegmentEntry(cuid, segment));
+    return true;
+  } else {
+    SegmentEntries::iterator uitr = find_if(usedSegmentEntries.begin(),
+					    usedSegmentEntries.end(),
+					    FindSegmentEntryByCuid(cuid));
+    if(uitr == usedSegmentEntries.end()) {
+      return false;
+    } else {
+      segment = uitr->segment;
+      return true;
+    }
+  }
+}
+
+bool SegmentMan::getSegment(Segment& segment, int cuid) {
+  if(!bitfield) {
+    return onNullBitfield(segment, cuid);
+  }
+  SegmentEntries::iterator uitr = find_if(usedSegmentEntries.begin(),
+					  usedSegmentEntries.end(),
+					  FindSegmentEntryByCuid(cuid));
+  if(uitr != usedSegmentEntries.end()) {
+    segment = uitr->segment;
+    return true;
+  }
+  int index = bitfield->getSparseMissingUnusedIndex();
+  if(index == -1) {
+    return false;
+  } else {
+    segment = checkoutSegment(cuid, index);
+    return true;
+  }
+}
+
+bool SegmentMan::getSegment(Segment& segment, int cuid, int index) {
+  if(!bitfield) {
+    return onNullBitfield(segment, cuid);
+  }
+  if(index < 0 || bitfield->countBlock() <= index) {
+    return false;
+  }
+  if(bitfield->isBitSet(index) || bitfield->isUseBitSet(index)) {
+    return false;
+  } else {
+    segment = checkoutSegment(cuid, index);
+    return true;
+  }
+}
+
+bool SegmentMan::updateSegment(int cuid, const Segment& segment) {
+  if(segment.isNull()) {
+    return false;
+  }
+  SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
+					 usedSegmentEntries.end(),
+					 FindSegmentEntryByCuid(cuid));
+  if(itr == usedSegmentEntries.end()) {
+    return false;
+  } else {
+    (*itr).segment = segment;
+    return true;
+  }
+}
+
+class CancelSegment {
+private:
+  int cuid;
+  BitfieldMan* bitfield;
+public:
+  CancelSegment(int cuid, BitfieldMan* bitfield):cuid(cuid),
+						 bitfield(bitfield) {}
+  
+  void operator()(SegmentEntry& entry) {
+    if(entry.cuid == cuid) {
+      bitfield->unsetUseBit(entry.segment.index);
+      entry.cuid = 0;
+    }
+  }
+};
+
+void SegmentMan::cancelSegment(int cuid) {
+  if(bitfield) {
+    for_each(usedSegmentEntries.begin(), usedSegmentEntries.end(),
+	     CancelSegment(cuid, bitfield));
+  } else {
+    usedSegmentEntries.clear();
+  }
+}
+
+bool SegmentMan::completeSegment(int cuid, const Segment& segment) {
+  if(segment.isNull()) {
+    return false;
+  }
+  if(bitfield) {
+    bitfield->unsetUseBit(segment.index);
+    bitfield->setBit(segment.index);
+  } else {
+    initBitfield(option->getAsInt(PREF_SEGMENT_SIZE), segment.writtenLength);
+    bitfield->setAllBit();
+  }
+  SegmentEntries::iterator itr = find_if(usedSegmentEntries.begin(),
+					 usedSegmentEntries.end(),
+					 FindSegmentEntryByCuid(cuid));
+  if(itr == usedSegmentEntries.end()) {
+    return false;
+  } else {
+    usedSegmentEntries.erase(itr);
+    return true;
+  }
+}
+
+bool SegmentMan::hasSegment(int index) const {
+  if(bitfield) {
+    return bitfield->isBitSet(index);
+  } else {
+    return false;
+  }
+}
+
+long long int SegmentMan::getDownloadLength() const {
+  long long int dlLength = 0;
+  if(bitfield) {
+    dlLength += bitfield->getCompletedLength();
+  }
+  for(SegmentEntries::const_iterator itr = usedSegmentEntries.begin();
+      itr != usedSegmentEntries.end(); itr++) {
+    dlLength += itr->segment.writtenLength;
+  }
+  return dlLength;
+}
+
+void SegmentMan::registerPeerStat(const PeerStatHandle& peerStat) {
+  PeerStatHandle temp = getPeerStat(peerStat->getCuid());
+  if(!temp.get()) {
+    peerStats.push_back(peerStat);
+  }
+}
+
+int SegmentMan::calculateDownloadSpeed() const {
+  int speed = 0;
+  for(PeerStats::const_iterator itr = peerStats.begin();
+      itr != peerStats.end(); itr++) {
+    const PeerStatHandle& peerStat = *itr;
+    if(peerStat->getStatus() == PeerStat::ACTIVE) {
+      speed += peerStat->calculateDownloadSpeed();
+    }
+  }
+  return speed;
 }

+ 97 - 33
src/SegmentMan.h

@@ -26,23 +26,42 @@
 #include "Logger.h"
 #include "Segment.h"
 #include "Option.h"
-#include "SegmentSplitter.h"
 #include "DiskWriter.h"
 #include "Request.h"
+#include "BitfieldMan.h"
+#include "PeerStat.h"
 
 using namespace std;
 
 #define SEGMENT_FILE_EXTENSION ".aria2"
 
+class SegmentEntry {
+public:
+  int cuid;
+  Segment segment;
+public:
+  SegmentEntry(int cuid, const Segment& segment)
+    :cuid(cuid), segment(segment) {}
+  ~SegmentEntry() {}
+};
+
+typedef deque<SegmentEntry> SegmentEntries;
+typedef deque<PeerStatHandle> PeerStats;
+
 /**
  * This class holds the download progress of the one download entry.
  */
 class SegmentMan {
 private:
   const Logger* logger;
+  BitfieldMan* bitfield;
+  SegmentEntries usedSegmentEntries;
+  PeerStats peerStats;
 
   void read(FILE* file);
   FILE* openSegFile(const string& segFilename, const string& mode) const;
+  bool onNullBitfield(Segment& segment, int cuid);
+  Segment checkoutSegment(int cuid, int index);
 public:
   /**
    * The total number of bytes to download.
@@ -65,10 +84,6 @@ public:
    * The default value is false.
    */
   bool downloadStarted;
-  /**
-   * Holds segments.
-   */
-  Segments segments;
   /**
    * Respresents the file name of the downloaded file.
    * If the URL does not contain file name part(http://www.rednoah.com/, for 
@@ -91,7 +106,6 @@ public:
   int errors;
 
   const Option* option;
-  SegmentSplitter* splitter;
   DiskWriter* diskWriter;
   Requests reserved;
 
@@ -116,31 +130,6 @@ public:
     return getFilePath()+SEGMENT_FILE_EXTENSION;
   }
 
-  /**
-   * Sets the cuid of the holded segments with specified cuid to 0.
-   */
-  void unregisterId(int cuid);
-  /**
-   * There is a segment available for DownloadCommand specified by cuid,
-   * fills segment and returns true.
-   * There is no segment available, then returns false and segment is
-   * undefined in this case.
-   *
-   * @param segment segment to attach for cuid.
-   * @param cuid cuid of DownloadCommand.
-   * @returns true: there is a segment available, false: there is no segment
-   * available.
-   */
-  bool getSegment(Segment& segment, int cuid);
-  /**
-   * Updates the ds value of the specified segment.
-   * Only a segment x is updated where x.sp == sgment.sp &amp;&amp; x.ep ==
-   * segment.ep &amp;&amp; x.ds == segment.ds &amp;&amp;x.cuid == segment.cuid
-   * is true.
-   *
-   * @param segment segment to update
-   */
-  void updateSegment(const Segment& segment);
   /**
    * Returns true only if the segment data file exists.
    * The file name of the segment data is filename appended by ".aria2".
@@ -173,9 +162,84 @@ public:
    */
   void removeIfFinished() const;
   /**
-   * Returns the total number of bytes to be downloaded.
+   * Returns a vacant segment.
+   * If there is no vacant segment, then returns a segment instance whose
+   * isNull call is true.
+   */
+  bool getSegment(Segment& segment, int cuid);
+  /**
+   * Returns a segment whose index is index. 
+   * If it has already assigned
+   * to another cuid or has been downloaded, then returns a segment instance
+   * whose isNull call is true.
+   */
+  bool getSegment(Segment& segment, int cuid, int index);
+  /**
+   * Updates download status.
+   */
+  bool updateSegment(int cuid, const Segment& segment);
+  /**
+   * Cancels all the segment which the command having given cuid
+   * uses.
+   */
+  void cancelSegment(int cuid);
+  /**
+   * Tells SegmentMan that the segment has been downloaded successfully.
+   */
+  bool completeSegment(int cuid, const Segment& segment);
+  /**
+   * Initializes bitfield with the provided length parameters.
+   */
+  void initBitfield(int segmentLength, long long int totalLength);
+  /**
+   * Returns true if the segment whose index is index has been downloaded.
+   */
+  bool hasSegment(int index) const;
+  /**
+   * Returns the length of bytes downloaded.
+   */
+  long long int getDownloadLength() const;
+
+  /**
+   * Registers given peerStat if it has not been registerd.
+   * Otherwise does nothing.
+   */
+  void registerPeerStat(const PeerStatHandle& peerStat);
+
+  class FindPeerStat {
+  private:
+    int cuid;
+  public:
+    FindPeerStat(int cuid):cuid(cuid) {}
+
+    bool operator()(const PeerStatHandle& peerStat) {
+      if(peerStat->getCuid() == cuid) {
+	return true;
+      } else {
+	return false;
+      }
+    }
+  };
+
+  /**
+   * Returns peerStat whose cuid is given cuid. If it is not found, returns
+   * PeerStatHandle(0).
+   */
+  PeerStatHandle getPeerStat(int cuid) const {
+    PeerStats::const_iterator itr = find_if(peerStats.begin(), peerStats.end(),
+					    FindPeerStat(cuid));
+    if(itr == peerStats.end()) {
+      // TODO
+      return PeerStatHandle(0);
+    } else {
+      return *itr;
+    }
+  }
+
+  /**
+   * Returns current download speed in bytes per sec. 
    */
-  long long int getDownloadedSize() const;
+  int calculateDownloadSpeed() const;
 };
 
 #endif // _D_SEGMENT_MAN_H_

+ 82 - 0
src/SpeedCalc.cc

@@ -0,0 +1,82 @@
+/* <!-- 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 "SpeedCalc.h"
+#include <algorithm>
+#include <ostream>
+#include <iterator>
+
+#define CHANGE_INTERVAL_SEC 15
+
+class Reset {
+public:
+  void operator()(Time& tm) {
+    tm.reset();
+  }
+};
+
+void SpeedCalc::reset() {
+  fill(&lengthArray[0], &lengthArray[2], 0);
+  for_each(&cpArray[0], &cpArray[2], Reset());
+  sw = 0;
+  maxSpeed = 0;
+  prevSpeed = 0;
+}
+
+int SpeedCalc::calculateSpeed() {
+  int milliElapsed = cpArray[sw].differenceInMillis();
+  if(milliElapsed) {
+    int speed = lengthArray[sw]*1000/milliElapsed;
+    prevSpeed = speed;
+    maxSpeed = max<int>(speed, maxSpeed);
+    return speed;
+  } else {
+    return prevSpeed;
+  }
+}
+
+class Plus {
+private:
+  int d;
+public:
+  Plus(int d):d(d) {}
+
+  void operator()(long long int& length) {
+    length += d;
+  }
+};
+
+void SpeedCalc::update(int bytes) {
+  for_each(&lengthArray[0], &lengthArray[2], Plus(bytes));
+  if(isIntervalOver()) {
+    changeSw();
+  }
+}
+
+bool SpeedCalc::isIntervalOver() const {
+  return CHANGE_INTERVAL_SEC <= cpArray[sw].difference();
+}
+
+void SpeedCalc::changeSw() {
+  lengthArray[sw] = 0;
+  cpArray[sw].reset();
+  sw ^= 0x01;
+}

+ 59 - 0
src/SpeedCalc.h

@@ -0,0 +1,59 @@
+/* <!-- 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_SPEED_CALC_H_
+#define _D_SPEED_CALC_H_
+
+#include "common.h"
+#include "TimeA2.h"
+
+class SpeedCalc {
+private:
+  long long int lengthArray[2];
+  int sw;
+  Time cpArray[2];
+  int maxSpeed;
+  int prevSpeed;
+
+  bool isIntervalOver() const;
+  void changeSw();
+public:
+  SpeedCalc() {
+    reset();
+  }
+
+  ~SpeedCalc() {}
+
+  /**
+   * Returns download/upload speed in byte per sec
+   */
+  int calculateSpeed();
+
+  int getMaxSpeed() const {
+    return maxSpeed;
+  }
+
+  void update(int bytes);
+
+  void reset();
+};
+
+#endif // _D_SPEED_CALC_H_

+ 3 - 1
src/main.cc

@@ -22,7 +22,6 @@
 #include "HttpInitiateConnectionCommand.h"
 #include "ConsoleDownloadEngine.h"
 #include "SegmentMan.h"
-#include "SplitSlowestSegmentSplitter.h"
 #include "LogFactory.h"
 #include "common.h"
 #include "DefaultDiskWriter.h"
@@ -272,6 +271,8 @@ int main(int argc, char* argv[]) {
   op->put(PREF_DIR, ".");
   op->put(PREF_SPLIT, "1");
   op->put(PREF_DAEMON, V_FALSE);
+  op->put(PREF_SEGMENT_SIZE, Util::itos(1024*1024));
+  op->put(PREF_HTTP_KEEP_ALIVE, V_FALSE);
   op->put(PREF_LISTEN_PORT, "-1");
   op->put(PREF_METALINK_SERVERS, "15");
   op->put(PREF_FOLLOW_TORRENT,
@@ -303,6 +304,7 @@ int main(int argc, char* argv[]) {
   op->put(PREF_DIRECT_FILE_MAPPING, V_TRUE);
   op->put(PREF_UPLOAD_LIMIT, "0");
   op->put(PREF_LOWEST_SPEED_LIMIT, "0");
+  op->put(PREF_MAX_SPEED_LIMIT, "0");
   while(1) {
     int optIndex = 0;
     int lopt;

+ 7 - 1
src/prefs.h

@@ -57,8 +57,12 @@
 #define PREF_DAEMON "daemon"
 // value: a string
 #define PREF_REFERER "referer"
-// value' 1*digit
+// value: 1*digit
 #define PREF_LOWEST_SPEED_LIMIT "lowest_speed_limit"
+// value: 1*digit
+#define PREF_SEGMENT_SIZE "segment_size"
+// value: 1*digit
+#define PREF_MAX_SPEED_LIMIT "max_speed_limit"
 
 /**
  * FTP related preferences
@@ -86,6 +90,8 @@
 #  define V_BASIC "basic"
 // values: true | false
 #define PREF_HTTP_AUTH_ENABLED "http_auth_enabled"
+// values: true | false
+#define PREF_HTTP_KEEP_ALIVE "http_keep_alive"
 
 /** 
  * HTTP proxy related preferences

+ 28 - 0
test/BitfieldManTest.cc

@@ -12,6 +12,7 @@ class BitfieldManTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testIsAllBitSet);
   CPPUNIT_TEST(testFilter);
   CPPUNIT_TEST(testGetMissingIndex);
+  CPPUNIT_TEST(testGetSparceMissingUnusedIndex);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -24,6 +25,7 @@ public:
   void testIsAllBitSet();
   void testFilter();
   void testGetMissingIndex();
+  void testGetSparceMissingUnusedIndex();
 };
 
 
@@ -209,3 +211,29 @@ void BitfieldManTest::testGetMissingIndex() {
   CPPUNIT_ASSERT_EQUAL(-1, bt1.getMissingIndex(bitArray5, 32));
 
 }
+
+void BitfieldManTest::testGetSparceMissingUnusedIndex() {
+  BitfieldMan bitfield(1024*1024, 10*1024*1024);
+
+  CPPUNIT_ASSERT_EQUAL(0, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(0);
+  CPPUNIT_ASSERT_EQUAL(5, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setUseBit(5);
+  CPPUNIT_ASSERT_EQUAL(3, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(3);
+  CPPUNIT_ASSERT_EQUAL(8, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(8);
+  CPPUNIT_ASSERT_EQUAL(2, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(2);
+  CPPUNIT_ASSERT_EQUAL(7, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(7);
+  CPPUNIT_ASSERT_EQUAL(1, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(1);
+  CPPUNIT_ASSERT_EQUAL(4, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(4);
+  CPPUNIT_ASSERT_EQUAL(6, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(6);
+  CPPUNIT_ASSERT_EQUAL(9, bitfield.getSparseMissingUnusedIndex());
+  bitfield.setBit(9);
+  CPPUNIT_ASSERT_EQUAL(-1, bitfield.getSparseMissingUnusedIndex());
+}

+ 3 - 1
test/Makefile.am

@@ -37,7 +37,9 @@ aria2c_SOURCES = AllTest.cc\
 	MetalinkEntryTest.cc\
 	FeatureConfigTest.cc\
 	ShareRatioSeedCriteriaTest.cc\
-	TimeSeedCriteriaTest.cc
+	TimeSeedCriteriaTest.cc\
+	SegmentManTest.cc\
+	SpeedCalcTest.cc
 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
 

+ 7 - 2
test/Makefile.in

@@ -76,7 +76,8 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \
 	Xml2MetalinkProcessorTest.$(OBJEXT) MetalinkerTest.$(OBJEXT) \
 	MetalinkEntryTest.$(OBJEXT) FeatureConfigTest.$(OBJEXT) \
 	ShareRatioSeedCriteriaTest.$(OBJEXT) \
-	TimeSeedCriteriaTest.$(OBJEXT)
+	TimeSeedCriteriaTest.$(OBJEXT) SegmentManTest.$(OBJEXT) \
+	SpeedCalcTest.$(OBJEXT)
 aria2c_OBJECTS = $(am_aria2c_OBJECTS)
 am__DEPENDENCIES_1 =
 aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
@@ -267,7 +268,9 @@ aria2c_SOURCES = AllTest.cc\
 	MetalinkEntryTest.cc\
 	FeatureConfigTest.cc\
 	ShareRatioSeedCriteriaTest.cc\
-	TimeSeedCriteriaTest.cc
+	TimeSeedCriteriaTest.cc\
+	SegmentManTest.cc\
+	SpeedCalcTest.cc
 
 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
@@ -358,8 +361,10 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RejectMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentManTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitorTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShareRatioSeedCriteriaTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SpeedCalcTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentManTest.Po@am__quote@