📄 downloadtransferbt.cpp
字号:
//
// DownloadTransferBT.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 "BTClients.h"
#include "BTClient.h"
#include "BTPacket.h"
#include "Download.h"
#include "Downloads.h"
#include "DownloadSource.h"
#include "DownloadTransferBT.h"
#include "FragmentedFile.h"
#include "Network.h"
#include "Buffer.h"
#include "BENode.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT construction
CDownloadTransferBT::CDownloadTransferBT(CDownloadSource* pSource, CBTClient* pClient) : CDownloadTransfer( pSource, PROTOCOL_BT )
{
ASSERT( m_pDownload->m_bBTH );
ASSERT( m_pDownload->m_nSize != SIZE_UNKNOWN );
m_pClient = pClient;
m_nState = pClient ? dtsConnecting : dtsNull;
m_sUserAgent = _T("BitTorrent");
m_bChoked = TRUE;
m_bInterested = FALSE;
m_pAvailable = NULL;
m_pRequested = NULL;
m_nRequested = 0;
m_tRunThrottle = 0;
m_tSourceRequest = GetTickCount();
}
CDownloadTransferBT::~CDownloadTransferBT()
{
ASSERT( m_pClient == NULL );
m_pRequested->DeleteChain();
if ( m_pAvailable != NULL ) delete [] m_pAvailable;
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT initiate
BOOL CDownloadTransferBT::Initiate()
{
ASSERT( m_pClient == NULL );
ASSERT( m_nState == dtsNull );
m_pClient = new CBTClient();
if ( ! m_pClient->Connect( this ) )
{
delete m_pClient;
m_pClient = NULL;
Close( TS_FALSE );
return FALSE;
}
SetState( dtsConnecting );
m_tConnected = GetTickCount();
m_pHost = m_pClient->m_pHost;
m_sAddress = m_pClient->m_sAddress;
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT close
void CDownloadTransferBT::Close(TRISTATE bKeepSource)
{
if ( m_pClient != NULL )
{
m_pClient->m_pDownloadTransfer = NULL;
if ( m_pClient->IsOnline() )
{
m_pClient->Send( CBTPacket::New( BT_PACKET_NOT_INTERESTED ) );
}
else
{
m_pClient->Close();
}
m_pClient = NULL;
}
CDownloadTransfer::Close( bKeepSource );
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT bandwidth control
void CDownloadTransferBT::Boost()
{
if ( m_pClient == NULL ) return;
m_pClient->m_mInput.pLimit = NULL;
}
DWORD CDownloadTransferBT::GetAverageSpeed()
{
return m_pSource->m_nSpeed = GetMeasuredSpeed();
}
DWORD CDownloadTransferBT::GetMeasuredSpeed()
{
if ( m_pClient == NULL ) return 0;
m_pClient->Measure();
return m_pClient->m_mInput.nMeasure;
}
CString CDownloadTransferBT::GetStateText(BOOL bLong)
{
if ( m_nState == dtsTorrent )
{
CString str;
if ( ! m_bInterested )
str = _T("Uninterested");
else if ( m_bChoked )
str = _T("Choked");
else
str = _T("Requesting");
return str;
}
return CDownloadTransfer::GetStateText( bLong );
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT send packet helper
void CDownloadTransferBT::Send(CBTPacket* pPacket, BOOL bRelease)
{
ASSERT( m_pClient != NULL );
m_pClient->Send( pPacket, bRelease );
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT run event
BOOL CDownloadTransferBT::OnRun()
{
DWORD tNow = GetTickCount();
if ( tNow - m_tRunThrottle >= 2000 )
{
m_tRunThrottle = tNow;
ShowInterest();
if ( m_nState == dtsTorrent || m_nState == dtsRequesting || m_nState == dtsDownloading )
{
if ( ! SendRequests() ) return FALSE;
}
}
if ( m_pClient->m_bExchange && tNow - m_tSourceRequest >= Settings.BitTorrent.SourceExchangePeriod * 60000 )
{
Send( CBTPacket::New( BT_PACKET_SOURCE_REQUEST ) );
m_tSourceRequest = tNow;
}
return CDownloadTransfer::OnRun();
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT connection established event
BOOL CDownloadTransferBT::OnConnected()
{
ASSERT( m_pClient != NULL );
ASSERT( m_pSource != NULL );
SetState( dtsTorrent );
m_pHost = m_pClient->m_pHost;
m_sAddress = m_pClient->m_sAddress;
m_pSource->SetLastSeen();
m_pClient->m_mInput.pLimit = &Downloads.m_nLimitGeneric;
theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONNECTED, (LPCTSTR)m_sAddress );
if ( ! m_pDownload->PrepareFile() )
{
Close( TS_TRUE );
return FALSE;
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT bitfields
BOOL CDownloadTransferBT::OnBitfield(CBTPacket* pPacket)
{
QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize;
DWORD nBlockCount = m_pDownload->m_pTorrent.m_nBlockCount;
m_pSource->m_pAvailable->DeleteChain();
m_pSource->m_pAvailable = NULL;
if ( m_pAvailable != NULL ) delete [] m_pAvailable;
m_pAvailable = NULL;
if ( nBlockSize == 0 || nBlockCount == 0 ) return TRUE;
m_pAvailable = new BYTE[ nBlockCount ];
ZeroMemory( m_pAvailable, nBlockCount );
for ( DWORD nBlock = 0 ; nBlock < nBlockCount && pPacket->GetRemaining() ; )
{
BYTE nByte = pPacket->ReadByte();
for ( int nBit = 7 ; nBit >= 0 && nBlock < nBlockCount ; nBit--, nBlock++ )
{
if ( nByte & ( 1 << nBit ) )
{
QWORD nOffset = nBlockSize * nBlock;
QWORD nLength = min( nBlockSize, m_pDownload->m_nSize - nOffset );
CFileFragment::AddMerge( &m_pSource->m_pAvailable, nOffset, nLength );
m_pAvailable[ nBlock ] = TRUE;
}
}
}
ShowInterest();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT have block updates
void CDownloadTransferBT::SendFinishedBlock(DWORD nBlock)
{
if ( m_pClient == NULL || ! m_pClient->IsOnline() ) return;
CBTPacket* pPacket = CBTPacket::New( BT_PACKET_HAVE );
pPacket->WriteLongBE( nBlock );
Send( pPacket );
}
BOOL CDownloadTransferBT::OnHave(CBTPacket* pPacket)
{
if ( pPacket->GetRemaining() != sizeof(int) ) return TRUE;
QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize;
DWORD nBlockCount = m_pDownload->m_pTorrent.m_nBlockCount;
DWORD nBlock = pPacket->ReadLongBE();
if ( nBlock >= nBlockCount ) return TRUE;
QWORD nOffset = nBlockSize * nBlock;
QWORD nLength = min( nBlockSize, m_pDownload->m_nSize - nOffset );
CFileFragment::AddMerge( &m_pSource->m_pAvailable, nOffset, nLength );
if ( m_pAvailable == NULL )
{
m_pAvailable = new BYTE[ nBlockCount ];
ZeroMemory( m_pAvailable, nBlockCount );
}
m_pAvailable[ nBlock ] = TRUE;
ShowInterest();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT interest control
void CDownloadTransferBT::ShowInterest()
{
BOOL bInterested = FALSE;
// TODO: Use an algorithm similar to CDownloadWithTiger::FindNext.., rather
// than relying on that algorithm to complete verifications here.
if ( m_pAvailable == NULL )
{
// Never interested if we don't know what they have
// bInterested = m_pDownload->GetVolumeRemaining() != 0;
}
else if ( QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize )
{
for ( CFileFragment* pFragment = m_pDownload->GetFirstEmptyFragment() ; pFragment ; pFragment = pFragment->m_pNext )
{
DWORD nBlock = (DWORD)( pFragment->m_nOffset / nBlockSize );
for ( QWORD nLength = pFragment->m_nLength ; ; nBlock ++, nLength -= nBlockSize )
{
if ( m_pAvailable[ nBlock ] )
{
bInterested = TRUE;
break;
}
if ( nLength <= nBlockSize ) break;
}
if ( bInterested ) break;
}
}
if ( bInterested != m_bInterested )
{
m_bInterested = bInterested;
Send( CBTPacket::New( bInterested ? BT_PACKET_INTERESTED : BT_PACKET_NOT_INTERESTED ) );
if ( ! bInterested )
{
m_pRequested->DeleteChain();
m_pRequested = NULL;
m_nRequested = 0;
}
}
}
//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT choking
BOOL CDownloadTransferBT::OnChoked(CBTPacket* pPacket)
{
if ( m_bChoked ) return TRUE;
m_bChoked = TRUE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -