⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 querysearch.cpp

📁 p2p软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// QuerySearch.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza 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.
//
// Shareaza 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 Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//

#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "QuerySearch.h"
#include "Network.h"
#include "Datagrams.h"
#include "G1Packet.h"
#include "G2Packet.h"
#include "EDPacket.h"

#include "Schema.h"
#include "SchemaCache.h"
#include "QueryHashTable.h"
#include "GGEP.h"
#include "XML.h"
#include "SHA.h"
#include "MD5.h"
#include "ED2K.h"
#include "TigerTree.h"

#include "WndSearch.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//////////////////////////////////////////////////////////////////////
// CQuerySearch construction

CQuerySearch::CQuerySearch(BOOL bGUID)
{
	if ( bGUID ) Network.CreateID( &m_pGUID );
	
	m_pSchema	= NULL;
	m_pXML		= NULL;
	m_nMinSize	= 0x0000000000000000;
	m_nMaxSize	= 0xFFFFFFFFFFFFFFFF;
	
	m_bSHA1		= FALSE;
	m_bTiger	= FALSE;
	m_bED2K		= FALSE;
	m_bBTH		= FALSE;
	
	m_bWantURL	= TRUE;
	m_bWantDN	= TRUE;
	m_bWantXML	= TRUE;
	m_bWantCOM	= TRUE;
	m_bWantPFS	= TRUE;
	m_bAndG1	= Settings.Gnutella1.EnableToday;
	
	m_bUDP		= FALSE;
	m_nKey		= 0;
	m_bFirewall	= FALSE;
	
	m_nWords	= 0;
	m_pWordPtr	= NULL;
	m_pWordLen	= NULL;
}

CQuerySearch::CQuerySearch(CQuerySearch* pCopy)
{
	m_pGUID		= pCopy->m_pGUID;
	
	m_sSearch	= pCopy->m_sSearch;
	m_pSchema	= pCopy->m_pSchema;
	m_pXML		= pCopy->m_pXML ? pCopy->m_pXML->Clone() : NULL;
	m_nMinSize	= pCopy->m_nMinSize;
	m_nMaxSize	= pCopy->m_nMaxSize;
	
	m_bSHA1 = pCopy->m_bSHA1;
	if ( m_bSHA1 ) m_pSHA1 = pCopy->m_pSHA1;
	m_bTiger = pCopy->m_bTiger;
	if ( m_bTiger ) m_pTiger = pCopy->m_pTiger;
	m_bED2K = pCopy->m_bED2K;
	if ( m_bED2K ) m_pED2K = pCopy->m_pED2K;
	m_bBTH = pCopy->m_bBTH;
	if ( m_bBTH ) m_pBTH = pCopy->m_pBTH;
	
	m_bWantURL	= pCopy->m_bWantURL;
	m_bWantDN	= pCopy->m_bWantDN;
	m_bWantXML	= pCopy->m_bWantXML;
	m_bWantCOM	= pCopy->m_bWantCOM;
	m_bWantPFS	= pCopy->m_bWantPFS;
	m_bAndG1	= pCopy->m_bAndG1;
	
	m_bUDP		= pCopy->m_bUDP;
	m_nKey		= pCopy->m_nKey;
	if ( m_bUDP ) m_pEndpoint = pCopy->m_pEndpoint;
	
	m_nWords	= 0;
	m_pWordPtr	= NULL;
	m_pWordLen	= NULL;
}

CQuerySearch::~CQuerySearch()
{
	if ( m_pXML ) delete m_pXML;
	
	if ( m_pWordPtr ) delete [] m_pWordPtr;
	if ( m_pWordLen ) delete [] m_pWordLen;
}

//////////////////////////////////////////////////////////////////////
// CQuerySearch to G1 packet

