📄 g2neighbour.cpp
字号:
//
// 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 + -