bool CDownloadTransferED2K::SendFragmentRequests()
{
	ASSUME_LOCK( Transfers.m_pSection );

	ASSERT( m_pClient != NULL );

	if ( m_nState != dtsDownloading ) return TRUE;

	if ( m_oRequested.size() >= (int)Settings.eDonkey.RequestPipe ) return TRUE;

	Fragments::List oPossible( m_pDownload->GetEmptyFragmentList() );

	if ( ! m_pClient->m_bEmLargeFile && ( m_pDownload->m_nSize & 0xffffffff00000000 ) )
	{
		Fragments::Fragment Selected( 0x100000000, m_pDownload->m_nSize - 1 );
		oPossible.erase( Selected );
	}

	if ( ! m_pDownload->m_bTorrentEndgame )
	{
		for ( CDownloadTransfer* pTransfer = m_pDownload->GetFirstTransfer() ;
			pTransfer && ! oPossible.empty() ; pTransfer = pTransfer->m_pDlNext )
		{
			pTransfer->SubtractRequested( oPossible );
		}
	}

	typedef std::map< QWORD, Fragments::Fragment > _TRequest;
	typedef _TRequest::iterator _TRequestIndex;
	_TRequest oRequesting;
	while ( m_oRequested.size() < (int)Settings.eDonkey.RequestPipe )
	{
		QWORD nOffset, nLength;

		if ( SelectFragment( oPossible, nOffset, nLength, m_pDownload->m_bTorrentEndgame ) )
		{
			ChunkifyRequest( &nOffset, &nLength, Settings.eDonkey.RequestSize, FALSE );

			Fragments::Fragment Selected( nOffset, nOffset + nLength );
			oPossible.erase( Selected );

			m_oRequested.push_back( Selected );

			oRequesting.insert( _TRequest::value_type(nOffset, Selected) );
		}
		else
		{
			break;
		}
	}

	while ( ! oRequesting.empty() )
	{
		DWORD nCount = 0;
		QWORD nOffsetBegin[3] = {0,0,0}, nOffsetEnd[3] = {0,0,0};
		bool  bI64Offset = false;

		while ( nCount < 3 && ! oRequesting.empty() )
		{
			_TRequestIndex iIndex = oRequesting.begin();
			nOffsetBegin[nCount] = QWORD((*iIndex).second.begin());
			nOffsetEnd[nCount] = QWORD((*iIndex).second.end());
			bI64Offset |= ( ( ( nOffsetBegin[nCount] & 0xffffffff00000000 ) ) ||
							( ( nOffsetEnd[nCount] & 0xffffffff00000000 ) ) );
			oRequesting.erase(iIndex);
			nCount++;
		}

		if ( bI64Offset )
		{
			CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_REQUESTPARTS, ED2K_PROTOCOL_EMULE );
			pPacket->Write( m_pDownload->m_oED2K );

			// This commented-out code is for BigEndian, only needed when ported to different platform.
			//pPacket->WriteLongLE( (DWORD)( nOffsetBegin[0] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( ( nOffsetBegin[0] & 0xffffffff00000000 ) >> 32 ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetBegin[1] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( ( nOffsetBegin[1] & 0xffffffff00000000 ) >> 32 ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetBegin[2] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( ( nOffsetBegin[2] & 0xffffffff00000000 ) >> 32 ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetEnd[0] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( ( nOffsetEnd[0] & 0xffffffff00000000 ) >> 32 ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetEnd[1] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( ( nOffsetEnd[1] & 0xffffffff00000000 ) >> 32 ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetEnd[2] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( ( nOffsetEnd[2] & 0xffffffff00000000 ) >> 32 ) );

			// If little Endian, no need to use above code
			pPacket->Write( &nOffsetBegin[0], 8 );
			pPacket->Write( &nOffsetBegin[1], 8 );
			pPacket->Write( &nOffsetBegin[2], 8 );
			pPacket->Write( &nOffsetEnd[0], 8 );
			pPacket->Write( &nOffsetEnd[1], 8 );
			pPacket->Write( &nOffsetEnd[2], 8 );
			Send( pPacket );
		}
		else
		{
			CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_REQUESTPARTS );
			pPacket->Write( m_pDownload->m_oED2K );

			// This commented-out code is for BigEndian, only needed when ported to different platform.
			//pPacket->WriteLongLE( (DWORD)( nOffsetBegin[0] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetBegin[1] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetBegin[2] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetEnd[0] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetEnd[1] & 0x00000000ffffffff ) );
			//pPacket->WriteLongLE( (DWORD)( nOffsetEnd[2] & 0x00000000ffffffff ) );

			pPacket->Write( &nOffsetBegin[0], 4 );
			pPacket->Write( &nOffsetBegin[1], 4 );
			pPacket->Write( &nOffsetBegin[2], 4 );
			pPacket->Write( &nOffsetEnd[0], 4 );
			pPacket->Write( &nOffsetEnd[1], 4 );
			pPacket->Write( &nOffsetEnd[2], 4 );
			Send( pPacket );
		}

		while ( nCount-- )
		{
			int nType = ( m_nDownloaded == 0 || ( nOffsetBegin[nCount] % ED2K_PART_SIZE ) == 0 )
				? MSG_INFO : MSG_DEBUG;

			theApp.Message( (WORD)nType, IDS_DOWNLOAD_FRAGMENT_REQUEST,
				nOffsetBegin[nCount], nOffsetEnd[nCount], (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
		}
	}

	// If there are no more possible chunks to request, and endgame is available but not active
	if ( oPossible.empty() && Settings.eDonkey.Endgame && ! m_pDownload->m_bTorrentEndgame )
	{
		// And the file is at least 100MB, with less than 1MB to go
		if ( ( m_pDownload->GetVolumeComplete() > 100*1024*1024 ) &&
			 ( m_pDownload->GetVolumeRemaining() <  1*1024*1024 ) )
		{
			// Then activate endgame
			m_pDownload->m_bTorrentEndgame = true;
			theApp.Message( MSG_DEBUG, _T("Activating endgame for ed2k transfer %s"), m_pDownload->m_sName );
		}
	}

	if ( ! m_oRequested.empty() )
		return true;

	Send( CEDPacket::New( ED2K_C2C_QUEUERELEASE ) );

	theApp.Message( MSG_INFO, IDS_DOWNLOAD_FRAGMENT_END, (LPCTSTR)m_sAddress );
	Close( TRI_TRUE );

	return false;
}
Ejemplo n.º 2
0
bool CDownloadTransferBT::SendFragmentRequests()
{
	ASSUME_LOCK( Transfers.m_pSection );

	ASSERT( m_nState == dtsTorrent || m_nState == dtsRequesting || m_nState == dtsDownloading );
	if ( m_bChoked || ! m_bInterested )
	{
		if ( m_oRequested.empty() )
			SetState( dtsTorrent );

		return true;
	}

	if ( m_oRequested.size() >= (int)Settings.BitTorrent.RequestPipe )
	{
		if ( m_nState != dtsDownloading ) 
		{
			theApp.Message( MSG_DEBUG, L"Too many requests per host, staying in the requested state" );
			SetState( dtsRequesting );
		}

		return true;
	}

	QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize;
	ASSERT( nBlockSize != 0 );
	if ( !nBlockSize )
		return true;

	Fragments::List oPossible( m_pDownload->GetWantedFragmentList() );

	if ( ! m_pDownload->m_bTorrentEndgame )
	{
		for ( const CDownloadTransfer* pTransfer = m_pDownload->GetFirstTransfer() ; pTransfer && !oPossible.empty() ; pTransfer = pTransfer->m_pDlNext )
		{
			pTransfer->SubtractRequested( oPossible );
		}
	}

	while ( m_oRequested.size() < (int)Settings.BitTorrent.RequestPipe )
	{
		QWORD nOffset, nLength;
		if ( SelectFragment( oPossible, nOffset, nLength, m_pDownload->m_bTorrentEndgame ) )
		{
			ChunkifyRequest( &nOffset, &nLength, Settings.BitTorrent.RequestSize, FALSE );

			Fragments::Fragment Selected( nOffset, nOffset + nLength );
			oPossible.erase( Selected );

			m_oRequested.push_back( Selected );

			if ( m_nDownloaded == 0 || ( nOffset % nBlockSize ) == 0 )
				theApp.Message( MSG_INFO, IDS_DOWNLOAD_FRAGMENT_REQUEST,
					nOffset, nOffset + nLength - 1,
					(LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );

			m_pClient->Request(
				(DWORD)( nOffset / nBlockSize ),
				(DWORD)( nOffset % nBlockSize ),
				(DWORD)( nLength ) );
		}
		else
		{
			break;
		}
	}

	// If there are no more possible chunks to request, and endgame is available but not active
	if ( oPossible.empty() && Settings.BitTorrent.Endgame && ! m_pDownload->m_bTorrentEndgame )
	{
		// And the torrent is at least 95% complete
		if ( m_pDownload->GetProgress() > 95.0f )
		{
			// Then activate endgame
			m_pDownload->m_bTorrentEndgame = true;
			theApp.Message( MSG_DEBUG, _T("Torrent EndGame mode activated for %s"), m_pDownload->m_sName );
		}
	}

	if ( !m_oRequested.empty() && m_nState != dtsDownloading )
	{
		theApp.Message( MSG_DEBUG, L"Request for piece sent, switching to the requested state" );
		SetState( dtsRequesting );
	}

	if ( m_oRequested.empty() ) 
		SetState( dtsTorrent );

	return true;
}