📄 downloadclient.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.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 "emule.h"
#include <zlib/zlib.h>
#include "UpDownClient.h"
#include "PartFile.h"
#include "OtherFunctions.h"
#include "ListenSocket.h"
#include "PeerCacheSocket.h"
#include "Preferences.h"
#include "SafeFile.h"
#include "Packets.h"
#include "Statistics.h"
#include "ClientCredits.h"
#include "DownloadQueue.h"
#include "ClientUDPSocket.h"
#include "emuledlg.h"
#include "TransferWnd.h"
#include "PeerCacheFinder.h"
#include "Exceptions.h"
#include "clientlist.h"
#include "Kademlia/Kademlia/Kademlia.h"
#include "Kademlia/Kademlia/Prefs.h"
#include "Kademlia/Kademlia/Search.h"
#include "SHAHashSet.h"
#include "SharedFileList.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, LPCRECT rect, bool onlygreyrect, bool bFlat) const
{
COLORREF crNeither;
if(bFlat) {
crNeither = RGB(224, 224, 224);
} else {
crNeither = RGB(240, 240, 240);
}
ASSERT(reqfile);
s_StatusBar.SetFileSize(reqfile->GetFileSize());
s_StatusBar.SetHeight(rect->bottom - rect->top);
s_StatusBar.SetWidth(rect->right - rect->left);
s_StatusBar.Fill(crNeither);
if (!onlygreyrect && reqfile && m_abyPartStatus) {
COLORREF crBoth;
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);
}
char* pcNextPendingBlks = NULL;
if (m_nDownloadState == DS_DOWNLOADING){
pcNextPendingBlks = new char[m_nPartCount];
memset(pcNextPendingBlks, 'N', m_nPartCount); // do not use '_strnset' for uninitialized memory!
for (POSITION pos = m_PendingBlocks_list.GetHeadPosition(); pos != 0; ){
UINT uPart = m_PendingBlocks_list.GetNext(pos)->block->StartOffset / PARTSIZE;
if (uPart < m_nPartCount)
pcNextPendingBlks[uPart] = 'Y';
}
}
for (uint32 i = 0;i < m_nPartCount;i++){
if (m_abyPartStatus[i]){
uint32 uEnd;
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 >= PARTSIZE*i && m_nLastBlockOffset < uEnd)
s_StatusBar.FillRange(PARTSIZE*i, uEnd, crPending);
else if (pcNextPendingBlks != NULL && pcNextPendingBlks[i] == 'Y')
s_StatusBar.FillRange(PARTSIZE*i, uEnd, crNextPending);
else
s_StatusBar.FillRange(PARTSIZE*i, uEnd, crClientOnly);
}
}
delete[] pcNextPendingBlks;
}
s_StatusBar.Draw(dc, rect->left, rect->top, bFlat);
}
bool CUpDownClient::Compare(const CUpDownClient* tocomp, bool bIgnoreUserhash) const
{
//Compare only the user hash..
if(!bIgnoreUserhash && HasValidHash() && tocomp->HasValidHash())
return !md4cmp(this->GetUserHash(), tocomp->GetUserHash());
if (HasLowID())
{
//User is firewalled.. Must do two checks..
if (GetIP()!=0 && GetIP() == tocomp->GetIP())
{
//The IP of both match
if (GetUserPort()!=0 && GetUserPort() == tocomp->GetUserPort())
//IP-UserPort matches
return true;
if (GetKadPort()!=0 && GetKadPort() == tocomp->GetKadPort())
//IP-KadPort Matches
return true;
}
if (GetUserIDHybrid()!=0
&& GetUserIDHybrid() == tocomp->GetUserIDHybrid()
&& GetServerIP()!=0
&& GetServerIP() == tocomp->GetServerIP()
&& GetServerPort()!=0
&& GetServerPort() == tocomp->GetServerPort())
//Both have the same lowID, Same serverIP and Port..
return true;
#if defined(_DEBUG)
if ( HasValidBuddyID() && tocomp->HasValidBuddyID() )
{
//JOHNTODO: This is for future use to see if this will be needed...
if(!md4cmp(GetBuddyID(), tocomp->GetBuddyID()))
return true;
}
#endif
//Both IP, and Server do not match..
return false;
}
//User is not firewalled.
if (GetUserPort()!=0)
{
//User has a Port, lets check the rest.
if (GetIP() != 0 && tocomp->GetIP() != 0)
{
//Both clients have a verified IP..
if(GetIP() == tocomp->GetIP() && GetUserPort() == tocomp->GetUserPort())
//IP and UserPort match..
return true;
}
else
{
//One of the two clients do not have a verified IP
if (GetUserIDHybrid() == tocomp->GetUserIDHybrid() && GetUserPort() == tocomp->GetUserPort())
//ID and Port Match..
return true;
}
}
if(GetKadPort()!=0)
{
//User has a Kad Port.
if(GetIP() != 0 && tocomp->GetIP() != 0)
{
//Both clients have a verified IP.
if(GetIP() == tocomp->GetIP() && GetKadPort() == tocomp->GetKadPort())
//IP and KadPort Match..
return true;
}
else
{
//One of the users do not have a verified IP.
if (GetUserIDHybrid() == tocomp->GetUserIDHybrid() && GetKadPort() == tocomp->GetKadPort())
//ID and KadProt Match..
return true;
}
}
//No Matches..
return false;
}
// Return bool is not if you asked or not..
// false = Client was deleted!
// true = client was not deleted!
bool CUpDownClient::AskForDownload()
{
if (theApp.listensocket->TooManySockets() && !(socket && socket->IsConnected()) )
{
if (GetDownloadState() != DS_TOOMANYCONNS)
SetDownloadState(DS_TOOMANYCONNS);
return true;
}
if (m_bUDPPending)
{
m_nFailedUDPPackets++;
theApp.downloadqueue->AddFailedUDPFileReasks();
}
m_bUDPPending = false;
SwapToAnotherFile(_T("A4AF check before tcp file reask. CUpDownClient::AskForDownload()"), true, false, false, NULL, true, true); // ZZ:DownloadManager
SetDownloadState(DS_CONNECTING);
return TryToConnect();
}
bool CUpDownClient::IsSourceRequestAllowed() const
{
return IsSourceRequestAllowed(reqfile); // ZZ:DownloadManager
} // ZZ:DownloadManager
bool CUpDownClient::IsSourceRequestAllowed(CPartFile* partfile, bool sourceExchangeCheck) const // ZZ:DownloadManager
{ // ZZ:DownloadManager
DWORD dwTickCount = ::GetTickCount() + CONNECTION_LATENCY;
unsigned int nTimePassedClient = dwTickCount - GetLastSrcAnswerTime();
unsigned int nTimePassedFile = dwTickCount - partfile->GetLastAnsweredTime(); // ZZ:DownloadManager
bool bNeverAskedBefore = GetLastAskedForSources() == 0;
// ZZ:DownloadManager -->
UINT uSources = partfile->GetSourceCount();
UINT uValidSources = partfile->GetValidSourcesCount();
if(partfile != reqfile) {
uSources++;
uValidSources++;
}
UINT uReqValidSources = reqfile->GetValidSourcesCount();
// <-- ZZ:DownloadManager
return (
//if client has the correct extended protocol
ExtProtocolAvailable() && GetSourceExchangeVersion() > 1 &&
//AND if we need more sources
thePrefs.GetMaxSourcePerFileSoft() > uSources &&
//AND if...
(
//source is not complete and file is very rare
( !m_bCompleteSource
&& (bNeverAskedBefore || nTimePassedClient > SOURCECLIENTREASKS)
&& (uSources <= RARE_FILE/5)
&& (!sourceExchangeCheck || partfile == reqfile || uValidSources < uReqValidSources && uReqValidSources > 3) // ZZ:DownloadManager
) ||
//source is not complete and file is rare
( !m_bCompleteSource
&& (bNeverAskedBefore || nTimePassedClient > SOURCECLIENTREASKS)
&& (uSources <= RARE_FILE || (!sourceExchangeCheck || partfile == reqfile) && uSources <= RARE_FILE / 2 + uValidSources) // ZZ:DownloadManager
&& (nTimePassedFile > SOURCECLIENTREASKF)
&& (!sourceExchangeCheck || partfile == reqfile || uValidSources < SOURCECLIENTREASKS/SOURCECLIENTREASKF && uValidSources < uReqValidSources) // ZZ:DownloadManager
) ||
// OR if file is not rare
( (bNeverAskedBefore || nTimePassedClient > (unsigned)(SOURCECLIENTREASKS * MINCOMMONPENALTY))
&& (nTimePassedFile > (unsigned)(SOURCECLIENTREASKF * MINCOMMONPENALTY))
&& (!sourceExchangeCheck || partfile == reqfile || uValidSources < SOURCECLIENTREASKS/SOURCECLIENTREASKF && uValidSources < uReqValidSources) // ZZ:DownloadManager
)
)
);
}
void CUpDownClient::SendFileRequest()
{
// normally asktime has already been reset here, but then SwapToAnotherFile will return without much work, so check to make sure
SwapToAnotherFile(_T("A4AF check before tcp file reask. CUpDownClient::SendFileRequest()"), true, false, false, NULL, true, true); // ZZ:DownloadManager
ASSERT(reqfile != NULL);
if(!reqfile)
return;
AddAskedCountDown();
CSafeMemFile dataFileReq(16+16);
dataFileReq.WriteHash16(reqfile->GetFileHash());
if( SupportMultiPacket() )
{
dataFileReq.WriteUInt8(OP_REQUESTFILENAME);
//Extended information
if( GetExtendedRequestsVersion() > 0 )
reqfile->WritePartStatus(&dataFileReq);
if( GetExtendedRequestsVersion() > 1 )
reqfile->WriteCompleteSourcesCount(&dataFileReq);
if (reqfile->GetPartCount() > 1)
dataFileReq.WriteUInt8(OP_SETREQFILEID);
if( IsEmuleClient() )
{
SetRemoteQueueFull( true );
SetRemoteQueueRank(0);
}
if(IsSourceRequestAllowed())
{
dataFileReq.WriteUInt8(OP_REQUESTSOURCES);
reqfile->SetLastAnsweredTimeTimeout();
SetLastAskedForSources();
if (thePrefs.GetDebugSourceExchange())
AddDebugLogLine(false, _T("SXSend: Client source request; %s, File=\"%s\""), DbgGetClientInfo(), reqfile->GetFileName());
}
if (IsSupportingAICH()){
///*toremove*/ AddDebugLogLine(false, _T("Send OP_AICHFILEHASHREQ, %s"), DbgGetClientInfo());
dataFileReq.WriteUInt8(OP_AICHFILEHASHREQ);
}
/*else
AddDebugLogLine(false, _T("Did not Send OP_AICHFILEHASHREQ, %s"), DbgGetClientInfo());*/
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__MultiPacket", this, (char*)reqfile->GetFileHash());
Packet* packet = new Packet(&dataFileReq, OP_EMULEPROT);
packet->opcode = OP_MULTIPACKET;
theStats.AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet, true);
}
else
{
//This is extended information
if( GetExtendedRequestsVersion() > 0 ){
reqfile->WritePartStatus(&dataFileReq);
}
if( GetExtendedRequestsVersion() > 1 ){
reqfile->WriteCompleteSourcesCount(&dataFileReq);
}
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__FileRequest", this, (char*)reqfile->GetFileHash());
Packet* packet = new Packet(&dataFileReq);
packet->opcode=OP_REQUESTFILENAME;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -