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 );
	}
}
Esempio n. 2
0
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);
		}
	}
}