📄 downloadclient.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "StdAfx.h"
#include "zlib/zlib.h"
#include "updownclient.h"
#include "partfile.h"
#include "opcodes.h"
#include "packets.h"
#include "emule.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// members of CUpDownClient
// which are mainly used for downloading functions
CBarShader CUpDownClient::s_StatusBar(16);
void CUpDownClient::DrawStatusBar(CDC* dc, RECT* rect, bool onlygreyrect, bool bFlat){
COLORREF crBoth;
COLORREF crNeither;
COLORREF crClientOnly;
COLORREF crPending;
COLORREF crNextPending;
if(bFlat) {
crBoth = RGB(0, 0, 0);
crNeither = RGB(224, 224, 224);
crClientOnly = RGB(0, 100, 255);
crPending = RGB(0,150,0);
crNextPending = RGB(255,208,0);
} else {
crBoth = RGB(104, 104, 104);
crNeither = RGB(240, 240, 240);
crClientOnly = RGB(0, 100, 255);
crPending = RGB(0, 150, 0);
crNextPending = RGB(255,208,0);
}
s_StatusBar.SetFileSize(reqfile->GetFileSize());
s_StatusBar.SetHeight(rect->bottom - rect->top);
s_StatusBar.SetWidth(rect->right - rect->left);
s_StatusBar.Fill(crNeither);
uint32 uEnd;
// Barry - was only showing one part from client, even when reserved bits from 2 parts
CString gettingParts;
ShowDownloadingParts(&gettingParts);
if (!onlygreyrect && reqfile && m_abyPartStatus) {
for (uint32 i = 0;i != m_nPartCount;i++){
if (m_abyPartStatus[i]){
if (PARTSIZE*(i+1) > reqfile->GetFileSize())
uEnd = reqfile->GetFileSize();
else
uEnd = PARTSIZE*(i+1);
if (reqfile->IsComplete(PARTSIZE*i,PARTSIZE*(i+1)-1))
s_StatusBar.FillRange(PARTSIZE*i, uEnd, crBoth);
else if (m_nDownloadState == DS_DOWNLOADING && m_nLastBlockOffset < uEnd &&
m_nLastBlockOffset >= PARTSIZE*i)
s_StatusBar.FillRange(PARTSIZE*i, uEnd, crPending);
else if (gettingParts.GetAt(i) == 'Y')
s_StatusBar.FillRange(PARTSIZE*i, uEnd, crNextPending);
else
s_StatusBar.FillRange(PARTSIZE*i, uEnd, crClientOnly);
}
}
}
s_StatusBar.Draw(dc, rect->left, rect->top, bFlat);
}
bool CUpDownClient::Compare(CUpDownClient* tocomp){
if(HasValidHash() && tocomp->HasValidHash())
return !memcmp(this->GetUserHash(), tocomp->GetUserHash(), 16);
if (HasLowID())
return ((this->GetUserID() == tocomp->GetUserID()) && (GetServerIP() == tocomp->GetServerIP()) && (this->GetUserPort() == tocomp->GetUserPort()));
else
return ((this->GetUserID() == tocomp->GetUserID() && this->GetUserPort() == tocomp->GetUserPort()) || (this->GetIP() && (this->GetIP() == tocomp->GetIP() && this->GetUserPort() == tocomp->GetUserPort())) );
}
void CUpDownClient::AskForDownload(){
if (theApp.listensocket->TooManySockets() && !(socket && socket->IsConnected()) ){
if (GetDownloadState() != DS_TOOMANYCONNS)
SetDownloadState(DS_TOOMANYCONNS);
return;
}
m_bUDPPending = false;
m_dwLastAskedTime = ::GetTickCount();
SetDownloadState(DS_CONNECTING);
TryToConnect();
}
bool CUpDownClient::IsSourceRequestAllowed() {
DWORD dwTickCount = ::GetTickCount() + CONNECTION_LATENCY;
int nTimePassedClient = dwTickCount - GetLastSrcAnswerTime();
int nTimePassedFile = dwTickCount - reqfile->GetLastAnsweredTime();
bool bNeverAskedBefore = GetLastSrcReqTime() == 0;
return (
//if client has the correct extended protocol
ExtProtocolAvailable() && m_bySourceExchangeVer >= 1 &&
//AND if we need more sources
theApp.glob_prefs->GetMaxSourcePerFileSoft() > reqfile->GetSourceCount() &&
//AND if...
(
//source is not complete and file is rare, allow once every 10 minutes
( !m_bCompleteSource &&
( reqfile->GetSourceCount() - reqfile->GetValidSourcesCount() <= RARE_FILE / 4 ||
reqfile->GetSourceCount() <= RARE_FILE * 2
) &&
(bNeverAskedBefore || nTimePassedClient > SOURCECLIENTREASK)
) ||
// otherwise, allow every 90 minutes, but only if we haven't
// asked someone else in last 10 minutes
( (bNeverAskedBefore || nTimePassedClient > SOURCECLIENTREASK * reqfile->GetCommonFilePenalty()) &&
(nTimePassedFile > SOURCECLIENTREASK)
)
)
);
}
void CUpDownClient::SendFileRequest(){
ASSERT(reqfile != NULL);
if(!reqfile)
return;
AddAskedCountDown();
CMemFile* data = new CMemFile();
data->Write(reqfile->GetFileHash(),16);
if( GetExtendedRequestsVersion() > 0 ){
reqfile->WritePartStatus(data);
}
Packet* packet = new Packet(data);
packet->opcode=OP_FILEREQUEST;
theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet, true);
delete data;
data = new CMemFile();
data->Write(reqfile->GetFileHash(),16);
packet = new Packet(data);
packet->opcode = OP_SETREQFILEID;
theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet, true);
delete data;
if( IsEmuleClient() ){
SetRemoteQueueFull( true );
SetRemoteQueueRank(0);
}
if(IsSourceRequestAllowed()) {
reqfile->SetLastAnsweredTimeTimeout();
Packet* packet = new Packet(OP_REQUESTSOURCES,16,OP_EMULEPROT);
memcpy(packet->pBuffer,reqfile->GetFileHash(),16);
theApp.uploadqueue->AddUpDataOverheadSourceExchange(packet->size);
socket->SendPacket(packet,true,true);
theApp.emuledlg->AddDebugLogLine( false, "Send:Source Request User(%s) File(%s)", GetUserName(), reqfile->GetFileName() );
}
}
void CUpDownClient::ProcessFileInfo(char* packet,uint32 size){
CSafeMemFile* data = new CSafeMemFile((BYTE*)packet,size);
uchar cfilehash[16];
data->Read(cfilehash,16);
uint16 namelength;
data->Read(&namelength,2);
if (m_pszClientFilename)
delete[] m_pszClientFilename;
m_pszClientFilename = new char[namelength+1];
memset(m_pszClientFilename, 0, namelength+1);
data->Read(m_pszClientFilename,namelength); // TODO why does this overwrite the end of the buffer
//- because sizeof(uint16) is always 2
delete data;
if ( (!reqfile) || memcmp(cfilehash,reqfile->GetFileHash(),16))
throw CString(GetResString(IDS_ERR_WRONGFILEID)+ " (ProcessFileInfo)");
}
void CUpDownClient::ProcessFileStatus(char* packet,uint32 size){
CSafeMemFile* data = new CSafeMemFile((BYTE*)packet,size);
uchar cfilehash[16];
data->Read(cfilehash,16);
if ( (!reqfile) || memcmp(cfilehash,reqfile->GetFileHash(),16)){
delete data; //mf
throw CString(GetResString(IDS_ERR_WRONGFILEID)+ " (ProcessFileStatus)");
}
data->Read(&m_nPartCount,2);
if (m_abyPartStatus){
delete[] m_abyPartStatus;
m_abyPartStatus = NULL;
}
bool bPartsNeeded = false;
if (!m_nPartCount){
m_nPartCount = reqfile->GetPartCount();
m_abyPartStatus = new uint8[m_nPartCount];
memset(m_abyPartStatus,1,m_nPartCount);
bPartsNeeded = true;
m_bCompleteSource = true;
}
else{
if (reqfile->GetPartCount() != m_nPartCount){
delete data; //mf
throw GetResString(IDS_ERR_WRONGPARTNUMBER);
}
m_bCompleteSource = false;
m_abyPartStatus = new uint8[m_nPartCount];
uint16 done = 0;
while (done != m_nPartCount){
uint8 toread;
data->Read(&toread,1);
for (sint32 i = 0;i != 8;i++){
m_abyPartStatus[done] = ((toread>>i)&1)? 1:0;
if (m_abyPartStatus[done] && !reqfile->IsComplete(done*PARTSIZE,((done+1)*PARTSIZE)-1))
bPartsNeeded = true;
done++;
if (done == m_nPartCount)
break;
}
}
}
//theApp.emuledlg->transferwnd.downloadlistctrl.UpdateItem(this);
UpdateDisplayedInfo();
reqfile->UpdateAvailablePartsCount();
if (!bPartsNeeded)
SetDownloadState(DS_NONEEDEDPARTS);
else if (reqfile->hashsetneeded){
Packet* packet = new Packet(OP_HASHSETREQUEST,16);
memcpy(packet->pBuffer,reqfile->GetFileHash(),16);
theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet, true, true);
SetDownloadState(DS_REQHASHSET);
reqfile->hashsetneeded = false;
}
else{
SetDownloadState(DS_ONQUEUE);
delete data;
data = new CSafeMemFile(16);
data->Write(this->reqfile->GetFileHash(),16);
Packet* packet = new Packet(data);
packet->opcode = OP_STARTUPLOADREQ;
theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet, true, true);
}
reqfile->NewSrcPartsInfo();
delete data;
}
bool CUpDownClient::AddRequestForAnotherFile(CPartFile* file){
for (POSITION pos = m_OtherNoNeeded_list.GetHeadPosition();pos != 0;m_OtherNoNeeded_list.GetNext(pos)){
if (m_OtherNoNeeded_list.GetAt(pos) == file)
return false;
}
for (POSITION pos = m_OtherRequests_list.GetHeadPosition();pos != 0;m_OtherRequests_list.GetNext(pos)){
if (m_OtherRequests_list.GetAt(pos) == file)
return false;
}
m_OtherRequests_list.AddTail(file);
return true;
}
void CUpDownClient::SetDownloadState(uint8 byNewState){
if (m_nDownloadState != byNewState){
if(byNewState == DS_DOWNLOADING){
reqfile->AddDownloadingSource(this);
}
else if(m_nDownloadState == DS_DOWNLOADING){
reqfile->RemoveDownloadingSource(this);
}
if (m_nDownloadState == DS_DOWNLOADING ){
m_nDownloadState = byNewState;
for (POSITION pos = m_DownloadBlocks_list.GetHeadPosition();pos != 0;m_DownloadBlocks_list.GetNext(pos)){
Requested_Block_Struct* cur_block = m_DownloadBlocks_list.GetAt(pos);
reqfile->RemoveBlockFromList(cur_block->StartOffset,cur_block->EndOffset);
delete m_DownloadBlocks_list.GetAt(pos);
}
m_DownloadBlocks_list.RemoveAll();
for (POSITION pos = m_PendingBlocks_list.GetHeadPosition();pos != 0;m_PendingBlocks_list.GetNext(pos))
{
Pending_Block_Struct *pending = m_PendingBlocks_list.GetAt(pos);
if (reqfile)
reqfile->RemoveBlockFromList(pending->block->StartOffset, pending->block->EndOffset);
delete pending->block;
// Not always allocated
if (pending->zStream) delete pending->zStream;
delete pending;
}
m_PendingBlocks_list.RemoveAll();
m_nDownDatarate = 0;
if (byNewState == DS_NONE){
if (m_abyPartStatus)
delete[] m_abyPartStatus;
m_abyPartStatus = 0;
}
if (socket && byNewState != DS_ERROR)
socket->DisableDownloadLimit();
}
m_nDownloadState = byNewState;
if( GetDownloadState() == DS_DOWNLOADING ){
if ( IsEmuleClient() )
SetRemoteQueueFull(false);
SetRemoteQueueRank(0);
SetAskedCountDown(0);
}
UpdateDisplayedInfo(true);
}
}
void CUpDownClient::ProcessHashSet(char* packet,uint32 size){
if ( (!reqfile) || memcmp(packet,reqfile->GetFileHash(),16))
throw CString(GetResString(IDS_ERR_WRONGFILEID)+" (ProcessHashSet)");
CSafeMemFile* data = new CSafeMemFile((BYTE*)packet,size);
if (reqfile->LoadHashsetFromFile(data,true)){
}
else{
reqfile->hashsetneeded = true;
delete data; //mf
throw GetResString(IDS_ERR_BADHASHSET);
}
SetDownloadState(DS_ONQUEUE);
delete data;
data = new CSafeMemFile(16);
data->Write(this->reqfile->GetFileHash(),16);
Packet* opacket = new Packet(data);
opacket->opcode = OP_STARTUPLOADREQ;
theApp.uploadqueue->AddUpDataOverheadFileRequest(opacket->size);
socket->SendPacket(opacket, true, true);
delete data;
}
void CUpDownClient::SendBlockRequests(){
m_dwLastBlockReceived = ::GetTickCount();
if (!reqfile)
return;
if (m_DownloadBlocks_list.IsEmpty())
{
// Barry - instead of getting 3, just get how many is needed
uint16 count = 3 - 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;
}
// Barry - Why are unfinished blocks requested again, not just new ones?
while (m_PendingBlocks_list.GetCount() < 3 && !m_DownloadBlocks_list.IsEmpty()){
Pending_Block_Struct* pblock = new Pending_Block_Struct;
pblock->block = m_DownloadBlocks_list.RemoveHead();
pblock->zStream = NULL;
pblock->totalUnzipped = 0;
m_PendingBlocks_list.AddTail(pblock);
}
if (m_PendingBlocks_list.IsEmpty()){
Packet* packet = new Packet(OP_CANCELTRANSFER,0);
theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet,true,true);
SetDownloadState(DS_NONEEDEDPARTS);
return;
}
Packet* packet = new Packet(OP_REQUESTPARTS,40);
CMemFile* data = new CMemFile((BYTE*)packet->pBuffer,40);
data->Write(reqfile->GetFileHash(),16);
POSITION pos = m_PendingBlocks_list.GetHeadPosition();
uint32 null = 0;
Requested_Block_Struct* block;
for (uint32 i = 0; i != 3; i++){
if (pos){
block = m_PendingBlocks_list.GetAt(pos)->block;
m_PendingBlocks_list.GetNext(pos);
data->Write(&block->StartOffset,4);
}
else
data->Write(&null,4);
}
pos = m_PendingBlocks_list.GetHeadPosition();
for (uint32 i = 0; i != 3; i++){
if (pos){
block = m_PendingBlocks_list.GetAt(pos)->block;
m_PendingBlocks_list.GetNext(pos);
uint32 endpos = block->EndOffset+1;
data->Write(&endpos,4);
}
else
data->Write(&null,4);
}
delete data;
theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet,true,true);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -