📄 downloadclient.cpp
字号:
m_nDownloadState = nNewState;
ClearDownloadBlockRequests();
m_nDownDatarate = 0;
if (nNewState == DS_NONE){
if (m_abyPartStatus)
delete[] m_abyPartStatus;
m_abyPartStatus = NULL;
m_nPartCount = 0;
}
if (socket && nNewState != DS_ERROR )
socket->DisableDownloadLimit();
}
m_nDownloadState = nNewState;
if( GetDownloadState() == DS_DOWNLOADING ){
if ( IsEmuleClient() )
SetRemoteQueueFull(false);
SetRemoteQueueRank(0);
SetAskedCountDown(0);
}
UpdateDisplayedInfo(true);
}
}
void CUpDownClient::ProcessHashSet(char* packet,uint32 size){
if (!m_fHashsetRequesting)
throw CString(_T("unwanted hashset"));
if ( (!reqfile) || md4cmp(packet,reqfile->GetFileHash())){
CheckFailedFileIdReqs((uchar*)packet);
throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessHashSet)");
}
CSafeMemFile data((BYTE*)packet,size);
if (reqfile->LoadHashsetFromFile(&data,true)){
m_fHashsetRequesting = 0;
}
else{
reqfile->hashsetneeded = true;
throw GetResString(IDS_ERR_BADHASHSET);
}
SendStartupLoadReq();
}
void CUpDownClient::CreateBlockRequests(int iMaxBlocks)
{
ASSERT( iMaxBlocks >= 1 /*&& iMaxBlocks <= 3*/ );
if (m_DownloadBlocks_list.IsEmpty())
{
uint16 count = iMaxBlocks - m_PendingBlocks_list.GetCount();
Requested_Block_Struct** toadd = new Requested_Block_Struct*[count];
if (reqfile->GetNextRequestedBlock(this,toadd,&count)){
for (int i = 0; i < count; i++)
m_DownloadBlocks_list.AddTail(toadd[i]);
}
delete[] toadd;
}
while (m_PendingBlocks_list.GetCount() < iMaxBlocks && !m_DownloadBlocks_list.IsEmpty())
{
Pending_Block_Struct* pblock = new Pending_Block_Struct;
pblock->block = m_DownloadBlocks_list.RemoveHead();
m_PendingBlocks_list.AddTail(pblock);
}
}
void CUpDownClient::SendBlockRequests(){
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__RequestParts", this, reqfile!=NULL ? (char*)reqfile->GetFileHash() : NULL);
m_dwLastBlockReceived = ::GetTickCount();
if (!reqfile)
return;
CreateBlockRequests(3);
if (m_PendingBlocks_list.IsEmpty()){
SendCancelTransfer();
SetDownloadState(DS_NONEEDEDPARTS);
return;
}
const int iPacketSize = 16+(3*4)+(3*4); // 40
Packet* packet = new Packet(OP_REQUESTPARTS,iPacketSize);
CSafeMemFile data((BYTE*)packet->pBuffer,iPacketSize);
data.WriteHash16(reqfile->GetFileHash());
POSITION pos = m_PendingBlocks_list.GetHeadPosition();
for (uint32 i = 0; i != 3; i++){
if (pos){
Pending_Block_Struct* pending = m_PendingBlocks_list.GetNext(pos);
ASSERT( pending->block->StartOffset <= pending->block->EndOffset );
//ASSERT( pending->zStream == NULL );
//ASSERT( pending->totalUnzipped == 0 );
pending->fZStreamError = 0;
pending->fRecovered = 0;
data.WriteUInt32(pending->block->StartOffset);
}
else
data.WriteUInt32(0);
}
pos = m_PendingBlocks_list.GetHeadPosition();
for (uint32 i = 0; i != 3; i++){
if (pos){
Requested_Block_Struct* block = m_PendingBlocks_list.GetNext(pos)->block;
uint32 endpos = block->EndOffset+1;
data.WriteUInt32(endpos);
if (thePrefs.GetDebugClientTCPLevel() > 0){
CString strInfo;
strInfo.Format(_T(" Block request %u: "), i);
strInfo += DbgGetBlockInfo(block);
strInfo.AppendFormat(_T(", Complete=%s"), reqfile->IsComplete(block->StartOffset, block->EndOffset) ? _T("Yes(NOTE:)") : _T("No"));
strInfo.AppendFormat(_T(", PureGap=%s"), reqfile->IsPureGap(block->StartOffset, block->EndOffset) ? _T("Yes") : _T("No(NOTE:)"));
strInfo.AppendFormat(_T(", AlreadyReq=%s"), reqfile->IsAlreadyRequested(block->StartOffset, block->EndOffset) ? _T("Yes") : _T("No(NOTE:)"));
strInfo += _T('\n');
Debug(strInfo);
}
}
else
{
data.WriteUInt32(0);
if (thePrefs.GetDebugClientTCPLevel() > 0)
Debug(_T(" Block request %u: <empty>\n"), i);
}
}
theStats.AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet,true,true);
}
/* Barry - Originally this only wrote to disk when a full 180k block
had been received from a client, and only asked for data in
180k blocks.
This meant that on average 90k was lost for every connection
to a client data source. That is a lot of wasted data.
To reduce the lost data, packets are now written to a buffer
and flushed to disk regularly regardless of size downloaded.
This includes compressed packets.
Data is also requested only where gaps are, not in 180k blocks.
The requests will still not exceed 180k, but may be smaller to
fill a gap.
*/
void CUpDownClient::ProcessBlockPacket(char *packet, uint32 size, bool packed)
{
uint32 nDbgStartPos = *((uint32*)(packet+16));
if (thePrefs.GetDebugClientTCPLevel() > 1){
if (packed)
Debug(_T(" Start=%u BlockSize=%u Size=%u %s\n"), nDbgStartPos, *((uint32*)(packet + 16+4)), size-24, DbgGetFileInfo((uchar*)packet));
else
Debug(_T(" Start=%u End=%u Size=%u %s\n"), nDbgStartPos, *((uint32*)(packet + 16+4)), *((uint32*)(packet + 16+4)) - nDbgStartPos, DbgGetFileInfo((uchar*)packet));
}
// Ignore if no data required
if (!(GetDownloadState() == DS_DOWNLOADING || GetDownloadState() == DS_NONEEDEDPARTS)){
TRACE("%s - Invalid download state\n", __FUNCTION__);
return;
}
const int HEADER_SIZE = 24;
// Update stats
m_dwLastBlockReceived = ::GetTickCount();
// Read data from packet
CSafeMemFile data((BYTE*)packet, size);
uchar fileID[16];
data.ReadHash16(fileID);
// Check that this data is for the correct file
if ( (!reqfile) || md4cmp(packet, reqfile->GetFileHash()))
{
throw GetResString(IDS_ERR_WRONGFILEID) + _T(" (ProcessBlockPacket)");
}
// Find the start & end positions, and size of this chunk of data
uint32 nStartPos;
uint32 nEndPos;
uint32 nBlockSize = 0;
nStartPos = data.ReadUInt32();
if (packed)
{
nBlockSize = data.ReadUInt32();
nEndPos = nStartPos + (size - HEADER_SIZE);
}
else
nEndPos = data.ReadUInt32();
// Check that packet size matches the declared data size + header size (24)
if (nEndPos == nStartPos || size != ((nEndPos - nStartPos) + HEADER_SIZE))
throw GetResString(IDS_ERR_BADDATABLOCK) + _T(" (ProcessBlockPacket)");
// -khaos--+++>
// Extended statistics information based on which client and remote port sent this data.
// The new function adds the bytes to the grand total as well as the given client/port.
// bFromPF is not relevant to downloaded data. It is purely an uploads statistic.
thePrefs.Add2SessionTransferData(GetClientSoft(), GetUserPort(), false, false, size - HEADER_SIZE, false);
// <-----khaos-
m_nDownDataRateMS += size - HEADER_SIZE;
if (credits)
credits->AddDownloaded(size - HEADER_SIZE, GetIP());
// Move end back one, should be inclusive
nEndPos--;
// Loop through to find the reserved block that this is within
for (POSITION pos = m_PendingBlocks_list.GetHeadPosition(); pos != NULL; )
{
POSITION posLast = pos;
Pending_Block_Struct *cur_block = m_PendingBlocks_list.GetNext(pos);
if ((cur_block->block->StartOffset <= nStartPos) && (cur_block->block->EndOffset >= nStartPos))
{
// Found reserved block
if (cur_block->fZStreamError){
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("PrcBlkPkt: Ignoring %u bytes of block starting at %u because of errornous zstream state for file \"%s\" - %s"), size - HEADER_SIZE, nStartPos, reqfile->GetFileName(), DbgGetClientInfo());
reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
return;
}
// Remember this start pos, used to draw part downloading in list
m_nLastBlockOffset = nStartPos;
// Occasionally packets are duplicated, no point writing it twice
// This will be 0 in these cases, or the length written otherwise
uint32 lenWritten = 0;
// Handle differently depending on whether packed or not
if (!packed)
{
// Write to disk (will be buffered in part file class)
lenWritten = reqfile->WriteToBuffer(size - HEADER_SIZE,
(BYTE *) (packet + HEADER_SIZE),
nStartPos,
nEndPos,
cur_block->block,
this);
}
else // Packed
{
ASSERT( (int)size > 0 );
// Create space to store unzipped data, the size is only an initial guess, will be resized in unzip() if not big enough
uint32 lenUnzipped = (size * 2);
// Don't get too big
if (lenUnzipped > (EMBLOCKSIZE + 300))
lenUnzipped = (EMBLOCKSIZE + 300);
BYTE *unzipped = new BYTE[lenUnzipped];
// Try to unzip the packet
int result = unzip(cur_block, (BYTE *)(packet + HEADER_SIZE), (size - HEADER_SIZE), &unzipped, &lenUnzipped);
// no block can be uncompressed to >2GB, 'lenUnzipped' is obviously errornous.
if (result == Z_OK && (int)lenUnzipped >= 0)
{
if (lenUnzipped > 0) // Write any unzipped data to disk
{
ASSERT( (int)lenUnzipped > 0 );
// Use the current start and end positions for the uncompressed data
nStartPos = cur_block->block->StartOffset + cur_block->totalUnzipped - lenUnzipped;
nEndPos = cur_block->block->StartOffset + cur_block->totalUnzipped - 1;
if (nStartPos > cur_block->block->EndOffset || nEndPos > cur_block->block->EndOffset){
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("PrcBlkPkt: ") + GetResString(IDS_ERR_CORRUPTCOMPRPKG),reqfile->GetFileName(),666);
reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
// There is no chance to recover from this error
}
else{
// Write uncompressed data to file
lenWritten = reqfile->WriteToBuffer(size - HEADER_SIZE,
unzipped,
nStartPos,
nEndPos,
cur_block->block,
this);
}
}
}
else
{
if (thePrefs.GetVerbose())
{
CString strZipError;
if (cur_block->zStream && cur_block->zStream->msg)
strZipError.Format(_T(" - %hs"), cur_block->zStream->msg);
if (result == Z_OK && (int)lenUnzipped < 0){
ASSERT(0);
strZipError.AppendFormat(_T("; Z_OK,lenUnzipped=%d"), lenUnzipped);
}
AddDebugLogLine(false, _T("PrcBlkPkt: ") + GetResString(IDS_ERR_CORRUPTCOMPRPKG) + strZipError, reqfile->GetFileName(), result);
}
reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
// If we had an zstream error, there is no chance that we could recover from it nor that we
// could use the current zstream (which is in error state) any longer.
if (cur_block->zStream){
inflateEnd(cur_block->zStream);
delete cur_block->zStream;
cur_block->zStream = NULL;
}
// Although we can't further use the current zstream, there is no need to disconnect the sending
// client because the next zstream (a series of 10K-blocks which build a 180K-block) could be
// valid again. Just ignore all further blocks for the current zstream.
cur_block->fZStreamError = 1;
cur_block->totalUnzipped = 0;
}
delete [] unzipped;
}
// These checks only need to be done if any data was written
if (lenWritten > 0)
{
m_nTransferedDown += lenWritten;
SetTransferredDownMini(); // Sets boolean m_bTransferredDownMini to true // -khaos--+++> For determining whether the current download session was a success or not.
// If finished reserved block
if (nEndPos == cur_block->block->EndOffset)
{
reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
delete cur_block->block;
// Not always allocated
if (cur_block->zStream){
inflateEnd(cur_block->zStream);
delete cur_block->zStream;
}
delete cur_block;
m_PendingBlocks_list.RemoveAt(posLast);
// Request next block
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("More block requests", this);
SendBlockRequests();
}
}
// Stop looping and exit method
return;
}
}
TRACE("%s - Dropping packet\n", __FUNCTION__);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -