diff --git a/ChangeLog b/ChangeLog index d5fda956..aa278336 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2009-07-07 Tatsuhiro Tsujikawa + + Disconnect seeder if client is also in seed state. + * src/BtBitfieldMessage.cc + * src/BtHaveAllMessage.cc + * src/BtHaveMessage.cc + * src/message.h + * test/BtBitfieldMessageTest.cc + * test/BtHaveAllMessageTest.cc + * test/BtHaveMessageTest.cc + * test/MockPieceStorage.h + 2009-07-06 Tatsuhiro Tsujikawa Keep CreateRequestCommand in queue when no segment is available so diff --git a/src/BtBitfieldMessage.cc b/src/BtBitfieldMessage.cc index f81015ae..9ee9a8f4 100644 --- a/src/BtBitfieldMessage.cc +++ b/src/BtBitfieldMessage.cc @@ -73,6 +73,9 @@ BtBitfieldMessage::create(const unsigned char* data, size_t dataLength) void BtBitfieldMessage::doReceivedAction() { pieceStorage->updatePieceStats(bitfield, bitfieldLength, peer->getBitfield()); peer->setBitfield(bitfield, bitfieldLength); + if(peer->isSeeder() && pieceStorage->downloadFinished()) { + throw DL_ABORT_EX(MSG_GOOD_BYE_SEEDER); + } } const unsigned char* BtBitfieldMessage::getMessage() { diff --git a/src/BtHaveAllMessage.cc b/src/BtHaveAllMessage.cc index ccf04d5f..b99abbf5 100644 --- a/src/BtHaveAllMessage.cc +++ b/src/BtHaveAllMessage.cc @@ -37,6 +37,7 @@ #include "Peer.h" #include "StringFormat.h" #include "PieceStorage.h" +#include "message.h" namespace aria2 { @@ -59,6 +60,9 @@ void BtHaveAllMessage::doReceivedAction() peer->getBitfieldLength()); peer->setAllBitfield(); pieceStorage->addPieceStats(peer->getBitfield(), peer->getBitfieldLength()); + if(peer->isSeeder() && pieceStorage->downloadFinished()) { + throw DL_ABORT_EX(MSG_GOOD_BYE_SEEDER); + } } } // namespace aria2 diff --git a/src/BtHaveMessage.cc b/src/BtHaveMessage.cc index 6641f6a0..35317665 100644 --- a/src/BtHaveMessage.cc +++ b/src/BtHaveMessage.cc @@ -35,6 +35,8 @@ #include "BtHaveMessage.h" #include "Peer.h" #include "PieceStorage.h" +#include "message.h" +#include "DlAbortEx.h" namespace aria2 { @@ -50,6 +52,9 @@ void BtHaveMessage::doReceivedAction() { peer->updateBitfield(getIndex(), 1); pieceStorage->addPieceStats(getIndex()); + if(peer->isSeeder() && pieceStorage->downloadFinished()) { + throw DL_ABORT_EX(MSG_GOOD_BYE_SEEDER); + } } } // namespace aria2 diff --git a/src/message.h b/src/message.h index ca3d6b1b..64465764 100644 --- a/src/message.h +++ b/src/message.h @@ -172,6 +172,7 @@ " file. Skipping.") #define MSG_GID_NOT_PROVIDED "GID is not provided." #define MSG_CANNOT_PARSE_XML_RPC_REQUEST "Failed to parse xml-rpc request." +#define MSG_GOOD_BYE_SEEDER "Client is in seed state: Good Bye Seeder;)" #define EX_TIME_OUT _("Timeout.") #define EX_INVALID_CHUNK_SIZE _("Invalid chunk size.") diff --git a/test/BtBitfieldMessageTest.cc b/test/BtBitfieldMessageTest.cc index f8200366..4264c086 100644 --- a/test/BtBitfieldMessageTest.cc +++ b/test/BtBitfieldMessageTest.cc @@ -1,10 +1,14 @@ #include "BtBitfieldMessage.h" + +#include + +#include + #include "PeerMessageUtil.h" #include "Util.h" #include "Peer.h" #include "MockPieceStorage.h" -#include -#include +#include "DlAbortEx.h" namespace aria2 { @@ -14,6 +18,7 @@ class BtBitfieldMessageTest:public CppUnit::TestFixture { CPPUNIT_TEST(testCreate); CPPUNIT_TEST(testGetMessage); CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testDoReceivedAction_goodByeSeeder); CPPUNIT_TEST(testToString); CPPUNIT_TEST_SUITE_END(); private: @@ -25,6 +30,7 @@ public: void testCreate(); void testGetMessage(); void testDoReceivedAction(); + void testDoReceivedAction_goodByeSeeder(); void testToString(); }; @@ -87,6 +93,41 @@ void BtBitfieldMessageTest::testDoReceivedAction() { peer->getBitfieldLength())); } +void BtBitfieldMessageTest::testDoReceivedAction_goodByeSeeder() +{ + SharedHandle peer(new Peer("ip", 6000)); + peer->allocateSessionResource(1024, 1024); + BtBitfieldMessage msg; + msg.setPeer(peer); + SharedHandle pieceStorage(new MockPieceStorage()); + msg.setPieceStorage(pieceStorage); + unsigned char bitfield[] = { 0x00 }; + msg.setBitfield(bitfield, sizeof(bitfield)); + + // peer is not seeder and client have not completed download + msg.doReceivedAction(); + + pieceStorage->setDownloadFinished(true); + + // client completed download, but peer is not seeder + msg.doReceivedAction(); + + pieceStorage->setDownloadFinished(false); + bitfield[0] = 0x80; + msg.setBitfield(bitfield, sizeof(bitfield)); + + // peer is seeder, but client have not completed download + msg.doReceivedAction(); + + pieceStorage->setDownloadFinished(true); + try { + msg.doReceivedAction(); + CPPUNIT_FAIL("exception must be thrown."); + } catch(DlAbortEx& e) { + // success + } +} + void BtBitfieldMessageTest::testToString() { BtBitfieldMessage msg; unsigned char bitfield[] = { 0xff, 0xff }; diff --git a/test/BtHaveAllMessageTest.cc b/test/BtHaveAllMessageTest.cc index 63b4c1c8..d7a6e1e4 100644 --- a/test/BtHaveAllMessageTest.cc +++ b/test/BtHaveAllMessageTest.cc @@ -1,9 +1,13 @@ #include "BtHaveAllMessage.h" + +#include + +#include + #include "PeerMessageUtil.h" #include "Peer.h" #include "MockPieceStorage.h" -#include -#include +#include "DlAbortEx.h" namespace aria2 { @@ -13,6 +17,7 @@ class BtHaveAllMessageTest:public CppUnit::TestFixture { CPPUNIT_TEST(testCreate); CPPUNIT_TEST(testGetMessage); CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testDoReceivedAction_goodByeSeeder); CPPUNIT_TEST_SUITE_END(); private: @@ -23,6 +28,7 @@ public: void testCreate(); void testGetMessage(); void testDoReceivedAction(); + void testDoReceivedAction_goodByeSeeder(); }; @@ -80,4 +86,24 @@ void BtHaveAllMessageTest::testDoReceivedAction() { } catch(...) {} } +void BtHaveAllMessageTest::testDoReceivedAction_goodByeSeeder() +{ + BtHaveAllMessage msg; + SharedHandle peer(new Peer("ip", 6000)); + peer->allocateSessionResource(1024, 1024); + peer->setFastExtensionEnabled(true); + msg.setPeer(peer); + SharedHandle pieceStorage(new MockPieceStorage()); + msg.setPieceStorage(pieceStorage); + + pieceStorage->setDownloadFinished(true); + + try { + msg.doReceivedAction(); + CPPUNIT_FAIL("exception must be thrown."); + } catch(DlAbortEx& e) { + // success + } +} + } // namespace aria2 diff --git a/test/BtHaveMessageTest.cc b/test/BtHaveMessageTest.cc index 53fc192a..c4435d15 100644 --- a/test/BtHaveMessageTest.cc +++ b/test/BtHaveMessageTest.cc @@ -1,9 +1,13 @@ #include "BtHaveMessage.h" + +#include + +#include + #include "PeerMessageUtil.h" #include "Peer.h" #include "MockPieceStorage.h" -#include -#include +#include "DlAbortEx.h" namespace aria2 { @@ -13,6 +17,7 @@ class BtHaveMessageTest:public CppUnit::TestFixture { CPPUNIT_TEST(testCreate); CPPUNIT_TEST(testGetMessage); CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testDoReceivedAction_goodByeSeeder); CPPUNIT_TEST(testToString); CPPUNIT_TEST_SUITE_END(); private: @@ -24,6 +29,7 @@ public: void testCreate(); void testGetMessage(); void testDoReceivedAction(); + void testDoReceivedAction_goodByeSeeder(); void testToString(); }; @@ -80,6 +86,39 @@ void BtHaveMessageTest::testDoReceivedAction() { CPPUNIT_ASSERT(peer->hasPiece(msg.getIndex())); } + +void BtHaveMessageTest::testDoReceivedAction_goodByeSeeder() +{ + SharedHandle peer(new Peer("ip", 6000)); + peer->allocateSessionResource(1024, 2*1024); + BtHaveMessage msg; + msg.setIndex(0); + msg.setPeer(peer); + SharedHandle pieceStorage(new MockPieceStorage()); + msg.setPieceStorage(pieceStorage); + + // peer is not seeder and client have not completed download + msg.doReceivedAction(); + + pieceStorage->setDownloadFinished(true); + + // client have completed download but, peer is not seeder + msg.doReceivedAction(); + + msg.setIndex(1); + pieceStorage->setDownloadFinished(false); + + // peer is a seeder but client have not completed download + msg.doReceivedAction(); + + pieceStorage->setDownloadFinished(true); + try { + msg.doReceivedAction(); + CPPUNIT_FAIL("exception must be thrown."); + } catch(DlAbortEx& e) { + // success + } +} void BtHaveMessageTest::testToString() { BtHaveMessage msg; diff --git a/test/MockPieceStorage.h b/test/MockPieceStorage.h index f64e93f7..acf0a685 100644 --- a/test/MockPieceStorage.h +++ b/test/MockPieceStorage.h @@ -23,6 +23,7 @@ private: SharedHandle diskAdaptor; std::deque pieceLengthList; std::deque > inFlightPieces; + bool _downloadFinished; bool _allDownloadFinished; public: MockPieceStorage():totalLength(0), @@ -32,6 +33,7 @@ public: bitfieldMan(0), selectiveDownloadingMode(false), endGame(false), + _downloadFinished(false), _allDownloadFinished(false) {} virtual ~MockPieceStorage() {} @@ -133,7 +135,12 @@ public: virtual void clearFileFilter() {} virtual bool downloadFinished() { - return false; + return _downloadFinished; + } + + void setDownloadFinished(bool f) + { + _downloadFinished = f; } virtual bool allDownloadFinished() {