/* */ #include "PeerListenCommand.h" #include #include #include "DownloadEngine.h" #include "Peer.h" #include "RequestGroupMan.h" #include "RecoverableException.h" #include "message.h" #include "ReceiverMSEHandshakeCommand.h" #include "Logger.h" #include "LogFactory.h" #include "SocketCore.h" #include "SimpleRandomizer.h" #include "util.h" #include "fmt.h" namespace aria2 { PeerListenCommand::PeerListenCommand(cuid_t cuid, DownloadEngine* e, int family) : Command(cuid), e_(e), family_(family) { } PeerListenCommand::~PeerListenCommand() = default; bool PeerListenCommand::bindPort(uint16_t& port, SegList& sgl) { socket_ = std::make_shared(); std::vector ports; while (sgl.hasNext()) { ports.push_back(sgl.next()); } std::shuffle(ports.begin(), ports.end(), *SimpleRandomizer::getInstance()); const int ipv = (family_ == AF_INET) ? 4 : 6; for (std::vector::const_iterator i = ports.begin(), eoi = ports.end(); i != eoi; ++i) { port = *i; try { socket_->bind(nullptr, port, family_); socket_->beginListen(); A2_LOG_NOTICE( fmt(_("IPv%d BitTorrent: listening on TCP port %u"), ipv, port)); return true; } catch (RecoverableException& ex) { A2_LOG_ERROR_EX( fmt("IPv%d BitTorrent: failed to bind TCP port %u", ipv, port), ex); socket_->closeConnection(); } } return false; } uint16_t PeerListenCommand::getPort() const { if (!socket_) { return 0; } return socket_->getAddrInfo().port; } bool PeerListenCommand::execute() { if (e_->isHaltRequested() || e_->getRequestGroupMan()->downloadFinished()) { return true; } for (int i = 0; i < 3 && socket_->isReadable(0); ++i) { std::shared_ptr peerSocket; try { peerSocket = socket_->acceptConnection(); peerSocket->applyIpDscp(); auto endpoint = peerSocket->getPeerInfo(); auto peer = std::make_shared(endpoint.addr, endpoint.port, true); cuid_t cuid = e_->newCUID(); e_->addCommand( make_unique(cuid, peer, e_, peerSocket)); A2_LOG_DEBUG(fmt("Accepted the connection from %s:%u.", peer->getIPAddress().c_str(), peer->getPort())); A2_LOG_DEBUG(fmt( "Added CUID#%" PRId64 " to receive BitTorrent/MSE handshake.", cuid)); } catch (RecoverableException& ex) { A2_LOG_DEBUG_EX(fmt(MSG_ACCEPT_FAILURE, getCuid()), ex); } } e_->addCommand(std::unique_ptr(this)); return false; } } // namespace aria2