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

📄 edneighbour.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
字号:
//
// EDNeighbour.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 "Statistics.h"
#include "Neighbours.h"
#include "EDNeighbour.h"
#include "EDPacket.h"
#include "Security.h"
#include "GProfile.h"
#include "HostCache.h"
#include "EDClients.h"

#include "Library.h"
#include "SharedFile.h"
#include "Transfers.h"
#include "Downloads.h"
#include "Download.h"
#include "QuerySearch.h"
#include "QueryHit.h"

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


//////////////////////////////////////////////////////////////////////
// CEDNeighbour construction

CEDNeighbour::CEDNeighbour() : CNeighbour( PROTOCOL_ED2K )
{
	m_nNodeType		= ntHub;
	m_nClientID		= 0;
	m_nUserCount	= 0;
	m_nUserLimit	= 0;
	m_nFlags		= 0;
}

CEDNeighbour::~CEDNeighbour()
{
	for ( POSITION pos = m_pQueries.GetHeadPosition() ; pos ; )
	{
		delete (GGUID*)m_pQueries.GetNext( pos );
	}
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour connect to

BOOL CEDNeighbour::ConnectTo(IN_ADDR* pAddress, WORD nPort, BOOL bAutomatic)
{
	if ( CConnection::ConnectTo( pAddress, nPort ) )
	{
		WSAEventSelect( m_hSocket, Network.m_pWakeup, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE );
		
		theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_CONNECTING,
			(LPCTSTR)m_sAddress, htons( m_pHost.sin_port ) );
	}
	else
	{
		theApp.Message( MSG_ERROR, IDS_CONNECTION_CONNECT_FAIL,
			(LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ) );
		return FALSE;
	}
	
	m_nState		= nrsConnecting;
	m_bAutomatic	= bAutomatic;
	
	Neighbours.Add( this );
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour send packet

BOOL CEDNeighbour::Send(CPacket* pPacket, BOOL bRelease, BOOL bBuffered)
{
	BOOL bSuccess = FALSE;
	
	if ( ( m_nState == nrsHandshake1 || m_nState >= nrsConnected ) &&
		 pPacket->m_nProtocol == PROTOCOL_ED2K )
	{
		m_nOutputCount++;
		Statistics.Current.eDonkey.Outgoing++;
		
		pPacket->ToBuffer( m_pZOutput ? m_pZOutput : m_pOutput );
		QueueRun();
		
		pPacket->SmartDump( this, NULL, TRUE );
		// pPacket->Debug( _T("DonkeyOut") );
		bSuccess = TRUE;
	}
	
	if ( bRelease ) pPacket->Release();
	
	return bSuccess;
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour run event

BOOL CEDNeighbour::OnRun()
{
	DWORD tNow = GetTickCount();
	
	if ( m_nState != nrsConnected )
	{
		if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )
		{
			Close( IDS_CONNECTION_TIMEOUT_CONNECT );
			return FALSE;
		}
	}
	else if ( m_nClientID == 0 )
	{
		if ( tNow - m_tConnected > Settings.Connection.TimeoutHandshake )
		{
			Close( IDS_HANDSHAKE_TIMEOUT );
			return FALSE;
		}
	}
	else
	{
		if ( tNow - m_tLastPacket > 20 * 60 * 1000 )
		{
			Close( IDS_CONNECTION_TIMEOUT_TRAFFIC );
			return FALSE;
		}
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour connection event

BOOL CEDNeighbour::OnConnected()
{
	theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_CONNECTED, (LPCTSTR)m_sAddress );
	
	CEDPacket* pPacket = CEDPacket::New(  ED2K_C2S_LOGINREQUEST );
	
	GGUID pGUID	= MyProfile.GUID;
	pGUID.n[5]	= 14;
	pGUID.n[14]	= 111;
	pPacket->Write( &pGUID, 16 );
	
	pPacket->WriteLongLE( m_nClientID );
	pPacket->WriteShortLE( htons( Network.m_pHost.sin_port ) );
	pPacket->WriteLongLE( 4 );
	
	CEDTag( ED2K_CT_NAME, MyProfile.GetNick() ).Write( pPacket );
	CEDTag( ED2K_CT_VERSION, ED2K_VERSION ).Write( pPacket );
	CEDTag( ED2K_CT_PORT, htons( Network.m_pHost.sin_port ) ).Write( pPacket );
	CEDTag( ED2K_CT_COMPRESSION, 1 ).Write( pPacket );
	
	m_nState = nrsHandshake1;
	Send( pPacket );
	
	return TRUE;
}

void CEDNeighbour::OnDropped(BOOL bError)
{
	if ( m_nState < nrsConnected )
	{
		HostCache.OnFailure( &m_pHost.sin_addr, htons( m_pHost.sin_port ) );
	}
	
	if ( m_nState == nrsConnecting )
	{
		Close( IDS_CONNECTION_REFUSED );
	}
	else
	{
		Close( IDS_CONNECTION_DROPPED );
	}
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour read event

BOOL CEDNeighbour::OnRead()
{
	BOOL bSuccess = TRUE;
	CEDPacket* pPacket;
	
	CNeighbour::OnRead();
	
	while ( pPacket = CEDPacket::ReadBuffer( m_pZInput ? m_pZInput : m_pInput, ED2K_PROTOCOL_EDONKEY ) )
	{
		try
		{
			bSuccess = OnPacket( pPacket );
		}
		catch ( CException* pException )
		{
			pException->Delete();
		}
		
		pPacket->Release();
		if ( ! bSuccess ) break;
	}
	
	return bSuccess;
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour packet handler

BOOL CEDNeighbour::OnPacket(CEDPacket* pPacket)
{
	pPacket->SmartDump( this, NULL, FALSE );
	// pPacket->Debug( _T("DonkeyIn") );
	
	m_nInputCount++;
	Statistics.Current.eDonkey.Incoming++;
	m_tLastPacket = GetTickCount();
	
	switch ( pPacket->m_nType )
	{
	case ED2K_S2C_REJECTED:
		return OnRejected( pPacket );
	case ED2K_S2C_SERVERMESSAGE:
		return OnServerMessage( pPacket );
	case ED2K_S2C_IDCHANGE:
		return OnIdChange( pPacket );
	case ED2K_S2C_SERVERLIST:
		return OnServerList( pPacket );
	case ED2K_S2C_SERVERSTATUS:
		return OnServerStatus( pPacket );
	case ED2K_S2C_SERVERIDENT:
		return OnServerIdent( pPacket );
	case ED2K_S2C_CALLBACKREQUESTED:
		return OnCallbackRequest( pPacket );
	case ED2K_S2C_SEARCHRESULTS:
		return OnSearchResults( pPacket );
	case ED2K_S2C_FOUNDSOURCES:
		return OnFoundSources( pPacket );
	default:
		pPacket->Debug( _T("Unknown") );
		break;
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour server packets

BOOL CEDNeighbour::OnRejected(CEDPacket* pPacket)
{
	Close( IDS_ED2K_SERVER_REJECTED );
	return FALSE;
}

BOOL CEDNeighbour::OnServerMessage(CEDPacket* pPacket)
{
	if ( pPacket->GetRemaining() < 4 ) return TRUE;
	
	CString	strMessage = pPacket->ReadEDString();
	
	while ( strMessage.GetLength() > 0 )
	{
		CString strLine = strMessage.SpanExcluding( _T("\r\n") );
		
		if ( strLine.GetLength() > 0 )
		{
			strMessage = strMessage.Mid( strLine.GetLength() );
			theApp.Message( MSG_SYSTEM, IDS_ED2K_SERVER_MESSAGE,
				(LPCTSTR)m_sAddress, (LPCTSTR)strLine );
		}
		
		if ( strMessage.GetLength() > 0 ) strMessage = strMessage.Mid( 1 );
	}
	
	return TRUE;
}

BOOL CEDNeighbour::OnIdChange(CEDPacket* pPacket)
{
	if ( pPacket->GetRemaining() < 4 ) return TRUE;
	
	DWORD nClientID = pPacket->ReadLongLE();
	
	if ( nClientID == 0 )
	{
		Close( IDS_ED2K_SERVER_REFUSED );
		return FALSE;
	}
	
	if ( pPacket->GetRemaining() >= 4 )
	{
		m_nFlags = pPacket->ReadLongLE();
	}
	
	if ( m_nClientID == 0 )
	{
		theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_ONLINE, (LPCTSTR)m_sAddress, nClientID );
		SendSharedFiles();
		Send( CEDPacket::New(  ED2K_C2S_GETSERVERLIST ) );
		HostCache.eDonkey.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ) );
	}
	else
	{
		theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_IDCHANGE, (LPCTSTR)m_sAddress, m_nClientID, nClientID );
	}
	
	m_nState	= nrsConnected;
	m_nClientID	= nClientID;
	
	if ( ! CEDPacket::IsLowID( m_nClientID ) )
	{
		if ( Settings.Connection.InHost.IsEmpty() )
		{
			Network.m_pHost.sin_addr.S_un.S_addr = m_nClientID;
		}
	}
	
	return TRUE;
}

BOOL CEDNeighbour::OnServerList(CEDPacket* pPacket)
{
	if ( pPacket->GetRemaining() < 1 ) return TRUE;
	
	int nCount = pPacket->ReadByte();
	if ( pPacket->GetRemaining() < nCount * 6 ) return TRUE;
	
	while ( nCount-- > 0 )
	{
		DWORD nAddress	= pPacket->ReadLongLE();
		WORD nPort		= pPacket->ReadShortLE();
		
		theApp.Message( MSG_DEBUG, _T("CEDNeighbour::OnServerList(): %s: %s:%i"),
			(LPCTSTR)m_sAddress,
			(LPCTSTR)CString( inet_ntoa( (IN_ADDR&)nAddress ) ), nPort );
		
		if ( Settings.eDonkey.LearnNewServers )
		{
			HostCache.eDonkey.Add( (IN_ADDR*)&nAddress, nPort );
		}
	}
	
	HostCache.eDonkey.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ) );
	
	return TRUE;
}

