void ConnectionManager::connect(const Node::Ptr& node, const string& token, bool secure) { // don't allow connection if we didn't proceed a handshake if(!node->isOnline()) { // do handshake at first DHT::getInstance()->info(node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), DHT::PING | DHT::MAKE_ONLINE, node->getUser()->getCID(), node->getUdpKey()); return; } bool active = ClientManager::getInstance()->isActive(); // if I am not active, send reverse connect to me request AdcCommand cmd(active ? AdcCommand::CMD_CTM : AdcCommand::CMD_RCM, AdcCommand::TYPE_UDP); cmd.addParam(secure ? SECURE_CLIENT_PROTOCOL_TEST : CLIENT_PROTOCOL); if(active) { uint16_t port = secure ? dcpp::ConnectionManager::getInstance()->getSecurePort() : dcpp::ConnectionManager::getInstance()->getPort(); cmd.addParam(Util::toString(port)); } cmd.addParam(token); DHT::getInstance()->send(cmd, node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), node->getUser()->getCID(), node->getUdpKey()); }
/* * Sends request to create connection with me */ void ConnectionManager::revConnectToMe(const Node::Ptr& node, const AdcCommand& cmd) { // don't allow connection if we didn't proceed a handshake //if(!node->isOnline()) // return; // this is valid for active-passive connections only if(!ClientManager::getInstance()->isActive()) return; const string& protocol = cmd.getParam(1); const string& token = cmd.getParam(2); bool secure; if(protocol == CLIENT_PROTOCOL) { secure = false; } else if(protocol == SECURE_CLIENT_PROTOCOL_TEST && CryptoManager::getInstance()->TLSOk()) { secure = true; } else { AdcCommand sta(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_UNSUPPORTED, "Protocol unknown", AdcCommand::TYPE_UDP); sta.addParam("PR", protocol); sta.addParam("TO", token); DHT::getInstance()->send(sta, node->getIdentity().getIp(), node->getIdentity().getUdpPort(), node->getUser()->getCID(), node->getUdpKey()); return; } connect(node, token, secure); }
/* * Adds node to routing table */ bool KBucket::insert(const Node::Ptr& node) { if(node->isInList) return true; // node is already in the table string ip = node->getIdentity().getIp(); string port = node->getIdentity().getUdpPort(); // allow only one same IP:port bool isAcceptable = (ipMap.find(ip + ":" + port) == ipMap.end()); if((nodes.size() < (K * ID_BITS)) && isAcceptable) { nodes.push_back(node); node->isInList = true; ipMap.insert(ip + ":" + port); if(DHT::getInstance()) DHT::getInstance()->setDirty(); return true; } return isAcceptable; }
/* * Creates connection to specified node */ void ConnectionManager::connectToMe(const Node::Ptr& node, const AdcCommand& cmd) { // don't allow connection if we didn't proceed a handshake if(!node->isOnline()) { // do handshake at first DHT::getInstance()->info(node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), DHT::PING | DHT::MAKE_ONLINE, node->getUser()->getCID(), node->getUdpKey()); return; } const string& protocol = cmd.getParam(1); const string& port = cmd.getParam(2); const string& token = cmd.getParam(3); bool secure = false; if(protocol == CLIENT_PROTOCOL) { // Nothing special } else if(protocol == SECURE_CLIENT_PROTOCOL_TEST && CryptoManager::getInstance()->TLSOk()) { secure = true; } else { AdcCommand cmd(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_UNSUPPORTED, "Protocol unknown", AdcCommand::TYPE_UDP); cmd.addParam("PR", protocol); cmd.addParam("TO", token); DHT::getInstance()->send(cmd, node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), node->getUser()->getCID(), node->getUdpKey()); return; } if(!node->getIdentity().isTcpActive(0)) { AdcCommand err(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "IP unknown", AdcCommand::TYPE_UDP); DHT::getInstance()->send(err, node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), node->getUser()->getCID(), node->getUdpKey()); return; } dcpp::ConnectionManager::getInstance()->adcConnect(*node, static_cast<uint16_t>(Util::toInt(port)), token, secure); }
/* * Add new source to tth list */ void IndexManager::addSource(const TTHValue& tth, const Node::Ptr& node, uint64_t size, bool partial) { Source source; source.setCID(node->getUser()->getCID()); source.setIp(node->getIdentity().getIp()); source.setUdpPort(node->getIdentity().getUdpPort()); source.setSize(size); source.setExpires(GET_TICK() + (partial ? PFS_REPUBLISH_TIME : REPUBLISH_TIME)); source.setPartial(partial); Lock l(cs); TTHMap::iterator i = tthList.find(tth); if(i != tthList.end()) { // no user duplicites SourceList& sources = i->second; for(SourceList::iterator s = sources.begin(); s != sources.end(); ++s) { if(node->getUser()->getCID() == (*s).getCID()) { // delete old item sources.erase(s); break; } } // old items in front, new items in back sources.push_back(source); // if maximum sources reached, remove the oldest one if(sources.size() > MAX_SEARCH_RESULTS) sources.pop_front(); } else { // new file tthList.insert(std::make_pair(tth, SourceList(1, source))); } DHT::getInstance()->setDirty(); }
/* * Processes incoming request to publish file */ void IndexManager::processPublishSourceRequest(const Node::Ptr& node, const AdcCommand& cmd) { string tth; if(!cmd.getParam("TR", 1, tth)) return; // nothing to identify a file? string size; if(!cmd.getParam("SI", 1, size)) return; // no file size? string partial; cmd.getParam("PF", 1, partial); addSource(TTHValue(tth), node, Util::toInt64(size), partial == "1"); // send response AdcCommand res(AdcCommand::SEV_SUCCESS, AdcCommand::SUCCESS, "File published", AdcCommand::TYPE_UDP); res.addParam("FC", "PUB"); res.addParam("TR", tth); DHT::getInstance()->send(res, node->getIdentity().getIp(), node->getIdentity().getUdpPort(), node->getUser()->getCID(), node->getUdpKey()); }
/* * Creates new (or update existing) node which is NOT added to our routing table */ Node::Ptr KBucket::createNode(const UserPtr& u, const string& ip, uint16_t port, bool update, bool isUdpKeyValid) { if(u->isSet(User::DHT)) // is this user already known in DHT? { Node::Ptr node = NULL; // no online node found, try get from routing table for(NodeList::iterator it = nodes.begin(); it != nodes.end(); ++it) { if(u->getCID() == (*it)->getUser()->getCID()) { node = *it; // put node at the end of the list nodes.erase(it); nodes.push_back(node); break; } } if(node == NULL && u->isOnline()) { // try to get node from ClientManager (user can be online but not in our routing table) // this fixes the bug with DHT node online twice node = (Node*)ClientManager::getInstance()->findDHTNode(u->getCID()); node = node.get(); } if(node != NULL) { // fine, node found, update it and return it if(update) { string oldIp = node->getIdentity().getIp(); string oldPort = node->getIdentity().getUdpPort(); if(ip != oldIp || static_cast<uint16_t>(Util::toInt(oldPort)) != port) { node->setIpVerified(false); // TODO: don't allow update when new IP already exists for different node // erase old IP and remember new one ipMap.erase(oldIp + ":" + oldPort); ipMap.insert(ip + ":" + Util::toString(port)); } if(!node->isIpVerified()) node->setIpVerified(isUdpKeyValid); node->setAlive(); node->getIdentity().setIp(ip); node->getIdentity().setUdpPort(Util::toString(port)); DHT::getInstance()->setDirty(); } return node; } } u->setFlag(User::DHT); Node::Ptr node(new Node(u)); node->getIdentity().setIp(ip); node->getIdentity().setUdpPort(Util::toString(port)); node->setIpVerified(isUdpKeyValid); return node; }