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

📄 uploadtransferbt.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
字号:
//
// UploadTransferBT.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 "BTPacket.h"
#include "Download.h"
#include "DownloadTransferBT.h"
#include "Uploads.h"
#include "UploadFile.h"
#include "UploadTransferBT.h"
#include "FragmentedFile.h"
#include "TransferFile.h"
#include "Statistics.h"
#include "Buffer.h"

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


//////////////////////////////////////////////////////////////////////
// CUploadTransferBT construction

CUploadTransferBT::CUploadTransferBT(CBTClient* pClient, CDownload* pDownload) : CUploadTransfer( PROTOCOL_BT )
{
	ASSERT( pClient != NULL );
	ASSERT( pDownload != NULL );
	
	m_pDownload			= pDownload;
	m_pClient			= pClient;
	m_pHost				= pClient->m_pHost;
	m_sAddress			= pClient->m_sAddress;
	m_sUserAgent		= _T("BitTorrent");
	
	m_nState			= upsReady;
	m_bInterested		= FALSE;
	m_bChoked			= TRUE;
	m_nRandomUnchoke	= 0;
	
	m_pRequested		= NULL;
	m_pServed			= NULL;
	
	RequestPartial( m_pDownload );
	m_pDownload->AddUpload( this );
}

CUploadTransferBT::~CUploadTransferBT()
{
	ASSERT( m_pClient == NULL );
	ASSERT( m_pDownload == NULL );
	ASSERT( m_pRequested == NULL );
	ASSERT( m_pServed == NULL );
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT choking

void CUploadTransferBT::SetChoke(BOOL bChoke)
{
	if ( m_bChoked == bChoke ) return;
	m_bChoked = bChoke;
	
	m_pRequested->DeleteChain();
	m_pRequested = NULL;
	m_pServed->DeleteChain();
	m_pServed = NULL;
	
	if ( bChoke ) m_nState = upsReady;
	
	m_pClient->Send( CBTPacket::New( bChoke ? BT_PACKET_CHOKE : BT_PACKET_UNCHOKE ) );
	
	theApp.Message( MSG_DEBUG, _T("%s upload to %s"),
		bChoke ? _T("Choking") : _T("Unchoking"), (LPCTSTR)m_sAddress );
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT close

void CUploadTransferBT::Close(BOOL bMessage)
{
	if ( m_pClient != NULL )
	{
		m_pClient->m_pUpload = NULL;
		m_pClient->Close();
		m_pClient = NULL;
	}
	
	if ( m_pDiskFile != NULL ) CloseFile();
	
	if ( m_pDownload != NULL ) m_pDownload->RemoveUpload( this );
	m_pDownload = NULL;
	
	m_pRequested->DeleteChain();
	m_pRequested = NULL;
	m_pServed->DeleteChain();
	m_pServed = NULL;
	
	CUploadTransfer::Close( bMessage );
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT bandwidth

DWORD CUploadTransferBT::GetMeasuredSpeed()
{
	if ( m_pClient == NULL ) return 0;
	m_pClient->Measure();
	return m_pClient->m_mOutput.nMeasure;
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT connection event

BOOL CUploadTransferBT::OnConnected()
{
	m_pClient->m_mOutput.pLimit = &Uploads.m_nTorrentSpeed;
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT run event

BOOL CUploadTransferBT::OnRun()
{
	if ( m_nState >= upsRequest && ! m_bChoked ) return ServeRequests();
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT interest flag

BOOL CUploadTransferBT::OnInterested(CBTPacket* pPacket)
{
	if ( m_bInterested ) return TRUE;
	m_bInterested = TRUE;
	return TRUE;
}

BOOL CUploadTransferBT::OnUninterested(CBTPacket* pPacket)
{
	if ( ! m_bInterested ) return TRUE;
	m_bInterested = FALSE;
	m_nState = upsReady;
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT request management

BOOL CUploadTransferBT::OnRequest(CBTPacket* pPacket)
{
	if ( pPacket->GetRemaining() < 4 * 3 ) return TRUE;
	if ( m_bChoked ) return TRUE;
	
	QWORD nIndex	= pPacket->ReadLongBE();
	QWORD nOffset	= pPacket->ReadLongBE();
	QWORD nLength	= pPacket->ReadLongBE();
	
	nOffset += nIndex * m_pDownload->m_pTorrent.m_nBlockSize;
	
	if ( nLength > Settings.BitTorrent.RequestLimit )
	{
		// error
		theApp.Message( MSG_DEBUG, _T("CUploadTransferBT::OnRequest(): Request size %I64i is too large"), nLength );
		Close();
		return FALSE;
	}
	
	if ( nOffset + nLength > m_nFileSize )
	{
		// error
		theApp.Message( MSG_DEBUG, _T("CUploadTransferBT::OnRequest(): Request through %I64i > %I64i"), nLength, m_nFileSize );
		Close();
		return FALSE;
	}
	
	for ( CFileFragment* pFragment = m_pRequested ; pFragment ; pFragment = pFragment->m_pNext )
	{
		if ( pFragment->m_nOffset == nOffset && pFragment->m_nLength == nLength ) return TRUE;
	}
	
	CFileFragment* pNew = CFileFragment::New( NULL, m_pRequested, nOffset, nLength );
	if ( m_pRequested != NULL ) m_pRequested->m_pPrevious = pNew;
	m_pRequested = pNew;
	
	if ( m_nState == upsReady )
	{
		m_nState = upsRequest;
		AllocateBaseFile();
		theApp.Message( MSG_SYSTEM, IDS_UPLOAD_FILE,
			(LPCTSTR)m_sFileName, (LPCTSTR)m_sAddress );
	}
	
	return ServeRequests();
}

BOOL CUploadTransferBT::OnCancel(CBTPacket* pPacket)
{
	if ( pPacket->GetRemaining() < 4 * 3 ) return TRUE;
	
	QWORD nIndex	= pPacket->ReadLongBE();
	QWORD nOffset	= pPacket->ReadLongBE();
	QWORD nLength	= pPacket->ReadLongBE();
	
	nOffset += nIndex * m_pDownload->m_pTorrent.m_nBlockSize;
	
	CFileFragment::Subtract( &m_pRequested, nOffset, nLength );
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT file access

BOOL CUploadTransferBT::OpenFile()
{
	ASSERT( m_nState == upsRequest || m_nState == upsUploading );
	ASSERT( m_pBaseFile != NULL );
	
	if ( m_pDiskFile != NULL ) return TRUE;
	m_pDiskFile = TransferFiles.Open( m_sFilePath, FALSE, FALSE );
	if ( m_pDiskFile != NULL ) return TRUE;
	
	theApp.Message( MSG_ERROR, IDS_UPLOAD_CANTOPEN, (LPCTSTR)m_sAddress, (LPCTSTR)m_sFileName );
	
	Close();
	return FALSE;
}

//////////////////////////////////////////////////////////////////////
// CUploadTransferBT serving

BOOL CUploadTransferBT::ServeRequests()
{
	ASSERT( m_nState == upsRequest || m_nState == upsUploading );
	ASSERT( m_pBaseFile != NULL );
	ASSERT( m_nLength == SIZE_UNKNOWN );
	
	if ( m_bChoked ) return TRUE;
	if ( m_pClient->m_pOutput->m_nLength > Settings.BitTorrent.RequestSize / 3 ) return TRUE;
	
	while ( m_pRequested != NULL && m_nLength == SIZE_UNKNOWN )
	{
		CFileFragment* pFragment = m_pRequested;
		m_pRequested = pFragment->m_pNext;
		if ( m_pRequested != NULL ) m_pRequested->m_pPrevious = NULL;
		
		for ( CFileFragment* pOld = m_pServed ; pOld ; pOld = pOld->m_pNext )
		{
			if ( pOld->m_nOffset == pFragment->m_nOffset && pOld->m_nLength == pFragment->m_nLength ) break;
		}
		
		if ( pOld == NULL &&
			 pFragment->m_nOffset < m_nFileSize &&
			 pFragment->m_nOffset + pFragment->m_nLength <= m_nFileSize )
		{
			m_nOffset	= pFragment->m_nOffset;
			m_nLength	= pFragment->m_nLength;
			m_nPosition	= 0;
		}
		
		pFragment->DeleteThis();
	}
	
	if ( m_nLength < SIZE_UNKNOWN )
	{
		if ( ! OpenFile() ) return FALSE;
		
		theApp.Message( MSG_DEBUG, IDS_UPLOAD_CONTENT,
			m_nOffset, m_nOffset + m_nLength - 1,
			(LPCTSTR)m_sFileName, (LPCTSTR)m_sAddress, _T("BT") );
		
		CBuffer* pBuffer = m_pClient->m_pOutput;
		pBuffer->EnsureBuffer( sizeof(BT_PIECE_HEADER) + (DWORD)m_nLength );
		
		BT_PIECE_HEADER* pHeader = (BT_PIECE_HEADER*)( pBuffer->m_pBuffer + pBuffer->m_nLength );
		
		if ( ! m_pDiskFile->Read( m_nOffset + m_nPosition, &pHeader[1], m_nLength, &m_nLength ) ) return FALSE;

		pHeader->nLength	= SWAP_LONG( 1 + 8 + (DWORD)m_nLength );
		pHeader->nType		= BT_PACKET_PIECE;
		pHeader->nPiece		= (DWORD)( m_nOffset / m_pDownload->m_pTorrent.m_nBlockSize );
		pHeader->nOffset	= (DWORD)( m_nOffset % m_pDownload->m_pTorrent.m_nBlockSize );
		pHeader->nPiece		= SWAP_LONG( pHeader->nPiece );
		pHeader->nOffset	= SWAP_LONG( pHeader->nOffset );
		
		pBuffer->m_nLength += sizeof(BT_PIECE_HEADER) + (DWORD)m_nLength;
		m_pClient->Send( NULL );
		
		m_nPosition += m_nLength;
		m_nUploaded += m_nLength;
		m_pDownload->m_nTorrentUploaded += m_nLength;
		Statistics.Current.Uploads.Volume += ( m_nLength / 1024 );
		
		m_pServed = CFileFragment::New( NULL, m_pServed, m_nOffset, m_nLength );
		m_pBaseFile->AddFragment( m_nOffset, m_nLength );
		
		m_nState	= upsUploading;
		m_nLength	= SIZE_UNKNOWN;
	}
	else
	{
		m_nState = upsRequest;
	}
	
	return TRUE;
}

⌨️ 快捷键说明

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