예제 #1
0
	/*
	 * Remove dead nodes
	 */
	bool KBucket::checkExpiration(uint64_t currentTime)
	{
		bool dirty = false;

		// we should ping oldest node from every bucket here
		// but since we have only one bucket now, simulate it by pinging more nodes
		unsigned int pingCount = max(K, min((int)2 * K, (int)(nodes.size() / (K * 10)) + 1)); // <-- pings 10 - 20 oldest nodes
		unsigned int pinged = 0;
		dcdrun(unsigned int removed = 0);

		// first, remove dead nodes
		NodeList::iterator i = nodes.begin();
		while(i != nodes.end())
		{
			Node::Ptr& node = *i;

			if(node->getType() == 4 && node->expires > 0 && node->expires <= currentTime)
			{
				if(node->unique(2))
				{
					// node is dead, remove it
					string ip	= node->getIdentity().getIp();
					string port = node->getIdentity().getUdpPort();
					ipMap.erase(ip + ":" + port);

					if(node->isOnline())
					{
						ClientManager::getInstance()->putOffline(node.get());
						node->dec();
					}

					i = nodes.erase(i);
					dirty = true;

					dcdrun(removed++);
				}
				else
				{
					++i;
				}

				continue;
			}

			if(node->expires == 0)
				node->expires = currentTime;

			// select the oldest expired node
			if(pinged < pingCount && node->getType() < 4 && node->expires <= currentTime)
			{
				// ping the oldest (expired) node
				node->setTimeout(currentTime);
				DHT::getInstance()->info(node->getIdentity().getIp(), static_cast<uint16_t>(Util::toInt(node->getIdentity().getUdpPort())), DHT::PING, node->getUser()->getCID(), node->getUdpKey());
				pinged++;
			}

			++i;
		}

#ifdef _DEBUG
		int verified = 0; int types[5] = { 0 };
		for(NodeList::const_iterator j = nodes.begin(); j != nodes.end(); j++)
		{
			Node::Ptr n = *j;
			if(n->isIpVerified()) verified++;

			dcassert(n->getType() >= 0 && n->getType() <= 4);
			types[n->getType()]++;
		}

		dcdebug("DHT Nodes: %d (%d verified), Types: %d/%d/%d/%d/%d, pinged %d of %d, removed %d\n", nodes.size(), verified, types[0], types[1], types[2], types[3], types[4], pinged, pingCount, removed);
#endif

		return dirty;
	}
예제 #2
0
	/*
	 * 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;
	}