📄 baseclient.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"
#ifdef _DEBUG
#include "DebugHelpers.h"
#endif
#include "emule.h"
#include "UpDownClient.h"
#include "FriendList.h"
#include "Clientlist.h"
#include "OtherFunctions.h"
#include "PartFile.h"
#include "ListenSocket.h"
#include "PeerCacheSocket.h"
#include "Friend.h"
#include <zlib/zlib.h>
#include "Packets.h"
#include "Opcodes.h"
#include "SafeFile.h"
#include "Preferences.h"
#include "Server.h"
#include "ClientCredits.h"
#include "IPFilter.h"
#include "Statistics.h"
#include "Version.h"
#include "Sockets.h"
#include "DownloadQueue.h"
#include "UploadQueue.h"
#include "SearchList.h"
#include "SharedFileList.h"
#include "Kademlia/Kademlia/Kademlia.h"
#include "Kademlia/Net/KademliaUDPListener.h"
#include "emuledlg.h"
#include "ServerWnd.h"
#include "TransferWnd.h"
#include "ChatWnd.h"
#include "CxImage/xImage.h"
#include "PreviewDlg.h"
#include "Exceptions.h"
#include "Peercachefinder.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNAMIC(CClientException, CException)
IMPLEMENT_DYNAMIC(CUpDownClient, CObject)
CUpDownClient::CUpDownClient(CClientReqSocket* sender)
{
socket = sender;
reqfile = NULL;
Init();
}
CUpDownClient::CUpDownClient(CPartFile* in_reqfile, uint16 in_port, uint32 in_userid,uint32 in_serverip, uint16 in_serverport, bool ed2kID)
{
//Converting to the HybridID system.. The ED2K system didn't take into account of IP address ending in 0..
//All IP addresses ending in 0 were assumed to be a lowID because of the calculations.
socket = NULL;
reqfile = in_reqfile;
Init();
m_nUserPort = in_port;
//If this is a ED2K source, check if it's a lowID.. If not, convert it to a HyrbidID.
//Else, it's already in hybrid form.
if(ed2kID && !IsLowID(in_userid))
m_nUserIDHybrid = ntohl(in_userid);
else
m_nUserIDHybrid = in_userid;
//If highID and ED2K source, incoming ID and IP are equal..
//If highID and Kad source, incoming IP needs ntohl for the IP
if (!HasLowID() && ed2kID)
m_nConnectIP = in_userid;
else if(!HasLowID())
m_nConnectIP = ntohl(in_userid);
m_dwServerIP = in_serverip;
m_nServerPort = in_serverport;
}
void CUpDownClient::Init()
{
credits = 0;
sumavgUDR = 0; // by BadWolf - Accurate Speed Measurement
m_bAddNextConnect = false; // VQB Fix for LowID slots only on connection
m_nChatstate = MS_NONE;
m_nKadState = KS_NONE;
m_cShowDR = 0;
m_nUDPPort = 0;
m_nKadPort = 0;
m_nTransferedUp = 0;
m_cAsked = 0;
m_cDownAsked = 0;
dataratems = 0;
m_nUpDatarate = 0;
m_pszUsername = 0;
m_nUserIDHybrid = 0;
m_dwServerIP = 0;
m_nServerPort = 0;
m_iFileListRequested = 0;
m_dwLastUpRequest = 0;
m_bEmuleProtocol = false;
m_bCompleteSource = false;
m_bFriendSlot = false;
m_bCommentDirty = false;
m_bReaskPending = false;
m_bUDPPending = false;
m_byEmuleVersion = 0;
m_nUserPort = 0;
m_nPartCount = 0;
m_nUpPartCount = 0;
m_abyPartStatus = 0;
m_abyUpPartStatus = 0;
m_dwLastAskedTime = 0;
m_nDownloadState = DS_NONE;
m_dwUploadTime = 0;
m_nTransferedDown = 0;
m_nDownDatarate = 0;
m_nDownDataRateMS = 0;
m_nUploadState = US_NONE;
m_dwLastBlockReceived = 0;
m_byDataCompVer = 0;
m_byUDPVer = 0;
m_bySourceExchangeVer = 0;
m_byAcceptCommentVer = 0;
m_byExtendedRequestsVer = 0;
m_nRemoteQueueRank = 0;
m_dwLastSourceRequest = 0;
m_dwLastSourceAnswer = 0;
m_dwLastAskedForSources = 0;
m_byCompatibleClient = 0;
m_nSourceFrom = SF_SERVER;
m_bIsHybrid = false;
m_bIsML=false;
m_Friend = NULL;
m_iRate=0;
m_fMessageFiltered = 0;
m_fIsSpammer = 0;
m_cMessagesReceived = 0;
m_cMessagesSent = 0;
(void)m_strComment;
m_nCurSessionUp = 0;
m_nSumForAvgDownDataRate = 0;
m_clientSoft=SO_UNKNOWN;
m_bRemoteQueueFull = false;
md4clr(m_achUserHash);
if (socket){
SOCKADDR_IN sockAddr = {0};
int nSockAddrLen = sizeof(sockAddr);
socket->GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
m_dwUserIP = sockAddr.sin_addr.S_un.S_addr;
m_nConnectIP = m_dwUserIP;
}
else{
m_dwUserIP = 0;
m_nConnectIP = 0;
}
m_fHashsetRequesting = 0;
m_fSharedDirectories = 0;
m_fSentCancelTransfer = 0;
m_nClientVersion = 0;
m_lastRefreshedDLDisplay = 0;
m_dwDownStartTime = 0;
m_nLastBlockOffset = 0;
m_SecureIdentState = IS_UNAVAILABLE;
m_dwLastSignatureIP = 0;
m_bySupportSecIdent = 0;
m_byInfopacketsReceived = IP_NONE;
m_lastPartAsked = 0xffff;
m_nUpCompleteSourcesCount= 0;
m_fSupportsPreview = 0;
m_fPreviewReqPending = 0;
m_fPreviewAnsPending = 0;
m_bTransferredDownMini = false;
m_addedPayloadQueueSession = 0;
m_nCurQueueSessionPayloadUp = 0; // PENDING: Is this necessary? ResetSessionUp()...
m_lastRefreshedULDisplay = ::GetTickCount();
m_bGPLEvildoer = false;
m_bHelloAnswerPending = false;
m_fNoViewSharedFiles = 0;
m_bMultiPacket = 0;
md4clr(requpfileid);
m_nTotalUDPPackets = 0;
m_nFailedUDPPackets = 0;
m_nUrlStartPos = -1;
m_iHttpSendState = 0;
m_fPeerCache = 0;
m_uPeerCacheDownloadPushId = 0;
m_uPeerCacheUploadPushId = 0;
m_pPCDownSocket = NULL;
m_pPCUpSocket = NULL;
m_uPeerCacheRemoteIP = 0;
m_ePeerCacheDownState = PCDS_NONE;
m_ePeerCacheUpState = PCUS_NONE;
m_bPeerCacheDownHit = false;
m_bPeerCacheUpHit = false;
m_fNeedOurPublicIP = 0;
m_bSourceExchangeSwapped = false; // ZZ:DownloadManager
m_fQueueRankPending = 0;
m_fUnaskQueueRankRecv = 0;
m_fFailedFileIdReqs = 0;
}
CUpDownClient::~CUpDownClient(){
theApp.clientlist->RemoveClient(this, _T("Destructing client object"));
if (m_Friend){
m_Friend->SetLinkedClient(NULL);
}
if (socket){
socket->client = 0;
socket->Safe_Delete();
}
if (m_pPCDownSocket){
m_pPCDownSocket->client = NULL;
m_pPCDownSocket->Safe_Delete();
}
if (m_pPCUpSocket){
m_pPCUpSocket->client = NULL;
m_pPCUpSocket->Safe_Delete();
}
if (m_pszUsername)
free(m_pszUsername);
delete[] m_abyPartStatus;
delete[] m_abyUpPartStatus;
ClearUploadBlockRequests();
for (POSITION pos = m_DownloadBlocks_list.GetHeadPosition();pos != 0;)
delete m_DownloadBlocks_list.GetNext(pos);
for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;)
delete m_RequestedFiles_list.GetNext(pos);
for (POSITION pos = m_PendingBlocks_list.GetHeadPosition();pos != 0;){
Pending_Block_Struct *pending = m_PendingBlocks_list.GetNext(pos);
delete pending->block;
// Not always allocated
if (pending->zStream){
inflateEnd(pending->zStream);
delete pending->zStream;
}
delete pending;
}
for (POSITION pos = m_WaitingPackets_list.GetHeadPosition();pos != 0;)
delete m_WaitingPackets_list.GetNext(pos);
if (m_iRate>0 || !m_strComment.IsEmpty()){
m_iRate = 0;
m_strComment.Empty();
reqfile->UpdateFileRatingCommentAvail();
}
DEBUG_ONLY (theApp.listensocket->Debug_ClientDeleted(this));
SetUploadFileID(NULL);
}
void CUpDownClient::ClearHelloProperties()
{
m_nUDPPort = 0;
m_byUDPVer = 0;
m_byDataCompVer = 0;
m_byEmuleVersion = 0;
m_bySourceExchangeVer = 0;
m_byAcceptCommentVer = 0;
m_byExtendedRequestsVer = 0;
m_byCompatibleClient = 0;
m_nKadPort = 0;
m_bySupportSecIdent = 0;
m_fSupportsPreview = 0;
m_nClientVersion = 0;
m_fSharedDirectories = 0;
m_bMultiPacket = 0;
m_fPeerCache = 0;
m_uPeerCacheDownloadPushId = 0;
m_uPeerCacheUploadPushId = 0;
}
bool CUpDownClient::ProcessHelloPacket(char* pachPacket, uint32 nSize){
CSafeMemFile data((BYTE*)pachPacket,nSize);
data.ReadUInt8(); // read size of userhash
// reset all client properties; a client may not send a particular emule tag any longer
ClearHelloProperties();
return ProcessHelloTypePacket(&data);
}
bool CUpDownClient::ProcessHelloAnswer(char* pachPacket, uint32 nSize)
{
CSafeMemFile data((BYTE*)pachPacket,nSize);
bool bIsMule = ProcessHelloTypePacket(&data);
m_bHelloAnswerPending = false;
return bIsMule;
}
bool CUpDownClient::ProcessHelloTypePacket(CSafeMemFile* data)
{
USES_CONVERSION;
bool bDbgInfo = thePrefs.GetUseDebugDevice();
m_strHelloInfo.Empty();
// clear hello properties which can be changed _only_ on receiving OP_Hello/OP_HelloAnswer
m_bIsHybrid = false;
m_bIsML = false;
m_fNoViewSharedFiles = 0;
data->ReadHash16(m_achUserHash);
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("Hash=%s (%s)"), md4str(m_achUserHash), DbgGetHashTypeString(m_achUserHash));
m_nUserIDHybrid = data->ReadUInt32();
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" UserID=%u (%s)"), m_nUserIDHybrid, ipstr(m_nUserIDHybrid));
uint16 nUserPort = data->ReadUInt16(); // hmm clientport is sent twice - why?
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" Port=%u"), nUserPort);
DWORD dwEmuleTags = 0;
uint32 tagcount = data->ReadUInt32();
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" Tags=%u"), tagcount);
for (uint32 i = 0;i < tagcount; i++){
CTag temptag(data);
switch(temptag.tag.specialtag){
case CT_NAME:
if (m_pszUsername){
delete[] m_pszUsername;
m_pszUsername = NULL; // needed, in case 'nstrdup' fires an exception!!
}
if (temptag.tag.stringvalue)
m_pszUsername = _tcsdup(A2T(temptag.tag.stringvalue));
if (bDbgInfo){
if (m_pszUsername){//filter username for bad chars
TCHAR* psz = m_pszUsername;
while (*psz != _T('\0')) {
if (*psz == _T('\n') || *psz == _T('\r'))
*psz = _T(' ');
psz++;
}
}
m_strHelloInfo.AppendFormat(_T(" NAME='%s'"), m_pszUsername);
}
break;
case CT_VERSION:
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" VERSION=%u"), temptag.tag.intvalue);
m_nClientVersion = temptag.tag.intvalue;
break;
case CT_PORT:
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" PORT=%u"), temptag.tag.intvalue);
nUserPort = temptag.tag.intvalue;
break;
case CT_MOD_VERSION:
if (temptag.tag.type == 2)
m_strModVersion = temptag.tag.stringvalue;
else if (temptag.tag.type == 3)
m_strModVersion.Format(_T("ModID=%u"), temptag.tag.intvalue);
else
m_strModVersion = _T("ModID=<Unknwon>");
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" Mod=%s"), m_strModVersion);
CheckForGPLEvilDoer();
break;
case CT_EMULE_UDPPORTS:
// 16 KAD Port
// 16 UDP Port
m_nKadPort = (uint16)(temptag.tag.intvalue >> 16);
m_nUDPPort = (uint16)temptag.tag.intvalue;
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" KadPort=%u UDPPort=%u"), m_nKadPort, m_nUDPPort);
dwEmuleTags |= 1;
break;
case CT_EMULE_MISCOPTIONS1:
// 4 --Reserved for future use--
// 4 UDP version
// 4 Data compression version
// 4 Secure Ident
// 4 Source Exchange
// 4 Ext. Requests
// 4 Comments
// 1 PeerChache supported
// 1 No 'View Shared Files' supported
// 1 MultiPacket
// 1 Preview
m_byUDPVer = (temptag.tag.intvalue >> 4*6) & 0x0f;
m_byDataCompVer = (temptag.tag.intvalue >> 4*5) & 0x0f;
m_bySupportSecIdent = (temptag.tag.intvalue >> 4*4) & 0x0f;
m_bySourceExchangeVer = (temptag.tag.intvalue >> 4*3) & 0x0f;
m_byExtendedRequestsVer = (temptag.tag.intvalue >> 4*2) & 0x0f;
m_byAcceptCommentVer = (temptag.tag.intvalue >> 4*1) & 0x0f;
m_fPeerCache = (temptag.tag.intvalue >> 1*3) & 0x01;
m_fNoViewSharedFiles = (temptag.tag.intvalue >> 1*2) & 0x01;
m_bMultiPacket = (temptag.tag.intvalue >> 1*1) & 0x01;
m_fSupportsPreview = (temptag.tag.intvalue >> 1*0) & 0x01;
dwEmuleTags |= 2;
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" PeerCache=%u UDPVer=%u DataComp=%u SecIdent=%u SrcExchg=%u ExtReq=%u Commnt=%u Preview=%u NoViewFiles=%u"), m_fPeerCache, m_byUDPVer, m_byDataCompVer, m_bySupportSecIdent, m_bySourceExchangeVer, m_byExtendedRequestsVer, m_byAcceptCommentVer, m_fSupportsPreview, m_fNoViewSharedFiles);
break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -