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

📄 g2neighbour.cpp

📁 p2p软件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// G2Neighbour.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 "Network.h"
#include "Security.h"
#include "Statistics.h"
#include "Neighbours.h"
#include "G2Neighbour.h"
#include "G2Packet.h"
#include "G1Packet.h"
#include "Buffer.h"
#include "Handshakes.h"
#include "Datagrams.h"
#include "HostCache.h"
#include "RouteCache.h"
#include "VendorCache.h"
#include "QuerySearch.h"
#include "QueryHit.h"
#include "Library.h"
#include "LocalSearch.h"
#include "SearchManager.h"
#include "QueryHashTable.h"
#include "HubHorizon.h"
#include "GProfile.h"
#include "Uploads.h"
#include "XML.h"

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


//////////////////////////////////////////////////////////////////////
// CG2Neighbour construction

CG2Neighbour::CG2Neighbour(CNeighbour* pBase) : CNeighbour( PROTOCOL_G2, pBase )
{
	theApp.Message( MSG_DEFAULT, IDS_HANDSHAKE_ONLINE_G2, (LPCTSTR)m_sAddress,
		m_sUserAgent.IsEmpty() ? _T("Unknown") : (LPCTSTR)m_sUserAgent );
	
	m_nLeafCount	= 0;
	m_nLeafLimit	= 0;
	m_bCachedKeys	= FALSE;
	
	m_pGUIDCache	= new CRouteCache();
	m_pHubGroup		= new CHubHorizonGroup();
	
	m_tAdjust		= 0;
	m_tLastPingIn	= 0;
	m_tLastPingOut	= 0;
	m_tLastPacket	= GetTickCount();
	m_tWaitLNI		= m_tLastPacket;
	m_tLastKHL		= m_tLastPacket - Settings.Gnutella2.KHLPeriod + 1000;
	m_tLastHAW		= m_tLastPacket;
	
	SendStartups();
}

