diff --git a/ChangeLog b/ChangeLog index d616f74f..52df08b0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +2010-02-20 Tatsuhiro Tsujikawa + + Added Local Peer Discovery. It is disabled by default. Use + --bt-enable-lpd to enable the function. + * src/BtConstants.h + * src/BtSetup.cc + * src/LpdDispatchMessageCommand.cc + * src/LpdDispatchMessageCommand.h + * src/LpdMessage.h + * src/LpdMessageDispatcher.cc + * src/LpdMessageDispatcher.h + * src/LpdMessageReceiver.cc + * src/LpdMessageReceiver.h + * src/LpdReceiveMessageCommand.cc + * src/LpdReceiveMessageCommand.h + * src/Makefile.am + * src/OptionHandlerFactory.cc + * src/Peer.cc + * src/Peer.h + * src/PeerInteractionCommand.cc + * src/SocketCore.cc + * src/SocketCore.h + * src/prefs.cc + * src/prefs.h + * src/usage_text.h + * src/util.cc + * src/util.h + * test/LpdMessageDispatcherTest.cc + * test/LpdMessageReceiverTest.cc + * test/Makefile.am + 2010-02-20 Tatsuhiro Tsujikawa User-defined custom request headers specified by --header option diff --git a/src/BtConstants.h b/src/BtConstants.h index 8e35309c..d590647e 100644 --- a/src/BtConstants.h +++ b/src/BtConstants.h @@ -58,4 +58,8 @@ typedef std::map Extensions; #define METADATA_PIECE_SIZE (16*1024) +#define LPD_MULTICAST_ADDR "239.192.152.143" + +#define LPD_MULTICAST_PORT 6771 + #endif // _D_BT_CONSTANTS_ diff --git a/src/BtSetup.cc b/src/BtSetup.cc index df59fbcf..756f745c 100644 --- a/src/BtSetup.cc +++ b/src/BtSetup.cc @@ -60,6 +60,12 @@ #include "BtRuntime.h" #include "bittorrent_helper.h" #include "BtStopDownloadCommand.h" +#include "LpdReceiveMessageCommand.h" +#include "LpdDispatchMessageCommand.h" +#include "LpdMessageReceiver.h" +#include "LpdMessageDispatcher.h" +#include "message.h" +#include "SocketCore.h" namespace aria2 { @@ -164,6 +170,39 @@ void BtSetup::setup(std::deque& commands, PeerListenCommand* listenCommand = PeerListenCommand::getInstance(e); btRuntime->setListenPort(listenCommand->getPort()); } + if(option->getAsBool(PREF_BT_ENABLE_LPD) && + (metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0)) { + if(LpdReceiveMessageCommand::getNumInstance() == 0) { + SharedHandle receiver + (new LpdMessageReceiver(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT)); + try { + receiver->init(); + receiver->getSocket()->setMulticastTtl(1); + } catch(RecoverableException& e) { + _logger->info(EX_EXCEPTION_CAUGHT, e); + receiver.reset(); + } + if(!receiver.isNull()) { + LpdReceiveMessageCommand* cmd = + LpdReceiveMessageCommand::getInstance(e, receiver); + e->commands.push_back(cmd); + } + } + if(LpdReceiveMessageCommand::getNumInstance()) { + const unsigned char* infoHash = + bittorrent::getInfoHash(requestGroup->getDownloadContext()); + SharedHandle dispatcher + (new LpdMessageDispatcher + (std::string(&infoHash[0], &infoHash[INFO_HASH_LENGTH]), + btRuntime->getListenPort(), + LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, + LpdReceiveMessageCommand::getInstance()->getReceiverSocket())); + LpdDispatchMessageCommand* cmd = + new LpdDispatchMessageCommand(e->newCUID(), dispatcher, e); + cmd->setBtRuntime(btRuntime); + e->commands.push_back(cmd); + } + } time_t btStopTimeout = option->getAsInt(PREF_BT_STOP_TIMEOUT); if(btStopTimeout > 0) { BtStopDownloadCommand* stopDownloadCommand = diff --git a/src/LpdDispatchMessageCommand.cc b/src/LpdDispatchMessageCommand.cc new file mode 100644 index 00000000..b469935d --- /dev/null +++ b/src/LpdDispatchMessageCommand.cc @@ -0,0 +1,88 @@ +/* */ +#include "LpdDispatchMessageCommand.h" +#include "LpdMessageDispatcher.h" +#include "DownloadEngine.h" +#include "BtRuntime.h" +#include "Logger.h" +#include "RecoverableException.h" +#include "SocketCore.h" +#include "util.h" + +namespace aria2 { + +LpdDispatchMessageCommand::LpdDispatchMessageCommand +(int cuid, + const SharedHandle& dispatcher, + DownloadEngine* e): + Command(cuid), + _dispatcher(dispatcher), + _e(e), + _tryCount(0) {} + +bool LpdDispatchMessageCommand::execute() +{ + if(_btRuntime->isHalt()) { + return true; + } + if(_dispatcher->isAnnounceReady()) { + try { + logger->info("Dispatching LPD message for infohash=%s", + util::toHex(_dispatcher->getInfoHash()).c_str()); + if(_dispatcher->sendMessage()) { + logger->info("Sending LPD message is complete."); + _dispatcher->resetAnnounceTimer(); + _tryCount = 0; + } else { + ++_tryCount; + if(_tryCount >= 5) { + logger->info("Sending LPD message %u times but all failed."); + _dispatcher->resetAnnounceTimer(); + _tryCount = 0; + } else { + logger->info("Could not send LPD message, retry shortly."); + } + } + } catch(RecoverableException& e) { + logger->info("Failed to send LPD message.", e); + _dispatcher->resetAnnounceTimer(); + _tryCount = 0; + } + } + _e->commands.push_back(this); + return false; +} + +} // namespace aria2 diff --git a/src/LpdDispatchMessageCommand.h b/src/LpdDispatchMessageCommand.h new file mode 100644 index 00000000..4e4708e0 --- /dev/null +++ b/src/LpdDispatchMessageCommand.h @@ -0,0 +1,69 @@ +/* */ +#ifndef _D_LPD_DISPATCH_MESSAGE_COMMAND_H_ +#define _D_LPD_DISPATCH_MESSAGE_COMMAND_H_ + +#include "Command.h" +#include "SharedHandle.h" + +namespace aria2 { + +class LpdMessageDispatcher; +class DownloadEngine; +class BtRuntime; + +class LpdDispatchMessageCommand:public Command { +private: + SharedHandle _dispatcher; + DownloadEngine* _e; + unsigned int _tryCount; + SharedHandle _btRuntime; +public: + LpdDispatchMessageCommand + (int cuid, + const SharedHandle& dispatcher, + DownloadEngine* e); + + virtual bool execute(); + + void setBtRuntime(const SharedHandle& btRuntime) + { + _btRuntime = btRuntime; + } +}; + +} // namespace aria2 + +#endif // _D_LPD_DISPATCH_MESSAGE_COMMAND_H_ diff --git a/src/LpdMessage.h b/src/LpdMessage.h new file mode 100644 index 00000000..c6647e1d --- /dev/null +++ b/src/LpdMessage.h @@ -0,0 +1,65 @@ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2010 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. + */ +#ifndef _D_LPD_MESSAGE_H_ +#define _D_LPD_MESSAGE_H_ + +#include "common.h" + +#include + +#include "Peer.h" + +namespace aria2 { + +class LpdMessage { +private: + SharedHandle _peer; + std::string _infoHash; +public: + LpdMessage(const SharedHandle& peer, const std::string& infoHash): + _peer(peer), _infoHash(infoHash) {} + + const SharedHandle& getPeer() const + { + return _peer; + } + + const std::string& getInfoHash() const + { + return _infoHash; + } +}; + +} // namespace aria2 + +#endif // _D_LPD_MESSAGE_H_ diff --git a/src/LpdMessageDispatcher.cc b/src/LpdMessageDispatcher.cc new file mode 100644 index 00000000..3529c524 --- /dev/null +++ b/src/LpdMessageDispatcher.cc @@ -0,0 +1,95 @@ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2010 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. + */ +#include "LpdMessageDispatcher.h" +#include "SocketCore.h" +#include "A2STR.h" +#include "util.h" +#include "Logger.h" +#include "LogFactory.h" +#include "BtConstants.h" +#include "RecoverableException.h" + +namespace aria2 { + +LpdMessageDispatcher::LpdMessageDispatcher +(const std::string& infoHash, uint16_t port, + const std::string& multicastAddress, uint16_t multicastPort, + const SharedHandle& socket, + time_t interval): + _infoHash(infoHash), + _port(port), + _socket(socket), + _multicastAddress(multicastAddress), + _multicastPort(multicastPort), + _timer(0), + _interval(interval), + _request(bittorrent::createLpdRequest(_multicastAddress, _multicastPort, + _infoHash, _port)), + _logger(LogFactory::getInstance()) {} + +bool LpdMessageDispatcher::sendMessage() +{ + return + _socket->writeData(_request.c_str(), _request.size(), + _multicastAddress, _multicastPort) + == (ssize_t)_request.size(); +} + +bool LpdMessageDispatcher::isAnnounceReady() const +{ + return _timer.elapsed(_interval); +} + +void LpdMessageDispatcher::resetAnnounceTimer() +{ + _timer.reset(); +} + +namespace bittorrent { + +std::string createLpdRequest +(const std::string& multicastAddress, uint16_t multicastPort, + const std::string& infoHash, uint16_t port) +{ + std::string req = "BT-SEARCH * HTTP/1.1\r\n"; + strappend(req, "Host: ", multicastAddress, A2STR::COLON_C, + util::uitos(multicastPort), A2STR::CRLF); + strappend(req, "Port: ", util::uitos(port), A2STR::CRLF); + strappend(req, "Infohash: ", util::toHex(infoHash), A2STR::CRLF); + req += "\r\n\r\n"; + return req; +} + +} // namespace bittorrent + +} // namespac aria2 diff --git a/src/LpdMessageDispatcher.h b/src/LpdMessageDispatcher.h new file mode 100644 index 00000000..e09c0fa4 --- /dev/null +++ b/src/LpdMessageDispatcher.h @@ -0,0 +1,98 @@ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2010 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. + */ +#ifndef _D_LPD_MESSAGE_DISPATCHER_H_ +#define _D_LPD_MESSAGE_DISPATCHER_H_ + +#include "common.h" + +#include + +#include "SharedHandle.h" +#include "TimeA2.h" + +namespace aria2 { + +class SocketCore; +class Logger; + +class LpdMessageDispatcher { +private: + std::string _infoHash; + uint16_t _port; + SharedHandle _socket; + std::string _multicastAddress; + uint16_t _multicastPort; + Time _timer; + time_t _interval; + std::string _request; + Logger* _logger; +public: + LpdMessageDispatcher + (const std::string& infoHash, uint16_t port, + const std::string& multicastAddr, uint16_t multicastPort, + const SharedHandle& socket, + time_t interval = 5*60); + + // Returns true if _timer reached announce interval, which is by + // default 5mins. + bool isAnnounceReady() const; + + // Sends LPD message. If message is sent returns true. Otherwise + // returns false. + bool sendMessage(); + + // Reset _timer to the current time. + void resetAnnounceTimer(); + + const std::string& getInfoHash() const + { + return _infoHash; + } + + uint16_t getPort() const + { + return _port; + } +}; + +namespace bittorrent { + +std::string createLpdRequest +(const std::string& multicastAddress, uint16_t multicastPort, + const std::string& infoHash, uint16_t port); + +} // namespace bittorrent + +} // namespace aria2 + +#endif // _D_LPD_MESSAGE_DISPATCHER_H_ diff --git a/src/LpdMessageReceiver.cc b/src/LpdMessageReceiver.cc new file mode 100644 index 00000000..3d9567f2 --- /dev/null +++ b/src/LpdMessageReceiver.cc @@ -0,0 +1,107 @@ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2010 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. + */ +#include "LpdMessageReceiver.h" +#include "SocketCore.h" +#include "Logger.h" +#include "LogFactory.h" +#include "HttpHeaderProcessor.h" +#include "HttpHeader.h" +#include "util.h" +#include "LpdMessage.h" +#include "RecoverableException.h" + +namespace aria2 { + +LpdMessageReceiver::LpdMessageReceiver +(const std::string& multicastAddress, uint16_t multicastPort): + _multicastAddress(multicastAddress), + _multicastPort(multicastPort), + _logger(LogFactory::getInstance()) {} + +bool LpdMessageReceiver::init() +{ + try { + _socket.reset(new SocketCore(SOCK_DGRAM)); + // SocketCore::bind(port, flags) cannot be used here, because it + // is affected by --interface option. + _socket->bindWithFamily(_multicastPort, AF_INET); + _socket->joinMulticastGroup(_multicastAddress, _multicastPort); + _socket->setNonBlockingMode(); + _logger->info("Listening multicast group (%s:%u) packet", + _multicastAddress.c_str(), _multicastPort); + return true; + } catch(RecoverableException& e) { + _logger->error("Failed to initialize LPD message receiver.", e); + } + return false; +} + +SharedHandle LpdMessageReceiver::receiveMessage() +{ + SharedHandle msg; + try { + unsigned char buf[200]; + std::pair peerAddr; + ssize_t length = _socket->readDataFrom(buf, sizeof(buf), peerAddr); + if(length == 0) { + return msg; + } + HttpHeaderProcessor proc; + proc.update(buf, length); + if(!proc.eoh()) { + return msg; + } + SharedHandle header = proc.getHttpRequestHeader(); + std::string infoHashString = header->getFirst("Infohash"); + uint16_t port = header->getFirstAsUInt("Port"); + _logger->info("LPD message received infohash=%s, port=%u from %s", + infoHashString.c_str(), port, peerAddr.first.c_str()); + std::string infoHash; + if(infoHashString.size() != 40 || + (infoHash = util::fromHex(infoHashString)).empty() || + port == 0) { + _logger->info("LPD bad request. infohash=%s", infoHashString.c_str()); + return msg; + } + SharedHandle peer(new Peer(peerAddr.first, port, false)); + if(util::inPrivateAddress(peerAddr.first)) { + peer->setLocalPeer(true); + } + msg.reset(new LpdMessage(peer, infoHash)); + } catch(RecoverableException& e) { + _logger->info("Failed to receive LPD message.", e); + } + return msg; +} + +} // namespace aria2 diff --git a/src/LpdMessageReceiver.h b/src/LpdMessageReceiver.h new file mode 100644 index 00000000..16d1f895 --- /dev/null +++ b/src/LpdMessageReceiver.h @@ -0,0 +1,74 @@ +/* + * aria2 - The high speed download utility + * + * Copyright (C) 2010 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. + */ +#ifndef _LPD_MESSAGE_RECEIVER_H_ +#define _LPD_MESSAGE_RECEIVER_H_ + +#include "common.h" + +#include + +#include "SharedHandle.h" + +namespace aria2 { + +class SocketCore; +class Logger; +class LpdMessage; + +class LpdMessageReceiver { +private: + SharedHandle _socket; + std::string _multicastAddress; + uint16_t _multicastPort; + Logger* _logger; +public: + // Currently only IPv4 multicastAddresses are supported. + LpdMessageReceiver + (const std::string& multicastAddress, uint16_t multicastPort); + + // No throw. + bool init(); + + // Receives LPD message and process it. Returns false if message is + // not available. + SharedHandle receiveMessage(); + + SharedHandle getSocket() const + { + return _socket; + } +}; + +} // namespace aria2 + +#endif // _LPD_MESSAGE_RECEIVER_H_ diff --git a/src/LpdReceiveMessageCommand.cc b/src/LpdReceiveMessageCommand.cc new file mode 100644 index 00000000..ba169b8f --- /dev/null +++ b/src/LpdReceiveMessageCommand.cc @@ -0,0 +1,154 @@ +/* */ +#include "LpdReceiveMessageCommand.h" +#include "DownloadEngine.h" +#include "SocketCore.h" +#include "LpdMessageReceiver.h" +#include "RequestGroupMan.h" +#include "DownloadContext.h" +#include "PeerStorage.h" +#include "Peer.h" +#include "RequestGroup.h" +#include "BtRegistry.h" +#include "Logger.h" +#include "PieceStorage.h" +#include "BtRuntime.h" +#include "BtProgressInfoFile.h" +#include "BtAnnounce.h" +#include "LpdMessage.h" +#include "bittorrent_helper.h" + +namespace aria2 { + +unsigned int LpdReceiveMessageCommand::__numInstance = 0; + +LpdReceiveMessageCommand* LpdReceiveMessageCommand::__instance = 0; + +LpdReceiveMessageCommand::LpdReceiveMessageCommand +(int32_t cuid, const SharedHandle& receiver, + DownloadEngine* e):Command(cuid), _receiver(receiver), _e(e) +{ + _e->addSocketForReadCheck(_receiver->getSocket(), this); + ++__numInstance; +} + +LpdReceiveMessageCommand::~LpdReceiveMessageCommand() +{ + _e->deleteSocketForReadCheck(_receiver->getSocket(), this); + --__numInstance; + if(__numInstance == 0) { + __instance = 0; + } +} + +bool LpdReceiveMessageCommand::execute() +{ + if(_e->_requestGroupMan->downloadFinished() || _e->isHaltRequested()) { + return true; + } + for(size_t i = 0; i < 20; ++i) { + SharedHandle m = _receiver->receiveMessage(); + if(m.isNull()) { + break; + } + SharedHandle reg = _e->getBtRegistry(); + SharedHandle dctx = + reg->getDownloadContext(m->getInfoHash()); + if(dctx.isNull()) { + if(logger->debug()) { + logger->debug("Download Context is null for infohash=%s.", + util::toHex(m->getInfoHash()).c_str()); + } + continue; + } + const BDE& torrentAttrs = dctx->getAttribute(bittorrent::BITTORRENT); + if(torrentAttrs.containsKey(bittorrent::PRIVATE)) { + if(torrentAttrs[bittorrent::PRIVATE].i() == 1) { + if(logger->debug()) { + logger->debug("Ignore LPD message because the torrent is private."); + } + continue; + } + } + RequestGroup* group = dctx->getOwnerRequestGroup(); + assert(group); + BtObject btobj = reg->get(group->getGID()); + assert(!btobj.isNull()); + SharedHandle peerStorage = btobj._peerStorage; + assert(!peerStorage.isNull()); + SharedHandle peer = m->getPeer(); + if(peerStorage->addPeer(peer)) { + if(logger->debug()) { + logger->debug("LPD peer %s:%u local=%d added.", + peer->ipaddr.c_str(), peer->port, + peer->isLocalPeer()?1:0); + } + } else { + if(logger->debug()) { + logger->debug("LPD peer %s:%u local=%d not added.", + peer->ipaddr.c_str(), peer->port, + peer->isLocalPeer()?1:0); + } + } + } + _e->commands.push_back(this); + return false; +} + +SharedHandle LpdReceiveMessageCommand::getReceiverSocket() const +{ + return _receiver->getSocket(); +} + +LpdReceiveMessageCommand* +LpdReceiveMessageCommand::getInstance +(DownloadEngine* e, const SharedHandle& receiver) +{ + if(__numInstance == 0) { + __instance = new LpdReceiveMessageCommand(e->newCUID(), receiver, e); + } + return __instance; +} + +LpdReceiveMessageCommand* LpdReceiveMessageCommand::getInstance() +{ + if(__numInstance == 0) { + return 0; + } else { + return __instance; + } +} + +} // namespace aria2 diff --git a/src/LpdReceiveMessageCommand.h b/src/LpdReceiveMessageCommand.h new file mode 100644 index 00000000..251f0cfb --- /dev/null +++ b/src/LpdReceiveMessageCommand.h @@ -0,0 +1,84 @@ +/* */ +#ifndef _D_LPD_RECEIVE_MESSAGE_COMMAND_H_ +#define _D_LPD_RECEIVE_MESSAGE_COMMAND_H_ + +#include "Command.h" +#include "SharedHandle.h" + +namespace aria2 { + +class LpdMessageReceiver; +class DownloadEngine; +class SocketCore; + +class LpdReceiveMessageCommand:public Command { +private: + SharedHandle _receiver; + + static unsigned int __numInstance; + + static LpdReceiveMessageCommand* __instance; + + LpdReceiveMessageCommand + (int32_t cuid, const SharedHandle& receiver, + DownloadEngine* e); +protected: + DownloadEngine* _e; + +public: + virtual ~LpdReceiveMessageCommand(); + + virtual bool execute(); + + SharedHandle getReceiverSocket() const; + + static LpdReceiveMessageCommand* + getInstance + (DownloadEngine* e, const SharedHandle& receiver); + + // If __numInstance is 0, then return 0. If __numInstance > 0, it + // returns __instance + static LpdReceiveMessageCommand* getInstance(); + + static unsigned int getNumInstance() + { + return __numInstance; + } +}; + +} // namespace aria2 + +#endif // _D_LPD_RECEIVE_MESSAGE_COMMAND_H_ diff --git a/src/Makefile.am b/src/Makefile.am index ee736309..9130fd22 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -440,7 +440,12 @@ SRCS += PeerAbstractCommand.cc PeerAbstractCommand.h\ bencode.cc bencode.h\ bittorrent_helper.cc bittorrent_helper.h\ BtStopDownloadCommand.cc BtStopDownloadCommand.h\ - PriorityPieceSelector.cc PriorityPieceSelector.h + PriorityPieceSelector.cc PriorityPieceSelector.h\ + LpdMessageDispatcher.cc LpdMessageDispatcher.h\ + LpdMessageReceiver.cc LpdMessageReceiver.h\ + LpdMessage.h\ + LpdReceiveMessageCommand.cc LpdReceiveMessageCommand.h\ + LpdDispatchMessageCommand.cc LpdDispatchMessageCommand.h endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/src/Makefile.in b/src/Makefile.in index 44b3dcaf..763cc480 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -243,7 +243,12 @@ bin_PROGRAMS = aria2c$(EXEEXT) @ENABLE_BITTORRENT_TRUE@ bencode.cc bencode.h\ @ENABLE_BITTORRENT_TRUE@ bittorrent_helper.cc bittorrent_helper.h\ @ENABLE_BITTORRENT_TRUE@ BtStopDownloadCommand.cc BtStopDownloadCommand.h\ -@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelector.cc PriorityPieceSelector.h +@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelector.cc PriorityPieceSelector.h\ +@ENABLE_BITTORRENT_TRUE@ LpdMessageDispatcher.cc LpdMessageDispatcher.h\ +@ENABLE_BITTORRENT_TRUE@ LpdMessageReceiver.cc LpdMessageReceiver.h\ +@ENABLE_BITTORRENT_TRUE@ LpdMessage.h\ +@ENABLE_BITTORRENT_TRUE@ LpdReceiveMessageCommand.cc LpdReceiveMessageCommand.h\ +@ENABLE_BITTORRENT_TRUE@ LpdDispatchMessageCommand.cc LpdDispatchMessageCommand.h @ENABLE_METALINK_TRUE@am__append_14 = Metalinker.cc Metalinker.h\ @ENABLE_METALINK_TRUE@ MetalinkEntry.cc MetalinkEntry.h\ @@ -570,8 +575,12 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \ IndexBtMessageValidator.h ExtensionMessageRegistry.h \ bencode.cc bencode.h bittorrent_helper.cc bittorrent_helper.h \ BtStopDownloadCommand.cc BtStopDownloadCommand.h \ - PriorityPieceSelector.cc PriorityPieceSelector.h Metalinker.cc \ - Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ + PriorityPieceSelector.cc PriorityPieceSelector.h \ + LpdMessageDispatcher.cc LpdMessageDispatcher.h \ + LpdMessageReceiver.cc LpdMessageReceiver.h LpdMessage.h \ + LpdReceiveMessageCommand.cc LpdReceiveMessageCommand.h \ + LpdDispatchMessageCommand.cc LpdDispatchMessageCommand.h \ + Metalinker.cc Metalinker.h MetalinkEntry.cc MetalinkEntry.h \ MetalinkResource.cc MetalinkResource.h MetalinkProcessor.h \ MetalinkParserController.cc MetalinkParserController.h \ MetalinkParserStateMachine.cc MetalinkParserStateMachine.h \ @@ -734,7 +743,11 @@ am__objects_6 = @ENABLE_BITTORRENT_TRUE@ bencode.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ bittorrent_helper.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BtStopDownloadCommand.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelector.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelector.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ LpdMessageDispatcher.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ LpdMessageReceiver.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ LpdReceiveMessageCommand.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ LpdDispatchMessageCommand.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_14 = Metalinker.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntry.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkResource.$(OBJEXT) \ @@ -1465,6 +1478,10 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LogFactory.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Logger.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LongestSequencePieceSelector.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LpdDispatchMessageCommand.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LpdMessageDispatcher.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LpdMessageReceiver.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LpdReceiveMessageCommand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MSEHandshake.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MemoryBufferPreDownloadHandler.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MessageDigestHelper.Po@am__quote@ diff --git a/src/OptionHandlerFactory.cc b/src/OptionHandlerFactory.cc index 520ff42c..764944a1 100644 --- a/src/OptionHandlerFactory.cc +++ b/src/OptionHandlerFactory.cc @@ -942,6 +942,15 @@ OptionHandlers OptionHandlerFactory::createOptionHandlers() #endif // ENABLE_BITTORRENT || ENABLE_METALINK // BitTorrent Specific Options #ifdef ENABLE_BITTORRENT + { + SharedHandle op(new BooleanOptionHandler + (PREF_BT_ENABLE_LPD, + TEXT_BT_ENABLE_LPD, + V_FALSE, + OptionHandler::OPT_ARG)); + op->addTag(TAG_BITTORRENT); + handlers.push_back(op); + } { SharedHandle op(new DefaultOptionHandler (PREF_BT_EXTERNAL_IP, diff --git a/src/Peer.cc b/src/Peer.cc index 41ea2ce1..ceef6f9b 100644 --- a/src/Peer.cc +++ b/src/Peer.cc @@ -55,7 +55,8 @@ Peer::Peer(std::string ipaddr, uint16_t port, bool incoming): _badConditionStartTime(0), _seeder(false), _res(0), - _incoming(incoming) + _incoming(incoming), + _localPeer(false) { memset(_peerId, 0, PEER_ID_LENGTH); resetStatus(); diff --git a/src/Peer.h b/src/Peer.h index 0291d3db..79158811 100644 --- a/src/Peer.h +++ b/src/Peer.h @@ -78,6 +78,9 @@ private: // If true, port is assumed not to be a listening port. bool _incoming; + // If true, this peer is from local network. + bool _localPeer; + // Before calling updateSeeder(), make sure that // allocateSessionResource() is called and _res is created. // Otherwise assertion fails. @@ -282,6 +285,16 @@ public: void setIncomingPeer(bool incoming); + bool isLocalPeer() const + { + return _localPeer; + } + + void setLocalPeer(bool flag) + { + _localPeer = flag; + } + void setBtMessageDispatcher(const WeakHandle& dpt); size_t countOutstandingUpload() const; diff --git a/src/PeerInteractionCommand.cc b/src/PeerInteractionCommand.cc index 7df1c75a..9e731324 100644 --- a/src/PeerInteractionCommand.cc +++ b/src/PeerInteractionCommand.cc @@ -189,7 +189,8 @@ PeerInteractionCommand::PeerInteractionCommand (getOption()->getAsInt(PREF_BT_KEEP_ALIVE_INTERVAL)); btInteractive->setRequestGroupMan(e->_requestGroupMan); btInteractive->setBtMessageFactory(factory); - if(metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) { + if((metadataGetMode || torrentAttrs[bittorrent::PRIVATE].i() == 0) && + !peer->isLocalPeer()) { if(getOption()->getAsBool(PREF_ENABLE_PEER_EXCHANGE)) { btInteractive->setUTPexEnabled(true); } diff --git a/src/SocketCore.cc b/src/SocketCore.cc index d2bc2f10..4be28b30 100644 --- a/src/SocketCore.cc +++ b/src/SocketCore.cc @@ -253,6 +253,18 @@ static sock_t bindTo return -1; } +void SocketCore::bindWithFamily(uint16_t port, int family, int flags) +{ + closeConnection(); + std::string error; + sock_t fd = bindTo(0, port, family, _sockType, flags, error); + if(fd == (sock_t) -1) { + throw DL_ABORT_EX(StringFormat(EX_SOCKET_BIND, error.c_str()).str()); + } else { + sockfd = fd; + } +} + void SocketCore::bind(uint16_t port, int flags) { closeConnection(); @@ -403,6 +415,28 @@ void SocketCore::establishConnection(const std::string& host, uint16_t port) } } +void SocketCore::setSockOpt +(int level, int optname, void* optval, socklen_t optlen) +{ + if(setsockopt(sockfd, level, optname, optval, optlen) < 0) { + throw DL_ABORT_EX(StringFormat(EX_SOCKET_SET_OPT, errorMsg()).str()); + } +} + +void SocketCore::setMulticastTtl(unsigned char ttl) +{ + setSockOpt(IPPROTO_IP, IP_MULTICAST_TTL, (a2_sockopt_t)&ttl, sizeof(ttl)); +} + +void SocketCore::joinMulticastGroup(const std::string& ipaddr, uint16_t port) +{ + struct ip_mreq mreq; + memset(&mreq, 0, sizeof(mreq)); + mreq.imr_multiaddr.s_addr = inet_addr(ipaddr.c_str()); + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + setSockOpt(IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)); +} + void SocketCore::setNonBlockingMode() { #ifdef __MINGW32__ diff --git a/src/SocketCore.h b/src/SocketCore.h index df69e41d..b4b2714c 100644 --- a/src/SocketCore.h +++ b/src/SocketCore.h @@ -135,6 +135,8 @@ private: #endif // HAVE_EPOLL + void setSockOpt(int level, int optname, void* optval, socklen_t optlen); + SocketCore(sock_t sockfd, int sockType); public: SocketCore(int sockType = SOCK_STREAM); @@ -144,6 +146,12 @@ public: bool isOpen() const { return sockfd != (sock_t) -1; } + void setMulticastTtl(unsigned char ttl); + + void joinMulticastGroup(const std::string& ipaddr, uint16_t port); + + void bindWithFamily(uint16_t port, int family, int flags = AI_PASSIVE); + /** * Creates a socket and bind it with locahost's address and port. * flags is set to struct addrinfo's ai_flags. diff --git a/src/prefs.cc b/src/prefs.cc index cc612acb..fa451eb2 100644 --- a/src/prefs.cc +++ b/src/prefs.cc @@ -316,6 +316,8 @@ const std::string PREF_BT_PRIORITIZE_PIECE("bt-prioritize-piece"); const std::string PREF_BT_SAVE_METADATA("bt-save-metadata"); // values: true | false const std::string PREF_BT_METADATA_ONLY("bt-metadata-only"); +// values: true | false +const std::string PREF_BT_ENABLE_LPD("bt-enable-lpd"); /** * Metalink related preferences diff --git a/src/prefs.h b/src/prefs.h index c8ec63c1..d99124d2 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -320,6 +320,8 @@ extern const std::string PREF_BT_PRIORITIZE_PIECE; extern const std::string PREF_BT_SAVE_METADATA; // values: true | false extern const std::string PREF_BT_METADATA_ONLY; +// values: true | false +extern const std::string PREF_BT_ENABLE_LPD; /** * Metalink related preferences diff --git a/src/usage_text.h b/src/usage_text.h index b2dfc1f9..605d8afc 100644 --- a/src/usage_text.h +++ b/src/usage_text.h @@ -608,3 +608,5 @@ #define TEXT_HUMAN_READABLE \ _(" --human-readable[=true|false] Print sizes and speed in human readable format\n" \ " (e.g., 1.2Ki, 3.4Mi) in the console readout.") +#define TEXT_BT_ENABLE_LPD \ + _(" --bt-enable-lpd[=true|false] Enable Local Peer Discovery.") diff --git a/src/util.cc b/src/util.cc index b4ff69d5..fadf445c 100644 --- a/src/util.cc +++ b/src/util.cc @@ -1172,6 +1172,28 @@ void generateRandomKey(unsigned char* key) #endif // !ENABLE_MESSAGE_DIGEST } +// Returns true is given numeric ipv4addr is in Private Address Space. +// +// From Section.3 RFC1918 +// 10.0.0.0 - 10.255.255.255 (10/8 prefix) +// 172.16.0.0 - 172.31.255.255 (172.16/12 prefix) +// 192.168.0.0 - 192.168.255.255 (192.168/16 prefix) +bool inPrivateAddress(const std::string& ipv4addr) +{ + if(util::startsWith(ipv4addr, "10.") || + util::startsWith(ipv4addr, "192.168.")) { + return true; + } + if(util::startsWith(ipv4addr, "172.")) { + for(int i = 16; i <= 31; ++i) { + if(util::startsWith(ipv4addr, "172."+util::itos(i)+".")) { + return true; + } + } + } + return false; +} + } // namespace util } // namespace aria2 diff --git a/src/util.h b/src/util.h index 7e16a77b..0260a75e 100644 --- a/src/util.h +++ b/src/util.h @@ -378,6 +378,9 @@ std::string fixTaintedBasename(const std::string& src); // by key. Caller must allocate at least 20 bytes for generated key. void generateRandomKey(unsigned char* key); +// Returns true is given numeric ipv4addr is in Private Address Space. +bool inPrivateAddress(const std::string& ipv4addr); + } // namespace util } // namespace aria2 diff --git a/test/LpdMessageDispatcherTest.cc b/test/LpdMessageDispatcherTest.cc new file mode 100644 index 00000000..79272996 --- /dev/null +++ b/test/LpdMessageDispatcherTest.cc @@ -0,0 +1,69 @@ +#include "LpdMessageDispatcher.h" + +#include +#include + +#include + +#include "Exception.h" +#include "util.h" +#include "LpdMessageDispatcher.h" +#include "SocketCore.h" +#include "BtConstants.h" + +namespace aria2 { + +class LpdMessageDispatcherTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(LpdMessageDispatcherTest); + CPPUNIT_TEST(testCreateLpdRequest); + CPPUNIT_TEST(testSendMessage); + CPPUNIT_TEST_SUITE_END(); +public: + void testCreateLpdRequest(); + void testSendMessage(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(LpdMessageDispatcherTest); + +void LpdMessageDispatcherTest::testCreateLpdRequest() +{ + std::string infoHashString = "cd41c7fdddfd034a15a04d7ff881216e01c4ceaf"; + CPPUNIT_ASSERT_EQUAL + (std::string("BT-SEARCH * HTTP/1.1\r\n" + "Host: 239.192.152.143:6771\r\n" + "Port: 6000\r\n" + "Infohash: cd41c7fdddfd034a15a04d7ff881216e01c4ceaf\r\n" + "\r\n\r\n"), + bittorrent::createLpdRequest("239.192.152.143", 6771, + util::fromHex(infoHashString), 6000)); +} + +void LpdMessageDispatcherTest::testSendMessage() +{ + SharedHandle recvsock(new SocketCore(SOCK_DGRAM)); + recvsock->bind(LPD_MULTICAST_PORT); + recvsock->joinMulticastGroup(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT); + recvsock->setMulticastTtl(0); + LpdMessageDispatcher d("cd41c7fdddfd034a15a04d7ff881216e01c4ceaf", 6000, + LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, + recvsock); + + CPPUNIT_ASSERT(d.sendMessage()); + + unsigned char buf[200]; + + std::pair peer; + ssize_t nbytes = recvsock->readDataFrom(buf, sizeof(buf), peer); + buf[nbytes] = '\0'; + std::stringstream temp; + temp << "BT-SEARCH * HTTP/1.1\r\n" + << "Host: " << LPD_MULTICAST_ADDR << ":" << LPD_MULTICAST_PORT << "\r\n" + << "Port: " << d.getPort() << "\r\n" + << "Infohash: " << util::toHex(d.getInfoHash()) << "\r\n" + << "\r\n\r\n"; + CPPUNIT_ASSERT_EQUAL(temp.str(), std::string(&buf[0], &buf[nbytes])); +} + +} // namespace aria2 diff --git a/test/LpdMessageReceiverTest.cc b/test/LpdMessageReceiverTest.cc new file mode 100644 index 00000000..a0c412a7 --- /dev/null +++ b/test/LpdMessageReceiverTest.cc @@ -0,0 +1,75 @@ +#include "LpdMessageReceiver.h" + +#include + +#include + +#include "Exception.h" +#include "util.h" +#include "LpdMessageReceiver.h" +#include "SocketCore.h" +#include "BtConstants.h" +#include "LpdMessage.h" +#include "LpdMessageDispatcher.h" + +namespace aria2 { + +class LpdMessageReceiverTest:public CppUnit::TestFixture { + + CPPUNIT_TEST_SUITE(LpdMessageReceiverTest); + CPPUNIT_TEST(testReceiveMessage); + CPPUNIT_TEST_SUITE_END(); +public: + void testReceiveMessage(); +}; + + +CPPUNIT_TEST_SUITE_REGISTRATION(LpdMessageReceiverTest); + +void LpdMessageReceiverTest::testReceiveMessage() +{ + LpdMessageReceiver rcv(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT); + CPPUNIT_ASSERT(rcv.init()); + + SharedHandle sendsock = rcv.getSocket(); + sendsock->setMulticastTtl(0); + + std::string infoHashString = "cd41c7fdddfd034a15a04d7ff881216e01c4ceaf"; + std::string infoHash = util::fromHex(infoHashString); + std::string request = + bittorrent::createLpdRequest(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, + infoHash, + 6000); + + sendsock->writeData(request.c_str(), request.size(), + LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT); + + SharedHandle msg = rcv.receiveMessage(); + CPPUNIT_ASSERT(!msg.isNull()); + CPPUNIT_ASSERT_EQUAL(std::string("cd41c7fdddfd034a15a04d7ff881216e01c4ceaf"), + util::toHex(msg->getInfoHash())); + CPPUNIT_ASSERT_EQUAL((uint16_t)6000, msg->getPeer()->port); + + // Bad infohash + std::string badInfoHashString = "cd41c7fdddfd034a15a04d7ff881216e01c4ce"; + request = + bittorrent::createLpdRequest(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, + util::fromHex(badInfoHashString), + 6000); + sendsock->writeData(request.c_str(), request.size(), + LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT); + + CPPUNIT_ASSERT(rcv.receiveMessage().isNull()); + + // Bad port + request = + bittorrent::createLpdRequest(LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT, + infoHash, + 0); + sendsock->writeData(request.c_str(), request.size(), + LPD_MULTICAST_ADDR, LPD_MULTICAST_PORT); + + CPPUNIT_ASSERT(rcv.receiveMessage().isNull()); +} + +} // namespace aria2 diff --git a/test/Makefile.am b/test/Makefile.am index afc32956..29f8019c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -191,7 +191,9 @@ aria2c_SOURCES += BtAllowedFastMessageTest.cc\ BittorrentHelperTest.cc\ PriorityPieceSelectorTest.cc\ MockPieceSelector.h\ - extension_message_test_helper.h + extension_message_test_helper.h\ + LpdMessageDispatcherTest.cc\ + LpdMessageReceiverTest.cc endif # ENABLE_BITTORRENT if ENABLE_METALINK diff --git a/test/Makefile.in b/test/Makefile.in index b4556503..cce03b38 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -141,7 +141,9 @@ check_PROGRAMS = $(am__EXEEXT_1) @ENABLE_BITTORRENT_TRUE@ BittorrentHelperTest.cc\ @ENABLE_BITTORRENT_TRUE@ PriorityPieceSelectorTest.cc\ @ENABLE_BITTORRENT_TRUE@ MockPieceSelector.h\ -@ENABLE_BITTORRENT_TRUE@ extension_message_test_helper.h +@ENABLE_BITTORRENT_TRUE@ extension_message_test_helper.h\ +@ENABLE_BITTORRENT_TRUE@ LpdMessageDispatcherTest.cc\ +@ENABLE_BITTORRENT_TRUE@ LpdMessageReceiverTest.cc @ENABLE_METALINK_TRUE@am__append_7 = MetalinkerTest.cc\ @ENABLE_METALINK_TRUE@ MetalinkEntryTest.cc\ @@ -266,7 +268,8 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ MockExtensionMessage.h MockExtensionMessageFactory.h \ MockPieceStorage.h BencodeTest.cc BittorrentHelperTest.cc \ PriorityPieceSelectorTest.cc MockPieceSelector.h \ - extension_message_test_helper.h MetalinkerTest.cc \ + extension_message_test_helper.h LpdMessageDispatcherTest.cc \ + LpdMessageReceiverTest.cc MetalinkerTest.cc \ MetalinkEntryTest.cc Metalink2RequestGroupTest.cc \ MetalinkPostDownloadHandlerTest.cc MetalinkHelperTest.cc \ MetalinkParserControllerTest.cc MetalinkProcessorTest.cc @@ -356,7 +359,9 @@ am__aria2c_SOURCES_DIST = AllTest.cc TestUtil.cc TestUtil.h \ @ENABLE_BITTORRENT_TRUE@ MSEHandshakeTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BencodeTest.$(OBJEXT) \ @ENABLE_BITTORRENT_TRUE@ BittorrentHelperTest.$(OBJEXT) \ -@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelectorTest.$(OBJEXT) +@ENABLE_BITTORRENT_TRUE@ PriorityPieceSelectorTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ LpdMessageDispatcherTest.$(OBJEXT) \ +@ENABLE_BITTORRENT_TRUE@ LpdMessageReceiverTest.$(OBJEXT) @ENABLE_METALINK_TRUE@am__objects_7 = MetalinkerTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ MetalinkEntryTest.$(OBJEXT) \ @ENABLE_METALINK_TRUE@ Metalink2RequestGroupTest.$(OBJEXT) \ @@ -824,6 +829,8 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChecksumValidatorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IteratableChunkChecksumValidatorTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LongestSequencePieceSelectorTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LpdMessageDispatcherTest.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/LpdMessageReceiverTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MSEHandshakeTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MagnetTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/MessageDigestHelperTest.Po@am__quote@