CG1Packet* CQuerySearch::ToG1Packet()
{
	CG1Packet* pPacket = CG1Packet::New( G1_PACKET_QUERY,
		min( Settings.Gnutella1.SearchTTL, 4 ), &m_pGUID );
	
	WORD nFlags = G1_QF_TAG | G1_QF_BIN_HASH | G1_QF_DYNAMIC;
	if ( ! Network.IsListening() ) nFlags |= G1_QF_FIREWALLED;
	if ( m_bWantXML ) nFlags |= G1_QF_XML;
	pPacket->WriteShortLE( nFlags );
	
	CString strExtra;
	
	if ( m_sSearch.GetLength() )
	{
		pPacket->WriteString( m_sSearch );
	}
	else if ( m_pSchema != NULL && m_pXML != NULL )
	{
		strExtra = m_pSchema->GetIndexedWords( m_pXML->GetFirstElement() );
		pPacket->WriteString( strExtra );
		strExtra.Empty();
	}
	else
	{
		pPacket->WriteByte( 0 );
	}
	
	if ( m_bSHA1 )
	{
		strExtra = CSHA::HashToString( &m_pSHA1, TRUE );
	}
	else if ( m_bTiger )
	{
		strExtra = CTigerNode::HashToString( &m_pTiger, TRUE );
	}
	else if ( m_bED2K )
	{
		strExtra = CED2K::HashToString( &m_pED2K, TRUE );
	}
	else
	{
		strExtra = _T("urn:");
	}
	
	if ( m_pXML )
	{
		if ( strExtra.GetLength() ) strExtra += '\x1C';
		strExtra += m_pXML->ToString( TRUE );
	}
	
	pPacket->WriteString( strExtra );
	
	return pPacket;
}

//////////////////////////////////////////////////////////////////////
// CQuerySearch to G2 packet

CG2Packet* CQuerySearch::ToG2Packet(SOCKADDR_IN* pUDP, DWORD nKey)
{
	CG2Packet* pPacket = CG2Packet::New( G2_PACKET_QUERY, TRUE );
	
	if ( pUDP )
	{
		pPacket->WritePacket( "UDP", nKey ? 10 : 6 );
		pPacket->WriteLongLE( pUDP->sin_addr.S_un.S_addr );
		pPacket->WriteShortBE( htons( pUDP->sin_port ) );
		if ( nKey ) pPacket->WriteLongBE( nKey );
	}
	
	if ( m_bTiger && m_bSHA1 )
	{
		pPacket->WritePacket( "URN", sizeof(SHA1) + sizeof(TIGEROOT) + 3 );
		pPacket->WriteString( "bp" );
		pPacket->Write( &m_pSHA1, sizeof(SHA1) );
		pPacket->Write( &m_pTiger, sizeof(TIGEROOT) );
	}
	else if ( m_bSHA1 )
	{
		pPacket->WritePacket( "URN", sizeof(SHA1) + 5 );
		pPacket->WriteString( "sha1" );
		pPacket->Write( &m_pSHA1, sizeof(SHA1) );
	}
	else if ( m_bTiger )
	{
		pPacket->WritePacket( "URN", sizeof(TIGEROOT) + 4 );
		pPacket->WriteString( "ttr" );
		pPacket->Write( &m_pTiger, sizeof(TIGEROOT) );
	}
	else if ( m_bED2K )
	{
		pPacket->WritePacket( "URN", sizeof(MD4) + 5 );
		pPacket->WriteString( "ed2k" );
		pPacket->Write( &m_pED2K, sizeof(MD4) );
	}
	
	if ( m_bBTH )
	{
		pPacket->WritePacket( "URN", sizeof(SHA1) + 5 );
		pPacket->WriteString( "btih" );
		pPacket->Write( &m_pBTH, sizeof(SHA1) );
	}
	
	if ( m_sSearch.GetLength() )
	{
		pPacket->WritePacket( "DN", pPacket->GetStringLen( m_sSearch ) );
		pPacket->WriteString( m_sSearch, FALSE );
	}
	
	if ( m_pXML != NULL )
	{
		CString strXML;
		
		if ( true )
		{
			if ( CXMLElement* pBody = m_pXML->GetFirstElement() )
				strXML = pBody->ToString();
		}
		else
		{
			strXML = m_pXML->ToString( TRUE );
		}
		
		pPacket->WritePacket( "MD", pPacket->GetStringLen( strXML ) );
		pPacket->WriteString( strXML, FALSE );
	}
	
	if ( m_nMinSize != 0 || m_nMaxSize != SIZE_UNKNOWN )
	{
		if ( m_nMinSize < 0xFFFFFFFF && ( m_nMaxSize < 0xFFFFFFFF || m_nMaxSize == SIZE_UNKNOWN ) )
		{
			pPacket->WritePacket( "SZR", 8 );
			pPacket->WriteLongBE( (DWORD)m_nMinSize );
			pPacket->WriteLongBE( m_nMaxSize == SIZE_UNKNOWN ? 0xFFFFFFFF : (DWORD)m_nMaxSize );
		}
		else
		{
			pPacket->WritePacket( "SZR", 16 );
			pPacket->WriteInt64( m_nMinSize );
			pPacket->WriteInt64( m_nMaxSize );
		}
	}
	
	if ( ! m_bWantURL || ! m_bWantDN || ! m_bWantXML || ! m_bWantCOM || ! m_bWantPFS )
	{
		pPacket->WritePacket( "I",
			( m_bWantURL ? 4 : 0 ) + ( m_bWantDN ? 3 : 0 ) + ( m_bWantXML ? 3 : 0 ) +
			( m_bWantCOM ? 4 : 0 ) + ( m_bWantPFS ? 4 : 0 ) );
		
		if ( m_bWantURL ) pPacket->WriteString( "URL" );
		if ( m_bWantDN ) pPacket->WriteString( "DN" );
		if ( m_bWantXML ) pPacket->WriteString( "MD" );
		if ( m_bWantCOM ) pPacket->WriteString( "COM" );
		if ( m_bWantPFS ) pPacket->WriteString( "PFS" );
	}
	
	if ( m_bAndG1 ) pPacket->WritePacket( "G1", 0 );
	
	pPacket->WriteByte( 0 );
	pPacket->Write( &m_pGUID, sizeof(GGUID) );
	
	return pPacket;
}

//////////////////////////////////////////////////////////////////////
// CQuerySearch to ED2K packet

CEDPacket* CQuerySearch::ToEDPacket(BOOL bUDP)
{
	CEDPacket* pPacket = NULL;
	
	CString strWords = m_pSchema->GetIndexedWords( m_pXML->GetFirstElement() );
	
	if ( m_bED2K && ! m_bWantDN )
	{
		pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_GETSOURCES : ED2K_C2S_GETSOURCES );
		pPacket->Write( &m_pED2K, sizeof(MD4) );
	}
	else if ( m_bBTH )
	{
		// BitTorrent searches prohibited unless they are GETSOURCES above
	}
	else if ( m_sSearch.GetLength() > 0 || strWords.GetLength() > 0 )
	{
		pPacket = CEDPacket::New( bUDP ? ED2K_C2SG_SEARCHREQUEST : ED2K_C2S_SEARCHREQUEST );
		
		if ( m_nMinSize > 0 || m_nMaxSize < SIZE_UNKNOWN )
		{
			pPacket->WriteByte( 0 );
			pPacket->WriteByte( 0 );
			
			pPacket->WriteByte( 0 );
			pPacket->WriteByte( 0 );
			
			pPacket->WriteByte( 3 );
			pPacket->WriteLongLE( (DWORD)m_nMinSize );
			pPacket->WriteByte( 1 );
			pPacket->WriteShortLE( 1 );
			pPacket->WriteByte( ED2K_FT_FILESIZE );
			
			pPacket->WriteByte( 3 );
			pPacket->WriteLongLE( (DWORD)min( m_nMaxSize, 0xFFFFFFFF ) );
			pPacket->WriteByte( 2 );
			pPacket->WriteShortLE( 1 );
			pPacket->WriteByte( ED2K_FT_FILESIZE );
		}
		
		pPacket->WriteByte( 1 );
		pPacket->WriteEDString( m_sSearch.GetLength() ? m_sSearch : strWords );
	}
	
	return pPacket;
}

//////////////////////////////////////////////////////////////////////
// CQuerySearch from packet root

CQuerySearch* CQuerySearch::FromPacket(CPacket* pPacket, SOCKADDR_IN* pEndpoint)
{
	CQuerySearch* pSearch = new CQuerySearch( FALSE );
	
	if ( pPacket->m_nProtocol == PROTOCOL_G1 )
	{
		if ( pSearch->ReadG1Packet( (CG1Packet*)pPacket ) ) return pSearch;
	}
	else if ( pPacket->m_nProtocol == PROTOCOL_G2 )
	{
		if ( ((CG2Packet*)pPacket)->IsType( G2_PACKET_QUERY_WRAP ) )
		{
			if ( pSearch->ReadG1Packet( (CG1Packet*)pPacket ) ) return pSearch;
		}
		else
		{
			if ( pSearch->ReadG2Packet( (CG2Packet*)pPacket, pEndpoint ) ) return pSearch;
		}
	}
	
	delete pSearch;
	
	return NULL;
}

//////////////////////////////////////////////////////////////////////
// CQuerySearch from G1 packet

BOOL CQuerySearch::ReadG1Packet(CPacket* pPacket)
{
	CString strData;
	
	m_bWantCOM = m_bWantPFS = FALSE;
	
	if ( pPacket->m_nProtocol == PROTOCOL_G2 )
	{
		GNUTELLAPACKET pG1;
		if ( ! ((CG2Packet*)pPacket)->SeekToWrapped() ) return NULL;
		pPacket->Read( &pG1, sizeof(pG1) );
		m_pGUID = pG1.m_pGUID;
	}
	else
	{
		m_pGUID = ((CG1Packet*)pPacket)->m_pGUID;
	}
	
	if ( pPacket->GetRemaining() < 4 ) return FALSE;
	
	WORD nFlags = pPacket->ReadShortLE();
	
	if ( nFlags & G1_QF_TAG )
	{
		m_bFirewall	= 0 != ( nFlags & G1_QF_FIREWALLED );
		m_bWantXML	= 0 != ( nFlags & G1_QF_XML );
	}
	
	m_sSearch = pPacket->ReadString();
	
	if ( pPacket->GetRemaining() >= 1 )
	{
		strData = pPacket->ReadString();
		if ( strData.GetLength() > 1024 ) strData.Empty();
	}
	
	LPCTSTR pszData	= strData;
	LPCTSTR pszEnd	= pszData + _tcslen( pszData );
	int nIterations = 0;
	
	while ( *pszData && pszData < pszEnd )
	{
		if ( nIterations++ > 4 ) break;
		
		if ( (BYTE)*pszData == GGEP_MAGIC )
		{
			if ( ! Settings.Gnutella1.EnableGGEP ) break;
			
			CGGEPBlock pGGEP;
			pGGEP.ReadFromString( pszData );
			
			if ( CGGEPItem* pItem = pGGEP.Find( _T("H"), 21 ) )
			{
				if ( pItem->m_pBuffer[0] > 0 && pItem->m_pBuffer[0] < 3 )
				{
					CopyMemory( &m_pSHA1, &pItem->m_pBuffer[1], 20 );
					m_bSHA1 = TRUE;
				}
				if ( pItem->m_pBuffer[0] == 2 && pItem->m_nLength >= 24 + 20 + 1 )
				{
					CopyMemory( &m_pTiger, &pItem->m_pBuffer[21], 24 );
					m_bTiger = TRUE;
				}
			}
			else if ( CGGEPItem* pItem = pGGEP.Find( _T("u") ) )
			{
				strData = pItem->ToString();

				m_bSHA1		|= CSHA::HashFromURN( strData, &m_pSHA1 );
				m_bTiger	|= CTigerNode::HashFromURN( strData, &m_pTiger );
				m_bED2K		|= CED2K::HashFromURN( strData, &m_pED2K );
			}
			
			break;
		}
		
		LPCTSTR pszSep = _tcschr( pszData, 0x1C );
		int nLength = ( pszSep && *pszSep == 0x1C ) ? pszSep - pszData : _tcslen( pszData );
		
		if ( ! _istalnum( *pszData ) ) nLength = 0;
		
		if ( nLength >= 4 && _tcsncmp( pszData, _T("urn:"), 4 ) == 0 )
		{
			m_bSHA1		|= CSHA::HashFromURN( pszData, &m_pSHA1 );
			m_bTiger	|= CTigerNode::HashFromURN( pszData, &m_pTiger );
			m_bED2K		|= CED2K::HashFromURN( pszData, &m_pED2K );
		}
		else if ( nLength > 5 && _tcsncmp( pszData, _T("<?xml"), 5 ) == 0 )
		{
			m_pXML = CXMLElement::FromString( pszData, TRUE );
			
			if ( m_pXML == NULL ) continue;
			
			CString strSchemaURI = m_pXML->GetAttributeValue( CXMLAttribute::schemaName, NULL );
			m_pSchema = SchemaCache.Get( strSchemaURI );
		}
		
		if ( pszSep && *pszSep == 0x1C ) pszData = pszSep + 1;
		else break;
	}
	
	m_bAndG1 = TRUE;
	return CheckValid();
}

//////////////////////////////////////////////////////////////////////
// CQuerySearch from G2 packet

BOOL CQuerySearch::ReadG2Packet(CG2Packet* pPacket, SOCKADDR_IN* pEndpoint)
{
	if ( ! pPacket->m_bCompound ) return FALSE;
	
	CHAR szType[9];
	DWORD nLength;
	
	m_bAndG1 = FALSE;
	
	while ( pPacket->ReadPacket( szType, nLength ) )
	{
		DWORD nOffset = pPacket->m_nPosition + nLength;
		
		if ( strcmp( szType, "QKY" ) == 0 && nLength >= 4 )
		{
			if ( m_pEndpoint.sin_addr.S_un.S_addr == 0 && pEndpoint != NULL )
				m_pEndpoint = *pEndpoint;
			m_bUDP = ! Network.IsFirewalledAddress( &m_pEndpoint.sin_addr );
			
			m_nKey = pPacket->ReadLongBE();
			DWORD* pZero = (DWORD*)( pPacket->m_pBuffer + pPacket->m_nPosition - 4 );
			*pZero = 0;
		}
		else if ( strcmp( szType, "UDP" ) == 0 && nLength >= 6 )
		{
			m_pEndpoint.sin_addr.S_un.S_addr = pPacket->ReadLongLE();
			m_pEndpoint.sin_port = htons( pPacket->ReadShortBE() );
			
			if ( m_pEndpoint.sin_addr.S_un.S_addr == 0 && pEndpoint != NULL )
				m_pEndpoint = *pEndpoint;
			m_bUDP = ! Network.IsFirewalledAddress( &m_pEndpoint.sin_addr );
			if ( m_bUDP ) m_pEndpoint.sin_family = PF_INET;
			
			if ( nLength >= 10 )
			{
				m_nKey = pPacket->ReadLongBE();
				DWORD* pZero = (DWORD*)( pPacket->m_pBuffer + pPacket->m_nPosition - 4 );
				*pZero = 0;
			}
		}
		else if ( strcmp( szType, "I" ) == 0 )
		{
			m_bWantURL = m_bWantDN = m_bWantXML = m_bWantCOM = m_bWantPFS = FALSE;
			
			while ( nLength > 0 )
			{
				CString str = pPacket->ReadString( nLength );
				nLength -= str.GetLength() + 1;
				
				if ( str == _T("URL") )			m_bWantURL = TRUE;
				else if ( str == _T("DN") )		m_bWantDN = TRUE;
				else if ( str == _T("SZ") )		m_bWantDN = TRUE;	// Hack
				else if ( str == _T("MD") )		m_bWantXML = TRUE;
				else if ( str == _T("COM") )	m_bWantCOM = TRUE;
				else if ( str == _T("PFS") )	m_bWantPFS = TRUE;
			}
		}
		else if ( strcmp( szType, "URN" ) == 0 )
		{
			CString strURN = pPacket->ReadString( nLength );
			if ( strURN.GetLength() + 1 >= (int)nLength ) return FALSE;
			nLength -= strURN.GetLength() + 1;
			
			if ( nLength >= 20 && strURN == _T("sha1") )
			{
				m_bSHA1 = TRUE;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -