📄 g1neighbour.cpp
字号:
//
// G1Neighbour.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 "Buffer.h"
#include "Statistics.h"
#include "Neighbours.h"
#include "Handshakes.h"
#include "G1Neighbour.h"
#include "G1Packet.h"
#include "G2Packet.h"
#include "HostCache.h"
#include "RouteCache.h"
#include "PacketBuffer.h"
#include "Security.h"
#include "GProfile.h"
#include "PongCache.h"
#include "VendorCache.h"
#include "QuerySearch.h"
#include "QueryHit.h"
#include "QueryHashTable.h"
#include "LocalSearch.h"
#include "SearchManager.h"
#include "DiscoveryServices.h"
#include "Downloads.h"
#include "Uploads.h"
#include "Library.h"
#include "SHA.h"
#include "WndMain.h"
#include "WndChild.h"
#include "WndSearchMonitor.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// CG1Neighbour construction
CG1Neighbour::CG1Neighbour(CNeighbour* pBase) : CNeighbour( PROTOCOL_G1, pBase )
{
ZeroMemory( m_nPongNeeded, PONG_NEEDED_BUFFER );
m_tLastOutPing = m_tLastPacket;
m_nHopsFlow = 0xFF;
m_pOutbound = new CG1PacketBuffer( m_pZOutput ? m_pZOutput : m_pOutput );
theApp.Message( MSG_DEFAULT, IDS_HANDSHAKE_ONLINE, (LPCTSTR)m_sAddress,
0, m_bShake06 ? 6 : 4,
m_sUserAgent.IsEmpty() ? _T("Unknown") : (LPCTSTR)m_sUserAgent );
Send( CG1Packet::New( G1_PACKET_PING ) );
if ( Settings.Gnutella1.VendorMsg && m_bVendorMsg )
{
CG1Packet* pVendor = CG1Packet::New( G1_PACKET_VENDOR, 1 );
pVendor->WriteLongLE( 0 );
pVendor->WriteShortLE( 0 );
pVendor->WriteShortLE( 0 );
pVendor->WriteShortLE( 6 );
pVendor->WriteLongLE( 'RAEB' );
pVendor->WriteShortLE( 0x0004 );
pVendor->WriteShortLE( 1 );
pVendor->WriteLongLE( 'RAEB' );
pVendor->WriteShortLE( 0x000B );
pVendor->WriteShortLE( 1 );
pVendor->WriteLongLE( 'RAEB' );
pVendor->WriteShortLE( 0x000C );
pVendor->WriteShortLE( 1 );
pVendor->WriteLongLE( 'AZAR' );
pVendor->WriteShortLE( 0x0001 );
pVendor->WriteShortLE( 1 );
pVendor->WriteLongLE( 'AZAR' );
pVendor->WriteShortLE( 0x0002 );
pVendor->WriteShortLE( 1 );
pVendor->WriteLongLE( 'AZAR' );
pVendor->WriteShortLE( 0x0003 );
pVendor->WriteShortLE( 1 );
Send( pVendor );
}
}
CG1Neighbour::~CG1Neighbour()
{
if ( m_pOutbound ) delete m_pOutbound;
}
//////////////////////////////////////////////////////////////////////
// CG1Neighbour read and write events
BOOL CG1Neighbour::OnRead()
{
CNeighbour::OnRead();
return ProcessPackets();
}
BOOL CG1Neighbour::OnWrite()
{
CBuffer* pOutput = m_pZOutput ? m_pZOutput : m_pOutput;
DWORD nExpire = GetTickCount();
CNeighbour::OnWrite();
while ( pOutput->m_nLength == 0 && m_pOutbound->m_nTotal > 0 )
{
CG1Packet* pPacket = m_pOutbound->GetPacketToSend( nExpire );
if ( ! pPacket ) break;
pPacket->ToBuffer( pOutput );
pPacket->Release();
m_pOutbound->m_nTotal --;
CNeighbour::OnWrite();
}
m_nOutbound = m_pOutbound->m_nTotal;
m_nLostCount = m_pOutbound->m_nDropped;
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CG1Neighbour run event
BOOL CG1Neighbour::OnRun()
{
if ( ! CNeighbour::OnRun() ) return FALSE;
DWORD tNow = GetTickCount();
SendPing( tNow, NULL );
// if ( m_bShareaza && tNow - m_tClusterSent > 60000 ) SendClusterAdvisor();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CG1Neighbour send packet
BOOL CG1Neighbour::Send(CPacket* pPacket, BOOL bRelease, BOOL bBuffered)
{
CG1Packet* pPacketG1 = (CG1Packet*)pPacket;
BOOL bSuccess = FALSE;
if ( m_nState >= nrsConnected && pPacket->m_nProtocol == PROTOCOL_G1 && pPacketG1->m_nTTL )
{
m_nOutputCount++;
Statistics.Current.Gnutella1.Outgoing++;
m_pOutbound->Add( pPacketG1, bBuffered );
QueueRun();
pPacketG1->SmartDump( this, NULL, TRUE );
bSuccess = TRUE;
}
if ( bRelease ) pPacket->Release();
return bSuccess;
}
//////////////////////////////////////////////////////////////////////
// CG1Neighbour packet dispatch
BOOL CG1Neighbour::ProcessPackets()
{
CBuffer* pInput = m_pZInput ? m_pZInput : m_pInput;
for ( BOOL bSuccess = TRUE ; bSuccess ; )
{
GNUTELLAPACKET* pPacket = (GNUTELLAPACKET*)pInput->m_pBuffer;
if ( pInput->m_nLength < sizeof(*pPacket) ) break;
DWORD nLength = sizeof(*pPacket) + pPacket->m_nLength;
if ( pPacket->m_nLength < 0 || nLength >= Settings.Gnutella1.MaximumPacket )
{
Close( IDS_PROTOCOL_TOO_LARGE );
return FALSE;
}
if ( pInput->m_nLength < nLength ) break;
CG1Packet* pPacketObject = CG1Packet::New( pPacket );
bSuccess = OnPacket( pPacketObject );
pPacketObject->Release();
pInput->Remove( nLength );
}
if ( bSuccess ) return TRUE;
Close( 0 );
return FALSE;
}
//////////////////////////////////////////////////////////////////////
// CG1Neighbour packet handler
BOOL CG1Neighbour::OnPacket(CG1Packet* pPacket)
{
m_nInputCount++;
m_tLastPacket = GetTickCount();
Statistics.Current.Gnutella1.Incoming++;
if ( pPacket->m_nTTL == 0 )
{
theApp.Message( MSG_DEBUG, IDS_PROTOCOL_NO_TTL, (LPCTSTR)m_sAddress );
}
else if ( (DWORD)pPacket->m_nTTL + pPacket->m_nHops > Settings.Gnutella1.MaximumTTL &&
pPacket->m_nType != G1_PACKET_PUSH && pPacket->m_nType != G1_PACKET_HIT )
{
theApp.Message( MSG_ERROR, IDS_PROTOCOL_HIGH_TTL, (LPCTSTR)m_sAddress,
pPacket->m_nTTL, pPacket->m_nHops );
pPacket->m_nTTL = 1;
}
pPacket->SmartDump( this, NULL, FALSE );
switch ( pPacket->m_nType )
{
case G1_PACKET_PING:
return OnPing( pPacket );
case G1_PACKET_PONG:
return OnPong( pPacket );
case G1_PACKET_BYE:
return OnBye( pPacket );
case G1_PACKET_QUERY_ROUTE:
return OnCommonQueryHash( pPacket );
case G1_PACKET_VENDOR:
case G1_PACKET_VENDOR_APP:
return OnVendor( pPacket );
case G1_PACKET_PUSH:
return OnPush( pPacket );
case G1_PACKET_QUERY:
return OnQuery( pPacket );
case G1_PACKET_HIT:
return OnHit( pPacket );
}
theApp.Message( MSG_ERROR, IDS_PROTOCOL_UNKNOWN, (LPCTSTR)m_sAddress, pPacket->m_nType );
return ! Settings.Gnutella1.StrictPackets;
}
//////////////////////////////////////////////////////////////////////
// CG1Neighbour PING packet handlers
BOOL CG1Neighbour::SendPing(DWORD dwNow, GGUID* pGUID)
{
if ( m_nNodeType == ntLeaf && pGUID != NULL ) return FALSE;
BOOL bNeedPeers = Neighbours.NeedMoreHubs( TS_FALSE ) ||
Neighbours.NeedMoreLeafs( TS_FALSE );
if ( ! dwNow ) dwNow = GetTickCount();
if ( m_bPongCaching )
{
if ( dwNow - m_tLastOutPing < Settings.Gnutella1.PingRate * 2 ) return FALSE;
// if ( ! bNeedPeers && dwNow - m_tLastPacket < Settings.Gnutella1.PingRate ) return FALSE;
}
else
{
if ( dwNow - m_tLastOutPing < Settings.Gnutella1.PingRate * 2 ) return FALSE;
}
m_tLastOutPing = dwNow;
Send( CG1Packet::New( G1_PACKET_PING, ( pGUID || bNeedPeers ) ? 0 : 1, pGUID ), TRUE, TRUE );
return TRUE;
}
BOOL CG1Neighbour::OnPing(CG1Packet* pPacket)
{
if ( ! Neighbours.m_pPingRoute->Add( &pPacket->m_pGUID, this ) )
{
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
if ( pPacket->m_nLength != 0 && Settings.Gnutella1.StrictPackets )
{
theApp.Message( MSG_ERROR, IDS_PROTOCOL_SIZE_PING, (LPCTSTR)m_sAddress );
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
else if ( pPacket->m_nLength > Settings.Gnutella1.MaximumQuery )
{
theApp.Message( MSG_ERROR, IDS_PROTOCOL_TOO_LARGE, (LPCTSTR)m_sAddress );
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
BOOL bIsKeepAlive = ( pPacket->m_nTTL == 1 && pPacket->m_nHops == 0 );
DWORD dwNow = GetTickCount();
if ( dwNow - m_tLastInPing < Settings.Gnutella1.PingFlood && ! bIsKeepAlive )
{
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
if ( pPacket->m_nLength && m_bGGEP )
{
if ( pPacket->ReadByte() != GGEP_MAGIC )
{
theApp.Message( MSG_ERROR, IDS_PROTOCOL_GGEP_REQUIRED, (LPCTSTR)m_sAddress );
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
else if ( pPacket->Hop() )
{
if ( Neighbours.Broadcast( pPacket, this, TRUE ) )
Statistics.Current.Gnutella1.Routed ++;
pPacket->m_nHops --; // Dehop
pPacket->m_nTTL ++;
}
}
m_tLastInPing = dwNow;
m_nLastPingHops = pPacket->m_nHops + 1;
m_pLastPingID = pPacket->m_pGUID;
if ( pPacket->m_nTTL == 2 && pPacket->m_nHops == 0 )
{
for ( POSITION pos = Neighbours.GetIterator() ; pos ; )
{
CNeighbour* pConnection = Neighbours.GetNext( pos );
if ( pConnection->m_nState != nrsConnected ) continue;
CG1Packet* pPong = CG1Packet::New( G1_PACKET_PONG, m_nLastPingHops, &m_pLastPingID );
pPong->WriteShortLE( htons( pConnection->m_pHost.sin_port ) );
pPong->WriteLongLE( pConnection->m_pHost.sin_addr.S_un.S_addr );
pPong->WriteLongLE( 0 );
pPong->WriteLongLE( 0 );
Send( pPong );
}
// theApp.Message( MSG_DEFAULT, IDS_CONNECTION_CRAWLER, (LPCTSTR)m_sAddress );
return TRUE;
}
if ( bIsKeepAlive || ( Network.IsListening() && ! Neighbours.IsLeaf() ) )
{
CG1Packet* pPong = CG1Packet::New( G1_PACKET_PONG, m_nLastPingHops, &m_pLastPingID );
QWORD nMyVolume;
DWORD nMyFiles;
LibraryMaps.GetStatistics( &nMyFiles, &nMyVolume );
pPong->WriteShortLE( htons( Network.m_pHost.sin_port ) );
pPong->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
pPong->WriteLongLE( nMyFiles );
pPong->WriteLongLE( (DWORD)nMyVolume );
Send( pPong );
}
if ( bIsKeepAlive || m_nNodeType == ntHub || ! pPacket->Hop() ) return TRUE;
Neighbours.OnG1Ping();
CPtrList pIgnore;
ZeroMemory( m_nPongNeeded, PONG_NEEDED_BUFFER );
for ( BYTE nHops = 1 ; nHops <= pPacket->m_nTTL ; nHops++ )
{
m_nPongNeeded[ nHops ] = Settings.Gnutella1.PongCount / pPacket->m_nTTL;
CPongItem* pCache = NULL;
while ( ( m_nPongNeeded[ nHops ] > 0 ) &&
( pCache = Neighbours.m_pPongCache->Lookup( this, nHops, &pIgnore ) ) )
{
Send( pCache->ToPacket( m_nLastPingHops, &m_pLastPingID ) );
pIgnore.AddTail( pCache );
m_nPongNeeded[ nHops ]--;
}
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CG1Neighbour PONG packet handlers
BOOL CG1Neighbour::OnPong(CG1Packet* pPacket)
{
if ( pPacket->m_nLength < 14 || ( pPacket->m_nLength > 14 && Settings.Gnutella1.StrictPackets ) )
{
theApp.Message( MSG_ERROR, IDS_PROTOCOL_SIZE_PONG, (LPCTSTR)m_sAddress );
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
WORD nPort = pPacket->ReadShortLE();
DWORD nAddress = pPacket->ReadLongLE();
DWORD nFiles = pPacket->ReadLongLE();
DWORD nVolume = pPacket->ReadLongLE();
if ( Security.IsDenied( (IN_ADDR*)&nAddress ) )
{
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
if ( pPacket->m_nLength > 14 && m_bGGEP )
{
if ( pPacket->ReadByte() != GGEP_MAGIC )
{
theApp.Message( MSG_ERROR, IDS_PROTOCOL_GGEP_REQUIRED, (LPCTSTR)m_sAddress );
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
else if ( pPacket->Hop() )
{
CG1Neighbour* pOrigin;
Neighbours.m_pPingRoute->Lookup( &pPacket->m_pGUID, (CNeighbour**)&pOrigin );
if ( pOrigin && pOrigin->m_bGGEP )
{
Statistics.Current.Gnutella1.Routed++;
pOrigin->Send( pPacket, FALSE, TRUE );
}
pPacket->m_nHops--; // Dehop
}
}
BOOL bLocal = ! nPort || Network.IsFirewalledAddress( &nAddress );
if ( pPacket->m_nHops != 0 && bLocal )
{
if ( pPacket->m_nHops ) theApp.Message( MSG_DEBUG, IDS_PROTOCOL_ZERO_PONG, (LPCTSTR)m_sAddress );
Statistics.Current.Gnutella1.Dropped++;
m_nDropCount++;
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -