📄 baseclient.cpp
字号:
m_bySupportSecIdent = (temptag.GetInt() ) & 3;
m_fSupportsPreview = (temptag.GetInt() >> 7) & 1;
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n SecIdent=%u Preview=%u"), m_bySupportSecIdent, m_fSupportsPreview);
break;
case ET_MOD_VERSION:
if (temptag.IsStr())
m_strModVersion = temptag.GetStr();
else if (temptag.IsInt())
m_strModVersion.Format(_T("ModID=%u"), temptag.GetInt());
else
m_strModVersion = _T("ModID=<Unknwon>");
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ModID=%s"), m_strModVersion);
CheckForGPLEvilDoer();
break;
default:
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkTag=%s"), temptag.GetFullInfo());
}
}
if( m_byDataCompVer == 0 ){
m_bySourceExchangeVer = 0;
m_byExtendedRequestsVer = 0;
m_byAcceptCommentVer = 0;
m_nUDPPort = 0;
}
if (bDbgInfo && data.GetPosition() < data.GetLength()){
m_strMuleInfo.AppendFormat(_T("\n ***AddData: %u bytes"), data.GetLength() - data.GetPosition());
}
ReGetClientSoft();
m_byInfopacketsReceived |= IP_EMULEPROTPACK;
if (thePrefs.GetVerbose() && GetServerIP() == INADDR_NONE)
AddDebugLogLine(false, _T("Received invalid server IP %s from %s"), ipstr(GetServerIP()), DbgGetClientInfo());
}
void CUpDownClient::SendHelloAnswer(){
if (socket == NULL){
ASSERT(0);
return;
}
CSafeMemFile data(128);
SendHelloTypePacket(&data);
Packet* packet = new Packet(&data);
packet->opcode = OP_HELLOANSWER;
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__HelloAnswer", this);
theStats.AddUpDataOverheadOther(packet->size);
socket->SendPacket(packet,true);
}
void CUpDownClient::SendHelloTypePacket(CSafeMemFile* data)
{
data->WriteHash16(thePrefs.GetUserHash());
uint32 clientid;
clientid = theApp.GetID();
data->WriteUInt32(clientid);
data->WriteUInt16(thePrefs.GetPort());
uint32 tagcount = 6;
if( theApp.clientlist->GetBuddy() && theApp.IsFirewalled() )
tagcount += 2;
data->WriteUInt32(tagcount);
// eD2K Name
// TODO implement multi language website which informs users of the effects of bad mods
CTag tagName(CT_NAME, (!m_bGPLEvildoer) ? thePrefs.GetUserNick() : _T("Please use a GPL-conform version of eMule") );
tagName.WriteTagToFile(data, utf8strRaw);
// eD2K Version
CTag tagVersion(CT_VERSION,EDONKEYVERSION);
tagVersion.WriteTagToFile(data);
// eMule UDP Ports
uint32 kadUDPPort = 0;
if(Kademlia::CKademlia::isConnected())
{
kadUDPPort = thePrefs.GetUDPPort();
}
CTag tagUdpPorts(CT_EMULE_UDPPORTS,
((uint32)kadUDPPort << 16) |
((uint32)thePrefs.GetUDPPort() << 0)
);
tagUdpPorts.WriteTagToFile(data);
if( theApp.clientlist->GetBuddy() && theApp.IsFirewalled() )
{
CTag tagBuddyIP(CT_EMULE_BUDDYIP, theApp.clientlist->GetBuddy()->GetBuddyIP() );
tagBuddyIP.WriteTagToFile(data);
CTag tagBuddyPort(CT_EMULE_BUDDYUDP,
// ( RESERVED )
((uint32)theApp.clientlist->GetBuddy()->GetBuddyPort() )
);
tagBuddyPort.WriteTagToFile(data);
}
// eMule Misc. Options #1
const UINT uUdpVer = 4;
const UINT uDataCompVer = 1;
const UINT uSupportSecIdent = theApp.clientcredits->CryptoAvailable() ? 3 : 0;
const UINT uSourceExchangeVer = 3;
const UINT uExtendedRequestsVer = 2;
const UINT uAcceptCommentVer = 1;
const UINT uNoViewSharedFiles = (thePrefs.CanSeeShares() == vsfaNobody) ? 1 : 0; // for backward compatibility this has to be a 'negative' flag
const UINT uMultiPacket = 1;
const UINT uSupportPreview = (thePrefs.CanSeeShares() != vsfaNobody) ? 1 : 0; // set 'Preview supported' only if 'View Shared Files' allowed
const UINT uPeerCache = 1;
const UINT uUnicodeSupport = 1;
const UINT nAICHVer = 1;
CTag tagMisOptions1(CT_EMULE_MISCOPTIONS1,
(nAICHVer << 29) |
(uUnicodeSupport << 28) |
(uUdpVer << 24) |
(uDataCompVer << 20) |
(uSupportSecIdent << 16) |
(uSourceExchangeVer << 12) |
(uExtendedRequestsVer << 8) |
(uAcceptCommentVer << 4) |
(uPeerCache << 3) |
(uNoViewSharedFiles << 2) |
(uMultiPacket << 1) |
(uSupportPreview << 0)
);
tagMisOptions1.WriteTagToFile(data);
// eMule Misc. Options #2
const UINT uKadVersion = 1;
CTag tagMisOptions2(CT_EMULE_MISCOPTIONS2,
// (RESERVED )
(uKadVersion << 0)
);
tagMisOptions2.WriteTagToFile(data);
// eMule Version
CTag tagMuleVersion(CT_EMULE_VERSION,
//(uCompatibleClientID << 24) |
(VERSION_MJR << 17) |
(VERSION_MIN << 10) |
(VERSION_UPDATE << 7)
// (RESERVED )
);
tagMuleVersion.WriteTagToFile(data);
uint32 dwIP;
uint16 nPort;
if (theApp.serverconnect->IsConnected()){
dwIP = theApp.serverconnect->GetCurrentServer()->GetIP();
nPort = theApp.serverconnect->GetCurrentServer()->GetPort();
#ifdef _DEBUG
if (dwIP == theApp.serverconnect->GetLocalIP()){
dwIP = 0;
nPort = 0;
}
#endif
}
else{
nPort = 0;
dwIP = 0;
}
data->WriteUInt32(dwIP);
data->WriteUInt16(nPort);
// data->WriteUInt32(dwIP); //The Hybrid added some bits here, what ARE THEY FOR?
}
void CUpDownClient::ProcessMuleCommentPacket(char* pachPacket, uint32 nSize)
{
if (reqfile && reqfile->IsPartFile())
{
CSafeMemFile data((BYTE*)pachPacket, nSize);
uint8 uRating = data.ReadUInt8();
if (thePrefs.GetLogRatingDescReceived() && uRating > 0)
AddDebugLogLine(false, GetResString(IDS_RATINGRECV), m_strClientFilename, uRating);
UINT uLength = data.ReadUInt32();
if (uLength > 0)
{
// we have to increase the raw max. allowed file comment len because of possible UTF8 encoding.
if (uLength > MAXFILECOMMENTLEN*3)
uLength = MAXFILECOMMENTLEN*3;
CString strComment = data.ReadString(GetUnicodeSupport(), uLength);
if (thePrefs.GetLogRatingDescReceived() && !strComment.IsEmpty())
AddDebugLogLine(false, GetResString(IDS_DESCRIPTIONRECV), m_strClientFilename, strComment);
// test if comment is filtered
if (!thePrefs.GetCommentFilter().IsEmpty())
{
CString strCommentLower(strComment);
strCommentLower.MakeLower();
int iPos = 0;
CString strFilter(thePrefs.GetCommentFilter().Tokenize(_T("|"), iPos));
while (!strFilter.IsEmpty())
{
// comment filters are already in lowercase, compare with temp. lowercased received comment
if (strCommentLower.Find(strFilter) >= 0)
{
strComment.Empty();
uRating = 0;
break;
}
strFilter = thePrefs.GetCommentFilter().Tokenize(_T("|"), iPos);
}
}
if (!strComment.IsEmpty() || uRating > 0)
{
m_strFileComment = strComment;
m_uFileRating = uRating;
reqfile->UpdateFileRatingCommentAvail();
}
}
}
}
bool CUpDownClient::Disconnected(LPCTSTR pszReason, bool bFromSocket)
{
ASSERT( theApp.clientlist->IsValidClient(this) );
//If this is a KAD client object, just delete it!
SetKadState(KS_NONE);
if (GetUploadState() == US_UPLOADING || GetUploadState() == US_CONNECTING)
{
if (thePrefs.GetLogUlDlEvents() && GetUploadState()==US_UPLOADING && m_fSentOutOfPartReqs==0 && !theApp.uploadqueue->IsOnUploadQueue(this))
DebugLog(_T("Disconnected client removed from upload queue and waiting list: %s"), DbgGetClientInfo());
theApp.uploadqueue->RemoveFromUploadQueue(this, pszReason);
}
// 28-Jun-2004 [bc]: re-applied this patch which was in 0.30b-0.30e. it does not seem to solve the bug but
// it does not hurt either...
if (m_BlockRequests_queue.GetCount() > 0 || m_DoneBlocks_list.GetCount()){
// Although this should not happen, it seems(?) to happens sometimes. The problem we may run into here is as follows:
//
// 1.) If we do not clear the block send requests for that client, we will send those blocks next time the client
// gets an upload slot. But because we are starting to send any available block send requests right _before_ the
// remote client had a chance to prepare to deal with them, the first sent blocks will get dropped by the client.
// Worst thing here is, because the blocks are zipped and can therefore only be uncompressed when the first block
// was received, all of those sent blocks will create a lot of uncompress errors at the remote client.
//
// 2.) The remote client may have already received those blocks from some other client when it gets the next
// upload slot.
DebugLogWarning(_T("Disconnected client with non empty block send queue; %s reqs: %s doneblocks: %s"), DbgGetClientInfo(), m_BlockRequests_queue.GetCount() > 0 ? _T("true") : _T("false"), m_DoneBlocks_list.GetCount() ? _T("true") : _T("false"));
ClearUploadBlockRequests();
}
if (GetDownloadState() == DS_DOWNLOADING){
if (m_ePeerCacheDownState == PCDS_WAIT_CACHE_REPLY || m_ePeerCacheDownState == PCDS_DOWNLOADING)
theApp.m_pPeerCache->DownloadAttemptFailed();
SetDownloadState(DS_ONQUEUE, CString(_T("Disconnected: ")) + pszReason);
}
else{
// ensure that all possible block requests are removed from the partfile
ClearDownloadBlockRequests();
if(GetDownloadState() == DS_CONNECTED){
theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
theApp.downloadqueue->RemoveSource(this);
}
}
// we had still an AICH request pending, handle it
if (IsAICHReqPending()){
m_fAICHRequested = FALSE;
CAICHHashSet::ClientAICHRequestFailed(this);
}
// The remote client does not have to answer with OP_HASHSETANSWER *immediatly*
// after we've sent OP_HASHSETREQUEST. It may occure that a (buggy) remote client
// is sending use another OP_FILESTATUS which would let us change to DL-state to DS_ONQUEUE.
if (((GetDownloadState() == DS_REQHASHSET) || m_fHashsetRequesting) && (reqfile))
reqfile->hashsetneeded = true;
ASSERT( theApp.clientlist->IsValidClient(this) );
//check if this client is needed in any way, if not delete it
bool bDelete = true;
switch(m_nUploadState){
case US_ONUPLOADQUEUE:
bDelete = false;
break;
}
switch(m_nDownloadState){
case DS_ONQUEUE:
case DS_TOOMANYCONNS:
case DS_NONEEDEDPARTS:
case DS_LOWTOLOWIP:
bDelete = false;
}
switch(m_nUploadState){
case US_CONNECTING:
if (thePrefs.GetLogUlDlEvents())
AddDebugLogLine(DLP_VERYLOW, true,_T("---- %s: Removing connecting client from upload list. Reason: %s ----"), DbgGetClientInfo(), pszReason);
case US_WAITCALLBACK:
case US_ERROR:
theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
bDelete = true;
}
switch(m_nDownloadState){
case DS_CONNECTING:
case DS_WAITCALLBACK:
case DS_ERROR:
theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
bDelete = true;
}
if (GetChatState() != MS_NONE){
bDelete = false;
theApp.emuledlg->chatwnd->chatselector.ConnectingResult(this,false);
}
if (!bFromSocket && socket){
ASSERT (theApp.listensocket->IsValidSocket(socket));
socket->Safe_Delete();
}
socket = 0;
if (m_iFileListRequested){
LogWarning(LOG_STATUSBAR, GetResString(IDS_SHAREDFILES_FAILED), GetUserName());
m_iFileListRequested = 0;
}
if (m_Friend)
theApp.friendlist->RefreshFriend(m_Friend);
theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(this);
if (bDelete)
{
if (thePrefs.GetDebugClientTCPLevel() > 0)
Debug(_T("--- Deleted client %s; Reason=%s\n"), DbgGetClientInfo(true), pszReason);
return true;
}
else
{
if (thePrefs.GetDebugClientTCPLevel() > 0)
Debug(_T("--- Disconnected client %s; Reason=%s\n"), DbgGetClientInfo(true), pszReason);
m_fHashsetRequesting = 0;
SetSentCancelTransfer(0);
m_bHelloAnswerPending = false;
m_fQueueRankPending = 0;
m_fFailedFileIdReqs = 0;
m_fUnaskQueueRankRecv = 0;
m_uPeerCacheDownloadPushId = 0;
m_uPeerCacheUploadPushId = 0;
m_uPeerCacheRemoteIP = 0;
SetPeerCacheDownState(PCDS_NONE);
SetPeerCacheUpState(PCUS_NONE);
if (m_pPCDownSocket){
m_pPCDownSocket->client = NULL;
m_pPCDownSocket->Safe_Delete();
}
if (m_pPCUpSocket){
m_pPCUpSocket->client = NULL;
m_pPCUpSocket->Safe_Delete();
}
m_fSentOutOfPartReqs = 0;
return false;
}
}
//Returned bool is not if the TryToConnect is successful or not..
//false means the client was deleted!
//true means the client was not deleted!
bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon, CRuntimeClass* pClassSocket)
{
if (theApp.listensocket->TooManySockets() && !bIgnoreMaxCon && !(socket && socket->IsConnected()))
{
if(Disconnected(_T("Too many connections")))
{
delete this;
return false;
}
return true;
}
uint32 uClientIP = GetIP();
if (uClientIP == 0 && !HasLowID())
uClientIP = ntohl(m_nUserIDHybrid);
if (uClientIP)
{
// although we filter all received IPs (server sources, source exchange) and all incomming connection attempts,
// we do have to filter outgoing connection attempts here too, because we may have updated the ip filter list
if (theApp.ipfilter->IsFiltered(uClientIP))
{
theStats.filteredclients++;
if (thePrefs.GetLogFilteredIPs())
AddDebugLogLine(true, GetResString(IDS_IPFILTERED), ipstr(uClientIP), theApp.ipfilter->GetLastHit());
if (Disconnected(_T("IPFilter")))
{
delete this;
return false;
}
return true;
}
// for safety: check again whether that IP is banned
if (theApp.clientlist->IsBannedClient(uClientIP))
{
if (thePrefs.GetLogBannedClients())
AddDebugLogLine(false, _T("Refused to connect to banned client %s"), DbgGetClientInfo());
if (Disconnected(_T("Banned IP")))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -