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

📄 downloadtransferbt.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	SetState( dtsTorrent );
	theApp.Message( MSG_DEBUG, _T("Download from %s was choked."), (LPCTSTR)m_sAddress );
	
	for ( CFileFragment* pFragment = m_pRequested ; pFragment != NULL ; pFragment = pFragment->m_pNext )
	{
		CBTPacket* pPacket = CBTPacket::New( BT_PACKET_CANCEL );
		pPacket->WriteLongBE( (DWORD)( pFragment->m_nOffset / m_pDownload->m_pTorrent.m_nBlockSize ) );
		pPacket->WriteLongBE( (DWORD)( pFragment->m_nOffset % m_pDownload->m_pTorrent.m_nBlockSize ) );
		pPacket->WriteLongBE( (DWORD)pFragment->m_nLength );
		Send( pPacket );
	}
	
	m_pRequested->DeleteChain();
	m_pRequested = NULL;
	m_nRequested = 0;
	
	return TRUE;
}

BOOL CDownloadTransferBT::OnUnchoked(CBTPacket* pPacket)
{
	m_bChoked = FALSE;
	SetState( dtsTorrent );
	
	m_pRequested->DeleteChain();
	m_pRequested = NULL;
	m_nRequested = 0;
	
	theApp.Message( MSG_DEBUG, _T("Download from %s was UNchoked."), (LPCTSTR)m_sAddress );
	
	return SendRequests();
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT request pipe

BOOL CDownloadTransferBT::SendRequests()
{
	ASSERT( m_nState == dtsTorrent || m_nState == dtsRequesting || m_nState == dtsDownloading );
	
	if ( m_bChoked || ! m_bInterested )
	{
		if ( m_nRequested == 0 ) SetState( dtsTorrent );
		return TRUE;
	}
	
	if ( m_nRequested >= (int)Settings.BitTorrent.RequestPipe )
	{
		if ( m_nState != dtsDownloading ) SetState( dtsRequesting );
		return TRUE;
	}
	
	QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize;
	ASSERT( nBlockSize != 0 );
	if ( nBlockSize == 0 ) return TRUE;
	
	CFileFragment* pPossible = m_pDownload->GetFirstEmptyFragment()->CreateCopy();
	
	if ( ! m_pDownload->m_bTorrentEndgame )
	{
		for ( CDownloadTransfer* pTransfer = m_pDownload->GetFirstTransfer() ; pTransfer && pPossible ; pTransfer = pTransfer->m_pDlNext )
		{
			pTransfer->SubtractRequested( &pPossible );
		}
	}
	
	while ( m_nRequested < (int)Settings.BitTorrent.RequestPipe )
	{
		QWORD nOffset, nLength;
		
		if ( SelectFragment( pPossible, &nOffset, &nLength ) )
		{
			ChunkifyRequest( &nOffset, &nLength, Settings.BitTorrent.RequestSize, FALSE );
			
			CFileFragment::Subtract( &pPossible, nOffset, nLength );
			
			CFileFragment* pRequest = CFileFragment::New( NULL, m_pRequested, nOffset, nLength );
			if ( m_pRequested != NULL ) m_pRequested->m_pPrevious = pRequest;
			m_pRequested = pRequest;
			m_nRequested ++;
			
			int nType	= ( m_nDownloaded == 0 || ( nOffset % nBlockSize ) == 0 )
						? MSG_DEFAULT : MSG_DEBUG;
			
			theApp.Message( nType, IDS_DOWNLOAD_FRAGMENT_REQUEST,
				nOffset, nOffset + nLength - 1,
				(LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
			
#ifdef _DEBUG
			DWORD ndBlock1 = (DWORD)( nOffset / nBlockSize );
			DWORD ndBlock2 = (DWORD)( ( nOffset + nLength - 1 ) / nBlockSize );
			ASSERT( ndBlock1 < m_pDownload->m_pTorrent.m_nBlockCount );
			ASSERT( ndBlock1 == ndBlock2 );
			ASSERT( nLength <= nBlockSize );
#endif
			
			CBTPacket* pPacket = CBTPacket::New( BT_PACKET_REQUEST );
			pPacket->WriteLongBE( (DWORD)( nOffset / nBlockSize ) );
			pPacket->WriteLongBE( (DWORD)( nOffset % nBlockSize ) );
			pPacket->WriteLongBE( (DWORD)nLength );
			Send( pPacket );
		}
		else
		{
			break;
		}
	}
	
	if ( pPossible == NULL && m_pDownload->m_bTorrentEndgame == FALSE )
	{
		m_pDownload->m_bTorrentEndgame = Settings.BitTorrent.Endgame;
	}
	
	pPossible->DeleteChain();
	
	if ( m_nRequested > 0 && m_nState != dtsDownloading ) SetState( dtsRequesting );
	if ( m_nRequested == 0 ) SetState( dtsTorrent );
	
	return TRUE;
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT fragment selection

BOOL CDownloadTransferBT::SelectFragment(CFileFragment* pPossible, QWORD* pnOffset, QWORD* pnLength)
{
	ASSERT( pnOffset != NULL && pnLength != NULL );
	
	if ( pPossible == NULL ) return FALSE;
	
	QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize;
	CFileFragment* pComplete = NULL;
	DWORD nBlock;
	
	ASSERT( nBlockSize != 0 );
	
	for ( ; pPossible ; pPossible = pPossible->m_pNext )
	{
		if ( pPossible->m_nOffset % nBlockSize )
		{
			// the start of a block is complete, but part is missing
			
			nBlock = (DWORD)( pPossible->m_nOffset / nBlockSize );
			ASSERT( nBlock < m_pDownload->m_pTorrent.m_nBlockCount );
			
			if ( m_pAvailable == NULL || m_pAvailable[ nBlock ] )
			{
				*pnOffset = pPossible->m_nOffset;
				*pnLength = nBlockSize * (QWORD)nBlock + nBlockSize - *pnOffset;
				*pnLength = min( *pnLength, pPossible->m_nLength );
				ASSERT( *pnLength <= nBlockSize );
				
				pComplete->DeleteChain();
				return TRUE;
			}
		}
		else if (	( pPossible->m_nLength % nBlockSize ) &&
					( pPossible->m_nOffset + pPossible->m_nLength < m_pDownload->m_nSize ) )
		{
			// the end of a block is complete, but part is missing
			
			nBlock = (DWORD)( ( pPossible->m_nOffset + pPossible->m_nLength ) / nBlockSize );
			ASSERT( nBlock < m_pDownload->m_pTorrent.m_nBlockCount );
			
			if ( m_pAvailable == NULL || m_pAvailable[ nBlock ] )
			{
				*pnOffset = nBlockSize * (QWORD)nBlock;
				*pnLength = pPossible->m_nOffset + pPossible->m_nLength - *pnOffset;
				ASSERT( *pnLength <= nBlockSize );
				
				pComplete->DeleteChain();
				return TRUE;
			}
		}
		else
		{
			// this fragment contains one or more aligned empty blocks
			
			nBlock = (DWORD)( pPossible->m_nOffset / nBlockSize );
			*pnLength = pPossible->m_nLength;
			ASSERT( *pnLength != 0 );
			
			for ( ; ; nBlock ++, *pnLength -= nBlockSize )
			{
				ASSERT( nBlock < m_pDownload->m_pTorrent.m_nBlockCount );
				
				if ( m_pAvailable == NULL || m_pAvailable[ nBlock ] )
				{
					pComplete = CFileFragment::New( NULL, pComplete, (QWORD)nBlock, 0 );
				}
				
				if ( *pnLength <= nBlockSize ) break;
			}
		}
	}
	
	if ( CFileFragment* pRandom = pComplete->GetRandom() )
	{
		*pnOffset = pRandom->m_nOffset * nBlockSize;
		*pnLength = nBlockSize;
		*pnLength = min( *pnLength, m_pDownload->m_nSize - *pnOffset );
		ASSERT( *pnLength <= nBlockSize );
		
		pComplete->DeleteChain();
		return TRUE;
	}
	else
	{
		ASSERT( pComplete == NULL );
		return FALSE;
	}
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT multi-source fragment handling

BOOL CDownloadTransferBT::SubtractRequested(CFileFragment** ppFragments)
{
	if ( m_nRequested == 0 || m_bChoked ) return FALSE;
	CFileFragment::Subtract( ppFragments, m_pRequested );
	return TRUE;
}

BOOL CDownloadTransferBT::UnrequestRange(QWORD nOffset, QWORD nLength)
{
	if ( m_nRequested == 0 ) return FALSE;
	
	ASSERT( m_pDownload->m_pTorrent.m_nBlockSize != 0 );
	if ( m_pDownload->m_pTorrent.m_nBlockSize == 0 ) return FALSE;
	
	CFileFragment** ppPrevious = &m_pRequested;
	BOOL bMatch = FALSE;
	
	for ( CFileFragment* pFragment = *ppPrevious ; pFragment ; )
	{
		CFileFragment* pNext = pFragment->m_pNext;
		
		if ( nOffset < pFragment->m_nOffset + pFragment->m_nLength &&
			 nOffset + nLength > pFragment->m_nOffset )
		{
			CBTPacket* pPacket = CBTPacket::New( BT_PACKET_CANCEL );
			pPacket->WriteLongBE( (DWORD)( pFragment->m_nOffset / m_pDownload->m_pTorrent.m_nBlockSize ) );
			pPacket->WriteLongBE( (DWORD)( pFragment->m_nOffset % m_pDownload->m_pTorrent.m_nBlockSize ) );
			pPacket->WriteLongBE( (DWORD)pFragment->m_nLength );
			Send( pPacket );
			
			*ppPrevious = pNext;
			if ( pNext ) pNext->m_pPrevious = pFragment->m_pPrevious;
			pFragment->DeleteThis();
			m_nRequested --;
			bMatch = TRUE;
		}
		else
		{
			ppPrevious = &pFragment->m_pNext;
		}
		
		pFragment = pNext;
	}
	
	return bMatch;
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT piece reception

BOOL CDownloadTransferBT::OnPiece(CBTPacket* pPacket)
{
	ASSERT( m_pClient != NULL );
	
	if ( pPacket->GetRemaining() < 8 ) return TRUE;
	if ( m_nState != dtsRequesting && m_nState != dtsDownloading ) return TRUE;
	SetState( dtsDownloading );
	
	DWORD nBlock	= pPacket->ReadLongBE();
	QWORD nOffset	= pPacket->ReadLongBE();
	QWORD nLength	= pPacket->GetRemaining();
	
	nOffset += (QWORD)nBlock * m_pDownload->m_pTorrent.m_nBlockSize;
	
	m_nDownloaded += nLength;
	m_pDownload->m_nTorrentDownloaded += nLength;
	
	m_pSource->AddFragment( nOffset, nLength );
	m_pSource->SetValid();
	
	CFileFragment::Subtract( &m_pRequested, nOffset, nLength );
	m_nRequested = m_pRequested->GetCount();
	
	m_pDownload->SubmitData( nOffset,
		pPacket->m_pBuffer + pPacket->m_nPosition, nLength );
	
	// TODO: SendRequests and ShowInterest could be combined.. SendRequests
	// is probably going to tell us if we are interested or not
	
	ShowInterest();
	return SendRequests();
}

//////////////////////////////////////////////////////////////////////
// CDownloadTransferBT source exchange

BOOL CDownloadTransferBT::OnSourceResponse(CBTPacket* pPacket)
{
	CBuffer pInput;
	pInput.Add( pPacket->m_pBuffer, pPacket->GetRemaining() );
	
	CBENode* pRoot = CBENode::Decode( &pInput );
	if ( pRoot == NULL ) return TRUE;
	
	CBENode* pPeers = pRoot->GetNode( "peers" );
	
	if ( ! pPeers->IsType( CBENode::beList ) )
	{
		delete pRoot;
		return TRUE;
	}
	
	int nCount = 0;
	
	for ( int nPeer = 0 ; nPeer < pPeers->GetCount() ; nPeer++ )
	{
		CBENode* pPeer = pPeers->GetNode( nPeer );
		if ( ! pPeer->IsType( CBENode::beDict ) ) continue;
		
		CBENode* pURL = pPeer->GetNode( "url" );
		
		if ( pURL->IsType( CBENode::beString ) )
		{
			nCount += m_pDownload->AddSourceURL( pURL->GetString(), TRUE );
		}
		else
		{
			CBENode* pID = pPeer->GetNode( "peer id" );
			if ( ! pID->IsType( CBENode::beString ) || pID->m_nValue != sizeof(SHA1) ) continue;
			
			CBENode* pIP = pPeer->GetNode( "ip" );
			if ( ! pIP->IsType( CBENode::beString ) ) continue;
			
			CBENode* pPort = pPeer->GetNode( "port" );
			if ( ! pPort->IsType( CBENode::beInt ) ) continue;
			
			SOCKADDR_IN saPeer;
			if ( ! Network.Resolve( pIP->GetString(), (int)pPort->GetInt(), &saPeer ) ) continue;
			
			theApp.Message( MSG_DEBUG, _T("CDownloadTransferBT::OnSourceResponse(): %s: %s:%i"),
				(LPCTSTR)m_sAddress,
				(LPCTSTR)CString( inet_ntoa( saPeer.sin_addr ) ), htons( saPeer.sin_port ) );
			
			nCount += m_pDownload->AddSourceBT( (SHA1*)pID->m_pValue,
				&saPeer.sin_addr, htons( saPeer.sin_port ) );
		}
	}
	
	delete pRoot;
	
	theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_EXCHANGE, nCount, (LPCTSTR)m_sAddress );
	
	return TRUE;
}

⌨️ 快捷键说明

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