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; }
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; }