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

📄 edclient.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// EDClient.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 "Neighbours.h"
#include "EDNeighbour.h"
#include "EDClient.h"
#include "EDClients.h"
#include "EDPacket.h"
#include "GProfile.h"
#include "HostCache.h"
#include "ED2K.h"

#include "Library.h"
#include "SharedFile.h"
#include "Download.h"
#include "Downloads.h"
#include "DownloadSource.h"
#include "DownloadTransferED2K.h"
#include "UploadTransferED2K.h"
#include "SourceURL.h"

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


//////////////////////////////////////////////////////////////////////
// CEDClient construction

CEDClient::CEDClient()
{
	m_pEdPrev		= NULL;
	m_pEdNext		= NULL;
	
	m_bGUID			= FALSE;
	m_pGUID			= (GGUID&)GUID_NULL;
	m_nClientID		= 0;
	m_nUDP			= 0;
	
	m_bEmule		= FALSE;
	m_bEmSources	= FALSE;
	m_bEmComments	= FALSE;
	m_bEmRequest	= FALSE;
	m_bEmDeflate	= FALSE;
	m_nEmVersion	= 0;
	m_nEmCompatible	= 0;
	
	m_bLogin		= FALSE;
	m_bUpMD4		= FALSE;
	
	m_pDownload		= NULL;
	m_pUpload		= NULL;
	m_bSeeking		= FALSE;
	m_nRunExCookie	= 0;
	
	m_mInput.pLimit		= &Settings.Bandwidth.Request;
	m_mOutput.pLimit	= &Settings.Bandwidth.Request;
	
	EDClients.Add( this );
}

CEDClient::~CEDClient()
{
	ASSERT( m_hSocket == INVALID_SOCKET );
	ASSERT( m_pUpload == NULL );
	ASSERT( m_pDownload == NULL );
	
	EDClients.Remove( this );
}

//////////////////////////////////////////////////////////////////////
// CEDClient outbound connection

BOOL CEDClient::ConnectTo(DWORD nClientID, WORD nClientPort, IN_ADDR* pServerAddress, WORD nServerPort, GGUID* pGUID)
{
	ASSERT( m_nClientID == 0 );
	
	m_nClientID = nClientID;
	if ( m_bGUID = ( pGUID != NULL ) ) m_pGUID = *pGUID;
	
	m_pHost.sin_family		= AF_INET;
	m_pHost.sin_addr		= (IN_ADDR&)nClientID;
	m_pHost.sin_port		= htons( nClientPort );
	
	if ( pServerAddress != NULL && nServerPort != 0 )
	{
		m_pServer.sin_family	= AF_INET;
		m_pServer.sin_addr		= *pServerAddress;
		m_pServer.sin_port		= htons( nServerPort );
	}
	else
	{
		ZeroMemory( &m_pServer, sizeof(m_pServer) );
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDClient equality

BOOL CEDClient::Equals(CEDClient* pClient)
{
	ASSERT( this != NULL );
	ASSERT( pClient != NULL );
	
	if ( m_bGUID && pClient->m_bGUID ) return m_pGUID == pClient->m_pGUID;
	
	if ( CEDPacket::IsLowID( m_nClientID ) &&
		 CEDPacket::IsLowID( pClient->m_nClientID ) )
	{
		return	( m_pServer.sin_addr.S_un.S_addr == pClient->m_pServer.sin_addr.S_un.S_addr ) &&
				( m_nClientID == pClient->m_nClientID );
	}
	
	return m_pHost.sin_addr.S_un.S_addr == pClient->m_pHost.sin_addr.S_un.S_addr;
}

//////////////////////////////////////////////////////////////////////
// CEDClient connect

BOOL CEDClient::Connect()
{
	if ( m_hSocket != INVALID_SOCKET ) return FALSE;
	if ( EDClients.IsFull( this ) ) return FALSE;
	
	if ( CEDPacket::IsLowID( m_nClientID ) )
	{
		if ( ! Neighbours.PushDonkey( m_nClientID, &m_pServer.sin_addr, htons( m_pServer.sin_port ) ) ) return FALSE;
		m_tConnected = GetTickCount();
	}
	else
	{
		if ( ! CConnection::ConnectTo( &m_pHost ) ) return FALSE;
		theApp.Message( MSG_DEFAULT, IDS_ED2K_CLIENT_CONNECTING, (LPCTSTR)m_sAddress );
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDClient remove

void CEDClient::Remove()
{
	ASSERT( this != NULL );
	
	m_bGUID = TRUE;
	Close();
	
	DetachUpload();
	DetachDownload();
	
	Close();
	
	if ( Settings.General.Debug && Settings.General.DebugLog ) theApp.Message( MSG_DEBUG, _T("CEDClient::Remove(): %x"), this );
	
	delete this;
}

//////////////////////////////////////////////////////////////////////
// CEDClient merge

void CEDClient::Merge(CEDClient* pClient)
{
	ASSERT( pClient != NULL );
	
	if ( pClient->m_pDownload != NULL )
	{
		DetachDownload();
		m_pDownload = pClient->m_pDownload;
		m_pDownload->m_pClient = this;
		pClient->m_pDownload = NULL;
	}
	
	if ( pClient->m_pUpload != NULL )
	{
		DetachUpload();
		m_pUpload = pClient->m_pUpload;
		m_pUpload->m_pClient = this;
		pClient->m_pUpload = NULL;
	}
}

//////////////////////////////////////////////////////////////////////
// CEDClient send a packet

void CEDClient::Send(CEDPacket* pPacket, BOOL bRelease)
{
	if ( pPacket != NULL )
	{
		ASSERT( pPacket->m_nProtocol == PROTOCOL_ED2K );
		ASSERT( pPacket->m_nEdProtocol == ED2K_PROTOCOL_EDONKEY || m_bEmule || pPacket->m_nType == ED2K_C2C_EMULEINFO );
		
		if ( m_hSocket != INVALID_SOCKET )
		{
			// pPacket->Debug( _T("CEDClient::Send") );
			pPacket->ToBuffer( m_pOutput );
			OnWrite();
		}
		
		if ( bRelease ) pPacket->Release();
	}
	else if ( m_hSocket != INVALID_SOCKET )
	{
		OnWrite();
	}
}

//////////////////////////////////////////////////////////////////////
// CEDClient attach to existing connection

void CEDClient::AttachTo(CConnection* pConnection)
{
	ASSERT( m_hSocket == INVALID_SOCKET );
	CTransfer::AttachTo( pConnection );
	theApp.Message( MSG_DEFAULT, IDS_ED2K_CLIENT_ACCEPTED, (LPCTSTR)m_sAddress );
}

//////////////////////////////////////////////////////////////////////
// CEDClient close

void CEDClient::Close()
{
	ASSERT( this != NULL );
	CTransfer::Close();
	m_bConnected = m_bLogin = FALSE;
	// if ( ! m_bGUID ) Remove();
}

//////////////////////////////////////////////////////////////////////
// CEDClient transfer coupling

BOOL CEDClient::AttachDownload(CDownloadTransferED2K* pDownload)
{
	if ( m_pDownload != NULL ) return FALSE;
	m_pDownload = pDownload;
	
	if ( m_bLogin )
		return m_pDownload->OnConnected();
	else if ( m_hSocket == INVALID_SOCKET )
		Connect();
	
	return TRUE;
}

void CEDClient::OnDownloadClose()
{
	CDownloadSource* pExcept = m_pDownload ? m_pDownload->m_pSource : NULL;
	m_pDownload = NULL;
	m_mInput.pLimit = &Settings.Bandwidth.Request;
	SeekNewDownload( pExcept );
}

BOOL CEDClient::SeekNewDownload(CDownloadSource* pExcept)
{
	// Removed for a while
	return FALSE;
	
	if ( m_pDownload != NULL ) return FALSE;
	if ( m_bSeeking ) return FALSE;
	m_bSeeking = TRUE;
	BOOL bSeek = Downloads.OnDonkeyCallback( this, pExcept );
	m_bSeeking = FALSE;
	return bSeek;
}

void CEDClient::DetachDownload()
{
	m_bSeeking = TRUE;
	if ( m_pDownload != NULL ) m_pDownload->Close( TS_UNKNOWN );
	ASSERT( m_pDownload == NULL );
	m_bSeeking = FALSE;
}

void CEDClient::OnUploadClose()
{
	m_pUpload = NULL;
	m_mOutput.pLimit = &Settings.Bandwidth.Request;
}

void CEDClient::DetachUpload()
{
	if ( m_pUpload != NULL ) m_pUpload->Close();
	ASSERT( m_pUpload == NULL );
}

//////////////////////////////////////////////////////////////////////
// CEDClient run event

BOOL CEDClient::OnRun()
{
	// CTransfer::OnRun();
	
	DWORD tNow = GetTickCount();
	
	if ( ! m_bConnected )
	{
		if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )
		{
			theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_CONNECT_TIMEOUT, (LPCTSTR)m_sAddress );
			NotifyDropped();
			Close();
			return FALSE;
		}
	}
	else if ( ! m_bLogin )
	{
		if ( tNow - m_tConnected > Settings.Connection.TimeoutHandshake )
		{
			theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_TIMEOUT, (LPCTSTR)m_sAddress );
			NotifyDropped();
			Close();
			return FALSE;
		}
	}
	else
	{
		if ( tNow - m_mInput.tLast > Settings.Connection.TimeoutTraffic &&
			 tNow - m_mOutput.tLast > Settings.Connection.TimeoutTraffic )
		{
			theApp.Message( MSG_DEFAULT, IDS_ED2K_CLIENT_CLOSED, (LPCTSTR)m_sAddress );
			Close();
			return FALSE;
		}
	}
	
	return TRUE;
}

void CEDClient::OnRunEx(DWORD tNow)
{
	if ( m_pDownload != NULL )
	{
		m_pDownload->OnRunEx( tNow );
		if ( m_pUpload != NULL ) m_pUpload->OnRunEx( tNow );
	}
	else if ( m_pUpload != NULL )
	{
		m_pUpload->OnRunEx( tNow );
	}
	else if ( m_hSocket == INVALID_SOCKET )
	{
		Remove();
	}
}

//////////////////////////////////////////////////////////////////////
// CEDClient connection event

BOOL CEDClient::OnConnected()
{
	SendHello( ED2K_C2C_HELLO );
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDClient connection loss event

void CEDClient::OnDropped(BOOL bError)
{
	theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_DROPPED, (LPCTSTR)m_sAddress );
	NotifyDropped( bError );
	Close();
}

void CEDClient::NotifyDropped(BOOL bError)
{
	m_bSeeking = TRUE;
	if ( m_pDownload != NULL ) m_pDownload->OnDropped( bError );
	if ( m_pUpload != NULL ) m_pUpload->OnDropped( bError );
	m_bSeeking = FALSE;
}

//////////////////////////////////////////////////////////////////////
// CEDClient write event

BOOL CEDClient::OnWrite()
{
	CTransfer::OnWrite();
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDClient read event

BOOL CEDClient::OnRead()
{
	BOOL bSuccess = TRUE;
	CEDPacket* pPacket;
	
	CTransfer::OnRead();
	
	while ( pPacket = CEDPacket::ReadBuffer( m_pInput, ED2K_PROTOCOL_EMULE ) )
	{
		try
		{
			bSuccess = OnPacket( pPacket );
		}
		catch ( CException* pException )
		{
			pException->Delete();
			if ( ! m_bGUID ) bSuccess = FALSE;
		}
		
		pPacket->Release();
		if ( ! bSuccess ) break;
	}
	
	return bSuccess;
}

//////////////////////////////////////////////////////////////////////
// CEDClient logged in event

BOOL CEDClient::OnLoggedIn()
{
	m_bLogin = TRUE;
	
	EDClients.Merge( this );
	
	if ( m_pDownload != NULL )
	{
		m_pDownload->OnConnected();
	}
	else
	{
		SeekNewDownload();
	}
	
	if ( m_pUpload != NULL ) m_pUpload->OnConnected();
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDClient packet switch

BOOL CEDClient::OnPacket(CEDPacket* pPacket)
{
	// pPacket->Debug( _T("CEDClient::OnPacket") );
	
	if ( pPacket->m_nEdProtocol == ED2K_PROTOCOL_EDONKEY )
	{
		switch ( pPacket->m_nType )
		{
		// Handshake

		case ED2K_C2C_HELLO:
			if ( pPacket->GetRemaining() ) pPacket->ReadByte();
			return OnHello( pPacket );
		case ED2K_C2C_HELLOANSWER:
			return OnHello( pPacket );
		
		// Upload

		case ED2K_C2C_FILEREQUEST:
			return OnFileRequest( pPacket );
		case ED2K_C2C_FILESTATUSREQUEST:
			return OnFileStatusRequest( pPacket );
		case ED2K_C2C_HASHSETREQUEST:
			return OnHashsetRequest( pPacket );
		case ED2K_C2C_QUEUEREQUEST:
			return OnQueueRequest( pPacket );
		case ED2K_C2C_QUEUERELEASE:
			if ( m_pUpload != NULL ) m_pUpload->OnQueueRelease( pPacket );
			return TRUE;
		case ED2K_C2C_REQUESTPARTS:
			if ( m_pUpload != NULL ) m_pUpload->OnRequestParts( pPacket );
			return TRUE;
		
		// Download
		
		case ED2K_C2C_FILEREQANSWER:
			if ( m_pDownload != NULL ) m_pDownload->OnFileReqAnswer( pPacket );
			return TRUE;
		case ED2K_C2C_FILENOTFOUND:
			if ( m_pDownload != NULL ) m_pDownload->OnFileNotFound( pPacket );
			return TRUE;
		case ED2K_C2C_FILESTATUS:
			if ( m_pDownload != NULL ) m_pDownload->OnFileStatus( pPacket );
			return TRUE;
		case ED2K_C2C_HASHSETANSWER:
			if ( m_pDownload != NULL ) m_pDownload->OnHashsetAnswer( pPacket );
			return TRUE;
		case ED2K_C2C_QUEUERANK:
			if ( m_pDownload != NULL ) m_pDownload->OnQueueRank( pPacket );
			return TRUE;
		case ED2K_C2C_STARTUPLOAD:
			if ( m_pDownload != NULL ) m_pDownload->OnStartUpload( pPacket );
			return TRUE;
		case ED2K_C2C_FINISHUPLOAD:
			if ( m_pDownload != NULL ) m_pDownload->OnFinishUpload( pPacket );
			return TRUE;
		case ED2K_C2C_SENDINGPART:
			if ( m_pDownload != NULL ) m_pDownload->OnSendingPart( pPacket );
			return TRUE;

		}
	}
	else if ( pPacket->m_nEdProtocol == ED2K_PROTOCOL_EMULE )
	{
		switch ( pPacket->m_nType )
		{
		case ED2K_C2C_EMULEINFO:
			return OnEmuleInfo( pPacket );
		case ED2K_C2C_EMULEINFOANSWER:
			return OnEmuleInfo( pPacket );
		
		case ED2K_C2C_REQUESTSOURCES:
			return OnSourceRequest( pPacket );
		case ED2K_C2C_ANSWERSOURCES:
			return OnSourceAnswer( pPacket );
		
		case ED2K_C2C_QUEUERANKING:
			if ( m_pDownload != NULL ) m_pDownload->OnRankingInfo( pPacket );
			return TRUE;
		case ED2K_C2C_COMPRESSEDPART:
			if ( m_pDownload != NULL ) m_pDownload->OnCompressedPart( pPacket );
			return TRUE;

		}
	}
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CEDClient HELLO packet exchange

void CEDClient::SendHello(BYTE nType)
{
	CEDPacket* pPacket = CEDPacket::New( nType );
	
	if ( nType == ED2K_C2C_HELLO ) pPacket->WriteByte( 0x10 );
	
	CEDNeighbour* pServer = Neighbours.GetDonkeyServer();
	
	GGUID pGUID	= MyProfile.GUID;
	pGUID.n[5]	= 14;
	pGUID.n[14]	= 111;
	pPacket->Write( &pGUID, 16 );
	
	pPacket->WriteLongLE( pServer ? pServer->m_nClientID : Network.m_pHost.sin_addr.S_un.S_addr );
	pPacket->WriteShortLE( htons( Network.m_pHost.sin_port ) );
	
	pPacket->WriteLongLE( 2 );	// Tags
	
	CString strNick = MyProfile.GetNick();
	
	if ( Settings.eDonkey.TagNames )
	{
		if ( strNick.GetLength() )
			strNick += _T(" (shareaza.com)");
		else
			strNick = _T("www.shareaza.com");
	}
	
	CEDTag( ED2K_CT_NAME, strNick ).Write( pPacket );
	CEDTag( ED2K_CT_VERSION, ED2K_VERSION ).Write( pPacket );
	// CEDTag( ED2K_CT_PORT, htons( Network.m_pHost.sin_port )  ).Write( pPacket );
	
	if ( pServer != NULL )
	{
		pPacket->WriteLongLE( pServer->m_pHost.sin_addr.S_un.S_addr );
		pPacket->WriteShortLE( htons( pServer->m_pHost.sin_port ) );
	}
	else
	{
		pPacket->WriteLongLE( 0 );
		pPacket->WriteShortLE( 0 );
	}
	
	Send( pPacket );
}

BOOL CEDClient::OnHello(CEDPacket* pPacket)
{
	if ( m_bLogin ) return TRUE;
	

⌨️ 快捷键说明

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