Exemplo n.º 1
0
void CMuleKad::Process(UINT Tick)
{
	if(m_MyBuddy && IsFirewalled() && m_NextBuddyPing < GetCurTick())
	{
		m_NextBuddyPing = GetCurTick() + MIN2MS(10);
		m_MyBuddy->SendBuddyPing();
	}

	QVariantMap Request;
	Request["Firewalled"] = theCore->m_MuleManager->IsFirewalled(CAddress::IPv4, false, true);
	Request["PublicIP"] = theCore->m_MuleManager->GetAddress(CAddress::IPv4, true).ToQString();
	if(theCore->m_MuleManager->IsFirewalled(CAddress::IPv4))
	{
		if(m_MyBuddy)
		{
			Request["BuddyIP"] = m_MyBuddy->GetMule().IPv4.ToQString();
			Request["BuddyPort"] = m_MyBuddy->GetKadPort();
		}
	}

	// Note: we always advertize IPv6 addresses
	CAddress IPv6 = theCore->m_MuleManager->GetAddress(CAddress::IPv6, true);
	if(!IPv6.IsNull())
		Request["IPv6"] = IPv6.ToQString();

	if(Tick & EPerSec)
	{
		if(theCore->Cfg()->GetBool("Log/Merge"))
			SyncLog();
	}

	QVariantMap Response = theCore->m_Interfaces->RemoteProcedureCall("MuleKad", "SyncState", Request).toMap();

	m_KadID = Response["KadID"].toByteArray();

	if(Response["Result"] == "Connected")
	{
		if(m_KadStatus != eConnected)
		{
			LogLine(LOG_SUCCESS, tr("MuleKad Connected, ID: %1").arg(QString(m_KadID.toHex()).toUpper()));
			m_KadStatus = eConnected;
		}
	}
	else if(Response["Result"] == "Connecting")
		m_KadStatus = eConnecting;
	else //if(Response["Result"] == "Disconnected")
		m_KadStatus = eDisconnected;

	if(m_KadStatus == eDisconnected)
	{
		if(GetCurTick() > m_NextConnectionAttempt)
		{
			LogLine(LOG_INFO, tr("Connecting emule kademlia"));
			m_NextConnectionAttempt = GetCurTick() + SEC2MS(theCore->Cfg()->GetInt("Ed2kMule/IdleTimeout"));
			StartKad();
		}
		return;
	}
	
	m_Address = CAddress(Response["PublicIP"].toString());
	m_KadPort = Response["KadPort"].toUInt(); // external kad port
	//m_UDPPort = Response["UDPPort"].toUInt(); // socket port
	m_Firewalled = Response["Firewalled"].toBool();
	m_KadFirewalled = Response["KadFirewalled"].toBool();
	
	if (m_KadFirewalled && m_uNextKadFirewallRecheck <= GetCurTick())
	{
		m_uNextKadFirewallRecheck = GetCurTick() + SEC2MS(theCore->Cfg()->GetInt("Ed2kMule/CheckFWInterval"));
		CheckFWState();
	}

	foreach(const QVariant& vQueuedFWCheck, Response["QueuedFWChecks"].toList())
	{
		QVariantMap QueuedFWCheck = vQueuedFWCheck.toMap();

		SMuleSource Mule;
		Mule.SetIP(CAddress(QueuedFWCheck["Address"].toString()));
		Mule.TCPPort = QueuedFWCheck["TCPPort"].toUInt();
		Mule.ConOpts.Bits = QueuedFWCheck["ConOpts"].toUInt(); 
		if(Mule.ConOpts.Fields.RequestsCryptLayer) // some cleints seam to mess this up
			Mule.ConOpts.Fields.SupportsCryptLayer = true;
		QByteArray UserHash = QueuedFWCheck["UserHash"].toByteArray();
		
		if(!Mule.SelectIP() || !theCore->m_PeerWatch->CheckPeer(Mule.GetIP(), Mule.TCPPort))
			continue;

		bool bAdded = false;
		CMuleClient* pClient = theCore->m_MuleManager->GetClient(Mule, &bAdded);
		if(!bAdded)
		{
			if(QueuedFWCheck["TestUDP"].toBool() == true)
				SetUDPFWCheckResult(pClient, true);
			continue;
		}

		if(QueuedFWCheck["TestUDP"].toBool() == true)
		{
			uint32 UDPKey;
			if(QueuedFWCheck.contains("UDPKey"))
				UDPKey = QueuedFWCheck["UDPKey"].toUInt();
			else
				UDPKey = theCore->m_MuleManager->GetServer()->GetUDPKey(Mule.GetIP());
			m_QueuedFWChecks.insert(pClient, SFWCheck(QueuedFWCheck["IntPort"].toUInt(), QueuedFWCheck["ExtPort"].toUInt(), UDPKey));
		}
		else
			m_QueuedFWChecks.insert(pClient, SFWCheck());

		connect(pClient, SIGNAL(HelloRecived()), this, SLOT(OnHelloRecived()));
		connect(pClient, SIGNAL(SocketClosed()), this, SLOT(OnSocketClosed()));

		pClient->SetUserHash(UserHash);
		pClient->Connect();
	}

	QList<CAddress> PendingFWChecks;
	foreach(const QVariant& vPendingFWCheck, Response["PendingFWChecks"].toList())
	{
		QVariantMap PendingFWCheck = vPendingFWCheck.toMap();
		PendingFWChecks.append(CAddress(PendingFWCheck["Address"].toString()));
	}
	theCore->m_MuleManager->GetServer()->SetExpected(PendingFWChecks);

	foreach(const QVariant& vBufferedCallback, Response["BufferedCallbacks"].toList())
	{
		QVariantMap BufferedCallback = vBufferedCallback.toMap();

		CAddress Address = CAddress(BufferedCallback["Address"].toString());
		uint16 uPort = BufferedCallback["TCPPort"].toUInt();
		QByteArray BuddyID = BufferedCallback["BuddyID"].toByteArray();
		QByteArray FileID = BufferedCallback["FileID"].toByteArray();

		if(m_MyBuddy && m_MyBuddy->IsFirewalled(CAddress::IPv4))
		{
			if(m_MyBuddy->GetBuddyID() == BuddyID)
				m_MyBuddy->RelayKadCallback(Address, uPort, BuddyID, FileID);
		}
	}

	// Note: This comes in on the normal UDP Socket, as we provide thesocket now we dont haveto pull it
	/*foreach(const QVariant& vBufferedPackets, Response["BufferedPackets"].toList())
	{
		QVariantMap BufferedPackets = vBufferedPackets.toMap();

		CAddress Address = CAddress(BufferedPackets["Address"].toString());
		uint16 uPort = BufferedPackets["UDPPort"].toUInt();
		QByteArray Data = BufferedPackets["Data"].toByteArray();
			
		CBuffer Packet((byte*)Data.data(), Data.size(), true);
		RelayUDPPacket(Address, uPort, Packet);
	}

	foreach(const QVariant& vPendingCallback, Response["PendingCallbacks"].toList())
	{
		QVariantMap PendingCallback = vPendingCallback.toMap();

		SMuleSource Mule;
		Mule.SetIP(CAddress(PendingCallback["Address"].toString()));
		Mule.TCPPort = PendingCallback["TCPPort"].toUInt();
		Mule.UserHash = PendingCallback["UserHash"].toByteArray();
		Mule.ConOpts.Bits = PendingCallback["ConOpts"].toUInt();
		if(Mule.ConOpts.Fields.RequestsCryptLayer) // some cleints seam to mess this up
			Mule.ConOpts.Fields.SupportsCryptLayer = true;
		theCore->m_MuleManager->CallbackRequested(Mule);
	}*/

	foreach(const QVariant& vPendingBuddys, Response["PendingBuddys"].toList())
	{
		if(m_MyBuddy) // if we have a buddy we are not interested in new ones
			break;

		QVariantMap PendingBuddy = vPendingBuddys.toMap();

		SMuleSource Mule;
		Mule.SetIP(CAddress(PendingBuddy["Address"].toString()));
		Mule.TCPPort = PendingBuddy["TCPPort"].toUInt();
		Mule.KadPort = PendingBuddy["KadPort"].toUInt();
		Mule.ConOpts.Bits = PendingBuddy["ConOpts"].toUInt();
		if(Mule.ConOpts.Fields.RequestsCryptLayer) // some cleints seam to mess this up
			Mule.ConOpts.Fields.SupportsCryptLayer = true;
		Mule.UserHash = PendingBuddy["UserHash"].toByteArray();
		Mule.BuddyID = PendingBuddy["BuddyID"].toByteArray();

		if(!theCore->m_PeerWatch->CheckPeer(Mule.GetIP(), Mule.TCPPort))
			continue;

		bool bAdded = false;
		CMuleClient* pClient = theCore->m_MuleManager->GetClient(Mule, &bAdded);
		if(!bAdded)
			continue; // already known clients are not viable budies

		connect(pClient, SIGNAL(HelloRecived()), this, SLOT(OnHelloRecived()));
		connect(pClient, SIGNAL(SocketClosed()), this, SLOT(OnSocketClosed()));
		if(m_PendingBuddys.contains(pClient))
			continue; // already listes
		m_PendingBuddys.append(pClient);

		if(PendingBuddy["Incoming"].toBool()) // is this a lowID client that wants us to become his buddy ans will soon connect us?
			pClient->ExpectConnection();
		else //this is a high ID client that agreed to become our buddy
			pClient->Connect();
	}

	m_KadStats = Response["Stats"].toMap();

	if(Tick & EPerSec)
	{
		if(IsConnected())
		{
			SyncFiles();
			SyncNotes();

			foreach(CAbstractSearch* pSearch, m_RunningSearches)
				SyncSearch(pSearch);
		}
	}
}
Exemplo n.º 2
0
void CNetwork::HubBalancing()
{
	QMutexLocker l(&Neighbours.m_pSection);

	systemLog.postLog(LogSeverity::Notice, "*** HUB BALANCING REPORT ***");

	// get the local hub cluster load
	quint32 nLeaves = 0, nMaxLeaves = 0, nClusterLoad = 0, nLocalLoad = 0;

	const quint32 MINUTES_TRYING_BEFORE_SWITCH = 10; // emergency hub switch
	if(!isHub())
	{
		if(Neighbours.m_nHubsConnected == 0)   // if we're not connected to any hub
		{
			m_nMinutesTrying++;
			if(m_nMinutesTrying > MINUTES_TRYING_BEFORE_SWITCH)   // if no hub connects in this time
			{
				// emergency switch to hub mode, normal downgrades will filter out bad upgrades
				systemLog.postLog(LogSeverity::Notice, "No HUB connections for %u minutes, switching to HUB mode.", MINUTES_TRYING_BEFORE_SWITCH);
				SwitchClientMode(G2_HUB);
			}
			return;
		}
		else
		{
			m_nMinutesTrying = 0;
		}
	}

	// check how many leaves are in local hub cluster
	for(QList<CNeighbour*>::iterator itNode = Neighbours.begin(); itNode != Neighbours.end(); ++itNode)
	{
		CNeighbour* pNode = *itNode;
		if( pNode->m_nProtocol == dpGnutella2 && pNode->m_nState == nsConnected && ((CG2Node*)pNode)->m_nType == G2_HUB)
		{
			nLeaves += ((CG2Node*)pNode)->m_nLeafCount;
			nMaxLeaves += ((CG2Node*)pNode)->m_nLeafMax;
		}
	}

	if(isHub())
	{
		// add our numbers to cluster load
		nLeaves += Neighbours.m_nLeavesConnected;
		nMaxLeaves += quazaaSettings.Gnutella2.NumLeafs;
		// and calculate local hub load percentage
		nLocalLoad = Neighbours.m_nLeavesConnected * 100 / quazaaSettings.Gnutella2.NumLeafs;
		systemLog.postLog(LogSeverity::Notice, "Local Hub load: %u%%, leaves connected: %u, capacity: %u", nLocalLoad, Neighbours.m_nLeavesConnected, quazaaSettings.Gnutella2.NumLeafs);
	}

	// calculate local cluster load percentage
	nClusterLoad = nLeaves * 100 / nMaxLeaves;

	systemLog.postLog(LogSeverity::Notice, "Local Hub Cluster load: %u%%, leaves connected: %u, capacity: %u", nClusterLoad, nLeaves, nMaxLeaves);

	if(nClusterLoad < 50)
	{
		// if local cluster load is below 50%, increment counter
		m_nMinutesBelow50++;
		systemLog.postLog(LogSeverity::Notice, "Cluster loaded below 50%% for %u minutes.", m_nMinutesBelow50);
	}
	else if(nClusterLoad > 90)
	{
		// if local cluster load is above 90%, increment counter
		m_nMinutesAbove90++;
		systemLog.postLog(LogSeverity::Notice, "Cluster loaded above 90%% for %u minutes.", m_nMinutesAbove90);
	}
	else
	{
		// reset counters
		m_nMinutesAbove90 = 0;
		m_nMinutesBelow50 = 0;
	}

	if(quazaaSettings.Gnutella2.ClientMode != 0)   // if client mode is forced in settings
	{
		systemLog.postLog(LogSeverity::Notice, "Not checking for mode change possibility: current client mode forced.");
		return;
	}

	quint32 tNow = time(0);

	const quint32 MODE_CHANGE_WAIT = 1800; // grace period since last mode change
	const quint32 UPGRADE_TIMEOUT = 30; // if cluster loaded for this time - upgrade
	const quint32 DOWNGRADE_TIMEOUT = 60; // if cluster not loaded for this time - downgrade

	if(tNow - m_tLastModeChange < MODE_CHANGE_WAIT)
	{
		// too early for mode change
		systemLog.postLog(LogSeverity::Notice, "Not checking for mode change possibility: too early from last mode change.");
		return;
	}

	if(isHub() && m_nMinutesBelow50 > DOWNGRADE_TIMEOUT)
	{
		// if we're running in hub mode and timeout passed

		if(Neighbours.m_nHubsConnected > 0)   // if we have connections to other hubs
		{
			if(nLocalLoad > 50)   // and our load is below 50%
			{
				systemLog.postLog(LogSeverity::Notice, "Cluster load too low for too long, staying in HUB mode, we are above 50%% of our capacity.");
			}
			else
			{
				// switch to leaf mode
				systemLog.postLog(LogSeverity::Notice, "Cluster load too low for too long, switching to LEAF mode.");
				SwitchClientMode(G2_LEAF);
			}
		}
		else
		{
			// no connections to other hubs - stay in HUB mode
			systemLog.postLog(LogSeverity::Notice, "Cluster load too low for too long, staying in HUB mode due to lack of HUB connections.");
		}
	}
	else if(!isHub() && m_nMinutesAbove90 > UPGRADE_TIMEOUT)
	{
		// if we're running in leaf mode and timeout passed

		// TODO: Analyze computers performance and upgrade only if it meets minimum requirements

		if(!IsFirewalled())
		{
			// switch to HUB mode
			systemLog.postLog(LogSeverity::Notice, "Cluster load too high for too long, switching to HUB mode.");
			SwitchClientMode(G2_HUB);
		}
	}
	else
	{
		systemLog.postLog(LogSeverity::Notice, "No need for mode change.");
	}

}