2008-02-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

Catch exception inside DHTMessageReceiver::receiveMessage().
	Log unknown message.
	* src/DHTMessageReceiver.{h, cc}
	* src/DHTMessageFactory.h
	* src/DHTMessageFactoryImpl.{h, cc}
	* src/DHTMessageTracker.cc (handleTimeout): Catch and handle exception.
	* src/DHTInteractionCommand.cc
	* src/DHTUnknownMessage.{h, cc}
	* test/DHTUnknownMessageTest.cc
	* test/MockDHTMessageFactory.h
pull/1/head
Tatsuhiro Tsujikawa 2008-02-05 14:15:50 +00:00
parent 20621d011d
commit bdb1a25ca7
16 changed files with 335 additions and 64 deletions

View File

@ -1,3 +1,16 @@
2008-02-05 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Catch exception inside DHTMessageReceiver::receiveMessage().
Log unknown message.
* src/DHTMessageReceiver.{h, cc}
* src/DHTMessageFactory.h
* src/DHTMessageFactoryImpl.{h, cc}
* src/DHTMessageTracker.cc (handleTimeout): Catch and handle exception.
* src/DHTInteractionCommand.cc
* src/DHTUnknownMessage.{h, cc}
* test/DHTUnknownMessageTest.cc
* test/MockDHTMessageFactory.h
2008-02-02 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Commented out ip address comparison because a host can have multiple

View File

@ -76,16 +76,14 @@ bool DHTInteractionCommand::execute()
_taskQueue->executeTask();
for(size_t i = 0; i < 20 && _readCheckSocket->isReadable(0); ++i) {
try {
_receiver->receiveMessage();
} catch(RecoverableException* e) {
logger->error(EX_EXCEPTION_CAUGHT, e);
delete e;
for(size_t i = 0; i < 20; ++i) {
SharedHandle<DHTMessage> m = _receiver->receiveMessage();
if(m.isNull()) {
break;
}
}
_receiver->handleTimeout();
try {
_receiver->handleTimeout();
_dispatcher->sendMessages();
} catch(RecoverableException* e) {
logger->error(EX_EXCEPTION_CAUGHT, e);

View File

@ -102,6 +102,9 @@ public:
createAnnouncePeerReplyMessage(const DHTNodeHandle& remoteNode,
const string& transactionID) = 0;
virtual DHTMessageHandle
createUnknownMessage(const char* data, size_t length, const string& ipaddr,
uint16_t port) = 0;
};
#endif // _D_DHT_MESSAGE_FACTORY_H_

View File

@ -48,6 +48,7 @@
#include "DHTGetPeersReplyMessage.h"
#include "DHTAnnouncePeerMessage.h"
#include "DHTAnnouncePeerReplyMessage.h"
#include "DHTUnknownMessage.h"
#include "DHTConnection.h"
#include "DHTMessageDispatcher.h"
#include "DHTPeerAnnounceStorage.h"
@ -387,6 +388,16 @@ DHTMessageFactoryImpl::createAnnouncePeerReplyMessage(const DHTNodeHandle& remot
return m;
}
DHTMessageHandle
DHTMessageFactoryImpl::createUnknownMessage(const char* data, size_t length,
const string& ipaddr, uint16_t port)
{
SharedHandle<DHTUnknownMessage> m =
new DHTUnknownMessage(_localNode, data, length, ipaddr, port);
return m;
}
void DHTMessageFactoryImpl::setRoutingTable(const DHTRoutingTableHandle& routingTable)
{
_routingTable = routingTable;

View File

@ -152,6 +152,10 @@ public:
createAnnouncePeerReplyMessage(const DHTNodeHandle& remoteNode,
const string& transactionID);
virtual DHTMessageHandle
createUnknownMessage(const char* data, size_t length, const string& ipaddr,
uint16_t port);
void setRoutingTable(const DHTRoutingTableHandle& routingTable);
void setConnection(const DHTConnectionHandle& connection);

View File

@ -67,40 +67,47 @@ DHTMessageHandle DHTMessageReceiver::receiveMessage()
if(length <= 0) {
return 0;
}
bool isReply = false;
MetaEntryHandle msgroot = MetaFileUtil::bdecoding(data, length);
const Dictionary* d = dynamic_cast<const Dictionary*>(msgroot.get());
if(d) {
const Data* y = dynamic_cast<const Data*>(d->get("y"));
if(y->toString() == "r" || y->toString() == "e") {
isReply = true;
try {
bool isReply = false;
MetaEntryHandle msgroot = MetaFileUtil::bdecoding(data, length);
const Dictionary* d = dynamic_cast<const Dictionary*>(msgroot.get());
if(d) {
const Data* y = dynamic_cast<const Data*>(d->get("y"));
if(y->toString() == "r" || y->toString() == "e") {
isReply = true;
}
} else {
_logger->info("Malformed DHT message. This is not a bencoded directory. From:%s:%u", remoteAddr.c_str(), remotePort);
return handleUnknownMessage(data, sizeof(data), remoteAddr, remotePort);
}
} else {
throw new DlAbortEx("Malformed DHT message. From:%s:%u", remoteAddr.c_str(), remotePort);
}
DHTMessageHandle message = 0;
DHTMessageCallbackHandle callback = 0;
if(isReply) {
std::pair<DHTMessageHandle, DHTMessageCallbackHandle> p = _tracker->messageArrived(d, remoteAddr, remotePort);
message = p.first;
callback = p.second;
if(message.isNull()) {
// timeout or malicious message
return 0;
DHTMessageHandle message = 0;
DHTMessageCallbackHandle callback = 0;
if(isReply) {
std::pair<DHTMessageHandle, DHTMessageCallbackHandle> p = _tracker->messageArrived(d, remoteAddr, remotePort);
message = p.first;
callback = p.second;
if(message.isNull()) {
// timeout or malicious? message
return handleUnknownMessage(data, sizeof(data), remoteAddr, remotePort);
}
} else {
message = _factory->createQueryMessage(d, remoteAddr, remotePort);
}
} else {
message = _factory->createQueryMessage(d, remoteAddr, remotePort);
_logger->info("Message received: %s", message->toString().c_str());
message->validate();
message->doReceivedAction();
message->getRemoteNode()->markGood();
message->getRemoteNode()->updateLastContact();
_routingTable->addGoodNode(message->getRemoteNode());
if(!callback.isNull()) {
callback->onReceived(message);
}
return message;
} catch(RecoverableException* e) {
_logger->info("Exception thrown while receiving DHT message.", e);
delete e;
return handleUnknownMessage(data, sizeof(data), remoteAddr, remotePort);
}
_logger->info("Message received: %s", message->toString().c_str());
message->validate();
message->doReceivedAction();
message->getRemoteNode()->markGood();
message->getRemoteNode()->updateLastContact();
_routingTable->addGoodNode(message->getRemoteNode());
if(!callback.isNull()) {
callback->onReceived(message);
}
return message;
}
void DHTMessageReceiver::handleTimeout()
@ -108,6 +115,17 @@ void DHTMessageReceiver::handleTimeout()
_tracker->handleTimeout();
}
SharedHandle<DHTMessage>
DHTMessageReceiver::handleUnknownMessage(const char* data, size_t length,
const string& remoteAddr,
uint16_t remotePort)
{
SharedHandle<DHTMessage> m =
_factory->createUnknownMessage(data, length, remoteAddr, remotePort);
_logger->info("Message received: %s", m->toString().c_str());
return m;
}
DHTConnectionHandle DHTMessageReceiver::getConnection() const
{
return _connection;

View File

@ -56,12 +56,15 @@ private:
DHTRoutingTableHandle _routingTable;
const Logger* _logger;
SharedHandle<DHTMessage>
handleUnknownMessage(const char* data, size_t length,
const string& remoteAddr, uint16_t remotePort);
public:
DHTMessageReceiver(const DHTMessageTrackerHandle& tracker);
~DHTMessageReceiver();
// caller must handle thrown exception.
DHTMessageHandle receiveMessage();
void handleTimeout();

View File

@ -99,21 +99,26 @@ void DHTMessageTracker::handleTimeout()
for(DHTMessageTrackerEntries::iterator i = _entries.begin();
i != _entries.end();) {
if((*i)->isTimeout()) {
DHTMessageTrackerEntryHandle entry = *i;
i = _entries.erase(i);
DHTNodeHandle node = entry->getTargetNode();
_logger->debug("Message timeout: To:%s:%u",
node->getIPAddress().c_str(), node->getPort());
node->updateRTT(entry->getElapsedMillis());
node->timeout();
if(node->isBad()) {
_logger->debug("Marked bad: %s:%u",
try {
DHTMessageTrackerEntryHandle entry = *i;
i = _entries.erase(i);
DHTNodeHandle node = entry->getTargetNode();
_logger->debug("Message timeout: To:%s:%u",
node->getIPAddress().c_str(), node->getPort());
_routingTable->dropNode(node);
}
DHTMessageCallbackHandle callback = entry->getCallback();
if(!callback.isNull()) {
callback->onTimeout(node);
node->updateRTT(entry->getElapsedMillis());
node->timeout();
if(node->isBad()) {
_logger->debug("Marked bad: %s:%u",
node->getIPAddress().c_str(), node->getPort());
_routingTable->dropNode(node);
}
DHTMessageCallbackHandle callback = entry->getCallback();
if(!callback.isNull()) {
callback->onTimeout(node);
}
} catch(RecoverableException* e) {
delete e;
_logger->info("Exception thrown while handling timeouts.");
}
} else {
++i;

87
src/DHTUnknownMessage.cc Normal file
View File

@ -0,0 +1,87 @@
/* <!-- 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 "DHTUnknownMessage.h"
#include "DHTNode.h"
#include "Util.h"
#include <cstring>
DHTUnknownMessage::DHTUnknownMessage(const DHTNodeHandle& localNode,
const char* data, size_t length,
const string& ipaddr, uint16_t port):
DHTMessage(localNode, 0),
_length(length),
_ipaddr(ipaddr),
_port(port)
{
if(_length == 0) {
_data = 0;
} else {
_data = new char[length];
memcpy(_data, data, length);
}
}
DHTUnknownMessage::~DHTUnknownMessage()
{
delete [] _data;
}
void DHTUnknownMessage::doReceivedAction() {}
void DHTUnknownMessage::send() {}
bool DHTUnknownMessage::isReply() const
{
return false;
}
void DHTUnknownMessage::validate() const {}
string DHTUnknownMessage::getMessageType() const
{
return "unknown";
}
string DHTUnknownMessage::toString() const
{
size_t sampleLength = 8;
if(_length < sampleLength) {
sampleLength = _length;
}
string sample = string(&_data[0], &_data[sampleLength]);
return "dht unknown Remote:"+_ipaddr+":"+Util::uitos(_port)+" length="+
Util::uitos(_length)+", first 8 bytes(hex)="+Util::toHex(sample);
}

72
src/DHTUnknownMessage.h Normal file
View File

@ -0,0 +1,72 @@
/* <!-- 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_DHT_UNKNOWN_MESSAGE_H_
#define _D_DHT_UNKNOWN_MESSAGE_H_
#include "DHTMessage.h"
class DHTUnknownMessage:public DHTMessage {
private:
char* _data;
size_t _length;
string _ipaddr;
uint16_t _port;
public:
// _remoteNode is always null
DHTUnknownMessage(const DHTNodeHandle& localNode,
const char* data, size_t length,
const string& ipaddr, uint16_t port);
virtual ~DHTUnknownMessage();
// do nothing
virtual void doReceivedAction();
// do nothing; we don't use this message as outgoing message.
virtual void send();
// always return false
virtual bool isReply() const;
virtual void validate() const;
// returns "unknown"
virtual string getMessageType() const;
// show some sample bytes
virtual string toString() const;
};
#endif // _D_DHT_UNKNOWN_MESSAGE_H_

View File

@ -280,6 +280,7 @@ SRCS += MetaEntry.h\
DHTGetPeersReplyMessage.cc\
DHTAnnouncePeerMessage.cc\
DHTAnnouncePeerReplyMessage.cc\
DHTUnknownMessage.cc\
DHTMessageFactoryImpl.cc\
DHTNodeLookupTask.cc\
DHTNodeLookupEntry.cc\

View File

@ -163,6 +163,7 @@ bin_PROGRAMS = aria2c$(EXEEXT)
@ENABLE_BITTORRENT_TRUE@ DHTGetPeersReplyMessage.cc\
@ENABLE_BITTORRENT_TRUE@ DHTAnnouncePeerMessage.cc\
@ENABLE_BITTORRENT_TRUE@ DHTAnnouncePeerReplyMessage.cc\
@ENABLE_BITTORRENT_TRUE@ DHTUnknownMessage.cc\
@ENABLE_BITTORRENT_TRUE@ DHTMessageFactoryImpl.cc\
@ENABLE_BITTORRENT_TRUE@ DHTNodeLookupTask.cc\
@ENABLE_BITTORRENT_TRUE@ DHTNodeLookupEntry.cc\
@ -427,17 +428,17 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
DHTPingMessage.cc DHTPingReplyMessage.cc DHTFindNodeMessage.cc \
DHTFindNodeReplyMessage.cc DHTGetPeersMessage.cc \
DHTGetPeersReplyMessage.cc DHTAnnouncePeerMessage.cc \
DHTAnnouncePeerReplyMessage.cc DHTMessageFactoryImpl.cc \
DHTNodeLookupTask.cc DHTNodeLookupEntry.cc BNode.cc \
DHTMessageCallbackImpl.cc DHTAbstractTask.cc DHTPingTask.cc \
DHTTaskQueueImpl.cc DHTBucketRefreshTask.cc \
DHTAbstractNodeLookupTask.cc DHTPeerLookupTask.cc DHTSetup.cc \
DHTTaskFactoryImpl.cc DHTInteractionCommand.cc \
DHTPeerAnnounceEntry.cc DHTPeerAnnounceStorage.cc \
DHTTokenTracker.cc DHTGetPeersCommand.cc \
DHTTokenUpdateCommand.cc DHTBucketRefreshCommand.cc \
DHTPeerAnnounceCommand.cc DHTReplaceNodeTask.cc \
DHTEntryPointNameResolveCommand.cc \
DHTAnnouncePeerReplyMessage.cc DHTUnknownMessage.cc \
DHTMessageFactoryImpl.cc DHTNodeLookupTask.cc \
DHTNodeLookupEntry.cc BNode.cc DHTMessageCallbackImpl.cc \
DHTAbstractTask.cc DHTPingTask.cc DHTTaskQueueImpl.cc \
DHTBucketRefreshTask.cc DHTAbstractNodeLookupTask.cc \
DHTPeerLookupTask.cc DHTSetup.cc DHTTaskFactoryImpl.cc \
DHTInteractionCommand.cc DHTPeerAnnounceEntry.cc \
DHTPeerAnnounceStorage.cc DHTTokenTracker.cc \
DHTGetPeersCommand.cc DHTTokenUpdateCommand.cc \
DHTBucketRefreshCommand.cc DHTPeerAnnounceCommand.cc \
DHTReplaceNodeTask.cc DHTEntryPointNameResolveCommand.cc \
DHTRoutingTableSerializer.cc DHTRoutingTableDeserializer.cc \
DHTAutoSaveCommand.cc DHTRegistry.cc Metalinker.cc \
Metalinker.h MetalinkEntry.cc MetalinkEntry.h \
@ -544,6 +545,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
@ENABLE_BITTORRENT_TRUE@ DHTGetPeersReplyMessage.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DHTAnnouncePeerMessage.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DHTAnnouncePeerReplyMessage.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DHTUnknownMessage.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DHTMessageFactoryImpl.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DHTNodeLookupTask.$(OBJEXT) \
@ENABLE_BITTORRENT_TRUE@ DHTNodeLookupEntry.$(OBJEXT) \
@ -1189,6 +1191,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTTaskQueueImpl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTTokenTracker.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTTokenUpdateCommand.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTUnknownMessage.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DHTUtil.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Data.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/DefaultAuthResolver.Po@am__quote@

View File

@ -0,0 +1,44 @@
#include "DHTUnknownMessage.h"
#include "DHTNode.h"
#include "Exception.h"
#include <cppunit/extensions/HelperMacros.h>
class DHTUnknownMessageTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(DHTUnknownMessageTest);
CPPUNIT_TEST(testToString);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {}
void tearDown() {}
void testToString();
};
CPPUNIT_TEST_SUITE_REGISTRATION(DHTUnknownMessageTest);
void DHTUnknownMessageTest::testToString()
{
DHTNodeHandle localNode = new DHTNode();
string ipaddr = "192.168.0.1";
uint16_t port = 6881;
{
// data.size() > 8
string data = "chocolate";
DHTUnknownMessage msg(localNode, remoteNode, data.c_str(), data.size(),
ipaddr, port);
CPPUNIT_ASSERT_EQUAL(string("dht unknown Remote:192.168.0.1:6881 length=9, first 8 bytes(hex)=63686f636f6c617465"), msg.toString());
}
{
// data.size() == 3
string data = "foo";
DHTUnknownMessage msg(localNode, remoteNode, data.c_str(), data.size(),
ipaddr, port);
CPPUNIT_ASSERT_EQUAL(string("dht unknown Remote:192.168.0.1:6881 length=9, first 8 bytes(hex)=66666f"), msg.toString());
}
}

View File

@ -121,6 +121,7 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\
DHTGetPeersReplyMessageTest.cc\
DHTAnnouncePeerMessageTest.cc\
DHTAnnouncePeerReplyMessageTest.cc\
DHTUnknownMessageTest.cc\
DHTMessageFactoryImplTest.cc\
BNodeTest.cc\
DHTPeerAnnounceEntryTest.cc\

View File

@ -935,6 +935,7 @@ uninstall-am: uninstall-info-am
@ENABLE_BITTORRENT_TRUE@ DHTGetPeersReplyMessageTest.cc\
@ENABLE_BITTORRENT_TRUE@ DHTAnnouncePeerMessageTest.cc\
@ENABLE_BITTORRENT_TRUE@ DHTAnnouncePeerReplyMessageTest.cc\
@ENABLE_BITTORRENT_TRUE@ DHTUnknownMessageTest.cc\
@ENABLE_BITTORRENT_TRUE@ DHTMessageFactoryImplTest.cc\
@ENABLE_BITTORRENT_TRUE@ BNodeTest.cc\
@ENABLE_BITTORRENT_TRUE@ DHTPeerAnnounceEntryTest.cc\

View File

@ -107,6 +107,13 @@ public:
return 0;
}
virtual DHTMessageHandle
createUnknownMessage(const char* data, size_t length, const string& ipaddr,
uint16_t port)
{
return 0;
}
void setLocalNode(const DHTNodeHandle& node)
{
_localNode = node;