CG2Neighbour::~CG2Neighbour()
{
	delete m_pHubGroup;
	delete m_pGUIDCache;
	
	for ( POSITION pos = m_pOutbound.GetHeadPosition() ; pos ; )
	{
		CG2Packet* pOutbound = (CG2Packet*)m_pOutbound.GetNext( pos );
		pOutbound->Release();
	}
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour read and write events

BOOL CG2Neighbour::OnRead()
{
	CNeighbour::OnRead();
	return ProcessPackets();
}

BOOL CG2Neighbour::OnWrite()
{
	CBuffer* pOutput = m_pZOutput ? m_pZOutput : m_pOutput;
	
	while ( pOutput->m_nLength == 0 && m_nOutbound > 0 )
	{
		CG2Packet* pPacket = (CG2Packet*)m_pOutbound.RemoveHead();
		m_nOutbound--;
		
		pPacket->ToBuffer( pOutput );
		pPacket->Release();
		
		CNeighbour::OnWrite();
	}
	
	CNeighbour::OnWrite();
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour run event

BOOL CG2Neighbour::OnRun()
{
	if ( ! CNeighbour::OnRun() ) return FALSE;
	
	DWORD tNow = GetTickCount();
	
	if ( m_tWaitLNI > 0 && tNow - m_tWaitLNI > Settings.Gnutella2.KHLPeriod * 3 )
	{
		Close( IDS_CONNECTION_TIMEOUT_TRAFFIC );
		return FALSE;
	}
	else if ( tNow - m_tLastPingOut >= Settings.Gnutella1.PingRate )
	{
		BOOL bNeedStable = Network.IsListening() && ! Datagrams.IsStable();
		CG2Packet* pPing = CG2Packet::New( G2_PACKET_PING, TRUE );
		
		if ( bNeedStable )
		{
			pPing->WritePacket( "UDP", 6 );
			pPing->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
			pPing->WriteShortBE( htons( Network.m_pHost.sin_port ) );
		}
		
		Send( pPing );
		Datagrams.Send( &m_pHost, CG2Packet::New( G2_PACKET_PING ) );
		m_tLastPingOut = tNow;
	}
	
	if ( tNow - m_tLastKHL > Settings.Gnutella2.KHLPeriod )
	{
		SendLNI();
		SendKHL();
	}
	else if ( tNow - m_tLastHAW > Settings.Gnutella2.HAWPeriod )
	{
		SendHAW();
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour send packet

BOOL CG2Neighbour::Send(CPacket* pPacket, BOOL bRelease, BOOL bBuffered)
{
	BOOL bSuccess = FALSE;
	
	if ( m_nState >= nrsConnected && pPacket->m_nProtocol == PROTOCOL_G2 )
	{
		m_nOutputCount++;
		Statistics.Current.Gnutella2.Outgoing++;
		
		if ( bBuffered )
		{
			if ( m_nOutbound >= Settings.Gnutella1.PacketBufferSize )
			{
				CG2Packet* pRemove = (CG2Packet*)m_pOutbound.RemoveTail();
				pRemove->Release();
				m_nOutbound--;
				Statistics.Current.Gnutella2.Lost++;
			}
			
			pPacket->AddRef();
			m_pOutbound.AddHead( pPacket );
			m_nOutbound++;
		}
		else
		{
			pPacket->ToBuffer( m_pZOutput ? m_pZOutput : m_pOutput );
		}
		
		QueueRun();
		
		pPacket->SmartDump( this, NULL, TRUE );
		
		bSuccess = TRUE;
	}
	
	if ( bRelease ) pPacket->Release();
	
	return bSuccess;
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour startup events

void CG2Neighbour::SendStartups()
{	
	CG2Packet* pPing = CG2Packet::New( G2_PACKET_PING, TRUE );
	
	if ( Network.IsListening() )
	{
		pPing->WritePacket( "UDP", 6 );
		pPing->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
		pPing->WriteShortBE( htons( Network.m_pHost.sin_port ) );
	}
	
	Send( pPing, TRUE, TRUE );
	m_tLastPingOut = GetTickCount();
	
	Datagrams.Send( &m_pHost, CG2Packet::New( G2_PACKET_PING ) );
	
	Send( CG2Packet::New( G2_PACKET_PROFILE_CHALLENGE ), TRUE, TRUE );
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour packet dispatch

BOOL CG2Neighbour::ProcessPackets()
{
	CBuffer* pInput = m_pZInput ? m_pZInput : m_pInput;
	
	for ( BOOL bSuccess = TRUE ; bSuccess && pInput->m_nLength ; )
	{
		BYTE nInput = *(pInput->m_pBuffer);
		
		if ( nInput == 0 )
		{
			pInput->Remove( 1 );
			continue;
		}
		
		BYTE nLenLen	= ( nInput & 0xC0 ) >> 6;
		BYTE nTypeLen	= ( nInput & 0x38 ) >> 3;
		BYTE nFlags		= ( nInput & 0x07 );
		
		if ( (DWORD)pInput->m_nLength < (DWORD)nLenLen + nTypeLen + 2 ) break;
		
		DWORD nLength = 0;
		
		if ( nFlags & G2_FLAG_BIG_ENDIAN )
		{
			BYTE* pLenIn = pInput->m_pBuffer + 1;
			
			for ( BYTE nIt = nLenLen ; nIt ; nIt-- )
			{
				nLength <<= 8;
				nLength |= *pLenIn++;
			}
		}
		else
		{
			BYTE* pLenIn	= pInput->m_pBuffer + 1;
			BYTE* pLenOut	= (BYTE*)&nLength;
			for ( BYTE nLenCnt = nLenLen ; nLenCnt-- ; ) *pLenOut++ = *pLenIn++;
		}
		
		if ( nLength >= Settings.Gnutella1.MaximumPacket )
		{
			Close( IDS_PROTOCOL_TOO_LARGE );
			return FALSE;
		}
		
		if ( (DWORD)pInput->m_nLength < (DWORD)nLength + nLenLen + nTypeLen + 2 ) break;
		
		CG2Packet* pPacket = CG2Packet::New( pInput->m_pBuffer );
		
		try
		{
			bSuccess = OnPacket( pPacket );
		}
		catch ( CException* pException )
		{
			pException->Delete();
			// bSuccess = FALSE;		// SHOULD THIS BE LIKE THIS?
			bSuccess = TRUE;
		}
		
		pPacket->Release();
		
		pInput->Remove( nLength + nLenLen + nTypeLen + 2 );
	}
	
	if ( bSuccess ) return TRUE;
	
	Close( 0 );
	return FALSE;
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour packet handler

BOOL CG2Neighbour::OnPacket(CG2Packet* pPacket)
{
	m_nInputCount++;
	m_tLastPacket = GetTickCount();
	Statistics.Current.Gnutella2.Incoming++;
	
	pPacket->SmartDump( this, NULL, FALSE );
	
	if ( Network.RoutePacket( pPacket ) ) return TRUE;
	
	if ( pPacket->IsType( G2_PACKET_PING ) )
	{
		return OnPing( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_LNI ) )
	{
		return OnLNI( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_KHL ) )
	{
		return OnKHL( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_HAW ) )
	{
		return OnHAW( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_QUERY ) || pPacket->IsType( G2_PACKET_QUERY_WRAP ) )
	{
		return OnQuery( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_HIT ) || pPacket->IsType( G2_PACKET_HIT_WRAP ) )
	{
		return OnCommonHit( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_QUERY_ACK ) )
	{
		return OnQueryAck( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_QUERY_KEY_REQ ) )
	{
		return OnQueryKeyReq( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_QUERY_KEY_ANS ) )
	{
		return OnQueryKeyAns( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_QHT ) )
	{
		return OnCommonQueryHash( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_PUSH ) )
	{
		return OnPush( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_PROFILE_CHALLENGE ) )
	{
		return OnProfileChallenge( pPacket );
	}
	else if ( pPacket->IsType( G2_PACKET_PROFILE_DELIVERY ) )
	{
		return OnProfileDelivery( pPacket );
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour PING packet handler

BOOL CG2Neighbour::OnPing(CG2Packet* pPacket)
{
	Send( CG2Packet::New( G2_PACKET_PONG ) );
	
	if ( ! pPacket->m_bCompound ) return TRUE;
	
	BOOL bRelay = FALSE;
	DWORD nAddress = 0;
	WORD nPort = 0;
	CHAR szType[9];
	DWORD nLength;
	
	while ( pPacket->ReadPacket( szType, nLength ) )
	{
		DWORD nNext = pPacket->m_nPosition + nLength;
		
		if ( strcmp( szType, "UDP" ) == 0 && nLength >= 6 )
		{
			nAddress	= pPacket->ReadLongLE();
			nPort		= pPacket->ReadShortBE();
		}
		else if ( strcmp( szType, "RELAY" ) == 0 )
		{
			bRelay = TRUE;
		}
		
		pPacket->m_nPosition = nNext;
	}	
	
	if ( ! nPort || Network.IsFirewalledAddress( &nAddress ) ) return TRUE;
	
	if ( bRelay )
	{
		CG2Packet* pPong = CG2Packet::New( G2_PACKET_PONG, TRUE );
		pPong->WritePacket( "RELAY", 0 );
		Datagrams.Send( (IN_ADDR*)&nAddress, nPort, pPong );
	}
	else
	{
		DWORD tNow = GetTickCount();
		if ( tNow - m_tLastPingIn < Settings.Gnutella1.PingFlood ) return TRUE;
		m_tLastPingIn = tNow;
		
		BYTE* pRelay = pPacket->WriteGetPointer( 7, 0 );
		*pRelay++ = 0x60;
		*pRelay++ = 0;
		*pRelay++ = 'R'; *pRelay++ = 'E'; *pRelay++ = 'L';
		*pRelay++ = 'A'; *pRelay++ = 'Y';
		
		for ( POSITION pos = Neighbours.GetIterator() ; pos ; )
		{
			CG2Neighbour* pNeighbour = (CG2Neighbour*)Neighbours.GetNext( pos );
			
			if ( pNeighbour->m_nProtocol == PROTOCOL_G2 &&
				 pNeighbour != this )
			{
				pNeighbour->Send( pPacket, FALSE );
			}
		}
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour LOCAL NODE INFO : send

void CG2Neighbour::SendLNI()
{
	CG2Packet* pPacket = CG2Packet::New( G2_PACKET_LNI, TRUE );
	
	QWORD nMyVolume = 0;
	DWORD nMyFiles = 0;
	LibraryMaps.GetStatistics( &nMyFiles, &nMyVolume );
	
	WORD nLeafs = 0;
	
	for ( POSITION pos = Neighbours.GetIterator() ; pos ; )
	{
		CNeighbour* pNeighbour = Neighbours.GetNext( pos );

		if (	pNeighbour != this &&
				pNeighbour->m_nState == nrsConnected &&
				pNeighbour->m_nNodeType == ntLeaf )
		{
			nMyFiles += pNeighbour->m_nFileCount;
			nMyVolume += pNeighbour->m_nFileVolume;
			nLeafs++;
		}
	}

	pPacket->WritePacket( "NA", 6 );
	pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
	pPacket->WriteShortBE( htons( Network.m_pHost.sin_port ) );

	pPacket->WritePacket( "GU", 16 );
	pPacket->Write( &MyProfile.GUID, 16 );

	pPacket->WritePacket( "V", 4 );
	pPacket->WriteString( SHAREAZA_VENDOR_A, FALSE );

	pPacket->WritePacket( "LS", 8 );
	pPacket->WriteLongBE( (DWORD)nMyFiles );
	pPacket->WriteLongBE( (DWORD)nMyVolume );

	if ( ! Neighbours.IsLeaf() )
	{
		pPacket->WritePacket( "HS", 4 );
		pPacket->WriteShortBE( nLeafs );
		pPacket->WriteShortBE( Settings.Gnutella2.NumLeafs );
		
		pPacket->WritePacket( "QK", 0 );
	}
	
	Send( pPacket, TRUE, FALSE );
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour LOCAL NODE INFO : receive

BOOL CG2Neighbour::OnLNI(CG2Packet* pPacket)
{
	if ( ! pPacket->m_bCompound ) return TRUE;
	
	DWORD tNow = time( NULL );
	CHAR szType[9];
	DWORD nLength;
	
	m_nLeafCount = 0;
	
	while ( pPacket->ReadPacket( szType, nLength ) )
	{
		DWORD nNext = pPacket->m_nPosition + nLength;

		if ( strcmp( szType, "NA" ) == 0 && nLength >= 6 )
		{
			m_pHost.sin_addr.S_un.S_addr = pPacket->ReadLongLE();
			m_pHost.sin_port = htons( pPacket->ReadShortBE() );
		}
		else if ( strcmp( szType, "GU" ) == 0 && nLength >= 16 )
		{
			pPacket->Read( &m_pGUID, sizeof(GGUID) );
			m_bGUID = TRUE;
		}
		else if ( strcmp( szType, "V" ) == 0 && nLength >= 4 )
		{
			CHAR szVendor[5] = { 0, 0, 0, 0, 0 };
			pPacket->Read( szVendor, 4 );
			m_pVendor = VendorCache.Lookup( szVendor );
		}
		else if ( strcmp( szType, "LS" ) == 0 && nLength >= 8 )
		{
			m_nFileCount	= pPacket->ReadLongBE();
			m_nFileVolume	= pPacket->ReadLongBE();
		}
		else if ( strcmp( szType, "HS" ) == 0 && nLength >= 2 )
		{
			m_nLeafCount = pPacket->ReadShortBE();
			m_nLeafLimit = pPacket->ReadShortBE();
		}
		else if ( strcmp( szType, "QK" ) == 0 )
		{
			m_bCachedKeys = TRUE;
		}
		
		pPacket->m_nPosition = nNext;
	}
	
	if ( ! Network.IsFirewalledAddress( &m_pHost.sin_addr, TRUE ) &&
		   m_pVendor != NULL && m_nNodeType != ntLeaf )
	{
		HostCache.Gnutella2.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ),
			0, m_pVendor->m_sCode );
	}
	
	m_tWaitLNI = 0;
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CG2Neighbour KNOWN HUB LIST : send

void CG2Neighbour::SendKHL()
{
	CG2Packet* pPacket = CG2Packet::New( G2_PACKET_KHL, TRUE );
	
	DWORD nBase = pPacket->m_nPosition;
	
	for ( POSITION pos = Neighbours.GetIterator() ; pos ; )
	{
		CG2Neighbour* pNeighbour = (CG2Neighbour*)Neighbours.GetNext( pos );
		
		if (	pNeighbour != this &&
				pNeighbour->m_nProtocol == PROTOCOL_G2 &&
				pNeighbour->m_nState == nrsConnected &&
				pNeighbour->m_nNodeType != ntLeaf &&
				pNeighbour->m_pHost.sin_addr.S_un.S_addr != Network.m_pHost.sin_addr.S_un.S_addr )
		{
			if ( pNeighbour->m_pVendor && pNeighbour->m_pVendor->m_sCode.GetLength() == 4 )

⌨️ 快捷键说明

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