📄 kademliaudplistener.cpp
字号:
// bool flag3 = (type >> 8); //Reserved
type = type & 0x1F;
if( type == 0 )
{
CString strError;
strError.Format(_T("***NOTE: Received wrong type (0x%02x) in %hs"), type, __FUNCTION__);
throw strError;
}
//This is the target node trying to be found.
CUInt128 target;
bio.ReadUInt128(&target);
CUInt128 distance(prefs->getKadID());
distance.xor(target);
//This makes sure we are not mistaken identify. Some client may have fresh installed and have a new hash.
CUInt128 check;
bio.ReadUInt128(&check);
if( prefs->getKadID().compareTo(check))
return;
// Get required number closest to target
ContactMap results;
routingZone->getClosestTo(0, distance, (int)type, &results);
uint16 count = (uint16)results.size();
// Write response
// Max count is 32. size 817..
// 16 + 1 + 25(32)
CSafeMemFile bio2( 817 );
bio2.WriteUInt128(&target);
bio2.WriteUInt8((byte)count);
CContact *c;
CUInt128 id;
ContactMap::const_iterator it;
for (it = results.begin(); it != results.end(); it++)
{
c = it->second;
c->getClientID(&id);
bio2.WriteUInt128(&id);
bio2.WriteUInt32(c->getIPAddress());
bio2.WriteUInt16(c->getUDPPort());
bio2.WriteUInt16(c->getTCPPort());
bio2.WriteUInt8(c->getType());
}
if (thePrefs.GetDebugClientKadUDPLevel() > 0)
DebugSendF("KadRes", ip, port, _T("Count=%u"), count);
sendPacket(&bio2, KADEMLIA_RES, ip, port);
}
//KADEMLIA_RES
void CKademliaUDPListener::processKademliaResponse (const byte *packetData, uint32 lenPacket, uint32 ip, uint16 port)
{
// Verify packet is expected size
if (lenPacket < 17){
CString strError;
strError.Format(_T("***NOTE: Received wrong size (%u) packet in %hs"), lenPacket, __FUNCTION__);
throw strError;
}
//Used Pointers
CPrefs *prefs = CKademlia::getPrefs();
ASSERT(prefs != NULL);
CRoutingZone *routingZone = CKademlia::getRoutingZone();
ASSERT(routingZone != NULL);
if(prefs->getRecheckIP())
{
firewalledCheck(ip, port);
if (thePrefs.GetDebugClientKadUDPLevel() > 0)
DebugSend("KadHelloReq", ip, port);
sendMyDetails(KADEMLIA_HELLO_REQ, ip, port);
}
// What search does this relate to
CSafeMemFile bio( packetData, lenPacket);
CUInt128 target;
bio.ReadUInt128(&target);
uint16 numContacts = bio.ReadUInt8();
// Verify packet is expected size
if (lenPacket != 16+1 + (16+4+2+2+1)*numContacts){
CString strError;
strError.Format(_T("***NOTE: Received wrong size (%u) packet in %hs"), lenPacket, __FUNCTION__);
throw strError;
}
// Set contact to alive.
routingZone->setAlive(ip, port);
CUInt128 id;
ContactList *results = new ContactList;
try
{
for (uint16 i=0; i<numContacts; i++)
{
bio.ReadUInt128(&id);
uint32 ip = bio.ReadUInt32();
uint16 port = bio.ReadUInt16();
uint16 tport = bio.ReadUInt16();
byte type = bio.ReadUInt8();
if(::IsGoodIPPort(ntohl(ip),port))
{
routingZone->add(id, ip, port, tport, type);
results->push_back(new CContact(id, ip, port, tport, type, target));
}
}
}
catch(...)
{
delete results;
throw;
}
CSearchManager::processResponse(target, ip, port, results);
}
void CKademliaUDPListener::Free(SSearchTerm* pSearchTerms)
{
if (pSearchTerms->left)
Free(pSearchTerms->left);
if (pSearchTerms->right)
Free(pSearchTerms->right);
delete pSearchTerms;
}
SSearchTerm* CKademliaUDPListener::CreateSearchExpressionTree(CSafeMemFile& bio, int iLevel)
{
// the max. depth has to match our own limit for creating the search expression
// (see also 'ParsedSearchExpression' and 'GetSearchPacket')
if (iLevel >= 24){
AddDebugLogLine(false, _T("***NOTE: Search expression tree exceeds depth limit!"));
return NULL;
}
iLevel++;
uint8 op = bio.ReadUInt8();
if (op == 0x00)
{
uint8 boolop = bio.ReadUInt8();
if (boolop == 0x00) // AND
{
SSearchTerm* pSearchTerm = new SSearchTerm;
pSearchTerm->type = SSearchTerm::AND;
TRACE(" AND");
if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
ASSERT(0);
delete pSearchTerm;
return NULL;
}
if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
ASSERT(0);
Free(pSearchTerm->left);
delete pSearchTerm;
return NULL;
}
return pSearchTerm;
}
else if (boolop == 0x01) // OR
{
SSearchTerm* pSearchTerm = new SSearchTerm;
pSearchTerm->type = SSearchTerm::OR;
TRACE(" OR");
if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
ASSERT(0);
delete pSearchTerm;
return NULL;
}
if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
ASSERT(0);
Free(pSearchTerm->left);
delete pSearchTerm;
return NULL;
}
return pSearchTerm;
}
else if (boolop == 0x02) // NAND
{
SSearchTerm* pSearchTerm = new SSearchTerm;
pSearchTerm->type = SSearchTerm::NAND;
TRACE(" NAND");
if ((pSearchTerm->left = CreateSearchExpressionTree(bio, iLevel)) == NULL){
ASSERT(0);
delete pSearchTerm;
return NULL;
}
if ((pSearchTerm->right = CreateSearchExpressionTree(bio, iLevel)) == NULL){
ASSERT(0);
Free(pSearchTerm->left);
delete pSearchTerm;
return NULL;
}
return pSearchTerm;
}
else{
AddDebugLogLine(false, _T("*** Unknown boolean search operator 0x%02x (CreateSearchExpressionTree)"), boolop);
return NULL;
}
}
else if (op == 0x01) // String
{
CTagValueString str(bio.ReadStringUTF8());
KadTagStrMakeLower(str); // make lowercase, the search code expects lower case strings!
TRACE(" \"%ls\"", str);
SSearchTerm* pSearchTerm = new SSearchTerm;
pSearchTerm->type = SSearchTerm::String;
pSearchTerm->astr = new CStringWArray;
// pre-tokenize the string term
int iPosTok = 0;
CTagValueString strTok(str.Tokenize(_awszInvKadKeywordChars, iPosTok));
while (!strTok.IsEmpty())
{
pSearchTerm->astr->Add(strTok);
strTok = str.Tokenize(_awszInvKadKeywordChars, iPosTok);
}
return pSearchTerm;
}
else if (op == 0x02) // Meta tag
{
// read tag value
CTagValueString strValue(bio.ReadStringUTF8());
KadTagStrMakeLower(strValue); // make lowercase, the search code expects lower case strings!
// read tag name
CStringA strTagName;
uint16 lenTagName = bio.ReadUInt16();
bio.Read(strTagName.GetBuffer(lenTagName), lenTagName);
strTagName.ReleaseBuffer(lenTagName);
SSearchTerm* pSearchTerm = new SSearchTerm;
pSearchTerm->type = SSearchTerm::MetaTag;
pSearchTerm->tag = new Kademlia::CTagStr(strTagName, strValue);
if (lenTagName == 1)
TRACE(" Tag%02x=\"%ls\"", strTagName[0], strValue);
else
TRACE(" \"%s\"=\"%ls\"", strTagName, strValue);
return pSearchTerm;
}
else if (op == 0x03) // Min/Max
{
static const struct {
SSearchTerm::ESearchTermType eSearchTermOp;
LPCSTR pszOp;
} _aOps[] =
{
{ SSearchTerm::OpEqual, "=" }, // mmop=0x00
{ SSearchTerm::OpGreaterEqual, ">=" }, // mmop=0x01
{ SSearchTerm::OpLessEqual, "<=" }, // mmop=0x02
{ SSearchTerm::OpGreater, ">" }, // mmop=0x03
{ SSearchTerm::OpLess, "<" }, // mmop=0x04
{ SSearchTerm::OpNotEqual, "!=" } // mmop=0x05
};
// read tag value
uint32 uValue = bio.ReadUInt32();
// read integer operator
uint8 mmop = bio.ReadUInt8();
if (mmop >= ARRSIZE(_aOps)){
AddDebugLogLine(false, _T("*** Unknown integer search op=0x%02x (CreateSearchExpressionTree)"), mmop);
return NULL;
}
// read tag name
CStringA strTagName;
uint16 lenTagName = bio.ReadUInt16();
bio.Read(strTagName.GetBuffer(lenTagName), lenTagName);
strTagName.ReleaseBuffer(lenTagName);
SSearchTerm* pSearchTerm = new SSearchTerm;
pSearchTerm->type = _aOps[mmop].eSearchTermOp;
pSearchTerm->tag = new Kademlia::CTagUInt32(strTagName, uValue);
if (lenTagName == 1)
TRACE(" Tag%02x%s%u", (BYTE)strTagName[0], _aOps[mmop].pszOp, uValue);
else
TRACE(" \"%s\"%s%u", strTagName, _aOps[mmop].pszOp, uValue);
return pSearchTerm;
}
else{
AddDebugLogLine(false, _T("*** Unknown search op=0x%02x (CreateSearchExpressionTree)"), op);
return NULL;
}
}
//KADEMLIA_SEARCH_REQ
void CKademliaUDPListener::processSearchRequest (const byte *packetData, uint32 lenPacket, uint32 ip, uint16 port)
{
// Verify packet is expected size
if (lenPacket < 17){
CString strError;
strError.Format(_T("***NOTE: Received wrong size (%u) packet in %hs"), lenPacket, __FUNCTION__);
throw strError;
}
//Used Pointers
CIndexed *indexed = CKademlia::getIndexed();
ASSERT(indexed != NULL);
CSafeMemFile bio( packetData, lenPacket);
CUInt128 target;
bio.ReadUInt128(&target);
uint8 restrictive = bio.ReadUInt8();
#ifdef _DEBUG
DWORD dwNow = GetTickCount();
#endif
if(lenPacket == 17 )
{
if(restrictive)
{
//Source request
indexed->SendValidSourceResult(target, ip, port);
//DEBUG_ONLY( Debug("SendValidSourceResult: Time=%.2f sec\n", (GetTickCount() - dwNow) / 1000.0) );
}
else
{
//Single keyword request
indexed->SendValidKeywordResult(target, NULL, ip, port );
//DEBUG_ONLY( Debug("SendValidKeywordResult (Single): Time=%.2f sec\n", (GetTickCount() - dwNow) / 1000.0) );
}
}
else if(lenPacket > 17)
{
SSearchTerm* pSearchTerms = NULL;
if (restrictive)
{
try
{
pSearchTerms = CreateSearchExpressionTree(bio, 0);
TRACE("\n");
}
catch(...)
{
Free(pSearchTerms);
throw;
}
}
//Keyword request with added options.
indexed->SendValidKeywordResult(target, pSearchTerms, ip, port);
Free(pSearchTerms);
//DEBUG_ONLY( Debug("SendValidKeywordResult: Time=%.2f sec\n", (GetTickCount() - dwNow) / 1000.0) );
}
}
//KADEMLIA_SEARCH_RES
void CKademliaUDPListener::processSearchResponse (const byte *packetData, uint32 lenPacket, uint32 ip, uint16 port)
{
// Verify packet is expected size
if (lenPacket < 37){
CString strError;
strError.Format(_T("***NOTE: Received wrong size (%u) packet in %hs"), lenPacket, __FUNCTION__);
throw strError;
}
//Used Pointers
CRoutingZone *routingZone = CKademlia::getRoutingZone();
ASSERT(routingZone != NULL);
// Set contact to alive.
routingZone->setAlive(ip, port);
// What search does this relate to
CByteIO bio(packetData, lenPacket);
CUInt128 target;
bio.readUInt128(&target);
// How many results.. Not supported yet..
uint16 count = bio.readUInt16();
while( count > 0 )
{
// What is the answer
CUInt128 answer;
bio.readUInt128(&answer);
// Get info about answer
// NOTE: this is the one and only place in Kad where we allow string conversion to local code page in
// case we did not receive an UTF8 string. this is for backward compatibility for search results which are
// supposed to be 'viewed' by user only and not feed into the Kad engine again!
// If that tag list is once used for something else than for viewing, special care has to be taken for any
// string conversion!
TagList *tags = bio.readTagList(true/*bOptACP*/);
CSearchManager::processResult(target, ip, port, answer,tags);
count--;
}
}
//KADEMLIA_PUBLISH_REQ
void CKademliaUDPListener::processPublishRequest (const byte *packetData, uint32 lenPacket, uint32 ip, uint16 port)
{
//There are different types of publishing..
//Keyword and File are Stored..
// Verify packet is expected size
if (lenPacket < 37){
CString strError;
strError.Format(_T("***NOTE: Received wrong size (%u) packet in %hs"), lenPacket, __FUNCTION__);
throw strError;
}
//Used Pointers
CIndexed *indexed = CKademlia::getIndexed();
ASSERT(indexed != NULL);
CPrefs *prefs = CKademlia::getPrefs();
ASSERT(prefs != NULL);
if( prefs->getFirewalled() )
//We are firewalled. We should not index this entry and give publisher a false report.
return;
CByteIO bio(packetData, lenPacket);
CUInt128 file;
bio.readUInt128(&file);
CUInt128 distance;
prefs->getKadID(&distance);
distance.xor(file);
if( thePrefs.FilterLANIPs() && distance.get32BitChunk(0) > SEARCHTOLERANCE)
return;
bool bDbgInfo = thePrefs.GetDebugClientKadUDPLevel() > 0;
CString strInfo;
uint16 count = bio.readUInt16();
bool flag = false;
uint8 load = 0;
while( count > 0 )
{
strInfo.Empty();
CUInt128 target;
bio.readUInt128(&target);
Kademlia::CEntry* entry = new Kademlia::CEntry();
try
{
entry->ip = ip;
entry->udpport = port;
entry->keyID.setValue(file);
entry->sourceID.setValue(target);
uint32 tags = bio.readByte();
while(tags > 0)
{
CTag* tag = bio.readTag();
if(tag)
{
if (!tag->m_name.Compare(TAG_SOURCETYPE) && tag->m_type == 9)
{
if( entry->source == false )
{
entry->taglist.push_back(new CTagUInt32(TAG_SOURCEIP, entry->ip));
entry->taglist.push_back(new CTagUInt16(TAG_SOURCEUPORT, entry->udpport));
}
else
{
//More then one sourcetype tag found.
delete tag;
}
entry->source = true;
}
if (!tag->m_name.Compare(TAG_NAME))
{
if ( entry->fileName.IsEmpty() )
{
entry->fileName = tag->GetStr();
KadTagStrMakeLower(entry->fileName); // make lowercase, the search code expects lower case strings!
if (bDbgInfo)
strInfo.AppendFormat(_T(" Name=\"%ls\""), entry->fileName);
// NOTE: always add the 'name' tag, even if it's stored separately in 'fileName'. the tag is still needed for answering search request
entry->taglist.push_back(tag);
}
else
{
//More then one Name tag found.
delete tag;
}
}
else if (!tag->m_name.Compare(TAG_SIZE))
{
if( entry->size == 0 )
{
entry->size = tag->GetInt();
if (bDbgInfo)
strInfo.AppendFormat(_T(" Size=%u"), entry->size);
// NOTE: always add the 'size' tag, even if it's stored separately in 'size'. the tag is still needed for answering search request
entry->taglist.push_back(tag);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -