📄 search.cpp
字号:
//// This file is part of the aMule Project.//// Copyright (c) 2004-2006 Angel Vidal (Kry) ( kry@amule.org )// Copyright (c) 2004-2006 aMule Team ( admin@amule.org / http://www.amule.org )// Copyright (c) 2003 Barry Dunne (http://www.emule-project.net)//// Any parts of this program derived from the xMule, lMule or eMule project,// or contributed by third-party developers are copyrighted by their// respective authors.//// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// // You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA//// Note To Mods ///*Please do not change anything here and release it..There is going to be a new forum created just for the Kademlia side of the client..If you feel there is an error or a way to improve something, pleasepost it in the forum first and let us look at it.. If it is a real improvement,it will be added to the offical client.. Changing something without knowingwhat all it does can cause great harm to the network if released in mass form..Any mod that changes anything within the Kademlia side will not be allowed to advertisethere client on the eMule forum..*/#include "../../Tag.h"typedef CTag ed2kCTag;#include "Search.h"#include "Kademlia.h"#include "../../OPCodes.h"#include "Defines.h"#include "Prefs.h"#include "Indexed.h"#include "../io/IOException.h"#include "../routing/RoutingZone.h"#include "../routing/Contact.h"#include "../net/KademliaUDPListener.h"#include "../kademlia/Tag.h"#include "../../amule.h"#include "../../SharedFileList.h"#include "../../OtherFunctions.h"#include "../../KnownFile.h"#include "DownloadQueue.h"#include "PartFile.h"#include "SearchList.h"#include "MemFile.h"#include "ServerConnect.h"#include "Server.h"#include "ClientList.h"#include "updownclient.h"#include "Logger.h"#include "../../Preferences.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif////////////////////////////////////////using namespace Kademlia;////////////////////////////////////////CSearch::CSearch(){ m_created = time(NULL); m_searchTerms = NULL; m_type = (uint32)-1; m_answers = 0; m_totalRequestAnswers = 0; m_kadPacketSent = 0; m_searchID = (uint32)-1; m_keywordPublish = 0; (void)m_fileName; m_stoping = false; m_totalLoad = 0; m_totalLoadResponses = 0; bio1 = NULL; bio2 = NULL; bio3 = NULL; m_lastResponse = time(NULL);}CSearch::~CSearch(){ CPartFile* temp = theApp.downloadqueue->GetFileByKadFileSearchID(getSearchID()); if(temp) { temp->SetKadFileSearchID(0); } delete m_searchTerms; ContactMap::iterator it; for (it = m_inUse.begin(); it != m_inUse.end(); it++) { ((CContact*)it->second)->decUse(); } ContactList::const_iterator it2; for (it2 = m_delete.begin(); it2 != m_delete.end(); it2++) { delete *it2; } delete bio1; delete bio2; delete bio3; if(CKademlia::isRunning() && getNodeLoad() > 20) { switch(getSearchTypes()) { case CSearch::STOREKEYWORD: Kademlia::CKademlia::getIndexed()->AddLoad(getTarget(), ((uint32)(DAY2S(7)*((double)getNodeLoad()/100.0))+(uint32)time(NULL))); break; default: ; // WTF? } }}void CSearch::go(void){ // Start with a lot of possible contacts, this is a fallback in case search stalls due to dead contacts if (m_possible.empty()) { CUInt128 distance(CKademlia::getPrefs()->getKadID()); distance.XOR(m_target); CKademlia::getRoutingZone()->getClosestTo(3, m_target, distance, 50, &m_possible, true, true); } if (m_possible.empty()) { return; } ContactMap::iterator it; //Lets keep our contact list entries in mind to dec the inUse flag. for (it = m_possible.begin(); it != m_possible.end(); ++it) { m_inUse[it->first] = it->second; } wxASSERT(m_possible.size() == m_inUse.size()); // Take top 3 possible int count = min(ALPHA_QUERY, (int)m_possible.size()); CContact *c; for (int i=0; i<count; i++) { it = m_possible.begin(); c = it->second; // Move to tried m_tried[it->first] = c; m_possible.erase(it); // Send request c->checkingType(); sendFindValue(c->getClientID(), c->getIPAddress(), c->getUDPPort()); if(m_type == NODE) { break; } }}//If we allow about a 15 sec delay before deleting, we won't miss a lot of delayed returning packets.void CSearch::prepareToStop(){ if( m_stoping ) { return; } uint32 baseTime = 0; switch(m_type) { case NODE: case NODECOMPLETE: baseTime = SEARCHNODE_LIFETIME; break; case FILE: baseTime = SEARCHFILE_LIFETIME; break; case KEYWORD: baseTime = SEARCHKEYWORD_LIFETIME; break; case NOTES: baseTime = SEARCHNOTES_LIFETIME; break; case STOREFILE: baseTime = SEARCHSTOREFILE_LIFETIME; break; case STOREKEYWORD: baseTime = SEARCHSTOREKEYWORD_LIFETIME; break; case STORENOTES: baseTime = SEARCHSTORENOTES_LIFETIME; break; case FINDBUDDY: baseTime = SEARCHFINDBUDDY_LIFETIME; break; case FINDSOURCE: baseTime = SEARCHFINDSOURCE_LIFETIME; break; default: baseTime = SEARCH_LIFETIME; } m_created = time(NULL) - baseTime + SEC(15); m_stoping = true; }void CSearch::jumpStart(void){ if (m_possible.empty()) { prepareToStop(); return; } if ((time_t)(m_lastResponse + SEC(3)) > time(NULL)) { return; } while (!m_possible.empty()) { CContact *c = m_possible.begin()->second; //Have we already tried to contact this node. if (m_tried.count(m_possible.begin()->first) > 0) { //Did we get a response from this node, if so, try to store or get info. if(m_responded.count(m_possible.begin()->first) > 0) { StorePacket(); } m_possible.erase(m_possible.begin()); } else { // Move to tried m_tried[m_possible.begin()->first] = c; // Send request c->checkingType(); sendFindValue(c->getClientID(), c->getIPAddress(), c->getUDPPort()); break; } } }void CSearch::processResponse(uint32 fromIP, uint16 fromPort, ContactList *results){ AddDebugLogLineM(false, logKadSearch, wxT("Process search response from ") + Uint32_16toStringIP_Port(wxUINT32_SWAP_ALWAYS(fromIP), fromPort)); if (results) { m_lastResponse = time(NULL); } // Remember the contacts to be deleted when finished ContactList::iterator response; for (response = results->begin(); response != results->end(); ++response) { m_delete.push_back(*response); } // Not interested in responses for FIND_NODE, will be added to contacts by udp listener if (m_type == NODE) { AddDebugLogLineM(false, logKadSearch, wxT("Node type search result, discarding.")); m_answers++; m_possible.clear(); delete results; return; } ContactMap::const_iterator tried; CContact *c; CContact *from; CUInt128 distance; CUInt128 fromDistance; //Find contact that is responding. for (tried = m_tried.begin(); tried != m_tried.end(); ++tried) { fromDistance = tried->first; from = tried->second; if ((from->getIPAddress() == fromIP) && (from->getUDPPort() == fromPort)) { // Add to list of people who responded m_responded[fromDistance] = from; // Loop through their responses for (response = results->begin(); response != results->end(); ++response) { c = *response; distance = c->getClientID(); distance.XOR(m_target); // Ignore this contact if already know him if (m_possible.count(distance) > 0) { // AddDebugLogLineM(false, logKadSearch, wxT("Search result from already known client: ignore")); continue; } if (m_tried.count(distance) > 0) { // AddDebugLogLineM(false, logKadSearch, wxT("Search result from already tried client: ignore")); continue; } // Add to possible m_possible[distance] = c; if (distance < fromDistance) { bool top = false; if (m_best.size() < ALPHA_QUERY) { top = true; m_best[distance] = c; } else { ContactMap::iterator it = m_best.end(); --it; if (distance < it->first) { // Rotate best list m_best.erase(it); m_best[distance] = c; top = true; } } if (top) { // Add to tried m_tried[distance] = c; // Send request c->checkingType(); sendFindValue(c->getClientID(), c->getIPAddress(), c->getUDPPort()); } } } // We don't want anything from these people, so just increment the counter. if( m_type == NODECOMPLETE ) { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: Node complete")); m_answers++; } break; } } delete results;}void CSearch::StorePacket(){ wxASSERT(!m_possible.empty()); CContact *from; CUInt128 fromDistance; ContactMap::const_iterator possible; possible = m_possible.begin(); fromDistance = possible->first; from = possible->second; if(thePrefs::FilterLanIPs() && fromDistance.get32BitChunk(0) > SEARCHTOLERANCE) { AddDebugLogLineM(false, logKadSearch, wxT("Not stored: filtered lan ip")); return; } switch(m_type) { case FILE: case KEYWORD: { if (m_type == FILE) { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: File")); AddDebugLogLineM(false, logClientKadUDP, wxT("KadSearchReq (File) ") + Uint32_16toStringIP_Port(wxUINT32_SWAP_ALWAYS(from->getIPAddress()), from->getUDPPort())); } else { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: Keyword")); AddDebugLogLineM(false, logClientKadUDP, wxT("KadSearchReq (Keyword) ") + Uint32_16toStringIP_Port(wxUINT32_SWAP_ALWAYS(from->getIPAddress()), from->getUDPPort())); } wxASSERT( m_searchTerms->GetLength() > 0 ); // The data in 'm_searchTerms' is to be sent several times, so use the don't detach flag. CKademlia::getUDPListener()->sendPacket(m_searchTerms, KADEMLIA_SEARCH_REQ, from->getIPAddress(), from->getUDPPort()); m_totalRequestAnswers++; break; } case NOTES: { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: Notes")); CMemFile bio(34); bio.WriteUInt128(m_target); bio.WriteUInt128(CKademlia::getPrefs()->getKadID()); CKademlia::getUDPListener()->sendPacket( &bio, KADEMLIA_SRC_NOTES_REQ, from->getIPAddress(), from->getUDPPort()); m_totalRequestAnswers++; break; } case STOREFILE: { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: StoreFile")); if( m_answers > SEARCHSTOREFILE_TOTAL ) { prepareToStop(); break; } byte fileid[16]; m_target.toByteArray(fileid); CKnownFile* file = theApp.sharedfiles->GetFileByID(CMD4Hash(fileid)); if (file) { m_fileName = file->GetFileName(); CUInt128 id(CKademlia::getPrefs()->getClientHash()); TagList taglist; //We can use type for different types of sources. //1 is reserved for highID sources.. //2 cannot be used as older clients will not work. //3 Firewalled Kad Source. if( theApp.IsFirewalled() ) { if( theApp.clientlist->GetBuddy() ) { CUInt128 buddyID(true); buddyID.XOR(CKademlia::getPrefs()->getKadID()); taglist.push_back(new CTagUInt8(TAG_SOURCETYPE, 3)); taglist.push_back(new CTagUInt32(TAG_SERVERIP, theApp.clientlist->GetBuddy()->GetIP())); taglist.push_back(new CTagUInt16(TAG_SERVERPORT, theApp.clientlist->GetBuddy()->GetUDPPort())); byte hashBytes[16]; buddyID.toByteArray(hashBytes); taglist.push_back(new CTagStr(TAG_BUDDYHASH, CMD4Hash(hashBytes).Encode())); taglist.push_back(new CTagUInt16(TAG_SOURCEPORT, thePrefs::GetPort())); } else { prepareToStop(); break; } } else { taglist.push_back(new CTagUInt8(TAG_SOURCETYPE, 1)); taglist.push_back(new CTagUInt16(TAG_SOURCEPORT, thePrefs::GetPort())); } CKademlia::getUDPListener()->publishPacket(from->getIPAddress(), from->getUDPPort(),m_target,id, taglist); m_totalRequestAnswers++; TagList::const_iterator it; for (it = taglist.begin(); it != taglist.end(); ++it) { delete *it; } } break; } case STOREKEYWORD: { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: StoreKeyword")); if( m_answers > SEARCHSTOREKEYWORD_TOTAL ) { prepareToStop(); break; } if( bio1 ) { AddDebugLogLineM(false, logClientKadUDP, wxT("KadStoreKeywReq ") + Uint32_16toStringIP_Port(wxUINT32_SWAP_ALWAYS(from->getIPAddress()), from->getUDPPort())); CKademlia::getUDPListener()->sendPacket( packet1, ((1024*50)-bio1->getAvailable()), from->getIPAddress(), from->getUDPPort() ); } if( bio2 ) { AddDebugLogLineM(false, logClientKadUDP, wxT("KadStoreKeywReq ") + Uint32_16toStringIP_Port(wxUINT32_SWAP_ALWAYS(from->getIPAddress()), from->getUDPPort())); CKademlia::getUDPListener()->sendPacket( packet2, ((1024*50)-bio2->getAvailable()), from->getIPAddress(), from->getUDPPort() ); } if( bio3 ) { AddDebugLogLineM(false, logClientKadUDP, wxT("KadStoreKeywReq ") + Uint32_16toStringIP_Port(wxUINT32_SWAP_ALWAYS(from->getIPAddress()), from->getUDPPort())); CKademlia::getUDPListener()->sendPacket( packet3, ((1024*50)-bio3->getAvailable()), from->getIPAddress(), from->getUDPPort() ); } m_totalRequestAnswers++; break; } case STORENOTES: { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: StoreNotes")); byte fileid[16]; m_target.toByteArray(fileid); CKnownFile* file = theApp.sharedfiles->GetFileByID(CMD4Hash(fileid)); if (file) { byte packet[1024*2]; CByteIO bio(packet,sizeof(packet)); bio.writeUInt128(m_target); bio.writeUInt128(CKademlia::getPrefs()->getKadID()); uint8 tagcount = 1; if(file->GetFileRating() != 0) { ++tagcount; } if(!file->GetFileComment().IsEmpty()) { ++tagcount; } //Number of tags. bio.writeUInt8(tagcount); CTagStr fileName(TAG_FILENAME, file->GetFileName()); bio.writeTag(&fileName); if(file->GetFileRating() != 0) { CTagUInt16 rating(TAG_FILERATING, file->GetFileRating()); bio.writeTag(&rating); } if(!file->GetFileComment().IsEmpty()) { CTagStr description(TAG_DESCRIPTION, file->GetFileComment()); bio.writeTag(&description); } CKademlia::getUDPListener()->sendPacket( packet, sizeof(packet)-bio.getAvailable(), KADEMLIA_PUB_NOTES_REQ, from->getIPAddress(), from->getUDPPort()); m_totalRequestAnswers++; } break; } case FINDBUDDY: { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: FindBuddy")); if( m_answers > SEARCHFINDBUDDY_TOTAL ) { prepareToStop(); break; } CMemFile bio(34); bio.WriteUInt128(m_target); bio.WriteUInt128(CKademlia::getPrefs()->getClientHash()); bio.WriteUInt16(thePrefs::GetPort()); CKademlia::getUDPListener()->sendPacket( &bio, KADEMLIA_FINDBUDDY_REQ, from->getIPAddress(), from->getUDPPort()); m_answers++; break; } case FINDSOURCE: { AddDebugLogLineM(false, logKadSearch, wxT("Search result type: FindSource")); if( m_answers > SEARCHFINDSOURCE_TOTAL ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -