Преглед на файлове

2006-05-18 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

	To remove a wait from download loop:

	* src/DownloadEngine.cc
	(run): Comment out shortSleep.
	
        To rewrite the message handling:
	
	* src/CancelMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(create): New function.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/CancelMessage.cc
	(create): New function.
	(receivedAction): Replaced deleteRequestMessageInQueue with
	rejectPieceMessageInQueue.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/BitfieldMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(msgLength): New variable.
	(~BitfieldMessage): Deleted msg.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/BitfieldMessage.cc
	(create): New function.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/ChokeMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(sendPredicate): New function.
	(onSendComplete): New function.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	(create): New function.
	* src/ChokeMessage.cc
	(create): New function.
	(send): Removed.
	(sendPredicate): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	(onSendComplete): New function.
	* src/KeepAliveMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.	
	* src/KeepAliveMessage.cc
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/PortMessage.h
	(create): New function.
	(receivedAction): Updated log message.
	* src/PortMessage.cc: New file.
	* src/UnchokeMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(sendPredicate): New function.
	(onSendComplete): New function.
	(create): New function.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/UnchokeMessage.cc
	(create): New function.
	(send): Removed.
	(sendPredicate): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	(onSendComplete): New function.
	* src/PieceMessage.h
	(leftPieceDataLength): Removed.
	(leftDataLength): New variable.
	(headerSend): New variable.
	(pendingCount): New variable.
	(msgHeader): New variable.
	(sendPieceData): New function.
	(incrementPendingCount): New function.
	(isPendingCountMax): New function.
	(create): New function.
	(getMessageHeader): New function.
	(getMessageHeaderLength): New function.
	* src/PieceMessage.cc
	(create): New function.
	(getMessageHeader): New function.
	(getMessageHeaderLength): New function.
	(send): Rewritten.
	(sendPieceData): New function.
	* src/HaveMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(create): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/HaveMessage.cc
	(create): New function.
	(send): Removed.
	(sendPieceData): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/RequestMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(create): New function.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/RequestMessage.cc
	(create): New function.
	(receivedAction): Added the handling of fast extension.
	Deleted torrentMan->addUploadLength, 
torrentMan->addDeltaUploadLength.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/InterestedMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(sendPredicate): New function.
	(onSendComplete): New function.
	(create): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/InterestedMessage.cc
	(create): New function.
	(send): Removed.
	(sendPieceData): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	(onSendComplete): New function.
	* src/NotInterestedMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(sendPieceData): New function.
	(onSendComplete): New function.
	(create): New function.
	(send): Removed.
	(getMessage): New function.
	(getMessageLength): New function.
	* src/NotInterestedMessage.cc
	(create): New function.
	(send): Removed.
	(sendPredicate): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	(onSendComplete): New function.
	* src/AllowedFastMessage.h: New class.
	* src/AllowedFastMessage.cc: New class.
	* src/RejectMessage.h: New class.
	* src/RejectMessage.cc: New class.
	* src/SuggestPieceMessage.h: New class.
	* src/SuggestPieceMessage.cc: New class.
	* src/HaveAllMessage.h: New class.
	* src/HaveAllMessage.cc: New class.
	* src/HaveNoneMessage.h: New class.
	* src/HaveNoneMessage.cc: New class.
	* src/HandshakeMessage.h: Derived from SimplePeerMessage.
	(msg): New variable.
	(reserved): New variable.
	(create): New function.
	(getId): New function.
	(receivedAction): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	(isFastExtensionSupported): New function.
	* src/HandshakeMessage.cc
	(HandshakeMessage): Moved here from HandshakeMessage.h.
	(create): New function.
	(getMessage): New function.
	(getMessageLength): New function.
	(toString): Added the output of reserved field.
	(check): Added const qualifier.
	(isFastExtensionSupported): New function.
	* src/PeerMessageUtil.h
	(createChokeMessage): Removed.
	(createUnchokeMessage): Removed.
	(createInterestedMessage): Removed.
	(createNotInterestedMessage): Removed.
	(createHaveMessage): Removed.
	(createBitfieldMessage): Removed.
	(createRequestMessage): Removed.
	(createCancelMessage): Removed.
	(createPieceMessage): Removed.
	(createPortMessage): Removed.
	(createChokeMessage): Removed.
	(createUnchokeMessage): Removed.
	(createInterestedMessage): Removed.
	(createNotInterestedMessage): Removed.
	(createHaveMessage): Removed.
	(createBitfieldMessage): Removed.
	(createRequestMessage): Removed.
	(createCancelMessage): Removed.
	(createPieceMessage): Removed.
	(createKeepAliveMessage): Removed.
	(createHandshakeMessage): Removed.
	(setIntParam): New function.
	(createPeerMessageString): New function.
	* src/PeerMessageUtil.cc
	(createChokeMessage): Removed.
	(createUnchokeMessage): Removed.
	(createInterestedMessage): Removed.
	(createNotInterestedMessage): Removed.
	(createHaveMessage): Removed.
	(createBitfieldMessage): Removed.
	(createRequestMessage): Removed.
	(createCancelMessage): Removed.
	(createPieceMessage): Removed.
	(createPortMessage): Removed.
	(createRequestMessage): Removed.
	(createCancelMessage): Removed.
	(createPieceMessage): Removed.
	(createHaveMessage): Removed.
	(createChokeMessage): Removed.
	(createUnchokeMessage): Removed.
	(createInterestedMessage): Removed.
	(createNotInterestedMessage): Removed.
	(createBitfieldMessage): Removed.
	(createKeepAliveMessage): Removed.
	(createHandshakeMessage): Removed.
	(setIntParam): New function.
	(createPeerMessageString): New function.
	* src/PeerConnection.h
	(peer): Removed.
	(torrentMan): Removed.
	(createNLengthMessage): Removed.
	(setIntParam): Removed.
	(writeOutgoingMessageLog): Removed all overloaded functions.
	(PeerConnection): Deleted peer and torrentMan from its 
arguments.
	(sendMessage): New function.
	(sendHandshake): Removed.
	(sendKeepAlive): Removed.
	(sendChoke): Removed.
	(sendUnchoke): Removed.
	(sendInterested): Removed.
	(sendNotInterested): Removed.
	(sendHave): Removed.
	(sendBitfield): Removed.
	(sendRequest): Removed.
	(sendPiece): Removed.
	(sendPieceHeader): Removed.
	(sendPieceData): Removed.
	(sendCancel): Removed.
	(getPeer): Removed.
	* src/PeerConnection.cc
	(PeerConnection): Deleted peer and torrentMan from its 
arguments.
	(sendHandshake): Removed.
	(sendKeepAlive): Removed.
	(createNLengthMessage): Removed.
	(setIntParam): Removed.
	(writeOutgoingMessageLog): Removed all overloaded functions.
	(sendChoke): Removed.
	(sendUnchoke): Removed.
	(sendInterested): Removed.
	(sendNotInterested): Removed.
	(sendHave): Removed.
	(sendBitfield): Removed.
	(sendRequest): Removed.
	(sendPiece): Removed.
	(sendPieceHeader): Removed.
	(sendPieceData): Removed.
	(sendMessage): New function.
	(sendCancel): Removed.
	* src/PeerInteractionCommand.cc
	(PeerInteractionCommand): Call setUploadLimit.
	(executeInternal): Call setUploadLimit.
	Added the handling of "inProgress" state of handshake message.
	Call sendBitfield() or sendAllowdFast() instead of deprecated
	sendNow().
	(keepAlive): Call addMessage and sendMessage instead of 
deprecated
	sendNow().
	(beforeSocketCheck): Call addMessage instead of deprecated 
trySendNow()
	* src/TorrentMan.h
	(PEER_ID_LENGTH): New definition.
	(hasAllPieces): New function.
	* src/TorrentMan.cc
	(getMissingPiece): Added the handling of fast extension.
	(cancelPiece): Call updatePiece().
	(hasAllPieces): New function.
	* src/PeerInteraction.h
	(fastSet): New variable.
	(getNewPieceAndSendInterest): Changed the return type to void.
	(send): Renamed as sendMessages.
	(deleteAllRequestSlot): Removed.
	(deleteRequestMessageInQueue): Renamed as 
rejectPieceMessageInQueue.
	(cancelAllRequest): Removed all overloaded functions.
	(deleteAllRequestSlot): Removed.
	(deletePieceMessageInQueue): Renamed as 
rejectAllPieceMessageInQueue.
	(rejectPieceMessageInQueue): New function.
	(rejectAllPieceMessageInQueue): New function.
	(onChoked): New function.
	(isSendingMessageInProgress): New function.
	(getCorrespondingRequestSlot): Changed its arguments.
	(isInFastSet): New function.
	(addFastSetIndex): New function.
	(addRequests): New function.
	(sendNow): Removed.
	(trySendNow): Removed.
	(sendBitfield): New function.
	(sendAllowdFast): New function.
	(createHaveAllMessage): New function.
	(createHaveNoneMessage): New function.
	(createRejectMessage): New function.
	(createAllowedFastMessage): New function.
	* src/PeerInteraction.cc
	(send): Renamed as sendMessages.
	(sendMessages): New function.
	(MsgPushBack): New class.
	(isSendingMessageInProgress): New function.
	(deletePieceMessageInQueue): Renamed as 
rejectAllPieceMessageInQueue.
	(rejectAllPieceMessageInQueue): New function.
	Added the handling of fast extension.
	(deleteRequestMessageInQueue): Renamed as 
rejectPieceMessageInQueue.
	(rejectPieceMessageInQueue): New function.
	Added the handling of fast extension.
	(deleteRequestSlot): Replaced for loop with  std::find.
	(onChoked): New function.
	(deleteAllRequestSlot): Removed.
	(abortPiece): Rewirtten.
	(deleteTimeoutRequestSlot): Updated log messages.
	(getCorrespondingRequestSlot): Changed its arguments.
	(cancelAllRequest): Removed all overloaded functions.
	(receiveHandshake): Added the check to see whether an incoming 
peer
	supports fast extension.
	(createHandshakeMessage): Use HandshakeMessage::create instead 
of
	PeerMessageUtil.
	(createPeerMessage): Use create() of each message class instead 
of
	PeerMessageUtil.
	HaveAllMessage, HaveNoneMessage, RejectMessage, 
SuggestPieceMessage,
	AllowedFastMessage were added.
	(getNewPieceAndSendInterest): Changed its return value type to 
void.
	Added the handling of fast extension.
	(addRequests): New function.
	(sendNow): Removed.
	(sendHandshake): Rewritten.
	(trySendNow): Removed.
	(sendBitfield): New function.
	(sendAllowdFast): New function.
	(isInFastSet): New function.
	(addFastSetIndex): New function.
	(createRequestMessage): Use RequestMessage::create instead of
	PeerMessageUtil.
	(createCancelMessage): Use CancelMessage::create instead of
	PeerMessageUtil.
	(createPieceMessage): Use PieceMessage::create instead of
	PeerMessageUtil.
	(createHaveMessage): Use HaveMessage::create instead of
	PeerMessageUtil.
	(createChokeMessage): Use ChokeMessage::create instead of
	PeerMessageUtil.
	(createUnchokeMessage): Use UnchokeMessage::create instead of
	PeerMessageUtil.
	(createInterestedMessage): Use InterestedMessage::create instead 
of
	PeerMessageUtil.
	(createNotInterestedMessage): Use NotInterestedMessage::create 
instead
	of PeerMessageUtil.
	(createBitfieldMessage): Use BitfieldMessage::create instead of
	PeerMessageUtil.
	(createKeepAliveMessage): Use KeepAliveMessage::create instead 
