diff --git a/ChangeLog b/ChangeLog index a42e525d..d02b8df3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,61 @@ +2006-12-24 Tatsuhiro Tsujikawa + + Rewritten a portion of bittorrent implementation: + + * src/BtMessageValidator.h: New class. + * src/BtBitfieldMessageValidator.h: New class. + * src/BtHandshakeMessageValidator.h: New class. + * src/BtRequestMessageValidator.h: New class. + * src/BtSuggestPieceMessageValidator.h: New class. + * src/BtAllowedFastMessageValidator.h: New class. + * src/BtRejectMessageValidator.h: New class. + * src/BtCancelMessageValidator.h: New class. + * src/BtPieceMessageValidator.h: New class. + * src/BtHaveMessageValidator.h: New class. + * src/BtEventListener.h: New class. + * src/AbstractBtEventListener.h: New class. + * src/BtEvent.h: New class. + * src/BtChokingEvent.h: New class. + * src/BtChokedEvent.h: New class. + * src/BtCancelSendingPieceEvent.h: New class. + * src/BtAbortOutstandingRequestEvent.h: New class. + * src/Randomizer.h: New class. + * src/SimpleRandomizer.h: New class. + * src/BtMessage.h: New class. + * src/AbstractBtMessage.h: New class. + * src/SimpleBtMessage.h: New class. + * src/BtHaveMessage.h: New class. + * src/BtInterestedMessage.h: New class. + * src/BtAllowedFastMessage.h: New class. + * src/BtUnchokeMessage.h: New class. + * src/BtCancelMessage.h: New class. + * src/BtNotInterestedMessage.h: New class. + * src/BtChokeMessage.h: New class. + * src/BtHaveNoneMessage.h: New class. + * src/BtHandshakeMessage.h: New class. + * src/BtSuggestPieceMessage.h: New class. + * src/BtHaveMessage.h: New class. + * src/BtPieceMessage.h: New class. + * src/BtHaveAllMessage.h: New class. + * src/BtKeepAliveMessage.h: New class. + * src/BtPortMessage.h: New class. + * src/BtRejectMessage.h: New class. + * src/BtBitfieldMessage.h: New class. + * src/BtRequestMessage.h: New class. + * src/DefaultBtRequestFactory.h: New class. + * src/DefaultBtMessageReceiver.h: New class. + * src/BtInteractive.h: New class. + * src/BtMessageDispatcher.h: New class. + * src/DefaultBtMessageDispatcher.h: New class. + * src/DefaultBtInteractive.h: New class. + * src/BitfieldManFactory.h: New class. + * src/HandleRegistry.h: New class. + * src/BtMessageFactory.h: New class. + * src/BtMessageReceiver.h: New class. + * src/DefaultBtMessageFactory.h: New class. + * src/PeerObject.h: New class. + * src/BtRequestFactory.h: New class. + 2006-12-01 Tatsuhiro Tsujikawa To know root cause of exception: diff --git a/TODO b/TODO index 969d1acc..710712ca 100644 --- a/TODO +++ b/TODO @@ -20,4 +20,13 @@ * Add Turkish translation. * Add the message like "you can resume the transfer by invoking aria2 again" when the download stops. * Add --bt-timeout command line option. -* Fix DefaultBtProgressInfoFile.cc: save(), load() \ No newline at end of file +* Fix DefaultBtProgressInfoFile.cc: save(), load() +* Add a feature that if any existing file is detected, then +do not start downloading and print some useful message to the user. +* Fix Segfaults in BitfieldMan.cc:71 +https://sourceforge.net/tracker/index.php?func=detail&aid=1606060&group_id=159897&atid=813673 +* Prevent the file to be fragmented. Use PreAllocationDiskWriter +https://sourceforge.net/tracker/index.php?func=detail&aid=1611886&group_id=159897&atid=813673 +* Add #include to DefaultBtContext.h +* int32_t +* remove blockIndex diff --git a/src/AbstractBtEventListener.h b/src/AbstractBtEventListener.h new file mode 100644 index 00000000..4b16f4f6 --- /dev/null +++ b/src/AbstractBtEventListener.h @@ -0,0 +1,55 @@ +/* */ +#ifndef _D_ABSTRACT_BT_EVENT_LISTENER_H_ +#define _D_ABSTRACT_BT_EVENT_LISTENER_H_ + +#include "BtEventListener.h" + +class AbstractBtEventListener : public BtEventListener { +public: + virtual ~AbstractBtEventListener() {} + + virtual bool canHandle(const BtEventHandle& event) = 0; + + virtual void handleEventInternal(const BtEventHandle& event) = 0; + + virtual void handleEvent(const BtEventHandle& event) { + if(canHandle(event)) { + handleEventInternal(event); + } + } +}; + +#endif // _D_ABSTRACT_BT_EVENT_LISTENER_H_ diff --git a/src/AbstractBtMessage.h b/src/AbstractBtMessage.h new file mode 100644 index 00000000..07902eb8 --- /dev/null +++ b/src/AbstractBtMessage.h @@ -0,0 +1,167 @@ +/* */ +#ifndef _D_ABSTRACT_BT_MESSAGE_H_ +#define _D_ABSTRACT_BT_MESSAGE_H_ + +#include "BtMessage.h" +#include "Peer.h" +#include "Piece.h" +#include "LogFactory.h" +#include "Logger.h" +#include "BtEvent.h" +#include "BtEventListener.h" +#include "BtContext.h" +#include "BtRegistry.h" + +class AbstractBtMessage : public BtMessage { +protected: + bool sendingInProgress; + bool invalidate; + bool uploading; + int32_t id; + int32_t cuid; + + BtContextHandle btContext; + + PieceStorageHandle pieceStorage; + + PeerHandle peer; + + BtMessageValidatorHandle validator; + BtEventListeners listeners; + const Logger* logger; +public: + AbstractBtMessage():sendingInProgress(false), + invalidate(false), + uploading(false), + id(0), + cuid(0), + btContext(0), + pieceStorage(0), + peer(0), + validator(0), + logger(LogFactory::getInstance()) + + {} + + virtual bool isSendingInProgress() { + return sendingInProgress; + } + + void setSendingInProgress(bool sendingInProgress) { + this->sendingInProgress = sendingInProgress; + } + + virtual bool isInvalidate() { + return invalidate; + } + + void setInvalidate(bool invalidate) { + this->invalidate = invalidate; + } + + virtual bool isUploading() { + return uploading; + } + + void setUploading(bool uploading) { + this->uploading = uploading; + } + + virtual int32_t getId() { + return id; + } + + int32_t getCuid() const { + return cuid; + } + + void setCuid(int32_t cuid) { + this->cuid = cuid; + } + + PeerHandle getPeer() const { + return peer; + } + + void setPeer(const PeerHandle& peer) { + this->peer = peer; + } + + virtual void doReceivedAction() {} + + virtual bool validate(Errors& errors) { + if(validator.get()) { + return validator->validate(errors); + } else { + return true; + } + } + + virtual void onQueued() {} + + virtual void handleEvent(const BtEventHandle& event) { + for(BtEventListeners::iterator itr = listeners.begin(); + itr != listeners.end(); ++itr) { + (*itr)->handleEvent(event); + } + } + + void addEventListener(const BtEventListenerHandle& listener) { + listeners.push_back(listener); + } + + void setBtMessageValidator(const BtMessageValidatorHandle& validator) { + this->validator = validator; + } + + BtMessageValidatorHandle getBtMessageValidator() const { + return validator; + } + + void setBtContext(const BtContextHandle& btContext) { + this->btContext = btContext; + this->pieceStorage = PIECE_STORAGE(btContext); + } + + BtContextHandle getBtContext() const { + return btContext; + } + +}; + +typedef SharedHandle AbstractBtMessageHandle; + +#endif // _D_ABSTRACT_BT_MESSAGE_H_ diff --git a/src/BitfieldMan.cc b/src/BitfieldMan.cc index 736bc5b8..b29f4db7 100644 --- a/src/BitfieldMan.cc +++ b/src/BitfieldMan.cc @@ -38,7 +38,7 @@ BitfieldMan::BitfieldMan(int blockLength, long long int totalLength) :blockLength(blockLength), totalLength(totalLength), filterBitfield(0), - filterEnabled(false) { + filterEnabled(false), randomizer(0) { if(blockLength > 0 && totalLength > 0) { blocks = totalLength/blockLength+(totalLength%blockLength ? 1 : 0); bitfieldLength = blocks/8+(blocks%8 ? 1 : 0); @@ -49,7 +49,7 @@ BitfieldMan::BitfieldMan(int blockLength, long long int totalLength) } } -BitfieldMan::BitfieldMan(const BitfieldMan& bitfieldMan) { +BitfieldMan::BitfieldMan(const BitfieldMan& bitfieldMan):randomizer(0) { blockLength = bitfieldMan.blockLength; totalLength = bitfieldMan.totalLength; blocks = bitfieldMan.blocks; @@ -65,6 +65,7 @@ BitfieldMan::BitfieldMan(const BitfieldMan& bitfieldMan) { } else { filterBitfield = 0; } + this->randomizer = bitfieldMan.randomizer; } BitfieldMan::~BitfieldMan() { @@ -106,7 +107,9 @@ int BitfieldMan::getMissingIndexRandomly(const unsigned char* bitfield, int bitfieldLength) const { - int byte = (int)(((double)bitfieldLength)*random()/(RAND_MAX+1.0)); + int byte = (int)(((double)bitfieldLength)* + randomizer->getRandomNumber()/ + (randomizer->getMaxRandomNumber()+1.0)); unsigned char lastMask = 0; int lastByteLength = totalLength%(blockLength*8); diff --git a/src/BitfieldMan.h b/src/BitfieldMan.h index 53758601..43fb81a1 100644 --- a/src/BitfieldMan.h +++ b/src/BitfieldMan.h @@ -36,6 +36,7 @@ #define _D_BITFIELD_MAN_H_ #include "common.h" +#include "Randomizer.h" #include typedef deque BlockIndexes; @@ -50,6 +51,8 @@ private: int bitfieldLength; int blocks; bool filterEnabled; + RandomizerHandle randomizer; + int countSetBit(const unsigned char* bitfield, int len) const; int getNthBitIndex(const unsigned char bit, int nth) const; int getMissingIndexRandomly(const unsigned char* bitfield, int len) const; @@ -176,6 +179,8 @@ public: */ int countBlock() const; + int getMaxIndex() const { return blocks-1; } + void setBitfield(const unsigned char* bitfield, int bitfieldLength); void clearAllBit(); @@ -202,6 +207,14 @@ public: * affected by filter */ long long int getFilteredCompletedLength() const; + + void setRandomizer(const RandomizerHandle& randomizer) { + this->randomizer = randomizer; + } + + RandomizerHandle getRandomizer() const { + return randomizer; + } }; #endif // _D_BITFIELD_MAN_H_ diff --git a/src/BitfieldManFactory.cc b/src/BitfieldManFactory.cc new file mode 100644 index 00000000..2ee68222 --- /dev/null +++ b/src/BitfieldManFactory.cc @@ -0,0 +1,40 @@ +/* */ +#include "BitfieldManFactory.h" +#include "SimpleRandomizer.h" + +RandomizerHandle BitfieldManFactory::defaultRandomizer = SimpleRandomizer::getInstance(); + +BitfieldManFactory::BitfieldManFactory():randomizer(defaultRandomizer) {} diff --git a/src/BitfieldManFactory.h b/src/BitfieldManFactory.h new file mode 100644 index 00000000..2e1af096 --- /dev/null +++ b/src/BitfieldManFactory.h @@ -0,0 +1,85 @@ +/* */ +#ifndef _D_BITFIELD_MAN_FACTORY_H_ +#define _D_BITFIELD_MAN_FACTORY_H_ + +#include "common.h" +#include "Randomizer.h" +#include "BitfieldMan.h" + +class BitfieldManFactory; + +typedef SharedHandle BitfieldManFactoryHandle; + +class BitfieldManFactory { +private: + static RandomizerHandle defaultRandomizer; + RandomizerHandle randomizer; + + BitfieldManFactory(); +public: + ~BitfieldManFactory() {} + + static BitfieldManFactoryHandle getNewFactory() { + BitfieldManFactoryHandle factory = + BitfieldManFactoryHandle(new BitfieldManFactory()); + factory->setRandomizer(defaultRandomizer); + return factory; + } + + BitfieldMan* createBitfieldMan(int blockLength, long long int totalLength) { + BitfieldMan* bitfieldMan = new BitfieldMan(blockLength, totalLength); + bitfieldMan->setRandomizer(randomizer); + return bitfieldMan; + } + + static void setDefaultRandomizer(const RandomizerHandle& randomizer) { + defaultRandomizer = randomizer; + } + + static RandomizerHandle getDefaultRandomizer() { + return defaultRandomizer; + } + + void setRandomizer(const RandomizerHandle& randomizer) { + this->randomizer = randomizer; + } + + RandomizerHandle getRandomizer() const { + return randomizer; + } +}; + +#endif // _D_BITFIELD_MAN_FACTORY_H_ diff --git a/src/BtAbortOutstandingRequestEvent.h b/src/BtAbortOutstandingRequestEvent.h new file mode 100644 index 00000000..6d334bae --- /dev/null +++ b/src/BtAbortOutstandingRequestEvent.h @@ -0,0 +1,57 @@ +/* */ +#ifndef _D_BT_ABORT_OUTSTANDING_REQUEST_EVENT_H_ +#define _D_BT_ABORT_OUTSTANDING_REQUEST_EVENT_H_ + +#include "BtEvent.h" + +class BtAbortOutstandingRequestEvent : public BtEvent { +private: + PieceHandle piece; +public: + BtAbortOutstandingRequestEvent(const PieceHandle& piece):piece(piece) {} + + PieceHandle getPiece() const { + return piece; + } + + void setPiece(const PieceHandle& piece) { + this->piece = piece; + } +}; + +typedef SharedHandle BtAbortOutstandingRequestEventHandle; + +#endif // _D_BT_ABORT_OUTSTANDING_REQUEST_EVENT_H_ diff --git a/src/BtAllowedFastMessage.cc b/src/BtAllowedFastMessage.cc new file mode 100644 index 00000000..672a499c --- /dev/null +++ b/src/BtAllowedFastMessage.cc @@ -0,0 +1,89 @@ +/* */ +#include "BtAllowedFastMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include "DlAbortEx.h" + +BtAllowedFastMessageHandle BtAllowedFastMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 5) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "allowed fast", dataLength, 5); + } + uint32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "allowed fast", ID); + } + BtAllowedFastMessageHandle message = new BtAllowedFastMessage(); + message->setIndex(PeerMessageUtil::getIntParam(data, 1)); + return message; +} + +void BtAllowedFastMessage::doReceivedAction() { + if(!peer->isFastExtensionEnabled()) { + throw new DlAbortEx("%s received while fast extension is disabled", + toString().c_str()); + } + peer->addPeerAllowedIndex(index); +} + +uint32_t BtAllowedFastMessage::MESSAGE_LENGTH = 9; + +const char* BtAllowedFastMessage::getMessage() { + if(!msg) { + /** + * len --- 5, 4bytes + * id --- 17, 1byte + * piece index --- index, 4bytes + * total: 9bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 5, ID); + PeerMessageUtil::setIntParam(&msg[5], index); + } + return msg; +} + +uint32_t BtAllowedFastMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +void BtAllowedFastMessage::onSendComplete() { + peer->addAmAllowedIndex(index); +} + +string BtAllowedFastMessage::toString() const { + return "allowed fast index="+Util::uitos(index); +} diff --git a/src/BtAllowedFastMessage.h b/src/BtAllowedFastMessage.h new file mode 100644 index 00000000..8ace1619 --- /dev/null +++ b/src/BtAllowedFastMessage.h @@ -0,0 +1,85 @@ +/* */ +#ifndef _D_BT_ALLOWED_FAST_MESSAGE_H_ +#define _D_BT_ALLOWED_FAST_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtAllowedFastMessage; + +typedef SharedHandle BtAllowedFastMessageHandle; + +class BtAllowedFastMessage : public SimpleBtMessage { +private: + uint32_t index; + char* msg; + + static uint32_t MESSAGE_LENGTH; +public: + BtAllowedFastMessage(uint32_t index = 0) + :SimpleBtMessage(), + index(index), + msg(0) {} + + virtual ~BtAllowedFastMessage() { + delete [] msg; + } + + enum ID_t { + ID = 17 + }; + + void setIndex(uint32_t index) { + this->index = index; + } + uint32_t getIndex() const { return index; } + + static BtAllowedFastMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; + + virtual void onSendComplete(); + +}; + +#endif // _D_BT_ALLOWED_FAST_MESSAGE_H_ diff --git a/src/BtAllowedFastMessageValidator.h b/src/BtAllowedFastMessageValidator.h new file mode 100644 index 00000000..b6668239 --- /dev/null +++ b/src/BtAllowedFastMessageValidator.h @@ -0,0 +1,60 @@ +/* */ +#ifndef _D_BT_ALLOWED_FAST_MESSAGE_VALIDATOR_H_ +#define _D_BT_ALLOWED_FAST_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtAllowedFastMessage.h" + +class BtAllowedFastMessageValidator : public BtMessageValidator { +private: + const BtAllowedFastMessage* message; + uint32_t numPiece; +public: + BtAllowedFastMessageValidator(const BtAllowedFastMessage* message, + uint32_t numPiece): + message(message), + numPiece(numPiece) {} + + virtual bool validate(Errors& error) { + // TODO + PeerMessageUtil::checkIndex(message->getIndex(), numPiece); + return true; + } +}; + +typedef SharedHandle BtAllowedFastMessageValidatorHandle; + +#endif // _D_BT_ALLOWED_FAST_MESSAGE_VALIDATOR_H_ diff --git a/src/BtAnnounce.h b/src/BtAnnounce.h index 3b9e735f..4288a6e4 100644 --- a/src/BtAnnounce.h +++ b/src/BtAnnounce.h @@ -99,11 +99,6 @@ public: * Shuffles the URLs in each announce tier. */ virtual void shuffleAnnounce() = 0; - - /** - * Returns the peer id of the client. - */ - virtual string getPeerId() = 0; }; typedef SharedHandle BtAnnounceHandle; diff --git a/src/BtBitfieldMessage.cc b/src/BtBitfieldMessage.cc new file mode 100644 index 00000000..35d0894d --- /dev/null +++ b/src/BtBitfieldMessage.cc @@ -0,0 +1,95 @@ +/* */ +#include "BtBitfieldMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include "DlAbortEx.h" + +void BtBitfieldMessage::setBitfield(const unsigned char* bitfield, uint32_t bitfieldLength) { + if(this->bitfield == bitfield) { + return; + } + delete [] this->bitfield; + + this->bitfieldLength = bitfieldLength; + this->bitfield = new unsigned char[this->bitfieldLength]; + memcpy(this->bitfield, bitfield, this->bitfieldLength); +} + +BtBitfieldMessageHandle +BtBitfieldMessage::create(const unsigned char* data, uint32_t dataLength) +{ + if(dataLength <= 1) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be greater than %d", "bitfield", dataLength, 1); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "bitfield", ID); + } + BtBitfieldMessageHandle message = new BtBitfieldMessage(); + message->setBitfield((unsigned char*)data+1, dataLength-1); + return message; +} + +void BtBitfieldMessage::doReceivedAction() { + peer->setBitfield(bitfield, bitfieldLength); +} + +const char* BtBitfieldMessage::getMessage() { + if(!msg) { + /** + * 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; +} + +uint32_t BtBitfieldMessage::getMessageLength() { + getMessage(); + return msgLength; +} + +string BtBitfieldMessage::toString() const { + return "bitfield "+Util::toHex(bitfield, bitfieldLength); +} diff --git a/src/BtBitfieldMessage.h b/src/BtBitfieldMessage.h new file mode 100644 index 00000000..15bc13aa --- /dev/null +++ b/src/BtBitfieldMessage.h @@ -0,0 +1,98 @@ +/* */ +#ifndef _D_BT_BITFIELD_MESSAGE_H_ +#define _D_BT_BITFIELD_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtBitfieldMessage; + +typedef SharedHandle BtBitfieldMessageHandle; + +class BtBitfieldMessage : public SimpleBtMessage { +private: + unsigned char* bitfield; + uint32_t bitfieldLength; + char* msg; + int msgLength; + + void init() { + bitfield = 0; + bitfieldLength = 0; + msg = 0; + msgLength = 0; + } +public: + BtBitfieldMessage():SimpleBtMessage() + { + init(); + } + + BtBitfieldMessage(const unsigned char* bitfield, + uint32_t bitfieldLength):SimpleBtMessage() + { + init(); + setBitfield(bitfield, bitfieldLength); + } + + virtual ~BtBitfieldMessage() { + delete [] bitfield; + delete [] msg; + } + + enum ID_t { + ID = 5 + }; + + void setBitfield(const unsigned char* bitfield, uint32_t bitfieldLength); + + const unsigned char* getBitfield() const { return bitfield; } + + uint32_t getBitfieldLength() const { return bitfieldLength; } + + static BtBitfieldMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; +}; + +#endif // _D_BT_BITFIELD_MESSAGE_H_ diff --git a/src/BtBitfieldMessageValidator.h b/src/BtBitfieldMessageValidator.h new file mode 100644 index 00000000..d7a8ddb0 --- /dev/null +++ b/src/BtBitfieldMessageValidator.h @@ -0,0 +1,61 @@ +/* */ +#ifndef _D_BT_BITFIELD_MESSAGE_VALIDATOR_H_ +#define _D_BT_BITFIELD_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtBitfieldMessage.h" + +class BtBitfieldMessageValidator : public BtMessageValidator { +private: + const BtBitfieldMessage* message; + int numPiece; +public: + BtBitfieldMessageValidator(const BtBitfieldMessage* message, + int numPiece): + message(message), + numPiece(numPiece) {} + + virtual bool validate(Errors& error) { + // TODO + PeerMessageUtil::checkBitfield(message->getBitfield(), + message->getBitfieldLength(), + numPiece); + return true; + } +}; + +typedef SharedHandle BtBitfieldMessageValidatorHandle; +#endif // _D_BT_BITFIELD_MESSAGE_VALIDATOR_H_ diff --git a/src/BtCancelMessage.cc b/src/BtCancelMessage.cc new file mode 100644 index 00000000..ec2f2447 --- /dev/null +++ b/src/BtCancelMessage.cc @@ -0,0 +1,88 @@ +/* */ +#include "BtCancelMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include "DlAbortEx.h" + +BtCancelMessageHandle BtCancelMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 13) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "cancel", dataLength, 13); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "cancel", ID); + } + BtCancelMessageHandle message = new BtCancelMessage(); + message->setIndex(PeerMessageUtil::getIntParam(data, 1)); + message->setBegin(PeerMessageUtil::getIntParam(data, 5)); + message->setLength(PeerMessageUtil::getIntParam(data, 9)); + return message; +} + +void BtCancelMessage::doReceivedAction() { + BT_MESSAGE_DISPATCHER(btContext, peer)->doCancelSendingPieceAction(index, begin, length); +} + +uint32_t BtCancelMessage::MESSAGE_LENGTH = 17; + +const char* BtCancelMessage::getMessage() { + if(!msg) { + /** + * len --- 13, 4bytes + * id --- 8, 1byte + * index --- index, 4bytes + * begin --- begin, 4bytes + * length -- length, 4bytes + * total: 17bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 13, ID); + PeerMessageUtil::setIntParam(&msg[5], index); + PeerMessageUtil::setIntParam(&msg[9], begin); + PeerMessageUtil::setIntParam(&msg[13], length); + } + return msg; +} + +uint32_t BtCancelMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +string BtCancelMessage::toString() const { + return "cancel index="+Util::uitos(index)+", begin="+Util::uitos(begin)+ + ", length="+Util::uitos(length); +} diff --git a/src/BtCancelMessage.h b/src/BtCancelMessage.h new file mode 100644 index 00000000..ceee62fb --- /dev/null +++ b/src/BtCancelMessage.h @@ -0,0 +1,93 @@ +/* */ +#ifndef _D_BT_CANCEL_MESSAGE_H_ +#define _D_BT_CANCEL_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtCancelMessage; + +typedef SharedHandle BtCancelMessageHandle; + +class BtCancelMessage : public SimpleBtMessage { +private: + uint32_t index; + uint32_t begin; + uint32_t length; + char* msg; + + static uint32_t MESSAGE_LENGTH; +public: + BtCancelMessage(uint32_t index = 0, uint32_t begin = 0, uint32_t length = 0) + :SimpleBtMessage(), + index(index), + begin(begin), + length(length), + msg(0) {} + + virtual ~BtCancelMessage() { + delete [] msg; + } + + enum ID_t { + ID = 8 + }; + + uint32_t getIndex() const { return index; } + + void setIndex(uint32_t index) { this->index = index; } + + uint32_t getBegin() const { return begin; } + + void setBegin(uint32_t begin) { this->begin = begin; } + + uint32_t getLength() const { return length; } + + void setLength(uint32_t length) { this->length = length; } + + static BtCancelMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; +}; + +#endif // _D_BT_CANCEL_MESSAGE_H_ diff --git a/src/BtCancelMessageValidator.h b/src/BtCancelMessageValidator.h new file mode 100644 index 00000000..af453fa8 --- /dev/null +++ b/src/BtCancelMessageValidator.h @@ -0,0 +1,67 @@ +/* */ +#ifndef _D_BT_CANCEL_MESSAGE_VALIDATOR_H_ +#define _D_BT_CANCEL_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtCancelMessage.h" + +class BtCancelMessageValidator : public BtMessageValidator { +private: + const BtCancelMessage* message; + uint32_t numPiece; + uint32_t pieceLength; +public: + BtCancelMessageValidator(const BtCancelMessage* message, + uint32_t numPiece, + uint32_t pieceLength): + message(message), + numPiece(numPiece), + pieceLength(pieceLength) {} + + virtual bool validate(Errors& error) { + // TODO + PeerMessageUtil::checkIndex(message->getIndex(), numPiece); + PeerMessageUtil::checkBegin(message->getBegin(), pieceLength); + PeerMessageUtil::checkLength(message->getLength()); + PeerMessageUtil::checkRange(message->getBegin(), message->getLength(), + pieceLength); + return true; + } +}; + +typedef SharedHandle BtCancelMessageValidatorHandle; + +#endif // _D_BT_CANCEL_MESSAGE_VALIDATOR_H_ diff --git a/src/BtCancelSendingPieceEvent.h b/src/BtCancelSendingPieceEvent.h new file mode 100644 index 00000000..90dbb936 --- /dev/null +++ b/src/BtCancelSendingPieceEvent.h @@ -0,0 +1,78 @@ +/* */ +#ifndef _D_BT_CANCEL_SENDING_PIECE_EVENT_H_ +#define _D_BT_CANCEL_SENDING_PIECE_EVENT_H_ + +#include "BtEvent.h" + +class BtCancelSendingPieceEvent : public BtEvent { +private: + uint32_t index; + uint32_t begin; + uint32_t length; +public: + BtCancelSendingPieceEvent(uint32_t index, uint32_t begin, uint32_t length): + index(index), begin(begin), length(length) {} + + virtual ~BtCancelSendingPieceEvent() {} + + void setIndex(uint32_t index) { + this->index = index; + } + + uint32_t getIndex() const { + return index; + } + + void setBegin(uint32_t begin) { + this->begin = begin; + } + + uint32_t getBegin() const { + return begin; + } + + void setLength(uint32_t length) { + this->length = length; + } + + uint32_t getLength() const { + return length; + } +}; + +typedef SharedHandle BtCancelSendingPieceEventHandle; + +#endif // _D_BT_CANCEL_SENDING_PIECE_EVENT_H_ diff --git a/src/BtChokeMessage.cc b/src/BtChokeMessage.cc new file mode 100644 index 00000000..09465511 --- /dev/null +++ b/src/BtChokeMessage.cc @@ -0,0 +1,87 @@ +/* */ +#include "BtChokeMessage.h" +#include "PeerMessageUtil.h" +#include "DlAbortEx.h" + +BtChokeMessageHandle BtChokeMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 1) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "choke", dataLength, 1); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "choke", ID); + } + BtChokeMessageHandle chokeMessage = new BtChokeMessage(); + return chokeMessage; +} + +void BtChokeMessage::doReceivedAction() { + peer->peerChoking = true; + BT_MESSAGE_DISPATCHER(btContext, peer)->doChokedAction(); +} + +bool BtChokeMessage::sendPredicate() const { + return !peer->amChoking; +} + +uint32_t BtChokeMessage::MESSAGE_LENGTH = 5; + +const char* BtChokeMessage::getMessage() { + if(!msg) { + /** + * len --- 1, 4bytes + * id --- 0, 1byte + * total: 5bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 1, ID); + } + return msg; +} + +uint32_t BtChokeMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +void BtChokeMessage::onSendComplete() { + peer->amChoking = true; + BT_MESSAGE_DISPATCHER(btContext, peer)->doChokingAction(); +} + +string BtChokeMessage::toString() const { + return "choke"; +} diff --git a/src/BtChokeMessage.h b/src/BtChokeMessage.h new file mode 100644 index 00000000..b8ee8fee --- /dev/null +++ b/src/BtChokeMessage.h @@ -0,0 +1,77 @@ +/* */ +#ifndef _D_BT_CHOKE_MESSAGE_H_ +#define _D_BT_CHOKE_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtChokeMessage; + +typedef SharedHandle BtChokeMessageHandle; + +class BtChokeMessage : public SimpleBtMessage { +private: + char* msg; + + static uint32_t MESSAGE_LENGTH; +public: + BtChokeMessage():SimpleBtMessage(), msg(0) {} + + virtual ~BtChokeMessage() { + delete [] msg; + } + + enum ID_t { + ID = 0 + }; + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; + + static BtChokeMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual bool sendPredicate() const; + + virtual void onSendComplete(); +}; + +#endif // _D_CHOKE_MESSAGE_H_ diff --git a/src/BtChokedEvent.h b/src/BtChokedEvent.h new file mode 100644 index 00000000..8fbd293e --- /dev/null +++ b/src/BtChokedEvent.h @@ -0,0 +1,45 @@ +/* */ +#ifndef _D_BT_CHOKED_EVENT_H_ +#define _D_BT_CHOKED_EVENT_H_ + +#include "BtEvent.h" + +class BtChokedEvent : public BtEvent { +}; + +typedef SharedHandle BtChokedEventHandle; + +#endif // _D_BT_CHOKED_EVENT_H_ diff --git a/src/BtChokingEvent.h b/src/BtChokingEvent.h new file mode 100644 index 00000000..36d852dd --- /dev/null +++ b/src/BtChokingEvent.h @@ -0,0 +1,45 @@ +/* */ +#ifndef _D_BT_CHOKING_EVENT_H_ +#define _D_BT_CHOKING_EVENT_H_ + +#include "BtEvent.h" + +class BtChokingEvent : public BtEvent { +}; + +typedef SharedHandle BtChokingEventHandle; + +#endif // _D_BT_CHOKING_EVENT_H_ diff --git a/src/BtContext.h b/src/BtContext.h index ad05c4f8..7ab6197e 100644 --- a/src/BtContext.h +++ b/src/BtContext.h @@ -77,6 +77,11 @@ public: virtual int getPieceLength() const = 0; virtual int getNumPieces() const = 0; + + /** + * Returns the peer id of localhost, 20 byte length + */ + virtual const unsigned char* getPeerId() = 0; }; typedef SharedHandle BtContextHandle; diff --git a/src/BtEvent.h b/src/BtEvent.h new file mode 100644 index 00000000..fd80729a --- /dev/null +++ b/src/BtEvent.h @@ -0,0 +1,47 @@ +/* */ +#ifndef _D_BT_EVENT_H_ +#define _D_BT_EVENT_H_ + +#include "common.h" + +class BtEvent { +public: + virtual ~BtEvent() {} +}; + +typedef SharedHandle BtEventHandle; + +#endif // _D_BT_EVENT_H_ diff --git a/src/BtEventListener.h b/src/BtEventListener.h new file mode 100644 index 00000000..2d99c910 --- /dev/null +++ b/src/BtEventListener.h @@ -0,0 +1,51 @@ +/* */ +#ifndef _D_BT_EVENT_LISTENER_H_ +#define _D_BT_EVENT_LISTENER_H_ + +#include "common.h" +#include "BtEvent.h" + +class BtEventListener { +public: + virtual ~BtEventListener() {} + + virtual void handleEvent(const BtEventHandle& event) = 0; +}; + +typedef SharedHandle BtEventListenerHandle; +typedef deque BtEventListeners; + +#endif // _D_BT_EVENT_LISTENER_H_ diff --git a/src/BtHandshakeMessage.cc b/src/BtHandshakeMessage.cc new file mode 100644 index 00000000..3cedc217 --- /dev/null +++ b/src/BtHandshakeMessage.cc @@ -0,0 +1,100 @@ +/* */ +#include "BtHandshakeMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" + +const unsigned char* BtHandshakeMessage::BT_PSTR = (const unsigned char*)"BitTorrent protocol"; + +BtHandshakeMessage::BtHandshakeMessage() { + init(); +} + +BtHandshakeMessage::BtHandshakeMessage(const unsigned char* infoHash, + const unsigned char* peerId) +{ + init(); + memcpy(this->infoHash, infoHash, INFO_HASH_LENGTH); + memcpy(this->peerId, peerId, PEER_ID_LENGTH); +} + +void BtHandshakeMessage::init() { + msg = 0; + this->pstrlen = 19; + pstr = new unsigned char[PSTR_LENGTH]; + reserved = new unsigned char[RESERVED_LENGTH]; + infoHash = new unsigned char[INFO_HASH_LENGTH]; + peerId = new unsigned char[PEER_ID_LENGTH]; + memcpy(this->pstr, PSTR, PSTR_LENGTH); + memset(this->reserved, 0, RESERVED_LENGTH); + // fast extension + this->reserved[7] |= 0x04; +} + +BtHandshakeMessageHandle BtHandshakeMessage::create(const unsigned char* data, uint32_t dataLength) { + BtHandshakeMessageHandle message = new BtHandshakeMessage(); + message->pstrlen = data[0]; + memcpy(message->pstr, &data[1], PSTR_LENGTH); + memcpy(message->reserved, &data[20], RESERVED_LENGTH); + memcpy(message->infoHash, &data[28], INFO_HASH_LENGTH); + memcpy(message->peerId, &data[48], PEER_ID_LENGTH); + return message; +} + +const char* BtHandshakeMessage::getMessage() { + if(!msg) { + msg = new char[MESSAGE_LENGTH]; + msg[0] = pstrlen; + memcpy(msg+1, pstr, PSTR_LENGTH); + memcpy(msg+20, reserved, RESERVED_LENGTH); + memcpy(msg+28, infoHash, INFO_HASH_LENGTH); + memcpy(msg+48, peerId, PEER_ID_LENGTH); + } + return msg; +} + +uint32_t BtHandshakeMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +string BtHandshakeMessage::toString() const { + return "handshake peerId="+ + Util::urlencode(peerId, PEER_ID_LENGTH)+ + ", reserved="+Util::toHex(reserved, RESERVED_LENGTH); +} + +bool BtHandshakeMessage::isFastExtensionSupported() const { + return reserved[7]&0x04; +} diff --git a/src/BtHandshakeMessage.h b/src/BtHandshakeMessage.h new file mode 100644 index 00000000..427343ab --- /dev/null +++ b/src/BtHandshakeMessage.h @@ -0,0 +1,117 @@ +/* */ +#ifndef _D_BT_HANDSHAKE_MESSAGE_H_ +#define _D_BT_HANDSHAKE_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtHandshakeMessage; + +typedef SharedHandle BtHandshakeMessageHandle; + +class BtHandshakeMessage : public SimpleBtMessage { +public: + static const uint32_t PSTR_LENGTH = 19; + static const unsigned char* BT_PSTR; + static const uint32_t RESERVED_LENGTH = 8; + static const uint32_t MESSAGE_LENGTH = 68; +private: + uint8_t pstrlen; + unsigned char* pstr; + unsigned char* reserved; + unsigned char* infoHash; + unsigned char* peerId; + char* msg; + void init(); +public: + BtHandshakeMessage(); + /** + * infoHash must be 20 byte length. + * peerId must be 20 byte length. + */ + BtHandshakeMessage(const unsigned char* infoHash, const unsigned char* peerId); + + static BtHandshakeMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual ~BtHandshakeMessage() { + delete [] msg; + delete [] pstr; + delete [] reserved; + delete [] infoHash; + delete [] peerId; + } + + virtual int32_t getId() const { return INT32_MAX; } + + virtual void doReceivedAction() {}; + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; + + bool isFastExtensionSupported() const; + + uint8_t getPstrlen() const { + return pstrlen; + } + + const unsigned char* getPstr() const { + return pstr; + } + + const unsigned char* getReserved() const { + return reserved; + } + + const unsigned char* getInfoHash() const { + return infoHash; + } + + void setInfoHash(const unsigned char* infoHash) { + memcpy(this->infoHash, infoHash, INFO_HASH_LENGTH); + } + + const unsigned char* getPeerId() const { + return peerId; + } + + void setPeerId(const unsigned char* peerId) { + memcpy(this->peerId, peerId, PEER_ID_LENGTH); + } +}; + +#endif // _D_HANDSHAKE_MESSAGE_H_ diff --git a/src/BtHandshakeMessageValidator.h b/src/BtHandshakeMessageValidator.h new file mode 100644 index 00000000..e06d224b --- /dev/null +++ b/src/BtHandshakeMessageValidator.h @@ -0,0 +1,75 @@ +/* */ +#ifndef _D_BT_HANDSHAKE_MESSAGE_VALIDATOR_H_ +#define _D_BT_HANDSHAKE_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtHandshakeMessage.h" +#include "Util.h" + +class BtHandshakeMessageValidator : public BtMessageValidator { +private: + const BtHandshakeMessage* message; + unsigned char infoHash[20]; +public: + BtHandshakeMessageValidator(const BtHandshakeMessage* message, + const unsigned char* infoHash): + message(message) + { + memcpy(this->infoHash, infoHash, sizeof(this->infoHash)); + } + + virtual bool validate(Errors& error) { + // TODO + if(message->getPstrlen() != 19) { + throw new DlAbortEx("invalid handshake pstrlen=%u", + message->getPstrlen()); + } + if(memcmp(BtHandshakeMessage::BT_PSTR, message->getPstr(), 19) != 0) { + throw new DlAbortEx("invalid handshake pstr=%s", + Util::urlencode(message->getPstr(), 19).c_str()); + } + if(memcmp(infoHash, message->getInfoHash(), 20) != 0) { + throw new DlAbortEx("invalid handshake info hash: expected:%s, actual:%s", + Util::toHex(infoHash, 20).c_str(), + Util::toHex(message->getInfoHash(), 20).c_str()); + } + return true; + } +}; + +typedef SharedHandle BtHandshakeMessageValidatorHandle; + +#endif // _D_BT_HANDSHAKE_MESSAGE_VALIDATOR_H_ diff --git a/src/BtHaveAllMessage.cc b/src/BtHaveAllMessage.cc new file mode 100644 index 00000000..a8d2c671 --- /dev/null +++ b/src/BtHaveAllMessage.cc @@ -0,0 +1,81 @@ +/* */ +#include "BtHaveAllMessage.h" +#include "DlAbortEx.h" +#include "PeerMessageUtil.h" + +BtHaveAllMessageHandle BtHaveAllMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 1) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "have all", dataLength, 1); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "have all", ID); + } + BtHaveAllMessageHandle message = new BtHaveAllMessage(); + return message; +} + +void BtHaveAllMessage::doReceivedAction() { + if(!peer->isFastExtensionEnabled()) { + throw new DlAbortEx("%s received while fast extension is disabled", + toString().c_str()); + } + peer->setAllBitfield(); +} + +uint32_t BtHaveAllMessage::MESSAGE_LENGTH = 5; + +const char* BtHaveAllMessage::getMessage() { + if(!msg) { + /** + * len --- 1, 4bytes + * id --- 14, 1byte + * total: 5bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 1, ID); + } + return msg; +} + +uint32_t BtHaveAllMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +string BtHaveAllMessage::toString() const { + return "have all"; +} diff --git a/src/BtHaveAllMessage.h b/src/BtHaveAllMessage.h new file mode 100644 index 00000000..bce5dc85 --- /dev/null +++ b/src/BtHaveAllMessage.h @@ -0,0 +1,73 @@ +/* */ +#ifndef _D_BT_HAVE_ALL_MESSAGE_H_ +#define _D_BT_HAVE_ALL_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtHaveAllMessage; + +typedef SharedHandle BtHaveAllMessageHandle; + +class BtHaveAllMessage : public SimpleBtMessage { +private: + char* msg; + + static uint32_t MESSAGE_LENGTH; +public: + BtHaveAllMessage():msg(0) {} + + virtual ~BtHaveAllMessage() { + delete [] msg; + } + + enum ID_t { + ID = 14 + }; + + static BtHaveAllMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; +}; + +#endif // _D_BT_HAVE_ALL_MESSAGE_H_ diff --git a/src/BtHaveMessage.cc b/src/BtHaveMessage.cc new file mode 100644 index 00000000..fdcda7fa --- /dev/null +++ b/src/BtHaveMessage.cc @@ -0,0 +1,85 @@ +/* */ +#include "BtHaveMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include "DlAbortEx.h" + +BtHaveMessageHandle BtHaveMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 5) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "have", dataLength, 5); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "have", ID); + } + BtHaveMessageHandle message = new BtHaveMessage(); + message->setIndex(PeerMessageUtil::getIntParam(data, 1)); + return message; +} + +void BtHaveMessage::doReceivedAction() { + peer->updateBitfield(index, 1); +} + +bool BtHaveMessage::sendPredicate() const { + return !peer->hasPiece(index); +} + +uint32_t BtHaveMessage::MESSAGE_LENGTH = 9; + +const char* BtHaveMessage::getMessage() { + if(!msg) { + /** + * len --- 5, 4bytes + * id --- 4, 1byte + * piece index --- index, 4bytes + * total: 9bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 5, ID); + PeerMessageUtil::setIntParam(&msg[5], index); + } + return msg; +} + +uint32_t BtHaveMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +string BtHaveMessage::toString() const { + return "have index="+Util::uitos(index); +} diff --git a/src/BtHaveMessage.h b/src/BtHaveMessage.h new file mode 100644 index 00000000..e0ad84e2 --- /dev/null +++ b/src/BtHaveMessage.h @@ -0,0 +1,81 @@ +/* */ +#ifndef _D_BT_HAVE_MESSAGE_H_ +#define _D_BT_HAVE_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtHaveMessage; + +typedef SharedHandle BtHaveMessageHandle; + +class BtHaveMessage : public SimpleBtMessage { +private: + uint32_t index; + char* msg; + static uint32_t MESSAGE_LENGTH; +public: + BtHaveMessage(uint32_t index = 0):index(index), msg(0) {} + + virtual ~BtHaveMessage() { + delete [] msg; + } + + enum ID_t { + ID = 4 + }; + + void setIndex(uint32_t index) { + this->index = index; + } + + uint32_t getIndex() const { return index; } + + static BtHaveMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual bool sendPredicate() const; + + virtual string toString() const; +}; + +#endif // _D_BT_HAVE_MESSAGE_H_ diff --git a/src/BtHaveMessageValidator.h b/src/BtHaveMessageValidator.h new file mode 100644 index 00000000..acf2b351 --- /dev/null +++ b/src/BtHaveMessageValidator.h @@ -0,0 +1,60 @@ +/* */ +#ifndef _D_BT_HAVE_MESSAGE_VALIDATOR_H_ +#define _D_BT_HAVE_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtHaveMessage.h" +#include "PeerMessageUtil.h" + +class BtHaveMessageValidator : public BtMessageValidator { +private: + const BtHaveMessage* message; + int numPiece; +public: + BtHaveMessageValidator(const BtHaveMessage* message, + int numPiece): + message(message), + numPiece(numPiece) {} + + virtual bool validate(Errors& errors) { + // TODO + PeerMessageUtil::checkIndex(message->getIndex(), numPiece); + return true; + } + +}; + +#endif // _D_BT_HAVE_MESSAGE_VALIDATOR_H_ diff --git a/src/BtHaveNoneMessage.cc b/src/BtHaveNoneMessage.cc new file mode 100644 index 00000000..e501f56f --- /dev/null +++ b/src/BtHaveNoneMessage.cc @@ -0,0 +1,80 @@ +/* */ +#include "BtHaveNoneMessage.h" +#include "DlAbortEx.h" +#include "PeerMessageUtil.h" + +BtHaveNoneMessageHandle BtHaveNoneMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 1) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "have none", dataLength, 1); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "have none", ID); + } + BtHaveNoneMessageHandle message = new BtHaveNoneMessage(); + return message; +} + +void BtHaveNoneMessage::doReceivedAction() { + if(!peer->isFastExtensionEnabled()) { + throw new DlAbortEx("%s received while fast extension is disabled", + toString().c_str()); + } +} + +uint32_t BtHaveNoneMessage::MESSAGE_LENGTH = 5; + +const char* BtHaveNoneMessage::getMessage() { + if(!msg) { + /** + * len --- 1, 4bytes + * id --- 15, 1byte + * total: 5bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 1, ID); + } + return msg; +} + +uint32_t BtHaveNoneMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +string BtHaveNoneMessage::toString() const { + return "have none"; +} diff --git a/src/BtHaveNoneMessage.h b/src/BtHaveNoneMessage.h new file mode 100644 index 00000000..ca77d5c5 --- /dev/null +++ b/src/BtHaveNoneMessage.h @@ -0,0 +1,73 @@ +/* */ +#ifndef _D_BT_HAVE_NONE_MESSAGE_H_ +#define _D_BT_HAVE_NONE_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtHaveNoneMessage; + +typedef SharedHandle BtHaveNoneMessageHandle; + +class BtHaveNoneMessage : public SimpleBtMessage { +private: + char* msg; + + static uint32_t MESSAGE_LENGTH; +public: + BtHaveNoneMessage():msg(0) {} + + virtual ~BtHaveNoneMessage() { + delete [] msg; + } + + enum ID_t { + ID = 15 + }; + + static BtHaveNoneMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; +}; + +#endif // _D_BT_HAVE_NONE_MESSAGE_H_ diff --git a/src/BtInteractive.h b/src/BtInteractive.h new file mode 100644 index 00000000..8c493bc0 --- /dev/null +++ b/src/BtInteractive.h @@ -0,0 +1,66 @@ +/* */ +#ifndef _D_BT_INTERACTIVE_H_ +#define _D_BT_INTERACTIVE_H_ + +#include "common.h" +#include "BtMessage.h" + +class BtInteractive { +public: + virtual ~BtInteractive() {} + + virtual void initiateHandshake() = 0; + + virtual BtMessageHandle receiveHandshake(bool quickReply = false) = 0; + + virtual BtMessageHandle receiveAndSendHandshake() = 0; + + virtual void doPostHandshakeProcessing() = 0; + + virtual void doInteractionProcessing() = 0; + + virtual void cancelAllPiece() = 0; + + virtual void sendPendingMessage() = 0; + + virtual uint32_t countPendingMessage() = 0; + + virtual bool isSendingMessageInProgress() = 0; +}; + +typedef SharedHandle BtInteractiveHandle; + +#endif // _D_BT_INTERACTIVE_H_ diff --git a/src/BtInterestedMessage.cc b/src/BtInterestedMessage.cc new file mode 100644 index 00000000..c3680042 --- /dev/null +++ b/src/BtInterestedMessage.cc @@ -0,0 +1,85 @@ +/* */ +#include "BtInterestedMessage.h" +#include "PeerMessageUtil.h" +#include "DlAbortEx.h" + +BtInterestedMessageHandle BtInterestedMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 1) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "interested", dataLength, 1); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "interested", ID); + } + BtInterestedMessageHandle message = new BtInterestedMessage(); + return message; +} + +void BtInterestedMessage::doReceivedAction() { + peer->peerInterested = true; +} + +bool BtInterestedMessage::sendPredicate() const { + return !peer->amInterested; +} + +uint32_t BtInterestedMessage::MESSAGE_LENGTH = 5; + +const char* BtInterestedMessage::getMessage() { + if(!msg) { + /** + * len --- 1, 4bytes + * id --- 2, 1byte + * total: 5bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 1, ID); + } + return msg; +} + +uint32_t BtInterestedMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +void BtInterestedMessage::onSendComplete() { + peer->amInterested = true; +} + +string BtInterestedMessage::toString() const { + return "interested"; +} diff --git a/src/BtInterestedMessage.h b/src/BtInterestedMessage.h new file mode 100644 index 00000000..3a7b27b7 --- /dev/null +++ b/src/BtInterestedMessage.h @@ -0,0 +1,77 @@ +/* */ +#ifndef _D_BT_INTERESTED_MESSAGE_H_ +#define _D_BT_INTERESTED_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtInterestedMessage; + +typedef SharedHandle BtInterestedMessageHandle; + +class BtInterestedMessage : public SimpleBtMessage { +private: + char* msg; + + static uint32_t MESSAGE_LENGTH; +public: + BtInterestedMessage():msg(0) {} + + virtual ~BtInterestedMessage() { + delete [] msg; + } + + enum ID_t { + ID = 2 + }; + + static BtInterestedMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; + + virtual bool sendPredicate() const; + + virtual void onSendComplete(); +}; + +#endif // _D_BT_INTERESTED_MESSAGE_H_ diff --git a/src/BtKeepAliveMessage.cc b/src/BtKeepAliveMessage.cc new file mode 100644 index 00000000..ae9d4a3e --- /dev/null +++ b/src/BtKeepAliveMessage.cc @@ -0,0 +1,53 @@ +/* */ +#include "BtKeepAliveMessage.h" + +uint32_t BtKeepAliveMessage::MESSAGE_LENGTH = 4; + +const char* BtKeepAliveMessage::getMessage() { + if(!msg) { + /** + * len --- 0, 4bytes + * total: 4bytes + */ + msg = new char[MESSAGE_LENGTH]; + memset(msg, 0, MESSAGE_LENGTH); + } + return msg; +} + +uint32_t BtKeepAliveMessage::getMessageLength() { + return MESSAGE_LENGTH; +} diff --git a/src/BtKeepAliveMessage.h b/src/BtKeepAliveMessage.h new file mode 100644 index 00000000..9044dfe9 --- /dev/null +++ b/src/BtKeepAliveMessage.h @@ -0,0 +1,73 @@ +/* */ +#ifndef _D_BT_KEEP_ALIVE_MESSAGE_H_ +#define _D_BT_KEEP_ALIVE_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtKeepAliveMessage; + +typedef SharedHandle BtKeepAliveMessageHandle; + +class BtKeepAliveMessage : public SimpleBtMessage { +private: + char* msg; + + static uint32_t MESSAGE_LENGTH; +public: + BtKeepAliveMessage():msg(0) {} + + virtual ~BtKeepAliveMessage() { + delete [] msg; + } + + enum ID_t { + ID = 99 + }; + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction() {} + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const { + return "keep alive"; + } +}; + +#endif // _D_BT_KEEP_ALIVE_MESSAGE_H_ diff --git a/src/BtMessage.h b/src/BtMessage.h new file mode 100644 index 00000000..0a135fec --- /dev/null +++ b/src/BtMessage.h @@ -0,0 +1,72 @@ +/* */ +#ifndef _D_BT_MESSAGE_H_ +#define _D_BT_MESSAGE_H_ + +#include "common.h" +#include "Piece.h" +#include "BtMessageValidator.h" +#include "BtEvent.h" + +class BtMessage { +public: + virtual ~BtMessage() {} + + virtual bool isSendingInProgress() = 0; + + virtual bool isInvalidate() = 0; + + virtual bool isUploading() = 0; + + virtual int32_t getId() = 0; + + virtual void doReceivedAction() = 0; + + virtual void send() = 0; + + virtual bool validate(Errors& errors) = 0; + + virtual void handleEvent(const BtEventHandle& event) = 0; + + virtual void onQueued() = 0; + + virtual string toString() const = 0; + +}; + +typedef SharedHandle BtMessageHandle; +typedef deque BtMessages; + +#endif // _D_BT_MESSAGE_H_ diff --git a/src/BtMessageDispatcher.h b/src/BtMessageDispatcher.h new file mode 100644 index 00000000..7f3ebec2 --- /dev/null +++ b/src/BtMessageDispatcher.h @@ -0,0 +1,82 @@ +/* */ +#ifndef _D_BT_MESSAGE_DISPATCHER_H_ +#define _D_BT_MESSAGE_DISPATCHER_H_ + +#include "common.h" +#include "Piece.h" +#include "BtMessage.h" +#include "RequestSlot.h" + +class BtMessageDispatcher { +public: + virtual ~BtMessageDispatcher() {} + + virtual void addMessageToQueue(const BtMessageHandle& btMessage) = 0; + + virtual void addMessageToQueue(const BtMessages& btMessages) = 0; + + virtual void sendMessages() = 0; + + virtual void doCancelSendingPieceAction(uint32_t index, uint32_t begin, uint32_t blockLength) = 0; + + virtual void doCancelSendingPieceAction(const PieceHandle& piece) = 0; + + virtual void doAbortOutstandingRequestAction(const PieceHandle& piece) = 0; + + virtual void doChokedAction() = 0; + + virtual void doChokingAction() = 0; + + virtual void checkRequestSlotAndDoNecessaryThing() = 0; + + virtual bool isSendingInProgress() = 0; + + virtual uint32_t countMessageInQueue() = 0; + + virtual uint32_t countOutstandingRequest() = 0; + + virtual bool isOutstandingRequest(uint32_t index, uint32_t blockIndex) = 0; + + virtual RequestSlot getOutstandingRequest(uint32_t index, uint32_t begin, uint32_t blockLength) = 0; + + virtual void removeOutstandingRequest(const RequestSlot& slot) = 0; + + virtual void addOutstandingRequest(const RequestSlot& slot) = 0; +}; + +typedef SharedHandle BtMessageDispatcherHandle; + +#endif // _D_BT_MESSAGE_DISPATCHER_H_ diff --git a/src/BtMessageFactory.cc b/src/BtMessageFactory.cc new file mode 100644 index 00000000..2677c7b0 --- /dev/null +++ b/src/BtMessageFactory.cc @@ -0,0 +1,53 @@ +/* */ +#include "BtMessageFactory.h" +#include "DefaultBtMessageFactory.h" + +void BtMessageFactory::registerFactory(const string& key, + const BtMessageFactoryPrerequisiteHandle& prereq) { + prerequisiteMap.erase(key); + BtMessageFactoryPrerequisiteMap::value_type p(key, prereq); + prerequisiteMap.insert(p); +} + +static BtMessageFactory::BtMessageFactoryHandle getNewFactory(const string& key) { + DefaultBtMessageFactoryHandle factory = new DefaultBtMessageFactory(); + BtMessageFactoryPrerequisiteMap::iterator itr = prerequisiteMap.find(key); + if(prerequisiteMap.end() != itr) { + // TODO set prerequisite objects to factory here + } + return factory; +} + diff --git a/src/BtMessageFactory.h b/src/BtMessageFactory.h new file mode 100644 index 00000000..1dd73afa --- /dev/null +++ b/src/BtMessageFactory.h @@ -0,0 +1,91 @@ +/* */ +#ifndef _D_BT_MESSAGE_FACTORY_H_ +#define _D_BT_MESSAGE_FACTORY_H_ + +#include "common.h" +#include "BtMessage.h" +#include "Piece.h" + +class BtMessageFactory { +public: + virtual ~BtMessageFactory() {} + + virtual BtMessageHandle + createBtMessage(const unsigned char* msg, uint32_t msgLength) = 0; + + virtual BtMessageHandle + createHandshakeMessage(const unsigned char* msg, uint32_t msgLength) = 0; + + virtual BtMessageHandle + createHandshakeMessage(const unsigned char* infoHash, + const unsigned char* peerId) = 0; + + virtual BtMessageHandle + createRequestMessage(const PieceHandle& piece, uint32_t blockIndex) = 0; + + virtual BtMessageHandle + createCancelMessage(uint32_t index, uint32_t begin, uint32_t length) = 0; + + virtual BtMessageHandle + createPieceMessage(uint32_t index, uint32_t begin, uint32_t length) = 0; + + virtual BtMessageHandle createHaveMessage(uint32_t index) = 0; + + virtual BtMessageHandle createChokeMessage() = 0; + + virtual BtMessageHandle createUnchokeMessage() = 0; + + virtual BtMessageHandle createInterestedMessage() = 0; + + virtual BtMessageHandle createNotInterestedMessage() = 0; + + virtual BtMessageHandle createBitfieldMessage() = 0; + + virtual BtMessageHandle createKeepAliveMessage() = 0; + + virtual BtMessageHandle createHaveAllMessage() = 0; + + virtual BtMessageHandle createHaveNoneMessage() = 0; + + virtual BtMessageHandle + createRejectMessage(uint32_t index, uint32_t begin, uint32_t length) = 0; + + virtual BtMessageHandle createAllowedFastMessage(uint32_t index) = 0; +}; + +typedef SharedHandle BtMessageFactoryHandle; + +#endif // _D_BT_MESSAGE_FACTORY_H_ diff --git a/src/BtMessageReceiver.h b/src/BtMessageReceiver.h new file mode 100644 index 00000000..d39a128f --- /dev/null +++ b/src/BtMessageReceiver.h @@ -0,0 +1,54 @@ +/* */ +#ifndef _D_BT_MESSAGE_RECEIVER_H_ +#define _D_BT_MESSAGE_RECEIVER_H_ + +#include "common.h" +#include "BtMessage.h" + +class BtMessageReceiver { +public: + virtual ~BtMessageReceiver() {} + + virtual BtMessageHandle receiveHandshake(bool quickReply = false) = 0; + + virtual BtMessageHandle receiveAndSendHandshake() = 0; + + virtual BtMessageHandle receiveMessage() = 0; +}; + +typedef SharedHandle BtMessageReceiverHandle; + +#endif // _D_BT_MESSAGE_RECEIVER_H_ diff --git a/src/BtMessageValidator.h b/src/BtMessageValidator.h new file mode 100644 index 00000000..5298fde4 --- /dev/null +++ b/src/BtMessageValidator.h @@ -0,0 +1,52 @@ +/* */ +#ifndef _D_BT_MESSAGE_VALIDATOR_H_ +#define _D_BT_MESSAGE_VALIDATOR_H_ + +#include "common.h" +#include "BtMessage.h" + +typedef Strings Errors; + +class BtMessageValidator { +public: + virtual ~BtMessageValidator() {} + + virtual bool validate(Errors& errors) = 0; +}; + +typedef SharedHandle BtMessageValidatorHandle; + +#endif // _D_BT_MESSAGE_VALIDATOR_H_ diff --git a/src/BtNotInterestedMessage.cc b/src/BtNotInterestedMessage.cc new file mode 100644 index 00000000..4d3fc4eb --- /dev/null +++ b/src/BtNotInterestedMessage.cc @@ -0,0 +1,85 @@ +/* */ +#include "BtNotInterestedMessage.h" +#include "PeerMessageUtil.h" +#include "DlAbortEx.h" + +BtNotInterestedMessageHandle BtNotInterestedMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 1) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "not interested", dataLength, 1); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "not interested", ID); + } + BtNotInterestedMessageHandle message = new BtNotInterestedMessage(); + return message; +} + +void BtNotInterestedMessage::doReceivedAction() { + peer->peerInterested = false; +} + +bool BtNotInterestedMessage::sendPredicate() const { + return peer->amInterested; +} + +uint32_t BtNotInterestedMessage::MESSAGE_LENGTH = 5; + +const char* BtNotInterestedMessage::getMessage() { + if(!msg) { + /** + * len --- 1, 4bytes + * id --- 3, 1byte + * total: 5bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 1, ID); + } + return msg; +} + +uint32_t BtNotInterestedMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +void BtNotInterestedMessage::onSendComplete() { + peer->amInterested = false; +} + +string BtNotInterestedMessage::toString() const { + return "not interested"; +} diff --git a/src/BtNotInterestedMessage.h b/src/BtNotInterestedMessage.h new file mode 100644 index 00000000..f7cbee5a --- /dev/null +++ b/src/BtNotInterestedMessage.h @@ -0,0 +1,77 @@ +/* */ +#ifndef _D_BT_NOT_INTERESTED_MESSAGE_H_ +#define _D_BT_NOT_INTERESTED_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtNotInterestedMessage; + +typedef SharedHandle BtNotInterestedMessageHandle; + +class BtNotInterestedMessage : public SimpleBtMessage { +private: + char* msg; + + static uint32_t MESSAGE_LENGTH; +public: + BtNotInterestedMessage():msg(0) {} + + virtual ~BtNotInterestedMessage() { + delete [] msg; + } + + enum ID_t { + ID = 3 + }; + + static BtNotInterestedMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; + + virtual bool sendPredicate() const; + + virtual void onSendComplete(); +}; + +#endif // _D_BT_NOT_INTERESTED_MESSAGE_H_ diff --git a/src/BtPieceMessage.cc b/src/BtPieceMessage.cc new file mode 100644 index 00000000..a9bdb758 --- /dev/null +++ b/src/BtPieceMessage.cc @@ -0,0 +1,283 @@ +/* */ +#include "BtPieceMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include "message.h" +#include "DlAbortEx.h" +#include "BtChokingEvent.h" +#include "BtCancelSendingPieceEvent.h" + +void BtPieceMessage::setBlock(const unsigned char* block, uint32_t blockLength) { + delete [] this->block; + this->blockLength = blockLength; + this->block = new char[this->blockLength]; + memcpy(this->block, block, this->blockLength); +} + +BtPieceMessageHandle BtPieceMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength <= 9) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be greater than %d", "piece", dataLength, 9); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "piece", ID); + } + BtPieceMessageHandle message = new BtPieceMessage(); + message->setIndex(PeerMessageUtil::getIntParam(data, 1)); + message->setBegin(PeerMessageUtil::getIntParam(data, 5)); + message->setBlock(data+9, dataLength-9); + return message; +} + +void BtPieceMessage::doReceivedAction() { + RequestSlot slot = + BT_MESSAGE_DISPATCHER(btContext, peer)->getOutstandingRequest(index, + begin, + blockLength); + peer->updateDownloadLength(blockLength); + if(!RequestSlot::isNull(slot)) { + peer->snubbing = false; + peer->updateLatency(slot.getLatencyInMillis()); + PieceHandle piece = pieceStorage->getPiece(index); + uint64_t offset = + ((uint64_t)index)*btContext->getPieceLength()+begin; + logger->debug("CUID#%d - Piece received. index=%u, begin=%u, length=%u, offset=%llu, blockIndex=%u", + cuid, index, begin, blockLength, offset, slot.getBlockIndex()); + pieceStorage->getDiskAdaptor()->writeData(block, + blockLength, + offset); + piece->completeBlock(slot.getBlockIndex()); + BT_MESSAGE_DISPATCHER(btContext, peer)->removeOutstandingRequest(slot); + if(piece->pieceComplete()) { + if(checkPieceHash(piece)) { + onNewPiece(piece); + } else { + onWrongPiece(piece); + } + } + } +} + +uint32_t BtPieceMessage::MESSAGE_HEADER_LENGTH = 13; + +const char* BtPieceMessage::getMessageHeader() { + if(!msgHeader) { + /** + * len --- 9+blockLength, 4bytes + * id --- 7, 1byte + * index --- index, 4bytes + * begin --- begin, 4bytes + * total: 13bytes + */ + msgHeader = new char[MESSAGE_HEADER_LENGTH]; + PeerMessageUtil::createPeerMessageString(msgHeader, MESSAGE_HEADER_LENGTH, + 9+blockLength, ID); + PeerMessageUtil::setIntParam(&msgHeader[5], index); + PeerMessageUtil::setIntParam(&msgHeader[9], begin); + } + return msgHeader; +} + +uint32_t BtPieceMessage::getMessageHeaderLength() { + return MESSAGE_HEADER_LENGTH; +} + +void BtPieceMessage::send() { + if(invalidate) { + return; + } + if(!headerSent) { + if(!sendingInProgress) { + logger->info(MSG_SEND_PEER_MESSAGE, + cuid, peer->ipaddr.c_str(), peer->port, + toString().c_str()); + getMessageHeader(); + leftDataLength = getMessageHeaderLength(); + sendingInProgress = true; + } + uint32_t writtenLength + = PEER_CONNECTION(btContext, peer)->sendMessage(msgHeader+getMessageHeaderLength()-leftDataLength, + leftDataLength); + if(writtenLength == leftDataLength) { + headerSent = true; + leftDataLength = blockLength; + } else { + leftDataLength -= writtenLength; + } + } + if(headerSent) { + sendingInProgress = false; + uint64_t pieceDataOffset = + ((uint64_t)index)*btContext->getPieceLength()+begin+blockLength-leftDataLength; + uint32_t writtenLength = + sendPieceData(pieceDataOffset, leftDataLength); + peer->updateUploadLength(writtenLength); + if(writtenLength < leftDataLength) { + sendingInProgress = true; + } + leftDataLength -= writtenLength; + } +} + +uint32_t BtPieceMessage::sendPieceData(uint64_t offset, uint32_t length) const { + uint32_t BUF_SIZE = 256; + char buf[BUF_SIZE]; + int32_t iteration = length/BUF_SIZE; + uint32_t writtenLength = 0; + for(int32_t i = 0; i < iteration; i++) { + if(pieceStorage->getDiskAdaptor()->readData(buf, BUF_SIZE, offset+i*BUF_SIZE) < BUF_SIZE) { + throw new DlAbortEx("Failed to read data from disk."); + } + uint32_t ws = PEER_CONNECTION(btContext, peer)->sendMessage(buf, BUF_SIZE); + writtenLength += ws; + if(ws != BUF_SIZE) { + return writtenLength; + } + } + + int32_t rem = length%BUF_SIZE; + if(rem > 0) { + if(pieceStorage->getDiskAdaptor()->readData(buf, rem, offset+iteration*BUF_SIZE) < rem) { + throw new DlAbortEx("Failed to read data from disk."); + } + uint32_t ws = PEER_CONNECTION(btContext, peer)->sendMessage(buf, rem); + writtenLength += ws; + } + return writtenLength; +} + +string BtPieceMessage::toString() const { + return "piece index="+Util::uitos(index)+", begin="+Util::uitos(begin)+ + ", length="+Util::uitos(blockLength); +} + +bool BtPieceMessage::checkPieceHash(const PieceHandle& piece) { + uint64_t offset = + ((uint64_t)piece->getIndex())*btContext->getPieceLength(); + return pieceStorage->getDiskAdaptor()->sha1Sum(offset, piece->getLength()) == + btContext->getPieceHash(piece->getIndex()); +} + +void BtPieceMessage::onNewPiece(const PieceHandle& piece) { + logger->info(MSG_GOT_NEW_PIECE, cuid, piece->getIndex()); + pieceStorage->completePiece(piece); + pieceStorage->advertisePiece(cuid, piece->getIndex()); +} + +void BtPieceMessage::onWrongPiece(const PieceHandle& piece) { + logger->error(MSG_GOT_WRONG_PIECE, cuid, piece->getIndex()); + erasePieceOnDisk(piece); + piece->clearAllBlock(); + BT_REQUEST_FACTORY(btContext, peer)->removeTargetPiece(piece); +} + +void BtPieceMessage::erasePieceOnDisk(const PieceHandle& piece) { + int32_t BUFSIZE = 4096; + char buf[BUFSIZE]; + memset(buf, 0, BUFSIZE); + uint64_t offset = + ((uint64_t)piece->getIndex())*btContext->getPieceLength(); + for(int32_t i = 0; i < piece->getLength()/BUFSIZE; i++) { + pieceStorage->getDiskAdaptor()->writeData(buf, BUFSIZE, offset); + offset += BUFSIZE; + } + int32_t r = piece->getLength()%BUFSIZE; + if(r > 0) { + pieceStorage->getDiskAdaptor()->writeData(buf, r, offset); + } +} + +bool BtPieceMessage::BtChokingEventListener::canHandle(const BtEventHandle& event) { + BtChokingEvent* intEvent = dynamic_cast(event.get()); + return intEvent != 0; +} + +void BtPieceMessage::BtChokingEventListener::handleEventInternal(const BtEventHandle& event) { + message->handleChokingEvent(event); +} + +void BtPieceMessage::handleChokingEvent(const BtEventHandle& event) { + if(!invalidate && + !sendingInProgress && + !peer->isInAmAllowedIndexSet(index)) { + logger->debug("CUID#%d - Reject piece message in queue because" + " the peer has been choked. index=%d, begin=%d, length=%d", + cuid, + index, + begin, + blockLength); + + if(peer->isFastExtensionEnabled()) { + BtMessageHandle rej = + BT_MESSAGE_FACTORY(btContext, peer)->createRejectMessage(index, + begin, + blockLength); + BT_MESSAGE_DISPATCHER(btContext, peer)->addMessageToQueue(rej); + } + invalidate = true; + } +} + +bool BtPieceMessage::BtCancelSendingPieceEventListener::canHandle(const BtEventHandle& event) { + BtCancelSendingPieceEvent* intEvent = dynamic_cast(event.get()); + return intEvent != 0; +} + +void BtPieceMessage::BtCancelSendingPieceEventListener::handleEventInternal(const BtEventHandle& event) { + message->handleCancelSendingPieceEvent(event); +} + +void BtPieceMessage::handleCancelSendingPieceEvent(const BtEventHandle& event) { + BtCancelSendingPieceEvent* intEvent = (BtCancelSendingPieceEvent*)(event.get()); + if(!invalidate && + !sendingInProgress && + index == intEvent->getIndex() && + begin == intEvent->getBegin() && + blockLength == intEvent->getLength()) { + logger->debug("CUID#%d - Reject piece message in queue because cancel" + " message received. index=%d, begin=%d, length=%d", + cuid, index, begin, blockLength); + if(peer->isFastExtensionEnabled()) { + BtMessageHandle rej = + BT_MESSAGE_FACTORY(btContext, peer)->createRejectMessage(index, + begin, + blockLength); + BT_MESSAGE_DISPATCHER(btContext, peer)->addMessageToQueue(rej); + } + invalidate = true; + } +} diff --git a/src/BtPieceMessage.h b/src/BtPieceMessage.h new file mode 100644 index 00000000..d1677369 --- /dev/null +++ b/src/BtPieceMessage.h @@ -0,0 +1,154 @@ +/* */ +#ifndef _D_BT_PIECE_MESSAGE_H_ +#define _D_BT_PIECE_MESSAGE_H_ + +#include "AbstractBtMessage.h" +#include "BtContext.h" +#include "PieceStorage.h" +#include "BtEvent.h" +#include "AbstractBtEventListener.h" + +class BtPieceMessage; + +typedef SharedHandle BtPieceMessageHandle; + +class BtPieceMessage : public AbstractBtMessage { +private: + uint32_t index; + uint32_t begin; + uint32_t blockLength; + char* block; + uint32_t leftDataLength; + bool headerSent; + char* msgHeader; + + static uint32_t MESSAGE_HEADER_LENGTH; + + bool checkPieceHash(const PieceHandle& piece); + + void onNewPiece(const PieceHandle& piece); + + void onWrongPiece(const PieceHandle& piece); + + void erasePieceOnDisk(const PieceHandle& piece); + + uint32_t sendPieceData(uint64_t offset, uint32_t length) const; + + class BtChokingEventListener : public AbstractBtEventListener { + private: + BtPieceMessage* message; + public: + BtChokingEventListener(BtPieceMessage* message):message(message) {} + + virtual bool canHandle(const BtEventHandle& btEvent); + + virtual void handleEventInternal(const BtEventHandle& btEvent); + }; + + typedef SharedHandle BtChokingEventListenerHandle; + + class BtCancelSendingPieceEventListener : public AbstractBtEventListener { + private: + BtPieceMessage* message; + public: + BtCancelSendingPieceEventListener(BtPieceMessage* message):message(message) {} + + virtual bool canHandle(const BtEventHandle& btEvent); + + virtual void handleEventInternal(const BtEventHandle& btEvent); + }; + + typedef SharedHandle BtCancelSendingPieceEventListenerHandle; +public: + BtPieceMessage(uint32_t index = 0, uint32_t begin = 0, uint32_t blockLength = 0) + :index(index), + begin(begin), + blockLength(blockLength), + block(0), + leftDataLength(0), + headerSent(false), + msgHeader(0) + { + uploading = true; + addEventListener(new BtChokingEventListener(this)); + addEventListener(new BtCancelSendingPieceEventListener(this)); + } + + virtual ~BtPieceMessage() { + delete [] msgHeader; + delete [] block; + } + + enum ID_t { + ID = 7 + }; + + uint32_t getIndex() const { return index; } + + void setIndex(uint32_t index) { this->index = index; } + + uint32_t getBegin() const { return begin; } + + void setBegin(uint32_t begin) { this->begin = begin; } + + const char* getBlock() const { return block; } + + void setBlock(const unsigned char* block, uint32_t blockLength); + + uint32_t getBlockLength() const { return blockLength; } + + void setBlockLength(uint32_t blockLength) { this->blockLength = blockLength; } + + static BtPieceMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + const char* getMessageHeader(); + + uint32_t getMessageHeaderLength(); + + virtual void send(); + + virtual string toString() const; + + void handleChokingEvent(const BtEventHandle& event); + + void handleCancelSendingPieceEvent(const BtEventHandle& event); +}; + +#endif // _D_BT_PIECE_MESSAGE_H_ diff --git a/src/BtPieceMessageValidator.h b/src/BtPieceMessageValidator.h new file mode 100644 index 00000000..95e9a3a1 --- /dev/null +++ b/src/BtPieceMessageValidator.h @@ -0,0 +1,64 @@ +/* */ +#ifndef _D_BT_PIECE_MESSAGE_VALIDATOR_H_ +#define _D_BT_PIECE_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtPieceMessage.h" + +class BtPieceMessageValidator : public BtMessageValidator { +private: + const BtPieceMessage* message; + uint32_t numPiece; + uint32_t pieceLength; +public: + BtPieceMessageValidator(const BtPieceMessage* message, + uint32_t numPiece, + uint32_t pieceLength): + message(message), + numPiece(numPiece), + pieceLength(pieceLength) {} + + virtual bool validate(Errors& error) { + // TODO + PeerMessageUtil::checkIndex(message->getIndex(), numPiece); + PeerMessageUtil::checkBegin(message->getBegin(), pieceLength); + return true; + } +}; + +typedef SharedHandle BtPieceMessageValidatorHandle; + +#endif // _D_BT_PIECE_MESSAGE_VALIDATOR_H_ diff --git a/src/BtPortMessage.cc b/src/BtPortMessage.cc new file mode 100644 index 00000000..29ffc761 --- /dev/null +++ b/src/BtPortMessage.cc @@ -0,0 +1,56 @@ +/* */ +#include "BtPortMessage.h" +#include "PeerMessageUtil.h" +#include "DlAbortEx.h" +#include "Util.h" + +BtPortMessageHandle BtPortMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 3) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "port", dataLength, 3); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "piece", ID); + } + BtPortMessageHandle message = new BtPortMessage(); + message->setPort(PeerMessageUtil::getShortIntParam(data, 1)); + return message; +} + +string BtPortMessage::toString() const { + return "port port="+Util::uitos(port); +} diff --git a/src/BtPortMessage.h b/src/BtPortMessage.h new file mode 100644 index 00000000..43f4be34 --- /dev/null +++ b/src/BtPortMessage.h @@ -0,0 +1,72 @@ +/* */ +#ifndef _D_BT_PORT_MESSAGE_H_ +#define _D_BT_PORT_MESSAGE_H_ + +#include "AbstractBtMessage.h" + +class BtPortMessage; + +typedef SharedHandle BtPortMessageHandle; + +class BtPortMessage : public AbstractBtMessage { +private: + uint16_t port; +public: + BtPortMessage(uint16_t port = 0):port(port) {} + + virtual ~BtPortMessage() {} + + enum ID_t { + ID = 9 + }; + + uint16_t getPort() const { return port; } + + void setPort(uint16_t port) { this->port = port; } + + virtual int32_t getId() const { return ID; } + + static BtPortMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual void doReceivedAction() { + logger->info("DHT is not supported yet."); + } + virtual void send() {} + + virtual string toString() const; +}; + +#endif // _D_BT_PORT_MESSAGE_H_ diff --git a/src/BtRegistry.cc b/src/BtRegistry.cc index cdd9c6e6..e74b86bf 100644 --- a/src/BtRegistry.cc +++ b/src/BtRegistry.cc @@ -40,6 +40,7 @@ PieceStorageMap BtRegistry::pieceStorageMap; BtAnnounceMap BtRegistry::btAnnounceMap; BtRuntimeMap BtRegistry::btRuntimeMap; BtProgressInfoFileMap BtRegistry::btProgressInfoFileMap; +PeerObjectClusterRegistry BtRegistry::peerObjectClusterRegistry; PeerStorageHandle BtRegistry::getPeerStorage(const string& key) { PeerStorageMap::iterator itr = peerStorageMap.find(key); @@ -70,6 +71,7 @@ BtRegistry::getPieceStorage(const string& key) { bool BtRegistry::registerPieceStorage(const string& key, const PieceStorageHandle& pieceStorage) { + pieceStorageMap.erase(key); PieceStorageMap::value_type p(key, pieceStorage); pair retval = pieceStorageMap.insert(p); return retval.second; @@ -128,3 +130,31 @@ BtRegistry::registerBtProgressInfoFile(const string& key, btProgressInfoFileMap.insert(p); return retval.second; } + +PeerObjectClusterHandle +BtRegistry::getPeerObjectCluster(const string& key) +{ + return peerObjectClusterRegistry.getHandle(key); +} + +void +BtRegistry::registerPeerObjectCluster(const string& key, + const PeerObjectClusterHandle& cluster) +{ + peerObjectClusterRegistry.registerHandle(key, cluster); +} + +void +BtRegistry::unregisterPeerObjectCluster(const string& key) +{ + peerObjectClusterRegistry.unregisterHandle(key); +} + +void BtRegistry::clear() { + peerStorageMap.clear(); + pieceStorageMap.clear(); + btAnnounceMap.clear(); + btRuntimeMap.clear(); + btProgressInfoFileMap.clear(); + peerObjectClusterRegistry.clear(); +} diff --git a/src/BtRegistry.h b/src/BtRegistry.h index f8356a23..a04e0c06 100644 --- a/src/BtRegistry.h +++ b/src/BtRegistry.h @@ -41,6 +41,8 @@ #include "BtAnnounce.h" #include "BtRuntime.h" #include "BtProgressInfoFile.h" +#include "PeerObject.h" +#include "HandleRegistry.h" #include typedef map PeerStorageMap; @@ -49,6 +51,11 @@ typedef map BtAnnounceMap; typedef map BtRuntimeMap; typedef map BtProgressInfoFileMap; +// for BtMessageFactory +typedef HandleRegistry PeerObjectCluster; +typedef SharedHandle PeerObjectClusterHandle; +typedef HandleRegistry PeerObjectClusterRegistry; + class BtRegistry { private: BtRegistry() {} @@ -58,6 +65,7 @@ private: static BtAnnounceMap btAnnounceMap; static BtRuntimeMap btRuntimeMap; static BtProgressInfoFileMap btProgressInfoFileMap; + static PeerObjectClusterRegistry peerObjectClusterRegistry; public: static PeerStorageHandle getPeerStorage(const string& key); static bool registerPeerStorage(const string& key, @@ -78,6 +86,19 @@ public: static BtProgressInfoFileHandle getBtProgressInfoFile(const string& key); static bool registerBtProgressInfoFile(const string& key, const BtProgressInfoFileHandle& btProgressInfoFile); + + // for PeerObject + static PeerObjectClusterHandle + getPeerObjectCluster(const string& key); + + static void + registerPeerObjectCluster(const string& key, + const PeerObjectClusterHandle& cluster); + + static void + unregisterPeerObjectCluster(const string& key); + + static void clear(); }; #define PEER_STORAGE(btContext) \ @@ -95,4 +116,22 @@ BtRegistry::getBtRuntime(btContext->getInfoHashAsString()) #define BT_PROGRESS_INFO_FILE(btContext) \ BtRegistry::getBtProgressInfoFile(btContext->getInfoHashAsString()) +#define PEER_OBJECT_CLUSTER(btContext) \ +BtRegistry::getPeerObjectCluster(btContext->getInfoHashAsString()) + +#define PEER_OBJECT(btContext, peer) \ +PEER_OBJECT_CLUSTER(btContext)->getHandle(peer->getId()) + +#define BT_MESSAGE_DISPATCHER(btContext, peer) \ +PEER_OBJECT(btContext, peer)->btMessageDispatcher + +#define BT_MESSAGE_FACTORY(btContext, peer) \ +PEER_OBJECT(btContext, peer)->btMessageFactory + +#define BT_REQUEST_FACTORY(btContext, peer) \ +PEER_OBJECT(btContext, peer)->btRequestFactory + +#define PEER_CONNECTION(btContext, peer) \ +PEER_OBJECT(btContext, peer)->peerConnection + #endif // _D_BT_REGISTRY_H_ diff --git a/src/BtRejectMessage.cc b/src/BtRejectMessage.cc new file mode 100644 index 00000000..e6438c96 --- /dev/null +++ b/src/BtRejectMessage.cc @@ -0,0 +1,101 @@ +/* */ +#include "BtRejectMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include "DlAbortEx.h" + +BtRejectMessageHandle BtRejectMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 13) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "reject", dataLength, 13); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "reject", ID); + } + BtRejectMessageHandle message = new BtRejectMessage(); + message->setIndex(PeerMessageUtil::getIntParam(data, 1)); + message->setBegin(PeerMessageUtil::getIntParam(data, 5)); + message->setLength(PeerMessageUtil::getIntParam(data, 9)); + return message; +} + +void BtRejectMessage::doReceivedAction() { + 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 has never sent. + RequestSlot slot = + BT_MESSAGE_DISPATCHER(btContext, peer)->getOutstandingRequest(index, begin, length); + if(RequestSlot::isNull(slot)) { + //throw new DlAbortEx("reject recieved, but it is not in the request slots."); + } else { + BT_MESSAGE_DISPATCHER(btContext, peer)->removeOutstandingRequest(slot); + } + +} + +uint32_t BtRejectMessage::MESSAGE_LENGTH = 17; + +const char* BtRejectMessage::getMessage() { + if(!msg) { + /** + * len --- 13, 4bytes + * id --- 16, 1byte + * index --- index, 4bytes + * begin --- begin, 4bytes + * length -- length, 4bytes + * total: 17bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 13, ID); + PeerMessageUtil::setIntParam(&msg[5], index); + PeerMessageUtil::setIntParam(&msg[9], begin); + PeerMessageUtil::setIntParam(&msg[13], length); + } + return msg; +} + +uint32_t BtRejectMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +string BtRejectMessage::toString() const { + return "reject index="+Util::uitos(index)+", begin="+Util::uitos(begin)+ + ", length="+Util::uitos(length); +} diff --git a/src/BtRejectMessage.h b/src/BtRejectMessage.h new file mode 100644 index 00000000..4e081a6d --- /dev/null +++ b/src/BtRejectMessage.h @@ -0,0 +1,88 @@ +/* */ +#ifndef _D_BT_REJECT_MESSAGE_H_ +#define _D_BT_REJECT_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtRejectMessage; + +typedef SharedHandle BtRejectMessageHandle; + +class BtRejectMessage : public SimpleBtMessage { +private: + uint32_t index; + uint32_t begin; + uint32_t length; + char* msg; + static uint32_t MESSAGE_LENGTH; +public: + BtRejectMessage(uint32_t index = 0, uint32_t begin = 0, uint32_t length = 0) + :index(index), + begin(begin), + length(length), + msg(0) {} + + virtual ~BtRejectMessage() { + delete [] msg; + } + + enum ID_t { + ID = 16 + }; + + uint32_t getIndex() const { return index; } + void setIndex(uint32_t index) { this->index = index; } + + uint32_t getBegin() const { return begin; } + void setBegin(uint32_t begin) { this->begin = begin; } + + uint32_t getLength() const { return length; } + void setLength(uint32_t length) { this->length = length; } + + static BtRejectMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; +}; + +#endif // _D_BT_REJECT_MESSAGE_H_ diff --git a/src/BtRejectMessageValidator.h b/src/BtRejectMessageValidator.h new file mode 100644 index 00000000..84b814eb --- /dev/null +++ b/src/BtRejectMessageValidator.h @@ -0,0 +1,68 @@ +/* */ +#ifndef _D_BT_REJECT_MESSAGE_VALIDATOR_H_ +#define _D_BT_REJECT_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtRejectMessage.h" + +class BtRejectMessageValidator : public BtMessageValidator { +private: + const BtRejectMessage* message; + uint32_t numPiece; + uint32_t pieceLength; +public: + BtRejectMessageValidator(const BtRejectMessage* message, + uint32_t numPiece, + uint32_t pieceLength): + message(message), + numPiece(numPiece), + pieceLength(pieceLength) {} + + virtual bool validate(Errors& error) { + // TODO + PeerMessageUtil::checkIndex(message->getIndex(), numPiece); + PeerMessageUtil::checkBegin(message->getBegin(), pieceLength); + PeerMessageUtil::checkLength(message->getLength()); + PeerMessageUtil::checkRange(message->getBegin(), + message->getLength(), + pieceLength); + return true; + } +}; + +typedef SharedHandle BtRejectMessageValidatorHandle; + +#endif // _D_BT_REJECT_MESSAGE_VALIDATOR_H_ diff --git a/src/BtRequestFactory.h b/src/BtRequestFactory.h new file mode 100644 index 00000000..f68d0e77 --- /dev/null +++ b/src/BtRequestFactory.h @@ -0,0 +1,72 @@ +/* */ +#ifndef _D_BT_REQUEST_FACTORY_H_ +#define _D_BT_REQUEST_FACTORY_H_ + +#include "common.h" +#include "BtMessage.h" +#include "Piece.h" + +class BtRequestFactory { +public: + virtual ~BtRequestFactory() {} + + virtual void addTargetPiece(const PieceHandle& piece) = 0; + + virtual void removeTargetPiece(const PieceHandle& piece) = 0; + + virtual void removeAllTargetPiece() = 0; + + virtual int countTargetPiece() = 0; + + virtual void removeCompletedPiece() = 0; + + /** + * Creates RequestMessage objects associated to the pieces added by + * addTargetPiece() and returns them. + * The number of objects returned is capped by max. + */ + virtual BtMessages createRequestMessages(int max) = 0; + + /** + * Use this method in end game mode. + * + */ + virtual BtMessages createRequestMessagesOnEndGame(int max) = 0; +}; + +typedef SharedHandle BtRequestFactoryHandle; + +#endif // _D_BT_REQUEST_FACTORY_H_ diff --git a/src/BtRequestMessage.cc b/src/BtRequestMessage.cc new file mode 100644 index 00000000..6dffaa74 --- /dev/null +++ b/src/BtRequestMessage.cc @@ -0,0 +1,129 @@ +/* */ +#include "BtRequestMessage.h" +#include "PeerInteraction.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include "DlAbortEx.h" +#include "BtAbortOutstandingRequestEvent.h" + +BtRequestMessageHandle BtRequestMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 13) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "request", dataLength, 13); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "request", ID); + } + BtRequestMessageHandle message = new BtRequestMessage(); + message->setIndex(PeerMessageUtil::getIntParam(data, 1)); + message->setBegin(PeerMessageUtil::getIntParam(data, 5)); + message->setLength(PeerMessageUtil::getIntParam(data, 9)); + return message; +} + +void BtRequestMessage::doReceivedAction() { + if(pieceStorage->hasPiece(index) && + (!peer->amChoking || + peer->amChoking && peer->isInAmAllowedIndexSet(index))) { + BtMessageHandle msg = + BT_MESSAGE_FACTORY(btContext, peer)->createPieceMessage(index, + begin, + length); + BT_MESSAGE_DISPATCHER(btContext, peer)->addMessageToQueue(msg); + } else { + if(peer->isFastExtensionEnabled()) { + BtMessageHandle msg = + BT_MESSAGE_FACTORY(btContext, peer)->createRejectMessage(index, + begin, + length); + BT_MESSAGE_DISPATCHER(btContext, peer)->addMessageToQueue(msg); + } + } +} + +uint32_t BtRequestMessage::MESSAGE_LENGTH = 17; + +const char* BtRequestMessage::getMessage() { + if(!msg) { + /** + * len --- 13, 4bytes + * id --- 6, 1byte + * index --- index, 4bytes + * begin --- begin, 4bytes + * length --- length, 4bytes + * total: 17bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 13, ID); + PeerMessageUtil::setIntParam(&msg[5], index); + PeerMessageUtil::setIntParam(&msg[9], begin); + PeerMessageUtil::setIntParam(&msg[13], length); + } + return msg; +} + +uint32_t BtRequestMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +string BtRequestMessage::toString() const { + return "request index="+Util::uitos(index)+", begin="+Util::uitos(begin)+ + ", length="+Util::uitos(length); +} + +void BtRequestMessage::onQueued() { + RequestSlot requestSlot(index, begin, length, blockIndex); + BT_MESSAGE_DISPATCHER(btContext, peer)->addOutstandingRequest(requestSlot); +} + +bool BtRequestMessage::BtAbortOutstandingRequestEventListener::canHandle(const BtEventHandle& event) { + BtAbortOutstandingRequestEvent* intEvent = dynamic_cast(event.get()); + return intEvent != 0; +} + +void BtRequestMessage::BtAbortOutstandingRequestEventListener::handleEventInternal(const BtEventHandle& event) { + message->handleAbortOutstandingRequestEvent(event); +} + +void BtRequestMessage::handleAbortOutstandingRequestEvent(const BtEventHandle& event) { + BtAbortOutstandingRequestEvent* intEvent = (BtAbortOutstandingRequestEvent*)event.get(); + if(index == intEvent->getPiece()->getIndex() && + !invalidate && + !sendingInProgress) { + invalidate = true; + } +} diff --git a/src/BtRequestMessage.h b/src/BtRequestMessage.h new file mode 100644 index 00000000..f41b8882 --- /dev/null +++ b/src/BtRequestMessage.h @@ -0,0 +1,117 @@ +/* */ +#ifndef _D_BT_REQUEST_MESSAGE_H_ +#define _D_BT_REQUEST_MESSAGE_H_ + +#include "SimpleBtMessage.h" +#include "BtContext.h" +#include "PieceStorage.h" +#include "AbstractBtEventListener.h" + +class BtRequestMessage; + +typedef SharedHandle BtRequestMessageHandle; + +class BtRequestMessage : public SimpleBtMessage { +private: + uint32_t index; + uint32_t begin; + uint32_t length; + uint32_t blockIndex; + char* msg; + + static uint32_t MESSAGE_LENGTH; + + class BtAbortOutstandingRequestEventListener : public AbstractBtEventListener { + private: + BtRequestMessage* message; + public: + BtAbortOutstandingRequestEventListener(BtRequestMessage* message):message(message) {} + + virtual bool canHandle(const BtEventHandle& event); + + virtual void handleEventInternal(const BtEventHandle& event); + }; + + typedef SharedHandle BtAbortOutstandingRequestEventListenerHandle; +public: + BtRequestMessage(uint32_t index = 0, + uint32_t begin = 0, + uint32_t length = 0, + uint32_t blockIndex = 0) + :index(index), + begin(begin), + length(length), + blockIndex(blockIndex), + msg(0) + { + addEventListener(new BtAbortOutstandingRequestEventListener(this)); + } + + virtual ~BtRequestMessage() { + delete [] msg; + } + + enum ID_t { + ID = 6 + }; + + uint32_t getIndex() const { return index; } + void setIndex(uint32_t index) { this->index = index; } + uint32_t getBegin() const { return begin; } + void setBegin(uint32_t begin) { this->begin = begin; } + uint32_t getLength() const { return length; } + void setLength(uint32_t length) { this->length = length; } + uint32_t getBlockIndex() const { return blockIndex; } + void setBlockIndex(uint32_t blockIndex) { this->blockIndex = blockIndex; } + + static BtRequestMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; + + virtual void onQueued(); + + virtual void handleAbortOutstandingRequestEvent(const BtEventHandle& event); +}; + +#endif // _D_BT_REQUEST_MESSAGE_H_ diff --git a/src/BtRequestMessageValidator.h b/src/BtRequestMessageValidator.h new file mode 100644 index 00000000..baa5731a --- /dev/null +++ b/src/BtRequestMessageValidator.h @@ -0,0 +1,68 @@ +/* */ +#ifndef _D_BT_REQUEST_MESSAGE_VALIDATOR_H_ +#define _D_BT_REQUEST_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtRequestMessage.h" + +class BtRequestMessageValidator : public BtMessageValidator { +private: + const BtRequestMessage* message; + uint32_t numPiece; + uint32_t pieceLength; +public: + BtRequestMessageValidator(const BtRequestMessage* message, + uint32_t numPiece, + uint32_t pieceLength): + message(message), + numPiece(numPiece), + pieceLength(pieceLength) {} + + virtual bool validate(Errors& error) { + // TODO + PeerMessageUtil::checkIndex(message->getIndex(), numPiece); + PeerMessageUtil::checkBegin(message->getBegin(), pieceLength); + PeerMessageUtil::checkLength(message->getLength()); + PeerMessageUtil::checkRange(message->getBegin(), + message->getLength(), + pieceLength); + return true; + } +}; + +typedef SharedHandle BtRequestMessageValidatorHandle; + +#endif // _D_BT_REQUEST_MESSAGE_VALIDATOR_H_ diff --git a/src/BtSuggestPieceMessage.cc b/src/BtSuggestPieceMessage.cc new file mode 100644 index 00000000..615fb99c --- /dev/null +++ b/src/BtSuggestPieceMessage.cc @@ -0,0 +1,78 @@ +/* */ +#include "BtSuggestPieceMessage.h" +#include "PeerInteraction.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include "DlAbortEx.h" + +BtSuggestPieceMessageHandle BtSuggestPieceMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 5) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "suggest piece", dataLength, 5); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "suggest piece", ID); + } + BtSuggestPieceMessageHandle message = new BtSuggestPieceMessage(); + message->setIndex(PeerMessageUtil::getIntParam(data, 1)); + return message; +} + +uint32_t BtSuggestPieceMessage::MESSAGE_LENGTH = 9; + +const char* BtSuggestPieceMessage::getMessage() { + if(!msg) { + /** + * len --- 5, 4bytes + * id --- 13, 1byte + * piece index --- index, 4bytes + * total: 9bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 5, ID); + PeerMessageUtil::setIntParam(&msg[5], index); + } + return msg; +} + +uint32_t BtSuggestPieceMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +string BtSuggestPieceMessage::toString() const { + return "suggest piece index="+Util::uitos(index); +} diff --git a/src/BtSuggestPieceMessage.h b/src/BtSuggestPieceMessage.h new file mode 100644 index 00000000..5143a74a --- /dev/null +++ b/src/BtSuggestPieceMessage.h @@ -0,0 +1,81 @@ +/* */ +#ifndef _D_BT_SUGGEST_PIECE_MESSAGE_H_ +#define _D_BT_SUGGEST_PIECE_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtSuggestPieceMessage; + +typedef SharedHandle BtSuggestPieceMessageHandle; + +class BtSuggestPieceMessage : public SimpleBtMessage { +private: + uint32_t index; + char* msg; + static uint32_t MESSAGE_LENGTH; +public: + BtSuggestPieceMessage():index(0), msg(0) {} + + virtual ~BtSuggestPieceMessage() { + delete [] msg; + } + + enum ID_t { + ID = 13 + }; + + void setIndex(uint32_t index) { + this->index = index; + } + + uint32_t getIndex() const { return index; } + + static BtSuggestPieceMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction() { + // TODO Current implementation ignores this message. + } + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; +}; + +#endif // _D_BT_SUGGEST_PIECE_MESSAGE_H_ diff --git a/src/BtSuggestPieceMessageValidator.h b/src/BtSuggestPieceMessageValidator.h new file mode 100644 index 00000000..293b3c71 --- /dev/null +++ b/src/BtSuggestPieceMessageValidator.h @@ -0,0 +1,60 @@ +/* */ +#ifndef _D_BT_SUGGEST_PIECE_MESSAGE_VALIDATOR_H_ +#define _D_BT_SUGGEST_PIECE_MESSAGE_VALIDATOR_H_ + +#include "BtMessageValidator.h" +#include "BtSuggestPieceMessage.h" + +class BtSuggestPieceMessageValidator : public BtMessageValidator { +private: + const BtSuggestPieceMessage* message; + int numPiece; +public: + BtSuggestPieceMessageValidator(const BtSuggestPieceMessage* message, + int numPiece): + message(message), + numPiece(numPiece) {} + + virtual bool validate(Errors& errors) { + // TODO + PeerMessageUtil::checkIndex(message->getIndex(), numPiece); + return true; + } + +}; + +typedef SharedHandle BtSuggestPieceMessageValidatorHandle; +#endif // _D_BT_SUGGEST_PIECE_MESSAGE_VALIDATOR_H_ diff --git a/src/BtUnchokeMessage.cc b/src/BtUnchokeMessage.cc new file mode 100644 index 00000000..e96d9d96 --- /dev/null +++ b/src/BtUnchokeMessage.cc @@ -0,0 +1,85 @@ +/* */ +#include "BtUnchokeMessage.h" +#include "PeerMessageUtil.h" +#include "DlAbortEx.h" + +BtUnchokeMessageHandle BtUnchokeMessage::create(const unsigned char* data, uint32_t dataLength) { + if(dataLength != 1) { + throw new DlAbortEx("invalid payload size for %s, size = %d. It should be %d", "unchoke", dataLength, 1); + } + int32_t id = PeerMessageUtil::getId(data); + if(id != ID) { + throw new DlAbortEx("invalid ID=%d for %s. It should be %d.", + id, "unchoke", ID); + } + BtUnchokeMessageHandle message = new BtUnchokeMessage(); + return message; +} + +void BtUnchokeMessage::doReceivedAction() { + peer->peerChoking = false; +} + +bool BtUnchokeMessage::sendPredicate() const { + return peer->amChoking; +} + +uint32_t BtUnchokeMessage::MESSAGE_LENGTH = 5; + +const char* BtUnchokeMessage::getMessage() { + if(!msg) { + /** + * len --- 1, 4bytes + * id --- 1, 1byte + * total: 5bytes + */ + msg = new char[MESSAGE_LENGTH]; + PeerMessageUtil::createPeerMessageString(msg, MESSAGE_LENGTH, 1, ID); + } + return msg; +} + +uint32_t BtUnchokeMessage::getMessageLength() { + return MESSAGE_LENGTH; +} + +void BtUnchokeMessage::onSendComplete() { + peer->amChoking = false; +} + +string BtUnchokeMessage::toString() const { + return "unchoke"; +} diff --git a/src/BtUnchokeMessage.h b/src/BtUnchokeMessage.h new file mode 100644 index 00000000..b673621e --- /dev/null +++ b/src/BtUnchokeMessage.h @@ -0,0 +1,76 @@ +/* */ +#ifndef _D_BT_UNCHOKE_MESSAGE_H_ +#define _D_BT_UNCHOKE_MESSAGE_H_ + +#include "SimpleBtMessage.h" + +class BtUnchokeMessage; + +typedef SharedHandle BtUnchokeMessageHandle; + +class BtUnchokeMessage : public SimpleBtMessage { +private: + char* msg; + static uint32_t MESSAGE_LENGTH; +public: + BtUnchokeMessage():msg(0) {} + + virtual ~BtUnchokeMessage() { + delete [] msg; + } + + enum ID_t { + ID = 1 + }; + + static BtUnchokeMessageHandle create(const unsigned char* data, uint32_t dataLength); + + virtual int32_t getId() const { return ID; } + + virtual void doReceivedAction(); + + virtual const char* getMessage(); + + virtual uint32_t getMessageLength(); + + virtual string toString() const; + + virtual bool sendPredicate() const; + + virtual void onSendComplete(); +}; + +#endif // _D_BT_UNCHOKE_MESSAGE_H_ diff --git a/src/DefaultBtAnnounce.cc b/src/DefaultBtAnnounce.cc index 04e069eb..ab9cad07 100644 --- a/src/DefaultBtAnnounce.cc +++ b/src/DefaultBtAnnounce.cc @@ -62,7 +62,6 @@ DefaultBtAnnounce::DefaultBtAnnounce(BtContextHandle btContext, { prevAnnounceTime.setTimeInSec(0); key = generateKey(); - peerId = generatePeerId(); logger = LogFactory::getInstance(); } @@ -73,12 +72,6 @@ string DefaultBtAnnounce::generateKey() const { return Util::randomAlpha(8); } -string DefaultBtAnnounce::generatePeerId() const { - string peerId = "-aria2-"; - peerId += Util::randomAlpha(20-peerId.size()); - return peerId; -} - bool DefaultBtAnnounce::isDefaultAnnounceReady() { return (trackers == 0 && prevAnnounceTime.elapsed(minInterval)); } @@ -131,7 +124,7 @@ string DefaultBtAnnounce::getAnnounceUrl() { string url = announceList.getAnnounce()+"?"+ "info_hash="+Util::torrentUrlencode(btContext->getInfoHash(), btContext->getInfoHashLength())+"&"+ - "peer_id="+peerId+"&"+ + "peer_id="+Util::torrentUrlencode(btContext->getPeerId(), 20)+"&"+ "port="+Util::itos(btRuntime->getListenPort())+"&"+ "uploaded="+Util::llitos(stat.getSessionUploadLength())+"&"+ "downloaded="+Util::llitos(stat.getSessionDownloadLength())+"&"+ diff --git a/src/DefaultBtAnnounce.h b/src/DefaultBtAnnounce.h index f54c1ac9..128c02fd 100644 --- a/src/DefaultBtAnnounce.h +++ b/src/DefaultBtAnnounce.h @@ -60,7 +60,6 @@ private: string trackerId; string key; int trackerNumTry; - string peerId; const Option* option; Logger* logger; BtRuntimeHandle btRuntime; @@ -112,11 +111,7 @@ public: virtual void shuffleAnnounce(); - string generateKey() const; - - string generatePeerId() const; - - virtual string getPeerId() { return peerId; } + string generateKey() const; }; #endif // _D_DEFAULT_BT_ANNOUNCE_H_ diff --git a/src/DefaultBtContext.cc b/src/DefaultBtContext.cc index 1acf5fc5..0235f410 100644 --- a/src/DefaultBtContext.cc +++ b/src/DefaultBtContext.cc @@ -45,6 +45,12 @@ DefaultBtContext::DefaultBtContext() {} DefaultBtContext::~DefaultBtContext() {} +string DefaultBtContext::generatePeerId() const { + string peerId = "-aria2-"; + peerId += Util::randomAlpha(20-peerId.size()); + return peerId; +} + const unsigned char* DefaultBtContext::getInfoHash() const { return infoHash; } diff --git a/src/DefaultBtContext.h b/src/DefaultBtContext.h index 74bae247..4133d7ab 100644 --- a/src/DefaultBtContext.h +++ b/src/DefaultBtContext.h @@ -55,6 +55,7 @@ private: int pieceLength; string name; int numPieces; + string peerId; AnnounceTiers announceTiers; void clear(); @@ -92,6 +93,15 @@ private: virtual int getPieceLength() const; virtual int getNumPieces() const; + + virtual const unsigned char* getPeerId() { + if(peerId == "") { + peerId = generatePeerId(); + } + return (const unsigned char*)peerId.c_str(); + } + + string generatePeerId() const; }; #endif // _D_DEFAULT_BT_CONTEXT_H_ diff --git a/src/DefaultBtInteractive.cc b/src/DefaultBtInteractive.cc new file mode 100644 index 00000000..f3812b01 --- /dev/null +++ b/src/DefaultBtInteractive.cc @@ -0,0 +1,307 @@ +/* */ +#include "DefaultBtInteractive.h" +#include "prefs.h" +#include "message.h" +#include "BtHandshakeMessage.h" +#include "Util.h" +#include "BtKeepAliveMessage.h" +#include "BtChokeMessage.h" +#include "BtUnchokeMessage.h" +#include "DlAbortEx.h" + +void DefaultBtInteractive::initiateHandshake() { + BtMessageHandle message = + BT_MESSAGE_FACTORY(btContext, peer)-> + createHandshakeMessage(btContext->getInfoHash(), + btContext->getPeerId()); + dispatcher->addMessageToQueue(message); + dispatcher->sendMessages(); +} + +BtMessageHandle DefaultBtInteractive::receiveHandshake(bool quickReply) { + BtHandshakeMessageHandle message = + btMessageReceiver->receiveHandshake(quickReply); + if(message.isNull()) { + return 0; + } + peer->setPeerId(message->getPeerId()); + logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid, + peer->ipaddr.c_str(), peer->port, + message->toString().c_str()); + return message; +} + +BtMessageHandle DefaultBtInteractive::receiveAndSendHandshake() { + return receiveHandshake(true); +} + +void DefaultBtInteractive::doPostHandshakeProcessing() { + // TODO where is the valid place to rest haveCheckTime? + haveCheckPoint.reset(); + keepAliveCheckPoint.reset(); + floodingCheckPoint.reset(); + addBitfieldMessageToQueue(); + addAllowedFastMessageToQueue(); +} + +void DefaultBtInteractive::addBitfieldMessageToQueue() { + BtMessageFactoryHandle factory = BT_MESSAGE_FACTORY(btContext, peer); + if(peer->isFastExtensionEnabled()) { + if(pieceStorage->downloadFinished()) { + dispatcher->addMessageToQueue(factory->createHaveAllMessage()); + } else if(pieceStorage->getCompletedLength() > 0) { + dispatcher->addMessageToQueue(factory->createBitfieldMessage()); + } else { + dispatcher->addMessageToQueue(factory->createHaveNoneMessage()); + } + } else { + if(pieceStorage->getCompletedLength() > 0) { + dispatcher->addMessageToQueue(factory->createBitfieldMessage()); + } + } +} + +void DefaultBtInteractive::addAllowedFastMessageToQueue() { + if(peer->isFastExtensionEnabled()) { + Integers fastSet = Util::computeFastSet(peer->ipaddr, + btContext->getInfoHash(), + btContext->getNumPieces(), + allowedFastSetSize); + for(Integers::const_iterator itr = fastSet.begin(); + itr != fastSet.end(); itr++) { + dispatcher->addMessageToQueue(BT_MESSAGE_FACTORY(btContext, peer)-> + createAllowedFastMessage(*itr)); + } + } +} + +void DefaultBtInteractive::decideChoking() { + if(peer->shouldBeChoking()) { + if(!peer->amChoking) { + dispatcher->addMessageToQueue(BT_MESSAGE_FACTORY(btContext, peer)-> + createChokeMessage()); + } + } else { + if(peer->amChoking) { + dispatcher->addMessageToQueue(BT_MESSAGE_FACTORY(btContext, peer)-> + createUnchokeMessage()); + } + } +} + +void DefaultBtInteractive::checkHave() { + BtMessageFactoryHandle factory = BT_MESSAGE_FACTORY(btContext, peer); + Integers indexes = + pieceStorage->getAdvertisedPieceIndexes(cuid, haveCheckPoint); + haveCheckPoint.reset(); + if(indexes.size() >= 20) { + if(peer->isFastExtensionEnabled() && pieceStorage->downloadFinished()) { + dispatcher->addMessageToQueue(factory->createHaveAllMessage()); + } else { + dispatcher->addMessageToQueue(factory->createBitfieldMessage()); + } + } else { + for(Integers::iterator itr = indexes.begin(); itr != indexes.end(); itr++) { + dispatcher->addMessageToQueue(factory->createHaveMessage(*itr)); + } + } +} + +void DefaultBtInteractive::sendKeepAlive() { + if(keepAliveCheckPoint.elapsed(option->getAsInt(PREF_BT_KEEP_ALIVE_INTERVAL))) { + if(dispatcher->countMessageInQueue() == 0) { + dispatcher->addMessageToQueue(BT_MESSAGE_FACTORY(btContext, peer)->createKeepAliveMessage()); + dispatcher->sendMessages(); + } + keepAliveCheckPoint.reset(); + } +} + +void DefaultBtInteractive::receiveMessages() { + for(int i = 0; i < 50; i++) { + int maxSpeedLimit = option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT); + if(maxSpeedLimit > 0) { + TransferStat stat = peerStorage->calculateStat(); + if(maxSpeedLimit < stat.downloadSpeed) { + break; + } + } + BtMessageHandle message = btMessageReceiver->receiveMessage(); + if(message.isNull()) { + break; + } + logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid, + peer->ipaddr.c_str(), peer->port, + message->toString().c_str()); + message->doReceivedAction(); + + switch(message->getId()) { + case BtKeepAliveMessage::ID: + floodingStat.incKeepAliveCount(); + break; + case BtChokeMessage::ID: + if(!peer->peerChoking) { + floodingStat.incChokeUnchokeCount(); + } + break; + case BtUnchokeMessage::ID: + if(peer->peerChoking) { + floodingStat.incChokeUnchokeCount(); + } + break; + } + } +} + +void DefaultBtInteractive::decideInterest() { + if(!pieceStorage->hasMissingPiece(peer)) { + if(peer->amInterested) { + logger->debug("CUID#%d - Not interested in the peer", cuid); + dispatcher-> + addMessageToQueue(BT_MESSAGE_FACTORY(btContext, peer)-> + createNotInterestedMessage()); + } + } else { + if(!peer->amInterested) { + logger->debug("CUID#%d - Interested in the peer", cuid); + dispatcher-> + addMessageToQueue(BT_MESSAGE_FACTORY(btContext, peer)-> + createInterestedMessage()); + } + } +} + +void DefaultBtInteractive::fillPiece(int maxPieceNum) { + if(pieceStorage->hasMissingPiece(peer)) { + if(peer->peerChoking) { + dispatcher->doChokedAction(); + if(peer->isFastExtensionEnabled()) { + while(btRequestFactory->countTargetPiece() < maxPieceNum) { + PieceHandle piece = pieceStorage->getMissingFastPiece(peer); + if(piece.isNull()) { + break; + } else { + btRequestFactory->addTargetPiece(piece); + } + } + } + } else { + while(btRequestFactory->countTargetPiece() < maxPieceNum) { + PieceHandle piece = pieceStorage->getMissingPiece(peer); + if(piece.isNull()) { + break; + } else { + btRequestFactory->addTargetPiece(piece); + } + } + } + } +} + +void DefaultBtInteractive::addRequests() { + uint32_t MAX_PENDING_REQUEST; + if(peer->getLatency() < 500) { + MAX_PENDING_REQUEST = 24; + } else if(peer->getLatency() < 1500) { + MAX_PENDING_REQUEST = 12; + } else { + MAX_PENDING_REQUEST = 6; + } + uint32_t pieceNum; + if(pieceStorage->isEndGame()) { + pieceNum = 1; + } else { + uint32_t blocks = DIV_FLOOR(btContext->getPieceLength(), BLOCK_LENGTH); + pieceNum = DIV_FLOOR(MAX_PENDING_REQUEST, blocks); + } + fillPiece(pieceNum); + + uint32_t reqNumToCreate = + MAX_PENDING_REQUEST <= dispatcher->countOutstandingRequest() ? + 0 : MAX_PENDING_REQUEST-dispatcher->countOutstandingRequest(); + if(reqNumToCreate > 0) { + //logger->debug("CUID#%d - %u requets to go.", cuid, reqNumToCreate); + BtMessages requests; + if(pieceStorage->isEndGame()) { + requests = btRequestFactory->createRequestMessagesOnEndGame(reqNumToCreate); + } else { + requests = btRequestFactory->createRequestMessages(reqNumToCreate); + } + dispatcher->addMessageToQueue(requests); + } +} + +void DefaultBtInteractive::cancelAllPiece() { + btRequestFactory->removeAllTargetPiece(); +} + +void DefaultBtInteractive::sendPendingMessage() { + dispatcher->sendMessages(); +} + +void DefaultBtInteractive::detectMessageFlooding() { + if(floodingCheckPoint.elapsed(FLOODING_CHECK_INTERVAL)) { + if(floodingStat.getChokeUnchokeCount() >= 2 || + floodingStat.getKeepAliveCount() >= 2) { + throw new DlAbortEx("Flooding detected."); + } else { + floodingStat.reset(); + } + floodingCheckPoint.reset(); + } +} + +void DefaultBtInteractive::doInteractionProcessing() { + decideChoking(); + + detectMessageFlooding(); + + dispatcher->checkRequestSlotAndDoNecessaryThing(); + + checkHave(); + + sendKeepAlive(); + + receiveMessages(); + + btRequestFactory->removeCompletedPiece(); + + decideInterest(); + if(!pieceStorage->downloadFinished()) { + addRequests(); + } + sendPendingMessage(); +} diff --git a/src/DefaultBtInteractive.h b/src/DefaultBtInteractive.h new file mode 100644 index 00000000..cc6f99a9 --- /dev/null +++ b/src/DefaultBtInteractive.h @@ -0,0 +1,195 @@ +/* */ +#ifndef _D_DEFAULT_BT_INTERACTIVE_H_ +#define _D_DEFAULT_BT_INTERACTIVE_H_ + +#include "BtInteractive.h" +#include "Peer.h" +#include "BtContext.h" +#include "PieceStorage.h" +#include "PeerStorage.h" +#include "BtMessageReceiver.h" +#include "BtMessageDispatcher.h" +#include "BtRequestFactory.h" +#include "PeerConnection.h" +#include "BtRegistry.h" +#include "Logger.h" +#include "LogFactory.h" +#include "TimeA2.h" + +class FloodingStat { +private: + uint32_t chokeUnchokeCount; + uint32_t keepAliveCount; +public: + FloodingStat():chokeUnchokeCount(0), keepAliveCount(0) {} + + void incChokeUnchokeCount() { + if(chokeUnchokeCount < UINT32_MAX) { + chokeUnchokeCount++; + } + } + + void incKeepAliveCount() { + if(keepAliveCount < UINT32_MAX) { + keepAliveCount++; + } + } + + uint32_t getChokeUnchokeCount() const { + return chokeUnchokeCount; + } + + uint32_t getKeepAliveCount() const { + return keepAliveCount; + } + + void reset() { + chokeUnchokeCount = 0; + keepAliveCount = 0; + } +}; + +class DefaultBtInteractive : public BtInteractive { +private: + int32_t cuid; + PeerHandle peer; + BtContextHandle btContext; + PeerStorageHandle peerStorage; + PieceStorageHandle pieceStorage; + BtMessageReceiverHandle btMessageReceiver; + BtMessageDispatcherHandle dispatcher; + BtRequestFactoryHandle btRequestFactory; + PeerConnectionHandle peerConnection; + const Logger* logger; + uint32_t allowedFastSetSize; + Time haveCheckPoint; + Time keepAliveCheckPoint; + Time floodingCheckPoint; + FloodingStat floodingStat; + const Option* option; + + static const uint32_t FLOODING_CHECK_INTERVAL = 5; + + void addBitfieldMessageToQueue(); + void addAllowedFastMessageToQueue(); + void decideChoking(); + void checkHave(); + void sendKeepAlive(); + void decideInterest(); + void fillPiece(int maxPieceNum); + void addRequests(); + void detectMessageFlooding(); +public: + DefaultBtInteractive():peer(0), + btContext(0), + peerStorage(0), + pieceStorage(0), + btMessageReceiver(0), + dispatcher(0), + btRequestFactory(0), + peerConnection(0), + logger(LogFactory::getInstance()), + allowedFastSetSize(10) + { + logger->debug("DefaultBtInteractive instantiated."); + } + + virtual ~DefaultBtInteractive() { + logger->debug("DefaultBtInteractive deleted."); + } + + virtual void initiateHandshake(); + + virtual BtMessageHandle receiveHandshake(bool quickReply = false); + + virtual BtMessageHandle receiveAndSendHandshake(); + + virtual void doPostHandshakeProcessing(); + + virtual void doInteractionProcessing(); + + virtual void cancelAllPiece(); + + virtual void sendPendingMessage(); + + void receiveMessages(); + + virtual uint32_t countPendingMessage() { + return dispatcher->countMessageInQueue(); + } + + virtual bool isSendingMessageInProgress() { + return dispatcher->isSendingInProgress(); + } + + void setCuid(int32_t cuid) { + this->cuid = cuid; + } + + void setPeer(const PeerHandle& peer) { + this->peer = peer; + } + + void setBtContext(const BtContextHandle& btContext) { + this->btContext = btContext; + this->peerStorage = PEER_STORAGE(btContext); + this->pieceStorage = PIECE_STORAGE(btContext); + } + + void setBtMessageReceiver(const BtMessageReceiverHandle& receiver) { + this->btMessageReceiver = receiver; + } + + void setDispatcher(const BtMessageDispatcherHandle& dispatcher) { + this->dispatcher = dispatcher; + } + + void setBtRequestFactory(const BtRequestFactoryHandle& factory) { + this->btRequestFactory = factory; + } + + void setPeerConnection(const PeerConnectionHandle& peerConnection) { + this->peerConnection = peerConnection; + } + + void setOption(const Option* option) { + this->option = option; + } +}; + +typedef SharedHandle DefaultBtInteractiveHandle; + +#endif // _D_DEFAULT_BT_INTERACTIVE_H_ diff --git a/src/DefaultBtMessageDispatcher.cc b/src/DefaultBtMessageDispatcher.cc new file mode 100644 index 00000000..18d0dbc0 --- /dev/null +++ b/src/DefaultBtMessageDispatcher.cc @@ -0,0 +1,214 @@ +/* */ +#include "DefaultBtMessageDispatcher.h" +#include "BtRegistry.h" +#include "prefs.h" +#include "BtAbortOutstandingRequestEvent.h" +#include "BtCancelSendingPieceEvent.h" +#include "BtChokedEvent.h" +#include "BtChokingEvent.h" +#include "BtRegistry.h" +#include "BtMessageFactory.h" + +void DefaultBtMessageDispatcher::addMessageToQueue(const BtMessageHandle& btMessage) +{ + btMessage->onQueued(); + messageQueue.push_back(btMessage); +} + +void DefaultBtMessageDispatcher::addMessageToQueue(const BtMessages& btMessages) +{ + for(BtMessages::const_iterator itr = btMessages.begin(); itr != btMessages.end(); itr++) { + addMessageToQueue(*itr); + } +} + + +void DefaultBtMessageDispatcher::sendMessages() { + BtMessages tempQueue; + int32_t uploadLimit = option->getAsInt(PREF_MAX_UPLOAD_LIMIT); + while(messageQueue.size() > 0) { + BtMessageHandle msg = messageQueue.front(); + messageQueue.pop_front(); + if(uploadLimit > 0) { + TransferStat stat = peerStorage->calculateStat(); + if(uploadLimit < stat.getUploadSpeed() && + msg->isUploading() && !msg->isSendingInProgress()) { + tempQueue.push_back(msg); + continue; + } + } + msg->send(); + if(msg->isSendingInProgress()) { + messageQueue.push_front(msg); + break; + } + } + copy(tempQueue.begin(), tempQueue.end(), back_inserter(messageQueue)); +} + +// Cancel sending piece message to peer. +void DefaultBtMessageDispatcher::doCancelSendingPieceAction(uint32_t index, uint32_t begin, uint32_t blockLength) +{ + BtCancelSendingPieceEventHandle event = + new BtCancelSendingPieceEvent(index, begin, blockLength); + + BtMessages tempQueue = messageQueue; + for(BtMessages::iterator itr = tempQueue.begin(); itr != tempQueue.end(); itr++) { + (*itr)->handleEvent(event); + } +} + +// Cancel sending piece message to peer. +// TODO Is this method really necessary? +void DefaultBtMessageDispatcher::doCancelSendingPieceAction(const PieceHandle& piece) +{ +} + +// localhost cancels outstanding download requests to the peer. +void DefaultBtMessageDispatcher::doAbortOutstandingRequestAction(const PieceHandle& piece) { + for(RequestSlots::iterator itr = requestSlots.begin(); + itr != requestSlots.end();) { + RequestSlot& slot = *itr; + if(slot.getIndex() == piece->getIndex()) { + logger->debug("CUID#%d - Deleting request slot index=%d, blockIndex=%d", + cuid, + slot.getIndex(), + slot.getBlockIndex()); + piece->cancelBlock(slot.getBlockIndex()); + itr = requestSlots.erase(itr); + } else { + itr++; + } + } + + BtAbortOutstandingRequestEventHandle event = + new BtAbortOutstandingRequestEvent(piece); + + BtMessages tempQueue = messageQueue; + for(BtMessages::iterator itr = tempQueue.begin(); itr != tempQueue.end(); ++itr) { + (*itr)->handleEvent(event); + } +} + +// localhost received choke message from the peer. +void DefaultBtMessageDispatcher::doChokedAction() +{ + for(RequestSlots::iterator itr = requestSlots.begin(); + itr != requestSlots.end();) { + RequestSlot& slot = *itr; + logger->debug("CUID#%d - Deleting request slot index=%d, blockIndex=%d" + " because localhost got choked.", + cuid, + slot.getIndex(), + slot.getBlockIndex()); + PieceHandle piece = pieceStorage->getPiece(slot.getIndex()); + piece->cancelBlock(slot.getBlockIndex()); + itr = requestSlots.erase(itr); + } + + BtChokedEventHandle event = new BtChokedEvent(); + + BtMessages tempQueue = messageQueue; + for(BtMessages::iterator itr = tempQueue.begin(); itr != tempQueue.end(); ++itr) { + (*itr)->handleEvent(event); + } +} + +// localhost dispatched choke message to the peer. +void DefaultBtMessageDispatcher::doChokingAction() +{ + BtChokingEventHandle event = new BtChokingEvent(); + + BtMessages tempQueue = messageQueue; + for(BtMessages::iterator itr = tempQueue.begin(); itr != tempQueue.end(); ++itr) { + (*itr)->handleEvent(event); + } +} + +void DefaultBtMessageDispatcher::checkRequestSlotAndDoNecessaryThing() +{ + for(RequestSlots::iterator itr = requestSlots.begin(); + itr != requestSlots.end();) { + RequestSlot& slot = *itr; + PieceHandle piece = pieceStorage->getPiece(slot.getIndex()); + if(slot.isTimeout(option->getAsInt(PREF_BT_REQUEST_TIMEOUT))) { + logger->debug("CUID#%d - Deleting request slot blockIndex=%d" + " because of time out", + cuid, + slot.getBlockIndex()); + piece->cancelBlock(slot.getBlockIndex()); + peer->snubbing = true; + itr = requestSlots.erase(itr); + } else if(piece->hasBlock(slot.getBlockIndex())) { + logger->debug("CUID#%d - Deleting request slot blockIndex=%d because" + " the block has been acquired.", + cuid, + slot.getBlockIndex()); + addMessageToQueue(BT_MESSAGE_FACTORY(btContext, peer)-> + createCancelMessage(slot.getIndex(), + slot.getBegin(), + slot.getLength())); + itr = requestSlots.erase(itr); + } else { + itr++; + } + } +} + +bool DefaultBtMessageDispatcher::isSendingInProgress() +{ + if(messageQueue.size() > 0) { + return messageQueue.front()->isSendingInProgress(); + } else { + return false; + } +} + +uint32_t DefaultBtMessageDispatcher::countOutstandingRequest() +{ + return requestSlots.size(); +} + +bool DefaultBtMessageDispatcher::isOutstandingRequest(uint32_t index, uint32_t blockIndex) { + for(RequestSlots::const_iterator itr = requestSlots.begin(); + itr != requestSlots.end(); itr++) { + const RequestSlot& slot = *itr; + if(slot.getIndex() == index && slot.getBlockIndex() == blockIndex) { + return true; + } + } + return false; +} diff --git a/src/DefaultBtMessageDispatcher.h b/src/DefaultBtMessageDispatcher.h new file mode 100644 index 00000000..de325f65 --- /dev/null +++ b/src/DefaultBtMessageDispatcher.h @@ -0,0 +1,163 @@ +/* */ +#ifndef _D_DEFAULT_BT_MESSAGE_DISPATCHER_H_ +#define _D_DEFAULT_BT_MESSAGE_DISPATCHER_H_ + +#include "BtMessageDispatcher.h" +#include "BtContext.h" +#include "PeerStorage.h" +#include "PieceStorage.h" +#include "RequestSlot.h" +#include "BtMessage.h" +#include "Peer.h" +#include "Option.h" +#include "LogFactory.h" +#include "Logger.h" +#include "BtRegistry.h" + +class DefaultBtMessageDispatcher : public BtMessageDispatcher { +private: + int32_t cuid; + BtMessages messageQueue; + RequestSlots requestSlots; + BtContextHandle btContext; + PeerStorageHandle peerStorage; + PieceStorageHandle pieceStorage; + PeerHandle peer; + const Option* option; + const Logger* logger; +public: + DefaultBtMessageDispatcher(): + cuid(0), + btContext(0), + peerStorage(0), + pieceStorage(0), + peer(0), + option(0), + logger(LogFactory::getInstance()) + { + logger->debug("DefaultBtMessageDispatcher::instantiated"); + } + + virtual ~DefaultBtMessageDispatcher() + { + logger->debug("DefaultBtMessageDispatcher::deleted"); + } + + virtual void addMessageToQueue(const BtMessageHandle& btMessage); + + virtual void addMessageToQueue(const BtMessages& btMessages); + + virtual void sendMessages(); + + virtual void doCancelSendingPieceAction(uint32_t index, uint32_t begin, uint32_t blockLength); + + virtual void doCancelSendingPieceAction(const PieceHandle& piece); + + virtual void doAbortOutstandingRequestAction(const PieceHandle& piece); + + virtual void doChokedAction(); + + virtual void doChokingAction(); + + virtual void checkRequestSlotAndDoNecessaryThing(); + + virtual bool isSendingInProgress(); + + virtual uint32_t countMessageInQueue() { + return messageQueue.size(); + } + + virtual uint32_t countOutstandingRequest(); + + virtual bool isOutstandingRequest(uint32_t index, uint32_t blockIndex); + + virtual RequestSlot getOutstandingRequest(uint32_t index, uint32_t begin, uint32_t blockLength) { + for(RequestSlots::iterator itr = requestSlots.begin(); + itr != requestSlots.end(); itr++) { + if(itr->getIndex() == index && + itr->getBegin() == begin && + itr->getLength() == blockLength) { + return *itr; + } + } + return RequestSlot::nullSlot; + } + + virtual void removeOutstandingRequest(const RequestSlot& slot) { + RequestSlots temp; + remove_copy(requestSlots.begin(), requestSlots.end(), back_inserter(temp), slot); + requestSlots = temp; + } + + virtual void addOutstandingRequest(const RequestSlot& requestSlot) { + if(!isOutstandingRequest(requestSlot.getIndex(), requestSlot.getBlockIndex())) { + requestSlots.push_back(requestSlot); + } + } + + BtMessages& getMessageQueue() { + return messageQueue; + } + + void setOption(const Option* option) { + this->option = option; + } + + const Option* getOption() const { + return option; + } + + RequestSlots& getRequestSlots() { + return requestSlots; + } + + void setPeer(const PeerHandle& peer) { + this->peer = peer; + } + + void setBtContext(const BtContextHandle& btContext) { + this->btContext = btContext; + this->pieceStorage = PIECE_STORAGE(btContext); + this->peerStorage = PEER_STORAGE(btContext); + } + + void setCuid(int32_t cuid) { + this->cuid = cuid; + } +}; + +typedef SharedHandle DefaultBtMessageDispatcherHandle; +#endif // _D_DEFAULT_BT_MESSAGE_DISPATCHER_H_ diff --git a/src/DefaultBtMessageFactory.cc b/src/DefaultBtMessageFactory.cc new file mode 100644 index 00000000..219635be --- /dev/null +++ b/src/DefaultBtMessageFactory.cc @@ -0,0 +1,347 @@ +/* */ +#include "DefaultBtMessageFactory.h" +#include "DlAbortEx.h" +#include "PeerMessageUtil.h" +#include "BtKeepAliveMessage.h" +#include "BtChokeMessage.h" +#include "BtUnchokeMessage.h" +#include "BtInterestedMessage.h" +#include "BtNotInterestedMessage.h" +#include "BtHaveMessage.h" +#include "BtHaveMessageValidator.h" +#include "BtBitfieldMessage.h" +#include "BtBitfieldMessageValidator.h" +#include "BtRequestMessage.h" +#include "BtRequestMessageValidator.h" +#include "BtCancelMessage.h" +#include "BtCancelMessageValidator.h" +#include "BtPieceMessage.h" +#include "BtPieceMessageValidator.h" +#include "BtPortMessage.h" +#include "BtHaveAllMessage.h" +#include "BtHaveNoneMessage.h" +#include "BtRejectMessage.h" +#include "BtRejectMessageValidator.h" +#include "BtSuggestPieceMessage.h" +#include "BtSuggestPieceMessageValidator.h" +#include "BtAllowedFastMessage.h" +#include "BtAllowedFastMessageValidator.h" +#include "BtHandshakeMessage.h" +#include "BtHandshakeMessageValidator.h" + +BtMessageHandle +DefaultBtMessageFactory::createBtMessage(const unsigned char* data, uint32_t dataLength) +{ + AbstractBtMessageHandle msg(0); + if(dataLength == 0) { + // keep-alive + msg = new BtKeepAliveMessage(); + } else { + int32_t id = PeerMessageUtil::getId(data); + switch(id) { + case BtChokeMessage::ID: + msg = BtChokeMessage::create(data, dataLength); + break; + case BtUnchokeMessage::ID: + msg = BtUnchokeMessage::create(data, dataLength); + break; + case BtInterestedMessage::ID: + msg = BtInterestedMessage::create(data, dataLength); + break; + case BtNotInterestedMessage::ID: + msg = BtNotInterestedMessage::create(data, dataLength); + break; + case BtHaveMessage::ID: + msg = BtHaveMessage::create(data, dataLength); + msg->setBtMessageValidator(new BtHaveMessageValidator((BtHaveMessage*)msg.get(), + btContext->getNumPieces())); + break; + case BtBitfieldMessage::ID: + msg = BtBitfieldMessage::create(data, dataLength); + msg->setBtMessageValidator(new BtBitfieldMessageValidator((BtBitfieldMessage*)msg.get(), + btContext->getNumPieces())); + break; + case BtRequestMessage::ID: { + BtRequestMessageHandle temp = BtRequestMessage::create(data, dataLength); + BtMessageValidatorHandle validator = + new BtRequestMessageValidator(temp.get(), + btContext->getNumPieces(), + pieceStorage->getPieceLength(temp->getIndex())); + temp->setBtMessageValidator(validator); + msg = temp; + break; + } + case BtCancelMessage::ID: { + BtCancelMessageHandle temp = BtCancelMessage::create(data, dataLength); + BtMessageValidatorHandle validator = + new BtCancelMessageValidator(temp.get(), + btContext->getNumPieces(), + pieceStorage->getPieceLength(temp->getIndex())); + temp->setBtMessageValidator(validator); + msg = temp; + break; + } + case BtPieceMessage::ID: { + BtPieceMessageHandle temp = BtPieceMessage::create(data, dataLength); + BtMessageValidatorHandle validator = + new BtPieceMessageValidator(temp.get(), + btContext->getNumPieces(), + pieceStorage->getPieceLength(temp->getIndex())); + temp->setBtMessageValidator(validator); + msg = temp; + break; + } + case BtPortMessage::ID: + msg = BtPortMessage::create(data, dataLength); + break; + case BtHaveAllMessage::ID: + msg = BtHaveAllMessage::create(data, dataLength); + break; + case BtHaveNoneMessage::ID: + msg = BtHaveNoneMessage::create(data, dataLength); + break; + case BtRejectMessage::ID: { + BtRejectMessageHandle temp = BtRejectMessage::create(data, dataLength); + BtMessageValidatorHandle validator = + new BtRejectMessageValidator(temp.get(), + btContext->getNumPieces(), + pieceStorage->getPieceLength(temp->getIndex())); + temp->setBtMessageValidator(validator); + msg = temp; + break; + } + case BtSuggestPieceMessage::ID: { + BtSuggestPieceMessageHandle temp = BtSuggestPieceMessage::create(data, dataLength); + BtMessageValidatorHandle validator = + new BtSuggestPieceMessageValidator(temp.get(), + btContext->getNumPieces()); + temp->setBtMessageValidator(validator); + msg = temp; + break; + } + case BtAllowedFastMessage::ID: { + BtAllowedFastMessageHandle temp = BtAllowedFastMessage::create(data, dataLength); + BtMessageValidatorHandle validator = + new BtAllowedFastMessageValidator(temp.get(), + btContext->getNumPieces()); + temp->setBtMessageValidator(validator); + msg = temp; + break; + } + default: + throw new DlAbortEx("Invalid message id. id = %d", id); + } + } + setCommonProperty(msg); + return msg; +} + +void DefaultBtMessageFactory::setCommonProperty(const AbstractBtMessageHandle& msg) { + msg->setCuid(cuid); + msg->setPeer(peer); + msg->setBtContext(btContext); +} + +BtMessageHandle +DefaultBtMessageFactory::createHandshakeMessage(const unsigned char* data, uint32_t dataLength) +{ + BtHandshakeMessageHandle msg = BtHandshakeMessage::create(data, dataLength); + BtMessageValidatorHandle validator = + new BtHandshakeMessageValidator(msg.get(), + btContext->getInfoHash()); + msg->setBtMessageValidator(validator); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createHandshakeMessage(const unsigned char* infoHash, + const unsigned char* peerId) +{ + BtHandshakeMessageHandle msg = new BtHandshakeMessage(infoHash, peerId); + BtMessageValidatorHandle validator = + new BtHandshakeMessageValidator(msg.get(), + btContext->getInfoHash()); + msg->setBtMessageValidator(validator); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createRequestMessage(const PieceHandle& piece, uint32_t blockIndex) +{ + BtRequestMessageHandle msg = + new BtRequestMessage(piece->getIndex(), + blockIndex*piece->getBlockLength(), + piece->getBlockLength(blockIndex), + blockIndex); + BtMessageValidatorHandle validator = + new BtRequestMessageValidator(msg.get(), + btContext->getNumPieces(), + pieceStorage->getPieceLength(msg->getIndex())); + msg->setBtMessageValidator(validator); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createCancelMessage(uint32_t index, uint32_t begin, uint32_t length) +{ + BtCancelMessageHandle msg = new BtCancelMessage(index, begin, length); + BtMessageValidatorHandle validator = + new BtCancelMessageValidator(msg.get(), + btContext->getNumPieces(), + pieceStorage->getPieceLength(index)); + msg->setBtMessageValidator(validator); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createPieceMessage(uint32_t index, uint32_t begin, uint32_t length) +{ + BtPieceMessageHandle msg = new BtPieceMessage(index, begin, length); + BtMessageValidatorHandle validator = + new BtPieceMessageValidator(msg.get(), + btContext->getNumPieces(), + pieceStorage->getPieceLength(index)); + msg->setBtMessageValidator(validator); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createHaveMessage(uint32_t index) +{ + BtHaveMessageHandle msg = new BtHaveMessage(index); + msg->setBtMessageValidator(new BtHaveMessageValidator(msg.get(), + btContext->getNumPieces())); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createChokeMessage() +{ + BtChokeMessageHandle msg = new BtChokeMessage(); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createUnchokeMessage() +{ + BtUnchokeMessageHandle msg = new BtUnchokeMessage(); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createInterestedMessage() +{ + BtInterestedMessageHandle msg = new BtInterestedMessage(); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createNotInterestedMessage() +{ + BtNotInterestedMessageHandle msg = new BtNotInterestedMessage(); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createBitfieldMessage() +{ + BtBitfieldMessageHandle msg = + new BtBitfieldMessage(pieceStorage->getBitfield(), + pieceStorage->getBitfieldLength()); + msg->setBtMessageValidator(new BtBitfieldMessageValidator(msg.get(), + btContext->getNumPieces())); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createKeepAliveMessage() +{ + BtKeepAliveMessageHandle msg = new BtKeepAliveMessage(); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createHaveAllMessage() +{ + BtHaveAllMessageHandle msg = new BtHaveAllMessage(); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createHaveNoneMessage() +{ + BtHaveNoneMessageHandle msg = new BtHaveNoneMessage(); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createRejectMessage(uint32_t index, uint32_t begin, uint32_t length) +{ + BtRejectMessageHandle msg = new BtRejectMessage(index, begin, length); + BtMessageValidatorHandle validator = + new BtRejectMessageValidator(msg.get(), + btContext->getNumPieces(), + pieceStorage->getPieceLength(index)); + msg->setBtMessageValidator(validator); + setCommonProperty(msg); + return msg; +} + +BtMessageHandle +DefaultBtMessageFactory::createAllowedFastMessage(uint32_t index) +{ + BtAllowedFastMessageHandle msg = new BtAllowedFastMessage(index); + BtMessageValidatorHandle validator = + new BtAllowedFastMessageValidator(msg.get(), + btContext->getNumPieces()); + msg->setBtMessageValidator(validator); + setCommonProperty(msg); + return msg; +} diff --git a/src/DefaultBtMessageFactory.h b/src/DefaultBtMessageFactory.h new file mode 100644 index 00000000..b0e4b14e --- /dev/null +++ b/src/DefaultBtMessageFactory.h @@ -0,0 +1,131 @@ +/* */ +#ifndef _D_DEFAULT_BT_MESSAGE_FACTORY_H_ +#define _D_DEFAULT_BT_MESSAGE_FACTORY_H_ + +#include "BtMessageFactory.h" +#include "Peer.h" +#include "AbstractBtMessage.h" +#include "BtRegistry.h" + +class DefaultBtMessageFactory : public BtMessageFactory { +private: + int32_t cuid; + BtContextHandle btContext; + PieceStorageHandle pieceStorage; + PeerHandle peer; + + void setCommonProperty(const AbstractBtMessageHandle& msg); +public: + DefaultBtMessageFactory():cuid(0), + btContext(0), + pieceStorage(0), + peer(0) + { + LogFactory::getInstance()->debug("DefaultBtMessageFactory::instantiated"); + } + + virtual ~DefaultBtMessageFactory() + { + LogFactory::getInstance()->debug("DefaultBtMessageFactory::deleted"); + } + + virtual BtMessageHandle + createBtMessage(const unsigned char* msg, uint32_t msgLength); + + virtual BtMessageHandle + createHandshakeMessage(const unsigned char* msg, uint32_t msgLength); + + virtual BtMessageHandle + createHandshakeMessage(const unsigned char* infoHash, + const unsigned char* peerId); + + virtual BtMessageHandle + createRequestMessage(const PieceHandle& piece, uint32_t blockIndex); + + virtual BtMessageHandle + createCancelMessage(uint32_t index, uint32_t begin, uint32_t length); + + virtual BtMessageHandle + createPieceMessage(uint32_t index, uint32_t begin, uint32_t length); + + virtual BtMessageHandle createHaveMessage(uint32_t index); + + virtual BtMessageHandle createChokeMessage(); + + virtual BtMessageHandle createUnchokeMessage(); + + virtual BtMessageHandle createInterestedMessage(); + + virtual BtMessageHandle createNotInterestedMessage(); + + virtual BtMessageHandle createBitfieldMessage(); + + virtual BtMessageHandle createKeepAliveMessage(); + + virtual BtMessageHandle createHaveAllMessage(); + + virtual BtMessageHandle createHaveNoneMessage(); + + virtual BtMessageHandle + createRejectMessage(uint32_t index, uint32_t begin, uint32_t length); + + virtual BtMessageHandle createAllowedFastMessage(uint32_t index); + + void setPeer(const PeerHandle& peer) { + this->peer = peer; + } + + PeerHandle getPeer() const { + return peer; + } + + void setBtContext(const BtContextHandle& btContext) { + this->btContext = btContext; + this->pieceStorage = PIECE_STORAGE(btContext); + } + + BtContextHandle getBtContext() const { + return btContext; + } + + void setCuid(int32_t cuid) { + this->cuid = cuid; + } +}; + +typedef SharedHandle DefaultBtMessageFactoryHandle; + +#endif // _D_DEFAULT_BT_MESSAGE_FACTORY_H_ diff --git a/src/DefaultBtMessageReceiver.cc b/src/DefaultBtMessageReceiver.cc new file mode 100644 index 00000000..119404fb --- /dev/null +++ b/src/DefaultBtMessageReceiver.cc @@ -0,0 +1,95 @@ +/* */ +#include "DefaultBtMessageReceiver.h" +#include "BtHandshakeMessage.h" + +BtMessageHandle DefaultBtMessageReceiver::receiveHandshake(bool quickReply) { + unsigned char data[BtHandshakeMessage::MESSAGE_LENGTH]; + uint32_t dataLength = sizeof(data); + bool retval = peerConnection->receiveHandshake(data, dataLength); + // To handle tracker's NAT-checking feature + if(!handshakeSent && quickReply && dataLength >= 48) { + handshakeSent = true; + // check info_hash + if(memcmp(btContext->getInfoHash(), &data[28], INFO_HASH_LENGTH) == 0) { + sendHandshake(); + } + } + if(!retval) { + return 0; + } + BtHandshakeMessageHandle msg = + BT_MESSAGE_FACTORY(btContext, peer)->createHandshakeMessage(data, dataLength); + Errors errors; + if(msg->validate(errors)) { + if(msg->isFastExtensionSupported()) { + peer->setFastExtensionEnabled(true); + logger->info("CUID#%d - Fast extension enabled.", cuid); + } + } else { + // TODO throw exception here based on errors + } + return msg; +} + +BtMessageHandle DefaultBtMessageReceiver::receiveAndSendHandshake() { + return receiveHandshake(true); +} + +void DefaultBtMessageReceiver::sendHandshake() { + BtHandshakeMessageHandle msg = + BT_MESSAGE_FACTORY(btContext, peer)->createHandshakeMessage(btContext->getInfoHash(), + btContext->getPeerId()); + dispatcher->addMessageToQueue(msg); + dispatcher->sendMessages(); +} + +BtMessageHandle DefaultBtMessageReceiver::receiveMessage() { + unsigned char data[MAX_PAYLOAD_LEN]; + uint32_t dataLength = 0; + if(!peerConnection->receiveMessage(data, dataLength)) { + return 0; + } + BtMessageHandle msg = + BT_MESSAGE_FACTORY(btContext, peer)->createBtMessage(data, dataLength); + Errors errors; + if(msg->validate(errors)) { + return msg; + } else { + // TODO throw exception here based on errors; + return 0; + } +} + diff --git a/src/DefaultBtMessageReceiver.h b/src/DefaultBtMessageReceiver.h new file mode 100644 index 00000000..b8d0f89e --- /dev/null +++ b/src/DefaultBtMessageReceiver.h @@ -0,0 +1,120 @@ +/* */ +#ifndef _D_DEFAULT_BT_MESSAGE_RECEIVER_H_ +#define _D_DEFAULT_BT_MESSAGE_RECEIVER_H_ + +#include "BtMessageReceiver.h" +#include "BtContext.h" +#include "BtRegistry.h" +#include "Peer.h" +#include "PeerConnection.h" +#include "BtMessageDispatcher.h" +#include "Logger.h" +#include "LogFactory.h" + +class DefaultBtMessageReceiver : public BtMessageReceiver { +private: + int32_t cuid; + bool handshakeSent; + BtContextHandle btContext; + PeerHandle peer; + PeerConnectionHandle peerConnection; + BtMessageDispatcherHandle dispatcher; + const Logger* logger; + + void sendHandshake(); +public: + DefaultBtMessageReceiver():cuid(0), + handshakeSent(false), + btContext(0), + peer(0), + peerConnection(0), + dispatcher(0), + logger(LogFactory::getInstance()) + { + logger->debug("DefaultBtMessageReceiver::instantiated"); + } + + virtual ~DefaultBtMessageReceiver() + { + logger->debug("DefaultBtMessageReceiver::deleted"); + } + + virtual BtMessageHandle receiveHandshake(bool quickReply = false); + + virtual BtMessageHandle receiveAndSendHandshake(); + + virtual BtMessageHandle receiveMessage(); + + void setCuid(int32_t cuid) { + this->cuid = cuid; + } + + int32_t getCuid() const { + return cuid; + } + + void setPeerConnection(const PeerConnectionHandle& peerConnection) { + this->peerConnection = peerConnection; + } + + PeerConnectionHandle getPeerConnection() const { + return peerConnection; + } + + void setBtContext(const BtContextHandle& btContext) { + this->btContext = btContext; + } + + BtContextHandle getBtContext() const { + return btContext; + } + + void setPeer(const PeerHandle& peer) { + this->peer = peer; + } + + PeerHandle getPeer() const { + return peer; + } + + void setDispatcher(const BtMessageDispatcherHandle& dispatcher) { + this->dispatcher = dispatcher; + } +}; + +typedef SharedHandle DefaultBtMessageReceiverHandle; + +#endif // _D_DEFAULT_BT_MESSAGE_RECEIVER_H_ diff --git a/src/DefaultBtRequestFactory.cc b/src/DefaultBtRequestFactory.cc new file mode 100644 index 00000000..657f0631 --- /dev/null +++ b/src/DefaultBtRequestFactory.cc @@ -0,0 +1,99 @@ +/* */ +#include "DefaultBtRequestFactory.h" + +void DefaultBtRequestFactory::removeCompletedPiece() { + for(Pieces::iterator itr = pieces.begin(); itr != pieces.end();) { + PieceHandle& piece = *itr; + if(piece->pieceComplete()) { + dispatcher->doAbortOutstandingRequestAction(piece); + itr = pieces.erase(itr); + } else { + itr++; + } + } +} + +void DefaultBtRequestFactory::removeTargetPiece(const PieceHandle& piece) { + Pieces temp; + remove_copy(pieces.begin(), pieces.end(), back_inserter(temp), piece); + pieces = temp; + dispatcher->doAbortOutstandingRequestAction(piece); + pieceStorage->cancelPiece(piece); +} + +void DefaultBtRequestFactory::removeAllTargetPiece() { + for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) { + dispatcher->doAbortOutstandingRequestAction(*itr); + pieceStorage->cancelPiece(*itr); + } + pieces.clear(); +} + +BtMessages DefaultBtRequestFactory::createRequestMessages(int max) { + BtMessages requests; + for(Pieces::iterator itr = pieces.begin(); + itr != pieces.end() && requests.size() < (size_t)max; itr++) { + PieceHandle& piece = *itr; + int blockIndex; + while(requests.size() < (size_t)max && + (blockIndex = piece->getMissingUnusedBlockIndex()) != -1) { + requests.push_back(BT_MESSAGE_FACTORY(btContext, peer)-> + createRequestMessage(piece, blockIndex)); + } + } + return requests; +} + +BtMessages DefaultBtRequestFactory::createRequestMessagesOnEndGame(int max) { + BtMessages requests; + for(Pieces::iterator itr = pieces.begin(); + itr != pieces.end() && requests.size() < (size_t)max; itr++) { + PieceHandle& piece = *itr; + BlockIndexes missingBlockIndexes = piece->getAllMissingBlockIndexes(); + random_shuffle(missingBlockIndexes.begin(), missingBlockIndexes.end()); + for(BlockIndexes::const_iterator bitr = missingBlockIndexes.begin(); + bitr != missingBlockIndexes.end() && requests.size() < (size_t)max; + bitr++) { + int blockIndex = *bitr; + if(!dispatcher->isOutstandingRequest(piece->getIndex(), + blockIndex)) { + requests.push_back(BT_MESSAGE_FACTORY(btContext, peer)-> + createRequestMessage(piece, blockIndex)); + } + } + } + return requests; +} diff --git a/src/DefaultBtRequestFactory.h b/src/DefaultBtRequestFactory.h new file mode 100644 index 00000000..c8c95a9a --- /dev/null +++ b/src/DefaultBtRequestFactory.h @@ -0,0 +1,125 @@ +/* */ +#ifndef _D_DEFAULT_BT_REQUEST_FACTORY_H_ +#define _D_DEFAULT_BT_REQUEST_FACTORY_H_ + +#include "BtRequestFactory.h" +#include "BtContext.h" +#include "PieceStorage.h" +#include "Piece.h" +#include "Peer.h" +#include "BtMessageDispatcher.h" +#include "BtRegistry.h" +#include "LogFactory.h" + +class DefaultBtRequestFactory : public BtRequestFactory { +private: + int cuid; + BtContextHandle btContext; + PieceStorageHandle pieceStorage; + PeerHandle peer; + BtMessageDispatcherHandle dispatcher; + Pieces pieces; +public: + DefaultBtRequestFactory(): + cuid(0), + btContext(0), + pieceStorage(0), + peer(0), + dispatcher(0) + { + LogFactory::getInstance()->debug("DefaultBtRequestFactory::instantiated"); + } + + virtual ~DefaultBtRequestFactory() + { + LogFactory::getInstance()->debug("DefaultBtRequestFactory::deleted"); + } + + virtual void addTargetPiece(const PieceHandle& piece) { + pieces.push_back(piece); + } + + virtual void removeTargetPiece(const PieceHandle& piece); + + virtual void removeAllTargetPiece(); + + virtual int countTargetPiece() { + return pieces.size(); + } + + virtual void removeCompletedPiece(); + + virtual BtMessages createRequestMessages(int max); + + virtual BtMessages createRequestMessagesOnEndGame(int max); + + Pieces& getTargetPieces() { + return pieces; + } + + void setCuid(int32_t cuid) { + this->cuid = cuid; + } + + int32_t getCuid() const { + return cuid; + } + + void setBtContext(const BtContextHandle& btContext) { + this->btContext = btContext; + this->pieceStorage = PIECE_STORAGE(btContext); + } + + BtContextHandle getBtContext() const { + return btContext; + } + + PeerHandle getPeer() const { + return peer; + } + + void setPeer(const PeerHandle& peer) { + this->peer = peer; + } + + void setBtMessageDispatcher(const BtMessageDispatcherHandle& dispatcher) { + this->dispatcher = dispatcher; + } +}; + +typedef SharedHandle DefaultBtRequestFactoryHandle; + +#endif // _D_DEFAULT_BT_REQUEST_FACTORY_H_ diff --git a/src/DefaultPeerStorage.cc b/src/DefaultPeerStorage.cc index 3344a1f0..39c6ae5c 100644 --- a/src/DefaultPeerStorage.cc +++ b/src/DefaultPeerStorage.cc @@ -36,14 +36,11 @@ #include "LogFactory.h" #include "BtRegistry.h" -extern PeerHandle nullPeer; - DefaultPeerStorage::DefaultPeerStorage(BtContextHandle btContext, const Option* option): btContext(btContext), option(option), maxPeerListSize(MAX_PEER_LIST_SIZE), - peerEntryIdCounter(0), btRuntime(BT_RUNTIME(btContext)), removedPeerSessionDownloadLength(0), removedPeerSessionUploadLength(0) @@ -59,8 +56,6 @@ bool DefaultPeerStorage::addPeer(const PeerHandle& peer) { if(peers.size() >= (size_t)maxPeerListSize) { deleteUnusedPeer(peers.size()-maxPeerListSize+1); } - ++peerEntryIdCounter; - peer->entryId = peerEntryIdCounter; peers.push_back(peer); return true; } else { @@ -100,7 +95,7 @@ PeerHandle DefaultPeerStorage::getUnusedPeer() { Peers::const_iterator itr = find_if(peers.begin(), peers.end(), FindFinePeer()); if(itr == peers.end()) { - return nullPeer; + return 0; } else { return *itr; } @@ -123,7 +118,7 @@ PeerHandle DefaultPeerStorage::getPeer(const string& ipaddr, Peers::const_iterator itr = find_if(peers.begin(), peers.end(), FindPeer(ipaddr, port)); if(itr == peers.end()) { - return nullPeer; + return 0; } else { return *itr; } @@ -134,7 +129,7 @@ int DefaultPeerStorage::countPeer() const { } bool DefaultPeerStorage::isPeerAvailable() { - return getUnusedPeer() != nullPeer; + return !getUnusedPeer().isNull(); } Peers DefaultPeerStorage::getActivePeers() { diff --git a/src/DefaultPeerStorage.h b/src/DefaultPeerStorage.h index 0bda4187..756700dd 100644 --- a/src/DefaultPeerStorage.h +++ b/src/DefaultPeerStorage.h @@ -50,7 +50,6 @@ private: const Option* option; Peers peers; int maxPeerListSize; - int peerEntryIdCounter; Logger* logger; BtRuntimeHandle btRuntime; long long int removedPeerSessionDownloadLength; diff --git a/src/DefaultPieceStorage.cc b/src/DefaultPieceStorage.cc index 24fa364e..58f9d455 100644 --- a/src/DefaultPieceStorage.cc +++ b/src/DefaultPieceStorage.cc @@ -42,6 +42,7 @@ #include "MultiDiskWriter.h" #include "PreAllocationDiskWriter.h" #include "DlAbortEx.h" +#include "BitfieldManFactory.h" DefaultPieceStorage::DefaultPieceStorage(BtContextHandle btContext, const Option* option): btContext(btContext), @@ -49,13 +50,16 @@ DefaultPieceStorage::DefaultPieceStorage(BtContextHandle btContext, const Option endGamePieceNum(END_GAME_PIECE_NUM), option(option) { - bitfieldMan = new BitfieldMan(btContext->getPieceLength(), - btContext->getTotalLength()); + bitfieldMan = + BitfieldManFactory::getNewFactory()-> + createBitfieldMan(btContext->getPieceLength(), + btContext->getTotalLength()); logger = LogFactory::getInstance(); } DefaultPieceStorage::~DefaultPieceStorage() { delete bitfieldMan; + delete diskAdaptor; } bool DefaultPieceStorage::hasMissingPiece(const PeerHandle& peer) { @@ -79,15 +83,15 @@ int DefaultPieceStorage::getMissingPieceIndex(const PeerHandle& peer) { return index; } -Piece DefaultPieceStorage::checkOutPiece(int index) { +PieceHandle DefaultPieceStorage::checkOutPiece(int index) { if(index == -1) { - return Piece::nullPiece; + return 0; } bitfieldMan->setUseBit(index); - Piece piece = findUsedPiece(index); - if(Piece::isNull(piece)) { - Piece piece(index, bitfieldMan->getBlockLength(index)); + PieceHandle piece = findUsedPiece(index); + if(piece.isNull()) { + piece = new Piece(index, bitfieldMan->getBlockLength(index)); addUsedPiece(piece); return piece; } else { @@ -95,8 +99,26 @@ Piece DefaultPieceStorage::checkOutPiece(int index) { } } -void DefaultPieceStorage::addUsedPiece(const Piece& piece) { - // TODO ? if nullPiece +/** + * Newly instantiated piece is not added to usedPieces. + * Because it is waste of memory and there is no chance to use them later. + */ +PieceHandle DefaultPieceStorage::getPiece(int index) { + if(0 <= index && index <= bitfieldMan->getMaxIndex()) { + PieceHandle piece = findUsedPiece(index); + if(piece.isNull()) { + piece = new Piece(index, bitfieldMan->getBlockLength(index)); + if(hasPiece(index)) { + piece->setAllBlock(); + } + } + return piece; + } else { + return 0; + } +} + +void DefaultPieceStorage::addUsedPiece(const PieceHandle& piece) { usedPieces.push_back(piece); } @@ -106,23 +128,23 @@ private: public: FindPiece(int index):index(index) {} - bool operator()(const Piece& piece) { - return piece.getIndex() == index; + bool operator()(const PieceHandle& piece) { + return piece->getIndex() == index; } }; -Piece DefaultPieceStorage::findUsedPiece(int index) const { +PieceHandle DefaultPieceStorage::findUsedPiece(int index) const { Pieces::const_iterator itr = find_if(usedPieces.begin(), usedPieces.end(), FindPiece(index)); if(itr == usedPieces.end()) { - return Piece::nullPiece; + return 0; } else { return *itr; } } -Piece DefaultPieceStorage::getMissingPiece(const PeerHandle& peer) { +PieceHandle DefaultPieceStorage::getMissingPiece(const PeerHandle& peer) { int index = getMissingPieceIndex(peer); return checkOutPiece(index); } @@ -149,13 +171,13 @@ int DefaultPieceStorage::getMissingFastPieceIndex(const PeerHandle& peer) { return index; } -Piece DefaultPieceStorage::getMissingFastPiece(const PeerHandle& peer) { +PieceHandle DefaultPieceStorage::getMissingFastPiece(const PeerHandle& peer) { int index = getMissingFastPieceIndex(peer); return checkOutPiece(index); } -void DefaultPieceStorage::deleteUsedPiece(const Piece& piece) { - if(Piece::isNull(piece)) { +void DefaultPieceStorage::deleteUsedPiece(const PieceHandle& piece) { + if(piece.isNull()) { return; } Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), piece); @@ -185,12 +207,12 @@ int DefaultPieceStorage::deleteUsedPiecesByFillRate(int fillRate, int deleted = 0; for(Pieces::iterator itr = usedPieces.begin(); itr != usedPieces.end() && deleted < toDelete;) { - Piece& piece = *itr; - if(!bitfieldMan->isUseBitSet(piece.getIndex()) && - piece.countCompleteBlock() <= piece.countBlock()*(fillRate/100.0)) { + PieceHandle& piece = *itr; + if(!bitfieldMan->isUseBitSet(piece->getIndex()) && + piece->countCompleteBlock() <= piece->countBlock()*(fillRate/100.0)) { logger->debug("Deleting used piece index=%d, fillRate(%%)=%d<=%d", - piece.getIndex(), - (piece.countCompleteBlock()*100)/piece.countBlock(), + piece->getIndex(), + (piece->countCompleteBlock()*100)/piece->countBlock(), fillRate); itr = usedPieces.erase(itr); deleted++; @@ -201,8 +223,8 @@ int DefaultPieceStorage::deleteUsedPiecesByFillRate(int fillRate, return deleted; } -void DefaultPieceStorage::completePiece(const Piece& piece) { - if(Piece::isNull(piece)) { +void DefaultPieceStorage::completePiece(const PieceHandle& piece) { + if(piece.isNull()) { return; } deleteUsedPiece(piece); @@ -212,8 +234,8 @@ void DefaultPieceStorage::completePiece(const Piece& piece) { if(downloadFinished()) { return; } - bitfieldMan->setBit(piece.getIndex()); - bitfieldMan->unsetUseBit(piece.getIndex()); + bitfieldMan->setBit(piece->getIndex()); + bitfieldMan->unsetUseBit(piece->getIndex()); if(downloadFinished()) { diskAdaptor->onDownloadComplete(); if(isSelectiveDownloadingMode()) { @@ -235,50 +257,18 @@ void DefaultPieceStorage::finishSelectiveDownloadingMode() { } // not unittested -void DefaultPieceStorage::cancelPiece(const Piece& piece) { - if(Piece::isNull(piece)) { +void DefaultPieceStorage::cancelPiece(const PieceHandle& piece) { + if(piece.isNull()) { return; } - updatePiece(piece); - bitfieldMan->unsetUseBit(piece.getIndex()); + bitfieldMan->unsetUseBit(piece->getIndex()); if(!isEndGame()) { - if(piece.countCompleteBlock() == 0) { + if(piece->countCompleteBlock() == 0) { deleteUsedPiece(piece); } } } -// not unittested -void DefaultPieceStorage::updatePiece(const Piece& piece) { - if(Piece::isNull(piece)) { - return; - } - Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), - piece); - if(itr != usedPieces.end()) { - *itr = piece; - } -} - -// not unittested -void DefaultPieceStorage::syncPiece(Piece& piece) { - if(Piece::isNull(piece)) { - return; - } - Pieces::iterator itr = find(usedPieces.begin(), usedPieces.end(), - piece); - if(itr != usedPieces.end()) { - piece = *itr; - return; - } else { - // hasPiece(piece.getIndex()) is true, then set all bit of - // piece.bitfield to 1 - if(hasPiece(piece.getIndex())) { - piece.setAllBlock(); - } - } -} - bool DefaultPieceStorage::hasPiece(int index) { return bitfieldMan->isBitSet(index); } diff --git a/src/DefaultPieceStorage.h b/src/DefaultPieceStorage.h index 4b9a2066..2a41a4ce 100644 --- a/src/DefaultPieceStorage.h +++ b/src/DefaultPieceStorage.h @@ -77,29 +77,26 @@ private: int getMissingPieceIndex(const PeerHandle& peer); int getMissingFastPieceIndex(const PeerHandle& peer); - Piece checkOutPiece(int index); - void addUsedPiece(const Piece& piece); - Piece findUsedPiece(int index) const; + PieceHandle checkOutPiece(int index); int deleteUsedPiecesByFillRate(int fillRate, int toDelete); void reduceUsedPieces(int delMax); - void deleteUsedPiece(const Piece& piece); + void deleteUsedPiece(const PieceHandle& piece); + PieceHandle findUsedPiece(int index) const; public: DefaultPieceStorage(BtContextHandle btContext, const Option* option); virtual ~DefaultPieceStorage(); virtual bool hasMissingPiece(const PeerHandle& peer); - virtual Piece getMissingPiece(const PeerHandle& peer); + virtual PieceHandle getMissingPiece(const PeerHandle& peer); - virtual Piece getMissingFastPiece(const PeerHandle& peer); + virtual PieceHandle getMissingFastPiece(const PeerHandle& peer); - virtual void completePiece(const Piece& piece); + virtual PieceHandle getPiece(int index); - virtual void cancelPiece(const Piece& piece); + virtual void completePiece(const PieceHandle& piece); - virtual void updatePiece(const Piece& piece); - - virtual void syncPiece(Piece& piece); + virtual void cancelPiece(const PieceHandle& piece); virtual bool hasPiece(int index); @@ -153,6 +150,10 @@ public: virtual void removeAdvertisedPiece(int elapsed); + /** + * This method is made private for test purpose only. + */ + void addUsedPiece(const PieceHandle& piece); }; #endif // _D_DEFAULT_PIECE_STORAGE_H_ diff --git a/src/DownloadEngineFactory.cc b/src/DownloadEngineFactory.cc index 2bb84da2..c688b03c 100644 --- a/src/DownloadEngineFactory.cc +++ b/src/DownloadEngineFactory.cc @@ -107,6 +107,24 @@ DownloadEngineFactory::newTorrentConsoleEngine(const BtContextHandle& btContext, BtRegistry::registerBtProgressInfoFile(btContext->getInfoHashAsString(), btProgressInfoFile); + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + + /* + DefaultBtMessageFactoryAdaptorHandle factoryAdaptor = + new DefaultBtMessageFactoryAdaptor(); + BtRegistry::registerBtMessageFactoryAdaptor(btContext->getInfoHashAsString(), + factoryAdaptor); + + BtMessageFactoryClusterHandle factoryCluster = new BtMessageFactoryCluster(); + BtRegistry::registerBtMessageFactoryCluster(btContext->getInfoHashAsString(), + factoryCluster); + + BtMessageDispatcherClusterHandle dispatcherCluster = + new BtMessageDispatcherCluster(); + BtRegistry::registerBtMessageDispatcherCluster(btContext->getInfoHashAsString(), + dispatcherCluster); + */ te->setBtContext(btContext); // initialize file storage pieceStorage->initStorage(); diff --git a/src/HandleRegistry.h b/src/HandleRegistry.h new file mode 100644 index 00000000..de8fca38 --- /dev/null +++ b/src/HandleRegistry.h @@ -0,0 +1,73 @@ +/* */ +#ifndef _D_HANDLE_REGISTRY_H_ +#define _D_HANDLE_REGISTRY_H_ + +#include "SharedHandle.h" +#include + +using namespace std; + +template +class HandleRegistry { + typedef map > HandleMap; +private: + HandleMap handleMap; +public: + void registerHandle(const K& key, const SharedHandle& obj) { + unregisterHandle(key); + typename HandleMap::value_type p(key, obj); + handleMap.insert(p); + } + + void unregisterHandle(const K& key) { + handleMap.erase(key); + } + + SharedHandle getHandle(const K& key) { + typename HandleMap::const_iterator itr = handleMap.find(key); + if(itr == handleMap.end()) { + return 0; + } else { + return itr->second; + } + } + + void clear() { + handleMap.clear(); + } +}; + +#endif // _D_HANDLE_REGISTRY_H_ diff --git a/src/Makefile.am b/src/Makefile.am index e7860354..888d9f6c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -49,13 +49,18 @@ SRCS = Socket.h\ NullLogger.h\ TimeA2.cc TimeA2.h\ SharedHandle.h\ + HandleRegistry.h\ FeatureConfig.cc FeatureConfig.h\ DownloadEngineFactory.cc DownloadEngineFactory.h\ RequestInfo.h\ UrlRequestInfo.cc UrlRequestInfo.h\ SpeedCalc.cc SpeedCalc.h\ PeerStat.h\ - BitfieldMan.cc BitfieldMan.h + BitfieldMan.cc BitfieldMan.h\ + BitfieldManFactory.cc BitfieldManFactory.h\ + Randomizer.h\ + SimpleRandomizer.cc SimpleRandomizer.h +# debug_new.cpp if ENABLE_ASYNC_DNS SRCS += NameResolver.cc NameResolver.h @@ -138,7 +143,54 @@ SRCS += MetaEntry.h\ BtRuntime.h\ BtProgressInfoFile.h\ DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\ - BtContextAwareCommand.cc BtContextAwareCommand.h + BtContextAwareCommand.cc BtContextAwareCommand.h\ + BtMessage.h\ + AbstractBtMessage.h\ + SimpleBtMessage.cc SimpleBtMessage.h\ + BtAllowedFastMessage.cc BtAllowedFastMessage.h\ + BtBitfieldMessage.cc BtBitfieldMessage.h\ + BtCancelMessage.cc BtCancelMessage.h\ + BtChokeMessage.cc BtChokeMessage.h\ + BtHaveAllMessage.cc BtHaveAllMessage.h\ + BtHaveMessage.cc BtHaveMessage.h\ + BtHaveNoneMessage.cc BtHaveNoneMessage.h\ + BtInterestedMessage.cc BtInterestedMessage.h\ + BtKeepAliveMessage.cc BtKeepAliveMessage.h\ + BtNotInterestedMessage.cc BtNotInterestedMessage.h\ + BtPieceMessage.cc BtPieceMessage.h\ + BtPortMessage.cc BtPortMessage.h\ + BtRejectMessage.cc BtRejectMessage.h\ + BtRequestMessage.cc BtRequestMessage.h\ + BtSuggestPieceMessage.cc BtSuggestPieceMessage.h\ + BtUnchokeMessage.cc BtUnchokeMessage.h\ + BtHandshakeMessage.cc BtHandshakeMessage.h\ + BtMessageValidator.h\ + BtAllowedFastMessageValidator.h\ + BtBitfieldMessageValidator.h\ + BtCancelMessageValidator.h\ + BtHaveMessageValidator.h\ + BtPieceMessageValidator.h\ + BtRejectMessageValidator.h\ + BtRequestMessageValidator.h\ + BtSuggestPieceMessageValidator.h\ + BtHandshakeMessageValidator.h\ + BtMessageFactory.h\ + DefaultBtMessageFactory.cc DefaultBtMessageFactory.h\ + BtMessageDispatcher.h\ + DefaultBtMessageDispatcher.cc DefaultBtMessageDispatcher.h\ + BtMessageReceiver.h\ + DefaultBtMessageReceiver.cc DefaultBtMessageReceiver.h\ + BtRequestFactory.h\ + DefaultBtRequestFactory.cc DefaultBtRequestFactory.h\ + BtEvent.h\ + BtEventListener.h\ + BtCancelSendingPieceEvent.h\ + BtAbortOutstandingRequestEvent.h\ + BtChokedEvent.h\ + BtChokingEvent.h\ + BtInteractive.h\ + DefaultBtInteractive.cc DefaultBtInteractive.h\ + PeerObject.h endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/src/Makefile.in b/src/Makefile.in index 3ebd9e44..b1458c07 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -115,7 +115,54 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ BtRuntime.h\ @ENABLE_BITTORRENT_TRUE@ BtProgressInfoFile.h\ @ENABLE_BITTORRENT_TRUE@ DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\ -@ENABLE_BITTORRENT_TRUE@ BtContextAwareCommand.cc BtContextAwareCommand.h +@ENABLE_BITTORRENT_TRUE@ BtContextAwareCommand.cc BtContextAwareCommand.h\ +@ENABLE_BITTORRENT_TRUE@ BtMessage.h\ +@ENABLE_BITTORRENT_TRUE@ AbstractBtMessage.h\ +@ENABLE_BITTORRENT_TRUE@ SimpleBtMessage.cc SimpleBtMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtAllowedFastMessage.cc BtAllowedFastMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtBitfieldMessage.cc BtBitfieldMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtCancelMessage.cc BtCancelMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtChokeMessage.cc BtChokeMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtHaveAllMessage.cc BtHaveAllMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtHaveMessage.cc BtHaveMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtHaveNoneMessage.cc BtHaveNoneMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtInterestedMessage.cc BtInterestedMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtKeepAliveMessage.cc BtKeepAliveMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtNotInterestedMessage.cc BtNotInterestedMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtPieceMessage.cc BtPieceMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtPortMessage.cc BtPortMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtRejectMessage.cc BtRejectMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtRequestMessage.cc BtRequestMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtSuggestPieceMessage.cc BtSuggestPieceMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtUnchokeMessage.cc BtUnchokeMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtHandshakeMessage.cc BtHandshakeMessage.h\ +@ENABLE_BITTORRENT_TRUE@ BtMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtAllowedFastMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtBitfieldMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtCancelMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtHaveMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtPieceMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtRejectMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtRequestMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtSuggestPieceMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtHandshakeMessageValidator.h\ +@ENABLE_BITTORRENT_TRUE@ BtMessageFactory.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactory.cc DefaultBtMessageFactory.h\ +@ENABLE_BITTORRENT_TRUE@ BtMessageDispatcher.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageDispatcher.cc DefaultBtMessageDispatcher.h\ +@ENABLE_BITTORRENT_TRUE@ BtMessageReceiver.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageReceiver.cc DefaultBtMessageReceiver.h\ +@ENABLE_BITTORRENT_TRUE@ BtRequestFactory.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtRequestFactory.cc DefaultBtRequestFactory.h\ +@ENABLE_BITTORRENT_TRUE@ BtEvent.h\ +@ENABLE_BITTORRENT_TRUE@ BtEventListener.h\ +@ENABLE_BITTORRENT_TRUE@ BtCancelSendingPieceEvent.h\ +@ENABLE_BITTORRENT_TRUE@ BtAbortOutstandingRequestEvent.h\ +@ENABLE_BITTORRENT_TRUE@ BtChokedEvent.h\ +@ENABLE_BITTORRENT_TRUE@ BtChokingEvent.h\ +@ENABLE_BITTORRENT_TRUE@ BtInteractive.h\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtInteractive.cc DefaultBtInteractive.h\ +@ENABLE_BITTORRENT_TRUE@ PeerObject.h @ENABLE_METALINK_TRUE@am__append_3 = Metalinker.cc Metalinker.h\ @ENABLE_METALINK_TRUE@ MetalinkEntry.cc MetalinkEntry.h\ @@ -178,16 +225,19 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ AbstractDiskWriter.cc AbstractDiskWriter.h File.cc File.h \ Option.cc Option.h Base64.cc Base64.h CookieBox.cc CookieBox.h \ messageDigest.h LogFactory.cc LogFactory.h NullLogger.h \ - TimeA2.cc TimeA2.h SharedHandle.h FeatureConfig.cc \ - FeatureConfig.h DownloadEngineFactory.cc \ + TimeA2.cc TimeA2.h SharedHandle.h HandleRegistry.h \ + FeatureConfig.cc FeatureConfig.h DownloadEngineFactory.cc \ DownloadEngineFactory.h RequestInfo.h UrlRequestInfo.cc \ UrlRequestInfo.h SpeedCalc.cc SpeedCalc.h PeerStat.h \ - BitfieldMan.cc BitfieldMan.h NameResolver.cc NameResolver.h \ - MetaEntry.h Data.cc Data.h Dictionary.cc Dictionary.h List.cc \ - List.h MetaFileUtil.cc MetaFileUtil.h MetaEntryVisitor.h \ - ShaVisitor.cc ShaVisitor.h PeerConnection.cc PeerConnection.h \ - PeerMessageUtil.cc PeerMessageUtil.h PeerAbstractCommand.cc \ - PeerAbstractCommand.h PeerInitiateConnectionCommand.cc \ + BitfieldMan.cc BitfieldMan.h BitfieldManFactory.cc \ + BitfieldManFactory.h Randomizer.h SimpleRandomizer.cc \ + SimpleRandomizer.h debug_new.cpp NameResolver.cc \ + NameResolver.h MetaEntry.h Data.cc Data.h Dictionary.cc \ + Dictionary.h List.cc List.h MetaFileUtil.cc MetaFileUtil.h \ + MetaEntryVisitor.h ShaVisitor.cc ShaVisitor.h \ + PeerConnection.cc PeerConnection.h PeerMessageUtil.cc \ + PeerMessageUtil.h PeerAbstractCommand.cc PeerAbstractCommand.h \ + PeerInitiateConnectionCommand.cc \ PeerInitiateConnectionCommand.h PeerInteractionCommand.cc \ PeerInteractionCommand.h Peer.cc Peer.h \ TorrentDownloadEngine.cc TorrentDownloadEngine.h \ @@ -231,9 +281,38 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ DefaultBtAnnounce.h BtRegistry.cc BtRegistry.h BtRuntime.h \ BtProgressInfoFile.h DefaultBtProgressInfoFile.cc \ DefaultBtProgressInfoFile.h BtContextAwareCommand.cc \ - BtContextAwareCommand.h Metalinker.cc Metalinker.h \ - MetalinkEntry.cc MetalinkEntry.h MetalinkResource.cc \ - MetalinkResource.h MetalinkProcessor.h \ + BtContextAwareCommand.h BtMessage.h AbstractBtMessage.h \ + SimpleBtMessage.cc SimpleBtMessage.h BtAllowedFastMessage.cc \ + BtAllowedFastMessage.h BtBitfieldMessage.cc \ + BtBitfieldMessage.h BtCancelMessage.cc BtCancelMessage.h \ + BtChokeMessage.cc BtChokeMessage.h BtHaveAllMessage.cc \ + BtHaveAllMessage.h BtHaveMessage.cc BtHaveMessage.h \ + BtHaveNoneMessage.cc BtHaveNoneMessage.h \ + BtInterestedMessage.cc BtInterestedMessage.h \ + BtKeepAliveMessage.cc BtKeepAliveMessage.h \ + BtNotInterestedMessage.cc BtNotInterestedMessage.h \ + BtPieceMessage.cc BtPieceMessage.h BtPortMessage.cc \ + BtPortMessage.h BtRejectMessage.cc BtRejectMessage.h \ + BtRequestMessage.cc BtRequestMessage.h \ + BtSuggestPieceMessage.cc BtSuggestPieceMessage.h \ + BtUnchokeMessage.cc BtUnchokeMessage.h BtHandshakeMessage.cc \ + BtHandshakeMessage.h BtMessageValidator.h \ + BtAllowedFastMessageValidator.h BtBitfieldMessageValidator.h \ + BtCancelMessageValidator.h BtHaveMessageValidator.h \ + BtPieceMessageValidator.h BtRejectMessageValidator.h \ + BtRequestMessageValidator.h BtSuggestPieceMessageValidator.h \ + BtHandshakeMessageValidator.h BtMessageFactory.h \ + DefaultBtMessageFactory.cc DefaultBtMessageFactory.h \ + BtMessageDispatcher.h DefaultBtMessageDispatcher.cc \ + DefaultBtMessageDispatcher.h BtMessageReceiver.h \ + DefaultBtMessageReceiver.cc DefaultBtMessageReceiver.h \ + BtRequestFactory.h DefaultBtRequestFactory.cc \ + DefaultBtRequestFactory.h BtEvent.h BtEventListener.h \ + BtCancelSendingPieceEvent.h BtAbortOutstandingRequestEvent.h \ + BtChokedEvent.h BtChokingEvent.h BtInteractive.h \ + DefaultBtInteractive.cc DefaultBtInteractive.h PeerObject.h \ + Metalinker.cc Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ + MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \ Xml2MetalinkProcessor.cc Xml2MetalinkProcessor.h \ MetalinkRequestInfo.cc MetalinkRequestInfo.h @ENABLE_ASYNC_DNS_TRUE@am__objects_1 = NameResolver.$(OBJEXT) @@ -297,7 +376,30 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ DefaultBtAnnounce.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BtRegistry.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DefaultBtProgressInfoFile.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ BtContextAwareCommand.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ BtContextAwareCommand.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ SimpleBtMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtAllowedFastMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtBitfieldMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtCancelMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtChokeMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtHaveAllMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtHaveMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtHaveNoneMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtInterestedMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtKeepAliveMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtNotInterestedMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtPieceMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtPortMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtRejectMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtRequestMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtSuggestPieceMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtUnchokeMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtHandshakeMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactory.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageDispatcher.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageReceiver.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtRequestFactory.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtInteractive.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntry.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkResource.$(OBJEXT) \ @@ -326,8 +428,9 @@ am__objects_4 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \ CookieBox.$(OBJEXT) LogFactory.$(OBJEXT) TimeA2.$(OBJEXT) \ FeatureConfig.$(OBJEXT) DownloadEngineFactory.$(OBJEXT) \ UrlRequestInfo.$(OBJEXT) SpeedCalc.$(OBJEXT) \ - BitfieldMan.$(OBJEXT) $(am__objects_1) $(am__objects_2) \ - $(am__objects_3) + BitfieldMan.$(OBJEXT) BitfieldManFactory.$(OBJEXT) \ + SimpleRandomizer.$(OBJEXT) debug_new.$(OBJEXT) \ + $(am__objects_1) $(am__objects_2) $(am__objects_3) am_libaria2c_a_OBJECTS = $(am__objects_4) libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS) am__installdirs = "$(DESTDIR)$(bindir)" @@ -525,12 +628,14 @@ SRCS = Socket.h SocketCore.cc SocketCore.h Command.cc Command.h \ AbstractDiskWriter.cc AbstractDiskWriter.h File.cc File.h \ Option.cc Option.h Base64.cc Base64.h CookieBox.cc CookieBox.h \ messageDigest.h LogFactory.cc LogFactory.h NullLogger.h \ - TimeA2.cc TimeA2.h SharedHandle.h FeatureConfig.cc \ - FeatureConfig.h DownloadEngineFactory.cc \ + TimeA2.cc TimeA2.h SharedHandle.h HandleRegistry.h \ + FeatureConfig.cc FeatureConfig.h DownloadEngineFactory.cc \ DownloadEngineFactory.h RequestInfo.h UrlRequestInfo.cc \ UrlRequestInfo.h SpeedCalc.cc SpeedCalc.h PeerStat.h \ - BitfieldMan.cc BitfieldMan.h $(am__append_1) $(am__append_2) \ - $(am__append_3) + BitfieldMan.cc BitfieldMan.h BitfieldManFactory.cc \ + BitfieldManFactory.h Randomizer.h SimpleRandomizer.cc \ + SimpleRandomizer.h debug_new.cpp $(am__append_1) \ + $(am__append_2) $(am__append_3) noinst_LIBRARIES = libaria2c.a libaria2c_a_SOURCES = $(SRCS) aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\ @@ -547,7 +652,7 @@ AM_CPPFLAGS = -Wall\ all: all-am .SUFFIXES: -.SUFFIXES: .cc .o .obj +.SUFFIXES: .cc .cpp .o .obj $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ @@ -624,9 +729,27 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AnnounceList.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)/BitfieldManFactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtAllowedFastMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtBitfieldMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtCancelMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtChokeMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtContextAwareCommand.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHandshakeMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveAllMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveNoneMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtInterestedMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtKeepAliveMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtNotInterestedMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPieceMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPortMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRegistry.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRejectMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRequestMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSuggestPieceMessage.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtUnchokeMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CancelMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChokeMessage.Po@am__quote@ @@ -639,7 +762,12 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Data.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtAnnounce.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtContext.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtInteractive.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtMessageDispatcher.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtMessageFactory.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtMessageReceiver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtProgressInfoFile.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtRequestFactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerListProcessor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerStorage.Po@am__quote@ @@ -712,8 +840,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Segment.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SimpleBtMessage.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)/SimpleRandomizer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SleepCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SocketCore.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SpeedCalc.Po@am__quote@ @@ -729,6 +859,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UrlRequestInfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessor.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug_new.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ .cc.o: @@ -744,6 +875,20 @@ distclean-compile: @AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cpp.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cpp.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` uninstall-info-am: ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) diff --git a/src/Peer.cc b/src/Peer.cc index 9016c9cc..b9591d23 100644 --- a/src/Peer.cc +++ b/src/Peer.cc @@ -33,8 +33,33 @@ */ /* copyright --> */ #include "Peer.h" +#include "BitfieldManFactory.h" +#include "Util.h" -PeerHandle nullPeer = PeerHandle(new Peer("", 0, 0, 0)); +Peer::Peer(string ipaddr, int port, int pieceLength, long long int totalLength): + ipaddr(ipaddr), + port(port), + error(0), + sessionUploadLength(0), + sessionDownloadLength(0), + pieceLength(pieceLength), + active(false) +{ + resetStatus(); + this->bitfield = BitfieldManFactory::getNewFactory()-> + createBitfieldMan(pieceLength, totalLength); + string idSeed = ipaddr+":"+Util::itos(port); + id = Util::simpleMessageDigest(idSeed); +} + +/* +Peer::Peer():entryId(0), ipaddr(""), port(0), bitfield(0), + sessionUploadLength(0), sessionDownloadLength(0), + pieceLength(0) +{ + resetStatus(); +} +*/ void Peer::updateBitfield(int index, int operation) { if(operation == 1) { @@ -74,6 +99,8 @@ void Peer::resetStatus() { fastExtensionEnabled = false; latency = DEFAULT_LATENCY; fastSet.clear(); + peerAllowedIndexSet.clear(); + amAllowedIndexSet.clear(); peerStat.reset(); } @@ -87,6 +114,28 @@ void Peer::addFastSetIndex(int index) { } } +bool Peer::isInPeerAllowedIndexSet(int index) const { + return find(peerAllowedIndexSet.begin(), peerAllowedIndexSet.end(), + index) != peerAllowedIndexSet.end(); +} + +void Peer::addPeerAllowedIndex(int index) { + if(!isInPeerAllowedIndexSet(index)) { + peerAllowedIndexSet.push_back(index); + } +} + +bool Peer::isInAmAllowedIndexSet(int index) const { + return find(amAllowedIndexSet.begin(), amAllowedIndexSet.end(), + index) != amAllowedIndexSet.end(); +} + +void Peer::addAmAllowedIndex(int index) { + if(!isInAmAllowedIndexSet(index)) { + amAllowedIndexSet.push_back(index); + } +} + void Peer::setAllBitfield() { bitfield->setAllBit(); } diff --git a/src/Peer.h b/src/Peer.h index c7af34ee..cecd27f9 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -51,7 +51,6 @@ class Peer { friend bool operator==(const Peer& p1, const Peer& p2); friend bool operator!=(const Peer& p1, const Peer& p2); public: - int entryId; string ipaddr; int port; bool amChoking; @@ -65,42 +64,32 @@ public: bool optUnchoking; bool snubbing; private: - char peerId[PEER_ID_LENGTH]; + unsigned char peerId[PEER_ID_LENGTH]; BitfieldMan* bitfield; bool fastExtensionEnabled; // allowed fast indexes that peer has sent by Allowed Fast message Integers fastSet; + // fast index set which a peer has sent to localhost. + Integers peerAllowedIndexSet; + // fast index set which localhost has sent to a peer. + Integers amAllowedIndexSet; PeerStat peerStat; long long int sessionUploadLength; long long int sessionDownloadLength; int pieceLength; int latency; bool active; + string id; public: - Peer(string ipaddr, int port, int pieceLength, long long int totalLength): - entryId(0), ipaddr(ipaddr), port(port), error(0), - sessionUploadLength(0), sessionDownloadLength(0), - pieceLength(pieceLength), active(false) - { - resetStatus(); - this->bitfield = new BitfieldMan(pieceLength, totalLength); - } - - Peer():entryId(0), ipaddr(""), port(0), bitfield(0), - sessionUploadLength(0), sessionDownloadLength(0), - pieceLength(0) - { - resetStatus(); - } + Peer(string ipaddr, int port, int pieceLength, long long int totalLength); ~Peer() { - if(bitfield != NULL) { - delete bitfield; - } + delete bitfield; } bool operator==(const Peer& p) { - return ipaddr == p.ipaddr && port == p.port; + //return ipaddr == p.ipaddr && port == p.port; + return id == p.id; } bool operator!=(const Peer& p) { @@ -161,10 +150,10 @@ public: return active; } - void setPeerId(const char* peerId) { + void setPeerId(const unsigned char* peerId) { memcpy(this->peerId, peerId, PEER_ID_LENGTH); } - const char* getPeerId() const { return this->peerId; } + const unsigned char* getPeerId() const { return this->peerId; } void setBitfield(const unsigned char* bitfield, int bitfieldLength) { this->bitfield->setBitfield(bitfield, bitfieldLength); @@ -189,6 +178,12 @@ public: bool isInFastSet(int index) const; int countFastSet() const { return fastSet.size(); } + void addPeerAllowedIndex(int index); + bool isInPeerAllowedIndexSet(int index) const; + + void addAmAllowedIndex(int index); + bool isInAmAllowedIndexSet(int index) const; + bool shouldBeChoking() const; bool hasPiece(int index) const; @@ -197,6 +192,10 @@ public: void updateLatency(int latency); int getLatency() const { return latency; } + + const string& getId() const { + return id; + } }; typedef SharedHandle PeerHandle; diff --git a/src/PeerConnection.cc b/src/PeerConnection.cc index e8a5257e..6608149a 100644 --- a/src/PeerConnection.cc +++ b/src/PeerConnection.cc @@ -38,9 +38,10 @@ #include "PeerMessageUtil.h" #include "Util.h" #include "LogFactory.h" +#include "BtHandshakeMessage.h" #include -PeerConnection::PeerConnection(int cuid, +PeerConnection::PeerConnection(int32_t cuid, const SocketHandle& socket, const Option* op) :cuid(cuid), @@ -55,24 +56,26 @@ PeerConnection::PeerConnection(int cuid, PeerConnection::~PeerConnection() {} -int PeerConnection::sendMessage(const char* msg, int length) { - int writtenLength = 0; +uint32_t PeerConnection::sendMessage(const unsigned char* data, uint32_t dataLength) { + uint32_t writtenLength = 0; if(socket->isWritable(0)) { - socket->writeData(msg, length); - writtenLength += length; + // TODO fix this + socket->writeData((const char*)data, dataLength); + writtenLength += dataLength; } return writtenLength; } -bool PeerConnection::receiveMessage(char* msg, int& length) { +bool PeerConnection::receiveMessage(unsigned char* data, uint32_t& dataLength) { if(!socket->isReadable(0)) { return false; } if(resbufLength == 0 && lenbufLength != 4) { // read payload size, 4-byte integer - int remain = 4-lenbufLength; - int temp = remain; - socket->readData(lenbuf+lenbufLength, temp); + uint32_t remain = 4-lenbufLength; + uint32_t temp = remain; + // TODO fix this + socket->readData((char*)lenbuf+lenbufLength, (int&)temp); if(temp == 0) { // we got EOF throw new DlAbortEx(EX_EOF_FROM_PEER); @@ -83,7 +86,7 @@ bool PeerConnection::receiveMessage(char* msg, int& length) { return false; } //payloadLen = ntohl(nPayloadLen); - int payloadLength = ntohl(*((int*)lenbuf)); + uint32_t payloadLength = ntohl(*((uint32_t*)lenbuf)); if(payloadLength > MAX_PAYLOAD_LEN || payloadLength < 0) { throw new DlAbortEx("max payload length exceeded or invalid. length = %d", payloadLength); @@ -91,9 +94,9 @@ bool PeerConnection::receiveMessage(char* msg, int& length) { currentPayloadLength = payloadLength; } // we have currentPayloadLen-resbufLen bytes to read - int remaining = currentPayloadLength-resbufLength; + uint32_t remaining = currentPayloadLength-resbufLength; if(remaining > 0) { - socket->readData(resbuf+resbufLength, remaining); + socket->readData((char*)resbuf+resbufLength, (int&)remaining); if(remaining == 0) { // we got EOF throw new DlAbortEx(EX_EOF_FROM_PEER); @@ -107,19 +110,19 @@ bool PeerConnection::receiveMessage(char* msg, int& length) { resbufLength = 0; lenbufLength = 0; - memcpy(msg, resbuf, currentPayloadLength); - length = currentPayloadLength; + memcpy(data, resbuf, currentPayloadLength); + dataLength = currentPayloadLength; return true; } -bool PeerConnection::receiveHandshake(char* msg, int& length) { +bool PeerConnection::receiveHandshake(unsigned char* data, uint32_t& dataLength) { if(!socket->isReadable(0)) { - length = 0; + dataLength = 0; return false; } - int remain = HANDSHAKE_MESSAGE_LENGTH-resbufLength; - int temp = remain; - socket->readData(resbuf+resbufLength, temp); + uint32_t remain = BtHandshakeMessage::MESSAGE_LENGTH-resbufLength; + uint32_t temp = remain; + socket->readData((char*)resbuf+resbufLength, (int&)temp); if(temp == 0) { // we got EOF throw new DlAbortEx(EX_EOF_FROM_PEER); @@ -132,9 +135,9 @@ bool PeerConnection::receiveHandshake(char* msg, int& length) { } resbufLength += temp; // we got whole handshake payload - int writeLength = resbufLength > length ? length : resbufLength; - memcpy(msg, resbuf, writeLength); - length = writeLength; + uint32_t writeLength = resbufLength > dataLength ? dataLength : resbufLength; + memcpy(data, resbuf, writeLength); + dataLength = writeLength; if(retval) { resbufLength = 0; } diff --git a/src/PeerConnection.h b/src/PeerConnection.h index de52f004..5787db80 100644 --- a/src/PeerConnection.h +++ b/src/PeerConnection.h @@ -38,7 +38,6 @@ #include "Option.h" #include "Socket.h" #include "Logger.h" -#include "PeerMessage.h" #include "common.h" // we assume maximum length of incoming message is "piece" message with 16KB @@ -47,32 +46,44 @@ class PeerConnection { private: - int cuid; + int32_t cuid; SocketHandle socket; const Option* option; const Logger* logger; char resbuf[MAX_PAYLOAD_LEN]; - int resbufLength; - int currentPayloadLength; - char lenbuf[4]; - int lenbufLength; + uint32_t resbufLength; + uint32_t currentPayloadLength; + unsigned char lenbuf[4]; + uint32_t lenbufLength; public: - PeerConnection(int cuid, const SocketHandle& socket, const Option* op); + PeerConnection(int32_t cuid, const SocketHandle& socket, const Option* op); ~PeerConnection(); // Returns the number of bytes written - int sendMessage(const char* msg, int length); + uint32_t sendMessage(const unsigned char* data, uint32_t dataLength); + uint32_t sendMessage(const char* msg, int length) { + return sendMessage((const unsigned char*)msg, (uint32_t)length); + } + + bool receiveMessage(unsigned char* data, uint32_t& dataLength); + bool receiveMessage(char* msg, int& length) { + return receiveMessage((unsigned char*)msg, (uint32_t&)length); + } - bool receiveMessage(char* msg, int& length); /** * Returns true if a handshake message is fully received, otherwise returns * false. * In both cases, 'msg' is filled with received bytes and the filled length * is assigned to 'length'. */ - bool receiveHandshake(char* msg, int& length); + bool receiveHandshake(unsigned char* data, uint32_t& dataLength); + bool receiveHandshake(char* msg, int& length) { + return receiveHandshake((unsigned char*)msg, (uint32_t&)length); + } }; +typedef SharedHandle PeerConnectionHandle; + #endif // _D_PEER_CONNECTION_H_ diff --git a/src/PeerInteraction.cc b/src/PeerInteraction.cc index 1ec87ce0..bed01a01 100644 --- a/src/PeerInteraction.cc +++ b/src/PeerInteraction.cc @@ -123,8 +123,8 @@ void PeerInteraction::rejectPieceMessageInQueue(int index, int begin, int length void PeerInteraction::onChoked() { for(Pieces::iterator itr = pieces.begin(); itr != pieces.end();) { - Piece& piece = *itr; - if(!peer->isInFastSet(piece.getIndex())) { + PieceHandle& piece = *itr; + if(!peer->isInFastSet(piece->getIndex())) { abortPiece(piece); itr = pieces.erase(itr); } else { @@ -140,20 +140,20 @@ void PeerInteraction::abortAllPieces() { } } -void PeerInteraction::abortPiece(Piece& piece) { - if(!Piece::isNull(piece)) { +void PeerInteraction::abortPiece(const PieceHandle& piece) { + if(!piece.isNull()) { int size = messageQueue.size(); for(int i = 0; i < size; i++) { messageQueue.at(i)->onAbortPiece(piece); } for(RequestSlots::iterator itr = requestSlots.begin(); itr != requestSlots.end();) { - if(itr->getIndex() == piece.getIndex()) { + if(itr->getIndex() == piece->getIndex()) { logger->debug("CUID#%d - Deleting request slot blockIndex=%d" " because piece was canceled", cuid, itr->getBlockIndex()); - piece.cancelBlock(itr->getBlockIndex()); + piece->cancelBlock(itr->getBlockIndex()); itr = requestSlots.erase(itr); } else { itr++; @@ -181,14 +181,14 @@ void PeerInteraction::checkRequestSlot() { " because of time out", cuid, slot.getBlockIndex()); - Piece& piece = getDownloadPiece(slot.getIndex()); - piece.cancelBlock(slot.getBlockIndex()); + PieceHandle piece = getDownloadPiece(slot.getIndex()); + piece->cancelBlock(slot.getBlockIndex()); itr = requestSlots.erase(itr); peer->snubbing = true; } else { - Piece piece = getDownloadPiece(slot.getIndex()); - if(piece.hasBlock(slot.getBlockIndex()) || - pieceStorage->hasPiece(piece.getIndex())) { + PieceHandle piece = getDownloadPiece(slot.getIndex()); + if(piece->hasBlock(slot.getBlockIndex()) || + pieceStorage->hasPiece(piece->getIndex())) { logger->debug("CUID#%d - Deleting request slot blockIndex=%d because" " the block has been acquired.", cuid, slot.getBlockIndex()); @@ -275,15 +275,19 @@ PeerMessageHandle PeerInteraction::receiveMessage() { } void PeerInteraction::syncPiece() { + /* for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) { pieceStorage->syncPiece(*itr); } + */ } void PeerInteraction::updatePiece() { + /* for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) { pieceStorage->updatePiece(*itr); } + */ } void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) { @@ -297,8 +301,8 @@ void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) { onChoked(); if(peer->isFastExtensionEnabled()) { while((int)pieces.size() < pieceNum) { - Piece piece = pieceStorage->getMissingFastPiece(peer); - if(Piece::isNull(piece)) { + PieceHandle piece = pieceStorage->getMissingFastPiece(peer); + if(piece.isNull()) { break; } else { pieces.push_back(piece); @@ -307,8 +311,8 @@ void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) { } } else { while((int)pieces.size() < pieceNum) { - Piece piece = pieceStorage->getMissingPiece(peer); - if(Piece::isNull(piece)) { + PieceHandle piece = pieceStorage->getMissingPiece(peer); + if(piece.isNull()) { break; } else { pieces.push_back(piece); @@ -325,8 +329,8 @@ void PeerInteraction::getNewPieceAndSendInterest(int pieceNum) { void PeerInteraction::addRequests() { // Abort downloading of completed piece. for(Pieces::iterator itr = pieces.begin(); itr != pieces.end();) { - Piece& piece = *itr; - if(piece.pieceComplete()) { + PieceHandle& piece = *itr; + if(piece->pieceComplete()) { abortPiece(piece); itr = pieces.erase(itr); } else { @@ -350,16 +354,16 @@ void PeerInteraction::addRequests() { } getNewPieceAndSendInterest(pieceNum); for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) { - Piece& piece = *itr; + PieceHandle& piece = *itr; if(pieceStorage->isEndGame()) { - BlockIndexes missingBlockIndexes = piece.getAllMissingBlockIndexes(); + BlockIndexes missingBlockIndexes = piece->getAllMissingBlockIndexes(); random_shuffle(missingBlockIndexes.begin(), missingBlockIndexes.end()); int count = countRequestSlot(); for(BlockIndexes::const_iterator bitr = missingBlockIndexes.begin(); bitr != missingBlockIndexes.end() && count < MAX_PENDING_REQUEST; bitr++) { int blockIndex = *bitr; - if(!isInRequestSlot(piece.getIndex(), blockIndex)) { + if(!isInRequestSlot(piece->getIndex(), blockIndex)) { addMessage(peerMessageFactory->createRequestMessage(piece, blockIndex)); count++; @@ -367,7 +371,7 @@ void PeerInteraction::addRequests() { } } else { while(countRequestSlot() < MAX_PENDING_REQUEST) { - int blockIndex = piece.getMissingUnusedBlockIndex(); + int blockIndex = piece->getMissingUnusedBlockIndex(); if(blockIndex == -1) { break; } @@ -385,7 +389,7 @@ void PeerInteraction::addRequests() { void PeerInteraction::sendHandshake() { PeerMessageHandle handle = peerMessageFactory->createHandshakeMessage(btContext->getInfoHash(), - btAnnounce->getPeerId().c_str()); + (const char*)btContext->getPeerId()); addMessage(handle); sendMessages(); } @@ -420,9 +424,9 @@ void PeerInteraction::sendAllowedFast() { } } -Piece& PeerInteraction::getDownloadPiece(int index) { +PieceHandle PeerInteraction::getDownloadPiece(int index) { for(Pieces::iterator itr = pieces.begin(); itr != pieces.end(); itr++) { - if(itr->getIndex() == index) { + if((*itr)->getIndex() == index) { return *itr; } } @@ -431,7 +435,7 @@ Piece& PeerInteraction::getDownloadPiece(int index) { bool PeerInteraction::hasDownloadPiece(int index) const { for(Pieces::const_iterator itr = pieces.begin(); itr != pieces.end(); itr++) { - if(itr->getIndex() == index) { + if((*itr)->getIndex() == index) { return true; } } diff --git a/src/PeerInteraction.h b/src/PeerInteraction.h index 670cb0e2..de2d5d57 100644 --- a/src/PeerInteraction.h +++ b/src/PeerInteraction.h @@ -48,7 +48,6 @@ #define REQUEST_TIME_OUT 60 #define ALLOWED_FAST_SET_SIZE 10 -typedef deque RequestSlots; typedef deque MessageQueue; class PeerInteraction { @@ -85,7 +84,7 @@ public: void rejectPieceMessageInQueue(int index, int begin, int length); void rejectAllPieceMessageInQueue(); void onChoked(); - void abortPiece(Piece& piece); + void abortPiece(const PieceHandle& piece); void abortAllPieces(); bool isSendingMessageInProgress() const; @@ -104,7 +103,7 @@ public: // If the piece which this object has is nullPiece, then throws an exception. // So before calling this function, call hasDownloadPiece and make sure // this has valid piece, not nullPiece. - Piece& getDownloadPiece(int index); + PieceHandle getDownloadPiece(int index); bool isInFastSet(int index) const; diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index 86a6c3cd..20992357 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -35,15 +35,17 @@ #include "PeerInteractionCommand.h" #include "PeerInitiateConnectionCommand.h" #include "PeerMessageUtil.h" -#include "HandshakeMessage.h" -#include "KeepAliveMessage.h" -#include "ChokeMessage.h" -#include "UnchokeMessage.h" -#include "HaveMessage.h" +#include "DefaultBtInteractive.h" #include "DlAbortEx.h" #include "Util.h" #include "message.h" #include "prefs.h" +#include "DefaultBtMessageDispatcher.h" +#include "DefaultBtMessageReceiver.h" +#include "DefaultBtRequestFactory.h" +#include "DefaultBtMessageFactory.h" +#include "DefaultBtInteractive.h" +#include "PeerConnection.h" #include PeerInteractionCommand::PeerInteractionCommand(int cuid, @@ -52,198 +54,135 @@ PeerInteractionCommand::PeerInteractionCommand(int cuid, const BtContextHandle& btContext, const SocketHandle& s, int sequence) - :PeerAbstractCommand(cuid, p, e, btContext, s), sequence(sequence) { + :PeerAbstractCommand(cuid, p, e, btContext, s), + sequence(sequence), + btInteractive(0) +{ + // TODO move following bunch of processing to separate method, like init() if(sequence == INITIATOR_SEND_HANDSHAKE) { disableReadCheckSocket(); setWriteCheckSocket(socket); setTimeout(e->option->getAsInt(PREF_PEER_CONNECTION_TIMEOUT)); } - peerInteraction = new PeerInteraction(cuid, peer, socket, e->option, - btContext); + PeerConnectionHandle peerConnection = + new PeerConnection(cuid, socket, e->option); + + DefaultBtMessageDispatcherHandle dispatcher = new DefaultBtMessageDispatcher(); + dispatcher->setCuid(cuid); + dispatcher->setPeer(peer); + dispatcher->setBtContext(btContext); + dispatcher->setOption(e->option); + + DefaultBtMessageReceiverHandle receiver = new DefaultBtMessageReceiver(); + receiver->setCuid(cuid); + receiver->setPeer(peer); + receiver->setBtContext(btContext); + receiver->setPeerConnection(peerConnection); + receiver->setDispatcher(dispatcher); + + DefaultBtRequestFactoryHandle reqFactory = new DefaultBtRequestFactory(); + reqFactory->setCuid(cuid); + reqFactory->setPeer(peer); + reqFactory->setBtContext(btContext); + reqFactory->setBtMessageDispatcher(dispatcher); + + DefaultBtInteractiveHandle btInteractive = new DefaultBtInteractive(); + btInteractive->setCuid(cuid); + btInteractive->setPeer(peer); + btInteractive->setBtContext(btContext); + btInteractive->setBtMessageReceiver(receiver); + btInteractive->setDispatcher(dispatcher); + btInteractive->setBtRequestFactory(reqFactory); + btInteractive->setPeerConnection(peerConnection); + btInteractive->setOption(e->option); + this->btInteractive = btInteractive; + + DefaultBtMessageFactoryHandle factory = new DefaultBtMessageFactory(); + factory->setCuid(cuid); + factory->setBtContext(btContext); + factory->setPeer(peer); + + PeerObjectHandle peerObject = new PeerObject(); + peerObject->btMessageDispatcher = dispatcher; + peerObject->btMessageFactory = factory; + peerObject->btRequestFactory = reqFactory; + peerObject->peerConnection = peerConnection; + + PEER_OBJECT_CLUSTER(btContext)->registerHandle(peer->getId(), peerObject); + setUploadLimit(e->option->getAsInt(PREF_MAX_UPLOAD_LIMIT)); - chokeUnchokeCount = 0; - haveCount = 0; - keepAliveCount = 0; peer->activate(); } PeerInteractionCommand::~PeerInteractionCommand() { - delete peerInteraction; peer->deactivate(); + PEER_OBJECT_CLUSTER(btContext)->unregisterHandle(peer->getId()); + + logger->debug("CUID#%d - unregistered message factory using ID:%s", + cuid, peer->getId().c_str()); } bool PeerInteractionCommand::executeInternal() { + setReadCheckSocket(socket); disableWriteCheckSocket(); setUploadLimitCheck(false); setNoCheck(false); - switch(sequence) { case INITIATOR_SEND_HANDSHAKE: if(!socket->isWritable(0)) { + disableReadCheckSocket(); setWriteCheckSocket(socket); break; } socket->setBlockingMode(); - setReadCheckSocket(socket); - setTimeout(e->option->getAsInt(PREF_TIMEOUT)); - peerInteraction->sendHandshake(); + setTimeout(e->option->getAsInt(PREF_BT_TIMEOUT)); + btInteractive->initiateHandshake(); sequence = INITIATOR_WAIT_HANDSHAKE; break; case INITIATOR_WAIT_HANDSHAKE: { - if(peerInteraction->countMessageInQueue() > 0) { - peerInteraction->sendMessages(); - if(peerInteraction->countMessageInQueue() > 0) { + if(btInteractive->countPendingMessage() > 0) { + btInteractive->sendPendingMessage(); + if(btInteractive->countPendingMessage() > 0) { break; } } - PeerMessageHandle handshakeMessage = - peerInteraction->receiveHandshake(); - if(handshakeMessage.get() == 0) { + BtMessageHandle handshakeMessage = btInteractive->receiveHandshake(); + if(handshakeMessage.isNull()) { break; } - peer->setPeerId(((HandshakeMessage*)handshakeMessage.get())->peerId); - logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid, - peer->ipaddr.c_str(), peer->port, - handshakeMessage->toString().c_str()); - haveCheckTime.reset(); - peerInteraction->sendBitfield(); - peerInteraction->sendAllowedFast(); + btInteractive->doPostHandshakeProcessing(); sequence = WIRED; break; } case RECEIVER_WAIT_HANDSHAKE: { - PeerMessageHandle handshakeMessage = - peerInteraction->receiveHandshake(true); - if(handshakeMessage.get() == 0) { + BtMessageHandle handshakeMessage = btInteractive->receiveAndSendHandshake(); + if(handshakeMessage.isNull()) { break; } - peer->setPeerId(((HandshakeMessage*)handshakeMessage.get())->peerId); - logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid, - peer->ipaddr.c_str(), peer->port, - handshakeMessage->toString().c_str()); - haveCheckTime.reset(); - peerInteraction->sendBitfield(); - peerInteraction->sendAllowedFast(); + btInteractive->doPostHandshakeProcessing(); sequence = WIRED; break; } case WIRED: - peerInteraction->syncPiece(); - decideChoking(); + btInteractive->doInteractionProcessing(); - if(periodicExecPoint.elapsedInMillis(500)) { - periodicExecPoint.reset(); - detectMessageFlooding(); - peerInteraction->checkRequestSlot(); - checkHave(); - sendKeepAlive(); - } - receiveMessages(); - - peerInteraction->addRequests(); - - peerInteraction->sendMessages(); break; } - if(peerInteraction->countMessageInQueue() > 0) { - if(peerInteraction->isSendingMessageInProgress()) { - setUploadLimitCheck(true); - } + if(btInteractive->countPendingMessage() > 0) { setNoCheck(true); } + int maxSpeedLimit = e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT); + if(maxSpeedLimit > 0) { + TransferStat stat = peerStorage->calculateStat(); + if(maxSpeedLimit < stat.downloadSpeed) { + disableReadCheckSocket(); + setNoCheck(true); + } + } e->commands.push_back(this); return false; } -#define FLOODING_CHECK_INTERVAL 5 - -void PeerInteractionCommand::detectMessageFlooding() { - if(freqCheckPoint.elapsed(FLOODING_CHECK_INTERVAL)) { - if(chokeUnchokeCount*1.0/FLOODING_CHECK_INTERVAL >= 0.4 - //|| haveCount*1.0/elapsed >= 20.0 - || keepAliveCount*1.0/FLOODING_CHECK_INTERVAL >= 1.0) { - throw new DlAbortEx("Flooding detected."); - } else { - chokeUnchokeCount = 0; - haveCount = 0; - keepAliveCount = 0; - freqCheckPoint.reset(); - } - } -} - -/* -void PeerInteractionCommand::checkLongTimePeerChoking() { - if(pieceStorage->downloadFinished()) { - return; - } - if(peer->amInterested && peer->peerChoking) { - if(chokeCheckPoint.elapsed(MAX_PEER_CHOKING_INTERVAL)) { - logger->info("CUID#%d - The peer is choking too long.", cuid); - peer->snubbing = true; - } - } else { - chokeCheckPoint.reset(); - } -} -*/ - -void PeerInteractionCommand::decideChoking() { - if(peer->shouldBeChoking()) { - if(!peer->amChoking) { - peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> - createChokeMessage()); - } - } else { - if(peer->amChoking) { - peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> - createUnchokeMessage()); - } - } -} - -void PeerInteractionCommand::receiveMessages() { - for(int i = 0; i < 50; i++) { - int maxSpeedLimit = e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT); - if(maxSpeedLimit > 0) { - TransferStat stat = peerStorage->calculateStat(); - if(maxSpeedLimit < stat.downloadSpeed) { - disableReadCheckSocket(); - setNoCheck(true); - break; - } - } - - PeerMessageHandle message = peerInteraction->receiveMessage(); - if(message.get() == NULL) { - return; - } - logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid, - peer->ipaddr.c_str(), peer->port, - message->toString().c_str()); - // to detect flooding - switch(message->getId()) { - case KeepAliveMessage::ID: - keepAliveCount++; - break; - case ChokeMessage::ID: - if(!peer->peerChoking) { - chokeUnchokeCount++; - } - break; - case UnchokeMessage::ID: - if(peer->peerChoking) { - chokeUnchokeCount++; - } - break; - case HaveMessage::ID: - haveCount++; - break; - } - message->receivedAction(); - } -} - // TODO this method removed when PeerBalancerCommand is implemented bool PeerInteractionCommand::prepareForNextPeer(int wait) { if(peerStorage->isPeerAvailable() && btRuntime->lessThanEqMinPeer()) { @@ -266,42 +205,6 @@ bool PeerInteractionCommand::prepareForRetry(int wait) { } void PeerInteractionCommand::onAbort(Exception* ex) { - peerInteraction->abortAllPieces(); + btInteractive->cancelAllPiece(); PeerAbstractCommand::onAbort(ex); } - -void PeerInteractionCommand::sendKeepAlive() { - if(keepAliveCheckPoint.elapsed(KEEP_ALIVE_INTERVAL)) { - if(peerInteraction->countMessageInQueue() == 0) { - peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> - createKeepAliveMessage()); - peerInteraction->sendMessages(); - } - keepAliveCheckPoint.reset(); - } -} - -void PeerInteractionCommand::checkHave() { - Integers indexes = - pieceStorage->getAdvertisedPieceIndexes(cuid, haveCheckTime); - haveCheckTime.reset(); - if(indexes.size() >= 20) { - if(peer->isFastExtensionEnabled()) { - if(pieceStorage->downloadFinished()) { - peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> - createHaveAllMessage()); - } else { - peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> - createBitfieldMessage()); - } - } else { - peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> - createBitfieldMessage()); - } - } else { - for(Integers::iterator itr = indexes.begin(); itr != indexes.end(); itr++) { - peerInteraction->addMessage(peerInteraction->getPeerMessageFactory()-> - createHaveMessage(*itr)); - } - } -} diff --git a/src/PeerInteractionCommand.h b/src/PeerInteractionCommand.h index 73b9fc54..e4842e7b 100644 --- a/src/PeerInteractionCommand.h +++ b/src/PeerInteractionCommand.h @@ -36,45 +36,24 @@ #define _D_PEER_INTERACTION_COMMAND_H_ #include "PeerAbstractCommand.h" -#include "PeerConnection.h" -#include "PeerInteraction.h" -#include "TimeA2.h" - -using namespace std; - -#define MAX_PEER_CHOKING_INTERVAL (1*60) -#define KEEP_ALIVE_INTERVAL 120 +#include "BtInteractive.h" class PeerInteractionCommand : public PeerAbstractCommand { private: int sequence; - PeerInteraction* peerInteraction; - - Time keepAliveCheckPoint; - //Time chokeCheckPoint; - Time freqCheckPoint; - Time haveCheckTime; - Time periodicExecPoint; - int chokeUnchokeCount; - int haveCount; - int keepAliveCount; - void receiveMessages(); - void detectMessageFlooding(); - void checkLongTimePeerChoking(); - void detectTimeoutAndDuplicateBlock(); - void decideChoking(); - void sendKeepAlive(); - void checkHave(); + BtInteractiveHandle btInteractive; protected: bool executeInternal(); bool prepareForRetry(int wait); bool prepareForNextPeer(int wait); void onAbort(Exception* ex); public: - PeerInteractionCommand(int cuid, const PeerHandle& peer, + PeerInteractionCommand(int cuid, + const PeerHandle& peer, TorrentDownloadEngine* e, const BtContextHandle& btContext, - const SocketHandle& s, int sequence); + const SocketHandle& s, + int sequence); ~PeerInteractionCommand(); diff --git a/src/PeerMessage.cc b/src/PeerMessage.cc index fe440668..2ce7903b 100644 --- a/src/PeerMessage.cc +++ b/src/PeerMessage.cc @@ -39,6 +39,7 @@ PeerMessage::PeerMessage() :inProgress(false), invalidate(false), uploading(false), + peer(0), btContext(0), peerStorage(0), pieceStorage(0) diff --git a/src/PeerMessage.h b/src/PeerMessage.h index 2d54646b..ebe581c3 100644 --- a/src/PeerMessage.h +++ b/src/PeerMessage.h @@ -100,7 +100,7 @@ public: virtual void onPush() {} virtual void onChoked() {} virtual void onCanceled(int index, int begin, int blockLength) {} - virtual void onAbortPiece(const Piece& piece) {} + virtual void onAbortPiece(const PieceHandle& piece) {} }; typedef SharedHandle PeerMessageHandle; diff --git a/src/PeerMessageFactory.cc b/src/PeerMessageFactory.cc index 95709c8e..f3f4b810 100644 --- a/src/PeerMessageFactory.cc +++ b/src/PeerMessageFactory.cc @@ -171,12 +171,12 @@ PeerMessageFactory::setPeerMessageCommonProperty(PeerMessageHandle& peerMessage) peerMessage->setBtContext(btContext); } -PeerMessageHandle PeerMessageFactory::createRequestMessage(const Piece& piece, +PeerMessageHandle PeerMessageFactory::createRequestMessage(const PieceHandle& piece, int blockIndex) const { PeerMessageHandle handle = - PeerMessageHandle(new RequestMessage(piece.getIndex(), - blockIndex*piece.getBlockLength(), - piece.getBlockLength(blockIndex), + PeerMessageHandle(new RequestMessage(piece->getIndex(), + blockIndex*piece->getBlockLength(), + piece->getBlockLength(blockIndex), blockIndex)); setPeerMessageCommonProperty(handle); return handle; diff --git a/src/PeerMessageFactory.h b/src/PeerMessageFactory.h index 481a0b31..7d7856f7 100644 --- a/src/PeerMessageFactory.h +++ b/src/PeerMessageFactory.h @@ -71,7 +71,7 @@ public: createHandshakeMessage(const unsigned char* infoHash, const char* peerId) const; - PeerMessageHandle createRequestMessage(const Piece& piece, + PeerMessageHandle createRequestMessage(const PieceHandle& piece, int blockIndex) const; PeerMessageHandle createCancelMessage(int index, int begin, int length) const; PeerMessageHandle createPieceMessage(int index, int begin, int length) const; diff --git a/src/PeerMessageUtil.cc b/src/PeerMessageUtil.cc index 58728a9c..33cfe7be 100644 --- a/src/PeerMessageUtil.cc +++ b/src/PeerMessageUtil.cc @@ -37,67 +37,69 @@ #include "Util.h" #include -int PeerMessageUtil::getId(const char* msg) { - return (int)msg[0]; +int32_t PeerMessageUtil::getId(const unsigned char* msg) { + return (int32_t)msg[0]; } -int PeerMessageUtil::getIntParam(const char* msg, int offset) { - int nParam; - memcpy(&nParam, msg+offset, 4); +uint32_t PeerMessageUtil::getIntParam(const unsigned char* msg, int32_t offset) { + uint32_t nParam; + memcpy(&nParam, msg+offset, sizeof(uint32_t)); return ntohl(nParam); } -int PeerMessageUtil::getShortIntParam(const char* msg, int offset) { - short int nParam; - memcpy(&nParam, msg+offset, 2); +uint16_t PeerMessageUtil::getShortIntParam(const unsigned char* msg, int32_t offset) { + uint16_t nParam; + memcpy(&nParam, msg+offset, sizeof(uint16_t)); return ntohs(nParam); } -void PeerMessageUtil::checkIndex(int index, int pieces) { +void PeerMessageUtil::checkIndex(uint32_t index, uint32_t pieces) { if(!(0 <= index && index < pieces)) { - throw new DlAbortEx("invalid index = %d", index); + throw new DlAbortEx("invalid index = %u", index); } } -void PeerMessageUtil::checkBegin(int begin, int pieceLength) { +void PeerMessageUtil::checkBegin(uint32_t begin, uint32_t pieceLength) { if(!(0 <= begin && begin < pieceLength)) { - throw new DlAbortEx("invalid begin = %d", begin); + throw new DlAbortEx("invalid begin = %u", begin); } } -void PeerMessageUtil::checkLength(int length) { +void PeerMessageUtil::checkLength(uint32_t length) { if(length > MAX_BLOCK_LENGTH) { - throw new DlAbortEx("too large length %d > %dKB", length, + throw new DlAbortEx("too large length %u > %dKB", length, MAX_BLOCK_LENGTH/1024); } if(length <= 0) { - throw new DlAbortEx("invalid length %d", length); + throw new DlAbortEx("invalid length %u", length); } if(!Util::isPowerOf(length, 2)) { - throw new DlAbortEx("invalid length %d, which is not power of 2", + throw new DlAbortEx("invalid length %u, which is not power of 2", length); } } -void PeerMessageUtil::checkRange(int begin, int length, int pieceLength) { +void PeerMessageUtil::checkRange(uint32_t begin, uint32_t length, uint32_t pieceLength) { if(!(0 <= begin && 0 < length)) { - throw new DlAbortEx("invalid range, begin = %d, length = %d", + throw new DlAbortEx("invalid range, begin = %u, length = %u", begin, length); } - int end = begin+length; + uint32_t end = begin+length; if(!(0 < end && end <= pieceLength)) { - throw new DlAbortEx("invalid range, begin = %d, length = %d", + throw new DlAbortEx("invalid range, begin = %u, length = %u", begin, length); } } -void PeerMessageUtil::checkBitfield(const unsigned char* bitfield, int bitfieldLength, int pieces) { +void PeerMessageUtil::checkBitfield(const unsigned char* bitfield, + uint32_t bitfieldLength, + uint32_t pieces) { if(!(bitfieldLength == BITFIELD_LEN_FROM_PIECES(pieces))) { throw new DlAbortEx("invalid bitfield length = %d", bitfieldLength); } char lastbyte = bitfield[bitfieldLength-1]; - for(int i = 0; i < 8-pieces%8 && pieces%8 != 0; i++) { + for(uint32_t i = 0; i < 8-pieces%8 && pieces%8 != 0; i++) { if(!(((lastbyte >> i) & 1) == 0)) { throw new DlAbortEx("invalid bitfield"); } @@ -119,14 +121,20 @@ 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::setIntParam(unsigned char* dest, uint32_t param) { + uint32_t nParam = htonl(param); + memcpy(dest, &nParam, sizeof(uint32_t)); } -void PeerMessageUtil::createPeerMessageString(char* msg, int msgLength, - int payloadLength, - int messageId) { +void PeerMessageUtil::setShortIntParam(unsigned char* dest, uint16_t param) { + uint16_t nParam = htons(param); + memcpy(dest, &nParam, sizeof(uint16_t)); +} + +void PeerMessageUtil::createPeerMessageString(unsigned char* msg, + uint32_t msgLength, + uint32_t payloadLength, + int32_t messageId) { assert(msgLength >= 5); memset(msg, 0, msgLength); setIntParam(msg, payloadLength); diff --git a/src/PeerMessageUtil.h b/src/PeerMessageUtil.h index 3d11b1b3..aac462d3 100644 --- a/src/PeerMessageUtil.h +++ b/src/PeerMessageUtil.h @@ -44,25 +44,57 @@ class PeerMessageUtil { private: PeerMessageUtil() {} public: - static int getIntParam(const char* msg, int offset); - static int getShortIntParam(const char* msg, int offset); - static void setIntParam(char* dest, int param); + static uint32_t getIntParam(const unsigned char* msg, int32_t offset); + static uint32_t getIntParam(const char* msg, int32_t offset) { + return getIntParam((const unsigned char*)msg, offset); + } - static int getId(const char* msg); + static uint16_t getShortIntParam(const unsigned char* msg, int32_t offset); + static uint16_t getShortIntParam(const char* msg, int32_t offset) { + return getShortIntParam((const unsigned char*)msg, offset); + } + + static void setIntParam(unsigned char* dest, uint32_t param); + static void setIntParam(char* dest, uint32_t param) { + setIntParam((unsigned char*)dest, param); + } + + static void setShortIntParam(unsigned char* dest, uint16_t param); + static void setShortIntParam(char* dest, uint16_t param) { + setShortIntParam((unsigned char*)dest, param); + } + + static int32_t getId(const unsigned char* msg); + static int32_t getId(const char* msg) { + return getId((const unsigned char*)msg); + } - static void checkIndex(int index, int pieces); - static void checkBegin(int begin, int pieceLength); - static void checkLength(int length); - static void checkRange(int begin, int length, int pieceLength); + static void checkIndex(uint32_t index, uint32_t pieces); + static void checkBegin(uint32_t begin, uint32_t pieceLength); + static void checkLength(uint32_t length); + static void checkRange(uint32_t begin, uint32_t length, uint32_t pieceLength); static void checkBitfield(const unsigned char* bitfield, - int bitfieldLength, - int pieces); + uint32_t bitfieldLength, + uint32_t pieces); + static void checkBitfield(const char* bitfield, + uint32_t bitfieldLength, + uint32_t pieces) { + checkBitfield((unsigned char*)bitfield, bitfieldLength, pieces); + } static void checkHandshake(const HandshakeMessage* message, const unsigned char* infoHash); - static void createPeerMessageString(char* msg, int msgLength, - int payloadLength, int messageId); + static void createPeerMessageString(unsigned char* msg, + uint32_t msgLength, + uint32_t payloadLength, + int32_t messageId); + static void createPeerMessageString(char* msg, + uint32_t msgLength, + uint32_t payloadLength, + int32_t messageId) { + createPeerMessageString((unsigned char*)msg, msgLength, payloadLength, messageId); + } }; #endif // _D_PEER_MESSAGE_UTIL_H_ diff --git a/src/PeerObject.h b/src/PeerObject.h new file mode 100644 index 00000000..3accdc03 --- /dev/null +++ b/src/PeerObject.h @@ -0,0 +1,59 @@ +/* */ +#ifndef _D_PEER_OBJECT_H_ +#define _D_PEER_OBJECT_H_ + +#include "common.h" +#include "BtMessageFactory.h" +#include "BtRequestFactory.h" +#include "BtMessageDispatcher.h" +#include "PeerConnection.h" + +class PeerObject { +public: + PeerObject():btMessageFactory(0), + btRequestFactory(0), + btMessageDispatcher(0), + peerConnection(0) {} + + BtMessageFactoryHandle btMessageFactory; + BtRequestFactoryHandle btRequestFactory; + BtMessageDispatcherHandle btMessageDispatcher; + PeerConnectionHandle peerConnection; +}; + +typedef SharedHandle PeerObjectHandle; + +#endif // _D_PEER_OBJECT_H_ diff --git a/src/Piece.cc b/src/Piece.cc index f8d5ed68..1bba051b 100644 --- a/src/Piece.cc +++ b/src/Piece.cc @@ -34,8 +34,25 @@ /* copyright --> */ #include "Piece.h" #include "Util.h" +#include "BitfieldManFactory.h" + +Piece::Piece():index(0), length(0), bitfield(0) {} + +Piece::Piece(int index, int length):index(index), length(length) { + bitfield = + BitfieldManFactory::getNewFactory()->createBitfieldMan(BLOCK_LENGTH, length); +} + +Piece::Piece(const Piece& piece) { + index = piece.index; + length = piece.length; + if(piece.bitfield == 0) { + bitfield = 0; + } else { + bitfield = new BitfieldMan(*piece.bitfield); + } +} -Piece Piece::nullPiece; void Piece::completeBlock(int blockIndex) { bitfield->setBit(blockIndex); diff --git a/src/Piece.h b/src/Piece.h index f18eae38..79be4b3f 100644 --- a/src/Piece.h +++ b/src/Piece.h @@ -46,20 +46,11 @@ private: int length; BitfieldMan* bitfield; public: - Piece():index(0), length(0), bitfield(NULL) {} - Piece(int index, int length):index(index), length(length) { - bitfield = new BitfieldMan(BLOCK_LENGTH, length); - } + Piece(); - Piece(const Piece& piece) { - index = piece.index; - length = piece.length; - if(piece.bitfield == NULL) { - bitfield = NULL; - } else { - bitfield = new BitfieldMan(*piece.bitfield); - } - } + Piece(int index, int length); + + Piece(const Piece& piece); ~Piece() { delete bitfield; @@ -119,12 +110,12 @@ public: string toString() const; - static Piece nullPiece; - static bool isNull(const Piece& piece) { - return piece.index == 0 && piece.length == 0; + bool isBlockUsed(int index) const { + return bitfield->isUseBitSet(index); } }; -typedef deque Pieces; +typedef SharedHandle PieceHandle; +typedef deque Pieces; #endif // _D_PIECE_H_ diff --git a/src/PieceMessage.cc b/src/PieceMessage.cc index 367ad2f9..0e55a92f 100644 --- a/src/PieceMessage.cc +++ b/src/PieceMessage.cc @@ -74,7 +74,7 @@ void PieceMessage::receivedAction() { peer->snubbing = false; //logger->debug("CUID#%d - Latency=%d", cuid, slot.getLatencyInMillis()); peer->updateLatency(slot.getLatencyInMillis()); - Piece& piece = peerInteraction->getDownloadPiece(slot.getIndex()); + PieceHandle piece = peerInteraction->getDownloadPiece(slot.getIndex()); long long int offset = ((long long int)index)*btContext->getPieceLength()+begin; logger->debug("CUID#%d - Writing the block length=%d, offset=%lld", @@ -82,12 +82,12 @@ void PieceMessage::receivedAction() { pieceStorage->getDiskAdaptor()->writeData(block, blockLength, offset); - piece.completeBlock(slot.getBlockIndex()); + piece->completeBlock(slot.getBlockIndex()); peerInteraction->deleteRequestSlot(slot); - pieceStorage->updatePiece(piece); + //pieceStorage->updatePiece(piece); logger->debug("CUID#%d - Setting piece block index=%d", cuid, slot.getBlockIndex()); - if(piece.pieceComplete()) { + if(piece->pieceComplete()) { if(checkPieceHash(piece)) { onGotNewPiece(piece); } else { @@ -196,38 +196,38 @@ string PieceMessage::toString() const { ", length="+Util::itos(blockLength); } -bool PieceMessage::checkPieceHash(const Piece& piece) { +bool PieceMessage::checkPieceHash(const PieceHandle& piece) { long long int offset = - ((long long int)piece.getIndex())*btContext->getPieceLength(); - return pieceStorage->getDiskAdaptor()->sha1Sum(offset, piece.getLength()) == - btContext->getPieceHash(piece.getIndex()); + ((long long int)piece->getIndex())*btContext->getPieceLength(); + return pieceStorage->getDiskAdaptor()->sha1Sum(offset, piece->getLength()) == + btContext->getPieceHash(piece->getIndex()); } -void PieceMessage::onGotNewPiece(Piece& piece) { - logger->info(MSG_GOT_NEW_PIECE, cuid, piece.getIndex()); +void PieceMessage::onGotNewPiece(const PieceHandle& piece) { + logger->info(MSG_GOT_NEW_PIECE, cuid, piece->getIndex()); pieceStorage->completePiece(piece); - pieceStorage->advertisePiece(cuid, piece.getIndex()); + pieceStorage->advertisePiece(cuid, piece->getIndex()); } -void PieceMessage::onGotWrongPiece(Piece& piece) { - logger->error(MSG_GOT_WRONG_PIECE, cuid, piece.getIndex()); +void PieceMessage::onGotWrongPiece(const PieceHandle& piece) { + logger->error(MSG_GOT_WRONG_PIECE, cuid, piece->getIndex()); erasePieceOnDisk(piece); - piece.clearAllBlock(); - pieceStorage->updatePiece(piece); + piece->clearAllBlock(); + //pieceStorage->updatePiece(piece); peerInteraction->abortPiece(piece); } -void PieceMessage::erasePieceOnDisk(const Piece& piece) { +void PieceMessage::erasePieceOnDisk(const PieceHandle& piece) { int BUFSIZE = 4096; char buf[BUFSIZE]; memset(buf, 0, BUFSIZE); long long int offset = - ((long long int)piece.getIndex())*btContext->getPieceLength(); - for(int i = 0; i < piece.getLength()/BUFSIZE; i++) { + ((long long int)piece->getIndex())*btContext->getPieceLength(); + for(int i = 0; i < piece->getLength()/BUFSIZE; i++) { pieceStorage->getDiskAdaptor()->writeData(buf, BUFSIZE, offset); offset += BUFSIZE; } - int r = piece.getLength()%BUFSIZE; + int r = piece->getLength()%BUFSIZE; if(r > 0) { pieceStorage->getDiskAdaptor()->writeData(buf, r, offset); } diff --git a/src/PieceMessage.h b/src/PieceMessage.h index 328ff7bd..48b5cac1 100644 --- a/src/PieceMessage.h +++ b/src/PieceMessage.h @@ -52,10 +52,10 @@ private: char msgHeader[13]; - bool checkPieceHash(const Piece& piece); - void onGotNewPiece(Piece& piece); - void onGotWrongPiece(Piece& piece); - void erasePieceOnDisk(const Piece& piece); + bool checkPieceHash(const PieceHandle& piece); + void onGotNewPiece(const PieceHandle& piece); + void onGotWrongPiece(const PieceHandle& piece); + void erasePieceOnDisk(const PieceHandle& piece); int sendPieceData(long long int offset, int length) const; PeerMessageHandle createRejectMessage(int index, int begin, int blockLength) const; public: @@ -75,9 +75,7 @@ public: } virtual ~PieceMessage() { - if(block != NULL) { delete [] block; - } } enum ID_t { diff --git a/src/PieceStorage.h b/src/PieceStorage.h index 4ee76e05..892ffa8e 100644 --- a/src/PieceStorage.h +++ b/src/PieceStorage.h @@ -56,7 +56,7 @@ public: * from get the same piece. But in end game mode, same piece may be returned * to several commands. */ - virtual Piece getMissingPiece(const PeerHandle& peer) = 0; + virtual PieceHandle getMissingPiece(const PeerHandle& peer) = 0; /** * Returns a piece that the peer has but localhost doesn't. * Only pieces that declared as "fast" are returned. @@ -64,27 +64,23 @@ public: * from get the same piece. But in end game mode, same piece may be returned * to several commands. */ - virtual Piece getMissingFastPiece(const PeerHandle& peer) = 0; + virtual PieceHandle getMissingFastPiece(const PeerHandle& peer) = 0; + + /** + * Returns the piece denoted by index. + * No status of the piece is changed in this method. + */ + virtual PieceHandle getPiece(int index) = 0; /** * Tells that the download of the specfied piece completes. */ - virtual void completePiece(const Piece& piece) = 0; + virtual void completePiece(const PieceHandle& piece) = 0; /** * Tells that the download of the specified piece is canceled. */ - virtual void cancelPiece(const Piece& piece) = 0; - - /** - * Updates the internal piece data with the specified piece data. - */ - virtual void updatePiece(const Piece& piece) = 0; - - /** - * Updates the spcefied piece data with the internal piece data. - */ - virtual void syncPiece(Piece& piece) = 0; + virtual void cancelPiece(const PieceHandle& piece) = 0; /** * Returns true if the specified piece is already downloaded. diff --git a/src/Randomizer.h b/src/Randomizer.h new file mode 100644 index 00000000..cbfcc8bb --- /dev/null +++ b/src/Randomizer.h @@ -0,0 +1,50 @@ +/* */ +#ifndef _D_RANDOMIZER_H_ +#define _D_RANDOMIZER_H_ + +#include "common.h" + +class Randomizer { +public: + virtual ~Randomizer() {} + + virtual int getRandomNumber() = 0; + + virtual int getMaxRandomNumber() = 0; +}; + +typedef SharedHandle RandomizerHandle; +#endif // _D_RANDOMIZER_H_ diff --git a/src/RequestSlot.cc b/src/RequestSlot.cc index 4d595c3e..9d677bf8 100644 --- a/src/RequestSlot.cc +++ b/src/RequestSlot.cc @@ -35,7 +35,7 @@ #include "RequestSlot.h" #include "Util.h" -RequestSlot::RequestSlot(int index, int begin, int length, int blockIndex) +RequestSlot::RequestSlot(uint32_t index, uint32_t begin, uint32_t length, uint32_t blockIndex) :index(index), begin(begin), length(length), blockIndex(blockIndex) {} RequestSlot::RequestSlot(const RequestSlot& requestSlot) { @@ -56,7 +56,11 @@ void RequestSlot::setDispatchedTime() { dispatchedTime.reset(); } -bool RequestSlot::isTimeout(int timeoutSec) const { +void RequestSlot::setDispatchedTime(time_t secFromEpoch) { + dispatchedTime.setTimeInSec(secFromEpoch); +} + +bool RequestSlot::isTimeout(time_t timeoutSec) const { return dispatchedTime.differenceInMillis() > timeoutSec*1000; } diff --git a/src/RequestSlot.h b/src/RequestSlot.h index 2fb6cdee..20a6078d 100644 --- a/src/RequestSlot.h +++ b/src/RequestSlot.h @@ -41,13 +41,13 @@ class RequestSlot { private: Time dispatchedTime; - int index; - int begin; - int length; - int blockIndex; + uint32_t index; + uint32_t begin; + uint32_t length; + uint32_t blockIndex; void copy(const RequestSlot& requestSlot); public: - RequestSlot(int index, int begin, int legnth, int blockIndex); + RequestSlot(uint32_t index, uint32_t begin, uint32_t length, uint32_t blockIndex); RequestSlot(const RequestSlot& requestSlot); ~RequestSlot() {} @@ -65,22 +65,25 @@ public: } void setDispatchedTime(); + void setDispatchedTime(time_t secFromEpoch); - bool isTimeout(int timeoutSec) const; + bool isTimeout(time_t timeoutSec) const; int getLatencyInMillis() const; - 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; } - int getBlockIndex() const { return blockIndex; } - void setBlockIndex(int blockIndex) { this->blockIndex = blockIndex; } + uint32_t getIndex() const { return index; } + void setIndex(uint32_t index) { this->index = index; } + uint32_t getBegin() const { return begin; } + void setBegin(uint32_t begin) { this->begin = begin; } + uint32_t getLength() const { return length; } + void setLength(uint32_t length) { this->length = length; } + uint32_t getBlockIndex() const { return blockIndex; } + void setBlockIndex(uint32_t blockIndex) { this->blockIndex = blockIndex; } static RequestSlot nullSlot; static bool isNull(const RequestSlot& requestSlot); }; +typedef deque RequestSlots; + #endif // _D_REQUEST_SLOT_H_ diff --git a/src/SegmentMan.cc b/src/SegmentMan.cc index 7afdd58a..5d8dfe2f 100644 --- a/src/SegmentMan.cc +++ b/src/SegmentMan.cc @@ -39,6 +39,7 @@ #include "message.h" #include "prefs.h" #include "LogFactory.h" +#include "BitfieldManFactory.h" #include #include #include @@ -229,7 +230,7 @@ void SegmentMan::init() { } void SegmentMan::initBitfield(int segmentLength, long long int totalLength) { - this->bitfield = new BitfieldMan(segmentLength, totalLength); + this->bitfield = BitfieldManFactory::getNewFactory()->createBitfieldMan(segmentLength, totalLength); } class FindSegmentEntryByIndex { diff --git a/src/SharedHandle.h b/src/SharedHandle.h index 2b01ee38..0cb08575 100644 --- a/src/SharedHandle.h +++ b/src/SharedHandle.h @@ -64,8 +64,14 @@ public: ++*ucount; } template - SharedHandle(const SharedHandle& t):obj(t.get()), ucount(t.getRefCount()) { - ++*ucount; + SharedHandle(const SharedHandle& t) { + obj = dynamic_cast(t.get()); + if(obj) { + ucount = t.getRefCount(); + ++*ucount; + } else { + ucount = new int(1); + } } ~SharedHandle() { @@ -108,6 +114,10 @@ public: int* getRefCount() const { return ucount; } + + bool isNull() const { + return obj == 0; + } }; template diff --git a/src/SimpleBtMessage.cc b/src/SimpleBtMessage.cc new file mode 100644 index 00000000..ff08a287 --- /dev/null +++ b/src/SimpleBtMessage.cc @@ -0,0 +1,64 @@ +/* */ +#include "SimpleBtMessage.h" +#include "message.h" +#include "BtRegistry.h" + +SimpleBtMessage::SimpleBtMessage():leftDataLength(0) {} + +SimpleBtMessage::~SimpleBtMessage() {} + +void SimpleBtMessage::send() { + if(invalidate) { + return; + } + if(sendPredicate() || sendingInProgress) { + const char* msg = getMessage(); + int msgLength = getMessageLength(); + if(!sendingInProgress) { + logger->info(MSG_SEND_PEER_MESSAGE, + cuid, peer->ipaddr.c_str(), peer->port, toString().c_str()); + leftDataLength = getMessageLength(); + } + sendingInProgress = false; + int writtenLength = PEER_CONNECTION(btContext, peer)->sendMessage(msg+msgLength-leftDataLength, leftDataLength); + if(writtenLength == leftDataLength) { + onSendComplete(); + } else { + leftDataLength -= writtenLength; + sendingInProgress = true; + } + } +} diff --git a/src/SimpleBtMessage.h b/src/SimpleBtMessage.h new file mode 100644 index 00000000..b1a25310 --- /dev/null +++ b/src/SimpleBtMessage.h @@ -0,0 +1,60 @@ +/* */ +#ifndef _D_SIMPLE_BT_MESSAGE_H_ +#define _D_SIMPLE_BT_MESSAGE_H_ + +#include "AbstractBtMessage.h" + +class SimpleBtMessage : public AbstractBtMessage { +private: + int leftDataLength; +public: + SimpleBtMessage(); + + virtual ~SimpleBtMessage(); + + virtual void send(); + + virtual const char* getMessage() = 0; + + virtual uint32_t getMessageLength() = 0; + + virtual void onSendComplete() {}; + + virtual bool sendPredicate() const { return true; }; + +}; + +#endif // _D_SIMPLE_BT_MESSAGE_H_ diff --git a/src/SimpleRandomizer.cc b/src/SimpleRandomizer.cc new file mode 100644 index 00000000..f975aa7e --- /dev/null +++ b/src/SimpleRandomizer.cc @@ -0,0 +1,37 @@ +/* */ +#include "SimpleRandomizer.h" + +RandomizerHandle SimpleRandomizer::randomizer = RandomizerHandle(new SimpleRandomizer()); diff --git a/src/SimpleRandomizer.h b/src/SimpleRandomizer.h new file mode 100644 index 00000000..c826e5dd --- /dev/null +++ b/src/SimpleRandomizer.h @@ -0,0 +1,68 @@ +/* */ +#ifndef _D_SIMPLE_RANDOMIZER_H_ +#define _D_SIMPLE_RANDOMIZER_H_ + +#include "Randomizer.h" +#include +#include + +class SimpleRandomizer : public Randomizer { +private: + static RandomizerHandle randomizer; + + SimpleRandomizer() {} +public: + + static RandomizerHandle getInstance() { + return randomizer; + } + + static void init() { + srandom(time(NULL)); + } + + virtual ~SimpleRandomizer() {} + + virtual int getRandomNumber() { + return random(); + } + + virtual int getMaxRandomNumber() { + return RAND_MAX; + } +}; + +#endif // _D_SIMPLE_RANDOMIZER_H_ diff --git a/src/TorrentRequestInfo.cc b/src/TorrentRequestInfo.cc index 2fddf138..84a2af3f 100644 --- a/src/TorrentRequestInfo.cc +++ b/src/TorrentRequestInfo.cc @@ -73,6 +73,9 @@ RequestInfos TorrentRequestInfo::execute() { fail = true; delete ex; } + // TODO we want just 1 torrent download to clear + BtRegistry::clear(); + Util::setGlobalSignalHandler(SIGINT, SIG_DFL, 0); Util::setGlobalSignalHandler(SIGTERM, SIG_DFL, 0); diff --git a/src/TrackerUpdateCommand.cc b/src/TrackerUpdateCommand.cc index c314f41a..23a762b7 100644 --- a/src/TrackerUpdateCommand.cc +++ b/src/TrackerUpdateCommand.cc @@ -40,8 +40,6 @@ #include "SleepCommand.h" #include "Util.h" -extern PeerHandle nullPeer; - TrackerUpdateCommand::TrackerUpdateCommand(int cuid, TorrentDownloadEngine* e, const BtContextHandle& btContext): @@ -89,7 +87,7 @@ bool TrackerUpdateCommand::execute() { if(!e->segmentMan->finished()) { return prepareForRetry(); } - char* trackerResponse = NULL; + char* trackerResponse = 0; size_t trackerResponseLength = 0; try { @@ -99,7 +97,7 @@ bool TrackerUpdateCommand::execute() { trackerResponseLength); while(!btRuntime->isHalt() && btRuntime->lessThanMinPeer()) { PeerHandle peer = peerStorage->getUnusedPeer(); - if(peer == nullPeer) { + if(peer.isNull()) { break; } int newCuid = btRuntime->getNewCuid(); diff --git a/src/Util.cc b/src/Util.cc index a37ff330..f767a163 100644 --- a/src/Util.cc +++ b/src/Util.cc @@ -48,13 +48,9 @@ #include #include -string Util::itos(int value, bool comma) { - string str = llitos(value, comma); - return str; -} -string Util::llitos(long long int value, bool comma) -{ +template +string int2str(T value, bool comma) { string str; bool flag = false; if(value < 0) { @@ -80,6 +76,27 @@ string Util::llitos(long long int value, bool comma) return str; } +string Util::uitos(uint16_t value, bool comma) { + return int2str(value, comma); +} + +string Util::itos(int16_t value, bool comma) { + return int2str(value, comma); +} + +string Util::uitos(uint32_t value, bool comma) { + return int2str(value, comma); +} + +string Util::itos(int32_t value, bool comma) { + return int2str(value, comma); +} + +string Util::llitos(int64_t value, bool comma) +{ + return int2str(value, comma); +} + string Util::trim(const string& src) { string::size_type sp = src.find_first_not_of("\r\n\t "); string::size_type ep = src.find_last_not_of("\r\n\t "); @@ -430,6 +447,13 @@ void Util::sha1Sum(unsigned char* digest, const void* data, int dataLength) { ctx.digestFinal(digest); ctx.digestFree(); } + +string Util::simpleMessageDigest(const string& data) { + unsigned char checksum[20]; + sha1Sum(checksum, data.c_str(), data.size()); + return Util::toHex(checksum, sizeof(checksum)); +} + #endif // ENABLE_MESSAGE_DIGEST #ifdef ENABLE_MESSAGE_DIGEST diff --git a/src/Util.h b/src/Util.h index 379ff4ec..1fdaa4c1 100644 --- a/src/Util.h +++ b/src/Util.h @@ -52,8 +52,12 @@ using namespace std; class Util { public: static void split(pair& hp, const string& src, char delim); - static string llitos(long long int value, bool comma = false); - static string itos(int value, bool comma = false); + static string llitos(int64_t value, bool comma = false); + static string itos(int32_t value, bool comma = false); + static string uitos(uint32_t value, bool comma = false); + static string itos(int16_t value, bool comma = false); + static string uitos(uint16_t value, bool comma = false); + /** * Computes difference in micro-seconds between tv1 and tv2, * assuming tv1 is newer than tv2. @@ -103,6 +107,7 @@ public: // digest must be at least 20 bytes long. #ifdef ENABLE_MESSAGE_DIGEST static void sha1Sum(unsigned char* digest, const void* data, int dataLength); + static string simpleMessageDigest(const string& data); #endif // ENABLE_MESSAGE_DIGEST // Before call this method, allocate enough memory to the parameter "digest". diff --git a/src/common.h b/src/common.h index 15ebb043..94e686cc 100644 --- a/src/common.h +++ b/src/common.h @@ -34,6 +34,8 @@ /* copyright --> */ #ifndef _D_COMMON_H_ #define _D_COMMON_H_ +// use C99 limit macros +#define __STDC_LIMIT_MACROS #ifdef HAVE_CONFIG_H # include #endif @@ -62,6 +64,7 @@ #define DIV_FLOOR(X,Y) ((X)/(Y)+((X)%(Y)? 1:0)) using namespace std; +//#include "debug_new.h" class Deleter { public: @@ -74,6 +77,6 @@ public: #include "SharedHandle.h" typedef deque Strings; -typedef deque Integers; +typedef deque Integers; #endif // _D_COMMON_H_ diff --git a/src/main.cc b/src/main.cc index e6b04b13..610f6dd6 100644 --- a/src/main.cc +++ b/src/main.cc @@ -45,6 +45,8 @@ #include "DownloadEngineFactory.h" #include "UrlRequestInfo.h" #include "TorrentRequestInfo.h" +#include "BitfieldManFactory.h" +#include "SimpleRandomizer.h" #include #include #include @@ -308,6 +310,8 @@ int main(int argc, char* argv[]) { op->put(PREF_DNS_TIMEOUT, "10"); op->put(PREF_PEER_CONNECTION_TIMEOUT, "60"); op->put(PREF_BT_TIMEOUT, "180"); + op->put(PREF_BT_REQUEST_TIMEOUT, "60"); + op->put(PREF_BT_KEEP_ALIVE_INTERVAL, "120"); op->put(PREF_MIN_SEGMENT_SIZE, "1048576");// 1M op->put(PREF_MAX_TRIES, "5"); op->put(PREF_HTTP_AUTH_SCHEME, V_BASIC); @@ -710,7 +714,8 @@ int main(int argc, char* argv[]) { #ifdef ENABLE_METALINK xmlInitParser(); #endif // ENABLE_METALINK - srandom(time(NULL)); + SimpleRandomizer::init(); + BitfieldManFactory::setDefaultRandomizer(SimpleRandomizer::getInstance()); if(op->getAsBool(PREF_STDOUT_LOG)) { LogFactory::setLogFile("/dev/stdout"); } else if(op->get(PREF_LOG).size()) { diff --git a/src/prefs.h b/src/prefs.h index 371cbfc9..6a0c05fe 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -131,6 +131,8 @@ #define PREF_PEER_CONNECTION_TIMEOUT "peer_connection_timeout" // values: 1*digit #define PREF_BT_TIMEOUT "bt_timeout" +// values: 1*digit +#define PREF_BT_REQUEST_TIMEOUT "bt_request_timeout" // values: true | false #define PREF_SHOW_FILES "show_files" // values: true | false @@ -153,6 +155,8 @@ #define PREF_SEED_RATIO "seed_ratio" // values: 1*digit #define PREF_TRACKER_MAX_TRIES "tracker_max_tries" +// values: 1*digit +#define PREF_BT_KEEP_ALIVE_INTERVAL "bt_keep_alive_interval" /** * Metalink related preferences diff --git a/test/BitfieldManTest.cc b/test/BitfieldManTest.cc index cdb3b64d..e3dfff20 100644 --- a/test/BitfieldManTest.cc +++ b/test/BitfieldManTest.cc @@ -1,4 +1,6 @@ #include "BitfieldMan.h" +#include "FixedNumberRandomizer.h" +#include "BitfieldManFactory.h" #include #include @@ -15,8 +17,15 @@ class BitfieldManTest:public CppUnit::TestFixture { CPPUNIT_TEST(testGetSparceMissingUnusedIndex); CPPUNIT_TEST_SUITE_END(); private: + RandomizerHandle fixedNumberRandomizer; public: + BitfieldManTest():fixedNumberRandomizer(0) { + FixedNumberRandomizer* randomizer = new FixedNumberRandomizer(); + randomizer->setFixedNumber(0); + this->fixedNumberRandomizer = randomizer; + } + void setUp() { } @@ -82,9 +91,8 @@ void BitfieldManTest::testIsAllBitSet() { } void BitfieldManTest::testFilter() { - // set random seed here in order to get same random numbers. - srandom(100); BitfieldMan btman(2, 32); + btman.setRandomizer(fixedNumberRandomizer); // test offset=4, length=12 btman.addFilter(4, 12); @@ -140,12 +148,12 @@ void BitfieldManTest::testFilter() { btman2.addFilter(0, 31); btman2.enableFilter(); CPPUNIT_ASSERT_EQUAL((long long int)31, btman2.getFilteredTotalLength()); + } void BitfieldManTest::testGetMissingIndex() { - srandom(100); - BitfieldMan bt1(1024, 1024*256); + bt1.setRandomizer(fixedNumberRandomizer); unsigned char bitArray[] = { 0xff, 0xff, 0xff, 0xff, @@ -157,12 +165,12 @@ void BitfieldManTest::testGetMissingIndex() { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; - CPPUNIT_ASSERT_EQUAL(80, bt1.getMissingIndex(bitArray, 32)); + CPPUNIT_ASSERT_EQUAL(0, bt1.getMissingIndex(bitArray, 32)); unsigned char bitArray2[] = { + 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -170,11 +178,11 @@ void BitfieldManTest::testGetMissingIndex() { 0xff, 0xff, 0xff, 0xff, }; - CPPUNIT_ASSERT_EQUAL(80, bt1.getMissingIndex(bitArray2, 32)); + CPPUNIT_ASSERT_EQUAL(4, bt1.getMissingIndex(bitArray2, 32)); unsigned char bitArray3[] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -183,22 +191,9 @@ void BitfieldManTest::testGetMissingIndex() { 0xff, 0xff, 0xff, 0xff, }; - CPPUNIT_ASSERT_EQUAL(60, bt1.getMissingIndex(bitArray3, 32)); + CPPUNIT_ASSERT_EQUAL(8, bt1.getMissingIndex(bitArray3, 32)); unsigned char bitArray4[] = { - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - }; - - CPPUNIT_ASSERT_EQUAL(0, bt1.getMissingIndex(bitArray4, 32)); - - unsigned char bitArray5[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -209,7 +204,7 @@ void BitfieldManTest::testGetMissingIndex() { 0x00, 0x00, 0x00, 0x00, }; - CPPUNIT_ASSERT_EQUAL(-1, bt1.getMissingIndex(bitArray5, 32)); + CPPUNIT_ASSERT_EQUAL(-1, bt1.getMissingIndex(bitArray4, 32)); } diff --git a/test/BtAllowedFastMessageTest.cc b/test/BtAllowedFastMessageTest.cc new file mode 100644 index 00000000..635a4389 --- /dev/null +++ b/test/BtAllowedFastMessageTest.cc @@ -0,0 +1,100 @@ +#include "BtAllowedFastMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include + +using namespace std; + +class BtAllowedFastMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtAllowedFastMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testOnSendComplete); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testOnSendComplete(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtAllowedFastMessageTest); + +void BtAllowedFastMessageTest::testCreate() { + unsigned char msg[9]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 17); + PeerMessageUtil::setIntParam(&msg[5], 12345); + BtAllowedFastMessageHandle pm = BtAllowedFastMessage::create(&msg[4], 5); + CPPUNIT_ASSERT_EQUAL(17, pm->getId()); + CPPUNIT_ASSERT_EQUAL((uint32_t)12345, pm->getIndex()); + + // case: payload size is wrong + try { + unsigned char msg[10]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 6, 17); + BtAllowedFastMessage::create(&msg[4], 6); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[9]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 18); + BtAllowedFastMessage::create(&msg[4], 5); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtAllowedFastMessageTest::testGetMessage() { + BtAllowedFastMessage msg; + msg.setIndex(12345); + unsigned char data[9]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 5, 17); + PeerMessageUtil::setIntParam(&data[5], 12345); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 9) == 0); +} + +void BtAllowedFastMessageTest::testDoReceivedAction() { + BtAllowedFastMessage msg; + msg.setIndex(1); + PeerHandle peer = new Peer("localhost", 6969, 16*1024, 256*1024*1024); + peer->setFastExtensionEnabled(true); + msg.setPeer(peer); + CPPUNIT_ASSERT(!peer->isInPeerAllowedIndexSet(1)); + msg.doReceivedAction(); + CPPUNIT_ASSERT(peer->isInPeerAllowedIndexSet(1)); + + peer->setFastExtensionEnabled(false); + try { + msg.doReceivedAction(); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) {} +} + +void BtAllowedFastMessageTest::testOnSendComplete() { + BtAllowedFastMessage msg; + msg.setIndex(1); + PeerHandle peer = new Peer("localhost", 6969, 16*1024, 256*1024*1024); + peer->setFastExtensionEnabled(true); + msg.setPeer(peer); + CPPUNIT_ASSERT(!peer->isInAmAllowedIndexSet(1)); + msg.onSendComplete(); + CPPUNIT_ASSERT(peer->isInAmAllowedIndexSet(1)); +} + +void BtAllowedFastMessageTest::testToString() { + BtAllowedFastMessage msg; + msg.setIndex(1); + CPPUNIT_ASSERT_EQUAL(string("allowed fast index=1"), msg.toString()); +} diff --git a/test/BtBitfieldMessageTest.cc b/test/BtBitfieldMessageTest.cc new file mode 100644 index 00000000..d0430983 --- /dev/null +++ b/test/BtBitfieldMessageTest.cc @@ -0,0 +1,90 @@ +#include "BtBitfieldMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include + +using namespace std; + +class BtBitfieldMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtBitfieldMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtBitfieldMessageTest); + +void BtBitfieldMessageTest::testCreate() { + unsigned 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)); + BtBitfieldMessageHandle pm = BtBitfieldMessage::create(&msg[4], 3); + CPPUNIT_ASSERT_EQUAL(5, pm->getId()); + CPPUNIT_ASSERT(memcmp(bitfield, pm->getBitfield(), sizeof(bitfield)) == 0); + CPPUNIT_ASSERT_EQUAL((uint32_t)2, pm->getBitfieldLength()); + // case: payload size is wrong + try { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 5); + BtBitfieldMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[5+2]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 3, 6); + BtBitfieldMessage::create(&msg[4], 3); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtBitfieldMessageTest::testGetMessage() { + BtBitfieldMessage msg; + unsigned char bitfield[2]; + memset(bitfield, 0xff, sizeof(bitfield)); + msg.setBitfield(bitfield, sizeof(bitfield)); + unsigned 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); +} + +void BtBitfieldMessageTest::testDoReceivedAction() { + PeerHandle peer = new Peer("host1", 6969, 16*1024, 16*16*1024); + BtBitfieldMessage msg; + msg.setPeer(peer); + unsigned char bitfield[] = { 0xff, 0xff }; + msg.setBitfield(bitfield, sizeof(bitfield)); + + CPPUNIT_ASSERT_EQUAL(string("0000"), Util::toHex(peer->getBitfield(), + peer->getBitfieldLength())); + msg.doReceivedAction(); + CPPUNIT_ASSERT_EQUAL(string("ffff"), Util::toHex(peer->getBitfield(), + peer->getBitfieldLength())); +} + +void BtBitfieldMessageTest::testToString() { + BtBitfieldMessage msg; + unsigned char bitfield[] = { 0xff, 0xff }; + msg.setBitfield(bitfield, sizeof(bitfield)); + + CPPUNIT_ASSERT_EQUAL(string("bitfield ffff"), msg.toString()); +} diff --git a/test/BtCancelMessageTest.cc b/test/BtCancelMessageTest.cc new file mode 100644 index 00000000..cb766a47 --- /dev/null +++ b/test/BtCancelMessageTest.cc @@ -0,0 +1,118 @@ +#include "BtCancelMessage.h" +#include "PeerMessageUtil.h" +#include "MockBtMessageDispatcher.h" +#include "MockBtContext.h" +#include + +using namespace std; + +class BtCancelMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtCancelMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + BtCancelMessageTest():peer(0), btContext(0) {} + + PeerHandle peer; + MockBtContextHandle btContext; + + void setUp() { + BtRegistry::clear(); + peer = new Peer("host", 6969, 16*1024, 256*1024); + btContext = new MockBtContext(); + btContext->setInfoHash((const unsigned char*)"12345678901234567890"); + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + PEER_OBJECT_CLUSTER(btContext)->registerHandle(peer->getId(), new PeerObject()); + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + + class MockBtMessageDispatcher2 : public MockBtMessageDispatcher { + public: + uint32_t index; + uint32_t begin; + uint32_t length; + public: + MockBtMessageDispatcher2():index(0), + begin(0), + length(0) {} + + virtual void doCancelSendingPieceAction(uint32_t index, uint32_t begin, uint32_t length) { + this->index = index; + this->begin = begin; + this->length = length; + } + }; + + typedef SharedHandle MockBtMessageDispatcher2Handle; +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtCancelMessageTest); + +void BtCancelMessageTest::testCreate() { + unsigned 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); + BtCancelMessageHandle pm = BtCancelMessage::create(&msg[4], 13); + CPPUNIT_ASSERT_EQUAL(8, pm->getId()); + CPPUNIT_ASSERT_EQUAL((uint32_t)12345, pm->getIndex()); + CPPUNIT_ASSERT_EQUAL((uint32_t)256, pm->getBegin()); + CPPUNIT_ASSERT_EQUAL((uint32_t)1024, pm->getLength()); + + // case: payload size is wrong + try { + unsigned char msg[18]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 14, 8); + BtCancelMessage::create(&msg[4], 14); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[17]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 9); + BtCancelMessage::create(&msg[4], 13); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtCancelMessageTest::testGetMessage() { + BtCancelMessage msg; + msg.setIndex(12345); + msg.setBegin(256); + msg.setLength(1024); + unsigned 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); +} + +void BtCancelMessageTest::testDoReceivedAction() { + BtCancelMessage msg; + msg.setIndex(1); + msg.setBegin(2*16*1024); + msg.setLength(16*1024); + msg.setBtContext(btContext); + msg.setPeer(peer); + MockBtMessageDispatcher2Handle dispatcher = new MockBtMessageDispatcher2(); + PEER_OBJECT(btContext, peer)->btMessageDispatcher = dispatcher; + + msg.doReceivedAction(); + CPPUNIT_ASSERT_EQUAL(msg.getIndex(), dispatcher->index); + CPPUNIT_ASSERT_EQUAL(msg.getBegin(), dispatcher->begin); + CPPUNIT_ASSERT_EQUAL(msg.getLength(), dispatcher->length); +} diff --git a/test/BtChokeMessageTest.cc b/test/BtChokeMessageTest.cc new file mode 100644 index 00000000..c267d847 --- /dev/null +++ b/test/BtChokeMessageTest.cc @@ -0,0 +1,130 @@ +#include "BtChokeMessage.h" +#include "PeerMessageUtil.h" +#include "MockBtMessageDispatcher.h" +#include "MockBtContext.h" +#include + +using namespace std; + +class BtChokeMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtChokeMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testOnSendComplete); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + BtChokeMessageTest():peer(0), btContext(0) {} + + PeerHandle peer; + MockBtContextHandle btContext; + + void setUp() { + BtRegistry::clear(); + peer = new Peer("host", 6969, 16*1024, 256*1024); + btContext = new MockBtContext(); + btContext->setInfoHash((const unsigned char*)"12345678901234567890"); + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + PEER_OBJECT_CLUSTER(btContext)->registerHandle(peer->getId(), new PeerObject()); + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testOnSendComplete(); + void testToString(); + + class MockBtMessageDispatcher2 : public MockBtMessageDispatcher { + public: + bool doChokedActionCalled; + bool doChokingActionCalled; + public: + MockBtMessageDispatcher2():doChokedActionCalled(false), doChokingActionCalled(false) {} + + virtual void doChokedAction() { + doChokedActionCalled = true; + } + + virtual void doChokingAction() { + doChokingActionCalled = true; + } + }; + + typedef SharedHandle MockBtMessageDispatcher2Handle; +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtChokeMessageTest); + +void BtChokeMessageTest::testCreate() { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 0); + BtChokeMessageHandle pm = BtChokeMessage::create(&msg[4], 1); + CPPUNIT_ASSERT_EQUAL(0, pm->getId()); + + // case: payload size is wrong + try { + unsigned char msg[6]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 0); + BtChokeMessage::create(&msg[4], 2); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 1); + BtChokeMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtChokeMessageTest::testGetMessage() { + BtChokeMessage msg; + unsigned char data[5]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 0); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0); +} + +void BtChokeMessageTest::testDoReceivedAction() { + BtChokeMessage msg; + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + msg.setPeer(peer); + msg.setBtContext(btContext); + + MockBtMessageDispatcher2Handle dispatcher = new MockBtMessageDispatcher2(); + + PEER_OBJECT(btContext, peer)->btMessageDispatcher = dispatcher; + + msg.doReceivedAction(); + + CPPUNIT_ASSERT(dispatcher->doChokedActionCalled); + CPPUNIT_ASSERT(peer->peerChoking); +} + +void BtChokeMessageTest::testOnSendComplete() { + BtChokeMessage msg; + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + msg.setPeer(peer); + msg.setBtContext(btContext); + + MockBtMessageDispatcher2Handle dispatcher = new MockBtMessageDispatcher2(); + + PEER_OBJECT(btContext, peer)->btMessageDispatcher = dispatcher; + + msg.onSendComplete(); + + CPPUNIT_ASSERT(dispatcher->doChokingActionCalled); + CPPUNIT_ASSERT(peer->amChoking); +} + +void BtChokeMessageTest::testToString() { + BtChokeMessage msg; + CPPUNIT_ASSERT_EQUAL(string("choke"), msg.toString()); +} diff --git a/test/BtHandshakeMessageTest.cc b/test/BtHandshakeMessageTest.cc new file mode 100644 index 00000000..9ccb7771 --- /dev/null +++ b/test/BtHandshakeMessageTest.cc @@ -0,0 +1,102 @@ +#include "BtHandshakeMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include + +using namespace std; + +class BtHandshakeMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtHandshakeMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testToString(); + + static string BTPSTR; +}; + + +string BtHandshakeMessageTest::BTPSTR = "BitTorrent protocol"; + +CPPUNIT_TEST_SUITE_REGISTRATION(BtHandshakeMessageTest); + +void createHandshakeMessageData(unsigned char* msg) { + msg[0] = 19; + memcpy(&msg[1], BtHandshakeMessageTest::BTPSTR.c_str(), + BtHandshakeMessageTest::BTPSTR.size()); + unsigned char reserved[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04 }; + memcpy(&msg[20], reserved, sizeof(reserved)); + unsigned char infoHash[] = { 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff }; + memcpy(&msg[28], infoHash, sizeof(infoHash)); + unsigned char peerId[] = { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 }; + memcpy(&msg[48], peerId, sizeof(peerId)); +} + +void BtHandshakeMessageTest::testCreate() { + unsigned char msg[68]; + createHandshakeMessageData(msg); + BtHandshakeMessageHandle message = BtHandshakeMessage::create(&msg[0], sizeof(msg)); + CPPUNIT_ASSERT_EQUAL(INT32_MAX, message->getId()); + CPPUNIT_ASSERT_EQUAL((uint8_t)19, message->getPstrlen()); + CPPUNIT_ASSERT_EQUAL(Util::toHex((const unsigned char*)BTPSTR.c_str(), BTPSTR.size()), + Util::toHex(message->getPstr(), BtHandshakeMessage::PSTR_LENGTH)); + CPPUNIT_ASSERT_EQUAL(string("0000000000000004"), + Util::toHex(message->getReserved(), BtHandshakeMessage::RESERVED_LENGTH)); + CPPUNIT_ASSERT_EQUAL(string("ffffffffffffffffffffffffffffffffffffffff"), + Util::toHex(message->getInfoHash(), INFO_HASH_LENGTH)); + CPPUNIT_ASSERT_EQUAL(string("f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0"), + Util::toHex(message->getPeerId(), PEER_ID_LENGTH)); +} + +void BtHandshakeMessageTest::testGetMessage() { + unsigned char infoHash[] = { 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff }; + unsigned char peerId[] = { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 }; + + BtHandshakeMessageHandle msg = new BtHandshakeMessage(); + msg->setInfoHash(infoHash); + msg->setPeerId(peerId); + + unsigned char data[68]; + createHandshakeMessageData(data); + CPPUNIT_ASSERT_EQUAL(Util::toHex((const unsigned char*)data, 68), + Util::toHex((const unsigned char*)msg->getMessage(), 68)); +} + +void BtHandshakeMessageTest::testToString() { + unsigned char infoHash[] = { 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff }; + unsigned char peerId[] = { 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, + 0xf0, 0xf0, 0xf0, 0xf0, 0xf0 }; + + BtHandshakeMessage msg; + msg.setInfoHash(infoHash); + msg.setPeerId(peerId); + + CPPUNIT_ASSERT_EQUAL(string("handshake peerId=%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0%f0, reserved=0000000000000004"), msg.toString()); +} diff --git a/test/BtHaveAllMessageTest.cc b/test/BtHaveAllMessageTest.cc new file mode 100644 index 00000000..e5fe31f3 --- /dev/null +++ b/test/BtHaveAllMessageTest.cc @@ -0,0 +1,75 @@ +#include "BtHaveAllMessage.h" +#include "PeerMessageUtil.h" +#include + +using namespace std; + +class BtHaveAllMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtHaveAllMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtHaveAllMessageTest); + +void BtHaveAllMessageTest::testCreate() { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 14); + BtHaveAllMessageHandle pm = BtHaveAllMessage::create(&msg[4], 1); + CPPUNIT_ASSERT_EQUAL(14, pm->getId()); + + // case: payload size is wrong + try { + unsigned char msg[6]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 14); + BtHaveAllMessage::create(&msg[4], 2); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 15); + BtHaveAllMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtHaveAllMessageTest::testGetMessage() { + BtHaveAllMessage msg; + unsigned char data[5]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 14); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0); +} + +void BtHaveAllMessageTest::testDoReceivedAction() { + BtHaveAllMessage msg; + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + peer->setFastExtensionEnabled(true); + msg.setPeer(peer); + + msg.doReceivedAction(); + + CPPUNIT_ASSERT(peer->isSeeder()); + + peer->setFastExtensionEnabled(false); + + try { + msg.doReceivedAction(); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) {} +} diff --git a/test/BtHaveMessageTest.cc b/test/BtHaveMessageTest.cc new file mode 100644 index 00000000..edff817b --- /dev/null +++ b/test/BtHaveMessageTest.cc @@ -0,0 +1,83 @@ +#include "BtHaveMessage.h" +#include "PeerMessageUtil.h" +#include + +using namespace std; + +class BtHaveMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtHaveMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtHaveMessageTest); + +void BtHaveMessageTest::testCreate() { + unsigned char msg[9]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 4); + PeerMessageUtil::setIntParam(&msg[5], 12345); + BtHaveMessageHandle pm = BtHaveMessage::create(&msg[4], 5); + CPPUNIT_ASSERT_EQUAL(4, pm->getId()); + CPPUNIT_ASSERT_EQUAL((uint32_t)12345, pm->getIndex()); + + // case: payload size is wrong + try { + unsigned char msg[10]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 6, 4); + BtHaveMessage::create(&msg[4], 2); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[9]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 5); + BtHaveMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtHaveMessageTest::testGetMessage() { + BtHaveMessage msg; + msg.setIndex(12345); + unsigned char data[9]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 5, 4); + PeerMessageUtil::setIntParam(&data[5], 12345); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 9) == 0); +} + +void BtHaveMessageTest::testDoReceivedAction() { + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + BtHaveMessage msg; + msg.setIndex(1); + msg.setPeer(peer); + + CPPUNIT_ASSERT(!peer->hasPiece(msg.getIndex())); + + msg.doReceivedAction(); + + CPPUNIT_ASSERT(peer->hasPiece(msg.getIndex())); +} + +void BtHaveMessageTest::testToString() { + BtHaveMessage msg; + msg.setIndex(1); + + CPPUNIT_ASSERT_EQUAL(string("have index=1"), msg.toString()); +} diff --git a/test/BtHaveNoneMessageTest.cc b/test/BtHaveNoneMessageTest.cc new file mode 100644 index 00000000..fc78643c --- /dev/null +++ b/test/BtHaveNoneMessageTest.cc @@ -0,0 +1,78 @@ +#include "BtHaveNoneMessage.h" +#include "PeerMessageUtil.h" +#include + +using namespace std; + +class BtHaveNoneMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtHaveNoneMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtHaveNoneMessageTest); + +void BtHaveNoneMessageTest::testCreate() { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 15); + BtHaveNoneMessageHandle pm = BtHaveNoneMessage::create(&msg[4], 1); + CPPUNIT_ASSERT_EQUAL(15, pm->getId()); + + // case: payload size is wrong + try { + unsigned char msg[6]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 15); + BtHaveNoneMessage::create(&msg[4], 2); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 16); + BtHaveNoneMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtHaveNoneMessageTest::testGetMessage() { + BtHaveNoneMessage msg; + unsigned char data[5]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 15); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0); +} + +void BtHaveNoneMessageTest::testDoReceivedAction() { + BtHaveNoneMessage msg; + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + peer->setFastExtensionEnabled(true); + msg.setPeer(peer); + msg.doReceivedAction(); + + peer->setFastExtensionEnabled(false); + try { + msg.doReceivedAction(); + CPPUNIT_FAIL("an exception must be threw."); + } catch(...) {} +} + +void BtHaveNoneMessageTest::testToString() { + BtHaveNoneMessage msg; + CPPUNIT_ASSERT_EQUAL(string("have none"), msg.toString()); +} diff --git a/test/BtInterestedMessageTest.cc b/test/BtInterestedMessageTest.cc new file mode 100644 index 00000000..5989c044 --- /dev/null +++ b/test/BtInterestedMessageTest.cc @@ -0,0 +1,84 @@ +#include "BtInterestedMessage.h" +#include "PeerMessageUtil.h" +#include + +using namespace std; + +class BtInterestedMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtInterestedMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testOnSendComplete); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testOnSendComplete(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtInterestedMessageTest); + +void BtInterestedMessageTest::testCreate() { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 2); + BtInterestedMessageHandle pm = BtInterestedMessage::create(&msg[4], 1); + CPPUNIT_ASSERT_EQUAL(2, pm->getId()); + + // case: payload size is wrong + try { + unsigned char msg[6]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 2); + BtInterestedMessage::create(&msg[4], 2); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 3); + BtInterestedMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtInterestedMessageTest::testGetMessage() { + BtInterestedMessage msg; + unsigned char data[5]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 2); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0); +} + +void BtInterestedMessageTest::testDoReceivedAction() { + BtInterestedMessage msg; + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + msg.setPeer(peer); + CPPUNIT_ASSERT(!peer->peerInterested); + msg.doReceivedAction(); + CPPUNIT_ASSERT(peer->peerInterested); +} + +void BtInterestedMessageTest::testOnSendComplete() { + BtInterestedMessage msg; + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + msg.setPeer(peer); + CPPUNIT_ASSERT(!peer->amInterested); + msg.onSendComplete(); + CPPUNIT_ASSERT(peer->amInterested); +} + +void BtInterestedMessageTest::testToString() { + BtInterestedMessage msg; + CPPUNIT_ASSERT_EQUAL(string("interested"), msg.toString()); +} diff --git a/test/BtKeepAliveMessageTest.cc b/test/BtKeepAliveMessageTest.cc new file mode 100644 index 00000000..8f2a5715 --- /dev/null +++ b/test/BtKeepAliveMessageTest.cc @@ -0,0 +1,35 @@ +#include "BtKeepAliveMessage.h" +#include + +using namespace std; + +class BtKeepAliveMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtKeepAliveMessageTest); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testGetMessage(); + void testToString(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BtKeepAliveMessageTest); + +void BtKeepAliveMessageTest::testGetMessage() { + char msg[4]; + memset(msg, 0, sizeof(msg)); + BtKeepAliveMessage message; + CPPUNIT_ASSERT_EQUAL((uint32_t)4, message.getMessageLength()); + CPPUNIT_ASSERT(memcmp(msg, message.getMessage(), 4) == 0); +} + +void BtKeepAliveMessageTest::testToString() { + BtKeepAliveMessage msg; + CPPUNIT_ASSERT_EQUAL(string("keep alive"), msg.toString()); +} diff --git a/test/BtNotInterestedMessageTest.cc b/test/BtNotInterestedMessageTest.cc new file mode 100644 index 00000000..c242512e --- /dev/null +++ b/test/BtNotInterestedMessageTest.cc @@ -0,0 +1,86 @@ +#include "BtNotInterestedMessage.h" +#include "PeerMessageUtil.h" +#include + +using namespace std; + +class BtNotInterestedMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtNotInterestedMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testOnSendComplete); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testOnSendComplete(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtNotInterestedMessageTest); + +void BtNotInterestedMessageTest::testCreate() { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 3); + BtNotInterestedMessageHandle pm = BtNotInterestedMessage::create(&msg[4], 1); + CPPUNIT_ASSERT_EQUAL(3, pm->getId()); + + // case: payload size is wrong + try { + unsigned char msg[6]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 3); + BtNotInterestedMessage::create(&msg[4], 2); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 4); + BtNotInterestedMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtNotInterestedMessageTest::testGetMessage() { + BtNotInterestedMessage msg; + char data[5]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 3); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0); +} + +void BtNotInterestedMessageTest::testDoReceivedAction() { + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + peer->peerInterested = true; + BtNotInterestedMessage msg; + msg.setPeer(peer); + CPPUNIT_ASSERT(peer->peerInterested); + msg.doReceivedAction(); + CPPUNIT_ASSERT(!peer->peerInterested); +} + +void BtNotInterestedMessageTest::testOnSendComplete() { + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + peer->amInterested = true; + BtNotInterestedMessage msg; + msg.setPeer(peer); + CPPUNIT_ASSERT(peer->amInterested); + msg.onSendComplete(); + CPPUNIT_ASSERT(!peer->amInterested); +} + +void BtNotInterestedMessageTest::testToString() { + BtNotInterestedMessage msg; + CPPUNIT_ASSERT_EQUAL(string("not interested"), msg.toString()); +} diff --git a/test/BtPieceMessageTest.cc b/test/BtPieceMessageTest.cc new file mode 100644 index 00000000..0b628108 --- /dev/null +++ b/test/BtPieceMessageTest.cc @@ -0,0 +1,290 @@ +#include "BtPieceMessage.h" +#include "PeerMessageUtil.h" +#include "MockBtContext.h" +#include "MockBtMessage.h" +#include "MockBtMessageFactory.h" +#include "MockBtMessageDispatcher.h" +#include "BtChokingEvent.h" +#include "BtCancelSendingPieceEvent.h" +#include + +using namespace std; + +class BtPieceMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtPieceMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessageHeader); + CPPUNIT_TEST(testChokingEvent); + CPPUNIT_TEST(testChokingEvent_allowedFastEnabled); + CPPUNIT_TEST(testChokingEvent_inAmAllowedIndexSet); + CPPUNIT_TEST(testChokingEvent_invalidate); + CPPUNIT_TEST(testChokingEvent_sendingInProgress); + CPPUNIT_TEST(testCancelSendingPieceEvent); + CPPUNIT_TEST(testCancelSendingPieceEvent_noMatch); + CPPUNIT_TEST(testCancelSendingPieceEvent_allowedFastEnabled); + CPPUNIT_TEST(testCancelSendingPieceEvent_invalidate); + CPPUNIT_TEST(testCancelSendingPieceEvent_sendingInProgress); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +public: + BtPieceMessageTest():btMessageDispatcher(0), peer(0), msg(0) {} + + void testCreate(); + void testGetMessageHeader(); + void testChokingEvent(); + void testChokingEvent_allowedFastEnabled(); + void testChokingEvent_inAmAllowedIndexSet(); + void testChokingEvent_invalidate(); + void testChokingEvent_sendingInProgress(); + void testCancelSendingPieceEvent(); + void testCancelSendingPieceEvent_noMatch(); + void testCancelSendingPieceEvent_allowedFastEnabled(); + void testCancelSendingPieceEvent_invalidate(); + void testCancelSendingPieceEvent_sendingInProgress(); + void testToString(); + + class MockBtMessage2 : public MockBtMessage { + public: + uint32_t index; + uint32_t begin; + uint32_t length; + public: + MockBtMessage2(uint32_t index, uint32_t begin, uint32_t length):index(index), begin(begin), length(length) {} + + }; + + typedef SharedHandle MockBtMessage2Handle; + + class MockBtMessageFactory2 : public MockBtMessageFactory { + public: + virtual BtMessageHandle createRejectMessage(uint32_t index, + uint32_t begin, + uint32_t length) { + MockBtMessage2Handle msg = new MockBtMessage2(index, begin, length); + return msg; + } + }; + + typedef SharedHandle MockBtMessageFactory2Handle; + + MockBtMessageDispatcherHandle btMessageDispatcher; + PeerHandle peer; + BtPieceMessageHandle msg; + + void setUp() { + BtRegistry::clear(); + + MockBtContextHandle btContext; + btContext->setInfoHash((const unsigned char*)"12345678901234567890"); + btContext->setPieceLength(16*1024); + btContext->setTotalLength(256*1024); + + peer = new Peer("host", 6969, 16*1024, 256*1024); + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + PEER_OBJECT_CLUSTER(btContext)->registerHandle(peer->getId(), new PeerObject()); + btMessageDispatcher = new MockBtMessageDispatcher(); + PEER_OBJECT(btContext, peer)->btMessageDispatcher = btMessageDispatcher; + PEER_OBJECT(btContext, peer)->btMessageFactory = new MockBtMessageFactory2(); + + msg = new BtPieceMessage(); + msg->setIndex(1); + msg->setBegin(1024); + msg->setBlockLength(16*1024); + msg->setBtContext(btContext); + msg->setPeer(peer); + } +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtPieceMessageTest); + +void BtPieceMessageTest::testCreate() { + unsigned char msg[13+2]; + unsigned 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)); + BtPieceMessageHandle pm = BtPieceMessage::create(&msg[4], 11); + CPPUNIT_ASSERT_EQUAL(7, pm->getId()); + CPPUNIT_ASSERT_EQUAL((uint32_t)12345, pm->getIndex()); + CPPUNIT_ASSERT_EQUAL((uint32_t)256, pm->getBegin()); + CPPUNIT_ASSERT(memcmp(data, pm->getBlock(), sizeof(data)) == 0); + CPPUNIT_ASSERT_EQUAL((uint32_t)2, pm->getBlockLength()); + + // case: payload size is wrong + try { + unsigned char msg[13]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 9, 7); + BtPieceMessage::create(&msg[4], 9); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[13+2]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 11, 8); + BtPieceMessage::create(&msg[4], 11); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtPieceMessageTest::testGetMessageHeader() { + BtPieceMessage msg; + msg.setIndex(12345); + msg.setBegin(256); + msg.setBlockLength(1024); + unsigned 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); +} + +void BtPieceMessageTest::testChokingEvent() { + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + CPPUNIT_ASSERT(!peer->isInAmAllowedIndexSet(1)); + CPPUNIT_ASSERT(!peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtChokingEvent()); + + CPPUNIT_ASSERT(msg->isInvalidate()); + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->messageQueue.size()); +} + +void BtPieceMessageTest::testChokingEvent_allowedFastEnabled() { + peer->setFastExtensionEnabled(true); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + CPPUNIT_ASSERT(!peer->isInAmAllowedIndexSet(1)); + CPPUNIT_ASSERT(peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtChokingEvent()); + + CPPUNIT_ASSERT(msg->isInvalidate()); + CPPUNIT_ASSERT_EQUAL((size_t)1, btMessageDispatcher->messageQueue.size()); + MockBtMessage2* rej = (MockBtMessage2*)btMessageDispatcher->messageQueue.front().get(); + CPPUNIT_ASSERT_EQUAL((uint32_t)1, rej->index); + CPPUNIT_ASSERT_EQUAL((uint32_t)1024, rej->begin); + CPPUNIT_ASSERT_EQUAL((uint32_t)16*1024, rej->length); +} + +void BtPieceMessageTest::testChokingEvent_inAmAllowedIndexSet() { + peer->setFastExtensionEnabled(true); + peer->addAmAllowedIndex(1); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + CPPUNIT_ASSERT(peer->isInAmAllowedIndexSet(1)); + CPPUNIT_ASSERT(peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtChokingEvent()); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->messageQueue.size()); +} + +void BtPieceMessageTest::testChokingEvent_invalidate() { + msg->setInvalidate(true); + CPPUNIT_ASSERT(msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + CPPUNIT_ASSERT(!peer->isInAmAllowedIndexSet(1)); + CPPUNIT_ASSERT(!peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtChokingEvent()); + + CPPUNIT_ASSERT(msg->isInvalidate()); + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->messageQueue.size()); +} + +void BtPieceMessageTest::testChokingEvent_sendingInProgress() { + msg->setSendingInProgress(true); + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(msg->isSendingInProgress()); + CPPUNIT_ASSERT(!peer->isInAmAllowedIndexSet(1)); + CPPUNIT_ASSERT(!peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtChokingEvent()); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->messageQueue.size()); +} + +void BtPieceMessageTest::testCancelSendingPieceEvent() { + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + CPPUNIT_ASSERT(!peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtCancelSendingPieceEvent(1, 1024, 16*1024)); + + CPPUNIT_ASSERT(msg->isInvalidate()); +} + +void BtPieceMessageTest::testCancelSendingPieceEvent_noMatch() { + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + CPPUNIT_ASSERT(!peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtCancelSendingPieceEvent(0, 1024, 16*1024)); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + + msg->handleEvent(new BtCancelSendingPieceEvent(1, 0, 16*1024)); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + + msg->handleEvent(new BtCancelSendingPieceEvent(1, 1024, 0)); + + CPPUNIT_ASSERT(!msg->isInvalidate()); +} + +void BtPieceMessageTest::testCancelSendingPieceEvent_allowedFastEnabled() { + peer->setFastExtensionEnabled(true); + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + CPPUNIT_ASSERT(peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtCancelSendingPieceEvent(1, 1024, 16*1024)); + + CPPUNIT_ASSERT(msg->isInvalidate()); + CPPUNIT_ASSERT_EQUAL((size_t)1, btMessageDispatcher->messageQueue.size()); + MockBtMessage2* rej = (MockBtMessage2*)btMessageDispatcher->messageQueue.front().get(); + CPPUNIT_ASSERT_EQUAL((uint32_t)1, rej->index); + CPPUNIT_ASSERT_EQUAL((uint32_t)1024, rej->begin); + CPPUNIT_ASSERT_EQUAL((uint32_t)16*1024, rej->length); +} + +void BtPieceMessageTest::testCancelSendingPieceEvent_invalidate() { + msg->setInvalidate(true); + peer->setFastExtensionEnabled(true); + CPPUNIT_ASSERT(msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + CPPUNIT_ASSERT(peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtCancelSendingPieceEvent(1, 1024, 16*1024)); + + CPPUNIT_ASSERT(msg->isInvalidate()); + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->messageQueue.size()); +} + +void BtPieceMessageTest::testCancelSendingPieceEvent_sendingInProgress() { + msg->setSendingInProgress(true); + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(msg->isSendingInProgress()); + CPPUNIT_ASSERT(!peer->isFastExtensionEnabled()); + + msg->handleEvent(new BtCancelSendingPieceEvent(1, 1024, 16*1024)); + + CPPUNIT_ASSERT(!msg->isInvalidate()); +} + +void BtPieceMessageTest::testToString() { + CPPUNIT_ASSERT_EQUAL(string("piece index=1, begin=1024, length=16384"), + msg->toString()); +} diff --git a/test/BtPortMessageTest.cc b/test/BtPortMessageTest.cc new file mode 100644 index 00000000..a50e8382 --- /dev/null +++ b/test/BtPortMessageTest.cc @@ -0,0 +1,55 @@ +#include "BtPortMessage.h" +#include "PeerMessageUtil.h" +#include "Util.h" +#include + +using namespace std; + +class BtPortMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtPortMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtPortMessageTest); + +void BtPortMessageTest::testCreate() { + unsigned char msg[7]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 3, 9); + PeerMessageUtil::setShortIntParam(&msg[5], 12345); + BtPortMessageHandle pm = BtPortMessage::create(&msg[4], 3); + CPPUNIT_ASSERT_EQUAL(9, pm->getId()); + CPPUNIT_ASSERT_EQUAL((uint16_t)12345, pm->getPort()); + + // case: payload size is wrong + try { + unsigned char msg[8]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 4, 9); + BtPortMessage::create(&msg[4], 4); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[7]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 3, 10); + BtPortMessage::create(&msg[4], 3); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} +void BtPortMessageTest::testToString() { + BtPortMessage msg(1); + CPPUNIT_ASSERT_EQUAL(string("port port=1"), msg.toString()); +} diff --git a/test/BtRegistryTest.cc b/test/BtRegistryTest.cc index 29b97788..104bcd70 100644 --- a/test/BtRegistryTest.cc +++ b/test/BtRegistryTest.cc @@ -4,7 +4,6 @@ #include "MockPieceStorage.h" #include "MockBtAnnounce.h" #include "MockBtProgressInfoFile.h" -#include #include using namespace std; @@ -17,6 +16,7 @@ class BtRegistryTest:public CppUnit::TestFixture { CPPUNIT_TEST(testGetBtRuntime); CPPUNIT_TEST(testGetBtAnnounce); CPPUNIT_TEST(testGetBtProgressInfoFile); + CPPUNIT_TEST(testGetPeerObjectCluster); CPPUNIT_TEST_SUITE_END(); private: @@ -29,6 +29,7 @@ public: void testGetBtRuntime(); void testGetBtAnnounce(); void testGetBtProgressInfoFile(); + void testGetPeerObjectCluster(); }; @@ -86,3 +87,15 @@ void BtRegistryTest::testGetBtProgressInfoFile() { CPPUNIT_ASSERT_EQUAL(btProgressInfoFile.get(), BtRegistry::getBtProgressInfoFile("test").get()); } + +void BtRegistryTest::testGetPeerObjectCluster() { + CPPUNIT_ASSERT(!BtRegistry::getPeerObjectCluster("test").get()); + + BtRegistry::registerPeerObjectCluster("test", new PeerObjectCluster()); + + CPPUNIT_ASSERT(BtRegistry::getPeerObjectCluster("test").get()); + + BtRegistry::unregisterPeerObjectCluster("test"); + + CPPUNIT_ASSERT(!BtRegistry::getPeerObjectCluster("test").get()); +} diff --git a/test/BtRejectMessageTest.cc b/test/BtRejectMessageTest.cc new file mode 100644 index 00000000..8fab5895 --- /dev/null +++ b/test/BtRejectMessageTest.cc @@ -0,0 +1,176 @@ +#include "BtRejectMessage.h" +#include "PeerMessageUtil.h" +#include "Peer.h" +#include "MockBtMessageDispatcher.h" +#include "MockBtContext.h" +#include + +using namespace std; + +class BtRejectMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtRejectMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testDoReceivedActionNoMatch); + CPPUNIT_TEST(testDoReceivedActionFastExtensionDisabled); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testDoReceivedActionNoMatch(); + void testDoReceivedActionFastExtensionDisabled(); + void testToString(); + + class MockBtMessageDispatcher2 : public MockBtMessageDispatcher { + public: + RequestSlot slot; + public: + MockBtMessageDispatcher2():slot(RequestSlot::nullSlot) {} + + void setRequestSlot(const RequestSlot& slot) { + this->slot = slot; + } + + virtual RequestSlot getOutstandingRequest(uint32_t index, uint32_t begin, + uint32_t length) { + if(slot.getIndex() == index && slot.getBegin() == begin && + slot.getLength() == length) { + return slot; + } else { + return RequestSlot::nullSlot; + } + } + + virtual void removeOutstandingRequest(const RequestSlot& slot) { + if(this->slot.getIndex() == slot.getIndex() && + this->slot.getBegin() == slot.getBegin() && + this->slot.getLength() == slot.getLength()) { + this->slot = RequestSlot::nullSlot; + } + } + }; + + typedef SharedHandle MockBtMessageDispatcher2Handle; + + PeerHandle peer; + MockBtMessageDispatcher2Handle dispatcher; + BtRejectMessageHandle msg; + + BtRejectMessageTest():peer(0), dispatcher(0), msg(0) {} + + void setUp() { + BtRegistry::clear(); + peer = new Peer("host", 6969, 16*1024, 256*1024); + + MockBtContextHandle btContext = new MockBtContext(); + btContext->setInfoHash((const unsigned char*)"12345678901234567890"); + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + PEER_OBJECT_CLUSTER(btContext)->registerHandle(peer->getId(), new PeerObject()); + dispatcher = new MockBtMessageDispatcher2(); + PEER_OBJECT(btContext, peer)->btMessageDispatcher = dispatcher; + + msg = new BtRejectMessage(); + msg->setPeer(peer); + msg->setBtContext(btContext); + msg->setIndex(1); + msg->setBegin(16); + msg->setLength(32); + + + } +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtRejectMessageTest); + +void BtRejectMessageTest::testCreate() { + unsigned 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); + BtRejectMessageHandle pm = BtRejectMessage::create(&msg[4], 13); + CPPUNIT_ASSERT_EQUAL(16, pm->getId()); + CPPUNIT_ASSERT_EQUAL((uint32_t)12345, pm->getIndex()); + CPPUNIT_ASSERT_EQUAL((uint32_t)256, pm->getBegin()); + CPPUNIT_ASSERT_EQUAL((uint32_t)1024, pm->getLength()); + + // case: payload size is wrong + try { + unsigned char msg[18]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 14, 16); + BtRejectMessage::create(&msg[4], 14); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[17]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 17); + BtRejectMessage::create(&msg[4], 13); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtRejectMessageTest::testGetMessage() { + BtRejectMessage msg; + msg.setIndex(12345); + msg.setBegin(256); + msg.setLength(1024); + unsigned 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); +} + +void BtRejectMessageTest::testDoReceivedAction() { + peer->setFastExtensionEnabled(true); + RequestSlot slot(1, 16, 32, 2); + dispatcher->setRequestSlot(slot); + + CPPUNIT_ASSERT(!RequestSlot::isNull(dispatcher->getOutstandingRequest(1, 16, 32))); + + msg->doReceivedAction(); + + CPPUNIT_ASSERT(RequestSlot::isNull(dispatcher->getOutstandingRequest(1, 16, 32))); +} + +void BtRejectMessageTest::testDoReceivedActionNoMatch() { + peer->setFastExtensionEnabled(true); + RequestSlot slot(2, 16, 32, 2); + dispatcher->setRequestSlot(slot); + + CPPUNIT_ASSERT(!RequestSlot::isNull(dispatcher->getOutstandingRequest(2, 16, 32))); + + msg->doReceivedAction(); + + CPPUNIT_ASSERT(!RequestSlot::isNull(dispatcher->getOutstandingRequest(2, 16, 32))); + +} + +void BtRejectMessageTest::testDoReceivedActionFastExtensionDisabled() { + RequestSlot slot(1, 16, 32, 2); + dispatcher->setRequestSlot(slot); + + CPPUNIT_ASSERT(!RequestSlot::isNull(dispatcher->getOutstandingRequest(1, 16, 32))); + try { + msg->doReceivedAction(); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) {} + +} + +void BtRejectMessageTest::testToString() { + CPPUNIT_ASSERT_EQUAL(string("reject index=1, begin=16, length=32"), + msg->toString()); +} diff --git a/test/BtRequestMessageTest.cc b/test/BtRequestMessageTest.cc new file mode 100644 index 00000000..42a1f89b --- /dev/null +++ b/test/BtRequestMessageTest.cc @@ -0,0 +1,271 @@ +#include "BtRequestMessage.h" +#include "PeerMessageUtil.h" +#include "MockBtContext.h" +#include "MockBtMessage.h" +#include "MockPieceStorage.h" +#include "MockBtMessageFactory.h" +#include "MockBtMessageDispatcher.h" +#include "DefaultBtContext.h" +#include "BtAbortOutstandingRequestEvent.h" +#include + +using namespace std; + +class BtRequestMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtRequestMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction_hasPieceAndAmNotChoking); + CPPUNIT_TEST(testDoReceivedAction_hasPieceAndAmChokingAndFastExtensionEnabled); + CPPUNIT_TEST(testDoReceivedAction_hasPieceAndAmChokingAndFastExtensionDisabled); + CPPUNIT_TEST(testDoReceivedAction_doesntHavePieceAndFastExtensionEnabled); + CPPUNIT_TEST(testDoReceivedAction_doesntHavePieceAndFastExtensionDisabled); + CPPUNIT_TEST(testHandleAbortRequestEvent); + CPPUNIT_TEST(testHandleAbortRequestEvent_indexNoMatch); + CPPUNIT_TEST(testHandleAbortRequestEvent_alreadyInvalidated); + CPPUNIT_TEST(testHandleAbortRequestEvent_sendingInProgress); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void testCreate(); + void testGetMessage(); + void testDoReceivedAction_hasPieceAndAmNotChoking(); + void testDoReceivedAction_hasPieceAndAmChokingAndFastExtensionEnabled(); + void testDoReceivedAction_hasPieceAndAmChokingAndFastExtensionDisabled(); + void testDoReceivedAction_doesntHavePieceAndFastExtensionEnabled(); + void testDoReceivedAction_doesntHavePieceAndFastExtensionDisabled(); + void testHandleAbortRequestEvent(); + void testHandleAbortRequestEvent_indexNoMatch(); + void testHandleAbortRequestEvent_alreadyInvalidated(); + void testHandleAbortRequestEvent_sendingInProgress(); + void testToString(); + + class MockPieceStorage2 : public MockPieceStorage { + public: + virtual bool hasPiece(int index) { + return index == 1; + } + }; + + class MockBtMessage2 : public MockBtMessage { + public: + string type; + uint32_t index; + uint32_t begin; + uint32_t length; + public: + MockBtMessage2(string type, uint32_t index, uint32_t begin, uint32_t length):type(type), index(index), begin(begin), length(length) {} + }; + + typedef SharedHandle MockBtMessage2Handle; + + class MockBtMessageFactory2 : public MockBtMessageFactory { + public: + virtual BtMessageHandle + createPieceMessage(uint32_t index, uint32_t begin, uint32_t length) { + MockBtMessage2Handle btMsg = new MockBtMessage2("piece", index, begin, length); + return btMsg; + } + + virtual BtMessageHandle + createRejectMessage(uint32_t index, uint32_t begin, uint32_t length) { + MockBtMessage2Handle btMsg = new MockBtMessage2("reject", index, begin, length); + return btMsg; + } + }; + + typedef SharedHandle MockBtMessageFactory2Handle; + + PeerHandle peer; + MockBtMessageDispatcherHandle dispatcher; + BtRequestMessageHandle msg; + + BtRequestMessageTest():peer(0), dispatcher(0), msg(0) {} + + void setUp() { + BtRegistry::clear(); + + MockBtContextHandle btContext = new MockBtContext(); + btContext->setInfoHash((const unsigned char*)"12345678901234567890"); + btContext->setPieceLength(16*1024); + btContext->setTotalLength(256*1024); + + MockPieceStorageHandle pieceStorage = new MockPieceStorage2(); + + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage); + + peer = new Peer("host", 6969, btContext->getPieceLength(), btContext->getTotalLength()); + + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + PEER_OBJECT_CLUSTER(btContext)->registerHandle(peer->getId(), new PeerObject()); + + dispatcher = new MockBtMessageDispatcher(); + + PEER_OBJECT(btContext, peer)->btMessageDispatcher = dispatcher; + PEER_OBJECT(btContext, peer)->btMessageFactory = new MockBtMessageFactory2(); + + msg = new BtRequestMessage(); + msg->setBtContext(btContext); + msg->setPeer(peer); + msg->setIndex(1); + msg->setBegin(16); + msg->setLength(32); + msg->setBlockIndex(2); + } +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtRequestMessageTest); + +void BtRequestMessageTest::testCreate() { + unsigned 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); + BtRequestMessageHandle pm = BtRequestMessage::create(&msg[4], 13); + CPPUNIT_ASSERT_EQUAL(6, pm->getId()); + CPPUNIT_ASSERT_EQUAL((uint32_t)12345, pm->getIndex()); + CPPUNIT_ASSERT_EQUAL((uint32_t)256, pm->getBegin()); + CPPUNIT_ASSERT_EQUAL((uint32_t)1024, pm->getLength()); + + // case: payload size is wrong + try { + unsigned char msg[18]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 14, 6); + BtRequestMessage::create(&msg[4], 14); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[17]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 13, 7); + BtRequestMessage::create(&msg[4], 13); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtRequestMessageTest::testGetMessage() { + BtRequestMessage msg; + msg.setIndex(12345); + msg.setBegin(256); + msg.setLength(1024); + unsigned 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); +} + +void BtRequestMessageTest::testDoReceivedAction_hasPieceAndAmNotChoking() { + peer->amChoking = false; + msg->doReceivedAction(); + + CPPUNIT_ASSERT_EQUAL((size_t)1, dispatcher->messageQueue.size()); + MockBtMessage2* pieceMsg = (MockBtMessage2*)dispatcher->messageQueue.front().get(); + CPPUNIT_ASSERT_EQUAL(string("piece"), pieceMsg->type); + CPPUNIT_ASSERT_EQUAL((uint32_t)1, pieceMsg->index); + CPPUNIT_ASSERT_EQUAL((uint32_t)16, pieceMsg->begin); + CPPUNIT_ASSERT_EQUAL((uint32_t)32, pieceMsg->length); +} + +void BtRequestMessageTest::testDoReceivedAction_hasPieceAndAmChokingAndFastExtensionEnabled() { + peer->amChoking = true; + peer->setFastExtensionEnabled(true); + msg->doReceivedAction(); + + CPPUNIT_ASSERT_EQUAL((size_t)1, dispatcher->messageQueue.size()); + MockBtMessage2* pieceMsg = (MockBtMessage2*)dispatcher->messageQueue.front().get(); + CPPUNIT_ASSERT_EQUAL(string("reject"), pieceMsg->type); + CPPUNIT_ASSERT_EQUAL((uint32_t)1, pieceMsg->index); + CPPUNIT_ASSERT_EQUAL((uint32_t)16, pieceMsg->begin); + CPPUNIT_ASSERT_EQUAL((uint32_t)32, pieceMsg->length); +} + +void BtRequestMessageTest::testDoReceivedAction_hasPieceAndAmChokingAndFastExtensionDisabled() { + peer->amChoking = true; + msg->doReceivedAction(); + + CPPUNIT_ASSERT_EQUAL((size_t)0, dispatcher->messageQueue.size()); +} + +void BtRequestMessageTest::testDoReceivedAction_doesntHavePieceAndFastExtensionEnabled() { + msg->setIndex(2); + peer->amChoking = false; + peer->setFastExtensionEnabled(true); + msg->doReceivedAction(); + + CPPUNIT_ASSERT_EQUAL((size_t)1, dispatcher->messageQueue.size()); + MockBtMessage2* pieceMsg = (MockBtMessage2*)dispatcher->messageQueue.front().get(); + CPPUNIT_ASSERT_EQUAL(string("reject"), pieceMsg->type); + CPPUNIT_ASSERT_EQUAL((uint32_t)2, pieceMsg->index); + CPPUNIT_ASSERT_EQUAL((uint32_t)16, pieceMsg->begin); + CPPUNIT_ASSERT_EQUAL((uint32_t)32, pieceMsg->length); +} + +void BtRequestMessageTest::testDoReceivedAction_doesntHavePieceAndFastExtensionDisabled() { + msg->setIndex(2); + peer->amChoking = false; + msg->doReceivedAction(); + + CPPUNIT_ASSERT_EQUAL((size_t)0, dispatcher->messageQueue.size()); +} + +void BtRequestMessageTest::testHandleAbortRequestEvent() { + PieceHandle piece = new Piece(1, 16*1024); + BtAbortOutstandingRequestEventHandle event = + new BtAbortOutstandingRequestEvent(piece); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + msg->handleEvent(event); + + CPPUNIT_ASSERT(msg->isInvalidate()); +} + +void BtRequestMessageTest::testHandleAbortRequestEvent_indexNoMatch() { + PieceHandle piece = new Piece(2, 16*1024); + BtAbortOutstandingRequestEventHandle event = + new BtAbortOutstandingRequestEvent(piece); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + msg->handleEvent(event); + CPPUNIT_ASSERT(!msg->isInvalidate()); +} + +void BtRequestMessageTest::testHandleAbortRequestEvent_alreadyInvalidated() { + PieceHandle piece = new Piece(1, 16*1024); + BtAbortOutstandingRequestEventHandle event = + new BtAbortOutstandingRequestEvent(piece); + msg->setInvalidate(true); + + CPPUNIT_ASSERT(msg->isInvalidate()); + CPPUNIT_ASSERT(!msg->isSendingInProgress()); + msg->handleEvent(event); + CPPUNIT_ASSERT(msg->isInvalidate()); +} + +void BtRequestMessageTest::testHandleAbortRequestEvent_sendingInProgress() { + PieceHandle piece = new Piece(1, 16*1024); + BtAbortOutstandingRequestEventHandle event = + new BtAbortOutstandingRequestEvent(piece); + msg->setSendingInProgress(true); + + CPPUNIT_ASSERT(!msg->isInvalidate()); + CPPUNIT_ASSERT(msg->isSendingInProgress()); + msg->handleEvent(event); + CPPUNIT_ASSERT(!msg->isInvalidate()); +} + +void BtRequestMessageTest::testToString() { + CPPUNIT_ASSERT_EQUAL(string("request index=1, begin=16, length=32"), + msg->toString()); +} diff --git a/test/BtSuggestPieceMessageTest.cc b/test/BtSuggestPieceMessageTest.cc new file mode 100644 index 00000000..b62e9655 --- /dev/null +++ b/test/BtSuggestPieceMessageTest.cc @@ -0,0 +1,69 @@ +#include "BtSuggestPieceMessage.h" +#include "PeerMessageUtil.h" +#include + +using namespace std; + +class BtSuggestPieceMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtSuggestPieceMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtSuggestPieceMessageTest); + +void BtSuggestPieceMessageTest::testCreate() { + unsigned char msg[9]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 13); + PeerMessageUtil::setIntParam(&msg[5], 12345); + BtSuggestPieceMessageHandle pm = BtSuggestPieceMessage::create(&msg[4], 5); + CPPUNIT_ASSERT_EQUAL(13, pm->getId()); + CPPUNIT_ASSERT_EQUAL((uint32_t)12345, pm->getIndex()); + + // case: payload size is wrong + try { + unsigned char msg[10]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 6, 13); + BtSuggestPieceMessage::create(&msg[4], 2); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[9]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 5, 14); + BtSuggestPieceMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtSuggestPieceMessageTest::testGetMessage() { + BtSuggestPieceMessage msg; + msg.setIndex(12345); + unsigned char data[9]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 5, 13); + PeerMessageUtil::setIntParam(&data[5], 12345); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 9) == 0); +} + +void BtSuggestPieceMessageTest::testToString() { + BtSuggestPieceMessage msg; + msg.setIndex(12345); + + CPPUNIT_ASSERT_EQUAL(string("suggest piece index=12345"), + msg.toString()); +} diff --git a/test/BtUnchokeMessageTest.cc b/test/BtUnchokeMessageTest.cc new file mode 100644 index 00000000..82125b4a --- /dev/null +++ b/test/BtUnchokeMessageTest.cc @@ -0,0 +1,87 @@ +#include "BtUnchokeMessage.h" +#include "PeerMessageUtil.h" +#include + +using namespace std; + +class BtUnchokeMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtUnchokeMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testOnSendComplete); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testOnSendComplete(); + void testToString(); +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(BtUnchokeMessageTest); + +void BtUnchokeMessageTest::testCreate() { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 1); + BtUnchokeMessageHandle pm = BtUnchokeMessage::create(&msg[4], 1); + CPPUNIT_ASSERT_EQUAL(1, pm->getId()); + + // case: payload size is wrong + try { + unsigned char msg[6]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 2, 1); + BtUnchokeMessage::create(&msg[4], 2); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } + // case: id is wrong + try { + unsigned char msg[5]; + PeerMessageUtil::createPeerMessageString(msg, sizeof(msg), 1, 2); + BtUnchokeMessage::create(&msg[4], 1); + CPPUNIT_FAIL("exception must be threw."); + } catch(...) { + } +} + +void BtUnchokeMessageTest::testGetMessage() { + BtUnchokeMessage msg; + unsigned char data[5]; + PeerMessageUtil::createPeerMessageString(data, sizeof(data), 1, 1); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 5) == 0); +} + +void BtUnchokeMessageTest::testDoReceivedAction() { + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + peer->peerChoking = true; + BtUnchokeMessage msg; + msg.setPeer(peer); + + CPPUNIT_ASSERT(peer->peerChoking); + msg.doReceivedAction(); + CPPUNIT_ASSERT(!peer->peerChoking); +} + +void BtUnchokeMessageTest::testOnSendComplete() { + PeerHandle peer = new Peer("host", 6969, 16*1024, 256*1024); + peer->amChoking = true; + BtUnchokeMessage msg; + msg.setPeer(peer); + + CPPUNIT_ASSERT(peer->amChoking); + msg.onSendComplete(); + CPPUNIT_ASSERT(!peer->amChoking); +} + +void BtUnchokeMessageTest::testToString() { + BtUnchokeMessage msg; + CPPUNIT_ASSERT_EQUAL(string("unchoke"), msg.toString()); +} diff --git a/test/DefaultBtContextTest.cc b/test/DefaultBtContextTest.cc index 3010aea9..0e9348c0 100644 --- a/test/DefaultBtContextTest.cc +++ b/test/DefaultBtContextTest.cc @@ -22,6 +22,7 @@ class DefaultBtContextTest:public CppUnit::TestFixture { CPPUNIT_TEST(testGetAnnounceTierAnnounceList); CPPUNIT_TEST(testGetPieceLength); CPPUNIT_TEST(testGetInfoHashAsString); + CPPUNIT_TEST(testGetPeerId); CPPUNIT_TEST_SUITE_END(); public: void setUp() { @@ -41,6 +42,7 @@ public: void testGetAnnounceTierAnnounceList(); void testGetPieceLength(); void testGetInfoHashAsString(); + void testGetPeerId(); }; @@ -217,3 +219,8 @@ void DefaultBtContextTest::testGetInfoHashAsString() { CPPUNIT_ASSERT_EQUAL(string("248d0a1cd08284299de78d5c1ed359bb46717d8c"), btContext.getInfoHashAsString()); } + +void DefaultBtContextTest::testGetPeerId() { + DefaultBtContext btContext; + Util::torrentUrlencode(btContext.getPeerId(), 20); +} diff --git a/test/DefaultBtMessageDispatcherTest.cc b/test/DefaultBtMessageDispatcherTest.cc new file mode 100644 index 00000000..6e8b9e94 --- /dev/null +++ b/test/DefaultBtMessageDispatcherTest.cc @@ -0,0 +1,419 @@ +#include "DefaultBtMessageDispatcher.h" +#include "Util.h" +#include "Exception.h" +#include "MockPieceStorage.h" +#include "MockPeerStorage.h" +#include "BtRegistry.h" +#include "DefaultBtContext.h" +#include "MockBtMessage.h" +#include "MockBtMessageFactory.h" +#include "prefs.h" +#include "BtCancelSendingPieceEvent.h" +#include + +using namespace std; + +class DefaultBtMessageDispatcherTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultBtMessageDispatcherTest); + CPPUNIT_TEST(testAddMessage); + CPPUNIT_TEST(testSendMessages); + CPPUNIT_TEST(testSendMessages_underUploadLimit); + CPPUNIT_TEST(testSendMessages_overUploadLimit); + CPPUNIT_TEST(testSendMessages_sendingInProgress); + CPPUNIT_TEST(testDoCancelSendingPieceAction); + CPPUNIT_TEST(testCheckRequestSlotAndDoNecessaryThing); + CPPUNIT_TEST(testCheckRequestSlotAndDoNecessaryThing_timeout); + CPPUNIT_TEST(testCheckRequestSlotAndDoNecessaryThing_completeBlock); + CPPUNIT_TEST(testIsSendingInProgress); + CPPUNIT_TEST(testCountOutstandingRequest); + CPPUNIT_TEST(testIsOutstandingRequest); + CPPUNIT_TEST(testGetOutstandingRequest); + CPPUNIT_TEST(testRemoveOutstandingRequest); + CPPUNIT_TEST_SUITE_END(); +private: + BtContextHandle btContext; + Option* option; + PeerHandle peer; + DefaultBtMessageDispatcherHandle btMessageDispatcher; + MockPeerStorageHandle peerStorage; + MockPieceStorageHandle pieceStorage; +public: + DefaultBtMessageDispatcherTest():btContext(0), peer(0), btMessageDispatcher(0) {} + + void tearDown() { + delete option; + } + + void testAddMessage(); + void testSendMessages(); + void testSendMessages_underUploadLimit(); + void testSendMessages_overUploadLimit(); + void testSendMessages_sendingInProgress(); + void testDoCancelSendingPieceAction(); + void testCheckRequestSlotAndDoNecessaryThing(); + void testCheckRequestSlotAndDoNecessaryThing_timeout(); + void testCheckRequestSlotAndDoNecessaryThing_completeBlock(); + void testIsSendingInProgress(); + void testCountOutstandingRequest(); + void testIsOutstandingRequest(); + void testGetOutstandingRequest(); + void testRemoveOutstandingRequest(); + + class MockBtMessage2 : public MockBtMessage { + private: + bool onQueuedCalled; + bool sendCalled; + bool doCancelActionCalled; + public: + string type; + public: + MockBtMessage2():onQueuedCalled(false), + sendCalled(false), + doCancelActionCalled(false) + {} + + virtual ~MockBtMessage2() {} + + virtual void onQueued() { + onQueuedCalled = true; + } + + bool isOnQueuedCalled() const { + return onQueuedCalled; + } + + virtual void send() { + sendCalled = true; + } + + bool isSendCalled() const { + return sendCalled; + } + + virtual void handleEvent(const BtEventHandle& event) { + BtCancelSendingPieceEvent* e = + dynamic_cast(event.get()); + if(e) { + doCancelActionCalled = true; + } + } + + bool isDoCancelActionCalled() const { + return doCancelActionCalled; + } + }; + + typedef SharedHandle MockBtMessage2Handle; + + class MockPieceStorage2 : public MockPieceStorage { + private: + PieceHandle piece; + public: + virtual PieceHandle getPiece(int index) { + return piece; + } + + void setPiece(const PieceHandle& piece) { + this->piece = piece; + } + }; + + class MockBtMessageFactory2 : public MockBtMessageFactory { + public: + virtual BtMessageHandle + createCancelMessage(uint32_t index, uint32_t begin, uint32_t length) { + MockBtMessage2Handle btMsg = new MockBtMessage2(); + btMsg->type = "cancel"; + return btMsg; + } + }; + + void setUp() { + btContext = new DefaultBtContext(); + btContext->load("test.torrent"); + option = new Option(); + peer = new Peer("192.168.0.1", 6969, + btContext->getPieceLength(), + btContext->getTotalLength()); + peerStorage = new MockPeerStorage(); + pieceStorage = new MockPieceStorage(); + BtRegistry::clear(); + BtRegistry::registerPeerStorage(btContext->getInfoHashAsString(), + peerStorage); + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage); + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + + PeerObjectHandle peerObject = new PeerObject(); + peerObject->btMessageFactory = new MockBtMessageFactory2(); + + PEER_OBJECT_CLUSTER(btContext)->registerHandle(peer->getId(), peerObject); + + btMessageDispatcher = new DefaultBtMessageDispatcher(); + btMessageDispatcher->setCuid(1); + btMessageDispatcher->setBtContext(btContext); + btMessageDispatcher->setPeer(peer); + btMessageDispatcher->setOption(option); + } +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtMessageDispatcherTest); + +void DefaultBtMessageDispatcherTest::testAddMessage() { + MockBtMessage2Handle msg = new MockBtMessage2(); + CPPUNIT_ASSERT_EQUAL(false, msg->isOnQueuedCalled()); + btMessageDispatcher->addMessageToQueue(msg); + CPPUNIT_ASSERT_EQUAL(true, msg->isOnQueuedCalled()); + CPPUNIT_ASSERT_EQUAL((size_t)1, + btMessageDispatcher->getMessageQueue().size()); +} + +void DefaultBtMessageDispatcherTest::testSendMessages() { + option->put(PREF_MAX_UPLOAD_LIMIT, "0"); + TransferStat stat; + stat.setUploadSpeed(0); + peerStorage->setStat(stat); + + MockBtMessage2Handle msg1 = new MockBtMessage2(); + msg1->setSendingInProgress(false); + msg1->setUploading(false); + MockBtMessage2Handle msg2 = new MockBtMessage2(); + msg2->setSendingInProgress(false); + msg2->setUploading(false); + btMessageDispatcher->addMessageToQueue(msg1); + btMessageDispatcher->addMessageToQueue(msg2); + btMessageDispatcher->sendMessages(); + + CPPUNIT_ASSERT(msg1->isSendCalled()); + CPPUNIT_ASSERT(msg2->isSendCalled()); +} + +void DefaultBtMessageDispatcherTest::testSendMessages_underUploadLimit() { + option->put(PREF_MAX_UPLOAD_LIMIT, "0"); + TransferStat stat; + stat.setUploadSpeed(0); + peerStorage->setStat(stat); + + MockBtMessage2Handle msg1 = new MockBtMessage2(); + msg1->setSendingInProgress(false); + msg1->setUploading(true); + MockBtMessage2Handle msg2 = new MockBtMessage2(); + msg2->setSendingInProgress(false); + msg2->setUploading(true); + btMessageDispatcher->addMessageToQueue(msg1); + btMessageDispatcher->addMessageToQueue(msg2); + btMessageDispatcher->sendMessages(); + + CPPUNIT_ASSERT(msg1->isSendCalled()); + CPPUNIT_ASSERT(msg2->isSendCalled()); +} + +void DefaultBtMessageDispatcherTest::testSendMessages_overUploadLimit() { + option->put(PREF_MAX_UPLOAD_LIMIT, "100"); + TransferStat stat; + stat.setUploadSpeed(150); + peerStorage->setStat(stat); + + MockBtMessage2Handle msg1 = new MockBtMessage2(); + msg1->setSendingInProgress(false); + msg1->setUploading(true); + MockBtMessage2Handle msg2 = new MockBtMessage2(); + msg2->setSendingInProgress(false); + msg2->setUploading(true); + MockBtMessage2Handle msg3 = new MockBtMessage2(); + msg3->setSendingInProgress(false); + msg3->setUploading(false); + + btMessageDispatcher->addMessageToQueue(msg1); + btMessageDispatcher->addMessageToQueue(msg2); + btMessageDispatcher->addMessageToQueue(msg3); + btMessageDispatcher->sendMessages(); + + CPPUNIT_ASSERT(!msg1->isSendCalled()); + CPPUNIT_ASSERT(!msg2->isSendCalled()); + CPPUNIT_ASSERT(msg3->isSendCalled()); + + CPPUNIT_ASSERT_EQUAL((size_t)2, btMessageDispatcher->getMessageQueue().size()); +} + +void DefaultBtMessageDispatcherTest::testSendMessages_sendingInProgress() { + MockBtMessage2Handle msg1 = new MockBtMessage2(); + msg1->setSendingInProgress(false); + msg1->setUploading(false); + MockBtMessage2Handle msg2 = new MockBtMessage2(); + msg2->setSendingInProgress(true); + msg2->setUploading(false); + MockBtMessage2Handle msg3 = new MockBtMessage2(); + msg3->setSendingInProgress(false); + msg3->setUploading(false); + + btMessageDispatcher->addMessageToQueue(msg1); + btMessageDispatcher->addMessageToQueue(msg2); + btMessageDispatcher->addMessageToQueue(msg3); + + btMessageDispatcher->sendMessages(); + + CPPUNIT_ASSERT(msg1->isSendCalled()); + CPPUNIT_ASSERT(msg2->isSendCalled()); + CPPUNIT_ASSERT(!msg3->isSendCalled()); + + CPPUNIT_ASSERT_EQUAL((size_t)2, btMessageDispatcher->getMessageQueue().size()); +} + +void DefaultBtMessageDispatcherTest::testDoCancelSendingPieceAction() { + MockBtMessage2Handle msg1 = new MockBtMessage2(); + MockBtMessage2Handle msg2 = new MockBtMessage2(); + + btMessageDispatcher->addMessageToQueue(msg1); + btMessageDispatcher->addMessageToQueue(msg2); + + btMessageDispatcher->doCancelSendingPieceAction(0, 0, 0); + + CPPUNIT_ASSERT_EQUAL(true, msg1->isDoCancelActionCalled()); + CPPUNIT_ASSERT_EQUAL(true, msg2->isDoCancelActionCalled()); +} + +int MY_PIECE_LENGTH = 16*1024; + +void DefaultBtMessageDispatcherTest::testCheckRequestSlotAndDoNecessaryThing() { + RequestSlot slot(0, 0, MY_PIECE_LENGTH, 0); + + PieceHandle piece = new Piece(0, MY_PIECE_LENGTH); + assert(piece->getMissingUnusedBlockIndex() == 0); + + SharedHandle pieceStorage = new MockPieceStorage2(); + pieceStorage->setPiece(piece); + CPPUNIT_ASSERT(BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage)); + + option->put(PREF_BT_REQUEST_TIMEOUT, "60"); + + btMessageDispatcher = new DefaultBtMessageDispatcher(); + btMessageDispatcher->setCuid(1); + btMessageDispatcher->setBtContext(btContext); + btMessageDispatcher->setPeer(peer); + btMessageDispatcher->setOption(option); + + btMessageDispatcher->addOutstandingRequest(slot); + + btMessageDispatcher->checkRequestSlotAndDoNecessaryThing(); + + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->getMessageQueue().size()); + CPPUNIT_ASSERT_EQUAL((size_t)1, btMessageDispatcher->getRequestSlots().size()); +} + +void DefaultBtMessageDispatcherTest::testCheckRequestSlotAndDoNecessaryThing_timeout() { + RequestSlot slot(0, 0, MY_PIECE_LENGTH, 0); + // make this slot timeout + slot.setDispatchedTime(0); + + PieceHandle piece = new Piece(0, MY_PIECE_LENGTH); + assert(piece->getMissingUnusedBlockIndex() == 0); + + SharedHandle pieceStorage = new MockPieceStorage2(); + pieceStorage->setPiece(piece); + CPPUNIT_ASSERT(BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage)); + option->put(PREF_BT_REQUEST_TIMEOUT, "60"); + + btMessageDispatcher = new DefaultBtMessageDispatcher(); + btMessageDispatcher->setCuid(1); + btMessageDispatcher->setBtContext(btContext); + btMessageDispatcher->setPeer(peer); + btMessageDispatcher->setOption(option); + + btMessageDispatcher->addOutstandingRequest(slot); + + btMessageDispatcher->checkRequestSlotAndDoNecessaryThing(); + + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->getMessageQueue().size()); + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->getRequestSlots().size()); + CPPUNIT_ASSERT_EQUAL(false, piece->isBlockUsed(0)); + CPPUNIT_ASSERT_EQUAL(true, peer->snubbing); +} + +void DefaultBtMessageDispatcherTest::testCheckRequestSlotAndDoNecessaryThing_completeBlock() { + RequestSlot slot(0, 0, MY_PIECE_LENGTH, 0); + + PieceHandle piece = new Piece(0, MY_PIECE_LENGTH); + piece->completeBlock(0); + + SharedHandle pieceStorage = new MockPieceStorage2(); + pieceStorage->setPiece(piece); + CPPUNIT_ASSERT(BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + pieceStorage)); + + option->put(PREF_BT_REQUEST_TIMEOUT, "60"); + + btMessageDispatcher = new DefaultBtMessageDispatcher(); + btMessageDispatcher->setCuid(1); + btMessageDispatcher->setBtContext(btContext); + btMessageDispatcher->setPeer(peer); + btMessageDispatcher->setOption(option); + + btMessageDispatcher->addOutstandingRequest(slot); + + btMessageDispatcher->checkRequestSlotAndDoNecessaryThing(); + + CPPUNIT_ASSERT_EQUAL((size_t)1, btMessageDispatcher->getMessageQueue().size()); + CPPUNIT_ASSERT_EQUAL((size_t)0, btMessageDispatcher->getRequestSlots().size()); +} + +void DefaultBtMessageDispatcherTest::testIsSendingInProgress() { + CPPUNIT_ASSERT(!btMessageDispatcher->isSendingInProgress()); + MockBtMessage2Handle msg = new MockBtMessage2(); + msg->setSendingInProgress(false); + btMessageDispatcher->addMessageToQueue(msg); + CPPUNIT_ASSERT(!btMessageDispatcher->isSendingInProgress()); + msg->setSendingInProgress(true); + CPPUNIT_ASSERT(btMessageDispatcher->isSendingInProgress()); +} + +void DefaultBtMessageDispatcherTest::testCountOutstandingRequest() { + RequestSlot slot(0, 0, MY_PIECE_LENGTH, 0); + btMessageDispatcher->addOutstandingRequest(slot); + CPPUNIT_ASSERT_EQUAL((uint32_t)1, btMessageDispatcher->countOutstandingRequest()); +} + +void DefaultBtMessageDispatcherTest::testIsOutstandingRequest() { + RequestSlot slot(0, 0, MY_PIECE_LENGTH, 0); + btMessageDispatcher->addOutstandingRequest(slot); + + CPPUNIT_ASSERT(btMessageDispatcher->isOutstandingRequest(0, 0)); + CPPUNIT_ASSERT(!btMessageDispatcher->isOutstandingRequest(0, 1)); + CPPUNIT_ASSERT(!btMessageDispatcher->isOutstandingRequest(1, 0)); + CPPUNIT_ASSERT(!btMessageDispatcher->isOutstandingRequest(1, 1)); +} + +void DefaultBtMessageDispatcherTest::testGetOutstandingRequest() { + RequestSlot slot(1, 1024, 16*1024, 10); + btMessageDispatcher->addOutstandingRequest(slot); + + RequestSlot s2 = btMessageDispatcher->getOutstandingRequest(1, 1024, 16*1024); + CPPUNIT_ASSERT(!RequestSlot::isNull(s2)); + + RequestSlot s3 = btMessageDispatcher->getOutstandingRequest(1, 1024, 17*1024); + CPPUNIT_ASSERT(RequestSlot::isNull(s3)); + + RequestSlot s4 = btMessageDispatcher->getOutstandingRequest(1, 2*1024, 16*1024); + CPPUNIT_ASSERT(RequestSlot::isNull(s4)); + + RequestSlot s5 = btMessageDispatcher->getOutstandingRequest(2, 1024, 16*1024); + CPPUNIT_ASSERT(RequestSlot::isNull(s5)); +} + +void DefaultBtMessageDispatcherTest::testRemoveOutstandingRequest() { + RequestSlot slot(1, 1024, 16*1024, 10); + btMessageDispatcher->addOutstandingRequest(slot); + + RequestSlot s2 = btMessageDispatcher->getOutstandingRequest(1, 1024, 16*1024); + CPPUNIT_ASSERT(!RequestSlot::isNull(s2)); + + btMessageDispatcher->removeOutstandingRequest(s2); + + RequestSlot s3 = btMessageDispatcher->getOutstandingRequest(1, 1024, 16*1024); + CPPUNIT_ASSERT(RequestSlot::isNull(s3)); +} diff --git a/test/DefaultBtRequestFactoryTest.cc b/test/DefaultBtRequestFactoryTest.cc new file mode 100644 index 00000000..c36d31e3 --- /dev/null +++ b/test/DefaultBtRequestFactoryTest.cc @@ -0,0 +1,173 @@ +#include "DefaultBtRequestFactory.h" +#include "MockBtMessage.h" +#include "MockBtMessageFactory.h" +#include "MockBtMessageDispatcher.h" +#include "MockBtContext.h" +#include "BtRegistry.h" +#include "MockPieceStorage.h" +#include + +using namespace std; + +class DefaultBtRequestFactoryTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultBtRequestFactoryTest); + CPPUNIT_TEST(testAddTargetPiece); + CPPUNIT_TEST(testRemoveCompletedPiece); + CPPUNIT_TEST(testCreateRequestMessages); + CPPUNIT_TEST(testCreateRequestMessages_onEndGame); + CPPUNIT_TEST(testRemoveTargetPiece); + CPPUNIT_TEST_SUITE_END(); +private: + DefaultBtRequestFactoryHandle btRequestFactory; + MockBtContextHandle btContext; +public: + DefaultBtRequestFactoryTest():btRequestFactory(0), btContext(0) {} + + void testAddTargetPiece(); + void testRemoveCompletedPiece(); + void testCreateRequestMessages(); + void testCreateRequestMessages_onEndGame(); + void testRemoveTargetPiece(); + + class MockBtRequestMessage : public MockBtMessage { + public: + int index; + int blockIndex; + + MockBtRequestMessage(int index, int blockIndex):index(index), blockIndex(blockIndex) {} + }; + + typedef SharedHandle MockBtRequestMessageHandle; + + class MockBtMessageFactory2 : public MockBtMessageFactory { + public: + virtual BtMessageHandle + createRequestMessage(const PieceHandle& piece, uint32_t blockIndex) { + return new MockBtRequestMessage(piece->getIndex(), blockIndex); + } + }; + + class MockBtMessageDispatcher2 : public MockBtMessageDispatcher { + public: + virtual bool isOutstandingRequest(uint32_t index, uint32_t blockIndex) { + return index == 0 && blockIndex == 0; + } + }; + + void setUp() { + BtRegistry::clear(); + btContext = new MockBtContext(); + btContext->setInfoHash((const unsigned char*)"12345678901234567890"); + btContext->setPieceLength(16*1024); + btContext->setTotalLength(256*1024); + + BtRegistry::registerPieceStorage(btContext->getInfoHashAsString(), + new MockPieceStorage()); + + PeerHandle peer = new Peer("host", 6969, btContext->getPieceLength(), btContext->getTotalLength()); + + BtRegistry::registerPeerObjectCluster(btContext->getInfoHashAsString(), + new PeerObjectCluster()); + PeerObjectHandle peerObject = new PeerObject(); + peerObject->btMessageFactory = new MockBtMessageFactory2(); + PEER_OBJECT_CLUSTER(btContext)->registerHandle(peer->getId(), peerObject); + + btRequestFactory = new DefaultBtRequestFactory(); + btRequestFactory->setBtContext(btContext); + btRequestFactory->setPeer(peer); + btRequestFactory->setBtMessageDispatcher(new MockBtMessageDispatcher()); + } + +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtRequestFactoryTest); + +void DefaultBtRequestFactoryTest::testAddTargetPiece() { + PieceHandle piece = new Piece(0, 16*1024); + btRequestFactory->addTargetPiece(piece); + CPPUNIT_ASSERT_EQUAL(1, btRequestFactory->countTargetPiece()); +} + +void DefaultBtRequestFactoryTest::testRemoveCompletedPiece() { + PieceHandle piece1 = new Piece(0, 16*1024); + PieceHandle piece2 = new Piece(1, 16*1024); + piece2->setAllBlock(); + btRequestFactory->addTargetPiece(piece1); + btRequestFactory->addTargetPiece(piece2); + CPPUNIT_ASSERT_EQUAL(2, btRequestFactory->countTargetPiece()); + btRequestFactory->removeCompletedPiece(); + CPPUNIT_ASSERT_EQUAL(1, btRequestFactory->countTargetPiece()); + CPPUNIT_ASSERT_EQUAL(0, btRequestFactory->getTargetPieces().front()->getIndex()); +} + +void DefaultBtRequestFactoryTest::testCreateRequestMessages() { + int PIECE_LENGTH = 16*1024*2; + PieceHandle piece1 = new Piece(0, PIECE_LENGTH); + PieceHandle piece2 = new Piece(1, PIECE_LENGTH); + btRequestFactory->addTargetPiece(piece1); + btRequestFactory->addTargetPiece(piece2); + + BtMessages msgs = btRequestFactory->createRequestMessages(3); + + CPPUNIT_ASSERT_EQUAL((size_t)3, msgs.size()); + BtMessages::iterator itr = msgs.begin(); + MockBtRequestMessage* msg = (MockBtRequestMessage*)itr->get(); + CPPUNIT_ASSERT_EQUAL(0, msg->index); + CPPUNIT_ASSERT_EQUAL(0, msg->blockIndex); + ++itr; + msg = (MockBtRequestMessage*)itr->get(); + CPPUNIT_ASSERT_EQUAL(0, msg->index); + CPPUNIT_ASSERT_EQUAL(1, msg->blockIndex); + ++itr; + msg = (MockBtRequestMessage*)itr->get(); + CPPUNIT_ASSERT_EQUAL(1, msg->index); + CPPUNIT_ASSERT_EQUAL(0, msg->blockIndex); + + CPPUNIT_ASSERT_EQUAL((size_t)1, btRequestFactory->createRequestMessages(3).size()); +} + +void DefaultBtRequestFactoryTest::testCreateRequestMessages_onEndGame() { + MockBtMessageDispatcher2* dispatcher = new MockBtMessageDispatcher2(); + + btRequestFactory->setBtMessageDispatcher(dispatcher); + + int PIECE_LENGTH = 16*1024*2; + PieceHandle piece1 = new Piece(0, PIECE_LENGTH); + PieceHandle piece2 = new Piece(1, PIECE_LENGTH); + btRequestFactory->addTargetPiece(piece1); + btRequestFactory->addTargetPiece(piece2); + + BtMessages msgs = btRequestFactory->createRequestMessagesOnEndGame(3); + + CPPUNIT_ASSERT_EQUAL((size_t)3, msgs.size()); + BtMessages::iterator itr = msgs.begin(); + MockBtRequestMessage* msg = (MockBtRequestMessage*)itr->get(); + CPPUNIT_ASSERT_EQUAL(0, msg->index); + CPPUNIT_ASSERT_EQUAL(1, msg->blockIndex); + ++itr; + msg = (MockBtRequestMessage*)itr->get(); + CPPUNIT_ASSERT_EQUAL(1, msg->index); + CPPUNIT_ASSERT_EQUAL(0, msg->blockIndex); + ++itr; + msg = (MockBtRequestMessage*)itr->get(); + CPPUNIT_ASSERT_EQUAL(1, msg->index); + CPPUNIT_ASSERT_EQUAL(1, msg->blockIndex); +} + +void DefaultBtRequestFactoryTest::testRemoveTargetPiece() { + PieceHandle piece1 = new Piece(0, 16*1024); + + btRequestFactory->addTargetPiece(piece1); + + CPPUNIT_ASSERT(find(btRequestFactory->getTargetPieces().begin(), + btRequestFactory->getTargetPieces().end(), + piece1) != btRequestFactory->getTargetPieces().end()); + + btRequestFactory->removeTargetPiece(piece1); + + CPPUNIT_ASSERT(find(btRequestFactory->getTargetPieces().begin(), + btRequestFactory->getTargetPieces().end(), + piece1) == btRequestFactory->getTargetPieces().end()); +} diff --git a/test/DefaultPeerStorageTest.cc b/test/DefaultPeerStorageTest.cc index 1d65bd60..21b0326d 100644 --- a/test/DefaultPeerStorageTest.cc +++ b/test/DefaultPeerStorageTest.cc @@ -4,8 +4,6 @@ #include "Exception.h" #include -extern PeerHandle nullPeer; - using namespace std; class DefaultPeerStorageTest:public CppUnit::TestFixture { @@ -143,7 +141,7 @@ void DefaultPeerStorageTest::testGetPeer() { peer1->cuid = 1; - CPPUNIT_ASSERT(nullPeer == ps.getUnusedPeer()); + CPPUNIT_ASSERT(ps.getUnusedPeer().isNull()); peer1->resetStatus(); peer1->error = 1; @@ -154,7 +152,7 @@ void DefaultPeerStorageTest::testGetPeer() { peer1->resetStatus(); peer1->error = MAX_PEER_ERROR; - CPPUNIT_ASSERT(nullPeer == ps.getUnusedPeer()); + CPPUNIT_ASSERT(ps.getUnusedPeer().isNull()); } void DefaultPeerStorageTest::testIsPeerAvailable() { diff --git a/test/DefaultPieceStorageTest.cc b/test/DefaultPieceStorageTest.cc index d26926b0..067309da 100644 --- a/test/DefaultPieceStorageTest.cc +++ b/test/DefaultPieceStorageTest.cc @@ -2,6 +2,8 @@ #include "DefaultBtContext.h" #include "Util.h" #include "Exception.h" +#include "FixedNumberRandomizer.h" +#include "BitfieldManFactory.h" #include using namespace std; @@ -14,13 +16,20 @@ class DefaultPieceStorageTest:public CppUnit::TestFixture { CPPUNIT_TEST(testGetMissingFastPiece); CPPUNIT_TEST(testHasMissingPiece); CPPUNIT_TEST(testCompletePiece); + CPPUNIT_TEST(testGetPiece); + CPPUNIT_TEST(testGetPieceInUsedPieces); + CPPUNIT_TEST(testGetPieceCompletedPiece); CPPUNIT_TEST_SUITE_END(); private: BtContextHandle btContext; PeerHandle peer; Option* option; public: - DefaultPieceStorageTest():btContext(0) {} + DefaultPieceStorageTest():btContext(0), peer(0) { + FixedNumberRandomizer* randomizer = new FixedNumberRandomizer(); + randomizer->setFixedNumber(0); + BitfieldManFactory::setDefaultRandomizer(randomizer); + } void setUp() { btContext = BtContextHandle(new DefaultBtContext()); @@ -36,6 +45,9 @@ public: void testGetMissingFastPiece(); void testHasMissingPiece(); void testCompletePiece(); + void testGetPiece(); + void testGetPieceInUsedPieces(); + void testGetPieceCompletedPiece(); }; @@ -53,17 +65,17 @@ void DefaultPieceStorageTest::testGetMissingPiece() { pss.setEndGamePieceNum(0); peer->setAllBitfield(); - Piece piece = pss.getMissingPiece(peer); + PieceHandle piece = pss.getMissingPiece(peer); CPPUNIT_ASSERT_EQUAL(string("piece: index=0, length=128"), - piece.toString()); + piece->toString()); piece = pss.getMissingPiece(peer); CPPUNIT_ASSERT_EQUAL(string("piece: index=1, length=128"), - piece.toString()); + piece->toString()); piece = pss.getMissingPiece(peer); CPPUNIT_ASSERT_EQUAL(string("piece: index=2, length=128"), - piece.toString()); + piece->toString()); piece = pss.getMissingPiece(peer); - CPPUNIT_ASSERT(Piece::isNull(piece)); + CPPUNIT_ASSERT(piece.isNull()); } void DefaultPieceStorageTest::testGetMissingFastPiece() { @@ -74,9 +86,9 @@ void DefaultPieceStorageTest::testGetMissingFastPiece() { peer->setFastExtensionEnabled(true); peer->addFastSetIndex(2); - Piece piece = pss.getMissingFastPiece(peer); + PieceHandle piece = pss.getMissingFastPiece(peer); CPPUNIT_ASSERT_EQUAL(string("piece: index=2, length=128"), - piece.toString()); + piece->toString()); } void DefaultPieceStorageTest::testHasMissingPiece() { @@ -95,9 +107,9 @@ void DefaultPieceStorageTest::testCompletePiece() { peer->setAllBitfield(); - Piece piece = pss.getMissingPiece(peer); + PieceHandle piece = pss.getMissingPiece(peer); CPPUNIT_ASSERT_EQUAL(string("piece: index=0, length=128"), - piece.toString()); + piece->toString()); CPPUNIT_ASSERT_EQUAL((long long int)0, pss.getCompletedLength()); @@ -108,3 +120,33 @@ void DefaultPieceStorageTest::testCompletePiece() { pss.getCompletedLength()); } + +void DefaultPieceStorageTest::testGetPiece() { + DefaultPieceStorage pss(btContext, option); + + PieceHandle pieceGot = pss.getPiece(0); + CPPUNIT_ASSERT_EQUAL(0, pieceGot->getIndex()); + CPPUNIT_ASSERT_EQUAL(128, pieceGot->getLength()); + CPPUNIT_ASSERT_EQUAL(false, pieceGot->pieceComplete()); +} + +void DefaultPieceStorageTest::testGetPieceInUsedPieces() { + DefaultPieceStorage pss(btContext, option); + PieceHandle piece = PieceHandle(new Piece(0, 128)); + piece->completeBlock(0); + pss.addUsedPiece(piece); + PieceHandle pieceGot = pss.getPiece(0); + CPPUNIT_ASSERT_EQUAL(0, pieceGot->getIndex()); + CPPUNIT_ASSERT_EQUAL(128, pieceGot->getLength()); + CPPUNIT_ASSERT_EQUAL(1, pieceGot->countCompleteBlock()); +} + +void DefaultPieceStorageTest::testGetPieceCompletedPiece() { + DefaultPieceStorage pss(btContext, option); + PieceHandle piece = PieceHandle(new Piece(0, 128)); + pss.completePiece(piece); + PieceHandle pieceGot = pss.getPiece(0); + CPPUNIT_ASSERT_EQUAL(0, pieceGot->getIndex()); + CPPUNIT_ASSERT_EQUAL(128, pieceGot->getLength()); + CPPUNIT_ASSERT_EQUAL(true, pieceGot->pieceComplete()); +} diff --git a/test/FixedNumberRandomizer.h b/test/FixedNumberRandomizer.h new file mode 100644 index 00000000..bd4ed7df --- /dev/null +++ b/test/FixedNumberRandomizer.h @@ -0,0 +1,31 @@ +#ifndef _D_FIXED_NUMBER_RANDOMIZER_H_ +#define _D_FIXED_NUMBER_RANDOMIZER_H_ + +#include "Randomizer.h" + +class FixedNumberRandomizer : public Randomizer { +private: + int fixedNumber; +public: + FixedNumberRandomizer():fixedNumber(0) {} + + virtual ~FixedNumberRandomizer() {} + + virtual int getRandomNumber() { + return fixedNumber; + } + + virtual int getMaxRandomNumber() { + return RAND_MAX; + } + + void setFixedNumber(int num) { + this->fixedNumber = num; + } + + int getFixedNumber() const { + return fixedNumber; + } +}; + +#endif // _D_FIXED_NUMBER_RANDOMIZER_H_ diff --git a/test/Makefile.am b/test/Makefile.am index 10e5f44a..7c458631 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -14,23 +14,9 @@ aria2c_SOURCES = AllTest.cc\ MetaFileUtilTest.cc\ ShaVisitorTest.cc\ PeerMessageUtilTest.cc\ - BitfieldManTest.cc\ DefaultDiskWriterTest.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\ + BitfieldManTest.cc\ Xml2MetalinkProcessorTest.cc\ MetalinkerTest.cc\ MetalinkEntryTest.cc\ @@ -46,7 +32,32 @@ aria2c_SOURCES = AllTest.cc\ DefaultPieceStorageTest.cc\ DefaultPeerStorageTest.cc\ DefaultBtAnnounceTest.cc\ - BtRegistryTest.cc + BtRegistryTest.cc\ + DefaultBtMessageDispatcherTest.cc\ + MockPeerStorage.h\ + DefaultBtRequestFactoryTest.cc\ + PeerTest.cc\ + BtAllowedFastMessageTest.cc\ + BtBitfieldMessageTest.cc\ + BtCancelMessageTest.cc\ + BtChokeMessageTest.cc\ + BtHaveAllMessageTest.cc\ + BtHaveMessageTest.cc\ + BtHaveNoneMessageTest.cc\ + BtInterestedMessageTest.cc\ + BtKeepAliveMessageTest.cc\ + BtNotInterestedMessageTest.cc\ + BtPieceMessageTest.cc\ + BtPortMessageTest.cc\ + BtRejectMessageTest.cc\ + BtRequestMessageTest.cc\ + BtSuggestPieceMessageTest.cc\ + BtUnchokeMessageTest.cc\ + BtHandshakeMessageTest.cc\ + MockBtMessageDispatcher.h\ + FixedNumberRandomizer.h\ + MockBtMessageFactory.h\ + MockBtMessage.h #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_LDFLAGS = ${CPPUNIT_LIBS} diff --git a/test/Makefile.in b/test/Makefile.in index 514243d8..ef459e53 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -63,16 +63,8 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \ CookieBoxTest.$(OBJEXT) DataTest.$(OBJEXT) \ DictionaryTest.$(OBJEXT) ListTest.$(OBJEXT) \ MetaFileUtilTest.$(OBJEXT) ShaVisitorTest.$(OBJEXT) \ - PeerMessageUtilTest.$(OBJEXT) BitfieldManTest.$(OBJEXT) \ - DefaultDiskWriterTest.$(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) \ + PeerMessageUtilTest.$(OBJEXT) DefaultDiskWriterTest.$(OBJEXT) \ + MultiDiskWriterTest.$(OBJEXT) BitfieldManTest.$(OBJEXT) \ Xml2MetalinkProcessorTest.$(OBJEXT) MetalinkerTest.$(OBJEXT) \ MetalinkEntryTest.$(OBJEXT) FeatureConfigTest.$(OBJEXT) \ ShareRatioSeedCriteriaTest.$(OBJEXT) \ @@ -82,7 +74,21 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) RequestTest.$(OBJEXT) \ DefaultBtContextTest.$(OBJEXT) \ DefaultPieceStorageTest.$(OBJEXT) \ DefaultPeerStorageTest.$(OBJEXT) \ - DefaultBtAnnounceTest.$(OBJEXT) BtRegistryTest.$(OBJEXT) + DefaultBtAnnounceTest.$(OBJEXT) BtRegistryTest.$(OBJEXT) \ + DefaultBtMessageDispatcherTest.$(OBJEXT) \ + DefaultBtRequestFactoryTest.$(OBJEXT) PeerTest.$(OBJEXT) \ + BtAllowedFastMessageTest.$(OBJEXT) \ + BtBitfieldMessageTest.$(OBJEXT) BtCancelMessageTest.$(OBJEXT) \ + BtChokeMessageTest.$(OBJEXT) BtHaveAllMessageTest.$(OBJEXT) \ + BtHaveMessageTest.$(OBJEXT) BtHaveNoneMessageTest.$(OBJEXT) \ + BtInterestedMessageTest.$(OBJEXT) \ + BtKeepAliveMessageTest.$(OBJEXT) \ + BtNotInterestedMessageTest.$(OBJEXT) \ + BtPieceMessageTest.$(OBJEXT) BtPortMessageTest.$(OBJEXT) \ + BtRejectMessageTest.$(OBJEXT) BtRequestMessageTest.$(OBJEXT) \ + BtSuggestPieceMessageTest.$(OBJEXT) \ + BtUnchokeMessageTest.$(OBJEXT) \ + BtHandshakeMessageTest.$(OBJEXT) aria2c_OBJECTS = $(am_aria2c_OBJECTS) am__DEPENDENCIES_1 = aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1) @@ -94,6 +100,10 @@ CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ CXXLD = $(CXX) CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ -o $@ +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ SOURCES = $(aria2c_SOURCES) DIST_SOURCES = $(aria2c_SOURCES) ETAGS = etags @@ -256,23 +266,9 @@ aria2c_SOURCES = AllTest.cc\ MetaFileUtilTest.cc\ ShaVisitorTest.cc\ PeerMessageUtilTest.cc\ - BitfieldManTest.cc\ DefaultDiskWriterTest.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\ + BitfieldManTest.cc\ Xml2MetalinkProcessorTest.cc\ MetalinkerTest.cc\ MetalinkEntryTest.cc\ @@ -288,7 +284,32 @@ aria2c_SOURCES = AllTest.cc\ DefaultPieceStorageTest.cc\ DefaultPeerStorageTest.cc\ DefaultBtAnnounceTest.cc\ - BtRegistryTest.cc + BtRegistryTest.cc\ + DefaultBtMessageDispatcherTest.cc\ + MockPeerStorage.h\ + DefaultBtRequestFactoryTest.cc\ + PeerTest.cc\ + BtAllowedFastMessageTest.cc\ + BtBitfieldMessageTest.cc\ + BtCancelMessageTest.cc\ + BtChokeMessageTest.cc\ + BtHaveAllMessageTest.cc\ + BtHaveMessageTest.cc\ + BtHaveNoneMessageTest.cc\ + BtInterestedMessageTest.cc\ + BtKeepAliveMessageTest.cc\ + BtNotInterestedMessageTest.cc\ + BtPieceMessageTest.cc\ + BtPortMessageTest.cc\ + BtRejectMessageTest.cc\ + BtRequestMessageTest.cc\ + BtSuggestPieceMessageTest.cc\ + BtUnchokeMessageTest.cc\ + BtHandshakeMessageTest.cc\ + MockBtMessageDispatcher.h\ + FixedNumberRandomizer.h\ + MockBtMessageFactory.h\ + MockBtMessage.h #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_LDFLAGS = ${CPPUNIT_LIBS} @@ -352,19 +373,34 @@ 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)/AnnounceListTest.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)/BtAllowedFastMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtBitfieldMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtCancelMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtChokeMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHandshakeMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveAllMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtHaveNoneMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtInterestedMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtKeepAliveMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtNotInterestedMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPieceMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtPortMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRegistryTest.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)/BtRejectMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtRequestMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSuggestPieceMessageTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtUnchokeMessageTest.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)/DefaultBtAnnounceTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtContextTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtMessageDispatcherTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtRequestFactoryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultDiskWriterTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerListProcessorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPeerStorageTest.Po@am__quote@ @@ -372,30 +408,21 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DictionaryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FeatureConfigTest.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)/MetalinkEntryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MetalinkerTest.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)/PeerTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/RequestTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SegmentManTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShaVisitorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ShareRatioSeedCriteriaTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SpeedCalcTest.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SuggestPieceMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommandTest.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Xml2MetalinkProcessorTest.Po@am__quote@ diff --git a/test/MockBtContext.h b/test/MockBtContext.h index 96139edc..fdc0f880 100644 --- a/test/MockBtContext.h +++ b/test/MockBtContext.h @@ -13,10 +13,14 @@ private: string name; int pieceLength; int numPieces; + unsigned char peerId[20]; FileEntries fileEntries; AnnounceTiers announceTiers; public: - MockBtContext() {} + MockBtContext():totalLength(0), + pieceLength(0), + numPieces(0) {} + virtual ~MockBtContext() {} virtual const unsigned char* getInfoHash() const { @@ -100,6 +104,17 @@ public: void setNumPieces(int numPieces) { this->numPieces = numPieces; } + + virtual const unsigned char* getPeerId() { + return peerId; + } + + void setPeerId(const unsigned char* peerId) { + memcpy(this->peerId, peerId, sizeof(this->peerId)); + } + }; +typedef SharedHandle MockBtContextHandle; + #endif // _D_MOCK_BT_CONTEXT_H_ diff --git a/test/MockBtMessage.h b/test/MockBtMessage.h new file mode 100644 index 00000000..63d59cb6 --- /dev/null +++ b/test/MockBtMessage.h @@ -0,0 +1,102 @@ +/* */ +#ifndef _D_MOCK_BT_MESSAGE_H_ +#define _D_MOCK_BT_MESSAGE_H_ + +#include "BtMessage.h" + +class MockBtMessage : public BtMessage { +private: + bool sendingInProgress; + bool invalidate; + bool uploading; + int32_t id; +public: + MockBtMessage() {} + + virtual ~MockBtMessage() {} + + virtual bool isSendingInProgress() { + return sendingInProgress; + } + + void setSendingInProgress(bool flag) { + this->sendingInProgress = flag; + } + + virtual bool isInvalidate() { + return invalidate; + } + + void setInvalidate(bool flag) { + this->invalidate = flag; + } + + virtual bool isUploading() { + return uploading; + } + + void setUploading(bool flag) { + this->uploading = flag; + } + + virtual int32_t getId() { + return id; + } + + void setId(int32_t id) { + this->id = id; + } + + virtual void doReceivedAction() { + } + + virtual void send() {} + + virtual bool validate(Errors& errors) { + return false; + } + + virtual void handleEvent(const BtEventHandle& event) {} + + virtual void onQueued() {} + + virtual string toString() const { return "MockBtMessage"; } + +}; + +typedef SharedHandle MockBtMessageHandle; + +#endif // _D_MOCK_BT_MESSAGE_H_ diff --git a/test/MockBtMessageDispatcher.h b/test/MockBtMessageDispatcher.h new file mode 100644 index 00000000..5243ef0f --- /dev/null +++ b/test/MockBtMessageDispatcher.h @@ -0,0 +1,61 @@ +#ifndef _D_MOCK_BT_MESSAGE_DISPATCHER_H_ +#define _D_MOCK_BT_MESSAGE_DISPATCHER_H_ + +#include "BtMessageDispatcher.h" + +class MockBtMessageDispatcher : public BtMessageDispatcher { +public: + BtMessages messageQueue; + + virtual ~MockBtMessageDispatcher() {} + + virtual void addMessageToQueue(const BtMessageHandle& btMessage) { + messageQueue.push_back(btMessage); + } + + virtual void addMessageToQueue(const BtMessages& btMessages) { + copy(btMessages.begin(), btMessages.end(), back_inserter(messageQueue)); + } + + virtual void sendMessages() {} + + virtual void doCancelSendingPieceAction(uint32_t index, uint32_t begin, uint32_t blockLength) {} + + virtual void doCancelSendingPieceAction(const PieceHandle& piece) {} + + virtual void doAbortOutstandingRequestAction(const PieceHandle& piece) {} + + virtual void doChokedAction() {} + + virtual void doChokingAction() {} + + virtual void checkRequestSlotAndDoNecessaryThing() {} + + virtual bool isSendingInProgress() { + return false; + } + + virtual uint32_t countMessageInQueue() { + return messageQueue.size(); + } + + virtual uint32_t countOutstandingRequest() { + return 0; + } + + virtual bool isOutstandingRequest(uint32_t index, uint32_t blockIndex) { + return false; + } + + virtual RequestSlot getOutstandingRequest(uint32_t index, uint32_t begin, uint32_t blockLength) { + return RequestSlot::nullSlot; + } + + virtual void removeOutstandingRequest(const RequestSlot& slot) {} + + virtual void addOutstandingRequest(const RequestSlot& slot) {} +}; + +typedef SharedHandle MockBtMessageDispatcherHandle; + +#endif // _D_MOCK_BT_MESSAGE_DISPATCHER_H_ diff --git a/test/MockBtMessageFactory.h b/test/MockBtMessageFactory.h new file mode 100644 index 00000000..69df2ff1 --- /dev/null +++ b/test/MockBtMessageFactory.h @@ -0,0 +1,91 @@ +#ifndef _D_MOCK_BT_MESSAGE_FACTORY_H_ +#define _D_MOCK_BT_MESSAGE_FACTORY_H_ + +#include "BtMessageFactory.h" + +class MockBtMessageFactory : public BtMessageFactory { +public: + MockBtMessageFactory() {} + + virtual ~MockBtMessageFactory() {} + + virtual BtMessageHandle + createBtMessage(const unsigned char* msg, uint32_t msgLength) { + return BtMessageHandle(0); + }; + + virtual BtMessageHandle + createHandshakeMessage(const unsigned char* msg, uint32_t msgLength) { + return BtMessageHandle(0); + } + + virtual BtMessageHandle + createHandshakeMessage(const unsigned char* infoHash, + const unsigned char* peerId) { + return BtMessageHandle(0); + } + + virtual BtMessageHandle + createRequestMessage(const PieceHandle& piece, uint32_t blockIndex) { + return BtMessageHandle(0); + } + + virtual BtMessageHandle + createCancelMessage(uint32_t index, uint32_t begin, uint32_t length) { + return BtMessageHandle(0); + } + + virtual BtMessageHandle + createPieceMessage(uint32_t index, uint32_t begin, uint32_t length) { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createHaveMessage(uint32_t index) { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createChokeMessage() { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createUnchokeMessage() { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createInterestedMessage() { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createNotInterestedMessage() { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createBitfieldMessage() { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createKeepAliveMessage() { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createHaveAllMessage() { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createHaveNoneMessage() { + return BtMessageHandle(0); + } + + virtual BtMessageHandle + createRejectMessage(uint32_t index, uint32_t begin, uint32_t length) { + return BtMessageHandle(0); + } + + virtual BtMessageHandle createAllowedFastMessage(uint32_t index) { + return BtMessageHandle(0); + } +}; + +typedef SharedHandle MockBtMessageFactoryHandle; + +#endif // _D_MOCK_BT_MESSAGE_FACTORY_H_ diff --git a/test/MockPeerStorage.h b/test/MockPeerStorage.h index 90796529..7c858741 100644 --- a/test/MockPeerStorage.h +++ b/test/MockPeerStorage.h @@ -46,4 +46,6 @@ public: } }; +typedef SharedHandle MockPeerStorageHandle; + #endif // _D_MOCK_PEER_STORAGE_H_ diff --git a/test/MockPieceStorage.h b/test/MockPieceStorage.h index 2b1be23c..7c8f341d 100644 --- a/test/MockPieceStorage.h +++ b/test/MockPieceStorage.h @@ -23,21 +23,21 @@ public: return false; } - virtual Piece getMissingPiece(const PeerHandle& peer) { - return Piece(); + virtual PieceHandle getMissingPiece(const PeerHandle& peer) { + return new Piece(); } - virtual Piece getMissingFastPiece(const PeerHandle& peer) { - return Piece(); + virtual PieceHandle getMissingFastPiece(const PeerHandle& peer) { + return new Piece(); } - virtual void completePiece(const Piece& piece) {} + virtual PieceHandle getPiece(int index) { + return new Piece(); + } - virtual void cancelPiece(const Piece& piece) {} + virtual void completePiece(const PieceHandle& piece) {} - virtual void updatePiece(const Piece& piece) {} - - virtual void syncPiece(Piece& piece) {} + virtual void cancelPiece(const PieceHandle& piece) {} virtual bool hasPiece(int index) { return false; @@ -148,4 +148,6 @@ public: virtual void removeAdvertisedPiece(int elapsed) {} }; +typedef SharedHandle MockPieceStorageHandle; + #endif // _D_MOCK_PIECE_STORAGE_H_ diff --git a/test/PeerTest.cc b/test/PeerTest.cc new file mode 100644 index 00000000..6904a1b5 --- /dev/null +++ b/test/PeerTest.cc @@ -0,0 +1,45 @@ +#include "Peer.h" +#include + +using namespace std; + +class PeerTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(PeerTest); + CPPUNIT_TEST(testPeerAllowedIndexSet); + CPPUNIT_TEST(testAmAllowedIndexSet); + CPPUNIT_TEST(testGetId); + CPPUNIT_TEST_SUITE_END(); +private: + PeerHandle peer; +public: + PeerTest():peer(0) {} + + void setUp() { + peer = new Peer("localhost", 6969, 16*1024, 256*1024*1024); + } + + void testPeerAllowedIndexSet(); + void testAmAllowedIndexSet(); + void testGetId(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(PeerTest); + +void PeerTest::testPeerAllowedIndexSet() { + CPPUNIT_ASSERT(!peer->isInPeerAllowedIndexSet(0)); + peer->addPeerAllowedIndex(0); + CPPUNIT_ASSERT(peer->isInPeerAllowedIndexSet(0)); +} + +void PeerTest::testAmAllowedIndexSet() { + CPPUNIT_ASSERT(!peer->isInAmAllowedIndexSet(0)); + peer->addAmAllowedIndex(0); + CPPUNIT_ASSERT(peer->isInAmAllowedIndexSet(0)); +} + +void PeerTest::testGetId() { + CPPUNIT_ASSERT_EQUAL(string("f05897fc14a41cb3400e283e189158656d7184da"), + peer->getId()); +} diff --git a/test/SegmentManTest.cc b/test/SegmentManTest.cc index a1139562..f4e9ecad 100644 --- a/test/SegmentManTest.cc +++ b/test/SegmentManTest.cc @@ -22,6 +22,7 @@ public: void testSaveAndLoad(); void testNullBitfield(); void testCancelSegmentOnNullBitfield(); + }; @@ -75,7 +76,6 @@ void SegmentManTest::testSaveAndLoad() { CPPUNIT_ASSERT_EQUAL(seg3, seg3Load); CPPUNIT_ASSERT_EQUAL(segmentMan.getDownloadLength(), segmentManLoad.getDownloadLength()); - } catch(Exception* e) { cerr << e->getMsg() << endl; delete e; @@ -111,3 +111,4 @@ void SegmentManTest::testCancelSegmentOnNullBitfield() { segmentMan.cancelSegment(1); CPPUNIT_ASSERT(segmentMan.getSegment(segment, 1)); } +