/* */ #include "DHTMessageFactoryImpl.h" #include "LogFactory.h" #include "DlAbortEx.h" #include "Data.h" #include "Dictionary.h" #include "List.h" #include "DHTNode.h" #include "DHTRoutingTable.h" #include "DHTPingMessage.h" #include "DHTPingReplyMessage.h" #include "DHTFindNodeMessage.h" #include "DHTFindNodeReplyMessage.h" #include "DHTGetPeersMessage.h" #include "DHTGetPeersReplyMessage.h" #include "DHTAnnouncePeerMessage.h" #include "DHTAnnouncePeerReplyMessage.h" #include "DHTUnknownMessage.h" #include "DHTConnection.h" #include "DHTMessageDispatcher.h" #include "DHTPeerAnnounceStorage.h" #include "DHTTokenTracker.h" #include "PeerMessageUtil.h" #include "BtRuntime.h" #include "Util.h" #include "Peer.h" #include "Logger.h" #include #include namespace aria2 { DHTMessageFactoryImpl::DHTMessageFactoryImpl():_localNode(0), _logger(LogFactory::getInstance()) {} DHTMessageFactoryImpl::~DHTMessageFactoryImpl() {} SharedHandle DHTMessageFactoryImpl::getRemoteNode(const unsigned char* id, const std::string& ipaddr, uint16_t port) const { SharedHandle node = _routingTable->getNode(id, ipaddr, port); if(node.isNull()) { node = new DHTNode(id); node->setIPAddress(ipaddr); node->setPort(port); } return node; } static const Dictionary* getDictionary(const Dictionary* d, const std::string& key) { const Dictionary* c = dynamic_cast(d->get(key)); if(c) { return c; } else { throw new DlAbortEx("Malformed DHT message. Missing %s", key.c_str()); } } static const Data* getData(const Dictionary* d, const std::string& key) { const Data* c = dynamic_cast(d->get(key)); if(c) { return c; } else { throw new DlAbortEx("Malformed DHT message. Missing %s", key.c_str()); } } static const Data* getData(const List* l, size_t index) { const Data* c = dynamic_cast(l->getList()[index]); if(c) { return c; } else { throw new DlAbortEx("Malformed DHT message. element[%u] is not Data.", index); } } static const List* getList(const Dictionary* d, const std::string& key) { const List* l = dynamic_cast(d->get(key)); if(l) { return l; } else { throw new DlAbortEx("Malformed DHT message. Missing %s", key.c_str()); } } void DHTMessageFactoryImpl::validateID(const Data* id) const { if(id->getLen() != DHT_ID_LENGTH) { throw new DlAbortEx("Malformed DHT message. Invalid ID length. Expected:%d, Actual:%d", DHT_ID_LENGTH, id->getLen()); } } void DHTMessageFactoryImpl::validateIDMatch(const unsigned char* expected, const unsigned char* actual) const { if(memcmp(expected, actual, DHT_ID_LENGTH) != 0) { //throw new DlAbortEx("Different ID received."); } } void DHTMessageFactoryImpl::validatePort(const Data* i) const { if(!i->isNumber()) { throw new DlAbortEx("Malformed DHT message. Invalid port=%s", Util::toHex(i->toString()).c_str()); } uint32_t port = i->toInt(); if(UINT16_MAX < port) { throw new DlAbortEx("Malformed DHT message. Invalid port=%u", port); } } SharedHandle DHTMessageFactoryImpl::createQueryMessage(const Dictionary* d, const std::string& ipaddr, uint16_t port) { const Data* q = getData(d, "q"); const Data* t = getData(d, "t"); const Data* y = getData(d, "y"); const Dictionary* a = getDictionary(d, "a"); if(y->toString() != "q") { throw new DlAbortEx("Malformed DHT message. y != q"); } const Data* id = getData(getDictionary(d, "a"), "id"); validateID(id); SharedHandle remoteNode = getRemoteNode((const unsigned char*)id->toString().c_str(), ipaddr, port); std::string messageType = q->toString(); std::string transactionID = t->toString(); if(messageType == "ping") { return createPingMessage(remoteNode, transactionID); } else if(messageType == "find_node") { const Data* targetNodeID = getData(a, "target"); validateID(targetNodeID); return createFindNodeMessage(remoteNode, (const unsigned char*)targetNodeID->getData(), transactionID); } else if(messageType == "get_peers") { const Data* infoHash = getData(a, "info_hash"); validateID(infoHash); return createGetPeersMessage(remoteNode, (const unsigned char*)infoHash->getData(), transactionID); } else if(messageType == "announce_peer") { const Data* infoHash = getData(a, "info_hash"); validateID(infoHash); const Data* port = getData(a, "port"); validatePort(port); const Data* token = getData(a, "token"); return createAnnouncePeerMessage(remoteNode, (const unsigned char*)infoHash->getData(), (uint16_t)port->toInt(), token->toString(), transactionID); } else { throw new DlAbortEx("Unsupported message type: %s", messageType.c_str()); } } SharedHandle DHTMessageFactoryImpl::createResponseMessage(const std::string& messageType, const Dictionary* d, const SharedHandle& remoteNode) { const Data* t = getData(d, "t"); const Data* y = getData(d, "y"); if(y->toString() == "e") { // for now, just report error message arrived and throw exception. const List* e = getList(d, "e"); if(e->getList().size() == 2) { _logger->info("Received Error DHT message. code=%s, msg=%s", Util::urlencode(getData(e, 0)->toString()).c_str(), Util::urlencode(getData(e, 1)->toString()).c_str()); } else { _logger->debug("e doesn't have 2 elements."); } throw new DlAbortEx("Received Error DHT message."); } else if(y->toString() != "r") { throw new DlAbortEx("Malformed DHT message. y != r: y=%s", Util::urlencode(y->toString()).c_str()); } const Dictionary* r = getDictionary(d, "r"); const Data* id = getData(r, "id"); validateID(id); validateIDMatch(remoteNode->getID(), (const unsigned char*)id->toString().c_str()); std::string transactionID = t->toString(); if(messageType == "ping") { return createPingReplyMessage(remoteNode, (const unsigned char*)id->getData(), transactionID); } else if(messageType == "find_node") { return createFindNodeReplyMessage(remoteNode, d, transactionID); } else if(messageType == "get_peers") { const List* values = dynamic_cast(r->get("values")); if(values) { return createGetPeersReplyMessageWithValues(remoteNode, d, transactionID); } else { const Data* nodes = dynamic_cast(r->get("nodes")); if(nodes) { return createGetPeersReplyMessageWithNodes(remoteNode, d, transactionID); } else { throw new DlAbortEx("Malformed DHT message: missing nodes/values"); } } } else if(messageType == "announce_peer") { return createAnnouncePeerReplyMessage(remoteNode, transactionID); } else { throw new DlAbortEx("Unsupported message type: %s", messageType.c_str()); } } void DHTMessageFactoryImpl::setCommonProperty(const SharedHandle& m) { m->setConnection(_connection); m->setMessageDispatcher(_dispatcher); m->setRoutingTable(_routingTable); m->setMessageFactory(this); } SharedHandle DHTMessageFactoryImpl::createPingMessage(const SharedHandle& remoteNode, const std::string& transactionID) { SharedHandle m = new DHTPingMessage(_localNode, remoteNode, transactionID); setCommonProperty(m); return m; } SharedHandle DHTMessageFactoryImpl::createPingReplyMessage(const SharedHandle& remoteNode, const unsigned char* id, const std::string& transactionID) { SharedHandle m = new DHTPingReplyMessage(_localNode, remoteNode, id, transactionID); setCommonProperty(m); return m; } SharedHandle DHTMessageFactoryImpl::createFindNodeMessage(const SharedHandle& remoteNode, const unsigned char* targetNodeID, const std::string& transactionID) { SharedHandle m = new DHTFindNodeMessage(_localNode, remoteNode, targetNodeID, transactionID); setCommonProperty(m); return m; } SharedHandle DHTMessageFactoryImpl::createFindNodeReplyMessage(const SharedHandle& remoteNode, const std::deque >& closestKNodes, const std::string& transactionID) { SharedHandle m = new DHTFindNodeReplyMessage(_localNode, remoteNode, transactionID); m->setClosestKNodes(closestKNodes); setCommonProperty(m); return m; } std::deque > DHTMessageFactoryImpl::extractNodes(const char* src, size_t length) { if(length%26 != 0) { throw new DlAbortEx("Nodes length is not multiple of 26"); } std::deque > nodes; for(size_t offset = 0; offset < length; offset += 26) { SharedHandle node = new DHTNode(reinterpret_cast(src+offset)); std::pair addr = PeerMessageUtil::unpackcompact(src+offset+DHT_ID_LENGTH); node->setIPAddress(addr.first); node->setPort(addr.second); nodes.push_back(node); } return nodes; } SharedHandle DHTMessageFactoryImpl::createFindNodeReplyMessage(const SharedHandle& remoteNode, const Dictionary* d, const std::string& transactionID) { const Data* nodesData = getData(getDictionary(d, "r"), "nodes"); std::deque > nodes = extractNodes(nodesData->getData(), nodesData->getLen()); return createFindNodeReplyMessage(remoteNode, nodes, transactionID); } SharedHandle DHTMessageFactoryImpl::createGetPeersMessage(const SharedHandle& remoteNode, const unsigned char* infoHash, const std::string& transactionID) { SharedHandle m = new DHTGetPeersMessage(_localNode, remoteNode, infoHash, transactionID); m->setPeerAnnounceStorage(_peerAnnounceStorage); m->setTokenTracker(_tokenTracker); setCommonProperty(m); return m; } SharedHandle DHTMessageFactoryImpl::createGetPeersReplyMessageWithNodes(const SharedHandle& remoteNode, const Dictionary* d, const std::string& transactionID) { const Dictionary* r = getDictionary(d, "r"); const Data* nodesData = getData(r, "nodes"); std::deque > nodes = extractNodes(nodesData->getData(), nodesData->getLen()); const Data* token = getData(r, "token"); return createGetPeersReplyMessage(remoteNode, nodes, token->toString(), transactionID); } SharedHandle DHTMessageFactoryImpl::createGetPeersReplyMessage(const SharedHandle& remoteNode, const std::deque >& closestKNodes, const std::string& token, const std::string& transactionID) { SharedHandle m = new DHTGetPeersReplyMessage(_localNode, remoteNode, token, transactionID); m->setClosestKNodes(closestKNodes); setCommonProperty(m); return m; } SharedHandle DHTMessageFactoryImpl::createGetPeersReplyMessageWithValues(const SharedHandle& remoteNode, const Dictionary* d, const std::string& transactionID) { const Dictionary* r = getDictionary(d, "r"); const List* valuesList = getList(r, "values"); std::deque > peers; for(std::deque::const_iterator i = valuesList->getList().begin(); i != valuesList->getList().end(); ++i) { const Data* data = dynamic_cast(*i); if(data && data->getLen() == 6) { std::pair addr = PeerMessageUtil::unpackcompact(data->getData()); PeerHandle peer = new Peer(addr.first, addr.second); peers.push_back(peer); } } const Data* token = getData(r, "token"); return createGetPeersReplyMessage(remoteNode, peers, token->toString(), transactionID); } SharedHandle DHTMessageFactoryImpl::createGetPeersReplyMessage(const SharedHandle& remoteNode, const std::deque >& values, const std::string& token, const std::string& transactionID) { SharedHandle m = new DHTGetPeersReplyMessage(_localNode, remoteNode, token, transactionID); m->setValues(values); setCommonProperty(m); return m; } SharedHandle DHTMessageFactoryImpl::createAnnouncePeerMessage(const SharedHandle& remoteNode, const unsigned char* infoHash, uint16_t tcpPort, const std::string& token, const std::string& transactionID) { SharedHandle m = new DHTAnnouncePeerMessage(_localNode, remoteNode, infoHash, tcpPort, token, transactionID); m->setPeerAnnounceStorage(_peerAnnounceStorage); m->setTokenTracker(_tokenTracker); setCommonProperty(m); return m; } SharedHandle DHTMessageFactoryImpl::createAnnouncePeerReplyMessage(const SharedHandle& remoteNode, const std::string& transactionID) { SharedHandle m = new DHTAnnouncePeerReplyMessage(_localNode, remoteNode, transactionID); setCommonProperty(m); return m; } SharedHandle DHTMessageFactoryImpl::createUnknownMessage(const char* data, size_t length, const std::string& ipaddr, uint16_t port) { SharedHandle m = new DHTUnknownMessage(_localNode, data, length, ipaddr, port); return m; } void DHTMessageFactoryImpl::setRoutingTable(const WeakHandle& routingTable) { _routingTable = routingTable; } void DHTMessageFactoryImpl::setConnection(const WeakHandle& connection) { _connection = connection; } void DHTMessageFactoryImpl::setMessageDispatcher(const WeakHandle& dispatcher) { _dispatcher = dispatcher; } void DHTMessageFactoryImpl::setPeerAnnounceStorage(const WeakHandle& storage) { _peerAnnounceStorage = storage; } void DHTMessageFactoryImpl::setTokenTracker(const WeakHandle& tokenTracker) { _tokenTracker = tokenTracker; } void DHTMessageFactoryImpl::setLocalNode(const SharedHandle& localNode) { _localNode = localNode; } } // namespace aria2