of
	PeerMessageUtil.
	(createHaveAllMessage): New function.
	(createHaveNoneMessage): New function.
	(createRejectMessage): New function.
	(createAllowedFastMessage: New function.
	* src/Util.h
	(sha1Sum): New function.
	(computeFastSet): New function.
	* src/Util.cc
	(sha1Sum): New function.
	(computeFastSet): New function.
	* src/Peer.h
	(fastExtensionEnabled): New variable.
	(fastSet): New variable.
	(setAllBitfield): New function.
	(setFastExtensionEnabled): New function.
	(isFastExtensionEnabled): New function.
	(addFastSetIndex): New function.
	(getFastSet): New function.
	(isInFastSet): New function.
	(countFastSet): New function.
	* src/Peer.cc
	(isInFastSet): New function.
	(addFastSetIndex): New function.
	(setAllBitfield): New function.
	
	* src/AbstractCommand.cc (execute): Changed the procedure of 
checking
	sockets.
	* src/PeerAbstractCommand.cc
	(PeerAbstractCommand): Added the initialization for 
uploadLimitCheck
	and uploadLimit.
	(execute): Changed the procedure of checking sockets. The upload 
speed
	checking were added.
	(setUploadLimit): New function.
	(setUploadLimitCheck): New function.
	* src/PeerAbstractCommand.h
	(setUploadLimit): New function.
	(setUploadLimitCheck): New function.
	(uploadLimit): New variable.
	(uploadLimitCheck): New variable.

	To contact a tracker regularly:
	
	* src/TrackerWatcherCommand.h (interval): New variable.
	(checkPoint): New variable.
	(TrackerWatcherCommand): Added interval argument.
	* src/TrackerWatcherCommand.cc
	(TrackerWatcherCommand): Initialized checkPoint.
	(execute): Now a tracker is contacted in every specified period.
	If peer list is not needed, send request with numwant=0.

	* src/TrackerUpdateCommand.cc
	(execute): Updated log messages.

	* src/DownloadEngine.cc
	(~DownloadEngine): Removed two asserts.
	(waitData): Uncommented wfds. May be a bug fix.
Tatsuhiro Tsujikawa преди 19 години
родител
ревизия
d018b3a609
променени са 78 файла, в които са добавени 3249 реда и са изтрити 1006 реда
  1. 418 0
      ChangeLog
  2. 3 2
      TODO
  3. 16 13
      src/AbstractCommand.cc
  4. 78 0
      src/AllowedFastMessage.cc
  5. 64 0
      src/AllowedFastMessage.h
  6. 35 2
      src/BitfieldMessage.cc
  7. 14 5
      src/BitfieldMessage.h
  8. 38 3
      src/CancelMessage.cc
  9. 9 6
      src/CancelMessage.h
  10. 39 4
      src/ChokeMessage.cc
  11. 11 4
      src/ChokeMessage.h
  12. 2 4
      src/DownloadEngine.cc
  13. 41 4
      src/HandshakeMessage.cc
  14. 20 13
      src/HandshakeMessage.h
  15. 72 0
      src/HaveAllMessage.cc
  16. 48 0
      src/HaveAllMessage.h
  17. 34 3
      src/HaveMessage.cc
  18. 10 4
      src/HaveMessage.h
  19. 71 0
      src/HaveNoneMessage.cc
  20. 48 0
      src/HaveNoneMessage.h
  21. 36 4
      src/InterestedMessage.cc
  22. 12 4
      src/InterestedMessage.h
  23. 13 2
      src/KeepAliveMessage.cc
  24. 7 4
      src/KeepAliveMessage.h
  25. 7 1
      src/Makefile.am
  26. 19 2
      src/Makefile.in
  27. 36 4
      src/NotInterestedMessage.cc
  28. 12 4
      src/NotInterestedMessage.h
  29. 16 0
      src/Peer.cc
  30. 16 1
      src/Peer.h
  31. 19 8
      src/PeerAbstractCommand.cc
  32. 4 0
      src/PeerAbstractCommand.h
  33. 13 262
      src/PeerConnection.cc
  34. 4 26
      src/PeerConnection.h
  35. 255 118
      src/PeerInteraction.cc
  36. 27 15
      src/PeerInteraction.h
  37. 30 10
      src/PeerInteractionCommand.cc
  38. 13 169
      src/PeerMessageUtil.cc
  39. 9 28
      src/PeerMessageUtil.h
  40. 102 13
      src/PieceMessage.cc
  41. 15 2
      src/PieceMessage.h
  42. 38 0
      src/PortMessage.cc
  43. 4 2
      src/PortMessage.h
  44. 93 0
      src/RejectMessage.cc
  45. 76 0
      src/RejectMessage.h
  46. 43 6
      src/RequestMessage.cc
  47. 9 4
      src/RequestMessage.h
  48. 70 0
      src/SuggestPieceMessage.cc
  49. 62 0
      src/SuggestPieceMessage.h
  50. 29 4
      src/TorrentMan.cc
  51. 3 0
      src/TorrentMan.h
  52. 12 8
      src/TrackerUpdateCommand.cc
  53. 19 8
      src/TrackerWatcherCommand.cc
  54. 4 1
      src/TrackerWatcherCommand.h
  55. 36 4
      src/UnchokeMessage.cc
  56. 12 5
      src/UnchokeMessage.h
  57. 55 0
      src/Util.cc
  58. 6 0
      src/Util.h
  59. 2 1
      src/main.cc
  60. 59 0
      test/AllowedFastMessageTest.cc
  61. 63 0
      test/BitfieldMessageTest.cc
  62. 67 0
      test/CancelMessageTest.cc
  63. 55 0
      test/ChokeMessageTest.cc
  64. 55 0
      test/HaveAllMessageTest.cc
  65. 59 0
      test/HaveMessageTest.cc
  66. 55 0
      test/HaveNoneMessageTest.cc
  67. 55 0
      test/InterestedMessageTest.cc
  68. 15 1
      test/Makefile.am
  69. 37 2
      test/Makefile.in
  70. 8 8
      test/MetaFileUtilTest.cc
  71. 55 0
      test/NotInterestedMessageTest.cc
  72. 7 208
      test/PeerMessageUtilTest.cc
  73. 69 0
      test/PieceMessageTest.cc
  74. 67 0
      test/RejectMessageTest.cc
  75. 67 0
      test/RequestMessageTest.cc
  76. 59 0
      test/SuggestPieceMessageTest.cc
  77. 55 0
      test/UnchokeMessageTest.cc
  78. 33 0
      test/UtilTest.cc

+ 418 - 0
ChangeLog

@@ -1,3 +1,421 @@
+2006-05-18  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	To remove a wait from download loop:
+
+	* src/DownloadEngine.cc
+	(run): Comment out shortSleep.
+	
+        To rewrite the message handling:
+	
+	* src/CancelMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(create): New function.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/CancelMessage.cc
+	(create): New function.
+	(receivedAction): Replaced deleteRequestMessageInQueue with
+	rejectPieceMessageInQueue.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/BitfieldMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(msgLength): New variable.
+	(~BitfieldMessage): Deleted msg.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/BitfieldMessage.cc
+	(create): New function.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/ChokeMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(sendPredicate): New function.
+	(onSendComplete): New function.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	(create): New function.
+	* src/ChokeMessage.cc
+	(create): New function.
+	(send): Removed.
+	(sendPredicate): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	(onSendComplete): New function.
+	* src/KeepAliveMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.	
+	* src/KeepAliveMessage.cc
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/PortMessage.h
+	(create): New function.
+	(receivedAction): Updated log message.
+	* src/PortMessage.cc: New file.
+	* src/UnchokeMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(sendPredicate): New function.
+	(onSendComplete): New function.
+	(create): New function.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/UnchokeMessage.cc
+	(create): New function.
+	(send): Removed.
+	(sendPredicate): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	(onSendComplete): New function.
+	* src/PieceMessage.h
+	(leftPieceDataLength): Removed.
+	(leftDataLength): New variable.
+	(headerSend): New variable.
+	(pendingCount): New variable.
+	(msgHeader): New variable.
+	(sendPieceData): New function.
+	(incrementPendingCount): New function.
+	(isPendingCountMax): New function.
+	(create): New function.
+	(getMessageHeader): New function.
+	(getMessageHeaderLength): New function.
+	* src/PieceMessage.cc
+	(create): New function.
+	(getMessageHeader): New function.
+	(getMessageHeaderLength): New function.
+	(send): Rewritten.
+	(sendPieceData): New function.
+	* src/HaveMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(create): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/HaveMessage.cc
+	(create): New function.
+	(send): Removed.
+	(sendPieceData): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/RequestMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(create): New function.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/RequestMessage.cc
+	(create): New function.
+	(receivedAction): Added the handling of fast extension.
+	Deleted torrentMan->addUploadLength, torrentMan->addDeltaUploadLength.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/InterestedMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(sendPredicate): New function.
+	(onSendComplete): New function.
+	(create): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/InterestedMessage.cc
+	(create): New function.
+	(send): Removed.
+	(sendPieceData): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	(onSendComplete): New function.
+	* src/NotInterestedMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(sendPieceData): New function.
+	(onSendComplete): New function.
+	(create): New function.
+	(send): Removed.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	* src/NotInterestedMessage.cc
+	(create): New function.
+	(send): Removed.
+	(sendPredicate): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	(onSendComplete): New function.
+	* src/AllowedFastMessage.h: New class.
+	* src/AllowedFastMessage.cc: New class.
+	* src/RejectMessage.h: New class.
+	* src/RejectMessage.cc: New class.
+	* src/SuggestPieceMessage.h: New class.
+	* src/SuggestPieceMessage.cc: New class.
+	* src/HaveAllMessage.h: New class.
+	* src/HaveAllMessage.cc: New class.
+	* src/HaveNoneMessage.h: New class.
+	* src/HaveNoneMessage.cc: New class.
+	* src/HandshakeMessage.h: Derived from SimplePeerMessage.
+	(msg): New variable.
+	(reserved): New variable.
+	(create): New function.
+	(getId): New function.
+	(receivedAction): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	(isFastExtensionSupported): New function.
+	* src/HandshakeMessage.cc
+	(HandshakeMessage): Moved here from HandshakeMessage.h.
+	(create): New function.
+	(getMessage): New function.
+	(getMessageLength): New function.
+	(toString): Added the output of reserved field.
+	(check): Added const qualifier.
+	(isFastExtensionSupported): New function.
+	* src/PeerMessageUtil.h
+	(createChokeMessage): Removed.
+	(createUnchokeMessage): Removed.
+	(createInterestedMessage): Removed.
+	(createNotInterestedMessage): Removed.
+	(createHaveMessage): Removed.
+	(createBitfieldMessage): Removed.
+	(createRequestMessage): Removed.
+	(createCancelMessage): Removed.
+	(createPieceMessage): Removed.
+	(createPortMessage): Removed.
+	(createChokeMessage): Removed.
+	(createUnchokeMessage): Removed.
+	(createInterestedMessage): Removed.
+	(createNotInterestedMessage): Removed.
+	(createHaveMessage): Removed.
+	(createBitfieldMessage): Removed.
+	(createRequestMessage): Removed.
+	(createCancelMessage): Removed.
+	(createPieceMessage): Removed.
+	(createKeepAliveMessage): Removed.
+	(createHandshakeMessage): Removed.
+	(setIntParam): New function.
+	(createPeerMessageString): New function.
+	* src/PeerMessageUtil.cc
+	(createChokeMessage): Removed.
+	(createUnchokeMessage): Removed.
+	(createInterestedMessage): Removed.
+	(createNotInterestedMessage): Removed.
+	(createHaveMessage): Removed.
+	(createBitfieldMessage): Removed.
+	(createRequestMessage): Removed.
+	(createCancelMessage): Removed.
+	(createPieceMessage): Removed.
+	(createPortMessage): Removed.
+	(createRequestMessage): Removed.
+	(createCancelMessage): Removed.
+	(createPieceMessage): Removed.
+	(createHaveMessage): Removed.
+	(createChokeMessage): Removed.
+	(createUnchokeMessage): Removed.
+	(createInterestedMessage): Removed.
+	(createNotInterestedMessage): Removed.
+	(createBitfieldMessage): Removed.
+	(createKeepAliveMessage): Removed.
+	(createHandshakeMessage): Removed.
+	(setIntParam): New function.
+	(createPeerMessageString): New function.
+	* src/PeerConnection.h
+	(peer): Removed.
+	(torrentMan): Removed.
+	(createNLengthMessage): Removed.
+	(setIntParam): Removed.
+	(writeOutgoingMessageLog): Removed all overloaded functions.
+	(PeerConnection): Deleted peer and torrentMan from its arguments.
+	(sendMessage): New function.
+	(sendHandshake): Removed.
+	(sendKeepAlive): Removed.
+	(sendChoke): Removed.
+	(sendUnchoke): Removed.
+	(sendInterested): Removed.
+	(sendNotInterested): Removed.
+	(sendHave): Removed.
+	(sendBitfield): Removed.
+	(sendRequest): Removed.
+	(sendPiece): Removed.
+	(sendPieceHeader): Removed.
+	(sendPieceData): Removed.
+	(sendCancel): Removed.
+	(getPeer): Removed.
+	* src/PeerConnection.cc
+	(PeerConnection): Deleted peer and torrentMan from its arguments.
+	(sendHandshake): Removed.
+	(sendKeepAlive): Removed.
+	(createNLengthMessage): Removed.
+	(setIntParam): Removed.
+	(writeOutgoingMessageLog): Removed all overloaded functions.
+	(sendChoke): Removed.
+	(sendUnchoke): Removed.
+	(sendInterested): Removed.
+	(sendNotInterested): Removed.
+	(sendHave): Removed.
+	(sendBitfield): Removed.
+	(sendRequest): Removed.
+	(sendPiece): Removed.
+	(sendPieceHeader): Removed.
+	(sendPieceData): Removed.
+	(sendMessage): New function.
+	(sendCancel): Removed.
+	* src/PeerInteractionCommand.cc
+	(PeerInteractionCommand): Call setUploadLimit.
+	(executeInternal): Call setUploadLimit.
+	Added the handling of "inProgress" state of handshake message.
+	Call sendBitfield() or sendAllowdFast() instead of deprecated
+	sendNow().
+	(keepAlive): Call addMessage and sendMessage instead of deprecated
+	sendNow().
+	(beforeSocketCheck): Call addMessage instead of deprecated trySendNow()
+	* src/TorrentMan.h
+	(PEER_ID_LENGTH): New definition.
+	(hasAllPieces): New function.
+	* src/TorrentMan.cc
+	(getMissingPiece): Added the handling of fast extension.
+	(cancelPiece): Call updatePiece().
+	(hasAllPieces): New function.
+	* src/PeerInteraction.h
+	(fastSet): New variable.
+	(getNewPieceAndSendInterest): Changed the return type to void.
+	(send): Renamed as sendMessages.
+	(deleteAllRequestSlot): Removed.
+	(deleteRequestMessageInQueue): Renamed as rejectPieceMessageInQueue.
+	(cancelAllRequest): Removed all overloaded functions.
+	(deleteAllRequestSlot): Removed.
+	(deletePieceMessageInQueue): Renamed as rejectAllPieceMessageInQueue.
+	(rejectPieceMessageInQueue): New function.
+	(rejectAllPieceMessageInQueue): New function.
+	(onChoked): New function.
+	(isSendingMessageInProgress): New function.
+	(getCorrespondingRequestSlot): Changed its arguments.
+	(isInFastSet): New function.
+	(addFastSetIndex): New function.
+	(addRequests): New function.
+	(sendNow): Removed.
+	(trySendNow): Removed.
+	(sendBitfield): New function.
+	(sendAllowdFast): New function.
+	(createHaveAllMessage): New function.
+	(createHaveNoneMessage): New function.
+	(createRejectMessage): New function.
+	(createAllowedFastMessage): New function.
+	* src/PeerInteraction.cc
+	(send): Renamed as sendMessages.
+	(sendMessages): New function.
+	(MsgPushBack): New class.
+	(isSendingMessageInProgress): New function.
+	(deletePieceMessageInQueue): Renamed as rejectAllPieceMessageInQueue.
+	(rejectAllPieceMessageInQueue): New function.
+	Added the handling of fast extension.
+	(deleteRequestMessageInQueue): Renamed as rejectPieceMessageInQueue.
+	(rejectPieceMessageInQueue): New function.
+	Added the handling of fast extension.
+	(deleteRequestSlot): Replaced for loop with  std::find.
+	(onChoked): New function.
+	(deleteAllRequestSlot): Removed.
+	(abortPiece): Rewirtten.
+	(deleteTimeoutRequestSlot): Updated log messages.
+	(getCorrespondingRequestSlot): Changed its arguments.
+	(cancelAllRequest): Removed all overloaded functions.
+	(receiveHandshake): Added the check to see whether an incoming peer
+	supports fast extension.
+	(createHandshakeMessage): Use HandshakeMessage::create instead of
+	PeerMessageUtil.
+	(createPeerMessage): Use create() of each message class instead of
+	PeerMessageUtil.
+	HaveAllMessage, HaveNoneMessage, RejectMessage, SuggestPieceMessage,
+	AllowedFastMessage were added.
+	(getNewPieceAndSendInterest): Changed its return value type to void.
+	Added the handling of fast extension.
+	(addRequests): New function.
+	(sendNow): Removed.
+	(sendHandshake): Rewritten.
+	(trySendNow): Removed.
+	(sendBitfield): New function.
+	(sendAllowdFast): New function.
+	(isInFastSet): New function.
+	(addFastSetIndex): New function.
+	(createRequestMessage): Use RequestMessage::create instead of
+	PeerMessageUtil.
+	(createCancelMessage): Use CancelMessage::create instead of
+	PeerMessageUtil.
+	(createPieceMessage): Use PieceMessage::create instead of
+	PeerMessageUtil.
+	(createHaveMessage): Use HaveMessage::create instead of
+	PeerMessageUtil.
+	(createChokeMessage): Use ChokeMessage::create instead of
+	PeerMessageUtil.
+	(createUnchokeMessage): Use UnchokeMessage::create instead of
+	PeerMessageUtil.
+	(createInterestedMessage): Use InterestedMessage::create instead of
+	PeerMessageUtil.
+	(createNotInterestedMessage): Use NotInterestedMessage::create instead
+	of PeerMessageUtil.
+	(createBitfieldMessage): Use BitfieldMessage::create instead of
+	PeerMessageUtil.
+	(createKeepAliveMessage): Use KeepAliveMessage::create instead of
+	PeerMessageUtil.
+	(createHaveAllMessage): New function.
+	(createHaveNoneMessage): New function.
+	(createRejectMessage): New function.
+	(createAllowedFastMessage: New function.
+	* src/Util.h
+	(sha1Sum): New function.
+	(computeFastSet): New function.
+	* src/Util.cc
+	(sha1Sum): New function.
+	(computeFastSet): New function.
+	* src/Peer.h
+	(fastExtensionEnabled): New variable.
+	(fastSet): New variable.
+	(setAllBitfield): New function.
+	(setFastExtensionEnabled): New function.
+	(isFastExtensionEnabled): New function.
+	(addFastSetIndex): New function.
+	(getFastSet): New function.
+	(isInFastSet): New function.
+	(countFastSet): New function.
+	* src/Peer.cc
+	(isInFastSet): New function.
+	(addFastSetIndex): New function.
+	(setAllBitfield): New function.
+	
+	* src/AbstractCommand.cc (execute): Changed the procedure of checking
+	sockets.
+	* src/PeerAbstractCommand.cc
+	(PeerAbstractCommand): Added the initialization for uploadLimitCheck
+	and uploadLimit.
+	(execute): Changed the procedure of checking sockets. The upload speed
+	checking were added.
+	(setUploadLimit): New function.
+	(setUploadLimitCheck): New function.
+	* src/PeerAbstractCommand.h
+	(setUploadLimit): New function.
+	(setUploadLimitCheck): New function.
+	(uploadLimit): New variable.
+	(uploadLimitCheck): New variable.
+
+	To contact a tracker regularly:
+	
+	* src/TrackerWatcherCommand.h (interval): New variable.
+	(checkPoint): New variable.
+	(TrackerWatcherCommand): Added interval argument.
+	* src/TrackerWatcherCommand.cc
+	(TrackerWatcherCommand): Initialized checkPoint.
+	(execute): Now a tracker is contacted in every specified period.
+	If peer list is not needed, send request with numwant=0.
+
+	* src/TrackerUpdateCommand.cc
+	(execute): Updated log messages.
+
+	* src/DownloadEngine.cc
+	(~DownloadEngine): Removed two asserts.
+	(waitData): Uncommented wfds. May be a bug fix.
+	
 2006-05-10  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	* src/PeerInteractionCommand.h

+ 3 - 2
TODO

@@ -14,5 +14,6 @@
 * Add Mainline-compatible DHT support
 * Add Message stream encryption support
 * Add announce-list support
-* Add fast extension
-* Refacturing HttpConnection and FtpConnection
+* Refacturing HttpConnection and FtpConnection
+* HTTP/FTP downloading regression test
+* Fast extension test

+ 16 - 13
src/AbstractCommand.cc

@@ -72,25 +72,28 @@ bool AbstractCommand::isTimeoutDetected() {
 
 bool AbstractCommand::execute() {
   try {
-    if(checkSocketIsReadable && !readCheckTarget->isReadable(0)
-       || checkSocketIsWritable && !writeCheckTarget->isWritable(0)) {
+    if(checkSocketIsReadable && readCheckTarget->isReadable(0) ||
+       checkSocketIsWritable && writeCheckTarget->isWritable(0) ||
+       !checkSocketIsReadable && !checkSocketIsWritable) {
+
+      updateCheckPoint();
+      Segment seg = { 0, 0, 0, false };
+      if(e->segmentMan->downloadStarted) {
+	// get segment information in order to set Range header.
+	if(!e->segmentMan->getSegment(seg, cuid)) {
+	  // no segment available
+	  logger->info(MSG_NO_SEGMENT_AVAILABLE, cuid);
+	  return true;
+	}
+      }
+      return executeInternal(seg);
+    } else {
       if(isTimeoutDetected()) {
 	throw new DlRetryEx(EX_TIME_OUT);
       }
       e->commands.push_back(this);
       return false;
     }
-    updateCheckPoint();
-    Segment seg = { 0, 0, 0, false };
-    if(e->segmentMan->downloadStarted) {
-      // get segment information in order to set Range header.
-      if(!e->segmentMan->getSegment(seg, cuid)) {
-	// no segment available
-	logger->info(MSG_NO_SEGMENT_AVAILABLE, cuid);
-	return true;
-      }
-    }
-    return executeInternal(seg);
   } catch(DlAbortEx* err) {
     logger->error(MSG_DOWNLOAD_ABORTED, err, cuid);
     onAbort(err);

+ 78 - 0
src/AllowedFastMessage.cc

@@ -0,0 +1,78 @@
+/* <!-- 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 "AllowedFastMessage.h"
+#include "PeerInteraction.h"
+#include "PeerMessageUtil.h"
+#include "Util.h"
+#include "DlAbortEx.h"
+
+AllowedFastMessage* AllowedFastMessage::create(const char* data, int dataLength) {
+  if(dataLength != 5) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "allowed fast", dataLength, 5);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "allowed fast", ID);
+  }
+  AllowedFastMessage* allowedFastMessage = new AllowedFastMessage();
+  allowedFastMessage->setIndex(PeerMessageUtil::getIntParam(data, 1));
+  return allowedFastMessage;
+}
+
+void AllowedFastMessage::receivedAction() {
+  if(!peer->isFastExtensionEnabled()) {
+    throw new DlAbortEx("%s received while fast extension is disabled",
+			toString().c_str());
+  }
+  peer->addFastSetIndex(index);
+}
+
+const char* AllowedFastMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 5, 4bytes
+     * id --- 17, 1byte
+     * piece index --- index, 4bytes
+     * total: 9bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, ID);
+    PeerMessageUtil::setIntParam(&msg[5], index);
+  }
+  return msg;
+}
+
+int AllowedFastMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void AllowedFastMessage::onSendComplete() {
+  peerInteraction->addFastSetIndex(index);
+}
+
+void AllowedFastMessage::check() const {
+  PeerMessageUtil::checkIndex(index, pieces);
+}
+
+string AllowedFastMessage::toString() const {
+  return "allowed fast index="+Util::itos(index);
+}

+ 64 - 0
src/AllowedFastMessage.h

@@ -0,0 +1,64 @@
+/* <!-- 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_ALLOWED_FAST_MESSAGE_H_
+#define _D_ALLOWED_FAST_MESSAGE_H_
+
+#include "SimplePeerMessage.h"
+
+class AllowedFastMessage : public SimplePeerMessage {
+private:
+  int index;
+  // for check
+  int pieces;
+  char msg[9];
+protected:
+  virtual void onSendComplete();
+public:
+  AllowedFastMessage():SimplePeerMessage(), index(0), pieces(0) {}
+
+  virtual ~AllowedFastMessage() {}
+
+  enum ID {
+    ID = 17
+  };
+
+  void setIndex(int index) {
+    this->index = index;
+  }
+  int getIndex() const { return index; }
+
+  void setPieces(int pieces) {
+    this->pieces = pieces;
+  }
+  int getPieces() const { return pieces;}
+
+  static AllowedFastMessage* create(const char* data, int dataLength);
+
+  virtual int getId() const { return ID; }
+  virtual void receivedAction();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
+  virtual void check() const;
+  virtual string toString() const;
+};
+
+#endif // _D_ALLOWED_FAST_MESSAGE_H_

+ 35 - 2
src/BitfieldMessage.cc

@@ -23,6 +23,7 @@
 #include "PeerInteraction.h"
 #include "PeerMessageUtil.h"
 #include "Util.h"
+#include "DlAbortEx.h"
 
 void BitfieldMessage::setBitfield(const unsigned char* bitfield, int bitfieldLength) {
   if(this->bitfield != NULL) {
@@ -33,12 +34,44 @@ void BitfieldMessage::setBitfield(const unsigned char* bitfield, int bitfieldLen
   memcpy(this->bitfield, bitfield, this->bitfieldLength);
 }
 
+BitfieldMessage* BitfieldMessage::create(const char* data, int dataLength) {
+  if(dataLength <= 1) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be greater than %d", "bitfield", dataLength, 1);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "bitfield", ID);
+  }
+  BitfieldMessage* bitfieldMessage = new BitfieldMessage();
+  bitfieldMessage->setBitfield((unsigned char*)data+1, dataLength-1);
+  return bitfieldMessage;
+}
+
 void BitfieldMessage::receivedAction() {
   peer->setBitfield(bitfield, bitfieldLength);
 }
 
-void BitfieldMessage::send() {
-  peerInteraction->getPeerConnection()->sendBitfield();
+const char* BitfieldMessage::getMessage() {
+  if(!inProgress && msg == NULL) {
+    /**
+     * len --- 1+bitfieldLength, 4bytes
+     * id --- 5, 1byte
+     * bitfield --- bitfield, len bytes
+     * total: 5+len bytes
+     */
+    msgLength = 5+bitfieldLength;
+    msg = new char[msgLength];
+    PeerMessageUtil::createPeerMessageString(msg, msgLength,
+					     1+bitfieldLength, ID);
+    memcpy(msg+5, bitfield, bitfieldLength);
+  }
+  return msg;
+}
+
+int BitfieldMessage::getMessageLength() {
+  getMessage();
+  return msgLength;
 }
 
 void BitfieldMessage::check() const {

+ 14 - 5
src/BitfieldMessage.h

@@ -22,23 +22,29 @@
 #ifndef _D_BITFIELD_MESSAGE_H_
 #define _D_BITFIELD_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 
-class BitfieldMessage : public PeerMessage {
+class BitfieldMessage : public SimplePeerMessage {
 private:
   unsigned char* bitfield;
   int bitfieldLength;
   // for check
   int pieces;
+
+  char* msg;
+  int msgLength;
 public:
-  BitfieldMessage():PeerMessage(),
+  BitfieldMessage():SimplePeerMessage(),
 		    bitfield(NULL), bitfieldLength(0),
-		    pieces(0) {}
+		    pieces(0), msg(NULL), msgLength(0) {}
 
   virtual ~BitfieldMessage() {
     if(bitfield != NULL) {
       delete [] bitfield;
     }
+    if(msg != NULL) {
+      delete [] msg;
+    }
   }
 
   enum ID {
@@ -55,9 +61,12 @@ public:
   }
   int getPieces() const { return pieces;}
 
+  static BitfieldMessage* create(const char* data, int dataLength);
+
   virtual int getId() const { return ID; }
   virtual void receivedAction();
-  virtual void send();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual void check() const;
   virtual string toString() const;
 };

+ 38 - 3
src/CancelMessage.cc

@@ -23,13 +23,48 @@
 #include "PeerInteraction.h"
 #include "PeerMessageUtil.h"
 #include "Util.h"
+#include "DlAbortEx.h"
+
+CancelMessage* CancelMessage::create(const char* data, int dataLength) {
+  if(dataLength != 13) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "cancel", dataLength, 13);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "cancel", ID);
+  }
+  CancelMessage* cancelMessage = new CancelMessage();
+  cancelMessage->setIndex(PeerMessageUtil::getIntParam(data, 1));
+  cancelMessage->setBegin(PeerMessageUtil::getIntParam(data, 5));
+  cancelMessage->setLength(PeerMessageUtil::getIntParam(data, 9));
+  return cancelMessage;
+}
 
 void CancelMessage::receivedAction() {
-  peerInteraction->deletePieceMessageInQueue(this);
+  peerInteraction->rejectPieceMessageInQueue(index, begin, length);
+}
+
+const char* CancelMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 13, 4bytes
+     * id --- 8, 1byte
+     * index --- index, 4bytes
+     * begin --- begin, 4bytes
+     * length -- length, 4bytes
+     * total: 17bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, ID);
+    PeerMessageUtil::setIntParam(&msg[5], index);
+    PeerMessageUtil::setIntParam(&msg[9], begin);
+    PeerMessageUtil::setIntParam(&msg[13], length);
+  }
+  return msg;
 }
 
-void CancelMessage::send() {
-  peerInteraction->getPeerConnection()->sendCancel(index, begin, length);
+int CancelMessage::getMessageLength() {
+  return sizeof(msg);
 }
 
 void CancelMessage::check() const {

+ 9 - 6
src/CancelMessage.h

@@ -22,12 +22,10 @@
 #ifndef _D_CANCEL_MESSAGE_H_
 #define _D_CANCEL_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 #include "TorrentMan.h"
 
-class SendMessageQueue;
-
-class CancelMessage : public PeerMessage {
+class CancelMessage : public SimplePeerMessage {
 private:
   int index;
   int begin;
@@ -35,8 +33,10 @@ private:
   // for check
   int pieces;
   int pieceLength;
+
+  char msg[17];
 public:
-  CancelMessage():PeerMessage(),
+  CancelMessage():SimplePeerMessage(),
 		  index(0), begin(0), length(0),
 		  pieces(0), pieceLength(0) {}
 
@@ -63,9 +63,12 @@ public:
   }
   int getPieceLength() const { return pieceLength;}
 
+  static CancelMessage* create(const char* data, int dataLength);
+
   virtual int getId() const { return ID; }
   virtual void receivedAction();
-  virtual void send();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual void check() const;
   virtual string toString() const;
 };

+ 39 - 4
src/ChokeMessage.cc

@@ -21,16 +21,51 @@
 /* copyright --> */
 #include "ChokeMessage.h"
 #include "PeerInteraction.h"
+#include "message.h"
+#include "PeerMessageUtil.h"
+#include "DlAbortEx.h"
+
+ChokeMessage* ChokeMessage::create(const char* data, int dataLength) {
+  if(dataLength != 1) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "choke", dataLength, 1);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "choke", ID);
+  }
+  ChokeMessage* chokeMessage = new ChokeMessage();
+  return chokeMessage;
+}
 
 void ChokeMessage::receivedAction() {
   peer->peerChoking = true;
+  peerInteraction->onChoked();
+}
+
+bool ChokeMessage::sendPredicate() const {
+  return !peer->amChoking;
 }
 
-void ChokeMessage::send() {
-  if(!peer->amChoking) {
-    peerInteraction->getPeerConnection()->sendChoke();
-    peer->amChoking = true;
+const char* ChokeMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 1, 4bytes
+     * id --- 0, 1byte
+     * total: 5bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, ID);
   }
