void CUploadTransferED2K::Close(BOOL bMessage) { if ( m_nState == upsNull ) { if ( m_pClient != NULL ) m_pClient->OnUploadClose(); m_pClient = NULL; return; } if ( m_pBaseFile != NULL && m_pClient->IsOnline() ) { if ( m_nState == upsUploading || m_nState == upsQueued ) { Send( CEDPacket::New( ED2K_C2C_FINISHUPLOAD ) ); } CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_FILENOTFOUND ); pPacket->Write( &m_pED2K, sizeof(MD4) ); Send( pPacket ); } Cleanup(); ASSERT( m_pClient != NULL ); m_pClient->OnUploadClose(); m_pClient = NULL; CUploadTransfer::Close( bMessage ); }
BOOL CUploadTransferED2K::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 ) { CQuickLock oLock( Library.m_pSection ); if ( CLibraryFile* pFile = LibraryMaps.LookupFileByPath( m_sFilePath, TRUE, TRUE ) ) { pFile->m_nUploadsToday++; pFile->m_nUploadsTotal++; } return TRUE; } theApp.Message( MSG_ERROR, IDS_UPLOAD_CANTOPEN, (LPCTSTR)m_sFileName, (LPCTSTR)m_sAddress ); CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILENOTFOUND ); pReply->Write( &m_pED2K, sizeof(MD4) ); Send( pReply ); Cleanup(); Close(); return FALSE; }
BOOL CUploadTransferED2K::Request(MD4* pMD4) { BOOL bSame = ( m_bED2K && m_pED2K == *pMD4 ); Cleanup( ! bSame ); CSingleLock oLock( &Library.m_pSection, TRUE ); if ( CLibraryFile* pFile = LibraryMaps.LookupFileByED2K( pMD4, TRUE, TRUE ) ) { // Send comments if necessary if ( m_pClient ) m_pClient->SendCommentsPacket( pFile->m_nRating, pFile->m_sComments ); RequestComplete( pFile ); oLock.Unlock(); } else { oLock.Unlock(); if ( CDownload* pFile = Downloads.FindByED2K( pMD4, TRUE ) ) { RequestPartial( pFile ); } else { UploadQueues.Dequeue( this ); theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress, (LPCTSTR)CED2K::HashToString( pMD4, TRUE ) ); CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILENOTFOUND ); pReply->Write( pMD4, sizeof(MD4) ); Send( pReply ); Close(); return FALSE; } } if ( UploadQueues.GetPosition( this, FALSE ) < 0 && ! UploadQueues.Enqueue( this ) ) { theApp.Message( MSG_ERROR, IDS_UPLOAD_BUSY_QUEUE, (LPCTSTR)m_sFileName, (LPCTSTR)m_sAddress, _T("ED2K") ); CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILENOTFOUND ); pReply->Write( pMD4, sizeof(MD4) ); Send( pReply ); Close(); return FALSE; } AllocateBaseFile(); theApp.Message( MSG_SYSTEM, IDS_UPLOAD_FILE, (LPCTSTR)m_sFileName, (LPCTSTR)m_sAddress ); m_nRanking = -1; return CheckRanking(); }
BOOL CDownloadTransferED2K::SendPrimaryRequest() { ASSERT( m_pClient != NULL ); const DWORD tNow = GetTickCount(); //if ( m_pDownload->GetVolumeRemaining() == 0 ) //{ // theApp.Message( MSG_INFO, IDS_DOWNLOAD_FRAGMENT_END, (LPCTSTR)m_sAddress ); // Close( TRI_TRUE ); // return FALSE; //} // This source is current requesting SetState( dtsRequesting ); // Set the 'last requested' time m_tRequest = tNow; ClearRequests(); // Send ed2k file request CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_FILEREQUEST ); pPacket->Write( m_pDownload->m_oED2K ); if ( Settings.eDonkey.ExtendedRequest >= 1 && m_pClient->m_bEmRequest >= 1 ) m_pClient->WritePartStatus( pPacket, m_pDownload ); // It's not very accurate if ( Settings.eDonkey.ExtendedRequest >= 2 && m_pClient->m_bEmRequest >= 2 ) pPacket->WriteShortLE( (WORD)m_pDownload->GetED2KCompleteSourceCount() ); Send( pPacket ); if ( m_pDownload->m_nSize <= ED2K_PART_SIZE ) { // Don't ask for status - if the client answers, we know the file is complete anyway } else { // Send ed2k status request pPacket = CEDPacket::New( ED2K_C2C_FILESTATUSREQUEST ); pPacket->Write( m_pDownload->m_oED2K ); Send( pPacket ); } if ( m_pDownload->GetSourceCount() < Settings.Downloads.SourcesWanted && // We want more sources tNow > m_tSources && tNow > m_tSources + 30 * 60 * 1000 && // We have not asked for at least 30 minutes m_pClient->m_bEmule && Network.IsListening() ) // Remote client is eMule compatible and we are accepting packets { // Set 'last asked for sources' time m_tSources = tNow; // Send ed2k request for sources packet pPacket = CEDPacket::New( ED2K_C2C_REQUESTSOURCES, ED2K_PROTOCOL_EMULE ); pPacket->Write( m_pDownload->m_oED2K ); Send( pPacket ); } return TRUE; }
// Send a server status request void CEDClients::RequestServerStatus(IN_ADDR* pHost, WORD nPort) { CEDPacket* pPacket = CEDPacket::New( ED2K_C2SG_SERVERSTATUSREQUEST, ED2K_PROTOCOL_EDONKEY ); m_nLastServerKey = 0x55AA0000 + GetRandomNum( 0ui16, _UI16_MAX ); pPacket->WriteLongLE( m_nLastServerKey ); Datagrams.Send( pHost, nPort + 4, pPacket ); }
// Send a server status request void CEDClients::RequestServerStatus(IN_ADDR* pHost, WORD nPort) { CEDPacket* pPacket = CEDPacket::New( ED2K_C2SG_SERVERSTATUSREQUEST, ED2K_PROTOCOL_EDONKEY ); srand( GetTickCount() ); m_nLastServerKey = 0x55AA0000 + rand(); pPacket->WriteLongLE( m_nLastServerKey ); Datagrams.Send( pHost, nPort + 4, pPacket ); }
CEDPacket* CEDPacket::ReadBuffer(CBuffer* pBuffer, BYTE nEdProtocol) { ED2K_TCP_HEADER* pHeader = reinterpret_cast<ED2K_TCP_HEADER*>(pBuffer->m_pBuffer); if ( pBuffer->m_nLength < sizeof(*pHeader) ) return NULL; if ( pHeader->nProtocol != ED2K_PROTOCOL_EDONKEY && pHeader->nProtocol != ED2K_PROTOCOL_EMULE && pHeader->nProtocol != ED2K_PROTOCOL_PACKED ) return NULL; if ( pBuffer->m_nLength < sizeof(*pHeader) + pHeader->nLength - 1 ) return NULL; CEDPacket* pPacket = CEDPacket::New( pHeader ); pBuffer->Remove( sizeof(*pHeader) + pHeader->nLength - 1 ); if ( pPacket->InflateOrRelease( nEdProtocol ) ) return NULL; return pPacket; }
BOOL CUploadTransferED2K::OnReask() { if ( m_nState != upsQueued ) return FALSE; int nPosition = UploadQueues.GetPosition( this, TRUE ); if ( nPosition < 0 ) return FALSE; CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_UDP_REASKACK, ED2K_PROTOCOL_EMULE ); pPacket->WriteShortLE( nPosition ); Datagrams.Send( &m_pClient->m_pHost.sin_addr, m_pClient->m_nUDP, pPacket ); m_tRequest = GetTickCount(); return TRUE; }
BOOL CDownloadTransferED2K::RunQueued(DWORD tNow) { ASSERT( m_pClient != NULL ); ASSERT( m_nState == dtsQueued ); if ( Settings.Downloads.QueueLimit > 0 && m_nQueuePos > Settings.Downloads.QueueLimit ) { theApp.Message( MSG_ERROR, IDS_DOWNLOAD_QUEUE_HUGE, (LPCTSTR)m_sAddress, (LPCTSTR)m_pDownload->GetDisplayName(), m_nQueuePos ); Close( TRI_FALSE ); return FALSE; } else if ( m_pClient->m_bConnected == FALSE && tNow > m_tRanking && tNow - m_tRanking > Settings.eDonkey.ReAskTime * 1000 + 20000 ) { theApp.Message( MSG_ERROR, IDS_DOWNLOAD_QUEUE_TIMEOUT, (LPCTSTR)m_sAddress, (LPCTSTR)m_pDownload->GetDisplayName() ); Close( TRI_UNKNOWN ); return FALSE; } else if ( !( CEDPacket::IsLowID( m_pSource->m_pAddress.S_un.S_addr ) || m_pSource->m_bPushOnly ) && /*!Network.IsFirewalled(CHECK_BOTH)*/!Network.IsFirewalled(CHECK_UDP) && m_pClient->m_nUDP > 0 && ! m_bUDP && tNow > m_tRequest && // Temp disable tNow - m_tRequest > Settings.eDonkey.ReAskTime * 1000 - 20000 ) { CEDPacket* pPing = CEDPacket::New( ED2K_C2C_UDP_REASKFILEPING, ED2K_PROTOCOL_EMULE ); pPing->Write( m_pDownload->m_oED2K ); Datagrams.Send( &m_pClient->m_pHost.sin_addr, m_pClient->m_nUDP, pPing ); m_bUDP = TRUE; //m_tRequest = GetTickCount(); } else if ( tNow > m_tRequest && tNow - m_tRequest > Settings.eDonkey.ReAskTime * 1000 ) { m_tRequest = GetTickCount(); if ( m_pClient->IsOnline() ) { return OnConnected(); } else { m_pClient->Connect(); } } return TRUE; }
BOOL CDownloadTransferED2K::SendSecondaryRequest() { ASSERT( m_pClient != NULL ); ASSERT( m_nState > dtsConnecting ); // ASSERT( m_nState == dtsRequesting || m_nState == dtsHashset ); if ( ! m_pDownload->PrepareFile() ) { Close( TRI_TRUE ); return FALSE; } if ( m_bHashset == FALSE && m_pDownload->NeedHashset() ) { CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_HASHSETREQUEST ); pPacket->Write( m_pDownload->m_oED2K ); Send( pPacket ); SetState( dtsHashset ); m_pClient->m_mInput.tLast = GetTickCount(); } else if ( m_pSource->HasUsefulRanges() ) { CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_QUEUEREQUEST ); pPacket->Write( m_pDownload->m_oED2K ); Send( pPacket ); SetState( dtsEnqueue ); m_tRequest = GetTickCount(); } else { m_pSource->m_tAttempt = GetTickCount() + Settings.eDonkey.ReAskTime * 500; m_pSource->SetAvailableRanges( NULL ); theApp.Message( MSG_INFO, IDS_DOWNLOAD_FRAGMENT_END, (LPCTSTR)m_sAddress ); Close( TRI_TRUE ); return FALSE; } ClearRequests(); return TRUE; }
BOOL CUploadTransferED2K::CheckRanking() { DWORD tNow = GetTickCount(); int nPosition = UploadQueues.GetPosition( this, TRUE ); if ( nPosition < 0 ) { // Invalid queue position, or queue deleted. Drop client and exit. Cleanup(); Close( TRUE ); return FALSE; } // Update 'ranking checked' timer m_tRankingCheck = tNow; // If queue ranking hasn't changed, don't bother sending an update // Note: if a rank was requested by the remote client, then m_nRanking will be set to -1. if ( m_nRanking == nPosition ) return TRUE; if ( nPosition == 0 ) { //Ready to start uploading if ( m_pClient->IsOnline() ) { if ( m_nState != upsUploading ) { m_nState = upsRequest; Send( CEDPacket::New( ED2K_C2C_STARTUPLOAD ) ); } } else { m_nState = upsConnecting; m_pClient->Connect(); } // Update the 'request sent' timer m_tRequest = m_tRankingCheck; // Update the 'ranking sent' variables m_nRanking = nPosition; m_tRankingSent = tNow; } else if ( m_pClient->IsOnline() ) { //Upload is queued // Check if we should send a ranking packet- If we have not sent one in a while, or one was requested if ( ( tNow > m_tRankingSent && tNow - m_tRankingSent >= Settings.eDonkey.QueueRankThrottle ) || ( m_nRanking == -1 ) ) { // Send a queue rank packet CSingleLock pLock( &UploadQueues.m_pSection, TRUE ); if ( UploadQueues.Check( m_pQueue ) ) { theApp.Message( MSG_DEFAULT, IDS_UPLOAD_QUEUED, (LPCTSTR)m_sFileName, (LPCTSTR)m_sAddress, nPosition, m_pQueue->GetQueuedCount(), (LPCTSTR)m_pQueue->m_sName ); } pLock.Unlock(); m_nState = upsQueued; if ( m_pClient->m_bEmule ) { //eMule queue ranking CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_QUEUERANKING, ED2K_PROTOCOL_EMULE ); pPacket->WriteShortLE( nPosition ); pPacket->WriteShortLE( 0 ); pPacket->WriteLongLE( 0 ); pPacket->WriteLongLE( 0 ); Send( pPacket ); } else { //older eDonkey style CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_QUEUERANK ); pPacket->WriteLongLE( nPosition ); Send( pPacket ); } // Update the 'ranking sent' variables m_nRanking = nPosition; m_tRankingSent = tNow; } } return TRUE; }
BOOL CUploadTransferED2K::DispatchNextChunk() { ASSERT( m_nState == upsUploading ); if ( !m_pDiskFile ) return FALSE; ASSERT( m_nLength < SIZE_UNKNOWN ); ASSERT( m_nPosition < m_nLength ); QWORD nChunk = m_nLength - m_nPosition; nChunk = min( nChunk, QWORD(Settings.eDonkey.FrameSize) ); #if 0 // Use packet form CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_SENDINGPART ); pPacket->Write( &m_pED2K, sizeof(MD4) ); pPacket->WriteLongLE( m_nOffset + m_nPosition ); pPacket->WriteLongLE( m_nOffset + m_nPosition + nChunk ); m_pDiskFile->Read( m_nFileBase + m_nOffset + m_nPosition, pPacket->GetWritePointer( nChunk ), nChunk, &nChunk ); // SetFilePointer( hFile, m_nFileBase + m_nOffset + m_nPosition, NULL, FILE_BEGIN ); // ReadFile( hFile, pPacket->WriteGetPointer( nChunk ), nChunk, &nChunk, NULL ); if ( nChunk == 0 ) { pPacket->Release(); return FALSE; } pPacket->m_nLength = sizeof(MD4) + 8 + nChunk; Send( pPacket ); #else // Raw write CBuffer* pBuffer = m_pClient->m_pOutput; pBuffer->EnsureBuffer( sizeof(ED2K_PART_HEADER) + (DWORD)nChunk ); ED2K_PART_HEADER* pHeader = (ED2K_PART_HEADER*)( pBuffer->m_pBuffer + pBuffer->m_nLength ); if ( ! m_pDiskFile->Read( m_nFileBase + m_nOffset + m_nPosition, &pHeader[1], nChunk, &nChunk ) ) return FALSE; // SetFilePointer( hFile, m_nFileBase + m_nOffset + m_nPosition, NULL, FILE_BEGIN ); // ReadFile( hFile, &pHeader[1], nChunk, &nChunk, NULL ); if ( nChunk == 0 ) return FALSE; pHeader->nProtocol = ED2K_PROTOCOL_EDONKEY; pHeader->nType = ED2K_C2C_SENDINGPART; pHeader->nLength = 1 + sizeof(MD4) + 8 + (DWORD)nChunk; pHeader->pMD4 = m_pED2K; pHeader->nOffset1 = (DWORD)( m_nOffset + m_nPosition ); pHeader->nOffset2 = (DWORD)( m_nOffset + m_nPosition + nChunk ); pBuffer->m_nLength += sizeof(ED2K_PART_HEADER) + (DWORD)nChunk; m_pClient->Send( NULL ); #endif m_nPosition += nChunk; m_nUploaded += nChunk; Statistics.Current.Uploads.Volume += ( nChunk / 1024 ); return TRUE; }
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 CDownloadTransferED2K::SendPrimaryRequest() { ASSERT( m_pClient != NULL ); DWORD tNow = GetTickCount(); /* if ( m_pDownload->GetVolumeRemaining() == 0 ) { theApp.Message( MSG_INFO, IDS_DOWNLOAD_FRAGMENT_END, (LPCTSTR)m_sAddress ); Close( TRI_TRUE ); return FALSE; } */ //This source is current requesting SetState( dtsRequesting ); //Set the 'last requested' time m_tRequest = tNow; ClearRequests(); //Send ed2k file request CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_FILEREQUEST ); pPacket->Write( m_pDownload->m_oED2K ); if ( Settings.eDonkey.ExtendedRequest >= 1 && m_pClient->m_bEmRequest >= 1 ) { m_pClient->WritePartStatus( pPacket, m_pDownload ); } //It's not very accurate if ( Settings.eDonkey.ExtendedRequest >= 2 && m_pClient->m_bEmRequest >= 2 ) { pPacket->WriteShortLE( (WORD) m_pDownload->GetED2KCompleteSourceCount() ); } Send( pPacket ); if ( m_pDownload->m_nSize <= ED2K_PART_SIZE ) { // Don't ask for status - if the client answers, we know the file is complete anyway } else { //Send ed2k status request pPacket = CEDPacket::New( ED2K_C2C_FILESTATUSREQUEST ); pPacket->Write( m_pDownload->m_oED2K ); Send( pPacket ); } // TODO: Add new option "SourceExchangePeriod" (default: 10 minutes) like BitTorrent has if ( ( m_pDownload->GetSourceCount() < Settings.Downloads.SourcesWanted ) && ( tNow >= m_tSourceRequest + 10 * 60 * 1000 ) && m_pClient->m_bEmule ) { // Set 'last asked for sources' time m_tSourceRequest = tNow; // Send ed2k request for sources packet pPacket = CEDPacket::New( ED2K_C2C_REQUESTSOURCES, ED2K_PROTOCOL_EMULE ); pPacket->Write( m_pDownload->m_oED2K ); Send( pPacket ); } return TRUE; }