/// Byte-swap the summary data, in case it was saved by a system /// on a different platform void BlockFile::FixSummary(void *data) { if (mSummaryInfo.format != floatSample || mSummaryInfo.fields != 3) return; float *summary64K = (float *)((char *)data + mSummaryInfo.offset64K); float *summary256 = (float *)((char *)data + mSummaryInfo.offset256); float min, max; int bad; int i; ComputeMinMax256(summary256, &min, &max, &bad); if (min != summary64K[0] || max != summary64K[1] || bad > 0) { unsigned int *buffer = (unsigned int *)data; int len = mSummaryInfo.totalSummaryBytes / 4; for(i=0; i<len; i++) buffer[i] = wxUINT32_SWAP_ALWAYS(buffer[i]); ComputeMinMax256(summary256, &min, &max, &bad); if (min == summary64K[0] && max == summary64K[1] && bad == 0) { // The byte-swapping worked! return; } // Hmmm, no better, we should swap back for(i=0; i<len; i++) buffer[i] = wxUINT32_SWAP_ALWAYS(buffer[i]); } }
void CECTag::InitInt(uint64 data) { if (data <= 0xFF) { m_dataType = EC_TAGTYPE_UINT8; m_dataLen = 1; } else if (data <= 0xFFFF) { m_dataType = EC_TAGTYPE_UINT16; m_dataLen = 2; } else if (data <= 0xFFFFFFFF) { m_dataType = EC_TAGTYPE_UINT32; m_dataLen = 4; } else { m_dataType = EC_TAGTYPE_UINT64; m_dataLen = 8; } NewData(); switch (m_dataType) { case EC_TAGTYPE_UINT8: PokeUInt8( m_tagData, (uint8) data ); break; case EC_TAGTYPE_UINT16: PokeUInt16( m_tagData, wxUINT16_SWAP_ALWAYS((uint16) data )); break; case EC_TAGTYPE_UINT32: PokeUInt32( m_tagData, wxUINT32_SWAP_ALWAYS((uint32) data )); break; case EC_TAGTYPE_UINT64: PokeUInt64( m_tagData, wxUINT64_SWAP_ALWAYS(data) ); break; } }
bool CClientList::IncomingBuddy(Kademlia::CContact* contact, Kademlia::CUInt128* buddyID) { uint32_t nContactIP = wxUINT32_SWAP_ALWAYS(contact->GetIPAddress()); //If aMule already knows this client, abort this.. It could cause conflicts. //Although the odds of this happening is very small, it could still happen. if (FindClientByIP(nContactIP, contact->GetTCPPort())) { return false; } else if (IsKadFirewallCheckIP(nContactIP)) { // doing a kad firewall check with this IP, abort AddDebugLogLineN(logKadMain, wxT("Kad TCP firewallcheck / Buddy request collision for IP ") + Uint32toStringIP(nContactIP)); return false; } if (theApp->GetPublicIP() == nContactIP && thePrefs::GetPort() == contact->GetTCPPort()) { return false; // don't connect ourself } //Add client to the lists to be processed. CUpDownClient* pNewClient = new CUpDownClient(contact->GetTCPPort(), contact->GetIPAddress(), 0, 0, NULL, false, true ); pNewClient->SetKadPort(contact->GetUDPPort()); pNewClient->SetKadState(KS_INCOMING_BUDDY); byte ID[16]; contact->GetClientID().ToByteArray(ID); pNewClient->SetUserHash(CMD4Hash(ID)); buddyID->ToByteArray(ID); pNewClient->SetBuddyID(ID); AddToKadList(pNewClient); AddClient(pNewClient); return true; }
void CClientList::RequestBuddy(Kademlia::CContact* contact, uint8_t connectOptions) { uint32_t nContactIP = wxUINT32_SWAP_ALWAYS(contact->GetIPAddress()); // Don't connect to ourself if (theApp->GetPublicIP() == nContactIP && thePrefs::GetPort() == contact->GetTCPPort()) { return; } CUpDownClient* pNewClient = FindClientByIP(nContactIP, contact->GetTCPPort()); if (!pNewClient) { pNewClient = new CUpDownClient(contact->GetTCPPort(), contact->GetIPAddress(), 0, 0, NULL, false, true ); } else if (pNewClient->GetKadState() != KS_NONE) { return; // already busy with this client in some way (probably fw stuff), don't mess with it } else if (IsKadFirewallCheckIP(nContactIP)) { // doing a kad firewall check with this IP, abort AddDebugLogLineN(logKadMain, wxT("Kad TCP firewallcheck / Buddy request collision for IP ") + Uint32toStringIP(nContactIP)); return; } //Add client to the lists to be processed. pNewClient->SetKadPort(contact->GetUDPPort()); pNewClient->SetKadState(KS_QUEUED_BUDDY); uint8_t ID[16]; contact->GetClientID().ToByteArray(ID); pNewClient->SetUserHash(CMD4Hash(ID)); pNewClient->SetConnectOptions(connectOptions, true, false); AddToKadList(pNewClient); //This method checks if this is a dup already. AddClient(pNewClient); }
bool CClientList::RequestTCP(Kademlia::CContact* contact, uint8_t connectOptions) { uint32_t nContactIP = wxUINT32_SWAP_ALWAYS(contact->GetIPAddress()); // don't connect ourself if (theApp->GetPublicIP() == nContactIP && thePrefs::GetPort() == contact->GetTCPPort()) { return false; } CUpDownClient* pNewClient = FindClientByIP(nContactIP, contact->GetTCPPort()); if (!pNewClient) { //#warning Do we actually have to check friendstate here? pNewClient = new CUpDownClient(contact->GetTCPPort(), contact->GetIPAddress(), 0, 0, NULL, false, true); } else if (pNewClient->GetKadState() != KS_NONE) { return false; // already busy with this client in some way (probably buddy stuff), don't mess with it } //Add client to the lists to be processed. pNewClient->SetKadPort(contact->GetUDPPort()); pNewClient->SetKadState(KS_QUEUED_FWCHECK); if (contact->GetClientID() != 0) { uint8_t ID[16]; contact->GetClientID().ToByteArray(ID); pNewClient->SetUserHash(CMD4Hash(ID)); pNewClient->SetConnectOptions(connectOptions, true, false); } AddToKadList(pNewClient); // This was a direct adding, but I like to check duplicates //This method checks if this is a dup already. AddClient(pNewClient); return true; }
void CDownloadQueue::CheckAndAddKnownSource(CPartFile* sender,CUpDownClient* source) { // Kad reviewed if (sender->IsStopped()) { return; } // Filter sources which are known to be dead/useless if ( sender->IsDeadSource(source) ) { return; } // "Filter LAN IPs" -- this may be needed here in case we are connected to the internet and are also connected // to a LAN and some client from within the LAN connected to us. Though this situation may be supported in future // by adding that client to the source list and filtering that client's LAN IP when sending sources to // a client within the internet. // // "IPfilter" is not needed here, because that "known" client was already IPfiltered when receiving OP_HELLO. if (!source->HasLowID()) { uint32 nClientIP = wxUINT32_SWAP_ALWAYS(source->GetUserIDHybrid()); if (!IsGoodIP(nClientIP, thePrefs::FilterLanIPs())) { // check for 0-IP, localhost and LAN addresses AddDebugLogLineN(logIPFilter, wxT("Ignored already known source with IP=%s") + Uint32toStringIP(nClientIP)); return; } } // Filter sources which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it) if ( (source->RequiresCryptLayer() && (!thePrefs::IsClientCryptLayerSupported() || !source->HasValidHash())) || (thePrefs::IsClientCryptLayerRequired() && (!source->SupportsCryptLayer() || !source->HasValidHash()))) { source->Safe_Delete(); return; } CPartFile* file = source->GetRequestFile(); // Check if the file is already queued for something else if ( file ) { if ( file != sender ) { if ( source->AddRequestForAnotherFile( sender ) ) { Notify_SourceCtrlAddSource( sender, CCLIENTREF(source, wxT("CDownloadQueue::CheckAndAddKnownSource Notify_SourceCtrlAddSource 1")), A4AF_SOURCE ); } } } else { source->SetRequestFile( sender ); if ( source->GetFileRating() || !source->GetFileComment().IsEmpty() ) { sender->UpdateFileRatingCommentAvail(); } source->SetSourceFrom(SF_PASSIVE); sender->AddSource( source ); Notify_SourceCtrlAddSource( sender, CCLIENTREF(source, wxT("CDownloadQueue::CheckAndAddKnownSource Notify_SourceCtrlAddSource 2")), UNAVAILABLE_SOURCE); } }
bool CClientList::DoRequestFirewallCheckUDP(const Kademlia::CContact& contact) { // first make sure we don't know this IP already from somewhere if (IsIPAlreadyKnown(wxUINT32_SWAP_ALWAYS(contact.GetIPAddress()))) { return false; } // fine, just create the client object, set the state and wait // TODO: We don't know the client's userhash, this means we cannot build an obfuscated connection, which // again mean that the whole check won't work on "Require Obfuscation" setting, which is not a huge problem, // but certainly not nice. Only somewhat acceptable way to solve this is to use the KadID instead. CUpDownClient* pNewClient = new CUpDownClient(contact.GetTCPPort(), contact.GetIPAddress(), 0, 0, NULL, false, true); pNewClient->SetKadState(KS_QUEUED_FWCHECK_UDP); AddDebugLogLineN(logClient, wxT("Selected client for UDP Firewallcheck: ") + KadIPToString(contact.GetIPAddress())); AddToKadList(pNewClient); AddClient(pNewClient); wxASSERT(!pNewClient->SupportsDirectUDPCallback()); return true; }
void CDownloadQueue::KademliaSearchFile(uint32_t searchID, const Kademlia::CUInt128* pcontactID, const Kademlia::CUInt128* pbuddyID, uint8_t type, uint32_t ip, uint16_t tcp, uint16_t udp, uint32_t buddyip, uint16_t buddyport, uint8_t byCryptOptions) { AddDebugLogLineN(logKadSearch, CFormat(wxT("Search result sources (type %i)")) % type); //Safety measure to make sure we are looking for these sources CPartFile* temp = GetFileByKadFileSearchID(searchID); if( !temp ) { AddDebugLogLineN(logKadSearch, wxT("This is not the file we're looking for...")); return; } //Do we need more sources? if(!(!temp->IsStopped() && thePrefs::GetMaxSourcePerFile() > temp->GetSourceCount())) { AddDebugLogLineN(logKadSearch, wxT("No more sources needed for this file")); return; } uint32_t ED2KID = wxUINT32_SWAP_ALWAYS(ip); if (theApp->ipfilter->IsFiltered(ED2KID)) { AddDebugLogLineN(logKadSearch, wxT("Source ip got filtered")); AddDebugLogLineN(logIPFilter, CFormat(wxT("IPfiltered source IP=%s received from Kademlia")) % Uint32toStringIP(ED2KID)); return; } if( (ip == Kademlia::CKademlia::GetIPAddress() || ED2KID == theApp->GetED2KID()) && tcp == thePrefs::GetPort()) { AddDebugLogLineN(logKadSearch, wxT("Trying to add myself as source, ignore")); return; } CUpDownClient* ctemp = NULL; switch (type) { case 4: case 1: { // NonFirewalled users if(!tcp) { AddDebugLogLineN(logKadSearch, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, no tcp port received")) % Uint32toStringIP(ip)); return; } if (!IsGoodIP(ED2KID,thePrefs::FilterLanIPs())) { AddDebugLogLineN(logKadSearch, CFormat(wxT("%s got filtered")) % Uint32toStringIP(ED2KID)); AddDebugLogLineN(logIPFilter, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, filtered")) % Uint32toStringIP(ED2KID)); return; } ctemp = new CUpDownClient(tcp, ip, 0, 0, temp, false, true); ctemp->SetSourceFrom(SF_KADEMLIA); // not actually sent or needed for HighID sources //ctemp->SetServerIP(serverip); //ctemp->SetServerPort(serverport); ctemp->SetKadPort(udp); byte cID[16]; pcontactID->ToByteArray(cID); ctemp->SetUserHash(CMD4Hash(cID)); break; } case 2: { // Don't use this type... Some clients will process it wrong.. break; } case 5: case 3: { // This will be a firewalled client connected to Kad only. // We set the clientID to 1 as a Kad user only has 1 buddy. ctemp = new CUpDownClient(tcp, 1, 0, 0, temp, false, true); // The only reason we set the real IP is for when we get a callback // from this firewalled source, the compare method will match them. ctemp->SetSourceFrom(SF_KADEMLIA); ctemp->SetKadPort(udp); byte cID[16]; pcontactID->ToByteArray(cID); ctemp->SetUserHash(CMD4Hash(cID)); pbuddyID->ToByteArray(cID); ctemp->SetBuddyID(cID); ctemp->SetBuddyIP(buddyip); ctemp->SetBuddyPort(buddyport); break; } case 6: { // firewalled source which supports direct UDP callback // if we are firewalled ourself, the source is useless to us if (theApp->IsFirewalled()) { break; } if ((byCryptOptions & 0x08) == 0){ AddDebugLogLineN(logKadSearch, CFormat(wxT("Received Kad source type 6 (direct callback) which has the direct callback flag not set (%s)")) % Uint32toStringIP(ED2KID)); break; } ctemp = new CUpDownClient(tcp, 1, 0, 0, temp, false, true); ctemp->SetSourceFrom(SF_KADEMLIA); ctemp->SetKadPort(udp); ctemp->SetIP(ED2KID); // need to set the IP address, which cannot be used for TCP but for UDP byte cID[16]; pcontactID->ToByteArray(cID); ctemp->SetUserHash(CMD4Hash(cID)); } } if (ctemp) { // add encryption settings ctemp->SetConnectOptions(byCryptOptions); AddDebugLogLineN(logKadSearch, CFormat(wxT("Happily adding a source (%s) type %d")) % Uint32_16toStringIP_Port(ED2KID, ctemp->GetUserPort()) % type); CheckAndAddSource(temp, ctemp); } }
void CClientList::Process() { const uint32 cur_tick = ::GetTickCount(); if (m_dwLastBannCleanUp + BAN_CLEANUP_TIME < cur_tick) { m_dwLastBannCleanUp = cur_tick; ClientMap::iterator it = m_bannedList.begin(); while ( it != m_bannedList.end() ) { if ( it->second + CLIENTBANTIME < cur_tick ) { ClientMap::iterator tmp = it++; m_bannedList.erase( tmp ); theStats::RemoveBannedClient(); } else { ++it; } } } if ( m_dwLastTrackedCleanUp + TRACKED_CLEANUP_TIME < cur_tick ) { m_dwLastTrackedCleanUp = cur_tick; std::map<uint32, CDeletedClient*>::iterator it = m_trackedClientsList.begin(); while ( it != m_trackedClientsList.end() ) { std::map<uint32, CDeletedClient*>::iterator cur_src = it++; if ( cur_src->second->m_dwInserted + KEEPTRACK_TIME < cur_tick ) { delete cur_src->second; m_trackedClientsList.erase( cur_src ); } } } //We need to try to connect to the clients in m_KadList //If connected, remove them from the list and send a message back to Kad so we can send a ACK. //If we don't connect, we need to remove the client.. //The sockets timeout should delete this object. // buddy is just a flag that is used to make sure we are still connected or connecting to a buddy. buddyState buddy = Disconnected; CClientRefSet::iterator current_it = m_KadSources.begin(); while (current_it != m_KadSources.end()) { CUpDownClient* cur_client = current_it->GetClient(); ++current_it; // Won't be used anymore till while loop if( !Kademlia::CKademlia::IsRunning() ) { //Clear out this list if we stop running Kad. //Setting the Kad state to KS_NONE causes it to be removed in the switch below. cur_client->SetKadState(KS_NONE); } switch (cur_client->GetKadState()) { case KS_QUEUED_FWCHECK: case KS_QUEUED_FWCHECK_UDP: //Another client asked us to try to connect to them to check their firewalled status. cur_client->TryToConnect(true); break; case KS_CONNECTING_FWCHECK: //Ignore this state as we are just waiting for results. break; case KS_FWCHECK_UDP: case KS_CONNECTING_FWCHECK_UDP: // We want a UDP firewallcheck from this client and are just waiting to get connected to send the request break; case KS_CONNECTED_FWCHECK: //We successfully connected to the client. //We now send a ack to let them know. if (cur_client->GetKadVersion() >= 7) { // The result is now sent per TCP instead of UDP, because this will fail if our intern port is unreachable. // But we want the TCP testresult regardless if UDP is firewalled, the new UDP state and test takes care of the rest wxASSERT(cur_client->IsConnected()); AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_KAD_FWTCPCHECK_ACK to ") + Uint32toStringIP(cur_client->GetIP())); CPacket *packet = new CPacket(OP_KAD_FWTCPCHECK_ACK, 0, OP_EMULEPROT); cur_client->SafeSendPacket(packet); } else { AddDebugLogLineN(logClientKadUDP, wxT("KadFirewalledAckRes to ") + Uint32_16toStringIP_Port(cur_client->GetIP(), cur_client->GetKadPort())); Kademlia::CKademlia::GetUDPListener()->SendNullPacket(KADEMLIA_FIREWALLED_ACK_RES, wxUINT32_SWAP_ALWAYS(cur_client->GetIP()), cur_client->GetKadPort(), 0, NULL); } //We are done with this client. Set Kad status to KS_NONE and it will be removed in the next cycle. cur_client->SetKadState(KS_NONE); break; case KS_INCOMING_BUDDY: //A firewalled client wants us to be his buddy. //If we already have a buddy, we set Kad state to KS_NONE and it's removed in the next cycle. //If not, this client will change to KS_CONNECTED_BUDDY when it connects. if( m_nBuddyStatus == Connected ) { cur_client->SetKadState(KS_NONE); } break; case KS_QUEUED_BUDDY: //We are firewalled and want to request this client to be a buddy. //But first we check to make sure we are not already trying another client. //If we are not already trying. We try to connect to this client. //If we are already connected to a buddy, we set this client to KS_NONE and it's removed next cycle. //If we are trying to connect to a buddy, we just ignore as the one we are trying may fail and we can then try this one. if( m_nBuddyStatus == Disconnected ) { buddy = Connecting; m_nBuddyStatus = Connecting; cur_client->SetKadState(KS_CONNECTING_BUDDY); cur_client->TryToConnect(true); Notify_ServerUpdateED2KInfo(); } else { if( m_nBuddyStatus == Connected ) { cur_client->SetKadState(KS_NONE); } } break; case KS_CONNECTING_BUDDY: //We are trying to connect to this client. //Although it should NOT happen, we make sure we are not already connected to a buddy. //If we are we set to KS_NONE and it's removed next cycle. //But if we are not already connected, make sure we set the flag to connecting so we know //things are working correctly. if( m_nBuddyStatus == Connected ) { cur_client->SetKadState(KS_NONE); } else { wxASSERT( m_nBuddyStatus == Connecting ); buddy = Connecting; } break; case KS_CONNECTED_BUDDY: //A potential connected buddy client wanting to me in the Kad network //We set our flag to connected to make sure things are still working correctly. buddy = Connected; //If m_nBuddyStatus is not connected already, we set this client as our buddy! if( m_nBuddyStatus != Connected ) { m_pBuddy.Link(cur_client CLIENT_DEBUGSTRING("CClientList::Process KS_CONNECTED_BUDDY m_pBuddy.Link")); m_nBuddyStatus = Connected; Notify_ServerUpdateED2KInfo(); } if( m_pBuddy.GetClient() == cur_client && theApp->IsFirewalled() && cur_client->SendBuddyPingPong() ) { cur_client->SendBuddyPing(); } break; default: RemoveFromKadList(cur_client); } } //We either never had a buddy, or lost our buddy.. if( buddy == Disconnected ) { if( m_nBuddyStatus != Disconnected || m_pBuddy.IsLinked() ) { if( Kademlia::CKademlia::IsRunning() && theApp->IsFirewalled() && Kademlia::CUDPFirewallTester::IsFirewalledUDP(true) ) { //We are a lowID client and we just lost our buddy. //Go ahead and instantly try to find a new buddy. Kademlia::CKademlia::GetPrefs()->SetFindBuddy(); } m_pBuddy.Unlink(); m_nBuddyStatus = Disconnected; Notify_ServerUpdateED2KInfo(); } } if ( Kademlia::CKademlia::IsConnected() ) { // we only need a buddy if direct callback is not available if(Kademlia::CKademlia::IsFirewalled() && Kademlia::CUDPFirewallTester::IsFirewalledUDP(true)) { // TODO: Kad buddies won't work with RequireCrypt, so it is disabled for now, but should (and will) // be fixed in later version // Update: buddy connections themselves support obfuscation properly since eMule 0.49a and aMule SVN 2008-05-09 // (this makes it work fine if our buddy uses require crypt), however callback requests don't support it yet so we // wouldn't be able to answer callback requests with RequireCrypt, protocolchange intended for eMule 0.49b if(m_nBuddyStatus == Disconnected && Kademlia::CKademlia::GetPrefs()->GetFindBuddy() && !thePrefs::IsClientCryptLayerRequired()) { AddDebugLogLineN(logKadMain, wxT("Starting BuddySearch")); //We are a firewalled client with no buddy. We have also waited a set time //to try to avoid a false firewalled status.. So lets look for a buddy.. if (!Kademlia::CSearchManager::PrepareLookup(Kademlia::CSearch::FINDBUDDY, true, Kademlia::CUInt128(true) ^ (Kademlia::CKademlia::GetPrefs()->GetKadID()))) { //This search ID was already going. Most likely reason is that //we found and lost our buddy very quickly and the last search hadn't //had time to be removed yet. Go ahead and set this to happen again //next time around. Kademlia::CKademlia::GetPrefs()->SetFindBuddy(); } } } else { if (m_pBuddy.IsLinked()) { //Lets make sure that if we have a buddy, they are firewalled! //If they are also not firewalled, then someone must have fixed their firewall or stopped saturating their line.. //We just set the state of this buddy to KS_NONE and things will be cleared up with the next cycle. if( !m_pBuddy.HasLowID() ) { m_pBuddy.GetClient()->SetKadState(KS_NONE); } } } } else { if (m_pBuddy.IsLinked()) { //We are not connected anymore. Just set this buddy to KS_NONE and things will be cleared out on next cycle. m_pBuddy.GetClient()->SetKadState(KS_NONE); } } CleanUpClientList(); ProcessDirectCallbackList(); }