void CRoutingZone::DbgWriteBootstrapFile() { DebugLogWarning(_T("Writing special bootstrap nodes.dat - not intended for normal use")); try { // Write a saved contact list. CUInt128 uID; CSafeBufferedFile file; CFileException fexp; if (file.Open(m_sFilename, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary|CFile::shareDenyWrite, &fexp)) { setvbuf(file.m_pStream, NULL, _IOFBF, 32768); // The bootstrap method gets a very nice sample of contacts to save. ContactMap mapContacts; CUInt128 uRandom(CUInt128((ULONG)0), 0); CUInt128 uDistance = uRandom; uDistance.Xor(uMe); GetClosestTo(2, uRandom, uDistance, 1200, &mapContacts, false, false); // filter out Kad1 nodes for (ContactMap::iterator itContactMap = mapContacts.begin(); itContactMap != mapContacts.end(); ) { ContactMap::iterator itCurContactMap = itContactMap; ++itContactMap; CContact* pContact = itCurContactMap->second; if (pContact->GetVersion() <= 1) mapContacts.erase(itCurContactMap); } // Start file with 0 to prevent older clients from reading it. file.WriteUInt32(0); // Now tag it with a version which happens to be 2 (1 till 0.48a). file.WriteUInt32(3); file.WriteUInt32(1); // if we would use version >=3, this would mean that this is not a normal nodes.dat file.WriteUInt32((uint32_t)mapContacts.size()); for (ContactMap::const_iterator itContactMap = mapContacts.begin(); itContactMap != mapContacts.end(); ++itContactMap) { CContact* pContact = itContactMap->second; pContact->GetClientID(&uID); file.WriteUInt128(&uID); file.WriteUInt32(pContact->GetIPAddress()); file.WriteUInt16(pContact->GetUDPPort()); file.WriteUInt16(pContact->GetTCPPort()); file.WriteUInt8(pContact->GetVersion()); } file.Close(); AddDebugLogLine( false, _T("Wrote %ld contact to bootstrap file."), mapContacts.size()); } else DebugLogError(_T("Unable to store Kad file: %s"), m_sFilename); } catch (CFileException* e) { e->Delete(); AddDebugLogLine(false, _T("CFileException in CRoutingZone::writeFile")); } }
void CRoutingZone::WriteFile() { // don't overwrite a bootstrap nodes.dat with an empty one, if we didn't finished probing if (!CKademlia::s_liBootstapList.IsEmpty() && GetNumContacts() == 0){ DebugLogWarning(_T("Skipped storing nodes.dat, because we have an unfinished bootstrap of the nodes.dat version and no contacts in our routing table")); return; } try { // Write a saved contact list. CUInt128 uID; CSafeBufferedFile file; CFileException fexp; if (file.Open(m_sFilename, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary|CFile::shareDenyWrite, &fexp)) { setvbuf(file.m_pStream, NULL, _IOFBF, 32768); // The bootstrap method gets a very nice sample of contacts to save. ContactList listContacts; GetBootstrapContacts(&listContacts, 200); // Start file with 0 to prevent older clients from reading it. file.WriteUInt32(0); // Now tag it with a version which happens to be 2 (1 till 0.48a). file.WriteUInt32(2); // file.WriteUInt32(0) // if we would use version >=3, this would mean that this is a normal nodes.dat file.WriteUInt32((uint32_t)listContacts.size()); for (ContactList::const_iterator itContactList = listContacts.begin(); itContactList != listContacts.end(); ++itContactList) { CContact* pContact = *itContactList; pContact->GetClientID(&uID); file.WriteUInt128(&uID); file.WriteUInt32(pContact->GetIPAddress()); file.WriteUInt16(pContact->GetUDPPort()); file.WriteUInt16(pContact->GetTCPPort()); file.WriteUInt8(pContact->GetVersion()); pContact->GetUDPKey().StoreToFile(file); file.WriteUInt8(pContact->IsIpVerified() ? 1 : 0); } file.Close(); AddDebugLogLine( false, _T("Wrote %ld contact%s to file."), listContacts.size(), ((listContacts.size() == 1) ? _T("") : _T("s"))); } else DebugLogError(_T("Unable to store Kad file: %s"), m_sFilename); } catch (CFileException* e) { e->Delete(); AddDebugLogLine(false, _T("CFileException in CRoutingZone::writeFile")); } }
bool CKademlia::FindNodeIDByIP(CKadClientSearcher& requester, uint32_t ip, uint16_t tcpPort, uint16_t udpPort) { wxCHECK(IsRunning() && instance && GetUDPListener() && GetRoutingZone(), false); // first search our known contacts if we can deliver a result without asking, otherwise forward the request CContact* contact; if ((contact = GetRoutingZone()->GetContact(wxUINT32_SWAP_ALWAYS(ip), tcpPort, true)) != NULL) { uint8_t nodeID[16]; contact->GetClientID().ToByteArray(nodeID); requester.KadSearchNodeIDByIPResult(KCSR_SUCCEEDED, nodeID); return true; } else { return GetUDPListener()->FindNodeIDByIP(&requester, wxUINT32_SWAP_ALWAYS(ip), tcpPort, udpPort); } }
bool CKademlia::FindNodeIDByIP(CKadClientSearcher& rRequester, uint32_t dwIP, uint16_t nTCPPort, uint16_t nUDPPort) { if (!IsRunning() || m_pInstance == NULL || GetUDPListener() == NULL || GetRoutingZone() == NULL){ ASSERT( false ); return false; } // first search our known contacts if we can deliver a result without asking, otherwise forward the request CContact* pContact; if ((pContact = GetRoutingZone()->GetContact(ntohl(dwIP), nTCPPort, true)) != NULL){ uchar uchID[16]; pContact->GetClientID().ToByteArray(uchID); rRequester.KadSearchNodeIDByIPResult(KCSR_SUCCEEDED, uchID); return true; } else return GetUDPListener()->FindNodeIDByIP(&rRequester, ntohl(dwIP), nTCPPort, nUDPPort); }
void CRoutingZone::WriteFile() { try { // Write a saved contact list. CUInt128 uID; //CSafeBufferedFile file; CBufferedFileIO file; CFileException fexp; if (file.Open(m_sFilename, CFile::modeWrite | CFile::modeCreate | CFile::typeBinary|CFile::shareDenyWrite, &fexp)) { setvbuf(file.m_pStream, NULL, _IOFBF, 32768); // The bootstrap method gets a very nice sample of contacts to save. ContactList listContacts; GetBootstrapContacts(&listContacts, 200); // Start file with 0 to prevent older clients from reading it. file.WriteUInt32(0); // Now tag it with a version which happens to be 1. file.WriteUInt32(1); file.WriteUInt32((uint32)listContacts.size()); for (ContactList::const_iterator itContactList = listContacts.begin(); itContactList != listContacts.end(); ++itContactList) { CContact* pContact = *itContactList; pContact->GetClientID(&uID); file.WriteUInt128(&uID); file.WriteUInt32(pContact->GetIPAddress()); file.WriteUInt16(pContact->GetUDPPort()); file.WriteUInt16(pContact->GetTCPPort()); file.WriteUInt8(pContact->GetVersion()); } file.Close(); //AddDebugLogLine( false, _T("Wrote %ld contact%s to file."), listContacts.size(), ((listContacts.size() == 1) ? _T("") : _T("s"))); TRACE(_T("Wrote %ld contact%s to file.\n"), listContacts.size(), ((listContacts.size() == 1) ? _T("") : _T("s"))); } } catch (CFileException* e) { e->Delete(); AddDebugLogLine(false, _T("CFileException in CRoutingZone::writeFile")); } }
void CUDPFirewallTester::QueryNextClient(){ // try the next available client for the firewallcheck if (!IsFWCheckUDPRunning() || !GetUDPCheckClientsNeeded() || CKademlia::GetPrefs()->GetExternalKadPort() == 0) return; // check if more tests are needed and wait till we know our extern port if (!CKademlia::IsRunning() || CKademlia::GetRoutingZone() == NULL){ ASSERT( false ); return; } while (!m_liPossibleTestClients.IsEmpty()){ CContact curContact = m_liPossibleTestClients.RemoveHead(); // udp firewallchecks are not supported by clients with kadversion < 6 if (curContact.GetVersion() <= KADEMLIA_VERSION5_48a) continue; // sanitize - do not test ourself if (ntohl(curContact.GetIPAddress()) == theApp.GetPublicIP() || curContact.GetClientID().CompareTo(CKademlia::GetPrefs()->GetKadID()) == 0) continue; // check if we actually requested a firewallcheck from this client at some point bool bAlreadyRequested = false; for (POSITION pos = m_liUsedTestClients.GetHeadPosition(); pos != NULL;){ if (m_liUsedTestClients.GetNext(pos).contact.GetIPAddress() == curContact.GetIPAddress()){ bAlreadyRequested = true; break; } } // check if we know itsIP already from kademlia - we need an IP which was never used for UDP yet if (!bAlreadyRequested && CKademlia::GetRoutingZone()->GetContact(curContact.GetIPAddress(), 0, false) == NULL){ // ok, tell the clientlist to do the same search and start the check if ok if (theApp.clientlist->DoRequestFirewallCheckUDP(curContact)){ UsedClient_Struct sAdd = { curContact, false }; m_liUsedTestClients.AddHead(sAdd); m_byFWChecksRunningUDP++; break; } } } }
void CKademlia::Process() { if (instance == NULL || !m_running) { return; } time_t now = time(NULL); uint32_t maxUsers = 0; uint32_t tempUsers = 0; uint32_t lastContact = 0; bool updateUserFile = false; wxASSERT(instance->m_prefs != NULL); lastContact = instance->m_prefs->GetLastContact(); CSearchManager::UpdateStats(); if (m_statusUpdate <= now) { updateUserFile = true; m_statusUpdate = MIN2S(1) + now; } if (m_nextFirewallCheck <= now) { RecheckFirewalled(); } if (m_nextSelfLookup <= now) { CSearchManager::FindNode(instance->m_prefs->GetKadID(), true); m_nextSelfLookup = HR2S(4) + now; } if (m_nextFindBuddy <= now) { instance->m_prefs->SetFindBuddy(); m_nextFindBuddy = MIN2S(20) + now; } if (m_externPortLookup <= now && CUDPFirewallTester::IsFWCheckUDPRunning() && GetPrefs()->FindExternKadPort(false)) { // If our UDP firewallcheck is running and we don't know our external port, we send a request every 15 seconds CContact *contact = GetRoutingZone()->GetRandomContact(3, 6); if (contact != NULL) { AddDebugLogLineN(logKadPrefs, wxT("Requesting our external port from ") + KadIPToString(contact->GetIPAddress())); DebugSend(Kad2Ping, contact->GetIPAddress(), contact->GetUDPPort()); GetUDPListener()->SendNullPacket(KADEMLIA2_PING, contact->GetIPAddress(), contact->GetUDPPort(), contact->GetUDPKey(), &contact->GetClientID()); } else { AddDebugLogLineN(logKadPrefs, wxT("No valid client for requesting external port available")); } m_externPortLookup = 15 + now; } for (EventMap::const_iterator it = m_events.begin(); it != m_events.end(); ++it) { CRoutingZone *zone = it->first; if (updateUserFile) { // The EstimateCount function is not made for really small networks, if we are in LAN mode, it is actually // better to assume that all users of the network are in our routing table and use the real count function if (IsRunningInLANMode()) { tempUsers = zone->GetNumContacts(); } else { tempUsers = zone->EstimateCount(); } if (maxUsers < tempUsers) { maxUsers = tempUsers; } } if (m_bigTimer <= now) { if (zone->m_nextBigTimer <= now) { if(zone->OnBigTimer()) { zone->m_nextBigTimer = HR2S(1) + now; m_bigTimer = SEC(10) + now; } } else { if (lastContact && (now - lastContact > KADEMLIADISCONNECTDELAY - MIN2S(5))) { if(zone->OnBigTimer()) { zone->m_nextBigTimer = HR2S(1) + now; m_bigTimer = SEC(10) + now; } } } } if (zone->m_nextSmallTimer <= now) { zone->OnSmallTimer(); zone->m_nextSmallTimer = MIN2S(1) + now; } } // This is a convenient place to add this, although not related to routing if (m_nextSearchJumpStart <= now) { CSearchManager::JumpStart(); m_nextSearchJumpStart = SEARCH_JUMPSTART + now; } // Try to consolidate any zones that are close to empty. if (m_consolidate <= now) { uint32_t mergedCount = instance->m_routingZone->Consolidate(); if (mergedCount) { AddDebugLogLineN(logKadRouting, CFormat(wxT("Kad merged %u zones")) % mergedCount); } m_consolidate = MIN2S(45) + now; } // Update user count only if changed. if (updateUserFile) { if (maxUsers != instance->m_prefs->GetKademliaUsers()) { instance->m_prefs->SetKademliaUsers(maxUsers); instance->m_prefs->SetKademliaFiles(); theApp->ShowUserCount(); } } if (!IsConnected() && !s_bootstrapList.empty() && (now - m_bootstrap > 15 || (GetRoutingZone()->GetNumContacts() == 0 && now - m_bootstrap >= 2))) { CContact *contact = s_bootstrapList.front(); s_bootstrapList.pop_front(); m_bootstrap = now; AddDebugLogLineN(logKadMain, CFormat(wxT("Trying to bootstrap Kad from %s, Distance: %s Version: %u, %u contacts left")) % KadIPToString(contact->GetIPAddress()) % contact->GetDistance().ToHexString() % contact->GetVersion() % s_bootstrapList.size()); instance->m_udpListener->Bootstrap(contact->GetIPAddress(), contact->GetUDPPort(), contact->GetVersion(), &contact->GetClientID()); delete contact; } if (GetUDPListener() != NULL) { GetUDPListener()->ExpireClientSearch(); // function does only one compare in most cases, so no real need for a timer } }
void CRoutingZone::OnSmallTimer() { if (!IsLeaf()) return; CContact *pContact = NULL; time_t tNow = time(NULL); ContactList listEntries; // Remove dead entries m_pBin->GetEntries(&listEntries); for (ContactList::iterator itContactList = listEntries.begin(); itContactList != listEntries.end(); ++itContactList) { pContact = *itContactList; if ( pContact->GetType() == 4) { if (((pContact->m_tExpires > 0) && (pContact->m_tExpires <= tNow))) { if(!pContact->InUse()) { //----------------------------------------------------------------- CString strID; CUInt128 uId = pContact->GetClientID(); uId.ToHexString(&strID); CString strIP; pContact->GetIPAddress(&strIP); TRACE(_T("DelContact id=%s ip=%s %u %u %u\n"), strID, strIP, pContact->GetTCPPort(), pContact->GetUDPPort(), CKademlia::GetRoutingZone()->GetNumContacts()); //----------------------------------------------------------------- m_pBin->RemoveContact(pContact); delete pContact; } continue; } } if(pContact->m_tExpires == 0) pContact->m_tExpires = tNow; } pContact = m_pBin->GetOldest(); if( pContact != NULL ) { if ( pContact->m_tExpires >= tNow || pContact->GetType() == 4) { m_pBin->RemoveContact(pContact); m_pBin->m_listEntries.push_back(pContact); pContact = NULL; } } if(pContact != NULL) { pContact->CheckingType(); if (pContact->GetVersion() >= 2/*47a*/) { //--->xt if (thePrefs.GetDebugClientKadUDPLevel() > 0) //DebugSend("KADEMLIA2_HELLO_REQ", pContact->GetIPAddress(), pContact->GetUDPPort()); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, pContact->GetIPAddress(), pContact->GetUDPPort(), true); } else { //--->xt if (thePrefs.GetDebugClientKadUDPLevel() > 0) //DebugSend("KADEMLIA_HELLO_REQ", pContact->GetIPAddress(), pContact->GetUDPPort()); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA_HELLO_REQ, pContact->GetIPAddress(), pContact->GetUDPPort(), false); if (pContact->CheckIfKad2()) { //--->xt if (thePrefs.GetDebugClientKadUDPLevel() > 0) //DebugSend("KADEMLIA2_HELLO_REQ", pContact->GetIPAddress(), pContact->GetUDPPort()); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, pContact->GetIPAddress(), pContact->GetUDPPort(), true); } } } }
void CKademlia::Process() { if( m_pInstance == NULL || !m_bRunning) return; bool bUpdateUserFile = false; uint32_t uMaxUsers = 0; uint32_t uTempUsers = 0; time_t uLastContact = 0; time_t tNow = time(NULL); ASSERT(m_pInstance->m_pPrefs != NULL); uLastContact = m_pInstance->m_pPrefs->GetLastContact(); CSearchManager::UpdateStats(); if( m_tStatusUpdate <= tNow ) { bUpdateUserFile = true; m_tStatusUpdate = MIN2S(1) + tNow; } if( m_tNextFirewallCheck <= tNow) RecheckFirewalled(); if (m_tNextUPnPCheck != 0 && m_tNextUPnPCheck <= tNow) { theApp.emuledlg->RefreshUPnP(); m_tNextUPnPCheck = 0; // will be reset on firewallcheck } if (m_tNextSelfLookup <= tNow) { CSearchManager::FindNode(m_pInstance->m_pPrefs->GetKadID(), true); m_tNextSelfLookup = HR2S(4) + tNow; } if (m_tNextFindBuddy <= tNow) { m_pInstance->m_pPrefs->SetFindBuddy(); m_tNextFindBuddy = MIN2S(20) + tNow; } if (m_tExternPortLookup <= tNow && CUDPFirewallTester::IsFWCheckUDPRunning() && GetPrefs()->FindExternKadPort(false)){ // if our UDP firewallcheck is running and we don't know our external port, we send a request every 15 seconds CContact* pContact = GetRoutingZone()->GetRandomContact(3, KADEMLIA_VERSION6_49aBETA); if (pContact != NULL){ DEBUG_ONLY( DebugLog(_T("Requesting our external port from %s"), ipstr(ntohl(pContact->GetIPAddress()))) ); GetUDPListener()->SendNullPacket(KADEMLIA2_PING, pContact->GetIPAddress(), pContact->GetUDPPort(), pContact->GetUDPKey(), &pContact->GetClientID()); } else DEBUG_ONLY( DebugLogWarning(_T("No valid client for requesting external port available")) ); m_tExternPortLookup = 15 + tNow; } for (EventMap::const_iterator itEventMap = m_mapEvents.begin(); itEventMap != m_mapEvents.end(); ++itEventMap) { CRoutingZone* pZone = itEventMap->first; if( bUpdateUserFile ) { uTempUsers = pZone->EstimateCount(); if( uMaxUsers < uTempUsers ) uMaxUsers = uTempUsers; } if (m_tBigTimer <= tNow) { if( pZone->m_tNextBigTimer <= tNow ) { if(pZone->OnBigTimer()) { pZone->m_tNextBigTimer = HR2S(1) + tNow; m_tBigTimer = SEC(10) + tNow; } } else { if( uLastContact && ( (tNow - uLastContact) > (KADEMLIADISCONNECTDELAY-MIN2S(5)))) { if(pZone->OnBigTimer()) { pZone->m_tNextBigTimer = HR2S(1) + tNow; m_tBigTimer = SEC(10) + tNow; } } } } if (pZone->m_tNextSmallTimer <= tNow) { pZone->OnSmallTimer(); pZone->m_tNextSmallTimer = MIN2S(1) + tNow; } } // This is a convenient place to add this, although not related to routing if (m_tNextSearchJumpStart <= tNow) { CSearchManager::JumpStart(); m_tNextSearchJumpStart = SEARCH_JUMPSTART + tNow; } // Try to consolidate any zones that are close to empty. if (m_tConsolidate <= tNow) { uint32_t uMergedCount = m_pInstance->m_pRoutingZone->Consolidate(); if(uMergedCount) AddDebugLogLine(false, _T("Kad merged %u Zones"), uMergedCount); m_tConsolidate = MIN2S(45) + tNow; } //Update user count only if changed. if( bUpdateUserFile ) { if( uMaxUsers != m_pInstance->m_pPrefs->GetKademliaUsers()) { m_pInstance->m_pPrefs->SetKademliaUsers(uMaxUsers); m_pInstance->m_pPrefs->SetKademliaFiles(); theApp.emuledlg->ShowUserCount(); } } if(!IsConnected() && !s_liBootstapList.IsEmpty() && (tNow - m_tBootstrap > 15 || (GetRoutingZone()->GetNumContacts() == 0 && tNow - m_tBootstrap >= 2))) { CContact* pContact = s_liBootstapList.RemoveHead(); m_tBootstrap = tNow; DebugLog(_T("Trying to Bootstrap Kad from %s, Distance: %s, Version: %u, %u Contacts left"), ipstr(ntohl(pContact->GetIPAddress())), pContact->GetDistance().ToHexString(), pContact->GetVersion(), s_liBootstapList.GetCount()); m_pInstance->m_pUDPListener->Bootstrap(pContact->GetIPAddress(), pContact->GetUDPPort(), pContact->GetVersion() > 1, pContact->GetVersion(), &pContact->GetClientID()); delete pContact; } if (GetUDPListener() != NULL) GetUDPListener()->ExpireClientSearch(); // function does only one compare in most cases, so no real need for a timer }
void CRoutingZone::OnSmallTimer() { if (!IsLeaf()) { return; } CContact *c = NULL; time_t now = time(NULL); ContactList entries; // Remove dead entries m_bin->GetEntries(&entries); for (ContactList::iterator it = entries.begin(); it != entries.end(); ++it) { c = *it; if (c->GetType() == 4) { if ((c->GetExpireTime() > 0) && (c->GetExpireTime() <= now)) { if (!c->InUse()) { m_bin->RemoveContact(c); delete c; } continue; } } if(c->GetExpireTime() == 0) { c->SetExpireTime(now); } } c = m_bin->GetOldest(); if (c != NULL) { if (c->GetExpireTime() >= now || c->GetType() == 4) { m_bin->PushToBottom(c); c = NULL; } } if (c != NULL) { c->CheckingType(); if (c->GetVersion() >= 6) { DebugSend(L"Kad2HelloReq", c->GetIPAddress(), c->GetUDPPort()); CUInt128 clientID = c->GetClientID(); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, c->GetIPAddress(), c->GetUDPPort(), c->GetVersion(), c->GetUDPKey(), &clientID, false); if (c->GetVersion() >= 8) { // FIXME: // This is a bit of a work around for statistic values. Normally we only count values from incoming HELLO_REQs for // the firewalled statistics in order to get numbers from nodes which have us on their routing table, // however if we send a HELLO due to the timer, the remote node won't send a HELLO_REQ itself anymore (but // a HELLO_RES which we don't count), so count those statistics here. This isn't really accurate, but it should // do fair enough. Maybe improve it later for example by putting a flag into the contact and make the answer count CKademlia::GetPrefs()->StatsIncUDPFirewalledNodes(false); CKademlia::GetPrefs()->StatsIncTCPFirewalledNodes(false); } } else if (c->GetVersion() >= 2) { DebugSend(L"Kad2HelloReq", c->GetIPAddress(), c->GetUDPPort()); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, c->GetIPAddress(), c->GetUDPPort(), c->GetVersion(), 0, NULL, false); ASSERT(c->GetUDPKey() == CKadUDPKey(0)); } else { ASSERT(0); } } }
void CRoutingZone::OnSmallTimer() { if (!IsLeaf()) return; CContact *pContact = NULL; time_t tNow = time(NULL); ContactList listEntries; // Remove dead entries m_pBin->GetEntries(&listEntries); for (ContactList::iterator itContactList = listEntries.begin(); itContactList != listEntries.end(); ++itContactList) { pContact = *itContactList; if ( pContact->GetType() == 4) { if (((pContact->m_tExpires > 0) && (pContact->m_tExpires <= tNow))) { if(!pContact->InUse()) { m_pBin->RemoveContact(pContact); delete pContact; } continue; } } if(pContact->m_tExpires == 0) pContact->m_tExpires = tNow; } pContact = m_pBin->GetOldest(); if( pContact != NULL ) { if ( pContact->m_tExpires >= tNow || pContact->GetType() == 4) { m_pBin->PushToBottom(pContact); pContact = NULL; } } if(pContact != NULL) { pContact->CheckingType(); if (pContact->GetVersion() >= 6){ /*48b*/ if (thePrefs.GetDebugClientKadUDPLevel() > 0) DebugSend("KADEMLIA2_HELLO_REQ", pContact->GetIPAddress(), pContact->GetUDPPort()); CUInt128 uClientID = pContact->GetClientID(); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, pContact->GetIPAddress(), pContact->GetUDPPort(), pContact->GetVersion(), pContact->GetUDPKey(), &uClientID, false); if (pContact->GetVersion() >= KADEMLIA_VERSION8_49b){ // FIXME: // This is a bit of a work arround for statistic values. Normally we only count values from incoming HELLO_REQs for // the firewalled statistics in order to get numbers from nodes which have us on their routing table, // however if we send a HELLO due to the timer, the remote node won't send a HELLO_REQ itself anymore (but // a HELLO_RES which we don't count), so count those statistics here. This isn't really accurate, but it should // do fair enough. Maybe improve it later for example by putting a flag into the contact and make the answer count CKademlia::GetPrefs()->StatsIncUDPFirewalledNodes(false); CKademlia::GetPrefs()->StatsIncTCPFirewalledNodes(false); } } else if (pContact->GetVersion() >= 2/*47a*/){ if (thePrefs.GetDebugClientKadUDPLevel() > 0) DebugSend("KADEMLIA2_HELLO_REQ", pContact->GetIPAddress(), pContact->GetUDPPort()); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, pContact->GetIPAddress(), pContact->GetUDPPort(), pContact->GetVersion(), 0, NULL, false); ASSERT( CKadUDPKey(0) == pContact->GetUDPKey() ); } else { if (thePrefs.GetDebugClientKadUDPLevel() > 0) DebugSend("KADEMLIA_HELLO_REQ", pContact->GetIPAddress(), pContact->GetUDPPort()); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA_HELLO_REQ, pContact->GetIPAddress(), pContact->GetUDPPort(), 0, 0, NULL, false); if (pContact->CheckIfKad2()) { if (thePrefs.GetDebugClientKadUDPLevel() > 0) DebugSend("KADEMLIA2_HELLO_REQ", pContact->GetIPAddress(), pContact->GetUDPPort()); CKademlia::GetUDPListener()->SendMyDetails(KADEMLIA2_HELLO_REQ, pContact->GetIPAddress(), pContact->GetUDPPort(), 1, 0, NULL, false); } } } }
void CKademlia::Process() { if( m_pInstance == NULL || !m_bRunning) return; bool bUpdateUserFile = false; uint32 uMaxUsers = 0; uint32 uTempUsers = 0; uint32 uLastContact = 0; time_t tNow = time(NULL); ASSERT(m_pInstance->m_pPrefs != NULL); uLastContact = m_pInstance->m_pPrefs->GetLastContact(); CSearchManager::UpdateStats(); if( m_tStatusUpdate <= tNow ) { bUpdateUserFile = true; m_tStatusUpdate = MIN2S(1) + tNow; #ifdef _BOOTSTRAPNODESDAT // do some random lookup to fill out contact list with fresh (but for routing useless) nodes which we can // use for our bootstrap nodes.dat if (GetRoutingZone()->GetNumContacts() < 1500) { CUInt128 uRandom; uRandom.SetValueRandom(); CSearchManager::FindNode(uRandom, false); } #endif } if( m_tNextFirewallCheck <= tNow) RecheckFirewalled(); if (m_tNextUPnPCheck != 0 && m_tNextUPnPCheck <= tNow) { theApp.emuledlg->RefreshUPnP(); m_tNextUPnPCheck = 0; // will be reset on firewallcheck } if (m_tNextSelfLookup <= tNow) { CSearchManager::FindNode(m_pInstance->m_pPrefs->GetKadID(), true); m_tNextSelfLookup = HR2S(4) + tNow; } if (m_tNextFindBuddy <= tNow) { m_pInstance->m_pPrefs->SetFindBuddy(); m_tNextFindBuddy = MIN2S(20) + tNow; } if (m_tExternPortLookup <= tNow && CUDPFirewallTester::IsFWCheckUDPRunning() && GetPrefs()->FindExternKadPort(false)){ // if our UDP firewallcheck is running and we don't know our external port, we send a request every 15 seconds CContact* pContact = GetRoutingZone()->GetRandomContact(3, KADEMLIA_VERSION6_49aBETA); if (pContact != NULL){ DEBUG_ONLY( DebugLog(_T("Requesting our external port from %s"), ipstr(ntohl(pContact->GetIPAddress()))) ); GetUDPListener()->SendNullPacket(KADEMLIA2_PING, pContact->GetIPAddress(), pContact->GetUDPPort(), pContact->GetUDPKey(), &pContact->GetClientID()); } else DEBUG_ONLY( DebugLogWarning(_T("No valid client for requesting external port available")) ); m_tExternPortLookup = 15 + tNow; } for (EventMap::const_iterator itEventMap = m_mapEvents.begin(); itEventMap != m_mapEvents.end(); ++itEventMap) { CRoutingZone* pZone = itEventMap->first; if( bUpdateUserFile ) { // The EstimateCount function is not made for really small networks, if we are in LAN mode, it is actually // better to assume that all users of the network are in our routingtable and use the real count function if (IsRunningInLANMode()) uTempUsers = pZone->GetNumContacts(); else uTempUsers = pZone->EstimateCount(); if( uMaxUsers < uTempUsers ) uMaxUsers = uTempUsers; } if (m_tBigTimer <= tNow) { if( pZone->m_tNextBigTimer <= tNow ) { if(pZone->OnBigTimer()) { pZone->m_tNextBigTimer = HR2S(1) + tNow; m_tBigTimer = SEC(10) + tNow; } } else { if( uLastContact && ( (tNow - uLastContact) > (KADEMLIADISCONNECTDELAY-MIN2S(5)))) { if(pZone->OnBigTimer()) { pZone->m_tNextBigTimer = HR2S(1) + tNow; m_tBigTimer = SEC(10) + tNow; } } } } if (pZone->m_tNextSmallTimer <= tNow) { pZone->OnSmallTimer(); pZone->m_tNextSmallTimer = MIN2S(1) + tNow; } } // This is a convenient place to add this, although not related to routing if (m_tNextSearchJumpStart <= tNow) { CSearchManager::JumpStart(); m_tNextSearchJumpStart = SEARCH_JUMPSTART + tNow; } // Try to consolidate any zones that are close to empty. if (m_tConsolidate <= tNow) { uint32 uMergedCount = m_pInstance->m_pRoutingZone->Consolidate(); if(uMergedCount) AddDebugLogLine(false, _T("Kad merged %u Zones"), uMergedCount); m_tConsolidate = MIN2S(45) + tNow; } //Update user count only if changed. if( bUpdateUserFile ) { if( uMaxUsers != m_pInstance->m_pPrefs->GetKademliaUsers()) { m_pInstance->m_pPrefs->SetKademliaUsers(uMaxUsers); m_pInstance->m_pPrefs->SetKademliaFiles(); theApp.emuledlg->ShowUserCount(); } } if(!IsConnected() && !s_liBootstapList.IsEmpty() && (tNow - m_tBootstrap > 15 || (GetRoutingZone()->GetNumContacts() == 0 && tNow - m_tBootstrap >= 2))) { if (!s_liTriedBootstapList.IsEmpty()) { CContact* pLastTriedContact = s_liTriedBootstapList.GetHead(); pLastTriedContact->SetBootstrapFailed(); theApp.emuledlg->kademliawnd->ContactRef(pLastTriedContact); } CContact* pContact = s_liBootstapList.RemoveHead(); m_tBootstrap = tNow; DebugLog(_T("Trying to Bootstrap Kad from %s, Distance: %s, Version: %u, %u Contacts left"), ipstr(ntohl(pContact->GetIPAddress())), pContact->GetDistance().ToHexString(), pContact->GetVersion(), s_liBootstapList.GetCount()); m_pInstance->m_pUDPListener->Bootstrap(pContact->GetIPAddress(), pContact->GetUDPPort(), pContact->GetVersion(), &pContact->GetClientID()); s_liTriedBootstapList.AddHead(pContact); } else if (!IsConnected() && s_liBootstapList.IsEmpty() && !s_liTriedBootstapList.IsEmpty() && (tNow - m_tBootstrap > 15 || (GetRoutingZone()->GetNumContacts() == 0 && tNow - m_tBootstrap >= 2))) { // failed to bootstrap AddLogLine(true, GetResString(IDS_BOOTSTRAPFAILED)); theApp.emuledlg->kademliawnd->StopUpdateContacts(); while (!s_liTriedBootstapList.IsEmpty()) delete s_liTriedBootstapList.RemoveHead(); theApp.emuledlg->kademliawnd->StartUpdateContacts(); } if (GetUDPListener() != NULL) GetUDPListener()->ExpireClientSearch(); // function does only one compare in most cases, so no real need for a timer }