BOOL CEDNeighbour::OnServerStatus(CEDPacket* pPacket)
{
	if ( pPacket->GetRemaining() < 8 ) return TRUE;
	
	m_nUserCount	= pPacket->ReadLongLE();
	m_nFileCount	= pPacket->ReadLongLE();
	
	if ( CHostCacheHost* pHost = HostCache.eDonkey.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ) ) )
	{
		// pHost->m_nUserCount = max( pHost->m_nUserCount, m_nUserCount );
		pHost->m_nUserCount = m_nUserCount;
		pHost->m_nUserLimit = max( pHost->m_nUserLimit, m_nUserCount );
	}
	
	return TRUE;
}

BOOL CEDNeighbour::OnServerIdent(CEDPacket* pPacket)
{
	if ( pPacket->GetRemaining() < sizeof(GGUID) + 6 + 4 ) return TRUE;
	
	m_bGUID = TRUE;
	pPacket->Read( &m_pGUID, sizeof(GGUID) );
	
	pPacket->ReadLongLE();	// IP
	pPacket->ReadShortLE();	// Port
	
	DWORD nTags = pPacket->ReadLongLE();
	CString strDescription;
	
	while ( nTags-- > 0 && pPacket->GetRemaining() > 1 )
	{
		CEDTag pTag;
		if ( ! pTag.Read( pPacket ) ) break;
		
		if ( pTag.Check( ED2K_ST_SERVERNAME, ED2K_TAG_STRING ) )
		{
			m_sServerName = pTag.m_sValue;
		}
		else if ( pTag.Check( ED2K_ST_DESCRIPTION, ED2K_TAG_STRING ) )
		{
			strDescription = pTag.m_sValue;
		}
		else if ( pTag.Check( ED2K_ST_MAXUSERS, ED2K_TAG_INT ) )
		{
			m_nUserLimit = pTag.m_nValue;
		}
	}
	
	if ( (DWORD&)m_pGUID == 0x2A2A2A2A )
		m_sUserAgent = _T("eFarm Server");
	else
		m_sUserAgent = _T("eDonkey2000 Server");
	
	if ( CHostCacheHost* pHost = HostCache.eDonkey.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ) ) )
	{
		pHost->m_sName			= m_sServerName;
		pHost->m_sDescription	= strDescription;
		pHost->m_nUserLimit		= m_nUserLimit;
	}
	
	theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_IDENT, (LPCTSTR)m_sAddress, (LPCTSTR)m_sServerName );
	
	return TRUE;
}

BOOL CEDNeighbour::OnCallbackRequest(CEDPacket* pPacket)
{
	if ( pPacket->GetRemaining() < 6 ) return TRUE;
	
	DWORD nAddress	= pPacket->ReadLongLE();
	WORD nPort		= pPacket->ReadShortLE();
	
	if ( Network.IsFirewalledAddress( &nAddress ) ) return TRUE;
	
	EDClients.PushTo( nAddress, nPort );
	
	return TRUE;
}

BOOL CEDNeighbour::OnSearchResults(CEDPacket* pPacket)
{
	if ( m_pQueries.GetCount() == 0 )
	{
		Statistics.Current.eDonkey.Dropped++;
		m_nDropCount++;
		return TRUE;
	}
	
	GGUID* pGUID		= (GGUID*)m_pQueries.RemoveHead();
	CQueryHit* pHits	= CQueryHit::FromPacket( pPacket, &m_pHost, pGUID );
	
	if ( pHits == NULL )
	{
		delete pGUID;
		
		if ( pPacket->m_nLength != 17 && pPacket->m_nLength != 5 )
		{
			pPacket->Debug( _T("BadSearchResult") );
			theApp.Message( MSG_ERROR, IDS_PROTOCOL_BAD_HIT, (LPCTSTR)m_sAddress );
			Statistics.Current.eDonkey.Dropped++;
			m_nDropCount++;
		}
		
		return TRUE;
	}
	
	if ( pPacket->m_nType == ED2K_S2C_SEARCHRESULTS && pPacket->GetRemaining() == 1 && m_pQueries.IsEmpty() )
	{
		if ( pPacket->ReadByte() == TRUE )
		{
			Send( CEDPacket::New(  ED2K_C2S_MORERESULTS ) );
			m_pQueries.AddTail( pGUID );
			pGUID = NULL;
		}
	}
	
	Network.OnQueryHits( pHits );
	
	if ( pGUID != NULL ) delete pGUID;
	
	return TRUE;
}

BOOL CEDNeighbour::OnFoundSources(CEDPacket* pPacket)
{
	return OnSearchResults( pPacket );
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour file adverising

void CEDNeighbour::SendSharedFiles()
{
	CEDPacket* pPacket = CEDPacket::New( ED2K_C2S_OFFERFILES );
	BYTE pPadding[6] = { 0, 0, 0, 0, 0, 0 };
	POSITION pos;
	
	int nCount = 0, nLimit = Settings.eDonkey.MaxShareCount;
	
	pPacket->WriteLongLE( nCount );
	
	CSingleLock pLock1( &Library.m_pSection );
	CSingleLock pLock2( &Transfers.m_pSection );
	
	pLock1.Lock();
	
	for ( pos = LibraryMaps.GetFileIterator() ; pos != NULL && ( nLimit == 0 || nCount < nLimit ) ; )
	{
		CLibraryFile* pFile = LibraryMaps.GetNextFile( pos );
		
		if ( pFile->IsShared() && pFile->m_bED2K )
		{
			pPacket->Write( &pFile->m_pED2K, sizeof(MD4) );
			pPacket->Write( pPadding, 6 );
			pPacket->WriteLongLE( 2 );
			CEDTag( ED2K_FT_FILENAME, pFile->m_sName ).Write( pPacket );
			CEDTag( ED2K_FT_FILESIZE, (DWORD)pFile->GetSize() ).Write( pPacket );
			nCount++;
		}
	}
	
	pLock1.Unlock();
	pLock2.Lock();
	
	for ( pos = Downloads.GetIterator() ; pos != NULL && ( nLimit == 0 || nCount < nLimit ) ; )
	{
		CDownload* pDownload = Downloads.GetNext( pos );
		
		if ( pDownload->m_bED2K && pDownload->IsStarted() && ! pDownload->IsMoving() &&
			 pDownload->NeedHashset() == FALSE )
		{
			pPacket->Write( &pDownload->m_pED2K, sizeof(MD4) );
			pPacket->Write( pPadding, 6 );
			pPacket->WriteLongLE( 2 );
			CEDTag( ED2K_FT_FILENAME, pDownload->m_sRemoteName ).Write( pPacket );
			CEDTag( ED2K_FT_FILESIZE, (DWORD)pDownload->m_nSize ).Write( pPacket );
			nCount++;
		}
	}
	
	pLock2.Unlock();
	
	*(DWORD*)pPacket->m_pBuffer = nCount;
	
	if ( m_nFlags & ED2K_SERVER_TCP_DEFLATE ) pPacket->Deflate();
	Send( pPacket );
}

BOOL CEDNeighbour::SendSharedDownload(CDownload* pDownload)
{
	if ( m_nState < nrsConnected ) return FALSE;
	if ( ! pDownload->m_bED2K || pDownload->NeedHashset() ) return FALSE;
	
	CEDPacket* pPacket = CEDPacket::New(  ED2K_C2S_OFFERFILES );
	BYTE pPadding[6] = { 0, 0, 0, 0, 0, 0 };
	
	pPacket->WriteLongLE( 1 );
	pPacket->Write( &pDownload->m_pED2K, sizeof(MD4) );
	pPacket->Write( pPadding, 6 );
	pPacket->WriteLongLE( 2 );
	CEDTag( ED2K_FT_FILENAME, pDownload->m_sRemoteName ).Write( pPacket );
	CEDTag( ED2K_FT_FILESIZE, (DWORD)pDownload->m_nSize ).Write( pPacket );
	
	if ( m_nFlags & ED2K_SERVER_TCP_DEFLATE ) pPacket->Deflate();
	Send( pPacket );
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDNeighbour file adverising

BOOL CEDNeighbour::SendQuery(CQuerySearch* pSearch, CPacket* pPacket, BOOL bLocal)
{
	if ( m_nState != nrsConnected || m_nClientID == 0 )
	{
		return FALSE;	// We're not ready
	}
	else if ( pPacket == NULL || pPacket->m_nProtocol != PROTOCOL_ED2K || ! bLocal )
	{
		return FALSE;	// Packet is bad
	}
	
	m_pQueries.AddTail( new GGUID( pSearch->m_pGUID ) );
	Send( pPacket, FALSE, FALSE );
	
	return TRUE;
}

⌨️ 快捷键说明

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