⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 downloadclient.cpp

📁 非常出名开源客户端下载的程序emule
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//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 + -