📄 btclient.cpp
字号:
//
// BTClient.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 "BTClient.h"
#include "BTClients.h"
#include "BTPacket.h"
#include "BENode.h"
#include "Buffer.h"
#include "SHA.h"
#include "Download.h"
#include "Downloads.h"
#include "DownloadSource.h"
#include "DownloadTransferBT.h"
#include "Uploads.h"
#include "UploadTransferBT.h"
#include "SourceURL.h"
#include "GProfile.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// CBTClient construction
CBTClient::CBTClient()
{
m_bShareaza = FALSE;
m_pUpload = NULL;
m_pDownload = NULL;
m_pDownloadTransfer = NULL;
m_bShake = FALSE;
m_bOnline = FALSE;
m_bClosing = FALSE;
m_bExchange = FALSE;
m_sUserAgent = _T("BitTorrent");
m_mInput.pLimit = m_mOutput.pLimit = &Settings.Bandwidth.Request;
BTClients.Add( this );
}
CBTClient::~CBTClient()
{
ASSERT( m_hSocket == INVALID_SOCKET );
ASSERT( m_pDownloadTransfer == NULL );
ASSERT( m_pDownload == NULL );
ASSERT( m_pUpload == NULL );
BTClients.Remove( this );
}
//////////////////////////////////////////////////////////////////////
// CBTClient initiate a new connection
BOOL CBTClient::Connect(CDownloadTransferBT* pDownloadTransfer)
{
ASSERT( m_hSocket == INVALID_SOCKET );
ASSERT( m_pDownload == NULL );
CDownloadSource* pSource = pDownloadTransfer->m_pSource;
if ( ! CTransfer::ConnectTo( &pSource->m_pAddress, pSource->m_nPort ) ) return FALSE;
m_pDownload = pDownloadTransfer->m_pDownload;
m_pDownloadTransfer = pDownloadTransfer;
theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_CONNECTING, (LPCTSTR)m_sAddress );
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CBTClient attach to existing connection
void CBTClient::AttachTo(CConnection* pConnection)
{
ASSERT( m_hSocket == INVALID_SOCKET );
CTransfer::AttachTo( pConnection );
theApp.Message( MSG_DEFAULT, IDS_BT_ACCEPTED, (LPCTSTR)m_sAddress );
}
//////////////////////////////////////////////////////////////////////
// CBTClient close
void CBTClient::Close()
{
ASSERT( this != NULL );
if ( m_bClosing ) return;
m_bClosing = TRUE;
if ( m_pUpload != NULL ) m_pUpload->Close();
ASSERT( m_pUpload == NULL );
if ( m_pDownloadTransfer != NULL ) m_pDownloadTransfer->Close( TS_UNKNOWN );
ASSERT( m_pDownloadTransfer == NULL );
m_pDownload = NULL;
CTransfer::Close();
delete this;
}
//////////////////////////////////////////////////////////////////////
// CBTClient send a packet
void CBTClient::Send(CBTPacket* pPacket, BOOL bRelease)
{
ASSERT( m_hSocket != INVALID_SOCKET );
ASSERT( m_bOnline );
if ( pPacket != NULL )
{
ASSERT( pPacket->m_nProtocol == PROTOCOL_BT );
pPacket->ToBuffer( m_pOutput );
if ( bRelease ) pPacket->Release();
}
OnWrite();
}
//////////////////////////////////////////////////////////////////////
// CBTClient run event
BOOL CBTClient::OnRun()
{
CTransfer::OnRun();
DWORD tNow = GetTickCount();
if ( ! m_bConnected )
{
if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )
{
theApp.Message( MSG_ERROR, IDS_BT_CLIENT_CONNECT_TIMEOUT, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
}
else if ( ! m_bOnline )
{
if ( tNow - m_tConnected > Settings.Connection.TimeoutHandshake )
{
theApp.Message( MSG_ERROR, IDS_BT_CLIENT_HANDSHAKE_TIMEOUT, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
}
else
{
if ( tNow - max( m_mOutput.tLast, m_mInput.tLast ) > Settings.BitTorrent.LinkTimeout * 2 )
{
theApp.Message( MSG_ERROR, IDS_BT_CLIENT_LOST, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
else if ( tNow - m_mOutput.tLast > Settings.BitTorrent.LinkPing / 2 && m_pOutput->m_nLength == 0 )
{
DWORD tOutput = m_mOutput.tLast;
DWORD dwZero = 0;
m_pOutput->Add( &dwZero, 4 );
OnWrite();
m_mOutput.tLast = tOutput;
}
if ( m_pDownloadTransfer != NULL && ! m_pDownloadTransfer->OnRun() ) return FALSE;
if ( ! m_pUpload->OnRun() ) return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CBTClient connection establishment event
BOOL CBTClient::OnConnected()
{
theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_HANDSHAKING, (LPCTSTR)m_sAddress );
SendHandshake( TRUE, TRUE );
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CBTClient connection loss event
void CBTClient::OnDropped(BOOL bError)
{
if ( ! m_bConnected )
theApp.Message( MSG_ERROR, IDS_BT_CLIENT_CONNECT_TIMEOUT, (LPCTSTR)m_sAddress );
else if ( ! m_bOnline )
theApp.Message( MSG_ERROR, IDS_BT_CLIENT_HANDSHAKE_TIMEOUT, (LPCTSTR)m_sAddress );
else
theApp.Message( MSG_ERROR, IDS_BT_CLIENT_DROPPED, (LPCTSTR)m_sAddress );
Close();
}
//////////////////////////////////////////////////////////////////////
// CBTClient write event
BOOL CBTClient::OnWrite()
{
CTransfer::OnWrite();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CBTClient read event
BOOL CBTClient::OnRead()
{
BOOL bSuccess = TRUE;
CTransfer::OnRead();
if ( m_bOnline )
{
CBTPacket* pPacket;
while ( pPacket = CBTPacket::ReadBuffer( m_pInput ) )
{
try
{
bSuccess = OnPacket( pPacket );
}
catch ( CException* pException )
{
pException->Delete();
if ( ! m_bOnline ) bSuccess = FALSE;
}
pPacket->Release();
if ( ! bSuccess ) break;
}
}
else
{
if ( ! m_bShake && m_pInput->m_nLength >= BT_PROTOCOL_HEADER_LEN + 8 + sizeof(SHA1) )
{
bSuccess = OnHandshake1();
}
if ( bSuccess && m_bShake && m_pInput->m_nLength >= sizeof(SHA1) )
{
bSuccess = OnHandshake2();
}
}
return bSuccess;
}
//////////////////////////////////////////////////////////////////////
// CBTClient handshaking
void CBTClient::SendHandshake(BOOL bPart1, BOOL bPart2)
{
ASSERT( m_pDownload != NULL );
if ( bPart1 )
{
DWORD dwZero = 0;
m_pOutput->Print( BT_PROTOCOL_HEADER );
m_pOutput->Add( &dwZero, 4 );
m_pOutput->Add( &dwZero, 4 );
m_pOutput->Add( &m_pDownload->m_pBTH, sizeof(SHA1) );
}
if ( bPart2 )
{
m_pOutput->Add( BTClients.GetGUID(), sizeof(SHA1) );
}
OnWrite();
}
BOOL CBTClient::OnHandshake1()
{
ASSERT( ! m_bOnline );
ASSERT( ! m_bShake );
LPBYTE pIn = m_pInput->m_pBuffer;
if ( memcmp( pIn, BT_PROTOCOL_HEADER, BT_PROTOCOL_HEADER_LEN ) != 0 )
{
ASSERT( FALSE );
Close();
return FALSE;
}
pIn += BT_PROTOCOL_HEADER_LEN + 8;
SHA1 pFileHash = *(SHA1*)pIn;
pIn += sizeof(SHA1);
m_pInput->Remove( BT_PROTOCOL_HEADER_LEN + 8 + sizeof(SHA1) );
if ( m_bInitiated )
{
ASSERT( m_pDownload != NULL );
ASSERT( m_pDownloadTransfer != NULL );
if ( pFileHash != m_pDownload->m_pBTH || m_pDownload->IsShared() == FALSE )
{
theApp.Message( MSG_ERROR, IDS_BT_CLIENT_WRONG_FILE, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
}
else
{
ASSERT( m_pDownload == NULL );
ASSERT( m_pDownloadTransfer == NULL );
m_pDownload = Downloads.FindByBTH( &pFileHash, TRUE );
if ( m_pDownload == NULL )
{
m_pDownload = NULL;
theApp.Message( MSG_ERROR, IDS_BT_CLIENT_UNKNOWN_FILE, (LPCTSTR)m_sAddress );
Close();
return FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -