summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog59
-rw-r--r--src/BencodeVisitor.cc84
-rw-r--r--src/BencodeVisitor.h64
-rw-r--r--src/BtConstants.h43
-rw-r--r--src/BtContext.h9
-rw-r--r--src/BtExtendedMessage.cc115
-rw-r--r--src/BtExtendedMessage.h79
-rw-r--r--src/BtHandshakeMessage.cc7
-rw-r--r--src/BtHandshakeMessage.h2
-rw-r--r--src/BtMessageFactory.h5
-rw-r--r--src/BtRegistry.h3
-rw-r--r--src/BtRuntime.h35
-rw-r--r--src/CompactPeerListProcessor.cc18
-rw-r--r--src/Data.cc23
-rw-r--r--src/Data.h3
-rw-r--r--src/DefaultBtContext.cc7
-rw-r--r--src/DefaultBtInteractive.cc83
-rw-r--r--src/DefaultBtInteractive.h12
-rw-r--r--src/DefaultBtMessageFactory.cc18
-rw-r--r--src/DefaultBtMessageFactory.h2
-rw-r--r--src/DefaultBtMessageReceiver.cc9
-rw-r--r--src/DefaultExtensionMessageFactory.cc93
-rw-r--r--src/DefaultExtensionMessageFactory.h70
-rw-r--r--src/DefaultPeerStorage.cc29
-rw-r--r--src/DefaultPeerStorage.h2
-rw-r--r--src/ExtensionMessage.h57
-rw-r--r--src/ExtensionMessageFactory.h51
-rw-r--r--src/HandshakeExtensionMessage.cc174
-rw-r--r--src/HandshakeExtensionMessage.h128
-rw-r--r--src/Makefile.am7
-rw-r--r--src/Makefile.in30
-rw-r--r--src/MetaEntry.h1
-rw-r--r--src/MetaFileUtil.cc18
-rw-r--r--src/Peer.cc31
-rw-r--r--src/Peer.h34
-rw-r--r--src/PeerInteractionCommand.cc3
-rw-r--r--src/PeerMessageUtil.cc14
-rw-r--r--src/PeerMessageUtil.h10
-rw-r--r--src/PeerObject.h7
-rw-r--r--src/PeerReceiveHandshakeCommand.cc29
-rw-r--r--src/UTPexExtensionMessage.cc149
-rw-r--r--src/UTPexExtensionMessage.h99
-rw-r--r--src/message.h4
-rw-r--r--src/option_processing.cc1
-rw-r--r--src/prefs.h2
-rw-r--r--test/BencodeVisitorTest.cc70
-rw-r--r--test/BtExtendedMessageTest.cc121
-rw-r--r--test/BtHandshakeMessageTest.cc6
-rw-r--r--test/DefaultBtMessageFactoryTest.cc78
-rw-r--r--test/DefaultExtensionMessageFactoryTest.cc113
-rw-r--r--test/DefaultPeerListProcessorTest.cc6
-rw-r--r--test/DefaultPeerStorageTest.cc5
-rw-r--r--test/HandshakeExtensionMessageTest.cc155
-rw-r--r--test/Makefile.am8
-rw-r--r--test/Makefile.in29
-rw-r--r--test/MockBtMessageFactory.h8
-rw-r--r--test/MockExtensionMessage.h51
-rw-r--r--test/MockExtensionMessageFactory.h20
-rw-r--r--test/ShaVisitorTest.cc5
-rw-r--r--test/UTPexExtensionMessageTest.cc187
-rw-r--r--test/test.torrent2
61 files changed, 2487 insertions, 100 deletions
diff --git a/ChangeLog b/ChangeLog
index 3258f88c..21b5a5c0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,62 @@
+2007-12-22 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
+
+ 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 <tujikawa at rednoah dot com>
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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#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<const Data*>(e) != 0) {
+ visit((const Data*)e);
+ } else if(dynamic_cast<const List*>(e) != 0) {
+ visit((const List*)e);
+ } else if(dynamic_cast<const Dictionary*>(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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BT_CONSTANTS_
+#define _D_BT_CONSTANTS_
+
+#include "common.h"
+#include <map>
+
+typedef map<string, uint8_t> 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<AnnounceTierHandle> 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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_BT_EXTENDED_MESSAGE_H_
+#define _D_BT_EXTENDED_MESSAGE_H_
+#include "SimpleBtMessage.h"
+
+class BtExtendedMessage;
+typedef SharedHandle<BtExtendedMessage> BtExtendedMessageHandle;
+class ExtensionMessage;
+typedef SharedHandle<ExtensionMessage> 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<ExtensionMessage> 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<BtMessageFactory> 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<BtRuntime> 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<const Data*>(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<DefaultBtInteractive> 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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_DEFAULT_EXTENSION_MESSAGE_FACTORY_H_
+#define _D_DEFAULT_EXTENSION_MESSAGE_FACTORY_H_
+
+#include "ExtensionMessageFactory.h"
+
+class BtContext;
+typedef SharedHandle<BtContext> BtContextHandle;
+class Peer;
+typedef SharedHandle<Peer> 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<DefaultExtensionMessageFactory> 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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#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<ExtensionMessage> 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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_EXTENSION_MESSAGE_FACTORY_H_
+#define _D_EXTENSION_MESSAGE_FACTORY_H_
+
+#include "common.h"
+
+class ExtensionMessage;
+typedef SharedHandle<ExtensionMessage> ExtensionMessageHandle;
+
+class ExtensionMessageFactory {
+public:
+ virtual ~ExtensionMessageFactory() {}
+
+ virtual ExtensionMessageHandle createMessage(const char* data, size_t length) = 0;
+};
+
+typedef SharedHandle<ExtensionMessageFactory> 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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#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<Dictionary> 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<string, uint8_t>::const_iterator itr = _extensions.begin();
+ itr != _extensions.end(); ++itr) {
+ const map<string, uint8_t>::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<string, uint8_t>::const_iterator itr = _extensions.begin();
+ itr != _extensions.end(); ++itr) {
+ const map<string, uint8_t>::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<string, uint8_t>::const_iterator itr = _extensions.begin();
+ itr != _extensions.end(); ++itr) {
+ const map<string, uint8_t>::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<string, uint8_t>::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<MetaEntry> root = MetaFileUtil::bdecoding(data+1, length-1);
+ Dictionary* d = dynamic_cast<Dictionary*>(root.get());
+ if(d == 0) {
+ throw new DlAbortEx("Unexpected payload format for extended message handshake");
+ }
+ const Data* p = dynamic_cast<const Data*>(d->get("p"));
+ if(p) {
+ msg->_tcpPort = p->toInt();
+ }
+ const Data* v = dynamic_cast<const Data*>(d->get("v"));
+ if(v) {
+ msg->_clientVersion = v->toString();
+ }
+ const Dictionary* m = dynamic_cast<const Dictionary*>(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<const Data*>(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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_HANDSHAKE_EXTENSION_MESSAGE_H_
+#define _D_HANDSHAKE_EXTENSION_MESSAGE_H_
+
+#include "ExtensionMessage.h"
+#include "BtConstants.h"
+
+class BtContext;
+typedef SharedHandle<BtContext> BtContextHandle;
+class Peer;
+typedef SharedHandle<Peer> PeerHandle;
+class HandshakeExtensionMessage;
+typedef SharedHandle<HandshakeExtensionMessage> HandshakeExtensionMessageHandle;
+class Logger;
+
+class HandshakeExtensionMessage:public ExtensionMessage {
+private:
+ string _clientVersion;
+
+ uint16_t _tcpPort;
+
+ map<string, uint8_t> _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<HandshakeExtensionMessage> 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<MetaEntry> 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 <string.h>
#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<Peer> 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<PeerObject> 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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#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<Dictionary> d = new Dictionary();
+ pair<string, string> freshPeerPair = createCompactPeerListAndFlag(_freshPeers);
+ pair<string, string> 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<string, string> 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<string, string>(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<MetaEntry> root = MetaFileUtil::bdecoding(data+1, len-1);
+ if(root.isNull()) {
+ return msg;
+ }
+ const Dictionary* d = dynamic_cast<const Dictionary*>(root.get());
+ if(d) {
+ CompactPeerListProcessor proc(btContext->getPieceLength(),
+ btContext->getTotalLength());
+ const Data* added = dynamic_cast<const Data*>(d->get("added"));
+ if(added) {
+ msg->_freshPeers = proc.extractPeer(added);
+ }
+ const Data* dropped = dynamic_cast<const Data*>(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 @@
+/* <!-- copyright */
+/*
+ * aria2 - The high speed download utility
+ *
+ * Copyright (C) 2006 Tatsuhiro Tsujikawa
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL. If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so. If you
+ * do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+/* copyright --> */
+#ifndef _D_UT_PEX_EXTENSION_MESSAGE_H_
+#define _D_UT_PEX_EXTENSION_MESSAGE_H_
+
+#include "ExtensionMessage.h"
+
+class BtContext;
+typedef SharedHandle<BtContext> BtContextHandle;
+class Peer;
+typedef SharedHandle<Peer> PeerHandle;
+typedef deque<PeerHandle> Peers;
+class UTPexExtensionMessage;
+typedef SharedHandle<UTPexExtensionMessage> UTPexExtensionMessageHandle;
+
+class UTPexExtensionMessage:public ExtensionMessage {
+private:
+ uint8_t _extensionMessageID;
+
+ Peers _freshPeers;
+
+ Peers _droppedPeers;
+
+ BtContextHandle _btContext;
+
+ pair<string, string> 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<UTPexExtensionMessage> 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 <cppunit/extensions/HelperMacros.h>
+
+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 <cppunit/extensions/HelperMacros.h>
+
+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 <cppunit/extensions/HelperMacros.h>
+
+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 <cppunit/extensions/HelperMacros.h>
+
+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 <cppunit/extensions/HelperMacros.h>
+
+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<ExtensionMessage> 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<MockBtMessageFactory> 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<MockExtensionMessage> 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<MockExtensionMessageFactory> 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 <cppunit/extensions/HelperMacros.h>
+
+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