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); } } }
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."); } }