+  return msg;
+}
+
+int ChokeMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void ChokeMessage::onSendComplete() {
+  peer->amChoking = true;
+  peerInteraction->rejectAllPieceMessageInQueue();
 }
 
 string ChokeMessage::toString() const {

+ 11 - 4
src/ChokeMessage.h

@@ -22,11 +22,16 @@
 #ifndef _D_CHOKE_MESSAGE_H_
 #define _D_CHOKE_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 
-class ChokeMessage : public PeerMessage {
+class ChokeMessage : public SimplePeerMessage {
+private:
+  char msg[5];
+protected:
+  virtual bool sendPredicate() const;
+  virtual void onSendComplete();
 public:
-  ChokeMessage():PeerMessage() {}
+  ChokeMessage():SimplePeerMessage() {}
   virtual ~ChokeMessage() {}
 
   enum ID {
@@ -35,9 +40,11 @@ public:
 
   virtual int getId() const { return ID; }
   virtual void receivedAction();
-  virtual void send();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual string toString() const;
 
+  static ChokeMessage* create(const char* data, int dataLength);
 };
 
 #endif // _D_CHOKE_MESSAGE_H_

+ 2 - 4
src/DownloadEngine.cc

@@ -35,8 +35,6 @@ DownloadEngine::DownloadEngine():noWait(false), segmentMan(NULL) {
 }
 
 DownloadEngine::~DownloadEngine() {
-  assert(rsockets.empty());
-  assert(wsockets.empty());
   if(segmentMan != NULL) {
     delete segmentMan;
   }
@@ -59,7 +57,7 @@ void DownloadEngine::run() {
       }
     }
     afterEachIteration();
-    shortSleep();
+    //shortSleep();
     if(!noWait && !commands.empty()) {
       waitData();
     }
@@ -102,7 +100,7 @@ void DownloadEngine::waitData() {
   tv.tv_sec = 1;
   tv.tv_usec = 0;
 
-  retval = select(max+1, &rfds, /*&wfds*/NULL, NULL, &tv);
+  retval = select(max+1, &rfds, &wfds, NULL, &tv);
 }
 
 bool DownloadEngine::addSocket(Sockets& sockets, Socket* socket) {

+ 41 - 4
src/HandshakeMessage.cc

@@ -24,16 +24,53 @@
 #include "PeerMessageUtil.h"
 #include "Util.h"
 
-void HandshakeMessage::setPeerInteraction(PeerInteraction* peerInteraction) {
-  this->peerInteraction = peerInteraction;
+HandshakeMessage::HandshakeMessage() {
+  this->pstrlen = 19;
+  this->pstr = PSTR;
+  memset(this->reserved, 0, sizeof(this->reserved));
+  // fast extension
+  this->reserved[7] |= 0x04;
+}
+
+HandshakeMessage* HandshakeMessage::create(const char* data, int dataLength) {
+  HandshakeMessage* message = new HandshakeMessage();
+  message->pstrlen = data[0];
+  char pstrTemp[20];
+  memcpy(pstrTemp, &data[1], sizeof(pstrTemp)-1);
+  pstrTemp[sizeof(pstrTemp)-1] = '\0';
+  message->pstr = pstrTemp;
+  memcpy(message->reserved, &data[20], 8);
+  memcpy(message->infoHash, &data[28], 20);
+  memcpy(message->peerId, &data[48], 20);
+  return message;
+}
+
+const char* HandshakeMessage::getMessage() {
+  if(!inProgress) {
+    msg[0] = pstrlen;
+    memcpy(msg+1, pstr.c_str(), pstr.size());
+    memcpy(msg+20, reserved, 8);
+    memcpy(msg+28, infoHash, 20);
+    memcpy(msg+48, peerId, 20);
+  }
+  return msg;
+}
+
+int HandshakeMessage::getMessageLength() {
+  return sizeof(msg);
 }
 
 string HandshakeMessage::toString() const {
   return "handshake peerId="+
-    Util::urlencode((unsigned char*)peerId, sizeof(peerId));
+    Util::urlencode((unsigned char*)peerId, sizeof(peerId))+
+    " reserved="+Util::toHex(reserved, sizeof(reserved));
 }
 
-void HandshakeMessage::check() {
+void HandshakeMessage::check() const {
   PeerMessageUtil::checkHandshake(this,
 				  peerInteraction->getTorrentMan()->getInfoHash());
 }
+
+bool HandshakeMessage::isFastExtensionSupported() const {
+  return reserved[7]&0x04;
+}

+ 20 - 13
src/HandshakeMessage.h

@@ -22,29 +22,36 @@
 #ifndef _D_HANDSHAKE_MESSAGE_H_
 #define _D_HANDSHAKE_MESSAGE_H_
 
-#include "common.h"
-
-class PeerInteraction;
+#include "SimplePeerMessage.h"
+#include "TorrentMan.h"
 
 #define PSTR "BitTorrent protocol"
 #define HANDSHAKE_MESSAGE_LENGTH 68
 
-class HandshakeMessage {
+class HandshakeMessage : public SimplePeerMessage {
+private:
+  char msg[HANDSHAKE_MESSAGE_LENGTH];
 public:
   char pstrlen;
   string pstr;
-  unsigned char infoHash[20];
-  char peerId[20];
-  PeerInteraction* peerInteraction;
+  unsigned char reserved[8];
+  unsigned char infoHash[INFO_HASH_LENGTH];
+  char peerId[PEER_ID_LENGTH];
 public:
-  HandshakeMessage() {}
-  ~HandshakeMessage() {}
+  HandshakeMessage();
+
+  static HandshakeMessage* create(const char* data, int dataLength);
+
+  virtual ~HandshakeMessage() {}
 
-  PeerInteraction* getPeerInteraction() const { return peerInteraction; }
-  void setPeerInteraction(PeerInteraction* peerInteraction);
+  virtual int getId() const { return 999; }
+  virtual void receivedAction() {};
+  virtual const char* getMessage();
+  virtual int getMessageLength();
+  virtual void check() const;
+  virtual string toString() const;
 
-  string toString() const;
-  void check();
+  bool isFastExtensionSupported() const;
 };
 
 #endif // _D_HANDSHAKE_MESSAGE_H_

+ 72 - 0
src/HaveAllMessage.cc

@@ -0,0 +1,72 @@
+/* <!-- 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 "HaveAllMessage.h"
+#include "DlAbortEx.h"
+#include "PeerInteraction.h"
+#include "PeerMessageUtil.h"
+
+HaveAllMessage::HaveAllMessage() {}
+
+HaveAllMessage::~HaveAllMessage() {}
+
+HaveAllMessage* HaveAllMessage::create(const char* data, int dataLength) {
+  if(dataLength != 1) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "have all", dataLength, 1);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "have all", ID);
+  }
+  HaveAllMessage* haveAllMessage = new HaveAllMessage();
+  return haveAllMessage;
+}
+
+void HaveAllMessage::receivedAction() {
+  if(!peer->isFastExtensionEnabled()) {
+    throw new DlAbortEx("%s received while fast extension is disabled",
+			toString().c_str());
+  }
+  peer->setAllBitfield();
+}
+
+const char* HaveAllMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 1, 4bytes
+     * id --- 14, 1byte
+     * total: 5bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, ID);
+  }
+  return msg;
+}
+
+int HaveAllMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void HaveAllMessage::check() const {}
+
+string HaveAllMessage::toString() const {
+  return "have all";
+}

+ 48 - 0
src/HaveAllMessage.h

@@ -0,0 +1,48 @@
+/* <!-- 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_HAVE_ALL_MESSAGE_H_
+#define _D_HAVE_ALL_MESSAGE_H_
+
+#include "SimplePeerMessage.h"
+
+class HaveAllMessage : public SimplePeerMessage {
+private:
+  char msg[5];
+public:
+  HaveAllMessage();
+  virtual ~HaveAllMessage();
+
+  enum ID {
+    ID = 14
+  };
+
+  static HaveAllMessage* create(const char* data, int dataLength);
+
+  virtual int getId() const { return ID; }
+  virtual void receivedAction();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
+  virtual void check() const;
+  virtual string toString() const;
+};
+
+#endif // _D_HAVE_ALL_MESSAGE_H_

+ 34 - 3
src/HaveMessage.cc

@@ -23,15 +23,46 @@
 #include "PeerInteraction.h"
 #include "PeerMessageUtil.h"
 #include "Util.h"
+#include "DlAbortEx.h"
+
+HaveMessage* HaveMessage::create(const char* data, int dataLength) {
+  if(dataLength != 5) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "have", dataLength, 5);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "have", ID);
+  }
+  HaveMessage* haveMessage = new HaveMessage();
+  haveMessage->setIndex(PeerMessageUtil::getIntParam(data, 1));
+  return haveMessage;
+}
 
 void HaveMessage::receivedAction() {
   peer->updateBitfield(index, 1);
 }
 
-void HaveMessage::send() {
-  if(!peer->hasPiece(index)) {
-    peerInteraction->getPeerConnection()->sendHave(index);
+bool HaveMessage::sendPredicate() const {
+  return !peer->hasPiece(index);
+}
+
+const char* HaveMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 5, 4bytes
+     * id --- 4, 1byte
+     * piece index --- index, 4bytes
+     * total: 9bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, ID);
+    PeerMessageUtil::setIntParam(&msg[5], index);
   }
+  return msg;
+}
+
+int HaveMessage::getMessageLength() {
+  return sizeof(msg);
 }
 
 void HaveMessage::check() const {

+ 10 - 4
src/HaveMessage.h

@@ -22,15 +22,18 @@
 #ifndef _D_HAVE_MESSAGE_H_
 #define _D_HAVE_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 
-class HaveMessage : public PeerMessage {
+class HaveMessage : public SimplePeerMessage {
 private:
   int index;
   // for check
   int pieces;
+  char msg[9];
+protected:
+  virtual bool sendPredicate() const;
 public:
-  HaveMessage():PeerMessage(), index(0), pieces(0) {}
+  HaveMessage():SimplePeerMessage(), index(0), pieces(0) {}
 
   virtual ~HaveMessage() {}
 
@@ -48,9 +51,12 @@ public:
   }
   int getPieces() const { return pieces;}
 
+  static HaveMessage* create(const char* data, int dataLength);
+
   virtual int getId() const { return ID; }
   virtual void receivedAction();
-  virtual void send();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual void check() const;
   virtual string toString() const;
 };

+ 71 - 0
src/HaveNoneMessage.cc

@@ -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 --> */
+#include "HaveNoneMessage.h"
+#include "DlAbortEx.h"
+#include "PeerInteraction.h"
+#include "PeerMessageUtil.h"
+
+HaveNoneMessage::HaveNoneMessage() {}
+
+HaveNoneMessage::~HaveNoneMessage() {}
+
+HaveNoneMessage* HaveNoneMessage::create(const char* data, int dataLength) {
+  if(dataLength != 1) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "have none", dataLength, 1);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "have none", ID);
+  }
+  HaveNoneMessage* haveNoneMessage = new HaveNoneMessage();
+  return haveNoneMessage;
+}
+
+void HaveNoneMessage::receivedAction() {
+  if(!peer->isFastExtensionEnabled()) {
+    throw new DlAbortEx("%s received while fast extension is disabled",
+			toString().c_str());
+  }
+}
+
+const char* HaveNoneMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 1, 4bytes
+     * id --- 15, 1byte
+     * total: 5bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, ID);
+  }
+  return msg;
+}
+
+int HaveNoneMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void HaveNoneMessage::check() const {}
+
+string HaveNoneMessage::toString() const {
+  return "have none";
+}

+ 48 - 0
src/HaveNoneMessage.h

@@ -0,0 +1,48 @@
+/* <!-- 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_HAVE_NONE_MESSAGE_H_
+#define _D_HAVE_NONE_MESSAGE_H_
+
+#include "SimplePeerMessage.h"
+
+class HaveNoneMessage : public SimplePeerMessage {
+private:
+  char msg[5];
+public:
+  HaveNoneMessage();
+  virtual ~HaveNoneMessage();
+  
+  enum ID {
+    ID = 15
+  };
+  
+  static HaveNoneMessage* create(const char* data, int dataLength);
+
+  virtual int getId() const { return ID; }
+  virtual void receivedAction();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
+  virtual void check() const;
+  virtual string toString() const;
+};
+
+#endif // _D_HAVE_NONE_MESSAGE_H_

+ 36 - 4
src/InterestedMessage.cc

@@ -21,16 +21,48 @@
 /* copyright --> */
 #include "InterestedMessage.h"
 #include "PeerInteraction.h"
+#include "PeerMessageUtil.h"
+#include "DlAbortEx.h"
+
+InterestedMessage* InterestedMessage::create(const char* data, int dataLength) {
+  if(dataLength != 1) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "interested", dataLength, 1);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "interested", ID);
+  }
+  InterestedMessage* interestedMessage = new InterestedMessage();
+  return interestedMessage;
+}
 
 void InterestedMessage::receivedAction() {
   peer->peerInterested = true;
 }
 
-void InterestedMessage::send() {
-  if(!peer->amInterested) {
-    peerInteraction->getPeerConnection()->sendInterested();
-    peer->amInterested = true;
+bool InterestedMessage::sendPredicate() const {
+  return !peer->amInterested;
+}
+
+const char* InterestedMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 1, 4bytes
+     * id --- 2, 1byte
+     * total: 5bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, ID);
   }
+  return msg;
+}
+
+int InterestedMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void InterestedMessage::onSendComplete() {
+  peer->amInterested = true;
 }
 
 string InterestedMessage::toString() const {

+ 12 - 4
src/InterestedMessage.h

@@ -22,20 +22,28 @@
 #ifndef _D_INTERESTED_MESSAGE_H_
 #define _D_INTERESTED_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 
-class InterestedMessage : public PeerMessage {
+class InterestedMessage : public SimplePeerMessage {
+private:
+  char msg[5];
+protected:
+  virtual bool sendPredicate() const;
+  virtual void onSendComplete();
 public:
-  InterestedMessage():PeerMessage() {}
+  InterestedMessage():SimplePeerMessage() {}
   virtual ~InterestedMessage() {}
 
   enum ID {
     ID = 2
   };
 
+  static InterestedMessage* create(const char* data, int dataLength);
+
   virtual int getId() const { return ID; }
   virtual void receivedAction();
-  virtual void send();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual string toString() const;
 };
 

+ 13 - 2
src/KeepAliveMessage.cc

@@ -22,6 +22,17 @@
 #include "KeepAliveMessage.h"
 #include "PeerInteraction.h"
 
-void KeepAliveMessage::send() {
-  peerInteraction->getPeerConnection()->sendKeepAlive();
+const char* KeepAliveMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 0, 4bytes
+     * total: 4bytes
+     */
+    memset(msg, 0, sizeof(msg));
+  }
+  return msg;
+}
+
+int KeepAliveMessage::getMessageLength() {
+  return sizeof(msg);
 }

+ 7 - 4
src/KeepAliveMessage.h

@@ -22,11 +22,13 @@
 #ifndef _D_KEEP_ALIVE_MESSAGE_H_
 #define _D_KEEP_ALIVE_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 
-class KeepAliveMessage : public PeerMessage {
+class KeepAliveMessage : public SimplePeerMessage {
+private:
+  char msg[4];
 public:
-  KeepAliveMessage():PeerMessage() {}
+  KeepAliveMessage():SimplePeerMessage() {}
   virtual ~KeepAliveMessage() {}
 
   enum ID {
@@ -35,7 +37,8 @@ public:
 
   virtual int getId() const { return ID; }
   virtual void receivedAction() {}
-  virtual void send();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual string toString() const {
     return "keep alive";
   }

+ 7 - 1
src/Makefile.am

@@ -94,7 +94,13 @@ SRCS =  Socket.cc Socket.h\
 	PieceMessage.cc PieceMessage.h\
 	CancelMessage.cc CancelMessage.h\
 	KeepAliveMessage.cc KeepAliveMessage.h\
-	PortMessage.h
+	PortMessage.cc PortMessage.h\
+	HaveAllMessage.cc HaveAllMessage.h\
+	HaveNoneMessage.cc HaveNoneMessage.h\
+	RejectMessage.cc RejectMessage.h\
+	AllowedFastMessage.cc AllowedFastMessage.h\
+	SuggestPieceMessage.cc SuggestPieceMessage.h\
+	SimplePeerMessage.cc SimplePeerMessage.h
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
 aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\

+ 19 - 2
src/Makefile.in

@@ -105,7 +105,11 @@ am__objects_1 = Socket.$(OBJEXT) SocketCore.$(OBJEXT) \
 	InterestedMessage.$(OBJEXT) NotInterestedMessage.$(OBJEXT) \
 	HaveMessage.$(OBJEXT) BitfieldMessage.$(OBJEXT) \
 	RequestMessage.$(OBJEXT) PieceMessage.$(OBJEXT) \
-	CancelMessage.$(OBJEXT) KeepAliveMessage.$(OBJEXT)
+	CancelMessage.$(OBJEXT) KeepAliveMessage.$(OBJEXT) \
+	PortMessage.$(OBJEXT) HaveAllMessage.$(OBJEXT) \
+	HaveNoneMessage.$(OBJEXT) RejectMessage.$(OBJEXT) \
+	AllowedFastMessage.$(OBJEXT) SuggestPieceMessage.$(OBJEXT) \
+	SimplePeerMessage.$(OBJEXT)
 am_libaria2c_a_OBJECTS = $(am__objects_1)
 libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
 am__installdirs = "$(DESTDIR)$(bindir)"
@@ -349,7 +353,13 @@ SRCS = Socket.cc Socket.h\
 	PieceMessage.cc PieceMessage.h\
 	CancelMessage.cc CancelMessage.h\
 	KeepAliveMessage.cc KeepAliveMessage.h\
-	PortMessage.h
+	PortMessage.cc PortMessage.h\
+	HaveAllMessage.cc HaveAllMessage.h\
+	HaveNoneMessage.cc HaveNoneMessage.h\
+	RejectMessage.cc RejectMessage.h\
+	AllowedFastMessage.cc AllowedFastMessage.h\
+	SuggestPieceMessage.cc SuggestPieceMessage.h\
+	SimplePeerMessage.cc SimplePeerMessage.h
 
 noinst_LIBRARIES = libaria2c.a
 libaria2c_a_SOURCES = $(SRCS)
@@ -437,6 +447,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/alloca.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AbstractCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AbstractDiskWriter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AllowedFastMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMan.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMessage.Po@am__quote@
@@ -463,7 +474,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpTunnelRequestCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpTunnelResponseCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HandshakeMessage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveAllMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveMessage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveNoneMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpConnection.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpDownloadCommand.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpHeader.Po@am__quote@
@@ -494,7 +507,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerMessageUtil.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Piece.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceMessage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PortMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PreAllocationDiskWriter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RejectMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Request.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestMessage.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestSlot.Po@am__quote@
@@ -502,11 +517,13 @@ distclean-compile:
 @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)/Socket.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)/SuggestPieceMessage.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@

+ 36 - 4
src/NotInterestedMessage.cc

@@ -21,16 +21,48 @@
 /* copyright --> */
 #include "NotInterestedMessage.h"
 #include "PeerInteraction.h"
+#include "PeerMessageUtil.h"
+#include "DlAbortEx.h"
+
+NotInterestedMessage* NotInterestedMessage::create(const char* data, int dataLength) {
+  if(dataLength != 1) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "not interested", dataLength, 1);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "not interested", ID);
+  }
+  NotInterestedMessage* notInterestedMessage = new NotInterestedMessage();
+  return notInterestedMessage;
+}
 
 void NotInterestedMessage::receivedAction() {
   peer->peerInterested = false;
 }
 
-void NotInterestedMessage::send() {
-  if(peer->amInterested) {
-    peerInteraction->getPeerConnection()->sendNotInterested();
-    peer->amInterested = false;
+bool NotInterestedMessage::sendPredicate() const {
+  return peer->amInterested;
+}
+
+const char* NotInterestedMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 1, 4bytes
+     * id --- 3, 1byte
+     * total: 5bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, ID);
   }
