void CServerList::ServerStats() { // Update the server list even if we are connected to Kademlia only. The idea is for both networks to keep // each other up to date.. Kad network can get you back into the ED2K network.. And the ED2K network can get // you back into the Kad network.. if (theApp.IsConnected() && theApp.serverconnect->IsUDPSocketAvailable() && list.GetCount() > 0) { CServer* ping_server = GetNextStatServer(); if (!ping_server) return; uint32 tNow = (uint32)time(NULL); const CServer* test = ping_server; while (ping_server->GetLastPingedTime() != 0 && (tNow - ping_server->GetLastPingedTime()) < UDPSERVSTATREASKTIME) { ping_server = GetNextStatServer(); if (ping_server == test) return; } // IP-filter: We do not need to IP-filter any servers here, even dynIP-servers are not // needed to get filtered here. See also comments in 'CServerSocket::ConnectTo'. if (ping_server->GetFailedCount() >= thePrefs.GetDeadServerRetries()) { //Xman // Mighty Knife: Static server handling // Static servers can be prevented from being removed from the list. if ((!ping_server->IsStaticMember()) || (!thePrefs.GetDontRemoveStaticServers())) { theApp.emuledlg->serverwnd->serverlistctrl.RemoveServer(ping_server); return; } //Xman end } srand(tNow); ping_server->SetRealLastPingedTime(tNow); // this is not used to calcualte the next ping, but only to ensure a minimum delay for premature pings if (!ping_server->GetCryptPingReplyPending() && (tNow - ping_server->GetLastPingedTime()) >= UDPSERVSTATREASKTIME && theApp.GetPublicIP() != 0 && thePrefs.IsServerCryptLayerUDPEnabled()){ // we try a obfsucation ping first and wait 20 seconds for an answer // if it doesn'T get responsed, we don't count it as error but continue with a normal ping ping_server->SetCryptPingReplyPending(true); uint32 nPacketLen = 4 + (uint8)(rand() % 16); // max padding 16 bytes BYTE* pRawPacket = new BYTE[nPacketLen]; uint32 dwChallenge = (rand() << 17) | (rand() << 2) | (rand() & 0x03); if (dwChallenge == 0) dwChallenge++; PokeUInt32(pRawPacket, dwChallenge); for (uint32 i = 4; i < nPacketLen; i++) // fillung up the remaining bytes with random data pRawPacket[i] = (uint8)rand(); ping_server->SetChallenge(dwChallenge); ping_server->SetLastPinged(GetTickCount()); ping_server->SetLastPingedTime((tNow - (uint32)UDPSERVSTATREASKTIME) + 20); // give it 20 seconds to respond if (thePrefs.GetDebugServerUDPLevel() > 0) Debug(_T(">>> Sending OP__GlobServStatReq (obfuscated) to server %s:%u\n"), ping_server->GetAddress(), ping_server->GetPort()); theStats.AddUpDataOverheadServer(nPacketLen); theApp.serverconnect->SendUDPPacket(NULL, ping_server, true, ping_server->GetPort() + 12, pRawPacket, nPacketLen); } else if (ping_server->GetCryptPingReplyPending() || theApp.GetPublicIP() == 0 || !thePrefs.IsServerCryptLayerUDPEnabled()){ // our obfsucation ping request was not answered, so probably the server doesn'T supports obfuscation // continue with a normal request if (ping_server->GetCryptPingReplyPending() && thePrefs.IsServerCryptLayerUDPEnabled()) DEBUG_ONLY(DebugLog(_T("CryptPing failed for server %s"), ping_server->GetListName())); else if (thePrefs.IsServerCryptLayerUDPEnabled()) DEBUG_ONLY(DebugLog(_T("CryptPing skipped because our public IP is unknown for server %s"), ping_server->GetListName())); ping_server->SetCryptPingReplyPending(false); Packet* packet = new Packet(OP_GLOBSERVSTATREQ, 4); uint32 uChallenge = 0x55AA0000 + GetRandomUInt16(); ping_server->SetChallenge(uChallenge); PokeUInt32(packet->pBuffer, uChallenge); ping_server->SetLastPinged(GetTickCount()); ping_server->SetLastPingedTime(tNow - (rand() % HR2S(1))); ping_server->AddFailedCount(); theApp.emuledlg->serverwnd->serverlistctrl.RefreshServer(ping_server); if (thePrefs.GetDebugServerUDPLevel() > 0) Debug(_T(">>> Sending OP__GlobServStatReq (not obfuscated) to server %s:%u\n"), ping_server->GetAddress(), ping_server->GetPort()); theStats.AddUpDataOverheadServer(packet->size); theApp.serverconnect->SendUDPPacket(packet, ping_server, true); } else ASSERT( false ); } }
void CServerList::ServerStats() { uint32 tNow = ::GetTickCount(); if (theApp->IsConnectedED2K() && m_servers.size() > 0) { CServer* ping_server = GetNextStatServer(); CServer* test = ping_server; if (!ping_server) { return; } while (ping_server->GetLastPingedTime() && (tNow - ping_server->GetLastPingedTime()) < UDPSERVSTATREASKTIME) { ping_server = GetNextStatServer(); if (ping_server == test) { return; } } if (ping_server->GetFailedCount() >= thePrefs::GetDeadserverRetries() && thePrefs::DeadServer() && !ping_server->IsStaticMember()) { RemoveServer(ping_server); return; } srand((unsigned)time(NULL)); ping_server->SetRealLastPingedTime(tNow); // this is not used to calcualte the next ping, but only to ensure a minimum delay for premature pings if (!ping_server->GetCryptPingReplyPending() && (!ping_server->GetLastPingedTime() || (tNow - ping_server->GetLastPingedTime()) >= UDPSERVSTATREASKTIME) && theApp->GetPublicIP() && thePrefs::IsServerCryptLayerUDPEnabled()) { // We try a obfsucation ping first and wait 20 seconds for an answer // if it doesn't get responsed, we don't count it as error but continue with a normal ping ping_server->SetCryptPingReplyPending(true); uint32 nPacketLen = 4 + (uint8)(rand() % 16); // max padding 16 bytes CScopedArray<byte> pRawPacket(nPacketLen); uint32 dwChallenge = (rand() << 17) | (rand() << 2) | (rand() & 0x03); if (dwChallenge == 0) { dwChallenge++; } memcpy(pRawPacket.get(), &dwChallenge, sizeof(uint32)); for (uint32 i = 4; i < nPacketLen; i++) { // fillng up the remaining bytes with random data pRawPacket[i] = (uint8)rand(); } ping_server->SetChallenge(dwChallenge); ping_server->SetLastPinged(tNow); ping_server->SetLastPingedTime((tNow - (uint32)UDPSERVSTATREASKTIME) + 20); // give it 20 seconds to respond AddDebugLogLineN(logServerUDP, CFormat(wxT(">> Sending OP__GlobServStatReq (obfuscated) to server %s:%u")) % ping_server->GetAddress() % ping_server->GetPort()); CPacket* packet = new CPacket(pRawPacket[1], nPacketLen - 2, pRawPacket[0]); packet->CopyToDataBuffer(0, pRawPacket.get() + 2, nPacketLen - 2); theStats::AddUpOverheadServer(packet->GetPacketSize()); theApp->serverconnect->SendUDPPacket(packet, ping_server, true, true /*raw packet*/, 12 /* Port offset is 12 for obfuscated encryption*/); } else if (ping_server->GetCryptPingReplyPending() || theApp->GetPublicIP() == 0 || !thePrefs::IsServerCryptLayerUDPEnabled()){ // our obfsucation ping request was not answered, so probably the server doesn'T supports obfuscation // continue with a normal request if (ping_server->GetCryptPingReplyPending() && thePrefs::IsServerCryptLayerUDPEnabled()) { AddDebugLogLineN(logServerUDP, wxT("CryptPing failed for server ") + ping_server->GetListName()); } else if (thePrefs::IsServerCryptLayerUDPEnabled()) { AddDebugLogLineN(logServerUDP, wxT("CryptPing skipped because our public IP is unknown for server ") + ping_server->GetListName()); } ping_server->SetCryptPingReplyPending(false); CPacket* packet = new CPacket(OP_GLOBSERVSTATREQ, 4, OP_EDONKEYPROT); uint32 challenge = 0x55AA0000 + (uint16)rand(); ping_server->SetChallenge(challenge); packet->CopyUInt32ToDataBuffer(challenge); ping_server->SetLastPinged(tNow); ping_server->SetLastPingedTime(tNow - (rand() % HR2S(1))); ping_server->AddFailedCount(); Notify_ServerRefresh(ping_server); theStats::AddUpOverheadServer(packet->GetPacketSize()); theApp->serverconnect->SendUDPPacket(packet, ping_server, true); } else { wxFAIL; } } }
void CServerList::ServerStats() { // Update the server list even if we are connected to Kademlia only. The idea is for both networks to keep // each other up to date.. Kad network can get you back into the ED2K network.. And the ED2K network can get // you back into the Kad network.. if (theApp.IsConnected() && theApp.serverconnect->IsUDPSocketAvailable() && list.GetCount() > 0) { CServer* ping_server = GetNextStatServer(); if (!ping_server) return; uint32 tNow = (uint32)time(NULL); const CServer* test = ping_server; while (ping_server->GetLastPingedTime() != 0 && (tNow - ping_server->GetLastPingedTime()) < UDPSERVSTATREASKTIME) { ping_server = GetNextStatServer(); if (ping_server == test) return; } if (ping_server->GetFailedCount() >= thePrefs.GetDeadServerRetries()) { // Mighty Knife: Static server handling // Static servers can be prevented from being removed from the list. if ((!ping_server->IsStaticMember()) || (!thePrefs.GetDontRemoveStaticServers())) { theApp.emuledlg->serverwnd->serverlistctrl.RemoveServer(ping_server); return; } // [end] Mighty Knife theApp.emuledlg->serverwnd->serverlistctrl.RemoveServer(ping_server); return; } Packet* packet = new Packet(OP_GLOBSERVSTATREQ, 4); srand(tNow); uint32 uChallenge = 0x55AA0000 + GetRandomUInt16(); ping_server->SetChallenge(uChallenge); PokeUInt32(packet->pBuffer, uChallenge); ping_server->SetLastPinged(GetTickCount()); ping_server->SetLastPingedTime(tNow); ping_server->AddFailedCount(); theApp.emuledlg->serverwnd->serverlistctrl.RefreshServer(ping_server); if (thePrefs.GetDebugServerUDPLevel() > 0) Debug(_T(">>> Sending OP__GlobServStatReq to server %s:%u\n"), ping_server->GetAddress(), ping_server->GetPort()); theStats.AddUpDataOverheadServer(packet->size); theApp.serverconnect->SendUDPPacket(packet, ping_server, true); ping_server->SetLastDescPingedCount(false); if (ping_server->GetLastDescPingedCount() < 2) { // eserver 16.45+ supports a new OP_SERVER_DESC_RES answer, if the OP_SERVER_DESC_REQ contains a uint32 // challenge, the server returns additional info with OP_SERVER_DESC_RES. To properly distinguish the // old and new OP_SERVER_DESC_RES answer, the challenge has to be selected carefully. The first 2 bytes // of the challenge (in network byte order) MUST NOT be a valid string-len-int16! packet = new Packet(OP_SERVER_DESC_REQ, 4); uint32 uDescReqChallenge = ((uint32)GetRandomUInt16() << 16) + INV_SERV_DESC_LEN; // 0xF0FF = an 'invalid' string length. ping_server->SetDescReqChallenge(uDescReqChallenge); PokeUInt32(packet->pBuffer, uDescReqChallenge); theStats.AddUpDataOverheadServer(packet->size); if (thePrefs.GetDebugServerUDPLevel() > 0) Debug(_T(">>> Sending OP__ServDescReq to server %s:%u, challenge %08x\n"), ping_server->GetAddress(), ping_server->GetPort(), uDescReqChallenge); theApp.serverconnect->SendUDPPacket(packet, ping_server, true); } else { ping_server->SetLastDescPingedCount(true); } } }