diff --git a/ChangeLog b/ChangeLog index 3258f88c..21b5a5c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,62 @@ +2007-12-22 Tatsuhiro Tsujikawa + + Added uTorrent compatible Peer Exchange. + * src/BencodeVisitor.{h, cc} + * test/BencodeVisitorTest.cc + * src/BtConstants.h + * src/BtContext.h: Added 'private' flag. + * src/BtExtendedMessage.{h, cc} + * test/BtExtendedMessageTest.cc + * src/BtHandshakeMessage.{h, cc}: Set extended messaging bit in + reserved field. + * test/BtHandshakeMessageTest.cc + * src/BtMessageFactory.h + * src/BtRegistry.h + * src/BtRuntime.h: This class holds default extension message IDs for + aria2. By default, aria2 uses ID 8 for ut_pex. + * src/DefaultBtContext.cc + * src/DefaultBtInteractive.{h, cc}: This class holds _utPexEnabled. + When it is true, aria2 enables ut_pex. This value is set by + PeerInteractionCommand. + * src/DefaultBtMessageFactory.{h, cc} + * test/DefaultBtMessageFactoryTest.cc + * src/DefaultBtMessageReceiver.cc: Moved the code of fast extension + handling to DefaultBtInteractive class. + * src/DefaultExtensionMessageFactory.{h, cc} + * test/DefaultExtensionMessageFactoryTest.cc + * src/DefaultPeerStorage.cc: Returns false if a peer is already in + the container(peers and incomingPeers. The equality is determined by + Peer::id). + * test/DefaultPeerStorageTest.cc + * src/ExtensionMessage.h + * test/MockExtensionMessage.h + * src/ExtensionMessageFactory.h + * test/MockExtensionMessageFactory.h + * src/HandshakeExtensionMessage.{h, cc} + * test/HandshakeExtensionMessageTest.cc + * src/MetaEntry.h + * src/Peer.{h, cc} + * src/PeerInteractionCommand.cc + * src/PeerReceiveHandshakeCommand.cc: Evaluate the return value of + addIncomingPeer. + * src/PeerMessageUtil.{h, cc} + * src/PeerObject.h + * src/UTPexExtensionMessage.{h, cc} + * test/UTPexExtensionMessageTest.cc + * src/message.h + * src/prefs.h + + Fixed the bug that returns incomplete data when it contains null + character. A convenient constructor was also added. + * src/Data.{h, cc} + + Rewritten. + * src/CompactPeerListProcessor.cc + + Fixed typos. + * src/message.h + * src/MetaFileUtil.cc + 2007-12-16 Tatsuhiro Tsujikawa Added "Status Legend" label to the explanation text of 'stat' in diff --git a/src/BencodeVisitor.cc b/src/BencodeVisitor.cc new file mode 100644 index 00000000..32a11308 --- /dev/null +++ b/src/BencodeVisitor.cc @@ -0,0 +1,84 @@ +/* */ +#include "BencodeVisitor.h" +#include "Data.h" +#include "List.h" +#include "Dictionary.h" +#include "Util.h" + +BencodeVisitor::BencodeVisitor() {} + +BencodeVisitor::~BencodeVisitor() {} + +void BencodeVisitor::visit(const Data* d) +{ + if(d->isNumber()) { + _bencodedData += "i"+d->toString()+"e"; + } else { + _bencodedData += Util::itos(d->getLen())+":"+d->toString(); + } +} + +void BencodeVisitor::visit(const List* l) +{ + _bencodedData += "l"; + for_each(l->getList().begin(), l->getList().end(), + bind2nd(mem_fun(&MetaEntry::accept), this)); + _bencodedData += "e"; +} + +void BencodeVisitor::visit(const Dictionary* d) +{ + _bencodedData += "d"; + + for(Order::const_iterator itr = d->getOrder().begin(); itr != d->getOrder().end(); ++itr) { + _bencodedData += Util::itos((int32_t)(*itr).size()); + _bencodedData += ":"; + _bencodedData += *itr; + d->get(*itr)->accept(this); + } + _bencodedData += "e"; +} + +void BencodeVisitor::visit(const MetaEntry* e) +{ + if(dynamic_cast(e) != 0) { + visit((const Data*)e); + } else if(dynamic_cast(e) != 0) { + visit((const List*)e); + } else if(dynamic_cast(e) != 0) { + visit((const Dictionary*)e); + } +} diff --git a/src/BencodeVisitor.h b/src/BencodeVisitor.h new file mode 100644 index 00000000..f473a78e --- /dev/null +++ b/src/BencodeVisitor.h @@ -0,0 +1,64 @@ +/* */ +#ifndef _D_BENCODE_VISITOR_H_ +#define _D_BENCODE_VISITOR_H_ + +#include "MetaEntryVisitor.h" + +class Data; +class Dictionary; +class List; +class MetaEntry; + +class BencodeVisitor : public MetaEntryVisitor { +private: + string _bencodedData; +public: + BencodeVisitor(); + ~BencodeVisitor(); + + void visit(const Data* d); + void visit(const Dictionary* d); + void visit(const List* l); + + virtual void visit(const MetaEntry* e); + + const string& getBencodedData() const + { + return _bencodedData; + } +}; + +#endif // _D_BENCODE_VISITOR_H_ diff --git a/src/BtConstants.h b/src/BtConstants.h new file mode 100644 index 00000000..d233a53a --- /dev/null +++ b/src/BtConstants.h @@ -0,0 +1,43 @@ +/* */ +#ifndef _D_BT_CONSTANTS_ +#define _D_BT_CONSTANTS_ + +#include "common.h" +#include + +typedef map Extensions; + +#endif // _D_BT_CONSTANTS_ diff --git a/src/BtContext.h b/src/BtContext.h index 8adfcc0d..6cec275b 100644 --- a/src/BtContext.h +++ b/src/BtContext.h @@ -48,7 +48,11 @@ typedef deque AnnounceTiers; class RequestGroup; class BtContext:public DownloadContext { +protected: + bool _private; public: + BtContext():_private(false) {} + virtual ~BtContext() {} virtual const unsigned char* getInfoHash() const = 0; @@ -66,6 +70,11 @@ public: */ virtual const unsigned char* getPeerId() = 0; + bool isPrivate() const + { + return _private; + } + virtual Integers computeFastSet(const string& ipaddr, int32_t fastSetSize) = 0; virtual RequestGroup* getOwnerRequestGroup() = 0; diff --git a/src/BtExtendedMessage.cc b/src/BtExtendedMessage.cc new file mode 100644 index 00000000..257e45a2 --- /dev/null +++ b/src/BtExtendedMessage.cc @@ -0,0 +1,115 @@ +/* */ +#include "BtExtendedMessage.h" +#include "BtRegistry.h" +#include "ExtensionMessage.h" +#include "PeerMessageUtil.h" +#include "DlAbortEx.h" +#include "message.h" +#include "Util.h" + +BtExtendedMessage::BtExtendedMessage(const ExtensionMessageHandle& extensionMessage):_extensionMessage(extensionMessage), _msg(0), _msgLength(0) +{} + +BtExtendedMessage::~BtExtendedMessage() +{ + delete [] _msg; +} + +const unsigned char* BtExtendedMessage::getMessage() { + if(!_msg) { + /** + * len --- 2+extpayload.length, 4bytes + * id --- 20, 1byte + * extmsgid --- extmsgid, 1byte + * extpayload --- extpayload, nbytes + * total: 6+extpayload.length bytes + */ + string payload = _extensionMessage->getBencodedData(); + _msgLength = 6+payload.size(); + _msg = new unsigned char[_msgLength]; + PeerMessageUtil::createPeerMessageString(_msg, _msgLength, 2+payload.size(), ID); + *(_msg+5) = _extensionMessage->getExtensionMessageID(); + memcpy(_msg+6, payload.c_str(), payload.size()); + } + return _msg; +} + +int32_t BtExtendedMessage::getMessageLength() { + getMessage(); + return _msgLength; +} + +bool BtExtendedMessage::sendPredicate() const +{ + return peer->isExtendedMessagingEnabled(); +} + +string BtExtendedMessage::toString() const { + return "extended "+_extensionMessage->toString(); +} + +BtExtendedMessageHandle +BtExtendedMessage::create(const BtContextHandle& btContext, + const PeerHandle& peer, + const char* data, size_t dataLength) +{ + if(dataLength < 2) { + throw new DlAbortEx(MSG_TOO_SMALL_PAYLOAD_SIZE, "extended", dataLength); + } + int8_t id = PeerMessageUtil::getId((const unsigned char*)data); + if(id != ID) { + throw new DlAbortEx(EX_INVALID_BT_MESSAGE_ID, id, "extended", ID); + } + ExtensionMessageFactoryHandle factory = EXTENSION_MESSAGE_FACTORY(btContext, + peer); + assert(!factory.isNull()); + ExtensionMessageHandle extmsg = factory->createMessage(data+1, + dataLength-1); + BtExtendedMessageHandle message = new BtExtendedMessage(extmsg); + return message; +} + +void BtExtendedMessage::doReceivedAction() +{ + if(!_extensionMessage.isNull()) { + _extensionMessage->doReceivedAction(); + } +} + +ExtensionMessageHandle BtExtendedMessage::getExtensionMessage() const +{ + return _extensionMessage; +} diff --git a/src/BtExtendedMessage.h b/src/BtExtendedMessage.h new file mode 100644 index 00000000..df7e49a0 --- /dev/null +++ b/src/BtExtendedMessage.h @@ -0,0 +1,79 @@ +/* */ +#ifndef _D_BT_EXTENDED_MESSAGE_H_ +#define _D_BT_EXTENDED_MESSAGE_H_ +#include "SimpleBtMessage.h" + +class BtExtendedMessage; +typedef SharedHandle BtExtendedMessageHandle; +class ExtensionMessage; +typedef SharedHandle ExtensionMessageHandle; + +class BtExtendedMessage:public SimpleBtMessage +{ +private: + ExtensionMessageHandle _extensionMessage; + + unsigned char* _msg; + + size_t _msgLength; +public: + BtExtendedMessage(const ExtensionMessageHandle& extensionMessage = 0); + + virtual ~BtExtendedMessage(); + + static const uint8_t ID = 20; + + static BtExtendedMessageHandle create(const BtContextHandle& btContext, + const PeerHandle& peer, + const char* data, + size_t dataLength); + + virtual int8_t getId() { return ID; } + + virtual void doReceivedAction(); + + virtual const unsigned char* getMessage(); + + virtual int32_t getMessageLength(); + + virtual bool sendPredicate() const; + + virtual string toString() const; + + ExtensionMessageHandle getExtensionMessage() const; +}; + +#endif // _D_BT_EXTENDED_MESSAGE_H_ diff --git a/src/BtHandshakeMessage.cc b/src/BtHandshakeMessage.cc index 7df6f327..33ad8915 100644 --- a/src/BtHandshakeMessage.cc +++ b/src/BtHandshakeMessage.cc @@ -61,6 +61,8 @@ void BtHandshakeMessage::init() { memset(this->reserved, 0, RESERVED_LENGTH); // fast extension this->reserved[7] |= 0x04; + // extended messaging + this->reserved[5] |= 0x10; } BtHandshakeMessageHandle BtHandshakeMessage::create(const unsigned char* data, int32_t dataLength) { @@ -98,3 +100,8 @@ string BtHandshakeMessage::toString() const { bool BtHandshakeMessage::isFastExtensionSupported() const { return reserved[7]&0x04; } + +bool BtHandshakeMessage::isExtendedMessagingEnabled() const +{ + return reserved[5]&0x10; +} diff --git a/src/BtHandshakeMessage.h b/src/BtHandshakeMessage.h index c17f3094..9ad92f08 100644 --- a/src/BtHandshakeMessage.h +++ b/src/BtHandshakeMessage.h @@ -87,6 +87,8 @@ public: bool isFastExtensionSupported() const; + bool isExtendedMessagingEnabled() const; + int8_t getPstrlen() const { return pstrlen; } diff --git a/src/BtMessageFactory.h b/src/BtMessageFactory.h index a7c55978..11ea7926 100644 --- a/src/BtMessageFactory.h +++ b/src/BtMessageFactory.h @@ -39,6 +39,9 @@ #include "BtMessage.h" #include "Piece.h" +class ExtensionMessage; +typedef SharedHandle ExensionMessageHandle; + class BtMessageFactory { public: virtual ~BtMessageFactory() {} @@ -84,6 +87,8 @@ public: createRejectMessage(int32_t index, int32_t begin, int32_t length) = 0; virtual BtMessageHandle createAllowedFastMessage(int32_t index) = 0; + + virtual BtMessageHandle createBtExtendedMessage(const ExensionMessageHandle& msg) = 0; }; typedef SharedHandle BtMessageFactoryHandle; diff --git a/src/BtRegistry.h b/src/BtRegistry.h index d0722f05..895001f1 100644 --- a/src/BtRegistry.h +++ b/src/BtRegistry.h @@ -146,4 +146,7 @@ PEER_OBJECT(btContext, peer)->btRequestFactory #define PEER_CONNECTION(btContext, peer) \ PEER_OBJECT(btContext, peer)->peerConnection +#define EXTENSION_MESSAGE_FACTORY(btContext, peer) \ +PEER_OBJECT(btContext, peer)->extensionMessageFactory + #endif // _D_BT_REGISTRY_H_ diff --git a/src/BtRuntime.h b/src/BtRuntime.h index 55644bc6..dceebf4f 100644 --- a/src/BtRuntime.h +++ b/src/BtRuntime.h @@ -36,7 +36,7 @@ #define _D_BT_RUNTIME_H_ #include "common.h" -#include "SharedHandle.h" +#include "BtConstants.h" #define MIN_PEERS 40 @@ -47,6 +47,8 @@ private: bool halt; int32_t connections; bool _ready; + + Extensions _extensions; public: BtRuntime(): uploadLengthAtStartup(0), @@ -54,7 +56,9 @@ public: halt(false), connections(0), _ready(false) - {} + { + _extensions["ut_pex"] = 8; + } ~BtRuntime() {} int64_t getUploadLengthAtStartup() const { @@ -90,6 +94,33 @@ public: bool ready() { return _ready; } void setReady(bool go) { _ready = go; } + + const Extensions& getExtensions() const + { + return _extensions; + } + + uint8_t getExtensionMessageID(const string& name) + { + Extensions::const_iterator itr = _extensions.find(name); + if(itr == _extensions.end()) { + return 0; + } else { + return (*itr).second; + } + } + + string getExtensionName(uint8_t id) + { + for(Extensions::const_iterator itr = _extensions.begin(); + itr != _extensions.end(); ++itr) { + const Extensions::value_type& p = *itr; + if(p.second == id) { + return p.first; + } + } + return ""; + } }; typedef SharedHandle BtRuntimeHandle; diff --git a/src/CompactPeerListProcessor.cc b/src/CompactPeerListProcessor.cc index d18e2784..b98b5da8 100644 --- a/src/CompactPeerListProcessor.cc +++ b/src/CompactPeerListProcessor.cc @@ -43,19 +43,13 @@ Peers CompactPeerListProcessor::extractPeer(const MetaEntry* peersEntry) { Peers peers; const Data* peersData = (const Data*)peersEntry; - if(peersData->getLen() > 0) { + if(peersData->getLen()%6 == 0) { for(int32_t i = 0; i < peersData->getLen(); i += 6) { - uint32_t ipaddr1 = (unsigned char)*(peersData->getData()+i); - uint32_t ipaddr2 = (unsigned char)*(peersData->getData()+i+1); - uint32_t ipaddr3 = (unsigned char)*(peersData->getData()+i+2); - uint32_t ipaddr4 = (unsigned char)*(peersData->getData()+i+3); - int32_t port = ntohs(*(uint16_t*)(peersData->getData()+i+4)); - char ipaddr[16]; - - snprintf(ipaddr, sizeof(ipaddr), "%d.%d.%d.%d", - ipaddr1, ipaddr2, ipaddr3, ipaddr4); - PeerHandle peer = new Peer(ipaddr, port, pieceLength, totalLength); - + struct in_addr in; + in.s_addr = *(uint32_t*)(peersData->getData()+i); + string ipaddr = inet_ntoa(in); + uint16_t port = ntohs(*(uint16_t*)(peersData->getData()+i+4)); + PeerHandle peer = new Peer(ipaddr, port, pieceLength, totalLength); peers.push_back(peer); } } diff --git a/src/Data.cc b/src/Data.cc index e57873aa..0bfc91bd 100644 --- a/src/Data.cc +++ b/src/Data.cc @@ -46,21 +46,24 @@ Data::Data(const char* data, int32_t len, bool number):number(number) { } } +Data::Data(const string& data, bool number):number(number) +{ + if(data.empty()) { + this->data = 0; + this->len = 0; + } else { + this->data = new char[data.size()]; + memcpy(this->data, data.c_str(), data.size()); + this->len = data.size(); + } +} + Data::~Data() { delete [] data; } string Data::toString() const { - if(len == 0) { - return ""; - } else { - char* temp = new char[len+1]; - memcpy(temp, data, len); - temp[len] = '\0'; - string str(temp); - delete [] temp; - return str; - } + return string(&data[0], &data[len]); } const char* Data::getData() const { diff --git a/src/Data.h b/src/Data.h index 46905933..03499ea3 100644 --- a/src/Data.h +++ b/src/Data.h @@ -51,6 +51,9 @@ public: * memory of data. */ Data(const char* data, int32_t len, bool number = false); + + Data(const string& data, bool number = false); + ~Data(); string toString() const; diff --git a/src/DefaultBtContext.cc b/src/DefaultBtContext.cc index b4e43df1..7cb5cabb 100644 --- a/src/DefaultBtContext.cc +++ b/src/DefaultBtContext.cc @@ -84,6 +84,7 @@ void DefaultBtContext::clear() { numPieces = 0; name = ""; announceTiers.clear(); + _private = false; } void DefaultBtContext::extractPieceHash(const unsigned char* hashData, @@ -240,6 +241,12 @@ void DefaultBtContext::processMetaInfo(const MetaEntry* rootEntry, const string& extractPieceHash((unsigned char*)pieceHashData->getData(), pieceHashData->getLen(), PIECE_HASH_LENGTH); + const Data* privateFlag = dynamic_cast(infoDic->get("private")); + if(privateFlag) { + if(privateFlag->toString() == "1") { + _private = true; + } + } // retrieve uri-list. // This implemantation obeys HTTP-Seeding specification: // see http://www.getright.com/seedtorrent.html diff --git a/src/DefaultBtInteractive.cc b/src/DefaultBtInteractive.cc index 33ad725d..ee038fba 100644 --- a/src/DefaultBtInteractive.cc +++ b/src/DefaultBtInteractive.cc @@ -43,10 +43,16 @@ #include "BtRequestMessage.h" #include "BtPieceMessage.h" #include "DlAbortEx.h" +#include "BtExtendedMessage.h" +#include "HandshakeExtensionMessage.h" +#include "UTPexExtensionMessage.h" +#include "DefaultExtensionMessageFactory.h" +#include "BtRegistry.h" void DefaultBtInteractive::initiateHandshake() { - BtMessageHandle message = messageFactory->createHandshakeMessage(btContext->getInfoHash(), - btContext->getPeerId()); + BtHandshakeMessageHandle message = + messageFactory->createHandshakeMessage(btContext->getInfoHash(), + btContext->getPeerId()); dispatcher->addMessageToQueue(message); dispatcher->sendMessages(); } @@ -58,6 +64,18 @@ BtMessageHandle DefaultBtInteractive::receiveHandshake(bool quickReply) { return 0; } peer->setPeerId(message->getPeerId()); + + if(message->isFastExtensionSupported()) { + peer->setFastExtensionEnabled(true); + logger->info(MSG_FAST_EXTENSION_ENABLED, cuid); + } + if(message->isExtendedMessagingEnabled()) { + peer->setExtendedMessagingEnabled(true); + PEER_OBJECT(btContext, peer)->extensionMessageFactory = + new DefaultExtensionMessageFactory(btContext, peer); + logger->info(MSG_EXTENDED_MESSAGING_ENABLED, cuid); + } + logger->info(MSG_RECEIVE_PEER_MESSAGE, cuid, peer->ipaddr.c_str(), peer->port, message->toString().c_str()); @@ -73,11 +91,28 @@ void DefaultBtInteractive::doPostHandshakeProcessing() { haveCheckPoint.reset(); keepAliveCheckPoint.reset(); floodingCheckPoint.reset(); + _pexCheckPoint.setTimeInSec(0); + if(peer->isExtendedMessagingEnabled()) { + addHandshakeExtendedMessageToQueue(); + } addBitfieldMessageToQueue(); addAllowedFastMessageToQueue(); sendPendingMessage(); } +void DefaultBtInteractive::addHandshakeExtendedMessageToQueue() +{ + HandshakeExtensionMessageHandle m = new HandshakeExtensionMessage(); + m->setClientVersion("aria2"); + m->setTCPPort(btRuntime->getListenPort()); + m->setExtensions(btRuntime->getExtensions()); + + BtExtendedMessageHandle msg = + messageFactory->createBtExtendedMessage(m); + + dispatcher->addMessageToQueue(msg); +} + void DefaultBtInteractive::addBitfieldMessageToQueue() { if(peer->isFastExtensionEnabled()) { if(pieceStorage->allDownloadFinished()) { @@ -283,6 +318,45 @@ void DefaultBtInteractive::checkActiveInteraction() } } +void DefaultBtInteractive::addPeerExchangeMessage() +{ + time_t interval = 60; + if(_pexCheckPoint.elapsed(interval)) { + UTPexExtensionMessageHandle m = + new UTPexExtensionMessage(peer->getExtensionMessageID("ut_pex")); + const Peers& peers = peerStorage->getPeers(); + { + size_t max = 30; + for(Peers::const_iterator i = peers.begin(); + i != peers.end() && max; ++i) { + const PeerHandle& cpeer = *i; + if(peer->ipaddr != cpeer->ipaddr && + !cpeer->getFirstContactTime().elapsed(interval) && + Util::isNumbersAndDotsNotation(cpeer->ipaddr)) { + m->addFreshPeer(cpeer); + --max; + } + } + } + { + size_t max = 10; + for(Peers::const_reverse_iterator i = peers.rbegin(); + i != peers.rend() && max; ++i) { + const PeerHandle& cpeer = *i; + if(peer->ipaddr != cpeer->ipaddr && + !cpeer->getBadConditionStartTime().elapsed(interval) && + Util::isNumbersAndDotsNotation(cpeer->ipaddr)) { + m->addDroppedPeer(cpeer); + --max; + } + } + } + BtExtendedMessageHandle msg = messageFactory->createBtExtendedMessage(m); + dispatcher->addMessageToQueue(msg); + _pexCheckPoint.reset(); + } +} + void DefaultBtInteractive::doInteractionProcessing() { checkActiveInteraction(); @@ -304,5 +378,10 @@ void DefaultBtInteractive::doInteractionProcessing() { if(!pieceStorage->downloadFinished()) { addRequests(); } + + if(peer->getExtensionMessageID("ut_pex") && _utPexEnabled) { + addPeerExchangeMessage(); + } + sendPendingMessage(); } diff --git a/src/DefaultBtInteractive.h b/src/DefaultBtInteractive.h index fa546f70..c0c70077 100644 --- a/src/DefaultBtInteractive.h +++ b/src/DefaultBtInteractive.h @@ -102,13 +102,16 @@ private: Time floodingCheckPoint; FloodingStat floodingStat; Time inactiveCheckPoint; + Time _pexCheckPoint; int32_t keepAliveInterval; int32_t maxDownloadSpeedLimit; + bool _utPexEnabled; static const int32_t FLOODING_CHECK_INTERVAL = 5; void addBitfieldMessageToQueue(); void addAllowedFastMessageToQueue(); + void addHandshakeExtendedMessageToQueue(); void decideChoking(); void checkHave(); void sendKeepAlive(); @@ -117,6 +120,7 @@ private: void addRequests(); void detectMessageFlooding(); void checkActiveInteraction(); + void addPeerExchangeMessage(); public: DefaultBtInteractive():peer(0), @@ -131,7 +135,8 @@ public: logger(LogFactory::getInstance()), allowedFastSetSize(10), keepAliveInterval(120), - maxDownloadSpeedLimit(0) + maxDownloadSpeedLimit(0), + _utPexEnabled(false) {} virtual ~DefaultBtInteractive() {} @@ -202,6 +207,11 @@ public: void setBtMessageFactory(const BtMessageFactoryWeakHandle& factory) { this->messageFactory = factory; } + + void setUTPexEnabled(bool f) + { + _utPexEnabled = f; + } }; typedef SharedHandle DefaultBtInteractiveHandle; diff --git a/src/DefaultBtMessageFactory.cc b/src/DefaultBtMessageFactory.cc index 52c546fd..c10d47d9 100644 --- a/src/DefaultBtMessageFactory.cc +++ b/src/DefaultBtMessageFactory.cc @@ -61,6 +61,8 @@ #include "BtAllowedFastMessageValidator.h" #include "BtHandshakeMessage.h" #include "BtHandshakeMessageValidator.h" +#include "BtExtendedMessage.h" +#include "ExtensionMessage.h" BtMessageHandle DefaultBtMessageFactory::createBtMessage(const unsigned char* data, int32_t dataLength) @@ -161,6 +163,14 @@ DefaultBtMessageFactory::createBtMessage(const unsigned char* data, int32_t data msg = temp; break; } + case BtExtendedMessage::ID: { + if(peer->isExtendedMessagingEnabled()) { + msg = BtExtendedMessage::create(btContext, peer, (const char*)data, dataLength); + } else { + throw new DlAbortEx("Received extended message from peer during a session with extended messaging disabled."); + } + break; + } default: throw new DlAbortEx("Invalid message ID. id=%d", id); } @@ -349,3 +359,11 @@ DefaultBtMessageFactory::createAllowedFastMessage(int32_t index) setCommonProperty(msg); return msg; } + +BtMessageHandle +DefaultBtMessageFactory::createBtExtendedMessage(const ExensionMessageHandle& msg) +{ + BtExtendedMessageHandle m = new BtExtendedMessage(msg); + setCommonProperty(m); + return m; +} diff --git a/src/DefaultBtMessageFactory.h b/src/DefaultBtMessageFactory.h index bd2e07f4..d87da9ec 100644 --- a/src/DefaultBtMessageFactory.h +++ b/src/DefaultBtMessageFactory.h @@ -110,6 +110,8 @@ public: virtual BtMessageHandle createAllowedFastMessage(int32_t index); + virtual BtMessageHandle createBtExtendedMessage(const ExensionMessageHandle& msg); + void setPeer(const PeerHandle& peer) { this->peer = peer; } diff --git a/src/DefaultBtMessageReceiver.cc b/src/DefaultBtMessageReceiver.cc index 6899e155..7bee71b4 100644 --- a/src/DefaultBtMessageReceiver.cc +++ b/src/DefaultBtMessageReceiver.cc @@ -53,14 +53,7 @@ BtMessageHandle DefaultBtMessageReceiver::receiveHandshake(bool quickReply) { } BtHandshakeMessageHandle msg = messageFactory->createHandshakeMessage(data, dataLength); Errors errors; - if(msg->validate(errors)) { - if(msg->isFastExtensionSupported()) { - peer->setFastExtensionEnabled(true); - logger->info(MSG_FAST_EXTENSION_ENABLED, cuid); - } - } else { - // TODO throw exception here based on errors - } + msg->validate(errors); return msg; } diff --git a/src/DefaultExtensionMessageFactory.cc b/src/DefaultExtensionMessageFactory.cc new file mode 100644 index 00000000..980cce89 --- /dev/null +++ b/src/DefaultExtensionMessageFactory.cc @@ -0,0 +1,93 @@ +/* */ +#include "DefaultExtensionMessageFactory.h" +#include "BtContext.h" +#include "Peer.h" +#include "DlAbortEx.h" +#include "HandshakeExtensionMessage.h" +#include "UTPexExtensionMessage.h" +#include "LogFactory.h" +#include "BtRegistry.h" + +DefaultExtensionMessageFactory::DefaultExtensionMessageFactory(): + _btContext(0), + _peer(0), + _logger(LogFactory::getInstance()) {} + +DefaultExtensionMessageFactory::DefaultExtensionMessageFactory(const BtContextHandle& btContext, + const PeerHandle& peer): + _btContext(btContext), + _peer(peer), + _logger(LogFactory::getInstance()) {} + +DefaultExtensionMessageFactory::~DefaultExtensionMessageFactory() {} + +ExtensionMessageHandle +DefaultExtensionMessageFactory::createMessage(const char* data, size_t length) +{ + uint8_t extensionMessageID = *data; + if(extensionMessageID == 0) { + // handshake + HandshakeExtensionMessageHandle m = HandshakeExtensionMessage::create(data, length); + m->setBtContext(_btContext); + m->setPeer(_peer); + return m; + } else { + string extensionName = BT_RUNTIME(_btContext)->getExtensionName(extensionMessageID); + if(extensionName.empty()) { + throw new DlAbortEx("No extension registered for extended message ID %u", + extensionMessageID); + } + if(extensionName == "ut_pex") { + // uTorrent compatible Peer-Exchange + UTPexExtensionMessageHandle m = + UTPexExtensionMessage::create(_btContext, data, length); + m->setBtContext(_btContext); + return m; + } else { + throw new DlAbortEx("Unsupported extension message received. extensionMessageID=%u, extensionName=%s", extensionMessageID, extensionName.c_str()); + } + } +} + +void DefaultExtensionMessageFactory::setBtContext(const BtContextHandle& btContext) +{ + _btContext = btContext; +} + +void DefaultExtensionMessageFactory::setPeer(const PeerHandle& peer) +{ + _peer = peer; +} diff --git a/src/DefaultExtensionMessageFactory.h b/src/DefaultExtensionMessageFactory.h new file mode 100644 index 00000000..71c780a5 --- /dev/null +++ b/src/DefaultExtensionMessageFactory.h @@ -0,0 +1,70 @@ +/* */ +#ifndef _D_DEFAULT_EXTENSION_MESSAGE_FACTORY_H_ +#define _D_DEFAULT_EXTENSION_MESSAGE_FACTORY_H_ + +#include "ExtensionMessageFactory.h" + +class BtContext; +typedef SharedHandle BtContextHandle; +class Peer; +typedef SharedHandle PeerHandle; +class Logger; + +class DefaultExtensionMessageFactory:public ExtensionMessageFactory { +private: + BtContextHandle _btContext; + + PeerHandle _peer; + + const Logger* _logger; + +public: + DefaultExtensionMessageFactory(); + + DefaultExtensionMessageFactory(const BtContextHandle& btContext, + const PeerHandle& peer); + + virtual ~DefaultExtensionMessageFactory(); + + virtual ExtensionMessageHandle createMessage(const char* data, size_t length); + + void setBtContext(const BtContextHandle& btContext); + + void setPeer(const PeerHandle& peer); +}; + +typedef SharedHandle DefaultExtensionMessageFactoryHandle; +#endif // _D_DEFAULT_EXTENSION_MESSAGE_FACTORY_H_ diff --git a/src/DefaultPeerStorage.cc b/src/DefaultPeerStorage.cc index b0782b11..0f370b14 100644 --- a/src/DefaultPeerStorage.cc +++ b/src/DefaultPeerStorage.cc @@ -52,29 +52,34 @@ DefaultPeerStorage::DefaultPeerStorage(BtContextHandle btContext, DefaultPeerStorage::~DefaultPeerStorage() {} +bool DefaultPeerStorage::isPeerAlreadyAdded(const PeerHandle& peer) +{ + return find(peers.begin(), peers.end(), peer) != peers.end() || + find(incomingPeers.begin(), incomingPeers.end(), peer) != incomingPeers.end(); +} + bool DefaultPeerStorage::addPeer(const PeerHandle& peer) { - Peers::iterator itr = find(peers.begin(), peers.end(), peer); - if(itr == peers.end()) { + if(isPeerAlreadyAdded(peer)) { + logger->debug("Adding %s:%u is rejected because it is already in PeerStorage.", peer->ipaddr.c_str(), peer->port); + return false; + } else { if(peers.size() >= (size_t)maxPeerListSize) { deleteUnusedPeer(peers.size()-maxPeerListSize+1); } peers.push_front(peer); return true; - } else { - const PeerHandle& peer = *itr; - if(!peer->isGood() || peer->cuid != 0) { - return false; - } else { - *itr = peer; - return true; - } } } bool DefaultPeerStorage::addIncomingPeer(const PeerHandle& peer) { - incomingPeers.push_back(peer); - return true; + if(isPeerAlreadyAdded(peer)) { + logger->debug("Adding %s:%u is rejected because it is already in PeerStorage.", peer->ipaddr.c_str(), peer->port); + return false; + } else { + incomingPeers.push_back(peer); + return true; + } } void DefaultPeerStorage::addPeer(const Peers& peers) { diff --git a/src/DefaultPeerStorage.h b/src/DefaultPeerStorage.h index 3b9c0071..5e889768 100644 --- a/src/DefaultPeerStorage.h +++ b/src/DefaultPeerStorage.h @@ -55,6 +55,8 @@ private: BtRuntimeHandle btRuntime; int64_t removedPeerSessionDownloadLength; int64_t removedPeerSessionUploadLength; + + bool isPeerAlreadyAdded(const PeerHandle& peer); public: DefaultPeerStorage(BtContextHandle btContext, const Option* option); virtual ~DefaultPeerStorage(); diff --git a/src/ExtensionMessage.h b/src/ExtensionMessage.h new file mode 100644 index 00000000..cf47d97e --- /dev/null +++ b/src/ExtensionMessage.h @@ -0,0 +1,57 @@ +/* */ +#ifndef _D_EXTENSION_MESSAGE_H_ +#define _D_EXTENSION_MESSAGE_H_ + +#include "common.h" + +class ExtensionMessage { +public: + virtual ~ExtensionMessage() {} + + virtual string getBencodedData() = 0; + + virtual uint8_t getExtensionMessageID() = 0; + + virtual const string& getExtensionName() const = 0; + + virtual string toString() const = 0; + + virtual void doReceivedAction() = 0; +}; + +typedef SharedHandle ExtensionMessageHandle; + +#endif // _D_EXTENSION_MESSAGE_H_ diff --git a/src/ExtensionMessageFactory.h b/src/ExtensionMessageFactory.h new file mode 100644 index 00000000..513a0651 --- /dev/null +++ b/src/ExtensionMessageFactory.h @@ -0,0 +1,51 @@ +/* */ +#ifndef _D_EXTENSION_MESSAGE_FACTORY_H_ +#define _D_EXTENSION_MESSAGE_FACTORY_H_ + +#include "common.h" + +class ExtensionMessage; +typedef SharedHandle ExtensionMessageHandle; + +class ExtensionMessageFactory { +public: + virtual ~ExtensionMessageFactory() {} + + virtual ExtensionMessageHandle createMessage(const char* data, size_t length) = 0; +}; + +typedef SharedHandle ExtensionMessageFactoryHandle; +#endif // _D_EXTENSION_MESSAGE_FACTORY_H_ diff --git a/src/HandshakeExtensionMessage.cc b/src/HandshakeExtensionMessage.cc new file mode 100644 index 00000000..df003b5b --- /dev/null +++ b/src/HandshakeExtensionMessage.cc @@ -0,0 +1,174 @@ +/* */ +#include "HandshakeExtensionMessage.h" +#include "Peer.h" +#include "BtContext.h" +#include "Dictionary.h" +#include "Data.h" +#include "Util.h" +#include "BencodeVisitor.h" +#include "BtRegistry.h" +#include "MetaFileUtil.h" +#include "DlAbortEx.h" +#include "LogFactory.h" +#include "message.h" + +const string HandshakeExtensionMessage::EXTENSION_NAME = "handshake"; + +HandshakeExtensionMessage::HandshakeExtensionMessage():_tcpPort(0), + _btContext(0), + _peer(0), + _logger(LogFactory::getInstance()) +{} + +HandshakeExtensionMessage::~HandshakeExtensionMessage() {} + +string HandshakeExtensionMessage::getBencodedData() +{ + SharedHandle dic = new Dictionary(); + if(!_clientVersion.empty()) { + Data* v = new Data(_clientVersion); + dic->put("v", v); + } + if(_tcpPort > 0) { + string portStr = Util::itos(_tcpPort); + Data* p = new Data(portStr, true); + dic->put("p", p); + } + Dictionary* exts = new Dictionary(); + dic->put("m", exts); + for(map::const_iterator itr = _extensions.begin(); + itr != _extensions.end(); ++itr) { + const map::value_type& vt = *itr; + string idStr = Util::uitos((uint32_t)vt.second); + exts->put(vt.first, new Data(idStr, true)); + } + BencodeVisitor v; + dic->accept(&v); + return v.getBencodedData(); +} + +string HandshakeExtensionMessage::toString() const +{ + string s = getExtensionName(); + if(!_clientVersion.empty()) { + s += " client="+Util::urlencode(_clientVersion); + } + if(_tcpPort > 0) { + s += ", tcpPort="+Util::itos(_tcpPort); + } + for(map::const_iterator itr = _extensions.begin(); + itr != _extensions.end(); ++itr) { + const map::value_type& vt = *itr; + s += ", "+vt.first+"="+Util::uitos((uint32_t)vt.second); + } + return s; +} + +void HandshakeExtensionMessage::doReceivedAction() +{ + if(_tcpPort > 0) { + _peer->port = _tcpPort; + } + for(map::const_iterator itr = _extensions.begin(); + itr != _extensions.end(); ++itr) { + const map::value_type& vt = *itr; + _peer->setExtension(vt.first, vt.second); + } + if(_peer->port > 0) { + // This is needed when _peer is a connection initiator, listen port of + // _peer is now available, which is initially unknown. + // If _peer is a receiver or already its port is known, _peer has to be + // already added to PeerStorage using addPeer() and call + // PeerStorage::addPeer() here does nothing and just returns false. + PEER_STORAGE(_btContext)->addPeer(_peer); + } +} + +void HandshakeExtensionMessage::setPeer(const PeerHandle& peer) +{ + _peer = peer; +} + +void HandshakeExtensionMessage::setBtContext(const BtContextHandle& btContext) +{ + _btContext = btContext; +} + +uint8_t HandshakeExtensionMessage::getExtensionMessageID(const string& name) const +{ + map::const_iterator i = _extensions.find(name); + if(i == _extensions.end()) { + return 0; + } else { + return (*i).second; + } +} + +HandshakeExtensionMessageHandle +HandshakeExtensionMessage::create(const char* data, size_t length) +{ + if(length < 1) { + throw new DlAbortEx(MSG_TOO_SMALL_PAYLOAD_SIZE, + EXTENSION_NAME.c_str(), length); + } + HandshakeExtensionMessageHandle msg = new HandshakeExtensionMessage(); + msg->_logger->debug("Creating HandshakeExtensionMessage from %s", + Util::urlencode((const unsigned char*)data, length).c_str()); + SharedHandle root = MetaFileUtil::bdecoding(data+1, length-1); + Dictionary* d = dynamic_cast(root.get()); + if(d == 0) { + throw new DlAbortEx("Unexpected payload format for extended message handshake"); + } + const Data* p = dynamic_cast(d->get("p")); + if(p) { + msg->_tcpPort = p->toInt(); + } + const Data* v = dynamic_cast(d->get("v")); + if(v) { + msg->_clientVersion = v->toString(); + } + const Dictionary* m = dynamic_cast(d->get("m")); + if(m) { + const Order& order = m->getOrder(); + for(Order::const_iterator i = order.begin(); i != order.end(); ++i) { + const Data* e = dynamic_cast(m->get(*i)); + if(e) { + msg->_extensions[*i] = e->toInt(); + } + } + } + return msg; +} diff --git a/src/HandshakeExtensionMessage.h b/src/HandshakeExtensionMessage.h new file mode 100644 index 00000000..be929248 --- /dev/null +++ b/src/HandshakeExtensionMessage.h @@ -0,0 +1,128 @@ +/* */ +#ifndef _D_HANDSHAKE_EXTENSION_MESSAGE_H_ +#define _D_HANDSHAKE_EXTENSION_MESSAGE_H_ + +#include "ExtensionMessage.h" +#include "BtConstants.h" + +class BtContext; +typedef SharedHandle BtContextHandle; +class Peer; +typedef SharedHandle PeerHandle; +class HandshakeExtensionMessage; +typedef SharedHandle HandshakeExtensionMessageHandle; +class Logger; + +class HandshakeExtensionMessage:public ExtensionMessage { +private: + string _clientVersion; + + uint16_t _tcpPort; + + map _extensions; + + BtContextHandle _btContext; + + PeerHandle _peer; + + const Logger* _logger; + +public: + HandshakeExtensionMessage(); + + virtual ~HandshakeExtensionMessage(); + + virtual string getBencodedData(); + + virtual uint8_t getExtensionMessageID() + { + return 0; + } + + virtual const string& getExtensionName() const + { + return EXTENSION_NAME; + } + + static const string EXTENSION_NAME; + + virtual string toString() const; + + virtual void doReceivedAction(); + + void setClientVersion(const string& version) + { + _clientVersion = version; + } + + const string& getClientVersion() const + { + return _clientVersion; + } + + void setTCPPort(uint16_t port) + { + _tcpPort = port; + } + + uint16_t getTCPPort() const + { + return _tcpPort; + } + + void setExtension(const string& name, uint8_t id) + { + _extensions[name] = id; + } + + void setExtensions(const Extensions& extensions) + { + _extensions = extensions; + } + + uint8_t getExtensionMessageID(const string& name) const; + + void setPeer(const PeerHandle& peer); + + void setBtContext(const BtContextHandle& btContext); + + static HandshakeExtensionMessageHandle create(const char* data, + size_t dataLength); + +}; + +typedef SharedHandle HandshakeExtensionMessageHandle; +#endif // _D_HANDSHAKE_EXTENSION_MESSAGE_H_ diff --git a/src/Makefile.am b/src/Makefile.am index af3851fd..5a3ec101 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -167,6 +167,7 @@ SRCS += MetaEntry.h\ MetaFileUtil.cc MetaFileUtil.h\ MetaEntryVisitor.h\ ShaVisitor.cc ShaVisitor.h\ + BencodeVisitor.cc\ PeerMessageUtil.cc PeerMessageUtil.h\ PeerAbstractCommand.cc PeerAbstractCommand.h\ PeerInitiateConnectionCommand.cc PeerInitiateConnectionCommand.h\ @@ -248,7 +249,11 @@ SRCS += MetaEntry.h\ BtSetup.cc BtSetup.h\ BtFileAllocationEntry.cc BtFileAllocationEntry.h\ BtPostDownloadHandler.cc BtPostDownloadHandler.h\ - BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h + BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h\ + BtExtendedMessage.cc\ + DefaultExtensionMessageFactory.cc\ + HandshakeExtensionMessage.cc\ + UTPexExtensionMessage.cc endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/src/Makefile.in b/src/Makefile.in index 60b84072..ba2d0427 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -54,6 +54,7 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ MetaFileUtil.cc MetaFileUtil.h\ @ENABLE_BITTORRENT_TRUE@ MetaEntryVisitor.h\ @ENABLE_BITTORRENT_TRUE@ ShaVisitor.cc ShaVisitor.h\ +@ENABLE_BITTORRENT_TRUE@ BencodeVisitor.cc\ @ENABLE_BITTORRENT_TRUE@ PeerMessageUtil.cc PeerMessageUtil.h\ @ENABLE_BITTORRENT_TRUE@ PeerAbstractCommand.cc PeerAbstractCommand.h\ @ENABLE_BITTORRENT_TRUE@ PeerInitiateConnectionCommand.cc PeerInitiateConnectionCommand.h\ @@ -135,7 +136,11 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ BtSetup.cc BtSetup.h\ @ENABLE_BITTORRENT_TRUE@ BtFileAllocationEntry.cc BtFileAllocationEntry.h\ @ENABLE_BITTORRENT_TRUE@ BtPostDownloadHandler.cc BtPostDownloadHandler.h\ -@ENABLE_BITTORRENT_TRUE@ BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h +@ENABLE_BITTORRENT_TRUE@ BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h\ +@ENABLE_BITTORRENT_TRUE@ BtExtendedMessage.cc\ +@ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactory.cc\ +@ENABLE_BITTORRENT_TRUE@ HandshakeExtensionMessage.cc\ +@ENABLE_BITTORRENT_TRUE@ UTPexExtensionMessage.cc @ENABLE_METALINK_TRUE@am__append_3 = Metalinker.cc Metalinker.h\ @ENABLE_METALINK_TRUE@ MetalinkEntry.cc MetalinkEntry.h\ @@ -303,8 +308,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ MessageDigestHelper.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 \ - PeerMessageUtil.cc PeerMessageUtil.h PeerAbstractCommand.cc \ - PeerAbstractCommand.h PeerInitiateConnectionCommand.cc \ + BencodeVisitor.cc PeerMessageUtil.cc PeerMessageUtil.h \ + PeerAbstractCommand.cc PeerAbstractCommand.h \ + PeerInitiateConnectionCommand.cc \ PeerInitiateConnectionCommand.h PeerInteractionCommand.cc \ PeerInteractionCommand.h PeerListenCommand.cc \ PeerListenCommand.h RequestSlot.cc RequestSlot.h Directory.cc \ @@ -355,8 +361,10 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ PeerReceiveHandshakeCommand.h BtSetup.cc BtSetup.h \ BtFileAllocationEntry.cc BtFileAllocationEntry.h \ BtPostDownloadHandler.cc BtPostDownloadHandler.h \ - BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h Metalinker.cc \ - Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ + BtCheckIntegrityEntry.cc BtCheckIntegrityEntry.h \ + BtExtendedMessage.cc DefaultExtensionMessageFactory.cc \ + HandshakeExtensionMessage.cc UTPexExtensionMessage.cc \ + Metalinker.cc Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \ MetalinkProcessorFactory.cc MetalinkParserController.cc \ MetalinkParserStateMachine.cc InitialMetalinkParserState.cc \ @@ -385,6 +393,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ Dictionary.$(OBJEXT) List.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ MetaFileUtil.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ ShaVisitor.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BencodeVisitor.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerMessageUtil.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerAbstractCommand.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ PeerInitiateConnectionCommand.$(OBJEXT) \ @@ -433,7 +442,11 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ @ENABLE_BITTORRENT_TRUE@ BtSetup.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BtFileAllocationEntry.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BtPostDownloadHandler.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ BtCheckIntegrityEntry.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ BtCheckIntegrityEntry.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtExtendedMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactory.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ HandshakeExtensionMessage.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ UTPexExtensionMessage.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_3 = Metalinker.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntry.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkResource.$(OBJEXT) \ @@ -935,6 +948,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AuthConfigFactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AutoSaveCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BencodeVisitor.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)/BtAllowedFastMessage.Po@am__quote@ @@ -944,6 +958,7 @@ distclean-compile: @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)/BtDependency.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtExtendedMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtFileAllocationEntry.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@ @@ -987,6 +1002,7 @@ distclean-compile: @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)/DefaultExtensionMessageFactory.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPieceStorage.Po@am__quote@ @@ -1022,6 +1038,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpTunnelRequestCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FtpTunnelResponseCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrowSegment.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HandshakeExtensionMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HashMetalinkParserState.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HaveEraseCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpConnection.Po@am__quote@ @@ -1111,6 +1128,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TrackerWatcherCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TransferStat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/URLMetalinkParserState.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UnknownLengthPieceStorage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UriListParser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Util.Po@am__quote@ diff --git a/src/MetaEntry.h b/src/MetaEntry.h index 155d6bfa..29c86efb 100644 --- a/src/MetaEntry.h +++ b/src/MetaEntry.h @@ -49,4 +49,5 @@ public: }; +typedef SharedHandle MetaEntryHandle; #endif // _D_META_ENTRY_H_ diff --git a/src/MetaFileUtil.cc b/src/MetaFileUtil.cc index 4d429877..5e4d8787 100644 --- a/src/MetaFileUtil.cc +++ b/src/MetaFileUtil.cc @@ -83,7 +83,7 @@ MetaEntry* MetaFileUtil::bdecoding(const char* buf, int32_t len) { MetaEntry* MetaFileUtil::bdecodingR(const char** pp, const char* end) { if(*pp >= end) { - throw new DlAbortEx("mulformed metainfo"); + throw new DlAbortEx("Malformed metainfo"); } MetaEntry* e; switch(**pp) { @@ -107,7 +107,7 @@ MetaEntry* MetaFileUtil::bdecodingR(const char** pp, const char* end) { Dictionary* MetaFileUtil::parseDictionaryTree(const char** pp, const char* end) { if(*pp >= end) { - throw new DlAbortEx("mulformed metainfo"); + throw new DlAbortEx("Malformed metainfo"); } Dictionary* dic = new Dictionary(); try { @@ -129,7 +129,7 @@ Dictionary* MetaFileUtil::parseDictionaryTree(const char** pp, const char* end) List* MetaFileUtil::parseListTree(const char** pp, const char* end) { if(*pp >= end) { - throw new DlAbortEx("mulformed metainfo"); + throw new DlAbortEx("Malformed metainfo"); } List* lis = new List(); try { @@ -150,12 +150,12 @@ List* MetaFileUtil::parseListTree(const char** pp, const char* end) { Data* MetaFileUtil::decodeInt(const char** pp, const char* end) { if(*pp >= end) { - throw new DlAbortEx(EX_MULFORMED_META_INFO); + throw new DlAbortEx(EX_MALFORMED_META_INFO); } char* endTerm = (char*)memchr(*pp, 'e', end-*pp); // TODO if endTerm is null if(endTerm == NULL) { - throw new DlAbortEx(EX_MULFORMED_META_INFO); + throw new DlAbortEx(EX_MALFORMED_META_INFO); } int32_t numSize = endTerm-*pp; @@ -166,12 +166,12 @@ Data* MetaFileUtil::decodeInt(const char** pp, const char* end) { Data* MetaFileUtil::decodeWord(const char** pp, const char* end) { if(*pp >= end) { - throw new DlAbortEx("mulformed metainfo"); + throw new DlAbortEx("Malformed metainfo"); } char* delim = (char*)memchr(*pp, ':', end-*pp); // TODO if delim is null if(delim == *pp || delim == NULL) { - throw new DlAbortEx(EX_MULFORMED_META_INFO); + throw new DlAbortEx(EX_MALFORMED_META_INFO); } int32_t numSize = delim-*pp; char* temp = new char[numSize+1]; @@ -181,12 +181,12 @@ Data* MetaFileUtil::decodeWord(const char** pp, const char* end) { int32_t size = strtol(temp, &endptr, 10); if(*endptr != '\0') { delete [] temp; - throw new DlAbortEx(EX_MULFORMED_META_INFO); + throw new DlAbortEx(EX_MALFORMED_META_INFO); } delete [] temp; if(delim+1+size > end) { - throw new DlAbortEx(EX_MULFORMED_META_INFO); + throw new DlAbortEx(EX_MALFORMED_META_INFO); } Data* data = new Data(delim+1, size); diff --git a/src/Peer.cc b/src/Peer.cc index 79e4d96f..f7637792 100644 --- a/src/Peer.cc +++ b/src/Peer.cc @@ -39,7 +39,7 @@ # include "MessageDigestHelper.h" #endif // ENABLE_MESSAGE_DIGEST -Peer::Peer(string ipaddr, int32_t port, int32_t pieceLength, int64_t totalLength): +Peer::Peer(string ipaddr, uint16_t port, int32_t pieceLength, int64_t totalLength): ipaddr(ipaddr), port(port), sessionUploadLength(0), @@ -113,6 +113,8 @@ void Peer::resetStatus() { optUnchoking = false; snubbing = false; fastExtensionEnabled = false; + _extendedMessagingEnabled = false; + _extensions.clear(); latency = DEFAULT_LATENCY; peerAllowedIndexSet.clear(); amAllowedIndexSet.clear(); @@ -158,3 +160,30 @@ bool Peer::isGood() const { return _badConditionStartTime.elapsed(_badConditionInterval); } + +uint8_t Peer::getExtensionMessageID(const string& name) +{ + Extensions::const_iterator itr = _extensions.find(name); + if(itr == _extensions.end()) { + return 0; + } else { + return (*itr).second; + } +} + +string Peer::getExtensionName(uint8_t id) +{ + for(Extensions::const_iterator itr = _extensions.begin(); + itr != _extensions.end(); ++itr) { + const Extensions::value_type& p = *itr; + if(p.second == id) { + return p.first; + } + } + return ""; +} + +void Peer::setExtension(const string& name, uint8_t id) +{ + _extensions[name] = id; +} diff --git a/src/Peer.h b/src/Peer.h index 1c61a48a..04ae33af 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -39,6 +39,7 @@ #include "BitfieldMan.h" #include "PeerStat.h" #include "TimeA2.h" +#include "BtConstants.h" #include #define PEER_ID_LENGTH 20 @@ -49,7 +50,7 @@ class Peer { friend bool operator!=(const Peer& p1, const Peer& p2); public: string ipaddr; - int32_t port; + uint16_t port; bool amChoking; bool amInterested; bool peerChoking; @@ -67,6 +68,8 @@ private: Integers peerAllowedIndexSet; // fast index set which localhost has sent to a peer. Integers amAllowedIndexSet; + bool _extendedMessagingEnabled; + Extensions _extensions; PeerStat peerStat; int64_t sessionUploadLength; int64_t sessionDownloadLength; @@ -74,10 +77,11 @@ private: int32_t latency; bool active; string id; + Time _firstContactTime; Time _badConditionStartTime; int32_t _badConditionInterval; public: - Peer(string ipaddr, int32_t port, int32_t pieceLength, int64_t totalLength); + Peer(string ipaddr, uint16_t port, int32_t pieceLength, int64_t totalLength); ~Peer() { delete bitfield; @@ -193,6 +197,16 @@ public: void addAmAllowedIndex(int32_t index); bool isInAmAllowedIndexSet(int32_t index) const; + void setExtendedMessagingEnabled(bool enabled) + { + _extendedMessagingEnabled = enabled; + } + + bool isExtendedMessagingEnabled() const + { + return _extendedMessagingEnabled; + } + bool shouldBeChoking() const; bool hasPiece(int32_t index) const; @@ -211,6 +225,22 @@ public: bool isGood() const; void reconfigure(int32_t pieceLength, int64_t totalLength); + + Time getFirstContactTime() const + { + return _firstContactTime; + } + + Time getBadConditionStartTime() const + { + return _badConditionStartTime; + } + + uint8_t getExtensionMessageID(const string& name); + + string getExtensionName(uint8_t id); + + void setExtension(const string& name, uint8_t id); }; typedef SharedHandle PeerHandle; diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index 7d9794ac..677fdc4f 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -112,6 +112,9 @@ PeerInteractionCommand::PeerInteractionCommand(int32_t cuid, btInteractive->setKeepAliveInterval(e->option->getAsInt(PREF_BT_KEEP_ALIVE_INTERVAL)); btInteractive->setMaxDownloadSpeedLimit(e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT)); btInteractive->setBtMessageFactory(factory); + if(!btContext->isPrivate() && e->option->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) { + btInteractive->setUTPexEnabled(true); + } this->btInteractive = btInteractive; // reverse depends diff --git a/src/PeerMessageUtil.cc b/src/PeerMessageUtil.cc index c342aec3..74a00037 100644 --- a/src/PeerMessageUtil.cc +++ b/src/PeerMessageUtil.cc @@ -125,3 +125,17 @@ void PeerMessageUtil::createPeerMessageString(unsigned char* msg, setIntParam(msg, payloadLength); msg[4] = messageId; } + +bool PeerMessageUtil::createcompact(char* compact, const string& addr, uint16_t port) +{ + struct in_addr in; + if(inet_aton(addr.c_str(), &in) == 0) { + return false; + } + uint32_t* addrp = (uint32_t*)compact; + *addrp = in.s_addr; + uint16_t* portp = (uint16_t*)(compact+4); + *portp = htons(port); + return true; +} + diff --git a/src/PeerMessageUtil.h b/src/PeerMessageUtil.h index 53648b5b..f66f2f0e 100644 --- a/src/PeerMessageUtil.h +++ b/src/PeerMessageUtil.h @@ -65,6 +65,16 @@ public: int32_t msgLength, int32_t payloadLength, int8_t messageId); + + /** + * Creates compact tracker format(6bytes for ipv4 address and port) + * and stores the results in compact. + * compact must be at least 6 bytes and pre-allocated. + * Returns true if creation is successful, otherwise returns false. + * The example of failure reason is that addr is not numbers-and-dots + * notation. + */ + static bool createcompact(char* compact, const string& addr, uint16_t port); }; #endif // _D_PEER_MESSAGE_UTIL_H_ diff --git a/src/PeerObject.h b/src/PeerObject.h index 77b19c3b..44521c8f 100644 --- a/src/PeerObject.h +++ b/src/PeerObject.h @@ -41,6 +41,7 @@ #include "BtMessageDispatcher.h" #include "PeerConnection.h" #include "BtMessageReceiver.h" +#include "ExtensionMessageFactory.h" class PeerObject { public: @@ -48,13 +49,15 @@ public: btRequestFactory(0), btMessageDispatcher(0), btMessageReceiver(0), - peerConnection(0) {} - + peerConnection(0), + extensionMessageFactory(0) {} + BtMessageFactoryHandle btMessageFactory; BtRequestFactoryHandle btRequestFactory; BtMessageDispatcherHandle btMessageDispatcher; BtMessageReceiverHandle btMessageReceiver; PeerConnectionHandle peerConnection; + ExtensionMessageFactoryHandle extensionMessageFactory; }; typedef SharedHandle PeerObjectHandle; diff --git a/src/PeerReceiveHandshakeCommand.cc b/src/PeerReceiveHandshakeCommand.cc index 81d9fb72..edb19756 100644 --- a/src/PeerReceiveHandshakeCommand.cc +++ b/src/PeerReceiveHandshakeCommand.cc @@ -77,21 +77,22 @@ bool PeerReceiveHandshakeCommand::executeInternal() if(!PIECE_STORAGE(btContext)->downloadFinished() && tstat.getDownloadSpeed() < _lowestSpeedLimit || BT_RUNTIME(btContext)->getConnections() < MAX_PEERS) { peer->reconfigure(btContext->getPieceLength(), btContext->getTotalLength()); - PEER_STORAGE(btContext)->addIncomingPeer(peer); + if(PEER_STORAGE(btContext)->addIncomingPeer(peer)) { - peer->cuid = cuid; - - PeerInteractionCommand* command = - new PeerInteractionCommand(cuid, - btContext->getOwnerRequestGroup(), - peer, - e, - btContext, - socket, - PeerInteractionCommand::RECEIVER_WAIT_HANDSHAKE, - _peerConnection); - e->commands.push_back(command); - logger->debug(MSG_INCOMING_PEER_CONNECTION, cuid, peer->cuid); + peer->cuid = cuid; + + PeerInteractionCommand* command = + new PeerInteractionCommand(cuid, + btContext->getOwnerRequestGroup(), + peer, + e, + btContext, + socket, + PeerInteractionCommand::RECEIVER_WAIT_HANDSHAKE, + _peerConnection); + e->commands.push_back(command); + logger->debug(MSG_INCOMING_PEER_CONNECTION, cuid, peer->cuid); + } } return true; } else { diff --git a/src/UTPexExtensionMessage.cc b/src/UTPexExtensionMessage.cc new file mode 100644 index 00000000..c8395ed8 --- /dev/null +++ b/src/UTPexExtensionMessage.cc @@ -0,0 +1,149 @@ +/* */ +#include "UTPexExtensionMessage.h" +#include "Peer.h" +#include "BtContext.h" +#include "Dictionary.h" +#include "Data.h" +#include "BencodeVisitor.h" +#include "a2netcompat.h" +#include "Util.h" +#include "PeerMessageUtil.h" +#include "BtRegistry.h" +#include "CompactPeerListProcessor.h" +#include "MetaFileUtil.h" +#include "DlAbortEx.h" +#include "message.h" + +const string UTPexExtensionMessage::EXTENSION_NAME = "ut_pex"; + +UTPexExtensionMessage::UTPexExtensionMessage(uint8_t extensionMessageID): + _extensionMessageID(extensionMessageID), + _btContext(0) {} + +UTPexExtensionMessage::~UTPexExtensionMessage() {} + +string UTPexExtensionMessage::getBencodedData() +{ + SharedHandle d = new Dictionary(); + pair freshPeerPair = createCompactPeerListAndFlag(_freshPeers); + pair droppedPeerPair = createCompactPeerListAndFlag(_droppedPeers); + d->put("added", new Data(freshPeerPair.first)); + d->put("added.f", new Data(freshPeerPair.second)); + d->put("dropped", new Data(droppedPeerPair.first)); + + BencodeVisitor v; + d->accept(&v); + return v.getBencodedData(); +} + +pair UTPexExtensionMessage::createCompactPeerListAndFlag(const Peers& peers) +{ + string addrstring; + string flagstring; + for(Peers::const_iterator itr = peers.begin(); itr != peers.end(); ++itr) { + char compact[6]; + if(PeerMessageUtil::createcompact(compact, (*itr)->ipaddr, (*itr)->port)) { + addrstring.append(&compact[0], &compact[6]); + flagstring += (*itr)->isSeeder() ? "2" : "0"; + } + } + return pair(addrstring, flagstring); +} + +string UTPexExtensionMessage::toString() const +{ + return "ut_pex added="+Util::uitos(_freshPeers.size())+", dropped="+ + Util::uitos(_droppedPeers.size()); +} + +void UTPexExtensionMessage::doReceivedAction() +{ + PEER_STORAGE(_btContext)->addPeer(_freshPeers); +} + +void UTPexExtensionMessage::addFreshPeer(const PeerHandle& peer) +{ + _freshPeers.push_back(peer); +} + +const Peers& UTPexExtensionMessage::getFreshPeers() const +{ + return _freshPeers; +} + +void UTPexExtensionMessage::addDroppedPeer(const PeerHandle& peer) +{ + _droppedPeers.push_back(peer); +} + +const Peers& UTPexExtensionMessage::getDroppedPeers() const +{ + return _droppedPeers; +} + +void UTPexExtensionMessage::setBtContext(const BtContextHandle& btContext) +{ + _btContext = btContext; +} + +UTPexExtensionMessageHandle +UTPexExtensionMessage::create(const BtContextHandle& btContext, + const char* data, size_t len) +{ + if(len < 1) { + throw new DlAbortEx(MSG_TOO_SMALL_PAYLOAD_SIZE, + EXTENSION_NAME.c_str(), len); + } + UTPexExtensionMessageHandle msg = new UTPexExtensionMessage(*data); + SharedHandle root = MetaFileUtil::bdecoding(data+1, len-1); + if(root.isNull()) { + return msg; + } + const Dictionary* d = dynamic_cast(root.get()); + if(d) { + CompactPeerListProcessor proc(btContext->getPieceLength(), + btContext->getTotalLength()); + const Data* added = dynamic_cast(d->get("added")); + if(added) { + msg->_freshPeers = proc.extractPeer(added); + } + const Data* dropped = dynamic_cast(d->get("dropped")); + if(dropped) { + msg->_droppedPeers = proc.extractPeer(dropped); + } + } + return msg; +} diff --git a/src/UTPexExtensionMessage.h b/src/UTPexExtensionMessage.h new file mode 100644 index 00000000..ec7df1ee --- /dev/null +++ b/src/UTPexExtensionMessage.h @@ -0,0 +1,99 @@ +/* */ +#ifndef _D_UT_PEX_EXTENSION_MESSAGE_H_ +#define _D_UT_PEX_EXTENSION_MESSAGE_H_ + +#include "ExtensionMessage.h" + +class BtContext; +typedef SharedHandle BtContextHandle; +class Peer; +typedef SharedHandle PeerHandle; +typedef deque Peers; +class UTPexExtensionMessage; +typedef SharedHandle UTPexExtensionMessageHandle; + +class UTPexExtensionMessage:public ExtensionMessage { +private: + uint8_t _extensionMessageID; + + Peers _freshPeers; + + Peers _droppedPeers; + + BtContextHandle _btContext; + + pair createCompactPeerListAndFlag(const Peers& peers); + +public: + UTPexExtensionMessage(uint8_t extensionMessageID); + + virtual ~UTPexExtensionMessage(); + + virtual string getBencodedData(); + + virtual uint8_t getExtensionMessageID() + { + return _extensionMessageID; + } + + virtual const string& getExtensionName() const + { + return EXTENSION_NAME; + } + + static const string EXTENSION_NAME; + + virtual string toString() const; + + virtual void doReceivedAction(); + + void addFreshPeer(const PeerHandle& peer); + + const Peers& getFreshPeers() const; + + void addDroppedPeer(const PeerHandle& peer); + + const Peers& getDroppedPeers() const; + + void setBtContext(const BtContextHandle& btContext); + + static UTPexExtensionMessageHandle create(const BtContextHandle& btContext, + const char* data, size_t len); +}; + +typedef SharedHandle UTPexExtensionMessageHandle; + +#endif // _D_UT_PEX_EXTENSION_MESSAGE_H_ diff --git a/src/message.h b/src/message.h index 6d008515..3847fdf3 100644 --- a/src/message.h +++ b/src/message.h @@ -78,6 +78,7 @@ #define MSG_DELETING_REQUEST_SLOT_TIMEOUT _("CUID#%d - Deleting request slot blockIndex=%d because of time out") #define MSG_DELETING_REQUEST_SLOT_ACQUIRED _("CUID#%d - Deleting request slot blockIndex=%d because the block has been acquired.") #define MSG_FAST_EXTENSION_ENABLED _("CUID#%d - Fast extension enabled.") +#define MSG_EXTENDED_MESSAGING_ENABLED _("CUID#%d - Extended Messaging enabled.") #define MSG_FILE_ALLOCATION_FAILURE _("CUID#%d - Exception caught while allocating file space.") #define MSG_CONTENT_DISPOSITION_DETECTED _("CUID#%d - Content-Disposition detected. Use %s as filename") #define MSG_PEER_BANNED _("CUID#%d - Peer %s:%d banned.") @@ -131,6 +132,7 @@ #define MSG_RESOURCE_NOT_FOUND _("Resource not found") #define MSG_FILE_RENAMED _("File already exists. Renamed to %s.") #define MSG_CANNOT_PARSE_METALINK _("Cannot parse metalink XML file. XML may be malformed.") +#define MSG_TOO_SMALL_PAYLOAD_SIZE _("Too small payload size for %s, size=%d.") #define EX_TIME_OUT _("Timeout.") #define EX_INVALID_CHUNK_SIZE _("Invalid chunk size.") @@ -154,7 +156,7 @@ #define EX_AUTH_FAILED _("Authorization failed.") #define EX_GOT_EOF _("Got EOF from the server.") #define EX_EOF_FROM_PEER _("Got EOF from peer.") -#define EX_MULFORMED_META_INFO _("Malformed meta info.") +#define EX_MALFORMED_META_INFO _("Malformed meta info.") #define EX_FILE_OPEN _("Failed to open the file %s, cause: %s") #define EX_FILE_WRITE _("Failed to write into the file %s, cause: %s") diff --git a/src/option_processing.cc b/src/option_processing.cc index ef121141..61dfa264 100644 --- a/src/option_processing.cc +++ b/src/option_processing.cc @@ -129,6 +129,7 @@ Option* option_processing(int argc, char* const argv[]) op->put(PREF_ENABLE_DIRECT_IO, V_FALSE); op->put(PREF_ALLOW_PIECE_LENGTH_CHANGE, V_FALSE); op->put(PREF_METALINK_PREFERRED_PROTOCOL, V_NONE); + op->put(PREF_ENABLE_PEER_EXCHANGE, V_TRUE); while(1) { int optIndex = 0; int lopt; diff --git a/src/prefs.h b/src/prefs.h index 67fe0b87..1cb3aa90 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -207,6 +207,8 @@ #define PREF_BT_KEEP_ALIVE_INTERVAL "bt-keep-alive-interval" // values: a string, less than or equals to 20 bytes length #define PREF_PEER_ID_PREFIX "peer-id-prefix" +// values: true | false +#define PREF_ENABLE_PEER_EXCHANGE "enable-peer-exchange" /** * Metalink related preferences diff --git a/test/BencodeVisitorTest.cc b/test/BencodeVisitorTest.cc new file mode 100644 index 00000000..3af7e0b4 --- /dev/null +++ b/test/BencodeVisitorTest.cc @@ -0,0 +1,70 @@ +#include "BencodeVisitor.h" +#include "Data.h" +#include "List.h" +#include "Dictionary.h" +#include + +class BencodeVisitorTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BencodeVisitorTest); + CPPUNIT_TEST(testVisit_data); + CPPUNIT_TEST(testVisit_list); + CPPUNIT_TEST(testVisit_dictionary); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() { + } + + void testVisit_data(); + void testVisit_list(); + void testVisit_dictionary(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION( BencodeVisitorTest ); + +void BencodeVisitorTest::testVisit_data() +{ + { + BencodeVisitor v; + string str = "apple"; + MetaEntryHandle m = new Data(str.c_str(), str.size()); + m->accept(&v); + CPPUNIT_ASSERT_EQUAL(string("5:apple"), v.getBencodedData()); + } + { + BencodeVisitor v; + string str = "123"; + MetaEntryHandle m = new Data(str.c_str(), str.size(), true); + m->accept(&v); + CPPUNIT_ASSERT_EQUAL(string("i123e"), v.getBencodedData()); + } +} + +void BencodeVisitorTest::testVisit_list() +{ + BencodeVisitor v; + List l; + string s1 = "alpha"; + l.add(new Data(s1.c_str(), s1.size())); + string s2 = "bravo"; + l.add(new Data(s2.c_str(), s2.size())); + string s3 = "123"; + l.add(new Data(s3.c_str(), s3.size(), true)); + l.accept(&v); + CPPUNIT_ASSERT_EQUAL(string("l5:alpha5:bravoi123ee"), v.getBencodedData()); +} + +void BencodeVisitorTest::testVisit_dictionary() +{ + BencodeVisitor v; + Dictionary d; + string s1 = "alpha"; + d.put("team", new Data(s1.c_str(), s1.size())); + string s2 = "123"; + d.put("score", new Data(s2.c_str(), s2.size(), true)); + d.accept(&v); + CPPUNIT_ASSERT_EQUAL(string("d4:team5:alpha5:scorei123ee"), v.getBencodedData()); +} diff --git a/test/BtExtendedMessageTest.cc b/test/BtExtendedMessageTest.cc new file mode 100644 index 00000000..43c1ca94 --- /dev/null +++ b/test/BtExtendedMessageTest.cc @@ -0,0 +1,121 @@ +#include "BtExtendedMessage.h" +#include "PeerMessageUtil.h" +#include "MockBtContext.h" +#include "MockExtensionMessageFactory.h" +#include + +using namespace std; + +class BtExtendedMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(BtExtendedMessageTest); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testGetMessage); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST_SUITE_END(); +private: + +public: + void setUp() + { + BtRegistry::unregisterAll(); + } + + void tearDown() + { + BtRegistry::unregisterAll(); + } + + void testCreate(); + void testGetMessage(); + void testDoReceivedAction(); + void testToString(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(BtExtendedMessageTest); + +void BtExtendedMessageTest::testCreate() { + PeerHandle peer = new Peer("192.168.0.1", 6969, 16*1024, 256*1024); + peer->setExtension("charlie", 1); + MockBtContextHandle ctx = new MockBtContext(); + unsigned char infohash[20]; + memset(infohash, 0, sizeof(infohash)); + ctx->setInfoHash(infohash); + MockExtensionMessageFactoryHandle exmsgFactory = new MockExtensionMessageFactory(); + + + BtRegistry::registerPeerObjectCluster(ctx->getInfoHashAsString(), new PeerObjectCluster()); + PeerObjectHandle peerObject = new PeerObject(); + peerObject->extensionMessageFactory = exmsgFactory; + + PEER_OBJECT_CLUSTER(ctx)->registerHandle(peer->getId(), peerObject); + + // payload:{4:name3:foo}->11bytes + string payload = "4:name3:foo"; + char msg[17];// 6+11bytes + PeerMessageUtil::createPeerMessageString((unsigned char*)msg, sizeof(msg), 13, 20); + msg[5] = 1; // Set dummy extended message ID 1 + memcpy(msg+6, payload.c_str(), payload.size()); + BtExtendedMessageHandle pm = BtExtendedMessage::create(ctx, + peer, + &msg[4], 13); + CPPUNIT_ASSERT_EQUAL((int8_t)20, pm->getId()); + + // case: payload size is wrong + try { + char msg[5]; + PeerMessageUtil::createPeerMessageString((unsigned char*)msg, sizeof(msg), 1, 20); + BtExtendedMessage::create(ctx, peer, &msg[4], 1); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e << endl; + delete e; + } + // case: id is wrong + try { + char msg[6]; + PeerMessageUtil::createPeerMessageString((unsigned char*)msg, sizeof(msg), 2, 21); + BtExtendedMessage::create(ctx, peer, &msg[4], 2); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e << endl; + delete e; + } +} + +void BtExtendedMessageTest::testGetMessage() { + string payload = "4:name3:foo"; + uint8_t extendedMessageID = 1; + MockExtensionMessageHandle exmsg = + new MockExtensionMessage("charlie", extendedMessageID, + payload.c_str(), + payload.size()); + BtExtendedMessage msg(exmsg); + + char data[17]; + PeerMessageUtil::createPeerMessageString((unsigned char*)data, sizeof(data), 13, 20); + *(data+5) = extendedMessageID; + memcpy(data+6, payload.c_str(), payload.size()); + CPPUNIT_ASSERT(memcmp(msg.getMessage(), data, 17) == 0); +} + +void BtExtendedMessageTest::testDoReceivedAction() { + MockExtensionMessageHandle exmsg = + new MockExtensionMessage("charlie", 1, "", 0); + BtExtendedMessage msg(exmsg); + msg.doReceivedAction(); + CPPUNIT_ASSERT(exmsg->_doReceivedActionCalled); +} + +void BtExtendedMessageTest::testToString() { + string payload = "4:name3:foo"; + uint8_t extendedMessageID = 1; + MockExtensionMessageHandle exmsg = + new MockExtensionMessage("charlie", extendedMessageID, + payload.c_str(), + payload.size()); + BtExtendedMessage msg(exmsg); + CPPUNIT_ASSERT_EQUAL(string("extended charlie"), msg.toString()); +} diff --git a/test/BtHandshakeMessageTest.cc b/test/BtHandshakeMessageTest.cc index 6e4f07ad..64b9d774 100644 --- a/test/BtHandshakeMessageTest.cc +++ b/test/BtHandshakeMessageTest.cc @@ -34,7 +34,7 @@ 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 }; + unsigned char reserved[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x04 }; memcpy(&msg[20], reserved, sizeof(reserved)); unsigned char infoHash[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, @@ -56,7 +56,7 @@ void BtHandshakeMessageTest::testCreate() { CPPUNIT_ASSERT_EQUAL((int8_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"), + CPPUNIT_ASSERT_EQUAL(string("0000000000100004"), Util::toHex(message->getReserved(), BtHandshakeMessage::RESERVED_LENGTH)); CPPUNIT_ASSERT_EQUAL(string("ffffffffffffffffffffffffffffffffffffffff"), Util::toHex(message->getInfoHash(), INFO_HASH_LENGTH)); @@ -98,5 +98,5 @@ void BtHandshakeMessageTest::testToString() { 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()); + 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=0000000000100004"), msg.toString()); } diff --git a/test/DefaultBtMessageFactoryTest.cc b/test/DefaultBtMessageFactoryTest.cc new file mode 100644 index 00000000..95c8de66 --- /dev/null +++ b/test/DefaultBtMessageFactoryTest.cc @@ -0,0 +1,78 @@ +#include "DefaultBtMessageFactory.h" +#include "Peer.h" +#include "PeerMessageUtil.h" +#include "BtRegistry.h" +#include "MockBtContext.h" +#include "MockExtensionMessageFactory.h" +#include "BtExtendedMessage.h" +#include + +class DefaultBtMessageFactoryTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultBtMessageFactoryTest); + CPPUNIT_TEST(testCreateBtMessage_BtExtendedMessage); + CPPUNIT_TEST_SUITE_END(); +private: + MockBtContextHandle _btContext; + PeerHandle _peer; +public: + DefaultBtMessageFactoryTest():_btContext(0), _peer(0) {} + + void setUp() + { + BtRegistry::unregisterAll(); + MockBtContextHandle btContext = new MockBtContext(); + unsigned char infohash[20]; + memset(infohash, 0, sizeof(infohash)); + btContext->setInfoHash(infohash); + _btContext = btContext; + + _peer = new Peer("192.168.0.1", 6969, 16*1024, 256*1024); + _peer->setExtendedMessagingEnabled(true); + + MockExtensionMessageFactoryHandle exmsgFactory = new MockExtensionMessageFactory(); + BtRegistry::registerPeerObjectCluster(_btContext->getInfoHashAsString(), + new PeerObjectCluster()); + PeerObjectHandle peerObject = new PeerObject(); + peerObject->extensionMessageFactory = exmsgFactory; + + PEER_OBJECT_CLUSTER(_btContext)->registerHandle(_peer->getId(), peerObject); + } + + void tearDown() + { + BtRegistry::unregisterAll(); + } + + void testCreateBtMessage_BtExtendedMessage(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultBtMessageFactoryTest); + +void DefaultBtMessageFactoryTest::testCreateBtMessage_BtExtendedMessage() +{ + + DefaultBtMessageFactory factory; + factory.setBtContext(_btContext); + factory.setPeer(_peer); + + // payload:{4:name3:foo}->11bytes + string payload = "4:name3:foo"; + char msg[17];// 6+11bytes + PeerMessageUtil::createPeerMessageString((unsigned char*)msg, sizeof(msg), 13, 20); + msg[5] = 1; // Set dummy extended message ID 1 + memcpy(msg+6, payload.c_str(), payload.size()); + + BtExtendedMessageHandle m = factory.createBtMessage((const unsigned char*)msg+4, sizeof(msg)); + + try { + // disable extended messaging + _peer->setExtendedMessagingEnabled(false); + factory.createBtMessage((const unsigned char*)msg+4, sizeof(msg)); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e << endl; + delete e; + } +} diff --git a/test/DefaultExtensionMessageFactoryTest.cc b/test/DefaultExtensionMessageFactoryTest.cc new file mode 100644 index 00000000..0c222543 --- /dev/null +++ b/test/DefaultExtensionMessageFactoryTest.cc @@ -0,0 +1,113 @@ +#include "DefaultExtensionMessageFactory.h" +#include "Peer.h" +#include "MockBtContext.h" +#include "PeerMessageUtil.h" +#include "HandshakeExtensionMessage.h" +#include "UTPexExtensionMessage.h" +#include "Exception.h" +#include "BtRegistry.h" +#include "BtRuntime.h" +#include + +class DefaultExtensionMessageFactoryTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(DefaultExtensionMessageFactoryTest); + CPPUNIT_TEST(testCreateMessage_unknown); + CPPUNIT_TEST(testCreateMessage_Handshake); + CPPUNIT_TEST(testCreateMessage_UTPex); + CPPUNIT_TEST_SUITE_END(); +private: + MockBtContextHandle _btContext; + PeerHandle _peer; +public: + DefaultExtensionMessageFactoryTest():_btContext(0), _peer(0) {} + + void setUp() + { + BtRegistry::unregisterAll(); + MockBtContextHandle btContext = new MockBtContext(); + unsigned char infohash[20]; + memset(infohash, 0, sizeof(infohash)); + btContext->setInfoHash(infohash); + _btContext = btContext; + + BtRuntimeHandle btRuntime = new BtRuntime(); + BtRegistry::registerBtRuntime(_btContext->getInfoHashAsString(), + btRuntime); + + _peer = new Peer("192.168.0.1", 6969, 16*1024, 256*1024); + _peer->setExtension("ut_pex", 1); + } + + void tearDown() + { + BtRegistry::unregisterAll(); + } + + void testCreateMessage_unknown(); + void testCreateMessage_Handshake(); + void testCreateMessage_UTPex(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(DefaultExtensionMessageFactoryTest); + +void DefaultExtensionMessageFactoryTest::testCreateMessage_unknown() +{ + DefaultExtensionMessageFactory factory; + factory.setBtContext(_btContext); + factory.setPeer(_peer); + _peer->setExtension("foo", 255); + + char id[1] = { 255 }; + + string data = string(&id[0], &id[1]); + try { + factory.createMessage(data.c_str(), data.size()); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e << endl; + delete e; + } +} + +void DefaultExtensionMessageFactoryTest::testCreateMessage_Handshake() +{ + DefaultExtensionMessageFactory factory; + factory.setBtContext(_btContext); + factory.setPeer(_peer); + + char id[1] = { 0 }; + + string data = string(&id[0], &id[1])+"d1:v5:aria2e"; + HandshakeExtensionMessageHandle m = factory.createMessage(data.c_str(), data.size()); + CPPUNIT_ASSERT_EQUAL(string("aria2"), m->getClientVersion()); +} + +void DefaultExtensionMessageFactoryTest::testCreateMessage_UTPex() +{ + DefaultExtensionMessageFactory factory; + factory.setBtContext(_btContext); + factory.setPeer(_peer); + + char c1[6]; + char c2[6]; + char c3[6]; + char c4[6]; + PeerMessageUtil::createcompact(c1, "192.168.0.1", 6881); + PeerMessageUtil::createcompact(c2, "10.1.1.2", 9999); + PeerMessageUtil::createcompact(c3, "192.168.0.2", 6882); + PeerMessageUtil::createcompact(c4, "10.1.1.3",10000); + + char id[1] = { BT_RUNTIME(_btContext)->getExtensionMessageID("ut_pex") }; + + string data = string(&id[0], &id[1])+"d5:added12:"+ + string(&c1[0], &c1[6])+string(&c2[0], &c2[6])+ + "7:added.f2:207:dropped12:"+ + string(&c3[0], &c3[6])+string(&c4[0], &c4[6])+ + "e"; + + UTPexExtensionMessageHandle m = factory.createMessage(data.c_str(), data.size()); + CPPUNIT_ASSERT_EQUAL(BT_RUNTIME(_btContext)->getExtensionMessageID("ut_pex"), + m->getExtensionMessageID()); +} diff --git a/test/DefaultPeerListProcessorTest.cc b/test/DefaultPeerListProcessorTest.cc index f70abee2..9942a19f 100644 --- a/test/DefaultPeerListProcessorTest.cc +++ b/test/DefaultPeerListProcessorTest.cc @@ -36,7 +36,7 @@ void DefaultPeerListProcessorTest::testExtractPeer() { CPPUNIT_ASSERT_EQUAL((size_t)1, peers.size()); PeerHandle peer = *peers.begin(); CPPUNIT_ASSERT_EQUAL(string("192.168.0.1"), peer->ipaddr); - CPPUNIT_ASSERT_EQUAL((int32_t)2006, peer->port); + CPPUNIT_ASSERT_EQUAL((uint16_t)2006, peer->port); } void DefaultPeerListProcessorTest::testExtract2Peers() { @@ -49,9 +49,9 @@ void DefaultPeerListProcessorTest::testExtract2Peers() { CPPUNIT_ASSERT_EQUAL((size_t)2, peers.size()); PeerHandle peer = *peers.begin(); CPPUNIT_ASSERT_EQUAL(string("192.168.0.1"), peer->ipaddr); - CPPUNIT_ASSERT_EQUAL((int32_t)2006, peer->port); + CPPUNIT_ASSERT_EQUAL((uint16_t)2006, peer->port); peer = *(peers.begin()+1); CPPUNIT_ASSERT_EQUAL(string("192.168.0.2"), peer->ipaddr); - CPPUNIT_ASSERT_EQUAL((int32_t)2007, peer->port); + CPPUNIT_ASSERT_EQUAL((uint16_t)2007, peer->port); } diff --git a/test/DefaultPeerStorageTest.cc b/test/DefaultPeerStorageTest.cc index c8212a9d..46d0697e 100644 --- a/test/DefaultPeerStorageTest.cc +++ b/test/DefaultPeerStorageTest.cc @@ -113,9 +113,8 @@ void DefaultPeerStorageTest::testAddPeer() { CPPUNIT_ASSERT_EQUAL((int32_t)3, ps.countPeer()); - // this is true, because peer1 in the container has no errors and - // it is replaced by peer1(self assignment). - CPPUNIT_ASSERT_EQUAL(true, ps.addPeer(peer1)); + // this returns false, because peer1 is already in the container + CPPUNIT_ASSERT_EQUAL(false, ps.addPeer(peer1)); // the number of peers doesn't change. CPPUNIT_ASSERT_EQUAL((int32_t)3, ps.countPeer()); diff --git a/test/HandshakeExtensionMessageTest.cc b/test/HandshakeExtensionMessageTest.cc new file mode 100644 index 00000000..6cecd611 --- /dev/null +++ b/test/HandshakeExtensionMessageTest.cc @@ -0,0 +1,155 @@ +#include "HandshakeExtensionMessage.h" +#include "Peer.h" +#include "MockBtContext.h" +#include "MockPeerStorage.h" +#include "BtRegistry.h" +#include + +class HandshakeExtensionMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(HandshakeExtensionMessageTest); + CPPUNIT_TEST(testGetExtensionMessageID); + CPPUNIT_TEST(testGetExtensionName); + CPPUNIT_TEST(testGetBencodedData); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST(testCreate_stringnum); + CPPUNIT_TEST_SUITE_END(); +private: + BtContextHandle _btContext; +public: + HandshakeExtensionMessageTest():_btContext(0) {} + + void setUp() + { + BtRegistry::unregisterAll(); + MockBtContextHandle btContext = new MockBtContext(); + unsigned char infohash[20]; + memset(infohash, 0, sizeof(infohash)); + btContext->setInfoHash(infohash); + _btContext = btContext; + MockPeerStorageHandle peerStorage = new MockPeerStorage(); + BtRegistry::registerPeerStorage(_btContext->getInfoHashAsString(), + peerStorage); + } + + void tearDown() + { + BtRegistry::unregisterAll(); + } + + void testGetExtensionMessageID(); + void testGetExtensionName(); + void testGetBencodedData(); + void testToString(); + void testDoReceivedAction(); + void testCreate(); + void testCreate_stringnum(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(HandshakeExtensionMessageTest); + +void HandshakeExtensionMessageTest::testGetExtensionMessageID() +{ + HandshakeExtensionMessage msg; + CPPUNIT_ASSERT_EQUAL((uint8_t)0, msg.getExtensionMessageID()); +} + +void HandshakeExtensionMessageTest::testGetExtensionName() +{ + HandshakeExtensionMessage msg; + CPPUNIT_ASSERT_EQUAL(string("handshake"), msg.getExtensionName()); +} + +void HandshakeExtensionMessageTest::testGetBencodedData() +{ + HandshakeExtensionMessage msg; + msg.setClientVersion("aria2"); + msg.setTCPPort(6889); + msg.setExtension("ut_pex", 1); + msg.setExtension("a2_dht", 2); + CPPUNIT_ASSERT_EQUAL(string("d1:v5:aria21:pi6889e1:md6:a2_dhti2e6:ut_pexi1eee"), msg.getBencodedData()); +} + +void HandshakeExtensionMessageTest::testToString() +{ + HandshakeExtensionMessage msg; + msg.setClientVersion("aria2"); + msg.setTCPPort(6889); + msg.setExtension("ut_pex", 1); + msg.setExtension("a2_dht", 2); + CPPUNIT_ASSERT_EQUAL(string("handshake client=aria2, tcpPort=6889, a2_dht=2, ut_pex=1"), msg.toString()); +} + +void HandshakeExtensionMessageTest::testDoReceivedAction() +{ + PeerHandle peer = new Peer("192.168.0.1", 0, 1, 1); + HandshakeExtensionMessage msg; + msg.setClientVersion("aria2"); + msg.setTCPPort(6889); + msg.setExtension("ut_pex", 1); + msg.setExtension("a2_dht", 2); + msg.setPeer(peer); + msg.setBtContext(_btContext); + + msg.doReceivedAction(); + + CPPUNIT_ASSERT_EQUAL((uint16_t)6889, peer->port); + CPPUNIT_ASSERT_EQUAL((uint8_t)1, peer->getExtensionMessageID("ut_pex")); + CPPUNIT_ASSERT_EQUAL((uint8_t)2, peer->getExtensionMessageID("a2_dht")); + + CPPUNIT_ASSERT_EQUAL((size_t)1, PEER_STORAGE(_btContext)->getPeers().size()); + PeerHandle p1 = PEER_STORAGE(_btContext)->getPeers().front(); + CPPUNIT_ASSERT_EQUAL(string("192.168.0.1"), p1->ipaddr); + CPPUNIT_ASSERT_EQUAL((uint16_t)6889, p1->port); +} + +void HandshakeExtensionMessageTest::testCreate() +{ + string in = "0d1:pi6881e1:v5:aria21:md6:ut_pexi1eee"; + HandshakeExtensionMessageHandle m = + HandshakeExtensionMessage::create(in.c_str(), in.size()); + CPPUNIT_ASSERT_EQUAL(string("aria2"), m->getClientVersion()); + CPPUNIT_ASSERT_EQUAL((uint16_t)6881, m->getTCPPort()); + CPPUNIT_ASSERT_EQUAL((uint8_t)1, m->getExtensionMessageID("ut_pex")); + + try { + // bad payload format + string in = "011:hello world"; + HandshakeExtensionMessage::create(in.c_str(), in.size()); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e << endl; + delete e; + } + try { + // malformed dencoded message + string in = "011:hello"; + HandshakeExtensionMessage::create(in.c_str(), in.size()); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e << endl; + delete e; + } + try { + // 0 length data + string in = ""; + HandshakeExtensionMessage::create(in.c_str(), in.size()); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e << endl; + delete e; + } +} + +void HandshakeExtensionMessageTest::testCreate_stringnum() +{ + string in = "0d1:p4:68811:v5:aria21:md6:ut_pex1:1ee"; + HandshakeExtensionMessageHandle m = + HandshakeExtensionMessage::create(in.c_str(), in.size()); + CPPUNIT_ASSERT_EQUAL(string("aria2"), m->getClientVersion()); + CPPUNIT_ASSERT_EQUAL((uint16_t)6881, m->getTCPPort()); + CPPUNIT_ASSERT_EQUAL((uint8_t)1, m->getExtensionMessageID("ut_pex")); +} diff --git a/test/Makefile.am b/test/Makefile.am index 9b7de4c7..61ecb2f2 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -95,7 +95,13 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\ BtDependencyTest.cc\ BtPostDownloadHandlerTest.cc\ DownloadHandlerFactoryTest.cc\ - TimeSeedCriteriaTest.cc + TimeSeedCriteriaTest.cc\ + BencodeVisitorTest.cc\ + BtExtendedMessageTest.cc\ + HandshakeExtensionMessageTest.cc\ + UTPexExtensionMessageTest.cc\ + DefaultBtMessageFactoryTest.cc\ + DefaultExtensionMessageFactoryTest.cc endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/test/Makefile.in b/test/Makefile.in index 3bf295be..b2e97ecf 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -83,7 +83,13 @@ check_PROGRAMS = $(am__EXEEXT_1) @ENABLE_BITTORRENT_TRUE@ BtDependencyTest.cc\ @ENABLE_BITTORRENT_TRUE@ BtPostDownloadHandlerTest.cc\ @ENABLE_BITTORRENT_TRUE@ DownloadHandlerFactoryTest.cc\ -@ENABLE_BITTORRENT_TRUE@ TimeSeedCriteriaTest.cc +@ENABLE_BITTORRENT_TRUE@ TimeSeedCriteriaTest.cc\ +@ENABLE_BITTORRENT_TRUE@ BencodeVisitorTest.cc\ +@ENABLE_BITTORRENT_TRUE@ BtExtendedMessageTest.cc\ +@ENABLE_BITTORRENT_TRUE@ HandshakeExtensionMessageTest.cc\ +@ENABLE_BITTORRENT_TRUE@ UTPexExtensionMessageTest.cc\ +@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactoryTest.cc\ +@ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactoryTest.cc @ENABLE_METALINK_TRUE@am__append_3 = MetalinkerTest.cc\ @ENABLE_METALINK_TRUE@ MetalinkEntryTest.cc\ @@ -156,8 +162,11 @@ am__aria2c_SOURCES_DIST = AllTest.cc Base64Test.cc SequenceTest.cc \ PeerMessageUtilTest.cc ShareRatioSeedCriteriaTest.cc \ BtRegistryTest.cc BtDependencyTest.cc \ BtPostDownloadHandlerTest.cc DownloadHandlerFactoryTest.cc \ - TimeSeedCriteriaTest.cc MetalinkerTest.cc MetalinkEntryTest.cc \ - Metalink2RequestGroupTest.cc \ + TimeSeedCriteriaTest.cc BencodeVisitorTest.cc \ + BtExtendedMessageTest.cc HandshakeExtensionMessageTest.cc \ + UTPexExtensionMessageTest.cc DefaultBtMessageFactoryTest.cc \ + DefaultExtensionMessageFactoryTest.cc MetalinkerTest.cc \ + MetalinkEntryTest.cc Metalink2RequestGroupTest.cc \ MetalinkPostDownloadHandlerTest.cc MetalinkHelperTest.cc \ MetalinkParserControllerTest.cc MetalinkProcessorTest.cc @ENABLE_MESSAGE_DIGEST_TRUE@am__objects_1 = \ @@ -203,7 +212,13 @@ am__aria2c_SOURCES_DIST = AllTest.cc Base64Test.cc SequenceTest.cc \ @ENABLE_BITTORRENT_TRUE@ BtDependencyTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BtPostDownloadHandlerTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ DownloadHandlerFactoryTest.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ TimeSeedCriteriaTest.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ TimeSeedCriteriaTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BencodeVisitorTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ BtExtendedMessageTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ HandshakeExtensionMessageTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ UTPexExtensionMessageTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultBtMessageFactoryTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ DefaultExtensionMessageFactoryTest.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_3 = MetalinkerTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntryTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ Metalink2RequestGroupTest.$(OBJEXT) \ @@ -518,12 +533,14 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AnnounceListTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/AuthConfigFactoryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Base64Test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BencodeVisitorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BitfieldManTest.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)/BtDependencyTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtExtendedMessageTest.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@ @@ -549,9 +566,11 @@ distclean-compile: @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)/DefaultBtMessageFactoryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultBtProgressInfoFileTest.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)/DefaultExtensionMessageFactoryTest.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@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultPieceStorageTest.Po@am__quote@ @@ -562,6 +581,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FileUriListParserTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/GrowSegmentTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HandshakeExtensionMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpHeaderProcessorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpHeaderTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/HttpRequestTest.Po@am__quote@ @@ -604,6 +624,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SpeedCalcTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/StreamUriListParserTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/TimeSeedCriteriaTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UTPexExtensionMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/UtilTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/a2functionalTest.Po@am__quote@ diff --git a/test/MockBtMessageFactory.h b/test/MockBtMessageFactory.h index bcfd1d08..f4b063f7 100644 --- a/test/MockBtMessageFactory.h +++ b/test/MockBtMessageFactory.h @@ -3,6 +3,9 @@ #include "BtMessageFactory.h" +class ExtensionMessage; +typedef SharedHandle ExensionMessageHandle; + class MockBtMessageFactory : public BtMessageFactory { public: MockBtMessageFactory() {} @@ -84,6 +87,11 @@ public: virtual BtMessageHandle createAllowedFastMessage(int32_t index) { return BtMessageHandle(0); } + + virtual BtMessageHandle createBtExtendedMessage(const ExensionMessageHandle&) + { + return BtMessageHandle(0); + } }; typedef SharedHandle MockBtMessageFactoryHandle; diff --git a/test/MockExtensionMessage.h b/test/MockExtensionMessage.h new file mode 100644 index 00000000..0fdd9a67 --- /dev/null +++ b/test/MockExtensionMessage.h @@ -0,0 +1,51 @@ +#ifndef _D_MOCK_EXTENSION_MESSAGE_H_ +#define _D_MOCK_EXTENSION_MESSAGE_H_ + +#include "ExtensionMessage.h" + +class MockExtensionMessage:public ExtensionMessage { +public: + string _extensionName; + uint8_t _extensionMessageID; + string _data; + bool _doReceivedActionCalled; +public: + MockExtensionMessage(const string& extensionName, + uint8_t extensionMessageID, + const char* data, + size_t length):_extensionName(extensionName), + _extensionMessageID(extensionMessageID), + _data(&data[0], &data[length]), + _doReceivedActionCalled(false) {} + + virtual ~MockExtensionMessage() {} + + virtual string getBencodedData() + { + return _data; + } + + virtual uint8_t getExtensionMessageID() + { + return _extensionMessageID; + } + + virtual const string& getExtensionName() const + { + return _extensionName; + } + + virtual string toString() const + { + return _extensionName; + } + + virtual void doReceivedAction() + { + _doReceivedActionCalled = true; + } +}; + +typedef SharedHandle MockExtensionMessageHandle; + +#endif // _D_MOCK_EXTENSION_MESSAGE_H_ diff --git a/test/MockExtensionMessageFactory.h b/test/MockExtensionMessageFactory.h new file mode 100644 index 00000000..f9789be1 --- /dev/null +++ b/test/MockExtensionMessageFactory.h @@ -0,0 +1,20 @@ +#ifndef _D_MOCK_EXTENSION_MESSAGE_FACTORY_H_ +#define _D_MOCK_EXTENSION_MESSAGE_FACTORY_H_ + +#include "ExtensionMessageFactory.h" +#include "MockExtensionMessage.h" + +class MockExtensionMessageFactory:public ExtensionMessageFactory { +public: + virtual ~MockExtensionMessageFactory() {} + + virtual ExtensionMessageHandle createMessage(const char* data, + size_t length) + { + return new MockExtensionMessage("a2_mock", *data, data+1, length-1); + + } +}; + +typedef SharedHandle MockExtensionMessageFactoryHandle; +#endif // _D_MOCK_EXTENSION_MESSAGE_FACTORY_H_ diff --git a/test/ShaVisitorTest.cc b/test/ShaVisitorTest.cc index 28fc4a00..c9e8d1cb 100644 --- a/test/ShaVisitorTest.cc +++ b/test/ShaVisitorTest.cc @@ -51,12 +51,13 @@ void ShaVisitorTest::testVisit() { void ShaVisitorTest::testVisitCompound() { ShaVisitor v; - MetaEntry* e = MetaFileUtil::parseMetaFile("test.torrent"); + string data = "d4:name5:aria24:listli123eee"; + MetaEntry* e = MetaFileUtil::bdecoding(data.c_str(), data.size()); e->accept(&v); unsigned char md[20]; int len = 0; v.getHash(md, len); string hashHex = hexHash(md, len); - CPPUNIT_ASSERT_EQUAL(string("5a2bf55fb6ec71a9cd3e06537aa7795cafccffab"), + CPPUNIT_ASSERT_EQUAL(string("75538fbac9a074bb98c6a19b6bca3bc87ef9bf8e"), hashHex); } diff --git a/test/UTPexExtensionMessageTest.cc b/test/UTPexExtensionMessageTest.cc new file mode 100644 index 00000000..1b837802 --- /dev/null +++ b/test/UTPexExtensionMessageTest.cc @@ -0,0 +1,187 @@ +#include "UTPexExtensionMessage.h" +#include "Peer.h" +#include "a2netcompat.h" +#include "Util.h" +#include "PeerMessageUtil.h" +#include "BtRegistry.h" +#include "MockBtContext.h" +#include "MockPeerStorage.h" +#include + +class UTPexExtensionMessageTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(UTPexExtensionMessageTest); + CPPUNIT_TEST(testGetExtensionMessageID); + CPPUNIT_TEST(testGetExtensionName); + CPPUNIT_TEST(testGetBencodedData); + CPPUNIT_TEST(testToString); + CPPUNIT_TEST(testDoReceivedAction); + CPPUNIT_TEST(testCreate); + CPPUNIT_TEST_SUITE_END(); +private: + MockBtContextHandle _btContext; +public: + UTPexExtensionMessageTest():_btContext(0) {} + + void setUp() + { + BtRegistry::unregisterAll(); + MockBtContextHandle btContext = new MockBtContext(); + unsigned char infohash[20]; + memset(infohash, 0, sizeof(infohash)); + btContext->setInfoHash(infohash); + _btContext = btContext; + MockPeerStorageHandle peerStorage = new MockPeerStorage(); + BtRegistry::registerPeerStorage(_btContext->getInfoHashAsString(), + peerStorage); + } + + void tearDown() + { + BtRegistry::unregisterAll(); + } + + void testGetExtensionMessageID(); + void testGetExtensionName(); + void testGetBencodedData(); + void testToString(); + void testDoReceivedAction(); + void testCreate(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(UTPexExtensionMessageTest); + +void UTPexExtensionMessageTest::testGetExtensionMessageID() +{ + UTPexExtensionMessage msg(1); + CPPUNIT_ASSERT_EQUAL((uint8_t)1, msg.getExtensionMessageID()); +} + +void UTPexExtensionMessageTest::testGetExtensionName() +{ + UTPexExtensionMessage msg(1); + CPPUNIT_ASSERT_EQUAL(string("ut_pex"), msg.getExtensionName()); +} + +void UTPexExtensionMessageTest::testGetBencodedData() +{ + UTPexExtensionMessage msg(1); + PeerHandle p1 = new Peer("192.168.0.1", 6881, 1, 1); + p1->setAllBitfield(); + msg.addFreshPeer(p1);// added seeder, check add.f flag + PeerHandle p2 = new Peer("10.1.1.2", 9999, 1, 1); + msg.addFreshPeer(p2); + PeerHandle p3 = new Peer("192.168.0.2", 6882, 1, 1); + msg.addDroppedPeer(p3); + PeerHandle p4 = new Peer("10.1.1.3", 10000, 1, 1); + msg.addDroppedPeer(p4); + + char c1[6]; + char c2[6]; + char c3[6]; + char c4[6]; + PeerMessageUtil::createcompact(c1, p1->ipaddr, p1->port); + PeerMessageUtil::createcompact(c2, p2->ipaddr, p2->port); + PeerMessageUtil::createcompact(c3, p3->ipaddr, p3->port); + PeerMessageUtil::createcompact(c4, p4->ipaddr, p4->port); + + string expected = "d5:added12:"+ + string(&c1[0], &c1[6])+string(&c2[0], &c2[6])+ + "7:added.f2:207:dropped12:"+ + string(&c3[0], &c3[6])+string(&c4[0], &c4[6])+ + "e"; + string bd = msg.getBencodedData(); + CPPUNIT_ASSERT_EQUAL(Util::urlencode(expected), + Util::urlencode(bd)); +} + +void UTPexExtensionMessageTest::testToString() +{ + UTPexExtensionMessage msg(1); + PeerHandle p1 = new Peer("192.168.0.1", 6881, 1, 1); + p1->setAllBitfield(); + msg.addFreshPeer(p1);// added seeder, check add.f flag + PeerHandle p2 = new Peer("10.1.1.2", 9999, 1, 1); + msg.addFreshPeer(p2); + PeerHandle p3 = new Peer("192.168.0.2", 6882, 1, 1); + msg.addDroppedPeer(p3); + PeerHandle p4 = new Peer("10.1.1.3", 10000, 1, 1); + msg.addDroppedPeer(p4); + CPPUNIT_ASSERT_EQUAL(string("ut_pex added=2, dropped=2"), msg.toString()); +} + +void UTPexExtensionMessageTest::testDoReceivedAction() +{ + UTPexExtensionMessage msg(1); + PeerHandle p1 = new Peer("192.168.0.1", 6881, 1, 1); + p1->setAllBitfield(); + msg.addFreshPeer(p1);// added seeder, check add.f flag + PeerHandle p2 = new Peer("10.1.1.2", 9999, 1, 1); + msg.addFreshPeer(p2); + PeerHandle p3 = new Peer("192.168.0.2", 6882, 1, 1); + msg.addDroppedPeer(p3); + PeerHandle p4 = new Peer("10.1.1.3", 10000, 1, 1); + msg.addDroppedPeer(p4); + msg.setBtContext(_btContext); + + msg.doReceivedAction(); + + CPPUNIT_ASSERT_EQUAL((size_t)2, PEER_STORAGE(_btContext)->getPeers().size()); + { + PeerHandle p = PEER_STORAGE(_btContext)->getPeers()[0]; + CPPUNIT_ASSERT_EQUAL(string("192.168.0.1"), p->ipaddr); + CPPUNIT_ASSERT_EQUAL((uint16_t)6881, p->port); + } + { + PeerHandle p = PEER_STORAGE(_btContext)->getPeers()[1]; + CPPUNIT_ASSERT_EQUAL(string("10.1.1.2"), p->ipaddr); + CPPUNIT_ASSERT_EQUAL((uint16_t)9999, p->port); + } +} + +void UTPexExtensionMessageTest::testCreate() +{ + _btContext->setPieceLength(256*1024); + _btContext->setTotalLength(1024*1024); + + char c1[6]; + char c2[6]; + char c3[6]; + char c4[6]; + PeerMessageUtil::createcompact(c1, "192.168.0.1", 6881); + PeerMessageUtil::createcompact(c2, "10.1.1.2", 9999); + PeerMessageUtil::createcompact(c3, "192.168.0.2", 6882); + PeerMessageUtil::createcompact(c4, "10.1.1.3",10000); + + char id[1] = { 1 }; + + string data = string(&id[0], &id[1])+"d5:added12:"+ + string(&c1[0], &c1[6])+string(&c2[0], &c2[6])+ + "7:added.f2:207:dropped12:"+ + string(&c3[0], &c3[6])+string(&c4[0], &c4[6])+ + "e"; + + UTPexExtensionMessageHandle msg = + UTPexExtensionMessage::create(_btContext, data.c_str(), data.size()); + CPPUNIT_ASSERT_EQUAL((uint8_t)1, msg->getExtensionMessageID()); + CPPUNIT_ASSERT_EQUAL((size_t)2, msg->getFreshPeers().size()); + CPPUNIT_ASSERT_EQUAL(string("192.168.0.1"), msg->getFreshPeers()[0]->ipaddr); + CPPUNIT_ASSERT_EQUAL((uint16_t)6881, msg->getFreshPeers()[0]->port); + CPPUNIT_ASSERT_EQUAL(string("10.1.1.2"), msg->getFreshPeers()[1]->ipaddr); + CPPUNIT_ASSERT_EQUAL((uint16_t)9999, msg->getFreshPeers()[1]->port); + CPPUNIT_ASSERT_EQUAL((size_t)2, msg->getDroppedPeers().size()); + CPPUNIT_ASSERT_EQUAL(string("192.168.0.2"), msg->getDroppedPeers()[0]->ipaddr); + CPPUNIT_ASSERT_EQUAL((uint16_t)6882, msg->getDroppedPeers()[0]->port); + CPPUNIT_ASSERT_EQUAL(string("10.1.1.3"), msg->getDroppedPeers()[1]->ipaddr); + CPPUNIT_ASSERT_EQUAL((uint16_t)10000, msg->getDroppedPeers()[1]->port); + try { + // 0 length data + string in = ""; + UTPexExtensionMessage::create(_btContext, in.c_str(), in.size()); + CPPUNIT_FAIL("exception must be thrown."); + } catch(Exception* e) { + cerr << *e << endl; + delete e; + } +} diff --git a/test/test.torrent b/test/test.torrent index 18c616b1..09e622fa 100644 --- a/test/test.torrent +++ b/test/test.torrent @@ -1 +1 @@ -d8:announce36:http://aria.rednoah.com/announce.php13:announce-listll16:http://tracker1 el15:http://tracker2el15:http://tracker3ee7:comment17:REDNOAH.COM RULES13:creation datei1123456789e4:infod5:filesld6:lengthi284e4:pathl5:aria23:src6:aria2ceed6:lengthi100e4:pathl19:aria2-0.2.2.tar.bz2eee4:name10:aria2-test12:piece lengthi128e6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCee \ No newline at end of file +d8:announce36:http://aria.rednoah.com/announce.php13:announce-listll16:http://tracker1 el15:http://tracker2el15:http://tracker3ee7:privatei1e7:comment17:REDNOAH.COM RULES13:creation datei1123456789e4:infod5:filesld6:lengthi284e4:pathl5:aria23:src6:aria2ceed6:lengthi100e4:pathl19:aria2-0.2.2.tar.bz2eee4:name10:aria2-test12:piece lengthi128e6:pieces60:AAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCee \ No newline at end of file