+  return msg;
+}
+
+int NotInterestedMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void NotInterestedMessage::onSendComplete() {
+  peer->amInterested = false;
 }
 
 string NotInterestedMessage::toString() const {

+ 12 - 4
src/NotInterestedMessage.h

@@ -22,20 +22,28 @@
 #ifndef _D_NOT_INTERESTED_MESSAGE_H_
 #define _D_NOT_INTERESTED_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 
-class NotInterestedMessage : public PeerMessage {
+class NotInterestedMessage : public SimplePeerMessage {
+private:
+  char msg[5];
+protected:
+  virtual bool sendPredicate() const;
+  virtual void onSendComplete();
 public:
-  NotInterestedMessage():PeerMessage() {}
+  NotInterestedMessage():SimplePeerMessage() {}
   virtual ~NotInterestedMessage() {}
 
   enum ID {
     ID = 3
   };
 
+  static NotInterestedMessage* create(const char* data, int dataLength);
+
   virtual int getId() const { return ID; }
   virtual void receivedAction();
-  virtual void send();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual string toString() const;
 };
 

+ 16 - 0
src/Peer.cc

@@ -59,4 +59,20 @@ void Peer::resetStatus() {
   resetDeltaDownload();
   chokingRequired = true;
   optUnchoking = false;
+  fastExtensionEnabled = false;
+  fastSet.clear();
+}
+
+bool Peer::isInFastSet(int index) const {
+  return find(fastSet.begin(), fastSet.end(), index) != fastSet.end();
+}
+
+void Peer::addFastSetIndex(int index) {
+  if(!isInFastSet(index)) {
+    fastSet.push_back(index);
+  }
+}
+
+void Peer::setAllBitfield() {
+  bitfield->setAllBit();
 }

+ 16 - 1
src/Peer.h

@@ -48,6 +48,9 @@ public:
 private:
   char peerId[PEER_ID_LENGTH];
   BitfieldMan* bitfield;
+  bool fastExtensionEnabled;
+  // allowed fast indexes that peer has sent by Allowed Fast message
+  Integers fastSet;
   long long int peerUpload;
   long long int peerDownload;
   int pieceLength;
@@ -62,6 +65,7 @@ public:
     tryCount(0), error(0), cuid(0),
     chokingRequired(true), optUnchoking(false),
     bitfield(NULL),
+    fastExtensionEnabled(false),
     peerUpload(0), peerDownload(0),
     pieceLength(pieceLength), totalLength(totalLength),
     deltaUpload(0), deltaDownload(0) {
@@ -98,13 +102,14 @@ public:
   }
   const unsigned char* getBitfield() const { return bitfield->getBitfield(); }
   int getBitfieldLength() const { return bitfield->getBitfieldLength(); }
+  void setAllBitfield();
 
   /**
    * operation = 1: set index-th bit 1
    * operation = 0: set index-th bit 0
    */
   void updateBitfield(int index, int operation);
-
+  
   void addPeerUpload(int size) {
     peerUpload += size;
     addDeltaUpload(size);
@@ -119,6 +124,16 @@ public:
   void setPeerDownload(long long int size) { peerDownload = size; }
   long long int getPeerDownload() const { return peerDownload; }
 
+  void setFastExtensionEnabled(bool enabled) {
+    fastExtensionEnabled = enabled;
+  }
+  bool isFastExtensionEnabled() const { return fastExtensionEnabled; }
+
+  void addFastSetIndex(int index);
+  const Integers getFastSet() const { return fastSet; }
+  bool isInFastSet(int index) const;
+  int countFastSet() const { return fastSet.size(); }
+
   bool shouldBeChoking() const;
 
   bool hasPiece(int index) const;

+ 19 - 8
src/PeerAbstractCommand.cc

@@ -28,7 +28,9 @@
 #include <sys/time.h>
 
 PeerAbstractCommand::PeerAbstractCommand(int cuid, Peer* peer, TorrentDownloadEngine* e, const Socket* s):
-  Command(cuid), e(e), peer(peer), checkSocketIsReadable(false), checkSocketIsWritable(false) {
+  Command(cuid), e(e), peer(peer),
+  checkSocketIsReadable(false), checkSocketIsWritable(false),
+  uploadLimitCheck(false), uploadLimit(0) {
 
   if(s != NULL) {
     socket = new Socket(*s);
@@ -74,8 +76,13 @@ bool PeerAbstractCommand::isTimeoutDetected() {
 bool PeerAbstractCommand::execute() {
   try {
     beforeSocketCheck();
-    if(checkSocketIsReadable && !readCheckTarget->isReadable(0)
-       || checkSocketIsWritable && !writeCheckTarget->isWritable(0)) {
+    if(uploadLimitCheck && e->getUploadSpeed() <= uploadLimit*1024 ||
+       checkSocketIsReadable && readCheckTarget->isReadable(0) ||
+       checkSocketIsWritable && writeCheckTarget->isWritable(0) ||
+       !checkSocketIsReadable && !checkSocketIsWritable) {
+      updateCheckPoint();
+      return executeInternal();
+    } else {
       if(isTimeoutDetected()) {
 	// TODO
 	checkPoint.tv_sec = 0;
@@ -85,10 +92,6 @@ bool PeerAbstractCommand::execute() {
       e->commands.push_back(this);
       return false;
     }
-    updateCheckPoint();
-    bool returnValue =  executeInternal();
-    //e->torrentMan->updatePeer(peer);
-    return returnValue;
   } catch(Exception* err) {
     logger->error(MSG_DOWNLOAD_ABORTED, err, cuid);
     onAbort(err);
@@ -113,7 +116,7 @@ void PeerAbstractCommand::onAbort(Exception* ex) {
     peer->error += MAX_PEER_ERROR;
   }
   peer->resetStatus();
-  logger->debug("CUID#%d - peer %s:%d banned.", cuid, peer->ipaddr.c_str(), peer->port);
+  logger->debug("CUID#%d - Peer %s:%d banned.", cuid, peer->ipaddr.c_str(), peer->port);
 }
 
 void PeerAbstractCommand::setReadCheckSocket(Socket* socket) {
@@ -159,3 +162,11 @@ void PeerAbstractCommand::setWriteCheckSocket(Socket* socket) {
     }
   }
 }
+
+void PeerAbstractCommand::setUploadLimit(int uploadLimit) {
+  this->uploadLimit = uploadLimit;
+}
+
+void PeerAbstractCommand::setUploadLimitCheck(bool check) {
+  this->uploadLimitCheck = check;
+}

+ 4 - 0
src/PeerAbstractCommand.h

@@ -45,11 +45,15 @@ protected:
   virtual void beforeSocketCheck() {}
   void setReadCheckSocket(Socket* socket);
   void setWriteCheckSocket(Socket* socket);
+  void setUploadLimit(int uploadLimit);
+  void setUploadLimitCheck(bool check);
 private:
   bool checkSocketIsReadable;
   bool checkSocketIsWritable;
   Socket* readCheckTarget;
   Socket* writeCheckTarget;
+  bool uploadLimitCheck;
+  int uploadLimit;
 public:
   PeerAbstractCommand(int cuid, Peer* peer, TorrentDownloadEngine* e, const Socket* s = NULL);
   virtual ~PeerAbstractCommand();

+ 13 - 262
src/PeerConnection.cc

@@ -27,279 +27,30 @@
 #include "LogFactory.h"
 #include <netinet/in.h>
 
-PeerConnection::PeerConnection(int cuid, const Socket* socket,
-			       const Option* op,
-			       Peer* peer, TorrentMan* torrentMan)
-  :cuid(cuid), socket(socket), option(op), logger(logger), peer(peer),
-   torrentMan(torrentMan),
-   resbufLength(0), currentPayloadLength(0), lenbufLength(0) {
+PeerConnection::PeerConnection(int cuid,
+			       const Socket* socket,
+			       const Option* op)
+  :cuid(cuid),
+   socket(socket),
+   option(op),
+   logger(logger),
+   resbufLength(0),
+   currentPayloadLength(0),
+   lenbufLength(0) {
   logger = LogFactory::getInstance();
 }
 
 PeerConnection::~PeerConnection() {}
 
-void PeerConnection::sendHandshake() const {
-  /**
-   * pstrlen --- '19', 1byte
-   * pstr    --- "BitTorrent protocol", 19bytes
-   * reserved --- \0 * 8, 8bytes
-   * info_hash --- info_hash, 20bytes
-   * peer_id --- peer_id, 20bytes
-   * total: 68bytes
-   */
-  char msg[HANDSHAKE_MESSAGE_LENGTH];
-  memset(msg, 0, sizeof(msg));
-  msg[0] = 19;
-  memcpy(&msg[1], PSTR, strlen(PSTR));
-  memcpy(&msg[28], torrentMan->getInfoHash(), 20);
-  memcpy(&msg[48], torrentMan->peerId.c_str(), 20);
-  writeOutgoingMessageLog("handshake");
-  socket->writeData(msg, sizeof(msg));
-}
-
-void PeerConnection::sendKeepAlive() const {
-  /**
-   * len --- 0, 4bytes
-   * total: 4bytes
-   */
-  char msg[4];
-  memset(msg, 0, sizeof(msg));
-  writeOutgoingMessageLog("keep alive");
-  socket->writeData(msg, sizeof(msg));
-}
-
-void PeerConnection::createNLengthMessage(char* msg, int msgLen, int payloadLen, int id) const {
-  assert(msgLen >= 5);
-  memset(msg, 0, msgLen);
-  setIntParam(msg, payloadLen);
-  msg[4] = (char)id;
-}
-
-void PeerConnection::setIntParam(char* dest, int param) const {
-  int nParam = htonl(param);
-  memcpy(dest, &nParam, 4);
-}
-
-void PeerConnection::writeOutgoingMessageLog(const char* msg) const {
-  logger->info(MSG_SEND_PEER_MESSAGE, cuid, peer->ipaddr.c_str(), peer->port, msg);
-}
-
-void PeerConnection::writeOutgoingMessageLog(const char* msg, int index) const {
-  logger->info(MSG_SEND_PEER_MESSAGE_WITH_INDEX, cuid, peer->ipaddr.c_str(), peer->port, msg, index);
-}
-
-void PeerConnection::writeOutgoingMessageLog(const char* msg, const unsigned char* bitfield, int bitfieldLength) const {
-  logger->info(MSG_SEND_PEER_MESSAGE_WITH_BITFIELD, cuid, peer->ipaddr.c_str(), peer->port, msg, Util::toHex(bitfield, bitfieldLength).c_str());
-}
-
-void PeerConnection::writeOutgoingMessageLog(const char* msg, int index, int begin, int length) const {
-  logger->info(MSG_SEND_PEER_MESSAGE_WITH_INDEX_BEGIN_LENGTH, cuid, peer->ipaddr.c_str(), peer->port, msg, index, begin, length);
-}
-
-void PeerConnection::sendChoke() const {
-  /**
-   * len --- 1, 4bytes
-   * id --- 0, 1byte
-   * total: 5bytes
-   */
-  char msg[5];
-  createNLengthMessage(msg, sizeof(msg), 1, 0);
-  writeOutgoingMessageLog("choke");
-  socket->writeData(msg, sizeof(msg));
-}
-
-void PeerConnection::sendUnchoke() const {
-  /**
-   * len --- 1, 4bytes
-   * id --- 1, 1byte
-   * total: 5bytes
-   */
-  char msg[5];
-  createNLengthMessage(msg, sizeof(msg), 1, 1);
-  writeOutgoingMessageLog("unchoke");
-  socket->writeData(msg, sizeof(msg));
-}
-
-void PeerConnection::sendInterested() const {
-  /**
-   * len --- 1, 4bytes
-   * id --- 2, 1byte
-   * total: 5bytes
-   */
-  char msg[5];
-  createNLengthMessage(msg, sizeof(msg), 1, 2);
-  writeOutgoingMessageLog("interested");
-  socket->writeData(msg, sizeof(msg));
-}
-
-void PeerConnection::sendNotInterested() const {
-  /**
-   * len --- 1, 4bytes
-   * id --- 3, 1byte
-   * total: 5bytes
-   */
-  char msg[5];
-  createNLengthMessage(msg, sizeof(msg), 1, 3);
-  writeOutgoingMessageLog("not interested");
-  socket->writeData(msg, sizeof(msg));
-}
-
-void PeerConnection::sendHave(int index) const {
-  /**
-   * len --- 5, 4bytes
-   * id --- 4, 1byte
-   * piece index --- index, 4bytes
-   * total: 9bytes
-   */
-  char msg[9];
-  createNLengthMessage(msg, sizeof(msg), 5, 4);
-  setIntParam(&msg[5], index);
-  writeOutgoingMessageLog("have", index);
-  socket->writeData(msg, sizeof(msg));
-}
-
-void PeerConnection::sendBitfield() const {
-  int len = torrentMan->getBitfieldLength();
-  const unsigned char* bitfield = torrentMan->getBitfield();
-  /**
-   * len --- 1+len, 4bytes
-   * id --- 5, 1byte
-   * bitfield --- bitfield, len bytes
-   * total: 5+len bytes
-   */
-  int msgLen = 5+len;
-  char* msg = new char[msgLen];
-  try {
-    createNLengthMessage(msg, msgLen, 1+len, 5);
-    writeOutgoingMessageLog("bitfield", bitfield, len);
-    socket->writeData(msg, msgLen);
-    delete [] msg;
-  } catch(Exception* ex) {
-    delete [] msg;
-    throw;
-  }
-}
-    
-void PeerConnection::sendRequest(int index, int begin, int length) const {
-  /**
-   * len --- 13, 4bytes
-   * id --- 6, 1byte
-   * index --- index, 4bytes
-   * begin --- begin, 4bytes
-   * length --- length, 4bytes
-   * total: 17bytes
-   */
-  char msg[17];
-  createNLengthMessage(msg, sizeof(msg), 13, 6);
-  setIntParam(&msg[5], index);
-  setIntParam(&msg[9], begin);
-  setIntParam(&msg[13], length);
-  writeOutgoingMessageLog("request", index, begin, length);
-  socket->writeData(msg, sizeof(msg));
-}
-
-void PeerConnection::sendPiece(int index, int begin, int length) const {
-  /**
-   * len --- 9+length, 4bytes
-   * id --- 7, 1byte
-   * index --- index, 4bytes
-   * begin --- begin, 4bytes
-   * sub total: 13bytes
-   * additionally, 
-   * block --- data, X bytes
-   */
-  char msg[13];
-  createNLengthMessage(msg, sizeof(msg), 9+length, 7);
-  setIntParam(&msg[5], index);
-  setIntParam(&msg[9], begin);
-  writeOutgoingMessageLog("piece", index, begin, length);
-  socket->writeData(msg, sizeof(msg));
-  int BUF_SIZE = 4096;
-  char buf[BUF_SIZE];
-  int iteration = length/BUF_SIZE;
-  long long int pieceOffset = ((long long int)index*torrentMan->pieceLength)+begin;
-  for(int i = 0; i < iteration; i++) {
-    if(torrentMan->diskAdaptor->readData(buf, BUF_SIZE, pieceOffset+i*BUF_SIZE) < BUF_SIZE) {
-      throw new DlAbortEx("piece reading failed.");
-    }
-    socket->writeData(buf, BUF_SIZE);
-  }
-  int rem = length%BUF_SIZE;
-  if(rem > 0) {
-    if(torrentMan->diskAdaptor->readData(buf, rem, pieceOffset+iteration*BUF_SIZE) < rem) {
-      throw new DlAbortEx("piece reading failed.");
-    }
-    socket->writeData(buf, rem);
-  }
-}
-
-void PeerConnection::sendPieceHeader(int index, int begin, int length) const {
-  /**
-   * len --- 9+length, 4bytes
-   * id --- 7, 1byte
-   * index --- index, 4bytes
-   * begin --- begin, 4bytes
-   * sub total: 13bytes
-   * additionally, 
-   * block --- data, X bytes
-   */
-  char msg[13];
-  createNLengthMessage(msg, sizeof(msg), 9+length, 7);
-  setIntParam(&msg[5], index);
-  setIntParam(&msg[9], begin);
-  writeOutgoingMessageLog("piece", index, begin, length);
-  socket->writeData(msg, sizeof(msg));
-}
-
-int PeerConnection::sendPieceData(long long int offset, int length) const {
-  int BUF_SIZE = 256;
-  char buf[BUF_SIZE];
-  int iteration = length/BUF_SIZE;
+int PeerConnection::sendMessage(const char* msg, int length) {
   int writtenLength = 0;
-  bool isWritable = true;
-  for(int i = 0; i < iteration; i++) {
-    isWritable = socket->isWritable(0);
-    if(!isWritable) {
-      return writtenLength;
-    }
-    if(torrentMan->diskAdaptor->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) {
-      throw new DlAbortEx("piece reading failed.");
-    }
-    socket->writeData(buf, BUF_SIZE);
-    writtenLength += BUF_SIZE;
-  }
   if(socket->isWritable(0)) {
-    int rem = length%BUF_SIZE;
-    if(rem > 0) {
-      if(torrentMan->diskAdaptor->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) {
-	throw new DlAbortEx("piece reading failed.");
-      }
-      socket->writeData(buf, rem);
-      writtenLength += rem;
-    }
+    socket->writeData(msg, length);
+    writtenLength += length;
   }
   return writtenLength;
 }
 
-
-void PeerConnection::sendCancel(int index, int begin, int length) const {
-  /**
-   * len --- 13, 4bytes
-   * id --- 8, 1byte
-   * index --- index, 4bytes
-   * begin --- begin, 4bytes
-   * length -- length, 4bytes
-   * total: 17bytes
-   */
-  char msg[17];
-  createNLengthMessage(msg, sizeof(msg), 13, 8);
-  setIntParam(&msg[5], index);
-  setIntParam(&msg[9], begin);
-  setIntParam(&msg[13], length);
-  writeOutgoingMessageLog("cancel", index, begin, length);
-  socket->writeData(msg, sizeof(msg));
-}
-
 bool PeerConnection::receiveMessage(char* msg, int& length) {
   if(!socket->isReadable(0)) {
     return false;

+ 4 - 26
src/PeerConnection.h

@@ -39,8 +39,6 @@ private:
   const Socket* socket;
   const Option* option;
   const Logger* logger;
-  Peer* peer;
-  TorrentMan* torrentMan;
 
   char resbuf[MAX_PAYLOAD_LEN];
   int resbufLength;
@@ -48,35 +46,15 @@ private:
   char lenbuf[4];
   int lenbufLength;
 
-  void createNLengthMessage(char* msg, int msgLen, int payloadLen, int id) const;
-  void setIntParam(char* dest, int param) const;
-
-  void writeOutgoingMessageLog(const char* msg) const;
-  void writeOutgoingMessageLog(const char* msg, int index) const;
-  void writeOutgoingMessageLog(const char* msg, const unsigned char* bitfield, int bitfieldLength) const;
-  void writeOutgoingMessageLog(const char* msg, int index, int begin, int length) const;
 public:
-  PeerConnection(int cuid, const Socket* socket, const Option* op,
-		 Peer* peer, TorrentMan* torrenMan);
+  PeerConnection(int cuid, const Socket* socket, const Option* op);
   ~PeerConnection();
+  
+  // Returns the number of bytes written
+  int sendMessage(const char* msg, int length);
 
-  void sendHandshake() const;
-  void sendKeepAlive() const;
-  void sendChoke() const;
-  void sendUnchoke() const;
-  void sendInterested() const;
-  void sendNotInterested() const;
-  void sendHave(int index) const;
-  void sendBitfield() const;
-  void sendRequest(int index, int begin, int length) const;
-  void sendPiece(int index, int begin, int length) const;
-  void sendPieceHeader(int index, int begin, int length) const;
-  int sendPieceData(long long int offset, int length) const;
-  void sendCancel(int index, int begin, int length) const;
   bool receiveMessage(char* msg, int& length);
   bool receiveHandshake(char* msg, int& length);
-
-  Peer* getPeer() const { return peer; }
 };
 
 #endif // _D_PEER_CONNECTION_H_

+ 255 - 118
src/PeerInteraction.cc

@@ -24,6 +24,7 @@
 #include "DlAbortEx.h"
 #include "KeepAliveMessage.h"
 #include "PeerMessageUtil.h"
+#include "Util.h"
 #include <netinet/in.h>
 
 PeerInteraction::PeerInteraction(int cuid,
@@ -36,7 +37,7 @@ PeerInteraction::PeerInteraction(int cuid,
    torrentMan(torrentMan),
    peer(peer),
    piece(Piece::nullPiece) {
-  peerConnection = new PeerConnection(cuid, socket, op, peer, this->torrentMan);
+  peerConnection = new PeerConnection(cuid, socket, op);
   logger = LogFactory::getInstance();
 }
 
@@ -45,14 +46,37 @@ PeerInteraction::~PeerInteraction() {
   for_each(messageQueue.begin(), messageQueue.end(), Deleter());
 }
 
-void PeerInteraction::send(int uploadSpeed) {
-  int size = messageQueue.size();
-  for(int i = 0; i < size; i++) {
+class MsgPushBack {
+private:
+  MessageQueue* messageQueue;
+public:
+  MsgPushBack(MessageQueue* messageQueue):messageQueue(messageQueue) {}
+
+  void operator()(PeerMessage* msg) {
+    messageQueue->push_back(msg);
+  }
+};
+
+bool PeerInteraction::isSendingMessageInProgress() const {
+  if(messageQueue.size() > 0) {
+    PeerMessage* peerMessage = messageQueue.front();
+    if(peerMessage->isInProgress()) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void PeerInteraction::sendMessages(int uploadSpeed) {
+  MessageQueue tempQueue;
+  while(messageQueue.size() > 0) {
     PeerMessage* msg = messageQueue.front();
     messageQueue.pop_front();
     if(uploadLimit != 0 && uploadLimit*1024 <= uploadSpeed &&
        msg->getId() == PieceMessage::ID && !msg->isInProgress()) {
-      messageQueue.push_back(msg);
+      //!((PieceMessage*)msg)->isPendingCountMax()) {
+      //((PieceMessage*)msg)->incrementPendingCount();
+      tempQueue.push_back(msg);
     } else {
       try {
 	msg->send();
@@ -68,6 +92,7 @@ void PeerInteraction::send(int uploadSpeed) {
       }
     }
   }
+  for_each(tempQueue.begin(), tempQueue.end(), MsgPushBack(&messageQueue));
 }
 
 void PeerInteraction::addMessage(PeerMessage* peerMessage) {
@@ -82,75 +107,111 @@ void PeerInteraction::addMessage(PeerMessage* peerMessage) {
   }
 }
 
-void PeerInteraction::deletePieceMessageInQueue(const CancelMessage* cancelMessage) {
+void PeerInteraction::rejectAllPieceMessageInQueue() {
+  MessageQueue tempQueue;
   for(MessageQueue::iterator itr = messageQueue.begin();
       itr != messageQueue.end();) {
-    if((*itr)->getId() == PieceMessage::ID) {
+    // Don't delete piece message which is in the allowed fast set.
+    if((*itr)->getId() == PieceMessage::ID && !(*itr)->isInProgress()
+       && !isInFastSet(((PieceMessage*)*itr)->getIndex())) {
       PieceMessage* pieceMessage = (PieceMessage*)*itr;
-      if(pieceMessage->getIndex() == cancelMessage->getIndex() &&
-	 pieceMessage->getBegin() == cancelMessage->getBegin() &&
-	 pieceMessage->getBlockLength() == cancelMessage->getLength() &&
-	 !pieceMessage->isInProgress()) {
-	logger->debug("CUID#%d - deleting piece message in queue because cancel message received. index=%d, begin=%d, length=%d",
-		      cuid,
-		      cancelMessage->getIndex(),
-		      cancelMessage->getBegin(),
-		      cancelMessage->getLength());
-	delete pieceMessage;
-	itr = messageQueue.erase(itr);
-      } else {
-	itr++;
+      logger->debug("CUID#%d - Reject piece message in queue because"
+		    " peer has been choked. index=%d, begin=%d, length=%d",
+		    cuid,
+		    pieceMessage->getIndex(),
+		    pieceMessage->getBegin(),
+		    pieceMessage->getBlockLength());
+      if(peer->isFastExtensionEnabled()) {
+	tempQueue.push_back(createRejectMessage(pieceMessage->getIndex(),
+						pieceMessage->getBegin(),
+						pieceMessage->getBlockLength()));
       }
+      delete pieceMessage;
+      itr = messageQueue.erase(itr);
     } else {
       itr++;
     }
   }
+  for_each(tempQueue.begin(), tempQueue.end(), MsgPushBack(&messageQueue));
 }
 
-void PeerInteraction::deleteRequestMessageInQueue() {
+void PeerInteraction::rejectPieceMessageInQueue(int index, int begin, int length) {
+  MessageQueue tempQueue;
   for(MessageQueue::iterator itr = messageQueue.begin();
       itr != messageQueue.end();) {
-    if((*itr)->getId() == RequestMessage::ID) {
-      delete *itr;
-      itr = messageQueue.erase(itr);
+    if((*itr)->getId() == PieceMessage::ID && !(*itr)->isInProgress()) {
+      PieceMessage* pieceMessage = (PieceMessage*)*itr;
+      if(pieceMessage->getIndex() == index &&
+	 pieceMessage->getBegin() == begin &&
+	 pieceMessage->getBlockLength() == length) {
+	logger->debug("CUID#%d - Reject piece message in queue because cancel"
+		      " message received. index=%d, begin=%d, length=%d",
+		      cuid, index, begin, length);
+	delete pieceMessage;
+	itr = messageQueue.erase(itr);
+	if(peer->isFastExtensionEnabled()) {
+	  tempQueue.push_back(createRejectMessage(index, begin, length));
+	}
+      } else {
+	itr++;
+      }
     } else {
       itr++;
     }
-  }      
+  }
+  for_each(tempQueue.begin(), tempQueue.end(), MsgPushBack(&messageQueue));
 }
 
-void PeerInteraction::deleteRequestSlot(const RequestSlot& requestSlot) {
-  // TODO use STL algorithm
-  for(RequestSlots::iterator itr = requestSlots.begin();
-      itr != requestSlots.end(); itr++) {
-    if(*itr == requestSlot) {
-      requestSlots.erase(itr);
-      break;
-    }
+void PeerInteraction::onChoked() {
+  if(!Piece::isNull(piece) && !peer->isInFastSet(piece.getIndex())) {
+    abortPiece();
   }
 }
 
-void PeerInteraction::deleteAllRequestSlot(Piece& piece) {
+void PeerInteraction::abortPiece() {
   if(!Piece::isNull(piece)) {
+    for(MessageQueue::iterator itr = messageQueue.begin();
+	itr != messageQueue.end();) {
+      if((*itr)->getId() == RequestMessage::ID
+	 && !(*itr)->isInProgress()) {
+	delete *itr;
+	itr = messageQueue.erase(itr);
+      } else {
+	itr++;
+      }
+    }  
     for(RequestSlots::const_iterator itr = requestSlots.begin();
 	itr != requestSlots.end(); itr++) {
-      if(itr->getIndex() == piece.getIndex()) {
-	piece.cancelBlock(itr->getBlockIndex());
-      }
+      logger->debug("CUID#%d - Deleting request slot blockIndex=%d"
+		    " because piece was canceled",
+		    cuid,
+		    itr->getBlockIndex());
+      piece.cancelBlock(itr->getBlockIndex());
     }
-    torrentMan->updatePiece(piece);
+    requestSlots.clear();
+    torrentMan->cancelPiece(piece);
+    piece = Piece::nullPiece;
+  }
+}
+
+
+void PeerInteraction::deleteRequestSlot(const RequestSlot& requestSlot) {
+  RequestSlots::iterator itr = find(requestSlots.begin(), requestSlots.end(),
+				    requestSlot);
+  if(itr != requestSlots.end()) {
+    requestSlots.erase(itr);
   }
-  requestSlots.clear();
 }
 
 void PeerInteraction::deleteTimeoutRequestSlot() {
   for(RequestSlots::iterator itr = requestSlots.begin();
       itr != requestSlots.end();) {
     if(itr->isTimeout(REQUEST_TIME_OUT)) {
-      logger->debug("CUID#%d - deleting requestslot blockIndex=%d because of time out", cuid,
+      logger->debug("CUID#%d - Deleting request slot blockIndex=%d"
+		    " because of time out",
+		    cuid,
 		    itr->getBlockIndex());
       if(!Piece::isNull(piece)) {
-	//addMessage(createCancelMessage(itr->getIndex(), itr->getBegin(), itr->getLength()));
 	piece.cancelBlock(itr->getBlockIndex());
       }
       itr = requestSlots.erase(itr);
@@ -166,7 +227,8 @@ void PeerInteraction::deleteCompletedRequestSlot() {
       itr != requestSlots.end();) {
     if(Piece::isNull(piece) || piece.hasBlock(itr->getBlockIndex()) ||
        torrentMan->hasPiece(piece.getIndex())) {
-      logger->debug("CUID#%d - deleting requestslot blockIndex=%d because the block is already acquired.", cuid,
+      logger->debug("CUID#%d - Deleting request slot blockIndex=%d because"
+		    " the block has been acquired.", cuid,
 		    itr->getBlockIndex());
       addMessage(createCancelMessage(itr->getIndex(), itr->getBegin(), itr->getLength()));
       itr = requestSlots.erase(itr);
@@ -176,28 +238,21 @@ void PeerInteraction::deleteCompletedRequestSlot() {
   }
 }
 
-RequestSlot PeerInteraction::getCorrespondingRequestSlot(const PieceMessage* pieceMessage) const {
+RequestSlot PeerInteraction::getCorrespondingRequestSlot(int index,
+							 int begin,
+							 int length) const {
   for(RequestSlots::const_iterator itr = requestSlots.begin();
       itr != requestSlots.end(); itr++) {
     const RequestSlot& slot = *itr;
-    if(slot.getIndex() == pieceMessage->getIndex() &&
-       slot.getBegin() == pieceMessage->getBegin() &&
-       slot.getLength() == pieceMessage->getBlockLength()) {
+    if(slot.getIndex() == index &&
+       slot.getBegin() == begin &&
+       slot.getLength() == length) {
       return slot;
     }
   }
   return RequestSlot::nullSlot;
 }
 
-void PeerInteraction::cancelAllRequest() {
-  cancelAllRequest(Piece::nullPiece);
-}
-
-void PeerInteraction::cancelAllRequest(Piece& piece) {
-  deleteRequestMessageInQueue();
-  deleteAllRequestSlot(piece);
-}
-
 int PeerInteraction::countMessageInQueue() const {
   return messageQueue.size();
 }
@@ -219,12 +274,17 @@ HandshakeMessage* PeerInteraction::receiveHandshake() {
     delete handshakeMessage;
     throw;
   }
+  if(handshakeMessage->isFastExtensionSupported()) {
+    peer->setFastExtensionEnabled(true);
+    logger->info("CUID#%d - Fast extension enabled.");
+  }
   return handshakeMessage;
 }
 
 HandshakeMessage* PeerInteraction::createHandshakeMessage(const char* msg, int msgLength) {
-  HandshakeMessage* message = PeerMessageUtil::createHandshakeMessage(msg, msgLength);
-  message->setPeerInteraction(this);
+  HandshakeMessage* message = HandshakeMessage::create(msg, msgLength);
+
+  setPeerMessageCommonProperty(message);
   return message;
 }
 
@@ -253,42 +313,61 @@ PeerMessage* PeerInteraction::createPeerMessage(const char* msg, int msgLength)
     int id = PeerMessageUtil::getId(msg);
     switch(id) {
     case ChokeMessage::ID:
-      peerMessage = PeerMessageUtil::createChokeMessage(msg, msgLength);
+      peerMessage = ChokeMessage::create(msg, msgLength);
       break;
     case UnchokeMessage::ID:
-      peerMessage = PeerMessageUtil::createUnchokeMessage(msg, msgLength);
+      peerMessage = UnchokeMessage::create(msg, msgLength);
       break;
     case InterestedMessage::ID:
-      peerMessage = PeerMessageUtil::createInterestedMessage(msg, msgLength);
+      peerMessage = InterestedMessage::create(msg, msgLength);
       break;
     case NotInterestedMessage::ID:
-      peerMessage = PeerMessageUtil::createNotInterestedMessage(msg, msgLength);
+      peerMessage = NotInterestedMessage::create(msg, msgLength);
       break;
     case HaveMessage::ID:
-      peerMessage = PeerMessageUtil::createHaveMessage(msg, msgLength);
+      peerMessage = HaveMessage::create(msg, msgLength);
       ((HaveMessage*)peerMessage)->setPieces(torrentMan->pieces);
       break;
     case BitfieldMessage::ID:
-      peerMessage = PeerMessageUtil::createBitfieldMessage(msg, msgLength);
+      peerMessage = BitfieldMessage::create(msg, msgLength);
       ((BitfieldMessage*)peerMessage)->setPieces(torrentMan->pieces);
       break;
     case RequestMessage::ID:
-      peerMessage = PeerMessageUtil::createRequestMessage(msg, msgLength);
+      peerMessage = RequestMessage::create(msg, msgLength);
       ((RequestMessage*)peerMessage)->setPieces(torrentMan->pieces);
       ((RequestMessage*)peerMessage)->setPieceLength(torrentMan->getPieceLength(((RequestMessage*)peerMessage)->getIndex()));
       break;
     case CancelMessage::ID:
-      peerMessage = PeerMessageUtil::createCancelMessage(msg, msgLength);
+      peerMessage = CancelMessage::create(msg, msgLength);
       ((CancelMessage*)peerMessage)->setPieces(torrentMan->pieces);
       ((CancelMessage*)peerMessage)->setPieceLength(torrentMan->getPieceLength(((CancelMessage*)peerMessage)->getIndex()));
       break;
     case PieceMessage::ID:
-      peerMessage = PeerMessageUtil::createPieceMessage(msg, msgLength);
+      peerMessage = PieceMessage::create(msg, msgLength);
       ((PieceMessage*)peerMessage)->setPieces(torrentMan->pieces);
       ((PieceMessage*)peerMessage)->setPieceLength(torrentMan->getPieceLength(((PieceMessage*)peerMessage)->getIndex()));
       break;
     case PortMessage::ID:
-      peerMessage = PeerMessageUtil::createPortMessage(msg, msgLength);
+      peerMessage = PortMessage::create(msg, msgLength);
+      break;
+    case HaveAllMessage::ID:
+      peerMessage = HaveAllMessage::create(msg, msgLength);
+      break;
+    case HaveNoneMessage::ID:
+      peerMessage = HaveNoneMessage::create(msg, msgLength);
+      break;
+    case RejectMessage::ID:
+      peerMessage = RejectMessage::create(msg, msgLength);
+      ((RejectMessage*)peerMessage)->setPieces(torrentMan->pieces);
+      ((RejectMessage*)peerMessage)->setPieceLength(torrentMan->getPieceLength(((RejectMessage*)peerMessage)->getIndex()));
+      break;
+    case SuggestPieceMessage::ID:
+      peerMessage = SuggestPieceMessage::create(msg, msgLength);
+      ((SuggestPieceMessage*)peerMessage)->setPieces(torrentMan->pieces);
+      break;
+    case AllowedFastMessage::ID:
+      peerMessage = AllowedFastMessage::create(msg, msgLength);
+      ((AllowedFastMessage*)peerMessage)->setPieces(torrentMan->pieces);
       break;
     default:
       throw new DlAbortEx("invalid message id. id = %d", id);
@@ -306,34 +385,35 @@ void PeerInteraction::syncPiece() {
   torrentMan->syncPiece(piece);
 }
 
-Piece PeerInteraction::getNewPieceAndSendInterest() {
-  cancelAllRequest();
-  Piece piece = torrentMan->getMissingPiece(peer);
+void PeerInteraction::getNewPieceAndSendInterest() {
+  piece = torrentMan->getMissingPiece(peer);
   if(Piece::isNull(piece)) {
-    logger->debug("CUID#%d - not interested in the peer", cuid);
+    logger->debug("CUID#%d - Not interested in the peer", cuid);
     addMessage(createNotInterestedMessage());
   } else {
-    logger->debug("CUID#%d - starting download for piece index=%d (%d/%d completed)",
-		  cuid, piece.getIndex(), piece.countCompleteBlock(),
-		  piece.countBlock());
-    logger->debug("CUID#%d - interested in the peer", cuid);
+    if(peer->peerChoking && !peer->isInFastSet(piece.getIndex())) {
+      abortPiece();
+    } else {
+      logger->info("CUID#%d - Starting download for piece index=%d (%d/%d completed)",
+		    cuid, piece.getIndex(), piece.countCompleteBlock(),
+		    piece.countBlock());
+    }
+    logger->debug("CUID#%d - Interested in the peer", cuid);
     addMessage(createInterestedMessage());
   }
-  return piece;
 }
 
-void PeerInteraction::sendMessages(int currentUploadSpeed) {
+void PeerInteraction::addRequests() {
   if(Piece::isNull(piece)) {
     // retrive new piece from TorrentMan
-    piece = getNewPieceAndSendInterest();
-  } else if(peer->peerChoking) {
-    cancelAllRequest(piece);
-    torrentMan->cancelPiece(piece);
-    piece = Piece::nullPiece;
+    getNewPieceAndSendInterest();
+  } else if(peer->peerChoking && !peer->isInFastSet(piece.getIndex())) {
+    onChoked();
   } else if(piece.pieceComplete()) {
-    piece = getNewPieceAndSendInterest();
+    abortPiece();
+    getNewPieceAndSendInterest();
   }
-  if(!Piece::isNull(piece) && !peer->peerChoking) {
+  if(!Piece::isNull(piece)) {
     if(torrentMan->isEndGame()) {
       BlockIndexes missingBlockIndexes = piece.getAllMissingBlockIndexes();
       if(countRequestSlot() == 0) {
@@ -355,30 +435,43 @@ void PeerInteraction::sendMessages(int currentUploadSpeed) {
       }
     }
   }
-  send(currentUploadSpeed);
-}
-
-void PeerInteraction::sendNow(PeerMessage* peerMessage) {
-  // ignore inProgress state
-  peerMessage->send();
-  delete peerMessage;
 }
 
-void PeerInteraction::trySendNow(PeerMessage* peerMessage) {
-  if(countMessageInQueue() == 0) {
-    sendNow(peerMessage);
+void PeerInteraction::sendHandshake() {
+  HandshakeMessage* handshake = new HandshakeMessage();
+  memcpy(handshake->infoHash, torrentMan->getInfoHash(), INFO_HASH_LENGTH);
+  memcpy(handshake->peerId, torrentMan->peerId.c_str(), PEER_ID_LENGTH);
+  setPeerMessageCommonProperty(handshake);
+  addMessage(handshake);
+  sendMessages(0);
+}
+
+void PeerInteraction::sendBitfield() {
+  if(peer->isFastExtensionEnabled()) {
+    if(torrentMan->hasAllPieces()) {
+      addMessage(createHaveAllMessage());
+    } else if(torrentMan->getDownloadLength() > 0) {
+      addMessage(createBitfieldMessage());
+    } else {
+      addMessage(createHaveNoneMessage());
+    }
   } else {
-    addMessage(peerMessage);
+    if(torrentMan->getDownloadLength() > 0) {
+      addMessage(createBitfieldMessage());
+    }
   }
+  sendMessages(0);
 }
 
-void PeerInteraction::sendHandshake() {
-  peerConnection->sendHandshake();
-}
-
-void PeerInteraction::abortPiece() {
-  cancelAllRequest(piece);
-  torrentMan->cancelPiece(piece);
+void PeerInteraction::sendAllowedFast() {
+  if(peer->isFastExtensionEnabled()) {
+    Integers fastSet = Util::computeFastSet(peer->ipaddr, torrentMan->getInfoHash(),
+				   torrentMan->pieces, ALLOWED_FAST_SET_SIZE);
+    for(Integers::const_iterator itr = fastSet.begin();
+	itr != fastSet.end(); itr++) {
+      addMessage(createAllowedFastMessage(*itr));
+    }
+  }
 }
 
 Piece& PeerInteraction::getDownloadPiece() {
@@ -388,6 +481,16 @@ Piece& PeerInteraction::getDownloadPiece() {
   return piece;
 }
 
+bool PeerInteraction::isInFastSet(int index) const {
+  return find(fastSet.begin(), fastSet.end(), index) != fastSet.end();
+}
+
+void PeerInteraction::addFastSetIndex(int index) {
+  if(!isInFastSet(index)) {
+    fastSet.push_back(index);
+  }
+}
+
 void PeerInteraction::setPeerMessageCommonProperty(PeerMessage* peerMessage) {
   peerMessage->setPeer(peer);
   peerMessage->setCuid(cuid);
@@ -395,68 +498,102 @@ void PeerInteraction::setPeerMessageCommonProperty(PeerMessage* peerMessage) {
 }
 
 RequestMessage* PeerInteraction::createRequestMessage(int blockIndex) {
-  RequestMessage* msg =
-    PeerMessageUtil::createRequestMessage(piece.getIndex(),
-					  blockIndex*piece.getBlockLength(),
-					  piece.getBlockLength(blockIndex),
-					  blockIndex);
+  RequestMessage* msg = new RequestMessage();
+  msg->setIndex(piece.getIndex());
+  msg->setBegin(blockIndex*piece.getBlockLength());
+  msg->setLength(piece.getBlockLength(blockIndex));
+  msg->setBlockIndex(blockIndex);
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
 CancelMessage* PeerInteraction::createCancelMessage(int index, int begin, int length) {
-  CancelMessage* msg =
-    PeerMessageUtil::createCancelMessage(index, begin, length);
+  CancelMessage* msg = new CancelMessage();
+  msg->setIndex(index);
+  msg->setBegin(begin);
+  msg->setLength(length);
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
 PieceMessage* PeerInteraction::createPieceMessage(int index, int begin, int length) {
-  PieceMessage* msg =
-    PeerMessageUtil::createPieceMessage(index, begin, length);
+  PieceMessage* msg = new PieceMessage();
+  msg->setIndex(index);
+  msg->setBegin(begin);
+  msg->setBlockLength(length);
   setPeerMessageCommonProperty(msg);
   return msg;  
 }
 
 HaveMessage* PeerInteraction::createHaveMessage(int index) {
-  HaveMessage* msg = PeerMessageUtil::createHaveMessage(index);
+  HaveMessage* msg = new HaveMessage();
+  msg->setIndex(index);
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
 ChokeMessage* PeerInteraction::createChokeMessage() {
-  ChokeMessage* msg = PeerMessageUtil::createChokeMessage();
+  ChokeMessage* msg = new ChokeMessage();
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
 UnchokeMessage* PeerInteraction::createUnchokeMessage() {
-  UnchokeMessage* msg = PeerMessageUtil::createUnchokeMessage();
+  UnchokeMessage* msg = new UnchokeMessage();
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
 InterestedMessage* PeerInteraction::createInterestedMessage() {
-  InterestedMessage* msg = PeerMessageUtil::createInterestedMessage();
+  InterestedMessage* msg = new InterestedMessage();
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
 NotInterestedMessage* PeerInteraction::createNotInterestedMessage() {
-  NotInterestedMessage* msg = PeerMessageUtil::createNotInterestedMessage();
+  NotInterestedMessage* msg = new NotInterestedMessage();
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
 BitfieldMessage* PeerInteraction::createBitfieldMessage() {
-  BitfieldMessage* msg = PeerMessageUtil::createBitfieldMessage();
+  BitfieldMessage* msg = new BitfieldMessage();
+  msg->setBitfield(getTorrentMan()->getBitfield(),
+		   getTorrentMan()->getBitfieldLength());
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
 KeepAliveMessage* PeerInteraction::createKeepAliveMessage() {
-  KeepAliveMessage* msg = PeerMessageUtil::createKeepAliveMessage();
+  KeepAliveMessage* msg = new KeepAliveMessage();
+  setPeerMessageCommonProperty(msg);
+  return msg;
+}
+
+HaveAllMessage* PeerInteraction::createHaveAllMessage() {
+  HaveAllMessage* msg = new HaveAllMessage();
   setPeerMessageCommonProperty(msg);
   return msg;
 }
 
+HaveNoneMessage* PeerInteraction::createHaveNoneMessage() {
+  HaveNoneMessage* msg = new HaveNoneMessage();
+  setPeerMessageCommonProperty(msg);
+  return msg;
+}
+
+RejectMessage* PeerInteraction::createRejectMessage(int index, int begin, int length) {
+  RejectMessage* msg = new RejectMessage();
+  msg->setIndex(index);
+  msg->setBegin(begin);
+  msg->setLength(length);
+  setPeerMessageCommonProperty(msg);
+  return msg;
+}
+
+AllowedFastMessage* PeerInteraction::createAllowedFastMessage(int index) {
+  AllowedFastMessage* msg = new AllowedFastMessage();
+  msg->setIndex(index);
+  setPeerMessageCommonProperty(msg);
+  return msg;
+}

+ 27 - 15
src/PeerInteraction.h

@@ -36,9 +36,15 @@
 #include "HandshakeMessage.h"
 #include "KeepAliveMessage.h"
 #include "PortMessage.h"
+#include "HaveAllMessage.h"
+#include "HaveNoneMessage.h"
+#include "RejectMessage.h"
+#include "AllowedFastMessage.h"
+#include "SuggestPieceMessage.h"
 #include "RequestSlot.h"
 
 #define REQUEST_TIME_OUT 120
+#define ALLOWED_FAST_SET_SIZE 10
 
 typedef deque<RequestSlot> RequestSlots;
 typedef deque<PeerMessage*> MessageQueue;
@@ -54,17 +60,14 @@ private:
   PeerConnection* peerConnection;
   Peer* peer;
   Piece piece;
+  // allowed fast piece indexes that local client has sent
+  Integers fastSet;
   const Logger* logger;
-
-  Piece getNewPieceAndSendInterest();
+  
+  void getNewPieceAndSendInterest();
   PeerMessage* createPeerMessage(const char* msg, int msgLength);
   HandshakeMessage* createHandshakeMessage(const char* msg, int msgLength);
-  void send(int uploadSpeed);
   void setPeerMessageCommonProperty(PeerMessage* peerMessage);
-  void deleteAllRequestSlot(Piece& piece);
-  void deleteRequestMessageInQueue();
-  void cancelAllRequest();
-  void cancelAllRequest(Piece& piece);
   int countRequestSlot() const;
 public:
   PeerInteraction(int cuid,
@@ -75,12 +78,16 @@ public:
   ~PeerInteraction();
 
   void addMessage(PeerMessage* peerMessage);
-  void deletePieceMessageInQueue(const CancelMessage* cancelMessage);
-  
+  void rejectPieceMessageInQueue(int index, int begin, int length);
+  void rejectAllPieceMessageInQueue();
+  void onChoked();
+  void abortPiece();
+
+  bool isSendingMessageInProgress() const;
   void deleteRequestSlot(const RequestSlot& requestSlot);
   void deleteTimeoutRequestSlot();
   void deleteCompletedRequestSlot();
-  RequestSlot getCorrespondingRequestSlot(const PieceMessage* pieceMessage) const;
+  RequestSlot getCorrespondingRequestSlot(int index, int begin, int length) const;
 
   int countMessageInQueue() const;
 
@@ -100,15 +107,16 @@ public:
   void setDownloadPiece(const Piece& piece) {
     this->piece = piece;
   }
+  
+  bool isInFastSet(int index) const;
+  void addFastSetIndex(int index);
 
   void syncPiece();
+  void addRequests();
   void sendMessages(int currentUploadSpeed);
-  // after sending message, deletes peerMessage.
-  // So don't use peerMessage after this function call.
-  void sendNow(PeerMessage* peerMessage);
-  void trySendNow(PeerMessage* peerMessage);
-  void abortPiece();
   void sendHandshake();
+  void sendBitfield();
+  void sendAllowedFast();
 
   PeerMessage* receiveMessage();
   HandshakeMessage* receiveHandshake();
@@ -123,6 +131,10 @@ public:
   NotInterestedMessage* createNotInterestedMessage();
   BitfieldMessage* createBitfieldMessage();
   KeepAliveMessage* createKeepAliveMessage();
+  HaveAllMessage* createHaveAllMessage();
+  HaveNoneMessage* createHaveNoneMessage();
+  RejectMessage* createRejectMessage(int index, int begin, int length);
+  AllowedFastMessage* createAllowedFastMessage(int index);
 };
 
 #endif // _D_PEER_INTERACTION_H_

+ 30 - 10
src/PeerInteractionCommand.cc

@@ -40,6 +40,7 @@ PeerInteractionCommand::PeerInteractionCommand(int cuid, Peer* peer,
   peerInteraction = new PeerInteraction(cuid, socket, e->option,
 					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;
@@ -65,6 +66,7 @@ bool PeerInteractionCommand::executeInternal() {
     setTimeout(e->option->getAsInt(PREF_TIMEOUT));
   }
   setWriteCheckSocket(NULL);
+  setUploadLimitCheck(false);
 
   switch(sequence) {
   case INITIATOR_SEND_HANDSHAKE:
@@ -72,6 +74,12 @@ bool PeerInteractionCommand::executeInternal() {
     sequence = INITIATOR_WAIT_HANDSHAKE;
     break;
   case INITIATOR_WAIT_HANDSHAKE: {
+    if(peerInteraction->countMessageInQueue() > 0) {
+      peerInteraction->sendMessages(e->getUploadSpeed());
+      if(peerInteraction->countMessageInQueue() > 0) {
+	break;
+      }
+    }
     HandshakeMessage* handshakeMessage = peerInteraction->receiveHandshake();
     if(handshakeMessage == NULL) {
       break;
@@ -81,9 +89,8 @@ bool PeerInteractionCommand::executeInternal() {
 		 peer->ipaddr.c_str(), peer->port,
 		 handshakeMessage->toString().c_str());
     delete handshakeMessage;
-    if(e->torrentMan->getDownloadLength() > 0) {
-      peerInteraction->sendNow(peerInteraction->createBitfieldMessage());
-    }
+    peerInteraction->sendBitfield();
+    peerInteraction->sendAllowedFast();
     sequence = WIRED;
     break;
   }
@@ -98,9 +105,8 @@ bool PeerInteractionCommand::executeInternal() {
 		 handshakeMessage->toString().c_str());
     delete handshakeMessage;
     peerInteraction->sendHandshake();
-    if(e->torrentMan->getDownloadLength() > 0) {
-      peerInteraction->sendNow(peerInteraction->createBitfieldMessage());
-    }
+    peerInteraction->sendBitfield();
+    peerInteraction->sendAllowedFast();
     sequence = WIRED;    
     break;
   }
@@ -115,11 +121,16 @@ bool PeerInteractionCommand::executeInternal() {
     }
     peerInteraction->deleteTimeoutRequestSlot();
     peerInteraction->deleteCompletedRequestSlot();
+    peerInteraction->addRequests();
     peerInteraction->sendMessages(e->getUploadSpeed());
     break;
   }
   if(peerInteraction->countMessageInQueue() > 0) {
-    setWriteCheckSocket(socket);
+    if(peerInteraction->isSendingMessageInProgress()) {
+      setWriteCheckSocket(socket);
+    } else {
+      setUploadLimitCheck(true);
+    }
   }
   e->commands.push_back(this);
   return false;
@@ -246,7 +257,8 @@ void PeerInteractionCommand::keepAlive() {
     gettimeofday(&now, NULL);
     if(Util::difftv(now, keepAliveCheckPoint) >= (long long int)120*1000000) {
       if(peerInteraction->countMessageInQueue() == 0) {
-	peerInteraction->sendNow(peerInteraction->createKeepAliveMessage());
+	peerInteraction->addMessage(peerInteraction->createKeepAliveMessage());
+	peerInteraction->sendMessages(e->getUploadSpeed());
       }
       keepAliveCheckPoint = now;
     }
@@ -261,10 +273,18 @@ void PeerInteractionCommand::beforeSocketCheck() {
 
     PieceIndexes indexes = e->torrentMan->getAdvertisedPieceIndexes(cuid);
     if(indexes.size() >= 20) {
-      peerInteraction->trySendNow(peerInteraction->createBitfieldMessage());
+      if(peer->isFastExtensionEnabled()) {
+	if(e->torrentMan->hasAllPieces()) {
+	  peerInteraction->addMessage(peerInteraction->createHaveAllMessage());
+	} else {
+	  peerInteraction->addMessage(peerInteraction->createBitfieldMessage());
+	}
+      } else {
+	peerInteraction->addMessage(peerInteraction->createBitfieldMessage());
+      }
     } else {
       for(PieceIndexes::iterator itr = indexes.begin(); itr != indexes.end(); itr++) {
-	peerInteraction->trySendNow(peerInteraction->createHaveMessage(*itr));
+	peerInteraction->addMessage(peerInteraction->createHaveMessage(*itr));
       }
     }
     keepAlive();

+ 13 - 169
src/PeerMessageUtil.cc

@@ -40,162 +40,6 @@ int PeerMessageUtil::getShortIntParam(const char* msg, int offset) {
   return ntohs(nParam);
 }
 
-ChokeMessage* PeerMessageUtil::createChokeMessage(const char* msg, int len) {
-  if(len != 1) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "choke", len, 1);
-  }
-  ChokeMessage* chokeMessage = new ChokeMessage();
-  return chokeMessage;
-}
-
-UnchokeMessage* PeerMessageUtil::createUnchokeMessage(const char* msg, int len) {
-  if(len != 1) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "unchoke", len, 1);
-  }
-  UnchokeMessage* unchokeMessage = new UnchokeMessage();
-  return unchokeMessage;
-}
-
-InterestedMessage* PeerMessageUtil::createInterestedMessage(const char* msg, int len) {
-  if(len != 1) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "interested", len, 1);
-  }
-  InterestedMessage* interestedMessage = new InterestedMessage();
-  return interestedMessage;
-}
-
-NotInterestedMessage* PeerMessageUtil::createNotInterestedMessage(const char* msg, int len) {
-  if(len != 1) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "not interested", len, 1);
-  }
-  NotInterestedMessage* notInterestedMessage = new NotInterestedMessage();
-  return notInterestedMessage;
-}
-
-HaveMessage* PeerMessageUtil::createHaveMessage(const char* msg, int len) {
-  if(len != 5) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "have", len, 5);
-  }
-  HaveMessage* haveMessage = new HaveMessage();
-  haveMessage->setIndex(getIntParam(msg, 1));
-  return haveMessage;
-}
-
-BitfieldMessage* PeerMessageUtil::createBitfieldMessage(const char* msg, int len) {
-  if(len <= 1) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be greater than %d", "bitfield", len, 1);
-  }
-  BitfieldMessage* bitfieldMessage = new BitfieldMessage();
-  bitfieldMessage->setBitfield((unsigned char*)msg+1, len-1);
-  return bitfieldMessage;
-}
-
-RequestMessage* PeerMessageUtil::createRequestMessage(const char* msg, int len) {
-  if(len != 13) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "request", len, 13);
-  }
-  RequestMessage* requestMessage = new RequestMessage();
-  requestMessage->setIndex(getIntParam(msg, 1));
-  requestMessage->setBegin(getIntParam(msg, 5));
-  requestMessage->setLength(getIntParam(msg, 9));
-  return requestMessage;
-}
-
-CancelMessage* PeerMessageUtil::createCancelMessage(const char* msg, int len) {
-  if(len != 13) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "cancel", len, 13);
-  }
-  CancelMessage* cancelMessage = new CancelMessage();
-  cancelMessage->setIndex(getIntParam(msg, 1));
-  cancelMessage->setBegin(getIntParam(msg, 5));
-  cancelMessage->setLength(getIntParam(msg, 9));
-  return cancelMessage;
-}
-
-PieceMessage* PeerMessageUtil::createPieceMessage(const char* msg, int len) {
-  if(len <= 9) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be greater than %d", "piece", len, 9);
-  }
-  PieceMessage* pieceMessage = new PieceMessage();
-  pieceMessage->setIndex(getIntParam(msg, 1));
-  pieceMessage->setBegin(getIntParam(msg, 5));
-  pieceMessage->setBlock(msg+9, len-9);
-  return pieceMessage;
-}
-
-PortMessage* PeerMessageUtil::createPortMessage(const char* msg, int len) {
-  if(len != 3) {
-    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "port", len, 3);
-  }
-  PortMessage* portMessage = new PortMessage();
-  portMessage->setPort(getShortIntParam(msg, 1));
-  return portMessage;
-}
-
-RequestMessage* PeerMessageUtil::createRequestMessage(int index,
-						       int begin,
-						       int length,
-						       int blockIndex) {
-  RequestMessage* msg = new RequestMessage();
-  msg->setIndex(index);
-  msg->setBegin(begin);
-  msg->setLength(length);
-  msg->setBlockIndex(blockIndex);
-  return msg;
-}
-
-CancelMessage* PeerMessageUtil::createCancelMessage(int index, int begin, int length) {
-  CancelMessage* msg = new CancelMessage();
-  msg->setIndex(index);
-  msg->setBegin(begin);
-  msg->setLength(length);
-  return msg;
-}
-
-PieceMessage* PeerMessageUtil::createPieceMessage(int index, int begin, int length) {
-  PieceMessage* msg = new PieceMessage();
-  msg->setIndex(index);
-  msg->setBegin(begin);
-  msg->setBlockLength(length);
-  return msg;  
-}
-
-HaveMessage* PeerMessageUtil::createHaveMessage(int index) {
-  HaveMessage* msg = new HaveMessage();
-  msg->setIndex(index);
-  return msg;
-}
-
-ChokeMessage* PeerMessageUtil::createChokeMessage() {
-  ChokeMessage* msg = new ChokeMessage();
-  return msg;
-}
-
-UnchokeMessage* PeerMessageUtil::createUnchokeMessage() {
-  UnchokeMessage* msg = new UnchokeMessage();
-  return msg;
-}
-
-InterestedMessage* PeerMessageUtil::createInterestedMessage() {
-  InterestedMessage* msg = new InterestedMessage();
-  return msg;
-}
-
-NotInterestedMessage* PeerMessageUtil::createNotInterestedMessage() {
-  NotInterestedMessage* msg = new NotInterestedMessage();
-  return msg;
-}
-
-BitfieldMessage* PeerMessageUtil::createBitfieldMessage() {
-  BitfieldMessage* msg = new BitfieldMessage();
-  return msg;
-}
-
-KeepAliveMessage* PeerMessageUtil::createKeepAliveMessage() {
-  KeepAliveMessage* msg = new KeepAliveMessage();
-  return msg;
-}
-
 void PeerMessageUtil::checkIndex(int index, int pieces) {
   if(!(0 <= index && index < pieces)) {
     throw new DlAbortEx("invalid index = %d", index);
@@ -244,19 +88,6 @@ void PeerMessageUtil::checkBitfield(const unsigned char* bitfield, int bitfieldL
   }
 }
 
-HandshakeMessage* PeerMessageUtil::createHandshakeMessage(const char* msg, int length) {
-  HandshakeMessage* message = new HandshakeMessage();
-  message->pstrlen = msg[0];
-  char pstr[20];
-  memcpy(pstr, &msg[1], sizeof(pstr)-1);
-  pstr[sizeof(pstr)-1] = '\0';
-  message->pstr = pstr;
-  memcpy(message->infoHash, &msg[28], 20);
-  memcpy(message->peerId, &msg[48], 20);
-  return message;
-}
-
-
 void PeerMessageUtil::checkHandshake(const HandshakeMessage* message, const unsigned char* infoHash) {
   if(message->pstrlen != 19) {
     throw new DlAbortEx("invalid handshake pstrlen = %d", (int)message->pstrlen);
@@ -272,3 +103,16 @@ void PeerMessageUtil::checkHandshake(const HandshakeMessage* message, const unsi
   }
 }
 
+void PeerMessageUtil::setIntParam(char* dest, int param) {
+  int nParam = htonl(param);
+  memcpy(dest, &nParam, 4);
+}
+
+void PeerMessageUtil::createPeerMessageString(char* msg, int msgLength,
+					      int payloadLength,
+					      int messageId) {
+  assert(msgLength >= 5);
+  memset(msg, 0, msgLength);
+  setIntParam(msg, payloadLength);
+  msg[4] = (char)messageId;
+}

+ 9 - 28
src/PeerMessageUtil.h

@@ -34,6 +34,8 @@
 #include "HandshakeMessage.h"
 #include "KeepAliveMessage.h"
 #include "PortMessage.h"
+#include "HaveAllMessage.h"
+#include "HaveNoneMessage.h"
 #include "PeerConnection.h"
 
 #define MAX_BLOCK_LENGTH (128*1024)
@@ -41,36 +43,13 @@
 class PeerMessageUtil {
 private:
   PeerMessageUtil() {}
-
+public:
   static int getIntParam(const char* msg, int offset);
   static int getShortIntParam(const char* msg, int offset);
-public:
-  static int getId(const char* msg);
-
-  static ChokeMessage* createChokeMessage(const char* msg, int len);
-  static UnchokeMessage* createUnchokeMessage(const char* msg, int len);
-  static InterestedMessage* createInterestedMessage(const char* msg, int len);
-  static NotInterestedMessage* createNotInterestedMessage(const char* msg,
-							  int len);
-  static HaveMessage* createHaveMessage(const char* msg, int len);
-  static BitfieldMessage* createBitfieldMessage(const char* msg, int len);
-  static RequestMessage* createRequestMessage(const char* msg, int len);
-  static CancelMessage* createCancelMessage(const char* msg, int len);
-  static PieceMessage* createPieceMessage(const char* msg, int len);
-  static PortMessage* createPortMessage(const char* msg, int len);
-
-  static ChokeMessage* createChokeMessage();
-  static UnchokeMessage* createUnchokeMessage();
-  static InterestedMessage* createInterestedMessage();
-  static NotInterestedMessage* createNotInterestedMessage();
-  static HaveMessage* createHaveMessage(int index);
-  static BitfieldMessage* createBitfieldMessage();
-  static RequestMessage* createRequestMessage(int index, int begin,
-					      int length, int blockIndex);
-  static CancelMessage* createCancelMessage(int index, int begin, int length);
-  static PieceMessage* createPieceMessage(int index, int begin, int length);
-  static KeepAliveMessage* createKeepAliveMessage();
+  static void setIntParam(char* dest, int param);
 
+  static int getId(const char* msg);
+  
   static void checkIndex(int index, int pieces);
   static void checkBegin(int begin, int pieceLength);
   static void checkLength(int length);
@@ -79,9 +58,11 @@ public:
 			    int bitfieldLength,
 			    int pieces);
 
-  static HandshakeMessage* createHandshakeMessage(const char* msg, int length);
   static void checkHandshake(const HandshakeMessage* message,
 			     const unsigned char* infoHash);
+
+  static void createPeerMessageString(char* msg, int msgLength,
+				      int payloadLength, int messageId);
 };
 
 #endif // _D_PEER_MESSAGE_UTIL_H_

+ 102 - 13
src/PieceMessage.cc

@@ -24,6 +24,7 @@
 #include "PeerInteraction.h"
 #include "Util.h"
 #include "message.h"
+#include "DlAbortEx.h"
 
 void PieceMessage::setBlock(const char* block, int blockLength) {
   if(this->block != NULL) {
@@ -34,16 +35,34 @@ void PieceMessage::setBlock(const char* block, int blockLength) {
   memcpy(this->block, block, this->blockLength);
 }
 
+PieceMessage* PieceMessage::create(const char* data, int dataLength) {
+  if(dataLength <= 9) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be greater than %d", "piece", dataLength, 9);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "piece", ID);
+  }
+  PieceMessage* pieceMessage = new PieceMessage();
+  pieceMessage->setIndex(PeerMessageUtil::getIntParam(data, 1));
+  pieceMessage->setBegin(PeerMessageUtil::getIntParam(data, 5));
+  pieceMessage->setBlock(data+9, dataLength-9);
+  return pieceMessage;
+}
+
 void PieceMessage::receivedAction() {
   TorrentMan* torrentMan = peerInteraction->getTorrentMan();
-  RequestSlot slot = peerInteraction->getCorrespondingRequestSlot(this);
+  RequestSlot slot = peerInteraction->getCorrespondingRequestSlot(index,
+								  begin,
+								  blockLength);
   peer->addPeerUpload(blockLength);
   if(peerInteraction->hasDownloadPiece() &&
      !RequestSlot::isNull(slot)) {
     Piece& piece = peerInteraction->getDownloadPiece();
     long long int offset =
       ((long long int)index)*torrentMan->pieceLength+begin;
-    logger->debug("CUID#%d - write block length = %d, offset=%lld",
+    logger->debug("CUID#%d - Writing the block length=%d, offset=%lld",
 		  cuid, blockLength, offset);      
     torrentMan->diskAdaptor->writeData(block,
 				       blockLength,
@@ -51,7 +70,7 @@ void PieceMessage::receivedAction() {
     piece.completeBlock(slot.getBlockIndex());
     peerInteraction->deleteRequestSlot(slot);
     torrentMan->updatePiece(piece);
-    logger->debug("CUID#%d - setting piece bit index=%d",
+    logger->debug("CUID#%d - Setting piece block index=%d",
 		  cuid, slot.getBlockIndex());
     torrentMan->addDeltaDownloadLength(blockLength);
     if(piece.pieceComplete()) {
@@ -64,25 +83,95 @@ void PieceMessage::receivedAction() {
   }
 }
 
+const char* PieceMessage::getMessageHeader() {
+  if(!inProgress) {
+    /**
+     * len --- 9+blockLength, 4bytes
+     * id --- 7, 1byte
+     * index --- index, 4bytes
+     * begin --- begin, 4bytes
+     * total: 13bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msgHeader, sizeof(msgHeader),
+					     9+blockLength, ID);
+    PeerMessageUtil::setIntParam(&msgHeader[5], index);
+    PeerMessageUtil::setIntParam(&msgHeader[9], begin);
+  }
+  return msgHeader;
+}
+
+int PieceMessage::getMessageHeaderLength() {
+  return sizeof(msgHeader);
+}
+
 void PieceMessage::send() {
-  if((!peer->amChoking && peer->peerInterested) || inProgress) {
-    PeerConnection* peerConnection = peerInteraction->getPeerConnection();
+  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
+  PeerConnection* peerConnection = peerInteraction->getPeerConnection();
+  if(!headerSent) {
     if(!inProgress) {
-      peerConnection->sendPieceHeader(index, begin, blockLength);
-      peer->addPeerDownload(blockLength);
-      leftPieceDataLength = blockLength;
+      logger->info(MSG_SEND_PEER_MESSAGE,
+		   cuid, peer->ipaddr.c_str(), peer->port,
+		   toString().c_str());
+      getMessageHeader();
+      leftDataLength = getMessageHeaderLength();
+      inProgress = true;
     }
+    int writtenLength
+      = peerConnection->sendMessage(msgHeader+getMessageHeaderLength()-leftDataLength,
+				    leftDataLength);
+    if(writtenLength == leftDataLength) {
+      headerSent = true;
+      leftDataLength = blockLength;
+    } else {
+      leftDataLength -= writtenLength;
+    }
+  }
+  if(headerSent) {
     inProgress = false;
-    int pieceLength = peerInteraction->getTorrentMan()->pieceLength;
+    int pieceLength = torrentMan->pieceLength;
     long long int pieceDataOffset =
-      ((long long int)index)*pieceLength+begin+blockLength-leftPieceDataLength;
+      ((long long int)index)*pieceLength+begin+blockLength-leftDataLength;
     int writtenLength =
-      peerConnection->sendPieceData(pieceDataOffset, leftPieceDataLength);
-    if(writtenLength != leftPieceDataLength) {
+      sendPieceData(pieceDataOffset, leftDataLength);
+    peer->addPeerDownload(writtenLength);
+    torrentMan->addUploadLength(writtenLength);
+    torrentMan->addDeltaUploadLength(writtenLength);
+    if(writtenLength != leftDataLength) {
       inProgress = true;
-      leftPieceDataLength -= writtenLength;
     }
+    leftDataLength -= writtenLength;
+  }
+}
+
+int PieceMessage::sendPieceData(long long int offset, int length) const {
+  int BUF_SIZE = 256;
+  char buf[BUF_SIZE];
+  int iteration = length/BUF_SIZE;
+  int writtenLength = 0;
+  TorrentMan* torrentMan = peerInteraction->getTorrentMan();
+  PeerConnection* peerConnection = peerInteraction->getPeerConnection();
+  for(int i = 0; i < iteration; i++) {
+    if(torrentMan->diskAdaptor->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) {
+      throw new DlAbortEx("Failed to read data from disk.");
+    }
+    int ws = peerConnection->sendMessage(buf, BUF_SIZE);
+    writtenLength += ws;
+    if(ws != BUF_SIZE) {
+      //logger->debug("CUID#%d - %d bytes written", cuid, writtenLength);
+      return writtenLength;
+    }
+  }
+
+  int rem = length%BUF_SIZE;
+  if(rem > 0) {
+    if(torrentMan->diskAdaptor->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) {
+      throw new DlAbortEx("Failed to read data from disk.");
+    }
+    int ws = peerConnection->sendMessage(buf, rem);
+    writtenLength += ws;
   }
+  //logger->debug("CUID#%d - %d bytes written", cuid, writtenLength);
+  return writtenLength;
 }
 
 void PieceMessage::check() const {

+ 15 - 2
src/PieceMessage.h

@@ -31,19 +31,25 @@ private:
   int begin;
   char* block;
   int blockLength;
-  int leftPieceDataLength;
+  int leftDataLength;
+  bool headerSent;
+  int pendingCount;
   // for check
   int pieces;
   int pieceLength;
+  
+  char msgHeader[13];
 
   bool checkPieceHash(const Piece& piece);
   void onGotNewPiece(Piece& piece);
   void onGotWrongPiece(Piece& piece);
   void erasePieceOnDisk(const Piece& piece);
+  int sendPieceData(long long int offset, int length) const;
 public:
   PieceMessage():PeerMessage(),
 		 index(0), begin(0), block(NULL), blockLength(0),
-		 leftPieceDataLength(0),
+		 leftDataLength(0), headerSent(false),
+		 pendingCount(0),
 		 pieces(0), pieceLength(0) {}
 
   virtual ~PieceMessage() {
@@ -75,8 +81,15 @@ public:
   }
   int getPieceLength() const { return pieceLength;}
 
+  void incrementPendingCount() { pendingCount++; }
+  bool isPendingCountMax() const { return pendingCount > 2; }
+
+  static PieceMessage* create(const char* data, int dataLength);
+
   virtual int getId() const { return ID; }
   virtual void receivedAction();
+  virtual const char* getMessageHeader();
+  virtual int getMessageHeaderLength();
   virtual void send();
   virtual void check() const;
   virtual string toString() const;

+ 38 - 0
src/PortMessage.cc

@@ -0,0 +1,38 @@
+/* <!-- 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 "PortMessage.h"
+#include "PeerMessageUtil.h"
+#include "DlAbortEx.h"
+
+PortMessage* PortMessage::create(const char* data, int dataLength) {
+  if(dataLength != 3) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "port", dataLength, 3);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "piece", ID);
+  }
+  PortMessage* portMessage = new PortMessage();
+  portMessage->setPort(PeerMessageUtil::getShortIntParam(data, 1));
+  return portMessage;
+}

+ 4 - 2
src/PortMessage.h

@@ -39,14 +39,16 @@ public:
   void setPort(int port) { this->port = port; }
 
   virtual int getId() const { return ID; }
+
+  static PortMessage* create(const char* data, int dataLength);
+
   virtual void receivedAction() {
-    logger->info("no DHT support right now.");
+    logger->info("DHT is not supported yet.");
   }
   virtual void send() {}
   virtual string toString() const {
     return "port";
   }
-
 };
 
 #endif // _D_PORT_MESSAGE_H_

+ 93 - 0
src/RejectMessage.cc

@@ -0,0 +1,93 @@
+/* <!-- 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 "RejectMessage.h"
+#include "PeerInteraction.h"
+#include "PeerMessageUtil.h"
+#include "Util.h"
+#include "DlAbortEx.h"
+
+RejectMessage* RejectMessage::create(const char* data, int dataLength) {
+  if(dataLength != 13) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "reject", dataLength, 13);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "reject", ID);
+  }
+  RejectMessage* rejectMessage = new RejectMessage();
+  rejectMessage->setIndex(PeerMessageUtil::getIntParam(data, 1));
+  rejectMessage->setBegin(PeerMessageUtil::getIntParam(data, 5));
+  rejectMessage->setLength(PeerMessageUtil::getIntParam(data, 9));
+  return rejectMessage;
+}
+
+void RejectMessage::receivedAction() {
+  if(!peer->isFastExtensionEnabled()) {
+    throw new DlAbortEx("%s received while fast extension is disabled",
+			toString().c_str());
+  }
+  // TODO Current implementation does not close a connection even if
+  // a request for this reject message is never sent.
+  RequestSlot slot =
+    peerInteraction->getCorrespondingRequestSlot(index, begin, length);
+  if(RequestSlot::isNull(slot)) {
+    //throw new DlAbortEx("reject recieved, but it is not in the request slots.");
+  } else {
+    peerInteraction->deleteRequestSlot(slot);
+  }
+
+}
+
+const char* RejectMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 13, 4bytes
+     * id --- 16, 1byte
+     * index --- index, 4bytes
+     * begin --- begin, 4bytes
+     * length -- length, 4bytes
+     * total: 17bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, ID);
+    PeerMessageUtil::setIntParam(&msg[5], index);
+    PeerMessageUtil::setIntParam(&msg[9], begin);
+    PeerMessageUtil::setIntParam(&msg[13], length);
+  }
+  return msg;
+}
+
+int RejectMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void RejectMessage::check() const {
+  PeerMessageUtil::checkIndex(index, pieces);
+  PeerMessageUtil::checkBegin(begin, pieceLength);
+  PeerMessageUtil::checkLength(length);
+  PeerMessageUtil::checkRange(begin, length, pieceLength);
+}
+
+string RejectMessage::toString() const {
+  return "reject index="+Util::itos(index)+", begin="+Util::itos(begin)+
+    ", length="+Util::itos(length);
+}

+ 76 - 0
src/RejectMessage.h

@@ -0,0 +1,76 @@
+/* <!-- 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_REJECT_MESSAGE_H_
+#define _D_REJECT_MESSAGE_H_
+
+#include "SimplePeerMessage.h"
+#include "TorrentMan.h"
+
+class RejectMessage : public SimplePeerMessage {
+private:
+  int index;
+  int begin;
+  int length;
+  // for check
+  int pieces;
+  int pieceLength;
+
+  char msg[17];
+public:
+  RejectMessage():SimplePeerMessage(),
+		  index(0), begin(0), length(0),
+		  pieces(0), pieceLength(0) {}
+
+  virtual ~RejectMessage() {}
+
+  enum ID {
+    ID = 16
+  };
+
+  int getIndex() const { return index; }
+  void setIndex(int index) { this->index = index; }
+  int getBegin() const { return begin; }
+  void setBegin(int begin) { this->begin = begin; }
+  int getLength() const { return length; }
+  void setLength(int length) { this->length = length; }
+
+  void setPieces(int pieces) {
+    this->pieces = pieces;
+  }
+  int getPieces() const { return pieces;}
+
+  void setPieceLength(int pieceLength) {
+    this->pieceLength = pieceLength;
+  }
+  int getPieceLength() const { return pieceLength;}
+
+  static RejectMessage* create(const char* data, int dataLength);
+
+  virtual int getId() const { return ID; }
+  virtual void receivedAction();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
+  virtual void check() const;
+  virtual string toString() const;
+};
+
+#endif // _D_REJECT_MESSAGE_H_

+ 43 - 6
src/RequestMessage.cc

@@ -23,20 +23,57 @@
 #include "PeerInteraction.h"
 #include "PeerMessageUtil.h"
 #include "Util.h"
+#include "DlAbortEx.h"
+
+RequestMessage* RequestMessage::create(const char* data, int dataLength) {
+  if(dataLength != 13) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "request", dataLength, 13);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "request", ID);
+  }
+  RequestMessage* requestMessage = new RequestMessage();
+  requestMessage->setIndex(PeerMessageUtil::getIntParam(data, 1));
+  requestMessage->setBegin(PeerMessageUtil::getIntParam(data, 5));
+  requestMessage->setLength(PeerMessageUtil::getIntParam(data, 9));
+  return requestMessage;
+}
 
 void RequestMessage::receivedAction() {
   TorrentMan* torrentMan = peerInteraction->getTorrentMan();
-  if(torrentMan->hasPiece(index)) {
+  if(torrentMan->hasPiece(index) &&
+     (!peer->amChoking ||
+      peer->amChoking && peerInteraction->isInFastSet(index))) {
     peerInteraction->addMessage(peerInteraction->createPieceMessage(index, begin, length));
-    torrentMan->addUploadLength(length);
-    torrentMan->addDeltaUploadLength(length);
+  } else {
+    if(peer->isFastExtensionEnabled()) {
+      peerInteraction->addMessage(peerInteraction->createRejectMessage(index, begin, length));
+    }
   }
 }
 
-void RequestMessage::send() {
-  if(!peer->peerChoking) {
-    peerInteraction->getPeerConnection()->sendRequest(index, begin, length);
+const char* RequestMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 13, 4bytes
+     * id --- 6, 1byte
+     * index --- index, 4bytes
+     * begin --- begin, 4bytes
+     * length --- length, 4bytes
+     * total: 17bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, ID);
+    PeerMessageUtil::setIntParam(&msg[5], index);
+    PeerMessageUtil::setIntParam(&msg[9], begin);
+    PeerMessageUtil::setIntParam(&msg[13], length);
   }
+  return msg;
+}
+
+int RequestMessage::getMessageLength() {
+  return sizeof(msg);
 }
 
 void RequestMessage::check() const {

+ 9 - 4
src/RequestMessage.h

@@ -22,10 +22,10 @@
 #ifndef _D_REQUEST_MESSAGE_H_
 #define _D_REQUEST_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 #include "TorrentMan.h"
 
-class RequestMessage : public PeerMessage {
+class RequestMessage : public SimplePeerMessage {
 private:
   int index;
   int begin;
@@ -34,8 +34,10 @@ private:
   // for check
   int pieces;
   int pieceLength;
+  
+  char msg[17];
 public:
-  RequestMessage():PeerMessage(),
+  RequestMessage():SimplePeerMessage(),
 		   index(0), begin(0), length(0), blockIndex(0),
 		   pieces(0), pieceLength(0) {}
   virtual ~RequestMessage() {}
@@ -63,9 +65,12 @@ public:
   }
   int getPieceLength() const { return pieceLength;}
 
+  static RequestMessage* create(const char* data, int dataLength);
+
   virtual int getId() const { return ID; }
   virtual void receivedAction();
-  virtual void send();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual void check() const;
   virtual string toString() const;
 };

+ 70 - 0
src/SuggestPieceMessage.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 "SuggestPieceMessage.h"
+#include "PeerInteraction.h"
+#include "PeerMessageUtil.h"
+#include "Util.h"
+#include "DlAbortEx.h"
+
+SuggestPieceMessage* SuggestPieceMessage::create(const char* data, int dataLength) {
+  if(dataLength != 5) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "suggest piece", dataLength, 5);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "suggest piece", ID);
+  }
+  SuggestPieceMessage* suggestPieceMessage = new SuggestPieceMessage();
+  suggestPieceMessage->setIndex(PeerMessageUtil::getIntParam(data, 1));
+  return suggestPieceMessage;
+}
+
+void SuggestPieceMessage::receivedAction() {
+  // TODO Current implementation ignores this message.
+}
+
+const char* SuggestPieceMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 5, 4bytes
+     * id --- 13, 1byte
+     * piece index --- index, 4bytes
+     * total: 9bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, ID);
+    PeerMessageUtil::setIntParam(&msg[5], index);
+  }
+  return msg;
+}
+
+int SuggestPieceMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void SuggestPieceMessage::check() const {
+  PeerMessageUtil::checkIndex(index, pieces);
+}
+
+string SuggestPieceMessage::toString() const {
+  return "suggest piece index="+Util::itos(index);
+}

+ 62 - 0
src/SuggestPieceMessage.h

@@ -0,0 +1,62 @@
+/* <!-- 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_SUGGEST_PIECE_MESSAGE_H_
+#define _D_SUGGEST_PIECE_MESSAGE_H_
+
+#include "SimplePeerMessage.h"
+
+class SuggestPieceMessage : public SimplePeerMessage {
+private:
+  int index;
+  // for check
+  int pieces;
+  char msg[9];
+public:
+  SuggestPieceMessage():SimplePeerMessage(), index(0), pieces(0) {}
+
+  virtual ~SuggestPieceMessage() {}
+
+  enum ID {
+    ID = 13
+  };
+
+  void setIndex(int index) {
+    this->index = index;
+  }
+  int getIndex() const { return index; }
+
+  void setPieces(int pieces) {
+    this->pieces = pieces;
+  }
+  int getPieces() const { return pieces;}
+
+  static SuggestPieceMessage* create(const char* data, int dataLength);
+
+  virtual int getId() const { return ID; }
+  virtual void receivedAction();
+  virtual const char* getMessage();
+  virtual int getMessageLength();
+  virtual void check() const;
+  virtual string toString() const;
+};
+
+#endif // _D_SUGGEST_PIECE_MESSAGE_H_

+ 29 - 4
src/TorrentMan.cc

@@ -147,10 +147,30 @@ bool TorrentMan::isEndGame() const {
 
 Piece TorrentMan::getMissingPiece(const Peer* peer) {
   int index = -1;
-  if(isEndGame()) {
-    index = bitfield->getMissingIndex(peer->getBitfield(), peer->getBitfieldLength());
-  } else {
-    index = bitfield->getMissingUnusedIndex(peer->getBitfield(), peer->getBitfieldLength());
+  if(peer->isFastExtensionEnabled() && peer->countFastSet() > 0) {
+    BitfieldMan tempBitfield(pieceLength, totalLength);
+    for(Integers::const_iterator itr = peer->getFastSet().begin();
+	itr != peer->getFastSet().end(); itr++) {
+      if(!hasPiece(*itr) && peer->hasPiece(*itr)) {
+	tempBitfield.setBit(*itr);
+      }
+    }
+    if(isEndGame()) {
+      index = bitfield->getMissingIndex(tempBitfield.getBitfield(),
+					tempBitfield.getBitfieldLength());
+    } else {
+      index = bitfield->getMissingUnusedIndex(tempBitfield.getBitfield(),
+					      tempBitfield.getBitfieldLength());
+    }
+  }
+  if(index == -1) {
+    if(isEndGame()) {
+      index = bitfield->getMissingIndex(peer->getBitfield(),
+					peer->getBitfieldLength());
+    } else {
+      index = bitfield->getMissingUnusedIndex(peer->getBitfield(),
+					      peer->getBitfieldLength());
+    }
   }
   if(index == -1) {
     return Piece::nullPiece;
@@ -248,6 +268,7 @@ void TorrentMan::cancelPiece(const Piece& piece) {
   if(Piece::isNull(piece)) {
     return;
   }
+  updatePiece(piece);
   bitfield->unsetUseBit(piece.getIndex());
   if(!isEndGame()) {
     if(piece.countCompleteBlock() == 0) {
@@ -303,6 +324,10 @@ bool TorrentMan::downloadComplete() const {
   return bitfield->isAllBitSet();
 }
 
+bool TorrentMan::hasAllPieces() const {
+  return bitfield->getTotalLength() == downloadLength;
+}
+
 void TorrentMan::readFileEntry(FileEntries& fileEntries, Directory** pTopDir, const Dictionary* infoDic, const string& defaultName) {
   Data* topName = (Data*)infoDic->get("name");
   if(topName != NULL) {

+ 3 - 0
src/TorrentMan.h

@@ -41,6 +41,7 @@
 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 MAX_PEERS 55
@@ -93,6 +94,7 @@ private:
 public:
   int pieceLength;
   int pieces;
+  // TODO type char* would be better
   string peerId;
   string announce;
   string trackerId;
@@ -133,6 +135,7 @@ public:
   void initBitfield();
   bool isEndGame() const;
   bool downloadComplete() const;
+  bool hasAllPieces() const;
   void setBitfield(unsigned char* bitfield, int len);
   const unsigned char* getBitfield() const {
     return bitfield->getBitfield();

+ 12 - 8
src/TrackerUpdateCommand.cc

@@ -99,17 +99,19 @@ bool TrackerUpdateCommand::execute() {
     Data* trackerId = (Data*)response->get("tracker id");
     if(trackerId != NULL) {
       e->torrentMan->trackerId = trackerId->toString();
-      logger->debug("Tracker ID:%s", e->torrentMan->trackerId.c_str());
+      logger->debug("CUID#%d - Tracker ID:%s",
+		    cuid, e->torrentMan->trackerId.c_str());
     }
     Data* interval = (Data*)response->get("interval");
     if(interval != NULL) {
       e->torrentMan->interval = interval->toInt();
-      logger->debug("interval:%d", e->torrentMan->interval);
+      logger->debug("CUID#%d - Interval:%d", cuid, e->torrentMan->interval);
     }
     Data* minInterval = (Data*)response->get("min interval");
     if(minInterval != NULL) {
       e->torrentMan->minInterval = minInterval->toInt();
-      logger->debug("min interval:%d", e->torrentMan->minInterval);
+      logger->debug("CUID#%d - Min interval:%d",
+		    cuid, e->torrentMan->minInterval);
     }
     if(e->torrentMan->minInterval > e->torrentMan->interval) {
       e->torrentMan->minInterval = e->torrentMan->interval;
@@ -117,12 +119,13 @@ bool TrackerUpdateCommand::execute() {
     Data* complete = (Data*)response->get("complete");
     if(complete != NULL) {
       e->torrentMan->complete = complete->toInt();
-      logger->debug("complete:%d", e->torrentMan->complete);
+      logger->debug("CUID#%d - Complete:%d", cuid, e->torrentMan->complete);
     }
     Data* incomplete = (Data*)response->get("incomplete");
     if(incomplete != NULL) {
       e->torrentMan->incomplete = incomplete->toInt();
-      logger->debug("incomplete:%d", e->torrentMan->incomplete);
+      logger->debug("CUID#%d - Incomplete:%d",
+		    cuid, e->torrentMan->incomplete);
     } 
     Data* peers = (Data*)response->get("peers");
     if(peers != NULL) {
@@ -139,13 +142,14 @@ bool TrackerUpdateCommand::execute() {
 	Peer* peer = new Peer(ipaddr, port, e->torrentMan->pieceLength,
 			      e->torrentMan->getTotalLength());
 	if(e->torrentMan->addPeer(peer)) {
-	  logger->debug("adding peer %s:%d", peer->ipaddr.c_str(), peer->port);
+	  logger->debug("CUID#%d - Adding peer %s:%d",
+			cuid, peer->ipaddr.c_str(), peer->port);
 	} else {
 	  delete peer;
 	}
     }
     } else {
-      logger->info("no peer list received.");
+      logger->info("CUID#%d - No peer list received.", cuid);
     }
     while(e->torrentMan->isPeerAvailable() &&
 	  e->torrentMan->connections < MAX_PEER_UPDATE) {
@@ -154,7 +158,7 @@ bool TrackerUpdateCommand::execute() {
       peer->cuid = newCuid;
       PeerInitiateConnectionCommand* command = new PeerInitiateConnectionCommand(newCuid, peer, e);
       e->commands.push_back(command);
-      logger->debug("adding new command CUID#%d", newCuid);
+      logger->debug("CUID#%d - Adding new command CUID#%d", cuid, newCuid);
     }
     if(e->torrentMan->req->getTrackerEvent() == Request::STARTED) {
       e->torrentMan->req->setTrackerEvent(Request::AUTO);

+ 19 - 8
src/TrackerWatcherCommand.cc

@@ -25,16 +25,27 @@
 #include "Util.h"
 
 TrackerWatcherCommand::TrackerWatcherCommand(int cuid,
-					     TorrentDownloadEngine* e):
-  Command(cuid), e(e) {
+					     TorrentDownloadEngine* e,
+					     int interval):
+  Command(cuid), e(e), interval(interval) {
+  checkPoint.tv_sec = 0;
+  checkPoint.tv_usec = 0;
 }
 
 TrackerWatcherCommand::~TrackerWatcherCommand() {}
 
 bool TrackerWatcherCommand::execute() {
-  if(e->torrentMan->trackers == 0 && e->torrentMan->connections < MIN_PEERS) {
+  struct timeval now;
+  gettimeofday(&now, NULL);
+  
+  if(e->torrentMan->trackers == 0 &&
+     Util::difftvsec(now, checkPoint) >= interval) {
+    checkPoint = now;
     e->torrentMan->req->resetTryCount();
-    
+    int numWant = 50;
+    if(e->torrentMan->connections >= MIN_PEERS) {
+      numWant = 0;
+    }    
     if(e->torrentMan->downloadComplete()) {
       if(e->torrentMan->req->getTrackerEvent() == Request::COMPLETED) {
 	e->torrentMan->req->setTrackerEvent(Request::AFTER_COMPLETED);
@@ -67,7 +78,8 @@ bool TrackerWatcherCommand::execute() {
       "left="+(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength() <= 0
 	       ? "0" : Util::llitos(e->torrentMan->getTotalLength()-e->torrentMan->getDownloadLength()))+"&"+
       "compact=1"+"&"+
-      "key="+e->torrentMan->peerId;
+      "key="+e->torrentMan->peerId+"&"+
+      "numwant="+Util::itos(numWant);
     if(!event.empty()) {
       url += string("&")+"event="+event;
     }
@@ -81,8 +93,7 @@ bool TrackerWatcherCommand::execute() {
     logger->info("CUID#%d - creating new tracker request command #%d", cuid,
 		 command->getCuid());
   }
-  SleepCommand* slpCommand = new SleepCommand(cuid, e, this,
-					      e->torrentMan->minInterval);
-  e->commands.push_back(slpCommand);
+  interval = e->torrentMan->minInterval;
+  e->commands.push_back(this);
   return false;
 }

+ 4 - 1
src/TrackerWatcherCommand.h

@@ -24,14 +24,17 @@
 
 #include "Command.h"
 #include "TorrentDownloadEngine.h"
+#include <sys/time.h>
 
 #define MIN_PEERS 15
 
 class TrackerWatcherCommand : public Command {
 private:
   TorrentDownloadEngine* e;
+  int interval;
+  struct timeval checkPoint;
 public:
-  TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e);
+  TrackerWatcherCommand(int cuid, TorrentDownloadEngine* e, int interval);
   ~TrackerWatcherCommand();
 
   bool execute();

+ 36 - 4
src/UnchokeMessage.cc

@@ -21,16 +21,48 @@
 /* copyright --> */
 #include "UnchokeMessage.h"
 #include "PeerInteraction.h"
+#include "PeerMessageUtil.h"
+#include "DlAbortEx.h"
+
+UnchokeMessage* UnchokeMessage::create(const char* data, int dataLength) {
+  if(dataLength != 1) {
+    throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "unchoke", dataLength, 1);
+  }
+  int id = PeerMessageUtil::getId(data);
+  if(id != ID) {
+    throw new DlAbortEx("invalid ID=%d for %s. It should be %d.",
+			id, "unchoke", ID);
+  }
+  UnchokeMessage* unchokeMessage = new UnchokeMessage();
+  return unchokeMessage;
+}
 
 void UnchokeMessage::receivedAction() {
   peer->peerChoking = false;
 }
 
-void UnchokeMessage::send() {
-  if(peer->amChoking) {
-    peerInteraction->getPeerConnection()->sendUnchoke();
-    peer->amChoking = false;
+bool UnchokeMessage::sendPredicate() const {
+  return peer->amChoking;
+}
+
+const char* UnchokeMessage::getMessage() {
+  if(!inProgress) {
+    /**
+     * len --- 1, 4bytes
+     * id --- 1, 1byte
+     * total: 5bytes
+     */
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, ID);
   }
+  return msg;
+}
+
+int UnchokeMessage::getMessageLength() {
+  return sizeof(msg);
+}
+
+void UnchokeMessage::onSendComplete() {
+  peer->amChoking = false;
 }
 
 string UnchokeMessage::toString() const {

+ 12 - 5
src/UnchokeMessage.h

@@ -22,21 +22,28 @@
 #ifndef _D_UNCHOKE_MESSAGE_H_
 #define _D_UNCHOKE_MESSAGE_H_
 
-#include "PeerMessage.h"
+#include "SimplePeerMessage.h"
 
-class UnchokeMessage : public PeerMessage {
+class UnchokeMessage : public SimplePeerMessage {
+private:
+  char msg[5];
+protected:
+  virtual bool sendPredicate() const;
+  virtual void onSendComplete();
 public:
-  UnchokeMessage():PeerMessage() {}
+  UnchokeMessage():SimplePeerMessage() {}
   virtual ~UnchokeMessage() {}
 
   enum ID {
     ID = 1
   };
 
+  static UnchokeMessage* create(const char* data, int dataLength);
+
   virtual int getId() const { return ID; }
   virtual void receivedAction();
-  virtual void send();
-
+  virtual const char* getMessage();
+  virtual int getMessageLength();
   virtual string toString() const;
 };
 

+ 55 - 0
src/Util.cc

@@ -23,10 +23,17 @@
 #include "DlAbortEx.h"
 #include "File.h"
 #include "message.h"
+#ifdef ENABLE_SHA1DIGEST
+#include "messageDigest.h"
+#endif // ENABLE_SHA1DIGEST
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 string Util::itos(int value, bool comma) {
   string str = llitos(value, comma);
@@ -355,3 +362,51 @@ string Util::getContentDispositionFilename(const string& header) {
   }
   return trim(header.substr(filenamesp, filenameep-filenamesp));
 }
+
+void Util::sha1Sum(unsigned char* digest, const void* data, int dataLength) {
+#ifdef ENABLE_SHA1DIGEST
+  MessageDigestContext ctx;
+  sha1DigestInit(ctx);
+  sha1DigestReset(ctx);
+  sha1DigestUpdate(ctx, data, dataLength);
+  sha1DigestFinal(ctx, digest);
+  sha1DigestFree(ctx);
+#endif // ENABLE_SHA1DIGEST
+}
+
+Integers Util::computeFastSet(string ipaddr, const unsigned char* infoHash,
+			     int pieces, int fastSetSize) {
+  Integers fastSet;
+  struct in_addr saddr;
+  if(inet_aton(ipaddr.c_str(), &saddr) == 0) {
+    abort();
+  }
+  unsigned char tx[24];
+  memcpy(tx, (void*)&saddr.s_addr, 4);
+  if((tx[0] & 0x80) == 0 || (tx[0] & 0x40) == 0) {
+    tx[2] = 0x00;
+    tx[3] = 0x00;
+  } else {
+    tx[3] = 0x00;
+  }
+  memcpy(tx+4, infoHash, 20);
+  unsigned char x[20];
+  sha1Sum(x, tx, 24);
+  while((int)fastSet.size() < fastSetSize) {
+    for(int i = 0; i < 5 && (int)fastSet.size() < fastSetSize; i++) {
+      int j = i*4;
+      unsigned int ny;
+      memcpy(&ny, x+j, 4);
+      unsigned int y = ntohl(ny);
+      int index = y%pieces;
+      if(find(fastSet.begin(), fastSet.end(), index) == fastSet.end()) {
+	fastSet.push_back(index);
+      }
+    }
+    unsigned char temp[20];
+    sha1Sum(temp, x, 20);
+    memcpy(x, temp, sizeof(x));
+  }
+  return fastSet;
+}
+

+ 6 - 0
src/Util.h

@@ -78,6 +78,12 @@ public:
 
   // this function temporarily put here
   static string getContentDispositionFilename(const string& header);
+
+  // digest must be at least 20 bytes long.
+  static void sha1Sum(unsigned char* digest, const void* data, int dataLength);
+
+  static Integers computeFastSet(string ipaddr, const unsigned char* infoHash,
+				int pieces, int fastSetSize);
 };
 
 #endif // _D_UTIL_H_

+ 2 - 1
src/main.cc

@@ -704,7 +704,8 @@ int main(int argc, char* argv[]) {
       te->torrentMan->setPort(port);
       te->commands.push_back(listenCommand);
       te->commands.push_back(new TrackerWatcherCommand(te->torrentMan->getNewCuid(),
-						  te));
+						       te,
+						       te->torrentMan->minInterval));
       te->commands.push_back(new TrackerUpdateCommand(te->torrentMan->getNewCuid(),
 						 te));
       te->commands.push_back(new TorrentAutoSaveCommand(te->torrentMan->getNewCuid(),

+ 59 - 0
test/AllowedFastMessageTest.cc

@@ -0,0 +1,59 @@
+#include "AllowedFastMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class AllowedFastMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(AllowedFastMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(AllowedFastMessageTest);
+
+void AllowedFastMessageTest::testCreate() {
+  char msg[9];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 17);
+  PeerMessageUtil::setIntParam(&msg[5], 12345);
+  AllowedFastMessage* pm = AllowedFastMessage::create(&msg[4], 5);
+  CPPUNIT_ASSERT_EQUAL(17, pm->getId());
+  CPPUNIT_ASSERT_EQUAL(12345, pm->getIndex());
+
+  // case: payload size is wrong
+  try {
+    char msg[10];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 6, 17);
+    AllowedFastMessage::create(&msg[4], 6);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[9];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 18);
+    AllowedFastMessage::create(&msg[4], 5);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void AllowedFastMessageTest::testGetMessage() {
+  AllowedFastMessage msg;
+  msg.setIndex(12345);
+  char data[9];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 5, 17);
+  PeerMessageUtil::setIntParam(&data[5], 12345);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 9) == 0);
+}

+ 63 - 0
test/BitfieldMessageTest.cc

@@ -0,0 +1,63 @@
+#include "BitfieldMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class BitfieldMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(BitfieldMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(BitfieldMessageTest);
+
+void BitfieldMessageTest::testCreate() {
+  char msg[5+2];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 3, 5);
+  unsigned char bitfield[2];
+  memset(bitfield, 0xff, sizeof(bitfield));
+  memcpy(&msg[5], bitfield, sizeof(bitfield));
+  BitfieldMessage* pm = BitfieldMessage::create(&msg[4], 3);
+  CPPUNIT_ASSERT_EQUAL(5, pm->getId());
+  CPPUNIT_ASSERT(memcmp(bitfield, pm->getBitfield(), sizeof(bitfield)) == 0);
+  CPPUNIT_ASSERT_EQUAL(2, pm->getBitfieldLength());
+  // case: payload size is wrong
+  try {
+    char msg[5];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 5);
+    BitfieldMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[5+2];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 3, 6);
+    BitfieldMessage::create(&msg[4], 3);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void BitfieldMessageTest::testGetMessage() {
+  BitfieldMessage msg;
+  unsigned char bitfield[2];
+  memset(bitfield, 0xff, sizeof(bitfield));
+  msg.setBitfield(bitfield, sizeof(bitfield));
+  char data[5+2];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 3, 5);
+  memcpy(&data[5], bitfield, sizeof(bitfield));
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 7) == 0);
+}

+ 67 - 0
test/CancelMessageTest.cc

@@ -0,0 +1,67 @@
+#include "CancelMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class CancelMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(CancelMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(CancelMessageTest);
+
+void CancelMessageTest::testCreate() {
+  char msg[17];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 8);
+  PeerMessageUtil::setIntParam(&msg[5], 12345);
+  PeerMessageUtil::setIntParam(&msg[9], 256);
+  PeerMessageUtil::setIntParam(&msg[13], 1024);
+  CancelMessage* pm = CancelMessage::create(&msg[4], 13);
+  CPPUNIT_ASSERT_EQUAL(8, pm->getId());
+  CPPUNIT_ASSERT_EQUAL(12345, pm->getIndex());
+  CPPUNIT_ASSERT_EQUAL(256, pm->getBegin());
+  CPPUNIT_ASSERT_EQUAL(1024, pm->getLength());
+
+  // case: payload size is wrong
+  try {
+    char msg[18];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 14, 8);
+    CancelMessage::create(&msg[4], 14);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[17];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 9);
+    CancelMessage::create(&msg[4], 13);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void CancelMessageTest::testGetMessage() {
+  CancelMessage msg;
+  msg.setIndex(12345);
+  msg.setBegin(256);
+  msg.setLength(1024);
+  char data[17];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 13, 8);
+  PeerMessageUtil::setIntParam(&data[5], 12345);
+  PeerMessageUtil::setIntParam(&data[9], 256);
+  PeerMessageUtil::setIntParam(&data[13], 1024);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 17) == 0);
+}

+ 55 - 0
test/ChokeMessageTest.cc

@@ -0,0 +1,55 @@
+#include "ChokeMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class ChokeMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(ChokeMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ChokeMessageTest);
+
+void ChokeMessageTest::testCreate() {
+  char msg[5];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 0);
+  PeerMessage* pm = ChokeMessage::create(&msg[4], 1);
+  CPPUNIT_ASSERT_EQUAL(0, pm->getId());
+
+  // case: payload size is wrong
+  try {
+    char msg[6];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 0);
+    ChokeMessage::create(&msg[4], 2);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[5];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 1);
+    ChokeMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void ChokeMessageTest::testGetMessage() {
+  ChokeMessage msg;
+  char data[5];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 0);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0);
+}

+ 55 - 0
test/HaveAllMessageTest.cc

@@ -0,0 +1,55 @@
+#include "HaveAllMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class HaveAllMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(HaveAllMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(HaveAllMessageTest);
+
+void HaveAllMessageTest::testCreate() {
+  char msg[5];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 14);
+  PeerMessage* pm = HaveAllMessage::create(&msg[4], 1);
+  CPPUNIT_ASSERT_EQUAL(14, pm->getId());
+
+  // case: payload size is wrong
+  try {
+    char msg[6];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 14);
+    HaveAllMessage::create(&msg[4], 2);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[5];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 15);
+    HaveAllMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void HaveAllMessageTest::testGetMessage() {
+  HaveAllMessage msg;
+  char data[5];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 14);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0);
+}

+ 59 - 0
test/HaveMessageTest.cc

@@ -0,0 +1,59 @@
+#include "HaveMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class HaveMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(HaveMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(HaveMessageTest);
+
+void HaveMessageTest::testCreate() {
+  char msg[9];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 4);
+  PeerMessageUtil::setIntParam(&msg[5], 12345);
+  HaveMessage* pm = HaveMessage::create(&msg[4], 5);
+  CPPUNIT_ASSERT_EQUAL(4, pm->getId());
+  CPPUNIT_ASSERT_EQUAL(12345, pm->getIndex());
+
+  // case: payload size is wrong
+  try {
+    char msg[10];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 6, 4);
+    HaveMessage::create(&msg[4], 2);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[9];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 5);
+    HaveMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void HaveMessageTest::testGetMessage() {
+  HaveMessage msg;
+  msg.setIndex(12345);
+  char data[9];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 5, 4);
+  PeerMessageUtil::setIntParam(&data[5], 12345);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 9) == 0);
+}

+ 55 - 0
test/HaveNoneMessageTest.cc

@@ -0,0 +1,55 @@
+#include "HaveNoneMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class HaveNoneMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(HaveNoneMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(HaveNoneMessageTest);
+
+void HaveNoneMessageTest::testCreate() {
+  char msg[5];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 15);
+  PeerMessage* pm = HaveNoneMessage::create(&msg[4], 1);
+  CPPUNIT_ASSERT_EQUAL(15, pm->getId());
+
+  // case: payload size is wrong
+  try {
+    char msg[6];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 15);
+    HaveNoneMessage::create(&msg[4], 2);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[5];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 16);
+    HaveNoneMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void HaveNoneMessageTest::testGetMessage() {
+  HaveNoneMessage msg;
+  char data[5];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 15);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0);
+}

+ 55 - 0
test/InterestedMessageTest.cc

@@ -0,0 +1,55 @@
+#include "InterestedMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class InterestedMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(InterestedMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(InterestedMessageTest);
+
+void InterestedMessageTest::testCreate() {
+  char msg[5];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 2);
+  PeerMessage* pm = InterestedMessage::create(&msg[4], 1);
+  CPPUNIT_ASSERT_EQUAL(2, pm->getId());
+
+  // case: payload size is wrong
+  try {
+    char msg[6];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 2);
+    InterestedMessage::create(&msg[4], 2);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[5];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 3);
+    InterestedMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void InterestedMessageTest::testGetMessage() {
+  InterestedMessage msg;
+  char data[5];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 2);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0);
+}

+ 15 - 1
test/Makefile.am

@@ -17,7 +17,21 @@ aria2c_SOURCES = AllTest.cc\
 	PeerMessageUtilTest.cc\
 	BitfieldManTest.cc\
 	DefaultDiskWriterTest.cc\
-	MultiDiskWriterTest.cc
+	MultiDiskWriterTest.cc\
+	ChokeMessageTest.cc\
+	UnchokeMessageTest.cc\
+	HaveAllMessageTest.cc\
+	HaveNoneMessageTest.cc\
+	InterestedMessageTest.cc\
+	NotInterestedMessageTest.cc\
+	HaveMessageTest.cc\
+	BitfieldMessageTest.cc\
+	RequestMessageTest.cc\
+	CancelMessageTest.cc\
+	PieceMessageTest.cc\
+	RejectMessageTest.cc\
+	AllowedFastMessageTest.cc\
+	SuggestPieceMessageTest.cc
 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
 

+ 37 - 2
test/Makefile.in

@@ -64,7 +64,14 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \
 	MetaFileUtilTest.$(OBJEXT) ShaVisitorTest.$(OBJEXT) \
 	TorrentManTest.$(OBJEXT) PeerMessageUtilTest.$(OBJEXT) \
 	BitfieldManTest.$(OBJEXT) DefaultDiskWriterTest.$(OBJEXT) \
-	MultiDiskWriterTest.$(OBJEXT)
+	MultiDiskWriterTest.$(OBJEXT) ChokeMessageTest.$(OBJEXT) \
+	UnchokeMessageTest.$(OBJEXT) HaveAllMessageTest.$(OBJEXT) \
+	HaveNoneMessageTest.$(OBJEXT) InterestedMessageTest.$(OBJEXT) \
+	NotInterestedMessageTest.$(OBJEXT) HaveMessageTest.$(OBJEXT) \
+	BitfieldMessageTest.$(OBJEXT) RequestMessageTest.$(OBJEXT) \
+	CancelMessageTest.$(OBJEXT) PieceMessageTest.$(OBJEXT) \
+	RejectMessageTest.$(OBJEXT) AllowedFastMessageTest.$(OBJEXT) \
+	SuggestPieceMessageTest.$(OBJEXT)
 aria2c_OBJECTS = $(am_aria2c_OBJECTS)
 am__DEPENDENCIES_1 =
 aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
@@ -222,7 +229,21 @@ aria2c_SOURCES = AllTest.cc\
 	PeerMessageUtilTest.cc\
 	BitfieldManTest.cc\
 	DefaultDiskWriterTest.cc\
-	MultiDiskWriterTest.cc
+	MultiDiskWriterTest.cc\
+	ChokeMessageTest.cc\
+	UnchokeMessageTest.cc\
+	HaveAllMessageTest.cc\
+	HaveNoneMessageTest.cc\
+	InterestedMessageTest.cc\
+	NotInterestedMessageTest.cc\
+	HaveMessageTest.cc\
+	BitfieldMessageTest.cc\
+	RequestMessageTest.cc\
+	CancelMessageTest.cc\
+	PieceMessageTest.cc\
+	RejectMessageTest.cc\
+	AllowedFastMessageTest.cc\
+	SuggestPieceMessageTest.cc
 
 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
 #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
@@ -284,22 +305,36 @@ distclean-compile:
 	-rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AllTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AllowedFastMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64Test.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldManTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMessageTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CancelMessageTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChokeMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncodingTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBoxTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DataTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriterTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DictionaryTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveAllMessageTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveMessageTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveNoneMessageTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/InterestedMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ListTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetaFileUtilTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MultiDiskWriterTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/NotInterestedMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/OptionTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PeerMessageUtilTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/PieceMessageTest.Po@am__quote@
+@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)/ShaVisitorTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TorrentManTest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnchokeMessageTest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@
 
 .cc.o:

+ 8 - 8
test/MetaFileUtilTest.cc

@@ -37,41 +37,41 @@ void MetaFileUtilTest::testBdecoding() {
   try {
     char* str = "5:abcd";
     MetaEntry* entry = MetaFileUtil::bdecoding(str, strlen(str));
-    CPPUNIT_FAIL("DlAbortEx exception must be throwed.");
+    CPPUNIT_FAIL("DlAbortEx exception must be threw.");
   } catch(DlAbortEx* ex) {
     delete ex;
   } catch(...) {
-    CPPUNIT_FAIL("DlAbortEx exception must be throwed.");
+    CPPUNIT_FAIL("DlAbortEx exception must be threw.");
   }
 
   try {
     char* str = "i1234";
     MetaEntry* entry = MetaFileUtil::bdecoding(str, strlen(str));
-    CPPUNIT_FAIL("DlAbortEx exception must be throwed.");
+    CPPUNIT_FAIL("DlAbortEx exception must be threw.");
   } catch(DlAbortEx* ex) {
     delete ex;
   } catch(...) {
-    CPPUNIT_FAIL("DlAbortEx exception must be throwed.");
+    CPPUNIT_FAIL("DlAbortEx exception must be threw.");
   }
 
   try {
     char* str = "5abcd";
     MetaEntry* entry = MetaFileUtil::bdecoding(str, strlen(str));
-    CPPUNIT_FAIL("DlAbortEx exception must be throwed.");
+    CPPUNIT_FAIL("DlAbortEx exception must be threw.");
   } catch(DlAbortEx* ex) {
     delete ex;
   } catch(...) {
-    CPPUNIT_FAIL("DlAbortEx exception must be throwed.");
+    CPPUNIT_FAIL("DlAbortEx exception must be threw.");
   }
 
   try {
     char* str = "d";
     MetaEntry* entry = MetaFileUtil::bdecoding(str, strlen(str));
-    CPPUNIT_FAIL("DlAbortEx exception must be throwed.");
+    CPPUNIT_FAIL("DlAbortEx exception must be threw.");
   } catch(DlAbortEx* ex) {
     delete ex;
   } catch(...) {
-    CPPUNIT_FAIL("DlAbortEx exception must be throwed.");
+    CPPUNIT_FAIL("DlAbortEx exception must be threw.");
   }
 }
     

+ 55 - 0
test/NotInterestedMessageTest.cc

@@ -0,0 +1,55 @@
+#include "NotInterestedMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class NotInterestedMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(NotInterestedMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(NotInterestedMessageTest);
+
+void NotInterestedMessageTest::testCreate() {
+  char msg[5];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 3);
+  PeerMessage* pm = NotInterestedMessage::create(&msg[4], 1);
+  CPPUNIT_ASSERT_EQUAL(3, pm->getId());
+
+  // case: payload size is wrong
+  try {
+    char msg[6];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 3);
+    NotInterestedMessage::create(&msg[4], 2);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[5];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 4);
+    NotInterestedMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void NotInterestedMessageTest::testGetMessage() {
+  NotInterestedMessage msg;
+  char data[5];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 3);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0);
+}

+ 7 - 208
test/PeerMessageUtilTest.cc

@@ -8,16 +8,6 @@ using namespace std;
 class PeerMessageUtilTest:public CppUnit::TestFixture {
 
   CPPUNIT_TEST_SUITE(PeerMessageUtilTest);
-  CPPUNIT_TEST(testCreatePeerMessageChoke);
-  CPPUNIT_TEST(testCreatePeerMessageUnchoke);
-  CPPUNIT_TEST(testCreatePeerMessageInterested);
-  CPPUNIT_TEST(testCreatePeerMessageNotInterested);
-  CPPUNIT_TEST(testCreatePeerMessageHave);
-  CPPUNIT_TEST(testCreatePeerMessageBitfield);
-  CPPUNIT_TEST(testCreatePeerMessageRequest);
-  CPPUNIT_TEST(testCreatePeerMessagePiece);
-  CPPUNIT_TEST(testCreatePeerMessageCancel);
-  CPPUNIT_TEST(testCreatePortMessage);
   CPPUNIT_TEST(testCheckIntegrityHave);
   CPPUNIT_TEST(testCheckIntegrityBitfield);
   CPPUNIT_TEST(testCheckIntegrityRequest);
@@ -28,7 +18,6 @@ public:
   void setUp() {
   }
 
-  void testCreatePeerMessageChoke();
   void testCreatePeerMessageUnchoke();
   void testCreatePeerMessageInterested();
   void testCreatePeerMessageNotInterested();
@@ -62,191 +51,11 @@ void createNLengthMessage(char* msg, int msgLen, int payloadLen, int id) {
   msg[4] = (char)id;
 }
 
-void PeerMessageUtilTest::testCreatePeerMessageChoke() {
-  char msg[5];
-  createNLengthMessage(msg, sizeof(msg), 1, 0);
-  PeerMessage* pm = PeerMessageUtil::createChokeMessage(&msg[4], 1);
-  CPPUNIT_ASSERT_EQUAL((int)ChokeMessage::ID, pm->getId());
-
-  try {
-    char msg[6];
-    createNLengthMessage(msg, sizeof(msg), 2, 0);
-    PeerMessageUtil::createChokeMessage(&msg[4], 2);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {
-  }
-}
-
-void PeerMessageUtilTest::testCreatePeerMessageUnchoke() {
-  char msg[5];
-  createNLengthMessage(msg, sizeof(msg), 1, 1);
-  PeerMessage* pm = PeerMessageUtil::createUnchokeMessage(&msg[4], 1);
-  CPPUNIT_ASSERT_EQUAL((int)UnchokeMessage::ID, pm->getId());
-
-  try {
-    char msg[6];
-    createNLengthMessage(msg, sizeof(msg), 2, 1);
-    PeerMessageUtil::createUnchokeMessage(&msg[4], 2);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {
-  }
-}
-  
-void PeerMessageUtilTest::testCreatePeerMessageInterested() {
-  char msg[5];
-  createNLengthMessage(msg, sizeof(msg), 1, 2);
-  PeerMessage* pm = PeerMessageUtil::createInterestedMessage(&msg[4], 1);
-  CPPUNIT_ASSERT_EQUAL((int)InterestedMessage::ID, pm->getId());
-
-  try {
-    char msg[6];
-    createNLengthMessage(msg, sizeof(msg), 2, 2);
-    PeerMessageUtil::createInterestedMessage(&msg[4], 2);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {
-  }
-}
-
-void PeerMessageUtilTest::testCreatePeerMessageNotInterested() {
-  char msg[5];
-  createNLengthMessage(msg, sizeof(msg), 1, 3);
-  PeerMessage* pm = PeerMessageUtil::createNotInterestedMessage(&msg[4], 1);
-  CPPUNIT_ASSERT_EQUAL((int)NotInterestedMessage::ID, pm->getId());
-
-  try {
-    char msg[6];
-    createNLengthMessage(msg, sizeof(msg), 2, 3);
-    PeerMessageUtil::createNotInterestedMessage(&msg[4], 2);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {
-  }
-}
-
-void PeerMessageUtilTest::testCreatePeerMessageHave() {
-  char msg[9];
-  createNLengthMessage(msg, sizeof(msg), 5, 4);
-  setIntParam(&msg[5], 100);
-  HaveMessage* pm = PeerMessageUtil::createHaveMessage(&msg[4], 5);
-  CPPUNIT_ASSERT_EQUAL((int)HaveMessage::ID, pm->getId());
-  CPPUNIT_ASSERT_EQUAL(100, pm->getIndex());
-
-  try {
-    char msg[8];
-    createNLengthMessage(msg, sizeof(msg), 4, 4);
-    PeerMessageUtil::createHaveMessage(&msg[4], 4);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {}
-  
-  try {
-    char msg[5];
-    createNLengthMessage(msg, sizeof(msg), 1, 4);
-    PeerMessageUtil::createHaveMessage(&msg[4], 1);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {}
-}
-
-void PeerMessageUtilTest::testCreatePeerMessageBitfield() {
-  int msgLen = 5+2;
-  char* msg = new char[msgLen];
-  createNLengthMessage(msg, msgLen, 3, 5);
-  BitfieldMessage* pm = PeerMessageUtil::createBitfieldMessage(&msg[4], 3);
-  CPPUNIT_ASSERT_EQUAL((int)BitfieldMessage::ID, pm->getId());
-  CPPUNIT_ASSERT_EQUAL((unsigned char)0, pm->getBitfield()[0]);
-  CPPUNIT_ASSERT_EQUAL((unsigned char)0, pm->getBitfield()[1]);
-  CPPUNIT_ASSERT_EQUAL(2, pm->getBitfieldLength());
-
-  try {
-    int msgLen = 5;
-    char* msg = new char[msgLen];
-    createNLengthMessage(msg, msgLen, 1, 5);
-    PeerMessageUtil::createBitfieldMessage(&msg[4], 1);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {}
-}
-
-void PeerMessageUtilTest::testCreatePeerMessageRequest() {
-  char msg[17];
-  createNLengthMessage(msg, sizeof(msg), 13, 6);
-  setIntParam(&msg[5], 1);
-  setIntParam(&msg[9], 16*1024);
-  setIntParam(&msg[13], 16*1024-1);
-  RequestMessage* pm = PeerMessageUtil::createRequestMessage(&msg[4], 13);
-  CPPUNIT_ASSERT_EQUAL((int)RequestMessage::ID, pm->getId());
-  CPPUNIT_ASSERT_EQUAL(1, pm->getIndex());
-  CPPUNIT_ASSERT_EQUAL(16*1024, pm->getBegin());
-  CPPUNIT_ASSERT_EQUAL(16*1024-1, pm->getLength());
-
-  try {
-    char msg[13];
-    createNLengthMessage(msg, sizeof(msg), 9, 6);
-    setIntParam(&msg[5], 1);
-    setIntParam(&msg[9], 16*1024);
-    PeerMessageUtil::createRequestMessage(&msg[4], 9);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {}
-}
-
-void PeerMessageUtilTest::testCreatePeerMessagePiece() {
-  char msg[23];
-  createNLengthMessage(msg, sizeof(msg), 9+10, 7);
-  setIntParam(&msg[5], 1);
-  setIntParam(&msg[9], 16*1024);
-  PieceMessage* pm = PeerMessageUtil::createPieceMessage(&msg[4], 19);
-  CPPUNIT_ASSERT_EQUAL((int)PieceMessage::ID, pm->getId());
-  CPPUNIT_ASSERT_EQUAL(1, pm->getIndex());
-  CPPUNIT_ASSERT_EQUAL(16*1024, pm->getBegin());
-  CPPUNIT_ASSERT_EQUAL(10, pm->getBlockLength());
-  for(int i = 0; i < 10; i++) {
-    CPPUNIT_ASSERT_EQUAL((char)0, pm->getBlock()[i]);
-  }
-
-  try {
-    char msg[13];
-    createNLengthMessage(msg, sizeof(msg), 9, 7);
-    setIntParam(&msg[5], 1);
-    setIntParam(&msg[9], 16*1024);
-    PeerMessageUtil::createPieceMessage(&msg[4], 9);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {}
-} 
-
-void PeerMessageUtilTest::testCreatePeerMessageCancel() {
-  char msg[17];
-  createNLengthMessage(msg, sizeof(msg), 13, 8);
-  setIntParam(&msg[5], 1);
-  setIntParam(&msg[9], 16*1024);
-  setIntParam(&msg[13], 16*1024-1);
-  CancelMessage* pm = PeerMessageUtil::createCancelMessage(&msg[4], 13);
-  CPPUNIT_ASSERT_EQUAL((int)CancelMessage::ID, pm->getId());
-  CPPUNIT_ASSERT_EQUAL(1, pm->getIndex());
-  CPPUNIT_ASSERT_EQUAL(16*1024, pm->getBegin());
-  CPPUNIT_ASSERT_EQUAL(16*1024-1, pm->getLength());
-
-  try {
-    char msg[13];
-    createNLengthMessage(msg, sizeof(msg), 9, 8);
-    setIntParam(&msg[5], 1);
-    setIntParam(&msg[9], 16*1024);
-    PeerMessageUtil::createCancelMessage(&msg[4], 9);
-    CPPUNIT_FAIL("exception must be throwed.");
-  } catch(...) {}
-}
-
-void PeerMessageUtilTest::testCreatePortMessage() {
-  char msg[7];
-  createNLengthMessage(msg, sizeof(msg), 3, 9);
-  setShortIntParam(&msg[5], 65535);
-  PortMessage* pm = PeerMessageUtil::createPortMessage(&msg[4], 3);
-  CPPUNIT_ASSERT_EQUAL((int)PortMessage::ID, pm->getId());
-  CPPUNIT_ASSERT_EQUAL(65535, pm->getPort());
-}
-
 void PeerMessageUtilTest::testCheckIntegrityHave() {
   HaveMessage* pm = new HaveMessage();
   pm->setIndex(119);
   pm->setPieces(120);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
   } catch(Exception* ex) {
     cerr << ex->getMsg() << endl;
@@ -255,9 +64,8 @@ void PeerMessageUtilTest::testCheckIntegrityHave() {
  
   pm->setIndex(120);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
-    CPPUNIT_FAIL("exception must be throwed.");
+    CPPUNIT_FAIL("exception must be threw.");
   } catch(...) {}
 }
 
@@ -270,7 +78,6 @@ void PeerMessageUtilTest::testCheckIntegrityBitfield() {
   pm->setBitfield(bitfield, bitfieldLength);
   pm->setPieces(120);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
   } catch(Exception* ex) {
     cerr << ex->getMsg() << endl;
@@ -282,9 +89,8 @@ void PeerMessageUtilTest::testCheckIntegrityBitfield() {
   memset(bitfield, 0xff, bitfieldLength);
   pm->setBitfield(bitfield, bitfieldLength);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
-    CPPUNIT_FAIL("exception must be throwed.");
+    CPPUNIT_FAIL("exception must be threw.");
   } catch(Exception* ex) {
   }
   delete [] bitfield;
@@ -293,9 +99,8 @@ void PeerMessageUtilTest::testCheckIntegrityBitfield() {
   memset(bitfield, 0xff, bitfieldLength);
   pm->setBitfield(bitfield, bitfieldLength);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
-    CPPUNIT_FAIL("exception must be throwed.");
+    CPPUNIT_FAIL("exception must be threw.");
   } catch(Exception* ex) {
   }
   delete [] bitfield;
@@ -306,7 +111,6 @@ void PeerMessageUtilTest::testCheckIntegrityBitfield() {
   pm->setBitfield(bitfield, bitfieldLength);
   pm->setPieces(119);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 119, 256*1024*120);
     pm->check();
   } catch(Exception* ex) {
     cerr << ex->getMsg() << endl;
@@ -318,9 +122,8 @@ void PeerMessageUtilTest::testCheckIntegrityBitfield() {
   memset(bitfield, 0xff, bitfieldLength);
   pm->setBitfield(bitfield, bitfieldLength);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 119, 256*1024*120);
     pm->check();
-    CPPUNIT_FAIL("exception must be throwed.");
+    CPPUNIT_FAIL("exception must be threw.");
   } catch(Exception* ex) {
   }  
   delete [] bitfield;
@@ -334,7 +137,6 @@ void PeerMessageUtilTest::testCheckIntegrityRequest() {
   pm->setPieces(120);
   pm->setPieceLength(256*1024);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
   } catch(Exception* ex) {
     cerr << ex->getMsg() << endl;
@@ -344,24 +146,21 @@ void PeerMessageUtilTest::testCheckIntegrityRequest() {
   pm->setBegin(256*1024);
   pm->setLength(16*1024);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
-    CPPUNIT_FAIL("exception must be throwed.");
+    CPPUNIT_FAIL("exception must be threw.");
   } catch(Exception* ex) {}
 
   pm->setBegin(0);
   pm->setLength(256*1024);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
-    CPPUNIT_FAIL("exception must be throwed.");
+    CPPUNIT_FAIL("exception must be threw.");
   } catch(Exception* ex) {}
 
   pm->setBegin(0);
   pm->setLength(5);
   try {
-    //PeerMessageUtil::checkIntegrity(pm, 256*1024, 120, 256*1024*120);
     pm->check();
-    CPPUNIT_FAIL("exception must be throwed.");
+    CPPUNIT_FAIL("exception must be threw.");
   } catch(Exception* ex) {}
 }

+ 69 - 0
test/PieceMessageTest.cc

@@ -0,0 +1,69 @@
+#include "PieceMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class PieceMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(PieceMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessageHeader);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessageHeader();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(PieceMessageTest);
+
+void PieceMessageTest::testCreate() {
+  char msg[13+2];
+  char data[2];
+  memset(data, 0xff, sizeof(data));
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 11, 7);
+  PeerMessageUtil::setIntParam(&msg[5], 12345);
+  PeerMessageUtil::setIntParam(&msg[9], 256);
+  memcpy(&msg[13], data, sizeof(data));
+  PieceMessage* pm = PieceMessage::create(&msg[4], 11);
+  CPPUNIT_ASSERT_EQUAL(7, pm->getId());
+  CPPUNIT_ASSERT_EQUAL(12345, pm->getIndex());
+  CPPUNIT_ASSERT_EQUAL(256, pm->getBegin());
+  CPPUNIT_ASSERT(memcmp(data, pm->getBlock(), sizeof(data)) == 0);
+  CPPUNIT_ASSERT_EQUAL(2, pm->getBlockLength());
+
+  // case: payload size is wrong
+  try {
+    char msg[13];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 9, 7);
+    PieceMessage::create(&msg[4], 9);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[13+2];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 11, 8);
+    PieceMessage::create(&msg[4], 11);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void PieceMessageTest::testGetMessageHeader() {
+  PieceMessage msg;
+  msg.setIndex(12345);
+  msg.setBegin(256);
+  msg.setBlockLength(1024);
+  char data[13];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 9+1024, 7);
+  PeerMessageUtil::setIntParam(&data[5], 12345);
+  PeerMessageUtil::setIntParam(&data[9], 256);
+  CPPUNIT_ASSERT(memcmp(msg.getMessageHeader(), data, 13) == 0);
+}

+ 67 - 0
test/RejectMessageTest.cc

@@ -0,0 +1,67 @@
+#include "RejectMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class RejectMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(RejectMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(RejectMessageTest);
+
+void RejectMessageTest::testCreate() {
+  char msg[17];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 16);
+  PeerMessageUtil::setIntParam(&msg[5], 12345);
+  PeerMessageUtil::setIntParam(&msg[9], 256);
+  PeerMessageUtil::setIntParam(&msg[13], 1024);
+  RejectMessage* pm = RejectMessage::create(&msg[4], 13);
+  CPPUNIT_ASSERT_EQUAL(16, pm->getId());
+  CPPUNIT_ASSERT_EQUAL(12345, pm->getIndex());
+  CPPUNIT_ASSERT_EQUAL(256, pm->getBegin());
+  CPPUNIT_ASSERT_EQUAL(1024, pm->getLength());
+
+  // case: payload size is wrong
+  try {
+    char msg[18];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 14, 16);
+    RejectMessage::create(&msg[4], 14);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[17];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 17);
+    RejectMessage::create(&msg[4], 13);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void RejectMessageTest::testGetMessage() {
+  RejectMessage msg;
+  msg.setIndex(12345);
+  msg.setBegin(256);
+  msg.setLength(1024);
+  char data[17];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 13, 16);
+  PeerMessageUtil::setIntParam(&data[5], 12345);
+  PeerMessageUtil::setIntParam(&data[9], 256);
+  PeerMessageUtil::setIntParam(&data[13], 1024);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 17) == 0);
+}

+ 67 - 0
test/RequestMessageTest.cc

@@ -0,0 +1,67 @@
+#include "RequestMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class RequestMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(RequestMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(RequestMessageTest);
+
+void RequestMessageTest::testCreate() {
+  char msg[17];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 6);
+  PeerMessageUtil::setIntParam(&msg[5], 12345);
+  PeerMessageUtil::setIntParam(&msg[9], 256);
+  PeerMessageUtil::setIntParam(&msg[13], 1024);
+  RequestMessage* pm = RequestMessage::create(&msg[4], 13);
+  CPPUNIT_ASSERT_EQUAL(6, pm->getId());
+  CPPUNIT_ASSERT_EQUAL(12345, pm->getIndex());
+  CPPUNIT_ASSERT_EQUAL(256, pm->getBegin());
+  CPPUNIT_ASSERT_EQUAL(1024, pm->getLength());
+
+  // case: payload size is wrong
+  try {
+    char msg[18];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 14, 6);
+    RequestMessage::create(&msg[4], 14);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[17];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 7);
+    RequestMessage::create(&msg[4], 13);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void RequestMessageTest::testGetMessage() {
+  RequestMessage msg;
+  msg.setIndex(12345);
+  msg.setBegin(256);
+  msg.setLength(1024);
+  char data[17];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 13, 6);
+  PeerMessageUtil::setIntParam(&data[5], 12345);
+  PeerMessageUtil::setIntParam(&data[9], 256);
+  PeerMessageUtil::setIntParam(&data[13], 1024);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 17) == 0);
+}

+ 59 - 0
test/SuggestPieceMessageTest.cc

@@ -0,0 +1,59 @@
+#include "SuggestPieceMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class SuggestPieceMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(SuggestPieceMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(SuggestPieceMessageTest);
+
+void SuggestPieceMessageTest::testCreate() {
+  char msg[9];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 13);
+  PeerMessageUtil::setIntParam(&msg[5], 12345);
+  SuggestPieceMessage* pm = SuggestPieceMessage::create(&msg[4], 5);
+  CPPUNIT_ASSERT_EQUAL(13, pm->getId());
+  CPPUNIT_ASSERT_EQUAL(12345, pm->getIndex());
+
+  // case: payload size is wrong
+  try {
+    char msg[10];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 6, 13);
+    SuggestPieceMessage::create(&msg[4], 2);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[9];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 14);
+    SuggestPieceMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void SuggestPieceMessageTest::testGetMessage() {
+  SuggestPieceMessage msg;
+  msg.setIndex(12345);
+  char data[9];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 5, 13);
+  PeerMessageUtil::setIntParam(&data[5], 12345);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 9) == 0);
+}

+ 55 - 0
test/UnchokeMessageTest.cc

@@ -0,0 +1,55 @@
+#include "UnchokeMessage.h"
+#include "PeerMessageUtil.h"
+#include <cppunit/extensions/HelperMacros.h>
+
+using namespace std;
+
+class UnchokeMessageTest:public CppUnit::TestFixture {
+
+  CPPUNIT_TEST_SUITE(UnchokeMessageTest);
+  CPPUNIT_TEST(testCreate);
+  CPPUNIT_TEST(testGetMessage);
+  CPPUNIT_TEST_SUITE_END();
+private:
+
+public:
+  void setUp() {
+  }
+
+  void testCreate();
+  void testGetMessage();
+};
+
+
+CPPUNIT_TEST_SUITE_REGISTRATION(UnchokeMessageTest);
+
+void UnchokeMessageTest::testCreate() {
+  char msg[5];
+  PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 1);
+  PeerMessage* pm = UnchokeMessage::create(&msg[4], 1);
+  CPPUNIT_ASSERT_EQUAL(1, pm->getId());
+
+  // case: payload size is wrong
+  try {
+    char msg[6];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 1);
+    UnchokeMessage::create(&msg[4], 2);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+  // case: id is wrong
+  try {
+    char msg[5];
+    PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 2);
+    UnchokeMessage::create(&msg[4], 1);
+    CPPUNIT_FAIL("exception must be threw.");
+  } catch(...) {
+  }
+}
+
+void UnchokeMessageTest::testGetMessage() {
+  UnchokeMessage msg;
+  char data[5];
+  PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 1);
+  CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0);
+}

+ 33 - 0
test/UtilTest.cc

@@ -15,6 +15,7 @@ class UtilTest:public CppUnit::TestFixture {
   CPPUNIT_TEST(testStartsWith);
   // may be moved to other helper class in the future.
   CPPUNIT_TEST(testGetContentDispositionFilename);
+  CPPUNIT_TEST(testComputeFastSet);
   CPPUNIT_TEST_SUITE_END();
 private:
 
@@ -28,6 +29,7 @@ public:
   void testEndsWith();
   void testReplace();
   void testStartsWith();
+  void testComputeFastSet();
   // may be moved to other helper class in the future.
   void testGetContentDispositionFilename();
 };
@@ -175,3 +177,34 @@ void UtilTest::testGetContentDispositionFilename() {
   string h4 = "attachment;";
   CPPUNIT_ASSERT_EQUAL(string(""), Util::getContentDispositionFilename(h4));
 }
+
+class Printer {
+public:
+  template<class T>
+  void operator()(T t) {
+    cerr << t << ", ";
+  }
+};
+
+void UtilTest::testComputeFastSet() {
+  string ipaddr = "192.168.0.1";
+  unsigned char infoHash[20];
+  memset(infoHash, 0, sizeof(infoHash));
+  infoHash[0] = 0xff;
+  
+  int pieces = 1000;
+  int fastSetSize = 10;
+
+  Integers fastSet = Util::computeFastSet(ipaddr, infoHash, pieces, fastSetSize);
+  //for_each(fastSet.begin(), fastSet.end(), Printer());
+  //cerr << endl;
+  int ans1[] = { 686, 459, 278, 200, 404, 834, 64, 203, 760, 950 };
+  Integers ansSet1(&ans1[0], &ans1[10]);
+  CPPUNIT_ASSERT(equal(fastSet.begin(), fastSet.end(), ansSet1.begin()));
+
+  ipaddr = "10.0.0.1";
+  fastSet = Util::computeFastSet(ipaddr, infoHash, pieces, fastSetSize);
+  int ans2[] = { 568, 188, 466, 452, 550, 662, 109, 226, 398, 11 };
+  Integers ansSet2(&ans2[0], &ans2[10]);
+  CPPUNIT_ASSERT(equal(fastSet.begin(), fastSet.end(), ansSet2.begin()));
+}