Rewritten NAT check handling.

We simplified PeerConnection::receiveHandshake().
DefaultBtMessageReceiver and PeerReceiverHandshakeCommand look
PeerConnection's buffer and do NAT check handling themselves.
pull/1/head
Tatsuhiro Tsujikawa 2011-01-09 23:57:07 +09:00
parent 1818f2ed55
commit 3e67079087
3 changed files with 60 additions and 50 deletions

View File

@ -47,6 +47,9 @@
#include "LogFactory.h" #include "LogFactory.h"
#include "bittorrent_helper.h" #include "bittorrent_helper.h"
#include "BtPieceMessage.h" #include "BtPieceMessage.h"
#include "util.h"
#include "fmt.h"
#include "DlAbortEx.h"
namespace aria2 { namespace aria2 {
@ -60,24 +63,40 @@ DefaultBtMessageReceiver::DefaultBtMessageReceiver():
SharedHandle<BtHandshakeMessage> SharedHandle<BtHandshakeMessage>
DefaultBtMessageReceiver::receiveHandshake(bool quickReply) DefaultBtMessageReceiver::receiveHandshake(bool quickReply)
{ {
A2_LOG_DEBUG
(fmt("Receiving handshake bufferLength=%lu",
static_cast<unsigned long>(peerConnection_->getBufferLength())));
unsigned char data[BtHandshakeMessage::MESSAGE_LENGTH]; unsigned char data[BtHandshakeMessage::MESSAGE_LENGTH];
size_t dataLength = BtHandshakeMessage::MESSAGE_LENGTH; size_t dataLength = BtHandshakeMessage::MESSAGE_LENGTH;
bool retval = peerConnection_->receiveHandshake(data, dataLength); SharedHandle<BtHandshakeMessage> msg;
// To handle tracker's NAT-checking feature if(handshakeSent_ || !quickReply || peerConnection_->getBufferLength() < 48) {
if(!handshakeSent_ && quickReply && dataLength >= 48) { if(peerConnection_->receiveHandshake(data, dataLength)) {
handshakeSent_ = true; msg = messageFactory_->createHandshakeMessage(data, dataLength);
// check info_hash msg->validate();
if(memcmp(bittorrent::getInfoHash(downloadContext_), &data[28],
INFO_HASH_LENGTH) == 0) {
sendHandshake();
} }
} }
if(!retval) { // Handle tracker's NAT-checking feature
return SharedHandle<BtHandshakeMessage>(); if(!handshakeSent_ && quickReply && peerConnection_->getBufferLength() >= 48){
handshakeSent_ = true;
// check info_hash
if(memcmp(bittorrent::getInfoHash(downloadContext_),
peerConnection_->getBuffer()+28,
INFO_HASH_LENGTH) == 0) {
sendHandshake();
} else {
throw DL_ABORT_EX
(fmt("Bad Info Hash %s",
util::toHex(peerConnection_->getBuffer()+28,
INFO_HASH_LENGTH).c_str()));
}
if(!msg &&
peerConnection_->getBufferLength() ==
BtHandshakeMessage::MESSAGE_LENGTH &&
peerConnection_->receiveHandshake(data, dataLength)) {
msg = messageFactory_->createHandshakeMessage(data, dataLength);
msg->validate();
}
} }
SharedHandle<BtHandshakeMessage> msg =
messageFactory_->createHandshakeMessage(data, dataLength);
msg->validate();
return msg; return msg;
} }

View File

@ -182,36 +182,22 @@ bool PeerConnection::receiveHandshake(unsigned char* data, size_t& dataLength,
("More than BtHandshakeMessage::MESSAGE_LENGTH bytes are buffered."); ("More than BtHandshakeMessage::MESSAGE_LENGTH bytes are buffered.");
} }
bool retval = true; bool retval = true;
if(((!prevPeek_ && peek) || (prevPeek_ && !peek)) && resbufLength_) { size_t remaining = BtHandshakeMessage::MESSAGE_LENGTH-resbufLength_;
// We have data in previous peek. if(remaining > 0) {
// There is a chance that socket is readable because of EOF, for example, size_t temp = remaining;
// official bttrack shutdowns socket after sending first 48 bytes of readData(resbuf_+resbufLength_, remaining, encryptionEnabled_);
// handshake in its NAT checking. if(remaining == 0 && !socket_->wantRead() && !socket_->wantWrite()) {
// So if there are data in resbuf_, return it without checking socket // we got EOF
// status. A2_LOG_DEBUG
// (fmt("CUID#%lld - In PeerConnection::receiveHandshake(), remain=%lu",
// (!prevPeek_ && peek) effectively returns preset buffer. cuid_,
prevPeek_ = false; static_cast<unsigned long>(temp)));
retval = BtHandshakeMessage::MESSAGE_LENGTH <= resbufLength_; peer_->setDisconnectedGracefully(true);
} else { throw DL_ABORT_EX(EX_EOF_FROM_PEER);
prevPeek_ = peek; }
size_t remaining = BtHandshakeMessage::MESSAGE_LENGTH-resbufLength_; resbufLength_ += remaining;
if(remaining > 0) { if(BtHandshakeMessage::MESSAGE_LENGTH > resbufLength_) {
size_t temp = remaining; retval = false;
readData(resbuf_+resbufLength_, remaining, encryptionEnabled_);
if(remaining == 0 && !socket_->wantRead() && !socket_->wantWrite()) {
// we got EOF
A2_LOG_DEBUG
(fmt("CUID#%lld - In PeerConnection::receiveHandshake(), remain=%lu",
cuid_,
static_cast<unsigned long>(temp)));
peer_->setDisconnectedGracefully(true);
throw DL_ABORT_EX(EX_EOF_FROM_PEER);
}
resbufLength_ += remaining;
if(BtHandshakeMessage::MESSAGE_LENGTH > resbufLength_) {
retval = false;
}
} }
} }
size_t writeLength = std::min(resbufLength_, dataLength); size_t writeLength = std::min(resbufLength_, dataLength);

View File

@ -33,6 +33,9 @@
*/ */
/* copyright --> */ /* copyright --> */
#include "PeerReceiveHandshakeCommand.h" #include "PeerReceiveHandshakeCommand.h"
#include <cstring>
#include "PeerConnection.h" #include "PeerConnection.h"
#include "DownloadEngine.h" #include "DownloadEngine.h"
#include "BtHandshakeMessage.h" #include "BtHandshakeMessage.h"
@ -87,13 +90,15 @@ bool PeerReceiveHandshakeCommand::exitBeforeExecute()
bool PeerReceiveHandshakeCommand::executeInternal() bool PeerReceiveHandshakeCommand::executeInternal()
{ {
unsigned char data[BtHandshakeMessage::MESSAGE_LENGTH]; // Handle tracker's NAT-checking feature
size_t dataLength = BtHandshakeMessage::MESSAGE_LENGTH; if(peerConnection_->getBufferLength() < 48) {
// ignore return value. The received data is kept in PeerConnection object size_t dataLength = 0;
// because of peek = true. // Ignore return value. The received data is kept in
peerConnection_->receiveHandshake(data, dataLength, true); // PeerConnection object because of peek = true.
// To handle tracker's NAT-checking feature peerConnection_->receiveHandshake(0, dataLength, true);
if(dataLength >= 48) { }
if(peerConnection_->getBufferLength() >= 48) {
const unsigned char* data = peerConnection_->getBuffer();
// check info_hash // check info_hash
std::string infoHash = std::string(&data[28], &data[28+INFO_HASH_LENGTH]); std::string infoHash = std::string(&data[28], &data[28+INFO_HASH_LENGTH]);