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