//this file is part of eMule
//Copyright (C)2002-2008 Merkur ( strEmail.Format("%s@%s", "devteam", "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"
#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
#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 "Sockets.h"
#include "DownloadQueue.h"
#include "UploadQueue.h"
#include "SearchFile.h"
#include "SearchList.h"
#include "SharedFileList.h"
#include "Kademlia/Kademlia/Kademlia.h"
#include "Kademlia/Kademlia/Search.h"
#include "Kademlia/Kademlia/SearchManager.h"
#include "Kademlia/Kademlia/UDPFirewallTester.h"
#include "Kademlia/routing/RoutingZone.h"
#include "Kademlia/Utils/UInt128.h"
#include "Kademlia/Net/KademliaUDPListener.h"
#include "Kademlia/Kademlia/Prefs.h"
#include "emuledlg.h"
#include "ServerWnd.h"
#include "TransferDlg.h"
#include "ChatWnd.h"
#include "CxImage/xImage.h"
#include "PreviewDlg.h"
#include "Exceptions.h"
#include "Peercachefinder.h"
#include "ClientUDPSocket.h"
#include "shahashset.h"
#include "Log.h"
#include "CaptchaGenerator.h"
//Xman
#include "DLP.h" //Xman DLP
#include "BandWidthControl.h"
//Xman End
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define URLINDICATOR _T("http:|www.|.de |.net |.com |.org |.to |.tk |.cc |.fr |ftp:|ed2k:|https:|ftp.|.info|.biz|.uk|.eu|.es|.tv|.cn|.tw|.ws|.nu|.jp")
//Xman unused
/*
IMPLEMENT_DYNAMIC(CClientException, CException)
*/
//Xman end
IMPLEMENT_DYNAMIC(CUpDownClient, CObject)
//Xman
// Maella -Upload Stop Reason-
// Maella -Download Stop Reason-
// Remark: static element are automaticaly initialized with zero
uint32 CUpDownClient::m_upStopReason[2][CUpDownClient::USR_EXCEPTION+1];
uint32 CUpDownClient::m_downStopReason[2][CUpDownClient::DSR_EXCEPTION+1];
// Maella end
//Xman Anti-Leecher: simple Anti-Thief
const CString CUpDownClient::str_ANTAddOn=CUpDownClient::GetANTAddOn();
//Xman end
CUpDownClient::CUpDownClient(CClientReqSocket* sender)
//Xman // Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter-
: m_upHistory_list(3),
m_downHistory_list(3)
// Maella end
{
socket = sender;
reqfile = NULL;
Init();
}
CUpDownClient::CUpDownClient(CPartFile* in_reqfile, uint16 in_port, uint32 in_userid,uint32 in_serverip, uint16 in_serverport, bool ed2kID)
//Xman // Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter-
: m_upHistory_list(3),
m_downHistory_list(3)
// Maella end
{
//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()
{
//Xman Full Chunk
upendsoon=false;
//Xman filter clients with failed downloads
m_faileddownloads=0;
//Xman Xtreme Mod
m_szFullUserIP=_T("?");
m_cFailed = 0; //Xman Downloadmanager / Xtreme Mod // holds the failed connection attempts
//Xman fix for startupload
lastaction=0;
//Xman fix for startupload (downloading side)
protocolstepflag1=false;
//Xman uploading problem client
isupprob=false;
//Xman askfordownload priority
m_downloadpriority=1;
//Xman end
m_nChatstate = MS_NONE;
m_nKadState = KS_NONE;
m_nChatCaptchaState = CA_NONE;
m_nUploadState = US_NONE;
m_nDownloadState = DS_NONE;
m_SecureIdentState = IS_UNAVAILABLE;
m_nConnectingState = CCS_NONE;
m_ePeerCacheDownState = PCDS_NONE;
m_ePeerCacheUpState = PCUS_NONE;
credits = NULL;
//Xman
/*
m_nSumForAvgUpDataRate = 0;
*/
//Xman end
m_bAddNextConnect = false;
//Xman
/*
m_cShowDR = 0;
*/
//Xman end
m_nUDPPort = 0;
m_nKadPort = 0;
m_nTransferredUp = 0;
m_cAsked = 0;
m_cDownAsked = 0;
//Xman
/*
m_nUpDatarate = 0;
*/
//Xman end
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_dwUploadTime = 0;
m_nTransferredDown = 0;
//Xman
/*
m_nDownDatarate = 0;
m_nDownDataRateMS = 0;
*/
//Xman end
m_dwLastBlockReceived = 0;
m_byDataCompVer = 0;
m_byUDPVer = 0;
m_bySourceExchange1Ver = 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_uFileRating=0;
(void)m_strFileComment;
m_fMessageFiltered = 0;
m_fIsSpammer = 0;
m_cMessagesReceived = 0;
m_cMessagesSent = 0;
m_nCurSessionUp = 0;
m_nCurSessionDown = 0;
m_nCurSessionPayloadDown = 0;
//Xman
/*
m_nSumForAvgDownDataRate = 0;
*/
//Xman end
m_clientSoft=SO_UNKNOWN;
m_bRemoteQueueFull = false;
md4clr(m_achUserHash);
SetBuddyID(NULL);
m_nBuddyIP = 0;
m_nBuddyPort = 0;
if (socket){
SOCKADDR_IN sockAddr = {0};
int nSockAddrLen = sizeof(sockAddr);
socket->GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
SetIP(sockAddr.sin_addr.S_un.S_addr);
}
else{
SetIP(0);
}
//Xman
//remark: in most cases we use the defaultstrcut (ip=0)
//we could use the right IP from begining by moving this method to the constructor
//disadvantage: we create and immediately delete many clients, always searching the
//country costs too much time
//EastShare Start - added by AndCycle, IP to Country
m_structUserCountry = theApp.ip2country->GetCountryFromIP(m_dwUserIP);
//EastShare End - added by AndCycle, IP to Country
m_fHashsetRequestingAICH = 0;
m_fHashsetRequestingMD4 = 0;
m_fSharedDirectories = 0;
m_fSentCancelTransfer = 0;
m_nClientVersion = 0;
m_lastRefreshedDLDisplay = 0;
m_dwDownStartTime = 0;
m_nLastBlockOffset = (uint64)-1;
m_bUnicodeSupport = false;
m_dwLastSignatureIP = 0;
m_bySupportSecIdent = 0;
m_byInfopacketsReceived = IP_NONE;
m_lastPartAsked = (uint16)-1;
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_bACATHelloAnswerPending = false; //zz_fly :: Client is always highid if we are connecting to them - by Enig123, idea from ACAT
m_fNoViewSharedFiles = 0;
m_bMultiPacket = 0;
md4clr(requpfileid);
m_nTotalUDPPackets = 0;
m_nFailedUDPPackets = 0;
m_nUrlStartPos = (uint64)-1;
m_iHttpSendState = 0;
m_fPeerCache = 0;
m_uPeerCacheDownloadPushId = 0;
m_uPeerCacheUploadPushId = 0;
m_pPCDownSocket = NULL;
m_pPCUpSocket = NULL;
m_uPeerCacheRemoteIP = 0;
m_bPeerCacheDownHit = false;
m_bPeerCacheUpHit = false;
m_fNeedOurPublicIP = 0;
m_random_update_wait = (uint32)(rand()/(RAND_MAX/1000));
//Xman
/*
m_bSourceExchangeSwapped = false; // ZZ:DownloadManager
m_dwLastTriedToConnect = ::GetTickCount()-20*60*1000; // ZZ:DownloadManager
*/
//Xman end
m_fQueueRankPending = 0;
m_fUnaskQueueRankRecv = 0;
m_fFailedFileIdReqs = 0;
//Xman
/*
m_slotNumber = 0;
lastSwapForSourceExchangeTick = 0;
*/
//Xman end
m_pReqFileAICHHash = NULL;
m_fSupportsAICH = 0;
m_fAICHRequested = 0;
m_byKadVersion = 0;
SetLastBuddyPingPongTime();
m_fSentOutOfPartReqs = 0;
m_bCollectionUploadSlot = false;
m_fSupportsLargeFiles = 0;
m_fExtMultiPacket = 0;
m_fRequestsCryptLayer = 0;
m_fSupportsCryptLayer = 0;
m_fRequiresCryptLayer = 0;
m_fSupportsSourceEx2 = 0;
m_fSupportsCaptcha = 0;
m_fDirectUDPCallback = 0;
m_cCaptchasSent = 0;
m_fSupportsFileIdent = 0;
//Xman -----------------
// Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter-
m_displayUpDatarateCounter = 0;
m_displayDownDatarateCounter = 0;
m_nUpDatarate = 0;
m_nUpDatarate10 = 0;
m_nUpDatarateMeasure = 0;
m_nDownDatarate = 0;
m_nDownDatarate10 = 0;
m_nDownDatarateMeasure = 0;
// Maella end
// Maella -Unnecessary Protocol Overload-
CalculateJitteredFileReaskTime(false); //Xman 5.1
m_dwLastAskedTime = 0;
m_dwLastUDPReaskTime = 0;
m_dwNextTCPAskedTime = 0;
// Maella end
//Xman Xtreme Downloadmanager
droptime=0;
isduringswap=false;
enterqueuetime=0;
oldQR=0; //Xman diffQR
//Xman end
// Maella -Extended clean-up II-
m_lastCleanUpCheck = GetTickCount(); //Note: this feature is important for Xtreme Downloadmanager
// Maella end
//Xman Anti-Leecher
m_bLeecher = 0;
old_m_pszUsername.Empty();
m_strBanMessage.Empty();
strBanReason_permament.Empty();
uhashsize=16;
//Xman Anti-Nick-Changer
m_uNickchanges=0;
m_ulastNickChage=0; //no need to initalize
//Xman end
//>>> Anti-XS-Exploit (Xman)
m_uiXSReqs = 0;
m_uiXSAnswer = 0;
//<<< Anti-XS-Exploit
//MORPH START - ReadBlockFromFileThread
m_abyfiledata = NULL;
m_readblockthread =NULL;
//MORPH END - ReadBlockFromFileThread
//Xman Funny-Nick (Stulle/Morph)
m_pszFunnyNick=NULL;
//Xman end
//Xman client percentage
hiscompletedparts_percent_up=-1;
hiscompletedparts_percent_down=-1;
//Xman end
//Xman end --------------
m_uModClient = MOD_NONE; // Mod Icons - Stulle
m_bGiveWaittimeBack = false; // SUQWT [Moonlight/EastShare/ MorphXT] - Stulle
m_bAntiUploaderCaseThree = false; // Anti Uploader Ban [Stulle] - Stulle
m_uSpreadClient = 0; // Spread Credits Slot [Stulle] - Stulle
// ==> requpfile optimization [SiRoB] - Stulle
requpfile = NULL;
requpfileid_lasttimeupdated = 0;
// <== requpfile optimization [SiRoB] - Stulle
m_bScheduleForMoveDown = false; // Superior Client Handling [Stulle] - Stulle
m_bScheduleForRemoval = false; // Schedule blocking clients for removal [Stulle] - Stulle
}
CUpDownClient::~CUpDownClient(){
//MORPH START - ReadBlockFromFileThread //Fafner: for safety (got mem leaks) - 071127
if (m_readblockthread) {
m_readblockthread->StopReadBlock();
m_readblockthread = NULL;
}
//MORPH END - ReadBlockFromFileThread
if (IsAICHReqPending()){
m_fAICHRequested = FALSE;
CAICHRecoveryHashSet::ClientAICHRequestFailed(this);
}
if (GetFriend() != NULL)
{
if (GetFriend()->IsTryingToConnect())
GetFriend()->UpdateFriendConnectionState(FCR_DELETED);
m_Friend->SetLinkedClient(NULL);
}
ASSERT( m_nConnectingState == CCS_NONE || !theApp.emuledlg->IsRunning() );
theApp.clientlist->RemoveClient(this, _T("Destructing client object"));
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();
}
free(m_pszUsername);
if (m_abyPartStatus){ //from MorphXT
delete[] m_abyPartStatus;
m_abyPartStatus = NULL;
}
if (m_abyUpPartStatus){ //from MorphXT
delete[] m_abyUpPartStatus;
m_abyUpPartStatus = NULL;
}
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);
DEBUG_ONLY (theApp.listensocket->Debug_ClientDeleted(this));
SetUploadFileID(NULL);
//Xman
/*
m_fileReaskTimes.RemoveAll(); // ZZ:DownloadManager (one resk timestamp for each file)
*/
//Xman end
delete m_pReqFileAICHHash;
//Xman --------------------
// Maella -Accurate measure of bandwidth: eDonkey data + control, network adapter-
m_upHistory_list.RemoveAll();
m_downHistory_list.RemoveAll();
// Maella -Unnecessary Protocol Overload-
m_partStatusMap.clear();
//Xman end
//Xman Extened credit- table-arragement
if(Credits())
{
Credits()->SetLastSeen(); //ensure we keep the credits at least 6 hours in memory, without this line our LastSeen can be outdated if we did only UDP
//zz_fly :: Optimized on table-arragement :: Enig123 :: Start
/*
if(Credits()->GetDownloadedTotal()==0 && Credits()->GetUploadedTotal()==0) //just to save some CPU-cycles, a second test is done at credits
Credits()->MarkToDelete();
*/
Credits()->DecReferredTimes();
//zz_fly :: End
}
//Xman end
//Xman Funny-Nick (Stulle/Morph)
if (m_pszFunnyNick) {
delete[] m_pszFunnyNick;
m_pszFunnyNick = NULL;
}
//Xman end
//Xman end -----------------
}
void CUpDownClient::ClearHelloProperties()
{
m_nUDPPort = 0;
m_byUDPVer = 0;
m_byDataCompVer = 0;
m_byEmuleVersion = 0;
m_bySourceExchange1Ver = 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;
m_byKadVersion = 0;
m_fSupportsLargeFiles = 0;
m_fExtMultiPacket = 0;
m_fRequestsCryptLayer = 0;
m_fSupportsCryptLayer = 0;
m_fRequiresCryptLayer = 0;
m_fSupportsSourceEx2 = 0;
m_fSupportsCaptcha = 0;
m_fDirectUDPCallback = 0;
m_fSupportsFileIdent = 0;
m_strModVersion.Empty(); //Maella -Support for tag ET_MOD_VERSION 0x55
}
bool CUpDownClient::ProcessHelloPacket(const uchar* pachPacket, uint32 nSize)
{
CSafeMemFile data(pachPacket, nSize);
//Xman Anti-Leecher
/*
data.ReadUInt8(); // read size of userhash
*/
uhashsize=data.ReadUInt8();
//Xman end
// reset all client properties; a client may not send a particular emule tag any longer
ClearHelloProperties();
//Xman Anti-Leecher
/*
return ProcessHelloTypePacket(&data);
*/
return ProcessHelloTypePacket(&data, true);
//Xman end
}
bool CUpDownClient::ProcessHelloAnswer(const uchar* pachPacket, uint32 nSize)
{
//Xman Anti-Leecher
uhashsize=16;
//Xman end
CSafeMemFile data(pachPacket, nSize);
//Xman Anti-Leecher
/*
bool bIsMule = ProcessHelloTypePacket(&data);
*/
bool bIsMule = ProcessHelloTypePacket(&data, false);
//Xman end
m_bHelloAnswerPending = false;
m_bACATHelloAnswerPending = false; //zz_fly :: Client is always highid if we are connecting to them - by Enig123, idea from ACAT
return bIsMule;
}
//Xman Anti-Leecher
/*
bool CUpDownClient::ProcessHelloTypePacket(CSafeMemFile* data)
*/
bool CUpDownClient::ProcessHelloTypePacket(CSafeMemFile* data, bool isHelloPacket)
//Xman end
{
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;
m_bUnicodeSupport = false;
m_uModClient = MOD_NONE; // Mod Icons - Stulle
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);
CString strBanReason; //Xman Anti-Leecher
bool nonofficialopcodes = false; //Xman Anti-Leecher
CString unknownopcode; //Xman Anti-Leecher
bool wronghello = false; //Xman Anti-Leecher
uint32 hellotagorder = 1; //Xman Anti-Leecher
bool foundmd4string = false; //Xman Anti-Leecher
//zz_fly :: Fake Shareaza Detection
bool bWasUDPPortSent = false;
bool bIsFakeShareaza = false;
//zz_fly :: Fake Shareaza Detection end
DWORD dwEmuleTags = 0;
bool bPrTag = false;
uint32 tagcount = data->ReadUInt32();
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T(" Tags=%u"), tagcount);
for (uint32 i = 0; i < tagcount; i++)
{
CTag temptag(data, true);
switch (temptag.GetNameID())
{
case CT_NAME:
if (temptag.IsStr()) {
free(m_pszUsername);
m_pszUsername = _tcsdup(temptag.GetStr());
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("\n Name='%s'"), m_pszUsername);
}
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
//Xman Anti-Leecher
if(hellotagorder!=1)
wronghello=true;
hellotagorder++;
//Xman end
break;
case CT_VERSION:
if (temptag.IsInt()) {
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n Version=%u"), temptag.GetInt());
m_nClientVersion = temptag.GetInt();
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
//Xman Anti-Leecher
if(hellotagorder!=2)
wronghello=true;
hellotagorder++;
//Xman end
break;
case CT_PORT:
if (temptag.IsInt()) {
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n Port=%u"), temptag.GetInt());
nUserPort = (uint16)temptag.GetInt();
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case CT_MOD_VERSION:
if (temptag.IsStr())
{
m_strModVersion = temptag.GetStr();
// ==> Mod Icons - Stulle
if(StrStrI(m_strModVersion,_T("ScarAngel"))!=0)
m_uModClient = MOD_SCAR;
else if(StrStrI(m_strModVersion,_T("StulleMule"))!=0)
m_uModClient = MOD_STULLE;
else if(StrStrI(m_strModVersion,_T("Xtreme"))!=0)
m_uModClient = MOD_XTREME;
else if(StrStrI(m_strModVersion,_T("MorphXT"))!=0)
m_uModClient = MOD_MORPH;
else if(StrStrI(m_strModVersion,_T("EastShare"))!=0)
m_uModClient = MOD_EASTSHARE;
else if(StrStrI(m_strModVersion,_T("eMuleFuture"))!=0)
m_uModClient = MOD_EMF;
else if(StrStrI(m_strModVersion,_T("Neo Mule"))!=0)
m_uModClient = MOD_NEO;
else if(StrStrI(m_strModVersion,_T("Mephisto"))!=0)
m_uModClient = MOD_MEPHISTO;
else if(StrStrI(m_strModVersion,_T("X-Ray"))!=0)
m_uModClient = MOD_XRAY;
else if(StrStrI(m_strModVersion,_T("Magic Angel"))!=0)
m_uModClient = MOD_MAGIC;
else
m_uModClient = MOD_NONE;
// <== Mod Icons - Stulle
}
else if (temptag.IsInt())
m_strModVersion.Format(_T("ModID=%u"), temptag.GetInt());
else
m_strModVersion = _T("ModID=");
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ModID=%s"), m_strModVersion);
CheckForGPLEvilDoer();
break;
case CT_EMULE_UDPPORTS:
// 16 KAD Port
// 16 UDP Port
if (temptag.IsInt()) {
m_nKadPort = (uint16)(temptag.GetInt() >> 16);
m_nUDPPort = (uint16)temptag.GetInt();
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n KadPort=%u UDPPort=%u"), m_nKadPort, m_nUDPPort);
dwEmuleTags |= 1;
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
bWasUDPPortSent = true; //zz_fly :: Fake Shareaza Detection
break;
case CT_EMULE_BUDDYUDP:
// 16 --Reserved for future use--
// 16 BUDDY Port
if (temptag.IsInt()) {
m_nBuddyPort = (uint16)temptag.GetInt();
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n BuddyPort=%u"), m_nBuddyPort);
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case CT_EMULE_BUDDYIP:
// 32 BUDDY IP
if (temptag.IsInt()) {
m_nBuddyIP = temptag.GetInt();
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n BuddyIP=%s"), ipstr(m_nBuddyIP));
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case CT_EMULE_MISCOPTIONS1:
// 3 AICH Version (0 = not supported)
// 1 Unicode
// 4 UDP version
// 4 Data compression version
// 4 Secure Ident
// 4 Source Exchange - deprecated
// 4 Ext. Requests
// 4 Comments
// 1 PeerChache supported
// 1 No 'View Shared Files' supported
// 1 MultiPacket - deprecated with FileIdentifiers/MultipacketExt2
// 1 Preview
if (temptag.IsInt()) {
m_fSupportsAICH = (temptag.GetInt() >> 29) & 0x07;
m_bUnicodeSupport = (temptag.GetInt() >> 28) & 0x01;
m_byUDPVer = (uint8)((temptag.GetInt() >> 24) & 0x0f);
m_byDataCompVer = (uint8)((temptag.GetInt() >> 20) & 0x0f);
m_bySupportSecIdent = (uint8)((temptag.GetInt() >> 16) & 0x0f);
m_bySourceExchange1Ver = (uint8)((temptag.GetInt() >> 12) & 0x0f);
m_byExtendedRequestsVer = (uint8)((temptag.GetInt() >> 8) & 0x0f);
m_byAcceptCommentVer = (uint8)((temptag.GetInt() >> 4) & 0x0f);
m_fPeerCache = (temptag.GetInt() >> 3) & 0x01;
m_fNoViewSharedFiles = (temptag.GetInt() >> 2) & 0x01;
m_bMultiPacket = (temptag.GetInt() >> 1) & 0x01;
m_fSupportsPreview = (temptag.GetInt() >> 0) & 0x01;
dwEmuleTags |= 2;
if (bDbgInfo) {
m_strHelloInfo.AppendFormat(_T("\n PeerCache=%u UDPVer=%u DataComp=%u SecIdent=%u SrcExchg=%u")
_T(" ExtReq=%u Commnt=%u Preview=%u NoViewFiles=%u Unicode=%u"),
m_fPeerCache, m_byUDPVer, m_byDataCompVer, m_bySupportSecIdent, m_bySourceExchange1Ver,
m_byExtendedRequestsVer, m_byAcceptCommentVer, m_fSupportsPreview, m_fNoViewSharedFiles, m_bUnicodeSupport);
//Xman
#ifdef LOGTAG
m_strHelloInfo.AppendFormat(_T("\n m_fSupportsAICH=%u"), m_fSupportsAICH);
#endif
//Xman end
}
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
//zz_fly :: Fake Shareaza Detection
if(!bWasUDPPortSent && !bIsFakeShareaza)
bIsFakeShareaza = true;
//zz_fly :: Fake Shareaza Detection end
break;
case CT_EMULE_MISCOPTIONS2:
// 18 Reserved
// 1 Supports new FileIdentifiers/MultipacketExt2
// 1 Direct UDP Callback supported and available
// 1 Supports ChatCaptchas
// 1 Supports SourceExachnge2 Packets, ignores SX1 Packet Version
// 1 Requires CryptLayer
// 1 Requests CryptLayer
// 1 Supports CryptLayer
// 1 Reserved (ModBit)
// 1 Ext Multipacket (Hash+Size instead of Hash) - deprecated with FileIdentifiers/MultipacketExt2
// 1 Large Files (includes support for 64bit tags)
// 4 Kad Version - will go up to version 15 only (may need to add another field at some point in the future)
if (temptag.IsInt()) {
m_fSupportsFileIdent = (temptag.GetInt() >> 13) & 0x01;
m_fDirectUDPCallback = (temptag.GetInt() >> 12) & 0x01;
m_fSupportsCaptcha = (temptag.GetInt() >> 11) & 0x01;
m_fSupportsSourceEx2 = (temptag.GetInt() >> 10) & 0x01;
m_fRequiresCryptLayer = (temptag.GetInt() >> 9) & 0x01;
m_fRequestsCryptLayer = (temptag.GetInt() >> 8) & 0x01;
m_fSupportsCryptLayer = (temptag.GetInt() >> 7) & 0x01;
// reserved 1
m_fExtMultiPacket = (temptag.GetInt() >> 5) & 0x01;
m_fSupportsLargeFiles = (temptag.GetInt() >> 4) & 0x01;
m_byKadVersion = (uint8)((temptag.GetInt() >> 0) & 0x0f);
dwEmuleTags |= 8;
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n KadVersion=%u, LargeFiles=%u ExtMultiPacket=%u CryptLayerSupport=%u CryptLayerRequest=%u CryptLayerRequires=%u SupportsSourceEx2=%u SupportsCaptcha=%u DirectUDPCallback=%u"), m_byKadVersion, m_fSupportsLargeFiles, m_fExtMultiPacket, m_fSupportsCryptLayer, m_fRequestsCryptLayer, m_fRequiresCryptLayer, m_fSupportsSourceEx2, m_fSupportsCaptcha, m_fDirectUDPCallback);
m_fRequestsCryptLayer &= m_fSupportsCryptLayer;
m_fRequiresCryptLayer &= m_fRequestsCryptLayer;
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
//zz_fly :: Fake Shareaza Detection
if(!bWasUDPPortSent && !bIsFakeShareaza)
bIsFakeShareaza = true;
//zz_fly :: Fake Shareaza Detection end
break;
case CT_EMULE_VERSION:
// 8 Compatible Client ID
// 7 Mjr Version (Doesn't really matter..)
// 7 Min Version (Only need 0-99)
// 3 Upd Version (Only need 0-5)
// 7 Bld Version (Only need 0-99) -- currently not used
if (temptag.IsInt()) {
m_byCompatibleClient = (uint8)((temptag.GetInt() >> 24));
m_nClientVersion = temptag.GetInt() & 0x00ffffff;
m_byEmuleVersion = 0x99;
m_fSharedDirectories = 1;
dwEmuleTags |= 4;
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ClientVer=%u.%u.%u.%u Comptbl=%u"), (m_nClientVersion >> 17) & 0x7f, (m_nClientVersion >> 10) & 0x7f, (m_nClientVersion >> 7) & 0x07, m_nClientVersion & 0x7f, m_byCompatibleClient);
}
else if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
//Xman Anti-Leecher
case 0x69: //Webcache WC_TAG_VOODOO
case 0x6A: //Webcache WC_TAG_FLAGS
case 0x3D: //ICS
//zz_fly :: Anti-Leehcer
case 0xEE: //VeryCD L2L protocol tag
case 0x3E: //X-Ray L2HAC tag
//zz_fly :: Anti-Leehcer end
nonofficialopcodes=true; //Xman Anti-Leecher
break;
//Xman end
default:
//Xman Anti-Leecher
if(thePrefs.GetAntiLeecherSnafu())
if(ProcessUnknownHelloTag(&temptag, strBanReason))
foundmd4string=true;
unknownopcode.AppendFormat(_T(",%s"),temptag.GetFullInfo());
//Xman end
// Since eDonkeyHybrid 1.3 is no longer sending the additional Int32 at the end of the Hello packet,
// we use the "pr=1" tag to determine them.
if (temptag.GetName() && temptag.GetName()[0]=='p' && temptag.GetName()[1]=='r') {
bPrTag = true;
}
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***UnkTag=%s"), temptag.GetFullInfo());
}
}
m_nUserPort = nUserPort;
m_dwServerIP = data->ReadUInt32();
m_nServerPort = data->ReadUInt16();
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n Server=%s:%u"), ipstr(m_dwServerIP), m_nServerPort);
// Check for additional data in Hello packet to determine client's software version.
//
// *) eDonkeyHybrid 0.40 - 1.2 sends an additional Int32. (Since 1.3 they don't send it any longer.)
// *) MLdonkey sends an additional Int32
//
if (data->GetLength() - data->GetPosition() == sizeof(uint32)){
uint32 test = data->ReadUInt32();
if (test == 'KDLM'){
m_bIsML = true;
if (bDbgInfo)
m_strHelloInfo += _T("\n ***AddData: \"MLDK\"");
}
else{
m_bIsHybrid = true;
if (bDbgInfo)
m_strHelloInfo.AppendFormat(_T("\n ***AddData: uint32=%u (0x%08x)"), test, test);
}
}
else if (bDbgInfo && data->GetPosition() < data->GetLength()){
UINT uAddHelloDataSize = (UINT)(data->GetLength() - data->GetPosition());
if (uAddHelloDataSize == sizeof(uint32)){
DWORD dwAddHelloInt32 = data->ReadUInt32();
m_strHelloInfo.AppendFormat(_T("\n ***AddData: uint32=%u (0x%08x)"), dwAddHelloInt32, dwAddHelloInt32);
}
else if (uAddHelloDataSize == sizeof(uint32)+sizeof(uint16)){
DWORD dwAddHelloInt32 = data->ReadUInt32();
WORD w = data->ReadUInt16();
m_strHelloInfo.AppendFormat(_T("\n ***AddData: uint32=%u (0x%08x), uint16=%u (0x%04x)"), dwAddHelloInt32, dwAddHelloInt32, w, w);
}
else
m_strHelloInfo.AppendFormat(_T("\n ***AddData: %u bytes"), uAddHelloDataSize);
}
//Xman IP to Country
uint32 oldIP=m_dwUserIP;
//Xman end
SOCKADDR_IN sockAddr = {0};
int nSockAddrLen = sizeof(sockAddr);
socket->GetPeerName((SOCKADDR*)&sockAddr, &nSockAddrLen);
SetIP(sockAddr.sin_addr.S_un.S_addr);
//Xman IP to Country
//only search if changed, it's cheaper
//EastShare Start - added by AndCycle, IP to Country
if(oldIP!=m_dwUserIP)
m_structUserCountry = theApp.ip2country->GetCountryFromIP(m_dwUserIP);
//EastShare End - added by AndCycle, IP to Country
if (thePrefs.GetAddServersFromClients() && m_dwServerIP && m_nServerPort){
CServer* addsrv = new CServer(m_nServerPort, ipstr(m_dwServerIP));
addsrv->SetListName(addsrv->GetAddress());
addsrv->SetPreference(SRV_PR_LOW);
if (!theApp.emuledlg->serverwnd->serverlistctrl.AddServer(addsrv, true))
delete addsrv;
}
//(a)If this is a highID user, store the ID in the Hybrid format.
//(b)Some older clients will not send a ID, these client are HighID users that are not connected to a server.
//(c)Kad users with a *.*.*.0 IPs will look like a lowID user they are actually a highID user.. They can be detected easily
//because they will send a ID that is the same as their IP..
//zz_fly :: Client is always highid if we are connecting to them - by Enig123, idea from ACAT
//note: if we can receive his hello answer, whatever the situation is, he must be a HighID.
// if we and he send hello packet concurrent, only one instance will survive. this fix will not cause trouble in this case.
/*
if(!HasLowID() || m_nUserIDHybrid == 0 || m_nUserIDHybrid == m_dwUserIP )
*/
if(!HasLowID() || m_nUserIDHybrid == 0 || m_nUserIDHybrid == m_dwUserIP || m_bACATHelloAnswerPending)
//zz_fly :: end
m_nUserIDHybrid = ntohl(m_dwUserIP);
//zz_fly :: Optimized on table-arragement :: Enig123 :: Start
//note: do not create credit in memory when we going to ban the client
/*
CClientCredits* pFoundCredits = theApp.clientcredits->GetCredit(m_achUserHash);
*/
//zz_fly :: End
if (credits == NULL){
//zz_fly :: Optimized on table-arragement :: Enig123 :: Start
/*
credits = pFoundCredits;
*/
//zz_fly :: End
//Xman Extened credit- table-arragement
/*
if (!theApp.clientlist->ComparePriorUserhash(m_dwUserIP, m_nUserPort, pFoundCredits)){
if (thePrefs.GetLogBannedClients())
AddDebugLogLine(false, _T("Clients: %s (%s), Banreason: Userhash changed (Found in TrackedClientsList)"), GetUserName(), ipstr(GetConnectIP()));
*/
if (!theApp.clientlist->ComparePriorUserhash(m_dwUserIP, m_nUserPort, m_achUserHash)){
AddLeecherLogLine(false, _T("Clients: %s (%s), Banreason: Userhash changed (Found in TrackedClientsList)"), GetUserName(), ipstr(GetConnectIP()));
//Xman end
Ban();
}
//zz_fly :: Optimized on table-arragement :: Enig123 :: Start
else if (GetUploadState()!=US_BANNED){
credits = theApp.clientcredits->GetCredit(m_achUserHash);
}
//zz_fly :: End
}
//zz_fly :: Optimized on table-arragement :: Enig123 :: Start
/*
else if (credits != pFoundCredits){
*/
else if (md4cmp(credits->GetKey(), m_achUserHash)){
//zz_fly :: End
//Xman Extened credit- table-arragement
credits->SetLastSeen(); //ensure to keep it at least 5 hours
//zz_fly :: Optimized on table-arragement :: Enig123 :: Start
/*
if(credits->GetUploadedTotal()==0 && credits->GetDownloadedTotal()==0)
credits->MarkToDelete(); //check also if the old hash is used by an other client
*/
credits->DecReferredTimes(); //check also if the old hash is used by an other client
//zz_fly :: End
//Xman end
// userhash change ok, however two hours "waittime" before it can be used
//zz_fly :: Optimized on table-arragement :: Enig123 :: Start
/*
credits = pFoundCredits;
*/
credits = NULL;
//zz_fly :: End
//Xman Extened credit- table-arragement
/*
if (thePrefs.GetLogBannedClients())
AddDebugLogLine(false, _T("Clients: %s (%s), Banreason: Userhash changed"), GetUserName(), ipstr(GetConnectIP()));
*/
AddLeecherLogLine(false, _T("Clients: %s (%s), Banreason: Userhash changed"), GetUserName(), ipstr(GetConnectIP()));
//Xman end
Ban();
}
//zz_fly :: Optimized on table-arragement :: Enig123 :: Start
else {
credits->SetLastSeen(); //Enig123::refresh is neccessary here to avoid wrong judgement
}
//zz_fly :: End
if (GetFriend() != NULL && GetFriend()->HasUserhash() && md4cmp(GetFriend()->m_abyUserhash, m_achUserHash) != 0)
{
// this isnt our friend anymore and it will be removed/replaced, tell our friendobject about it
if (GetFriend()->IsTryingToConnect())
GetFriend()->UpdateFriendConnectionState(FCR_USERHASHFAILED); // this will remove our linked friend
else
GetFriend()->SetLinkedClient(NULL);
}
// do not replace friendobjects which have no userhash, but the fitting ip with another friend object with the
// fitting userhash (both objects would fit to this instance), as this could lead to unwanted results
if (GetFriend() == NULL || GetFriend()->HasUserhash() || GetFriend()->m_dwLastUsedIP != GetConnectIP()
|| GetFriend()->m_nLastUsedPort != GetUserPort())
{
//zz_fly :: minor issue with friends handling :: WiZaRd :: start
/*
if ((m_Friend = theApp.friendlist->SearchFriend(m_achUserHash, m_dwUserIP, m_nUserPort)) != NULL){
*/
if ((m_Friend = theApp.friendlist->SearchFriend(m_achUserHash, GetConnectIP(), m_nUserPort)) != NULL){
//zz_fly :: end
// Link the friend to that client
m_Friend->SetLinkedClient(this);
}
else{
// avoid that an unwanted client instance keeps a friend slot
SetFriendSlot(false);
}
}
else{
// however, copy over our userhash in this case
md4cpy(GetFriend()->m_abyUserhash, m_achUserHash);
}
// check for known major gpl breaker
CString strBuffer = m_pszUsername;
strBuffer.MakeUpper();
strBuffer.Remove(_T(' '));
if (strBuffer.Find(_T("EMULE-CLIENT")) != -1 || strBuffer.Find(_T("POWERMULE")) != -1 ){
m_bGPLEvildoer = true;
}
m_byInfopacketsReceived |= IP_EDONKEYPROTPACK;
// check if at least CT_EMULEVERSION was received, all other tags are optional
bool bIsMule = (dwEmuleTags & 0x04) == 0x04;
if (bIsMule){
m_bEmuleProtocol = true;
m_byInfopacketsReceived |= IP_EMULEPROTPACK;
}
else if (bPrTag){
m_bIsHybrid = true;
}
InitClientSoftwareVersion();
if (m_bIsHybrid)
m_fSharedDirectories = 1;
if (thePrefs.GetVerbose() && GetServerIP() == INADDR_NONE)
AddDebugLogLine(false, _T("Received invalid server IP %s from %s"), ipstr(GetServerIP()), DbgGetClientInfo());
//Xman Anti-Leecher
if(thePrefs.GetAntiLeecher())
{
if (theApp.GetID()!=m_nUserIDHybrid && memcmp(m_achUserHash, thePrefs.GetUserHash(), 16)==0)
{
strBanReason = _T("Anti Credit Hack");
BanLeecher(strBanReason,9);
return bIsMule;
}
if(strBanReason.IsEmpty()==false && thePrefs.GetAntiLeecherSnafu())
{
BanLeecher(strBanReason,2); //snafu = old leecher = hard ban
return bIsMule;
}
if(foundmd4string && thePrefs.GetAntiLeecherSnafu())
{
strBanReason = _T("md4-string in opcode");
BanLeecher(strBanReason, 15);
return bIsMule;
}
//zz_fly :: Fake Shareaza Detection
//note: clients based on Shareaza send UDPPort tag AFTER Misc Options tag
if(bIsFakeShareaza && m_clientSoft==SO_EMULE)
{
strBanReason = _T("Fake emuleVersion");
BanLeecher(strBanReason,9);
return bIsMule;
}
//zz_fly :: Fake Shareaza Detection end
if(thePrefs.GetAntiLeecherBadHello() && (m_clientSoft==SO_EMULE || (m_clientSoft==SO_XMULE && m_byCompatibleClient!=SO_XMULE)))
{
if(wronghello)
{
strBanReason= _T("wrong hello order");
BanLeecher(strBanReason,1); //these are Leechers of a big german Leechercommunity
return bIsMule;
}
if(data->GetPosition() < data->GetLength())
{
strBanReason= _T("extra bytes");
BanLeecher(strBanReason,13); // darkmule (or buggy)
return bIsMule;
}
if(uhashsize!=16)
{
strBanReason= _T("wrong Hashsize");
BanLeecher(strBanReason,14); //new united community
return bIsMule;
}
if(m_fSupportsAICH > 1 && m_clientSoft == SO_EMULE && m_nClientVersion <= MAKE_CLIENT_VERSION(CemuleApp::m_nVersionMjr, CemuleApp::m_nVersionMin, CemuleApp::m_nVersionUpd))
{
strBanReason= _T("Applejuice");
BanLeecher(strBanReason,17); //Applejuice
return bIsMule;
}
}
//if it is now a good mod, remove the reducing of score but do a second test
if(IsLeecher()==1 || IsLeecher()==15) //category 2 is snafu and always a hard ban, need only to check 1
{
m_bLeecher=0; //it's a good mod now
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
old_m_strClientSoftwareFULL.Empty(); //force recheck
old_m_pszUsername.Empty();
}
if(IsLeecher()==14 && isHelloPacket) //check if it is a Hello-Packet
{
m_bLeecher=0; //it's a good mod now
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
old_m_strClientSoftwareFULL.Empty(); //force recheck
old_m_pszUsername.Empty();
}
if(IsLeecher()==17)
{
m_bLeecher=0; //it's a good mod now
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
old_m_strClientSoftwareFULL.Empty(); //force recheck
old_m_pszUsername.Empty();
}
TestLeecher(); //test for modstring, nick and thiefs
if(thePrefs.GetAntiLeecheremcrypt())
{
//Xman remark: I only check for 0.44d.
if(m_nClientVersion == MAKE_CLIENT_VERSION(0,44,3) && m_strModVersion.IsEmpty() && m_byCompatibleClient==0 && m_bUnicodeSupport==false && bIsMule)
{
if(IsLeecher()==0)
{
strBanReason = _T("emcrypt");
BanLeecher(strBanReason,12); // emcrypt = no unicode for unicode version
}
}
else if(IsLeecher()==12)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, it isn't any longer a emcrypt
}
}
else if(IsLeecher()==12)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, user doesn't want to ban it anymore
}
if(thePrefs.GetAntiGhost() )
{
if(m_strModVersion.IsEmpty() &&
((nonofficialopcodes==true && GetClientSoft()!=SO_LPHANT)
|| ((unknownopcode.IsEmpty()==false || m_byAcceptCommentVer > 1) && m_clientSoft == SO_EMULE && m_nClientVersion <= MAKE_CLIENT_VERSION(CemuleApp::m_nVersionMjr, CemuleApp::m_nVersionMin, CemuleApp::m_nVersionUpd)))
)
{
if(IsLeecher()==0)
{
strBanReason = _T("GhostMod");
if(unknownopcode.IsEmpty()==false)
strBanReason += _T(" ") + unknownopcode;
BanLeecher(strBanReason,3); // ghost mod = webcache tag without modstring
}
}
else if(IsLeecher()==3)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, it isn't any longer a ghost mod
}
}
else if(IsLeecher()==3)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, user doesn't want to ban it anymore
}
}
else if(IsLeecher()>0)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, user doesn't want to ban it anymore
}
//Xman end
UpdateFunnyNick(); //Xman Funny-Nick (Stulle/Morph)
return bIsMule;
}
void CUpDownClient::SendHelloPacket(){
if (socket == NULL){
ASSERT(0);
return;
}
CSafeMemFile data(128);
data.WriteUInt8(16); // size of userhash
SendHelloTypePacket(&data);
Packet* packet = new Packet(&data);
packet->opcode = OP_HELLO;
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__Hello", this);
theStats.AddUpDataOverheadOther(packet->size);
SendPacket(packet, true);
m_bHelloAnswerPending = true;
m_bACATHelloAnswerPending = true; //zz_fly :: Client is always highid if we are connecting to them - by Enig123, idea from ACAT
return;
}
void CUpDownClient::SendMuleInfoPacket(bool bAnswer){
if (socket == NULL){
ASSERT(0);
return;
}
CSafeMemFile data(128);
data.WriteUInt8((uint8)theApp.m_uCurVersionShort);
data.WriteUInt8(EMULE_PROTOCOL);
//Xman
// Maella -Support for tag ET_MOD_VERSION 0x55-
/*
data.WriteUInt32(7); // nr. of tags
*/
uint32 tagcount = 7;
//Added by SiRoB, Don't send MOD_VERSION to client that don't support it to reduce overhead
bool bSendModVersion = m_strModVersion.GetLength() || m_pszUsername==NULL;
if (bSendModVersion)
tagcount +=1;
data.WriteUInt32(tagcount); // nr. of tags
// Maella end
CTag tag(ET_COMPRESSION,1);
tag.WriteTagToFile(&data);
CTag tag2(ET_UDPVER,4);
tag2.WriteTagToFile(&data);
CTag tag3(ET_UDPPORT,thePrefs.GetUDPPort());
tag3.WriteTagToFile(&data);
CTag tag4(ET_SOURCEEXCHANGE,3);
tag4.WriteTagToFile(&data);
CTag tag5(ET_COMMENTS,1);
tag5.WriteTagToFile(&data);
CTag tag6(ET_EXTENDEDREQUEST,2);
tag6.WriteTagToFile(&data);
uint32 dwTagValue = (theApp.clientcredits->CryptoAvailable() ? 3 : 0);
if (thePrefs.CanSeeShares() != vsfaNobody) // set 'Preview supported' only if 'View Shared Files' allowed
dwTagValue |= 128;
CTag tag7(ET_FEATURES, dwTagValue);
tag7.WriteTagToFile(&data);
//Xman
// Maella -Support for tag ET_MOD_VERSION 0x55-
if (bSendModVersion){
// ==> ModID [itsonlyme/SiRoB] - Stulle
/*
CTag tag8(ET_MOD_VERSION, MOD_VERSION);
*/
CTag tag8(ET_MOD_VERSION, theApp.m_strModVersion);
// <== ModID [itsonlyme/SiRoB] - Stulle
tag8.WriteTagToFile(&data);
}
// Maella end
Packet* packet = new Packet(&data,OP_EMULEPROT);
if (!bAnswer)
packet->opcode = OP_EMULEINFO;
else
packet->opcode = OP_EMULEINFOANSWER;
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend(!bAnswer ? "OP__EmuleInfo" : "OP__EmuleInfoAnswer", this);
theStats.AddUpDataOverheadOther(packet->size);
SendPacket(packet, true);
}
void CUpDownClient::ProcessMuleInfoPacket(const uchar* pachPacket, uint32 nSize)
{
bool bDbgInfo = thePrefs.GetUseDebugDevice();
m_strMuleInfo.Empty();
CString strBanReason = NULL; //Xman Anti-Leecher
bool nonofficialopcodes = false; //Xman Anti-Leecher
CSafeMemFile data(pachPacket, nSize);
m_byCompatibleClient = 0;
m_byEmuleVersion = data.ReadUInt8();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("EmuleVer=0x%x"), (UINT)m_byEmuleVersion);
if (m_byEmuleVersion == 0x2B)
m_byEmuleVersion = 0x22;
uint8 protversion = data.ReadUInt8();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T(" ProtVer=%u"), (UINT)protversion);
//implicitly supported options by older clients
if (protversion == EMULE_PROTOCOL) {
//in the future do not use version to guess about new features
if (m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x22)
m_byUDPVer = 1;
if (m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x21)
m_bySourceExchange1Ver = 1;
if (m_byEmuleVersion == 0x24)
m_byAcceptCommentVer = 1;
// Shared directories are requested from eMule 0.28+ because eMule 0.27 has a bug in
// the OP_ASKSHAREDFILESDIR handler, which does not return the shared files for a
// directory which has a trailing backslash.
if (m_byEmuleVersion >= 0x28 && !m_bIsML) // MLdonkey currently does not support shared directories
m_fSharedDirectories = 1;
} else {
return;
}
uint32 tagcount = data.ReadUInt32();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T(" Tags=%u"), (UINT)tagcount);
for (uint32 i = 0; i < tagcount; i++)
{
CTag temptag(&data, false);
switch (temptag.GetNameID())
{
case ET_COMPRESSION:
// Bits 31- 8: 0 - reserved
// Bits 7- 0: data compression version
if (temptag.IsInt()) {
m_byDataCompVer = (uint8)temptag.GetInt();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n Compr=%u"), (UINT)temptag.GetInt());
}
else if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case ET_UDPPORT:
// Bits 31-16: 0 - reserved
// Bits 15- 0: UDP port
if (temptag.IsInt()) {
m_nUDPPort = (uint16)temptag.GetInt();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n UDPPort=%u"), (UINT)temptag.GetInt());
}
else if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case ET_UDPVER:
// Bits 31- 8: 0 - reserved
// Bits 7- 0: UDP protocol version
if (temptag.IsInt()) {
m_byUDPVer = (uint8)temptag.GetInt();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n UDPVer=%u"), (UINT)temptag.GetInt());
}
else if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case ET_SOURCEEXCHANGE:
// Bits 31- 8: 0 - reserved
// Bits 7- 0: source exchange protocol version
if (temptag.IsInt()) {
m_bySourceExchange1Ver = (uint8)temptag.GetInt();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n SrcExch=%u"), (UINT)temptag.GetInt());
}
else if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case ET_COMMENTS:
// Bits 31- 8: 0 - reserved
// Bits 7- 0: comments version
if (temptag.IsInt()) {
m_byAcceptCommentVer = (uint8)temptag.GetInt();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n Commnts=%u"), (UINT)temptag.GetInt());
}
else if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case ET_EXTENDEDREQUEST:
// Bits 31- 8: 0 - reserved
// Bits 7- 0: extended requests version
if (temptag.IsInt()) {
m_byExtendedRequestsVer = (uint8)temptag.GetInt();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ExtReq=%u"), (UINT)temptag.GetInt());
}
else if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case ET_COMPATIBLECLIENT:
// Bits 31- 8: 0 - reserved
// Bits 7- 0: compatible client ID
if (temptag.IsInt()) {
m_byCompatibleClient = (uint8)temptag.GetInt();
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n Comptbl=%u"), (UINT)temptag.GetInt());
}
else if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case ET_FEATURES:
// Bits 31- 8: 0 - reserved
// Bit 7: Preview
// Bit 6- 0: secure identification
if (temptag.IsInt()) {
m_bySupportSecIdent = (uint8)((temptag.GetInt()) & 3);
m_fSupportsPreview = (temptag.GetInt() >> 7) & 1;
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n SecIdent=%u Preview=%u"), m_bySupportSecIdent, m_fSupportsPreview);
}
else if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkType=%s"), temptag.GetFullInfo());
break;
case ET_MOD_VERSION:
if (temptag.IsStr())
{
m_strModVersion = temptag.GetStr();
// ==> Mod Icons - Stulle
if(StrStrI(m_strModVersion,_T("ScarAngel"))!=0)
m_uModClient = MOD_SCAR;
else if(StrStrI(m_strModVersion,_T("StulleMule"))!=0)
m_uModClient = MOD_STULLE;
else if(StrStrI(m_strModVersion,_T("Xtreme"))!=0)
m_uModClient = MOD_XTREME;
else if(StrStrI(m_strModVersion,_T("MorphXT"))!=0)
m_uModClient = MOD_MORPH;
else if(StrStrI(m_strModVersion,_T("EastShare"))!=0)
m_uModClient = MOD_EASTSHARE;
else if(StrStrI(m_strModVersion,_T("eMuleFuture"))!=0)
m_uModClient = MOD_EMF;
else if(StrStrI(m_strModVersion,_T("Neo Mule"))!=0)
m_uModClient = MOD_NEO;
else if(StrStrI(m_strModVersion,_T("Mephisto"))!=0)
m_uModClient = MOD_MEPHISTO;
else if(StrStrI(m_strModVersion,_T("X-Ray"))!=0)
m_uModClient = MOD_XRAY;
else if(StrStrI(m_strModVersion,_T("Magic Angel"))!=0)
m_uModClient = MOD_MAGIC;
else
m_uModClient = MOD_NONE;
// <== Mod Icons - Stulle
}
else if (temptag.IsInt())
m_strModVersion.Format(_T("ModID=%u"), temptag.GetInt());
else
m_strModVersion = _T("ModID=");
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ModID=%s"), m_strModVersion);
CheckForGPLEvilDoer();
break;
//Xman Anti-Leecher
case 0x3D: //ICS
nonofficialopcodes=true; //Xman Anti-Leecher
break;
//Xman end
default:
//Xman Anti-Leecher
if(thePrefs.GetAntiLeecher())
ProcessUnknownInfoTag(&temptag, strBanReason);
//Xman end
if (bDbgInfo)
m_strMuleInfo.AppendFormat(_T("\n ***UnkTag=%s"), temptag.GetFullInfo());
}
}
if (m_byDataCompVer == 0) {
m_bySourceExchange1Ver = 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());
}
m_bEmuleProtocol = true;
m_byInfopacketsReceived |= IP_EMULEPROTPACK;
InitClientSoftwareVersion();
if (thePrefs.GetVerbose() && GetServerIP() == INADDR_NONE)
AddDebugLogLine(false, _T("Received invalid server IP %s from %s"), ipstr(GetServerIP()), DbgGetClientInfo());
//Xman Anti-Leecher
if(thePrefs.GetAntiLeecher())
{
if(strBanReason.IsEmpty()==false && thePrefs.GetAntiLeecherSnafu())
{
BanLeecher(strBanReason,2); //snafu = old leecher = hard ban
return;
}
TestLeecher(); //test for modstring (older clients send it with the MuleInfoPacket
if(thePrefs.GetAntiGhost() )
{
if(nonofficialopcodes==true && m_strModVersion.IsEmpty() && GetClientSoft()!=SO_LPHANT)
{
if(IsLeecher()==0)
{
strBanReason = _T("GhostMod");
BanLeecher(strBanReason,3); // ghost mod = webcache tag without modstring
}
}
else if(IsLeecher()==3)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, it isn't any longer a ghost mod
}
}
else if(IsLeecher()==3)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, user doesn't want to ban it anymore
}
}
else if(IsLeecher()>0)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, user doesn't want to ban it anymore
}
//Xman end
}
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);
// Servers send a FIN right in the data packet on check connection, so we need to force the response immediate
bool bForceSend = theApp.serverconnect->AwaitingTestFromIP(GetConnectIP());
socket->SendPacket(packet, true, true, 0, bForceSend);
m_bHelloAnswerPending = false;
}
void CUpDownClient::SendHelloTypePacket(CSafeMemFile* data)
{
// ==> Emulate others [WiZaRd/Spike/shadow2004] - Stulle
/*
data->WriteHash16(thePrefs.GetUserHash());
*/
uchar hash[16];
memcpy(hash,thePrefs.GetUserHash(), 16);
if (thePrefs.IsEmuMLDonkey() && GetClientSoft() == SO_MLDONKEY)
{
// if(GetHashType() == SO_OLD_MLDONKEY)
{
hash[5] = 'M'; //WiZaRd::Proper Hash Fake :P
hash[14] = 'L'; //WiZaRd::Proper Hash Fake :P
if (thePrefs.IsEmuLog())
AddDebugLogLine(false,_T("[EMULATE] Emulate MLDonkey (%s)"),DbgGetClientInfo());
}
}
else if ((thePrefs.IsEmueDonkey() && GetClientSoft() == SO_EDONKEY)
|| (thePrefs.IsEmueDonkeyHybrid() && GetClientSoft() == SO_EDONKEYHYBRID))
{
uint8 random = (uint8)(rand()%_UI8_MAX); //Spike2, avoid C4244
hash[5] = random == 14 ? random+1 : random; //WiZaRd::Avoid eMule Hash
random = (uint8)(rand()%_UI8_MAX); //Spike2, avoid C4244
hash[14] = random == 111 ? random+1 : random; //WiZaRd::Avoid eMule Hash
if (thePrefs.IsEmuLog())
{
if(GetClientSoft() == SO_EDONKEY)
AddDebugLogLine(false,_T("[EMULATE] Emulate eDonkey (%s)"),DbgGetClientInfo());
else if(GetClientSoft() == SO_EDONKEYHYBRID)
AddDebugLogLine(false,_T("[EMULATE] Emulate eDonkeyHybrid (%s)"),DbgGetClientInfo());
}
}
data->WriteHash16(hash);
// <== Emulate others [WiZaRd/Spike/shadow2004] - Stulle
uint32 clientid;
clientid = theApp.GetID();
data->WriteUInt32(clientid);
data->WriteUInt16(thePrefs.GetPort());
uint32 tagcount = 6;
if( theApp.clientlist->GetBuddy() && theApp.IsFirewalled() )
tagcount += 2;
//Xman ModID
//Xman - Added by SiRoB, Don't send MOD_VERSION to client that don't support it to reduce overhead
//Xman send modtring only to non Leechers or Modthiefs
bool bSendModVersion = (m_strModVersion.GetLength() || m_pszUsername==NULL) && (IsLeecher()==0 || IsLeecher()==6);
if (bSendModVersion) tagcount+=1;
//Xman END - Added by SiRoB, Don't send MOD_VERSION to client that don't support it to reduce overhead
data->WriteUInt32(tagcount);
// eD2K Name
// TODO implement multi language website which informs users of the effects of bad mods
//Xman Anti-Leecher
/*
CTag tagName(CT_NAME, (!m_bGPLEvildoer) ? thePrefs.GetUserNick() : _T("Please use a GPL-conform version of eMule") );
tagName.WriteTagToFile(data, utf8strRaw);
*/
if(IsLeecher()==12)
{
//emcrypt
CTag tagName(CT_NAME, _T("You are using a spyware infected emule version") );
tagName.WriteTagToFile(data, utf8strRaw);
}
//Xman send Nickaddon only to non Leechers or NickThiefs/ModThiefs
else if(IsLeecher()==0 || IsLeecher()==11 || IsLeecher()==6)
{
// ==> ModID [itsonlyme/SiRoB] - Stulle
/*
CTag tagName(CT_NAME, (!m_bGPLEvildoer) ? thePrefs.GetUserNick() + _T(' ') + str_ANTAddOn + MOD_NICK_ADD : _T("Please use a GPL-conform version of eMule") ); //Xman Anti-Leecher: simple Anti-Thief
*/
CString m_strTemp = thePrefs.GetUserNick();
m_strTemp.AppendFormat(_T(" %s \xAB%s\xBB"), str_ANTAddOn, theApp.m_strModVersion);
CTag tagName(CT_NAME, (!m_bGPLEvildoer) ? m_strTemp : _T("Please use a GPL-conform version of eMule") );
// <== ModID [itsonlyme/SiRoB] - Stulle
tagName.WriteTagToFile(data, utf8strRaw);
}
//else send the standard-nick
else
{
CTag tagName(CT_NAME, (!m_bGPLEvildoer) ? thePrefs.GetUserNick() : _T("Please use a GPL-conform version of eMule") ); //Xman Anti-Leecher: simple Anti-Thief
tagName.WriteTagToFile(data, utf8strRaw);
}
//Xman end
// ==> Emulate others [WiZaRd/Spike/shadow2004] - Stulle
/*
// eD2K Version
CTag tagVersion(CT_VERSION,EDONKEYVERSION);
tagVersion.WriteTagToFile(data);
*/
if (thePrefs.IsEmuShareaza() && GetClientSoft() == SO_SHAREAZA)
{
CTag tagVersion(CT_VERSION, SHAREAZAEMUVERSION);
tagVersion.WriteTagToFile(data);
if (thePrefs.IsEmuLog())
AddDebugLogLine(false,_T("[EMULATE] Emulate Shareaza (%s)"),DbgGetClientInfo());
}
else
{
// eD2K Version
CTag tagVersion(CT_VERSION,EDONKEYVERSION);
tagVersion.WriteTagToFile(data);
}
// <== Emulate others [WiZaRd/Spike/shadow2004] - Stulle
// eMule UDP Ports
uint32 kadUDPPort = 0;
if(Kademlia::CKademlia::IsConnected())
{
if (Kademlia::CKademlia::GetPrefs()->GetExternalKadPort() != 0
&& Kademlia::CKademlia::GetPrefs()->GetUseExternKadPort()
&& Kademlia::CUDPFirewallTester::IsVerified())
{
kadUDPPort = Kademlia::CKademlia::GetPrefs()->GetExternalKadPort();
}
else
kadUDPPort = Kademlia::CKademlia::GetPrefs()->GetInternKadPort();
}
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()->GetIP() );
tagBuddyIP.WriteTagToFile(data);
CTag tagBuddyPort(CT_EMULE_BUDDYUDP,
// ( RESERVED )
((uint32)theApp.clientlist->GetBuddy()->GetUDPPort() )
);
tagBuddyPort.WriteTagToFile(data);
}
// eMule Misc. Options #1
const UINT uUdpVer = 4;
const UINT uDataCompVer = 1;
const UINT uSupportSecIdent = theApp.clientcredits->CryptoAvailable() ? 3 : 0;
// ***
// deprecated - will be set back to 3 with the next release (to allow the new version to spread first),
// due to a bug in earlier eMule version. Use SupportsSourceEx2 and new opcodes instead
const UINT uSourceExchange1Ver = 4;
// ***
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) |
(uSourceExchange1Ver << 12) |
(uExtendedRequestsVer << 8) |
(uAcceptCommentVer << 4) |
(uPeerCache << 3) |
(uNoViewSharedFiles << 2) |
(uMultiPacket << 1) |
(uSupportPreview << 0)
);
tagMisOptions1.WriteTagToFile(data);
// eMule Misc. Options #2
const UINT uKadVersion = KADEMLIA_VERSION;
const UINT uSupportLargeFiles = 1;
const UINT uExtMultiPacket = 1;
const UINT uReserved = 0; // mod bit
const UINT uSupportsCryptLayer = thePrefs.IsClientCryptLayerSupported() ? 1 : 0;
const UINT uRequestsCryptLayer = thePrefs.IsClientCryptLayerRequested() ? 1 : 0;
const UINT uRequiresCryptLayer = thePrefs.IsClientCryptLayerRequired() ? 1 : 0;
const UINT uSupportsSourceEx2 = 1;
const UINT uSupportsCaptcha = 1;
// direct callback is only possible if connected to kad, tcp firewalled and verified UDP open (for example on a full cone NAT)
const UINT uDirectUDPCallback = (Kademlia::CKademlia::IsRunning() && Kademlia::CKademlia::IsFirewalled()
&& !Kademlia::CUDPFirewallTester::IsFirewalledUDP(true) && Kademlia::CUDPFirewallTester::IsVerified()) ? 1 : 0;
const UINT uFileIdentifiers = 1;
CTag tagMisOptions2(CT_EMULE_MISCOPTIONS2,
// (RESERVED )
(uFileIdentifiers << 13) |
(uDirectUDPCallback << 12) |
(uSupportsCaptcha << 11) |
(uSupportsSourceEx2 << 10) |
(uRequiresCryptLayer << 9) |
(uRequestsCryptLayer << 8) |
(uSupportsCryptLayer << 7) |
(uReserved << 6) |
(uExtMultiPacket << 5) |
(uSupportLargeFiles << 4) |
(uKadVersion << 0)
);
tagMisOptions2.WriteTagToFile(data);
// ==> Emulate others [WiZaRd/Spike/shadow2004] - Stulle
/*
// eMule Version
CTag tagMuleVersion(CT_EMULE_VERSION,
//(uCompatibleClientID << 24) |
(CemuleApp::m_nVersionMjr << 17) |
(CemuleApp::m_nVersionMin << 10) |
(CemuleApp::m_nVersionUpd << 7)
// (RESERVED )
);
tagMuleVersion.WriteTagToFile(data);
*/
if (thePrefs.IsEmuShareaza() && GetClientSoft() == SO_SHAREAZA)
{
CTag tagMuleVersion(CT_EMULE_VERSION,
(SO_SHAREAZA << 24) |
(2 << 17) |
(2 << 10) |
(1 << 7) |
(0 )
);
tagMuleVersion.WriteTagToFile(data);
if (thePrefs.IsEmuLog())
AddDebugLogLine(false,_T("[EMULATE] Emulate Shareaza (%s)"),DbgGetClientInfo());
}
else if (thePrefs.IsEmuLphant() && GetClientSoft() == SO_LPHANT)
{
CTag tagMuleVersion(CT_EMULE_VERSION,
(SO_LPHANT << 24) |
(2 << 17) |
(9 << 10) |
(0 << 7)
);
tagMuleVersion.WriteTagToFile(data);
if (thePrefs.IsEmuLog())
AddDebugLogLine(false,_T("[EMULATE] Emulate Lphant (%s)"),DbgGetClientInfo());
}
else if (thePrefs.IsEmuMLDonkey() && GetClientSoft() == SO_MLDONKEY)
{
CTag tagMuleVersion(CT_EMULE_VERSION,
(SO_MLDONKEY << 24) |
(2 << 17) |
(7 << 10) |
(3 << 7)
);
tagMuleVersion.WriteTagToFile(data);
if (thePrefs.IsEmuLog())
AddDebugLogLine(false,_T("[EMULATE] Emulate MLDonkey (%s)"),DbgGetClientInfo());
}
else if (thePrefs.IsEmueDonkey() && GetClientSoft() == SO_EDONKEY)
{
CTag tagMuleVersion(CT_EMULE_VERSION,
(SO_EDONKEY << 24) |
(10405 << 17)
);
tagMuleVersion.WriteTagToFile(data);
if (thePrefs.IsEmuLog())
AddDebugLogLine(false,_T("[EMULATE] Emulate eDonkey (%s)"),DbgGetClientInfo());
}
else if (thePrefs.IsEmueDonkeyHybrid() && GetClientSoft() == SO_EDONKEYHYBRID)
{
CTag tagMuleVersion(CT_EMULE_VERSION,
(SO_EDONKEYHYBRID << 24) |
(10405 << 17)
);
tagMuleVersion.WriteTagToFile(data);
if (thePrefs.IsEmuLog())
AddDebugLogLine(false,_T("[EMULATE] Emulate eDonkeyHybrid (%s)"),DbgGetClientInfo());
}
else
{
// eMule Version
CTag tagMuleVersion(CT_EMULE_VERSION,
//(uCompatibleClientID << 24) |
(CemuleApp::m_nVersionMjr << 17) |
(CemuleApp::m_nVersionMin << 10) |
(CemuleApp::m_nVersionUpd << 7)
// (RESERVED )
);
tagMuleVersion.WriteTagToFile(data);
}
// <== Emulate others [WiZaRd/Spike/shadow2004] - Stulle
//Xman - modID
if (bSendModVersion) {
// ==> ModID [itsonlyme/SiRoB] - Stulle
/*
CTag tagMODVersion(ET_MOD_VERSION, MOD_VERSION);
*/
CTag tagMODVersion(ET_MOD_VERSION, theApp.m_strModVersion);
// <== ModID [itsonlyme/SiRoB] - Stulle
tagMODVersion.WriteTagToFile(data);
}
//Xman end - modID
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(const uchar* pachPacket, uint32 nSize)
{
if (reqfile && reqfile->IsPartFile())
{
CSafeMemFile data(pachPacket, nSize);
uint8 uRating = data.ReadUInt8();
if (thePrefs.GetLogRatingDescReceived() && uRating > 0)
AddDebugLogLine(false, GetResString(IDS_RATINGRECV), m_strClientFilename, uRating);
CString strComment;
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*4)
uLength = MAXFILECOMMENTLEN*4;
strComment = data.ReadString(GetUnicodeSupport()!=utf8strNone, uLength);
if (strComment.GetLength() > MAXFILECOMMENTLEN) // enforce the max len on the comment
strComment = strComment.Left(MAXFILECOMMENTLEN);
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;
SetSpammer(true);
break;
}
strFilter = thePrefs.GetCommentFilter().Tokenize(_T("|"), iPos);
}
}
}
if (!strComment.IsEmpty() || uRating > 0)
{
m_strFileComment = strComment;
m_uFileRating = uRating;
reqfile->UpdateFileRatingCommentAvail();
}
}
}
// Maella -Upload Stop Reason-
/*
bool CUpDownClient::Disconnected(LPCTSTR pszReason, bool bFromSocket)
*/
bool CUpDownClient::Disconnected(LPCTSTR pszReason, bool bFromSocket, UpStopReason reason)
//Xman end
{
ASSERT( theApp.clientlist->IsValidClient(this) );
// TODO LOGREMOVE
if (m_nConnectingState == CCS_DIRECTCALLBACK)
DebugLog(_T("Direct Callback failed - %s"), DbgGetClientInfo());
if (GetKadState() == KS_QUEUED_FWCHECK_UDP || GetKadState() == KS_CONNECTING_FWCHECK_UDP)
Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, ntohl(GetConnectIP()), 0); // inform the tester that this test was cancelled
else if (GetKadState() == KS_FWCHECK_UDP)
Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, false, ntohl(GetConnectIP()), 0); // inform the tester that this test has failed
else if (GetKadState() == KS_CONNECTED_BUDDY)
DebugLogWarning(_T("Buddy client disconnected - %s, %s"), pszReason, DbgGetClientInfo());
//If this is a KAD client object, just delete it!
SetKadState(KS_NONE);
//Xman Xtreme Mod
/*
if (GetUploadState() == US_UPLOADING || GetUploadState() == US_CONNECTING)
*/
if (GetUploadState() == US_UPLOADING) //uploading problem client
//Xman end
{
// sets US_NONE
// Maella -Upload Stop Reason-
/*
theApp.uploadqueue->RemoveFromUploadQueue(this, CString(_T("CUpDownClient::Disconnected: ")) + pszReason);
*/
theApp.uploadqueue->RemoveFromUploadQueue(this, CString(_T("CUpDownClient::Disconnected: ")) + pszReason , reason);
//Xman end
}
// 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){
ASSERT( m_nConnectingState == CCS_NONE );
if (m_ePeerCacheDownState == PCDS_WAIT_CACHE_REPLY || m_ePeerCacheDownState == PCDS_DOWNLOADING)
theApp.m_pPeerCache->DownloadAttemptFailed();
//Xman remark: the only reason can be a socket-error/timeout
// Maella -Download Stop Reason-
/*
SetDownloadState(DS_ONQUEUE, CString(_T("Disconnected: ")) + pszReason);
*/
//Xman remark: the only reason can be a socket-error/timeout
SetDownloadState(DS_ONQUEUE, CString(_T("Disconnected: ")) + pszReason, CUpDownClient::DSR_SOCKET);
//Xman end
}
else{
// ensure that all possible block requests are removed from the partfile
ClearDownloadBlockRequests();
//Xman Code Imrpovement moved down
/*
if (GetDownloadState() == DS_CONNECTED){ // successfully connected, but probably didn't responsed to our filerequest
theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
theApp.downloadqueue->RemoveSource(this);
}
*/
//Xman end
}
// we had still an AICH request pending, handle it
if (IsAICHReqPending()){
m_fAICHRequested = FALSE;
CAICHRecoveryHashSet::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 (m_fHashsetRequestingMD4 && (reqfile != NULL))
reqfile->m_bMD4HashsetNeeded = true;
if (m_fHashsetRequestingAICH && (reqfile != NULL))
reqfile->SetAICHHashSetNeeded(true);
if (m_iFileListRequested){
LogWarning(LOG_STATUSBAR, GetResString(IDS_SHAREDFILES_FAILED), GetUserName());
m_iFileListRequested = 0;
}
if (m_Friend)
theApp.friendlist->RefreshFriend(m_Friend);
ASSERT( theApp.clientlist->IsValidClient(this) );
//check if this client is needed in any way, if not delete it
bool bDelete = true;
//Xman
/*
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("Removing connecting client from upload list: %s Client: %s"), pszReason, DbgGetClientInfo());
//Xman uploading problem client
{
theApp.uploadqueue->RemoveFromUploadQueue(this,pszReason ,CUpDownClient::USR_SOCKET );
isupprob=true;
//back to queue
theApp.uploadqueue->AddClientDirectToQueue(this);
m_bAddNextConnect=true;
bDelete = false;
break;
}
//Xman end
}
case US_ONUPLOADQUEUE:
bDelete = false;
break;
//Xman 5.1 why we should keep it ?
case US_BANNED:
bDelete = true;
}
switch(m_nDownloadState){
case DS_ONQUEUE:
case DS_TOOMANYCONNS:
case DS_NONEEDEDPARTS:
case DS_LOWTOLOWIP:
bDelete = false;
}
//Xman end
//Xman remark:
//this official code is only used at downloadstate, because upload is handled different with Xtreme
//
// Dead Soure Handling
//
// If we failed to connect to that client, it is supposed to be 'dead'. Add the IP
// to the 'dead sources' lists so we don't waste resources and bandwidth to connect
// to that client again within the next hour.
//
// But, if we were just connecting to a proxy and failed to do so, that client IP
// is supposed to be valid until the proxy itself tells us that the IP can not be
// connected to (e.g. 504 Bad Gateway)
//
bool bAddDeadSource = true;
//Xman
/*
switch(m_nUploadState){
case US_CONNECTING:
if (socket && socket->GetProxyConnectFailed())
bAddDeadSource = false;
if (thePrefs.GetLogUlDlEvents())
AddDebugLogLine(DLP_VERYLOW, true,_T("Removing connecting client from upload list: %s Client: %s"), pszReason, DbgGetClientInfo());
case US_WAITCALLBACK:
case US_ERROR:
if (bAddDeadSource)
theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
bDelete = true;
}
if ( (m_nConnectingState != CCS_NONE && !(socket && socket->GetProxyConnectFailed()))
|| m_nDownloadState == DS_ERROR)
{
if (m_nDownloadState != DS_NONE) // Unable to connect = Remove any downloadstate
theApp.downloadqueue->RemoveSource(this);
theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
bDelete = true;
}
*/
//Xman end
if(m_nUploadState!=US_BANNED) //Xman DLP - Anti-Leecher / Code-Improvement
switch(m_nDownloadState){
case DS_CONNECTING:
{
m_cFailed++;
//Xman Anti-Leecher
if(IsBanned())
{
bDelete=true; //force delete and no retry and no deadsourcelist
break;
}
//Xman end
//Xman spread reasks after timeout
//Xman Xtreme Mod
//why we should immediately reask the source ?
//either the source are busy -->let`s wait
//or the source are gone, in this case, we shouldn't waste the socket,
//but ask other sources (too many connections)
//TryToConnect(); is called indirect later
//Xman
//optional retry connection attempts
if(thePrefs.retryconnectionattempts==false)
m_cFailed=5; //force deadsourcelist
//Xman udppending only 1 retry, and lets wait 70 sec
if (m_cFailed < 2) //we don't know this clients, only 2 attemps
{
SetNextTCPAskedTime(::GetTickCount()+70000); //wait 70 sec bevore the next try
SetDownloadState(DS_NONE);
bDelete = false; //Delete this socket but not this client
break;
}
else if (m_cFailed < 3 && GetUserName()!=NULL && !m_bUDPPending ) //we now the client, give 3 attemps
{
//theApp.AddLogLine(false,_T("Client with with IP=%s, Version=%s, Name=%s failed to connect %u times"), GetFullIP(), GetClientVerString(), GetUserName(),m_cFailed);
SetNextTCPAskedTime(::GetTickCount()+50000); //wait 50 sec bevore the next try
SetDownloadState(DS_NONE);
bDelete = false; //Delete this socket but not this client
break;
}
//Xman end
if (socket && socket->GetProxyConnectFailed())
bAddDeadSource = false;
}
case DS_CONNECTED: //Xman Code Improvement delete non answering clients
case DS_WAITCALLBACK:
if (bAddDeadSource)
theApp.clientlist->m_globDeadSourceList.AddDeadSource(this);
theApp.downloadqueue->AddFailedTCPFileReask(); //Xman Xtreme Mod: count the failed TCP-connections
if(m_bUDPPending) theApp.downloadqueue->AddFailedUDPFileReasks(); //Xman Xtreme Mod: for correct statistics, if it wasn't counted on connection established //Xman x4 test
case DS_ERROR: //Xman Xtreme Mod: this clients get IP-Filtered!
bDelete = true;
}
//Xman end
// We keep chat partners in any case
if (GetChatState() != MS_NONE){
//Xman Code Improvement
if(bDelete==true)
theApp.downloadqueue->RemoveSource(this);
//Xman end
bDelete = false;
if (GetFriend() != NULL && GetFriend()->IsTryingToConnect())
GetFriend()->UpdateFriendConnectionState(FCR_DISCONNECTED); // for friends any connectionupdate is handled in the friend class
else
theApp.emuledlg->chatwnd->chatselector.ConnectingResult(this,false); // other clients update directly
}
// Delete Socket
if (!bFromSocket && socket){
ASSERT( theApp.listensocket->IsValidSocket(socket) );
socket->Safe_Delete();
}
socket = NULL;
//Xman Code Improvement: don't refresh list-item on deletion
if(bDelete==false)
theApp.emuledlg->transferwnd->GetClientList()->RefreshClient(this);
// finally, remove the client from the timeouttimer and reset the connecting state
m_nConnectingState = CCS_NONE;
theApp.clientlist->RemoveConnectingClient(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_fHashsetRequestingMD4 = 0;
m_fHashsetRequestingAICH = 0;
SetSentCancelTransfer(0);
m_bHelloAnswerPending = false;
m_bACATHelloAnswerPending = false; //zz_fly :: Client is always highid if we are connecting to them - by Enig123, idea from ACAT
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, bool bNoCallbacks, CRuntimeClass* pClassSocket)
{
// There are 7 possible ways how we are going to connect in this function, sorted by priority:
// 1) Already Connected/Connecting
// We are already connected or try to connect right now. Abort, no additional Disconnect() call will be done
// 2) Immediate Fail
// Some precheck or precondition failed, or no other way is available, so we do not try to connect at all
// but fail right away, possibly deleting the client as it becomes useless
// 3) Normal Outgoing TCP Connection
// Applies to all HighIDs/Open clients: We do a straight forward connection try to the TCP port of the client
// 4) Direct Callback Connections
// Applies to TCP firewalled - UDP open clients: We sent a UDP packet to the client, requesting him to connect
// to us. This is pretty easy too and ressourcewise nearly on the same level as 3)
// (* 5) Waiting/Abort
// This check is done outside this function.
// We want to connect for some download related thing (for example reasking), but the client has a LowID and
// is on our uploadqueue. So we are smart and safing ressources by just waiting untill he reasks us, so we don't
// have to do the ressource intensive options 6 or 7. *)
// 6) Server Callback
// This client is firewalled, but connected to our server. We sent the server a callback request to forward to
// the client and hope for the best
// 7) Kad Callback
// This client is firewalled, but has a Kad buddy. We sent the buddy a callback request to forward to the client
// and hope for the best
if( GetKadState() == KS_QUEUED_FWCHECK )
SetKadState(KS_CONNECTING_FWCHECK);
else if (GetKadState() == KS_QUEUED_FWCHECK_UDP)
SetKadState(KS_CONNECTING_FWCHECK_UDP);
////////////////////////////////////////////////////////////
// Check for 1) Already Connected/Connecting
if (m_nConnectingState != CCS_NONE) {
DebugLog(_T("TryToConnect: Already Connecting (%s)"), DbgGetClientInfo());// TODO LogRemove
return true;
}
else if (socket != NULL){
if (socket->IsConnected())
{
if (CheckHandshakeFinished()){
DEBUG_ONLY( DebugLog(_T("TryToConnect: Already Connected (%s)"), DbgGetClientInfo()) );// TODO LogRemove
ConnectionEstablished();
}
else
DebugLogWarning( _T("TryToConnect found connected socket, but without Handshake finished - %s"), DbgGetClientInfo());
return true;
}
else
socket->Safe_Delete();
}
m_nConnectingState = CCS_PRECONDITIONS; // We now officially try to connect :)
////////////////////////////////////////////////////////////
// Check for 2) Immediate Fail
if (theApp.listensocket->TooManySockets() && !bIgnoreMaxCon)
{
// This is a sanitize check and counts as a "hard failure", so this check should be also done before calling
// TryToConnect if a special handling, like waiting till there are enough connection avaiable should be fone
DebugLogWarning(_T("TryToConnect: Too many connections sanitize check (%s)"), DbgGetClientInfo());
if(Disconnected(_T("Too many connections")))
{
delete this;
return false;
}
return true;
}
// do not try to connect to source which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it)
if ( (RequiresCryptLayer() && !thePrefs.IsClientCryptLayerSupported()) || (thePrefs.IsClientCryptLayerRequired() && !SupportsCryptLayer()) )
{
DEBUG_ONLY( AddDebugLogLine(DLP_DEFAULT, false, _T("Rejected outgoing connection because CryptLayer-Setting (Obfuscation) was incompatible %s"), DbgGetClientInfo()) );
if(Disconnected(_T("CryptLayer-Settings (Obfuscation) incompatible"))){
delete this;
return false;
}
else
return true;
}
uint32 uClientIP = (GetIP() != 0) ? GetIP() : GetConnectIP();
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());
m_cFailed=5; //force deletion //Xman
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());
m_cFailed=5; //force deletion //Xman
if (Disconnected(_T("Banned IP")))
{
delete this;
return false;
}
return true;
}
}
if ( HasLowID() )
{
ASSERT( pClassSocket == NULL );
if(!theApp.CanDoCallback(this)) // lowid2lowid check used for the whole function, don't remove
{
// We cannot reach this client, so we hard fail to connect, if this client should be kept,
// for example because we might want to wait a bit and hope we get a highid, this check has
// to be done before calling this function
if(Disconnected(_T("LowID->LowID")))
{
delete this;
return false;
}
return true;
}
// are callbacks disallowed?
if (bNoCallbacks){
DebugLogError(_T("TryToConnect: Would like to do callback on a no-callback client, %s"), DbgGetClientInfo());
if(Disconnected(_T("LowID: No Callback Option allowed")))
{
delete this;
return false;
}
return true;
}
// Is any callback available?
if (!( (SupportsDirectUDPCallback() && thePrefs.GetUDPPort() != 0 && GetConnectIP() != 0) // Direct Callback
|| (HasValidBuddyID() && Kademlia::CKademlia::IsConnected()) // Kad Callback
|| theApp.serverconnect->IsLocalServer(GetServerIP(), GetServerPort()) )) // Server Callback
{
// Nope
if(Disconnected(_T("LowID: No Callback Option available")))
{
delete this;
return false;
}
return true;
}
}
// Prechecks finished, now for the real connecting
////////////////////////////////////////////////////
theApp.clientlist->AddConnectingClient(this); // Starts and checks for the timeout, ensures following Disconnect() or ConnectionEstablished() call
////////////////////////////////////////////////////////////
// 3) Normal Outgoing TCP Connection
if (!HasLowID())
{
m_nConnectingState = CCS_DIRECTTCP;
if (pClassSocket == NULL)
pClassSocket = RUNTIME_CLASS(CClientReqSocket);
socket = static_cast(pClassSocket->CreateObject());
socket->SetClient(this);
if (!socket->Create())
{
socket->Safe_Delete();
// we let the timeout handle the cleanup in this case
DebugLogError(_T("TryToConnect: Failed to create socket for outgoing connection, %s"), DbgGetClientInfo());
}
else
Connect();
return true;
}
////////////////////////////////////////////////////////////
// 4) Direct Callback Connections
else if (SupportsDirectUDPCallback() && thePrefs.GetUDPPort() != 0 && GetConnectIP() != 0)
{
m_nConnectingState = CCS_DIRECTCALLBACK;
// TODO LOGREMOVE
DebugLog(_T("Direct Callback on port %u to client %s (%s) "), GetKadPort(), DbgGetClientInfo(), md4str(GetUserHash()));
CSafeMemFile data;
data.WriteUInt16(thePrefs.GetPort()); // needs to know our port
data.WriteHash16(thePrefs.GetUserHash()); // and userhash
// our connection settings
data.WriteUInt8(GetMyConnectOptions(true, false));
if (thePrefs.GetDebugClientUDPLevel() > 0)
DebugSend("OP_DIRECTCALLBACKREQ", this);
Packet* packet = new Packet(&data, OP_EMULEPROT);
packet->opcode = OP_DIRECTCALLBACKREQ;
theStats.AddUpDataOverheadOther(packet->size);
theApp.clientudp->SendPacket(packet, GetConnectIP(), GetKadPort(), ShouldReceiveCryptUDPPackets(), GetUserHash(), false, 0);
return true;
}
////////////////////////////////////////////////////////////
// 6) Server Callback + 7) Kad Callback
if (GetDownloadState() == DS_CONNECTING)
SetDownloadState(DS_WAITCALLBACK);
if (GetUploadState() == US_CONNECTING){
ASSERT( false ); // we should never try to connect in this case, but wait for the LowID to connect to us
DebugLogError( _T("LowID and US_CONNECTING (%s)"), DbgGetClientInfo());
}
if (theApp.serverconnect->IsLocalServer(m_dwServerIP, m_nServerPort))
{
m_nConnectingState = CCS_SERVERCALLBACK;
Packet* packet = new Packet(OP_CALLBACKREQUEST,4);
PokeUInt32(packet->pBuffer, m_nUserIDHybrid);
if (thePrefs.GetDebugServerTCPLevel() > 0 || thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__CallbackRequest", this);
theStats.AddUpDataOverheadServer(packet->size);
theApp.serverconnect->SendPacket(packet);
return true;
}
else if (HasValidBuddyID() && Kademlia::CKademlia::IsConnected())
{
m_nConnectingState = CCS_KADCALLBACK;
if( GetBuddyIP() && GetBuddyPort())
{
CSafeMemFile bio(34);
bio.WriteUInt128(&Kademlia::CUInt128(GetBuddyID()));
bio.WriteUInt128(&Kademlia::CUInt128(reqfile->GetFileHash()));
bio.WriteUInt16(thePrefs.GetPort());
if (thePrefs.GetDebugClientKadUDPLevel() > 0 || thePrefs.GetDebugClientUDPLevel() > 0)
DebugSend("KadCallbackReq", this);
Packet* packet = new Packet(&bio, OP_KADEMLIAHEADER);
packet->opcode = KADEMLIA_CALLBACK_REQ;
theStats.AddUpDataOverheadKad(packet->size);
// FIXME: We dont know which kadversion the buddy has, so we need to send unencrypted
theApp.clientudp->SendPacket(packet, GetBuddyIP(), GetBuddyPort(), false, NULL, true, 0);
SetDownloadState(DS_WAITCALLBACKKAD);
}
else
{
// I don't think we should ever have a buddy without its IP (anymore), but nevertheless let the functionality in
//Create search to find buddy.
Kademlia::CSearch *findSource = new Kademlia::CSearch;
findSource->SetSearchTypes(Kademlia::CSearch::FINDSOURCE);
findSource->SetTargetID(Kademlia::CUInt128(GetBuddyID()));
findSource->AddFileID(Kademlia::CUInt128(reqfile->GetFileHash()));
if( Kademlia::CKademlia::GetPrefs()->GetTotalSource() > 0 || Kademlia::CSearchManager::AlreadySearchingFor(Kademlia::CUInt128(GetBuddyID())))
{
//There are too many source lookups already or we are already searching this key.
// bad luck, as lookups aren't supposed to hapen anyway, we just let it fail, if we want
// to actually really use lookups (so buddies without known IPs), this should be reworked
// for example by adding a queuesystem for queries
DebugLogWarning(_T("TryToConnect: Buddy without knonw IP, Lookup crrently impossible"));
return true;
}
if(Kademlia::CSearchManager::StartSearch(findSource))
{
//Started lookup..
SetDownloadState(DS_WAITCALLBACKKAD);
}
else
{
//This should never happen..
ASSERT(0);
}
}
return true;
}
else {
ASSERT( false );
DebugLogError(_T("TryToConnect: Bug: No Callback available despite prechecks"));
return true;
}
}
void CUpDownClient::Connect()
{
// enable or disable crypting based on our and the remote clients preference
if (HasValidHash() && SupportsCryptLayer() && thePrefs.IsClientCryptLayerSupported() && (RequestsCryptLayer() || thePrefs.IsClientCryptLayerRequested())){
//DebugLog(_T("Enabling CryptLayer on outgoing connection to client %s"), DbgGetClientInfo()); // to be removed later
socket->SetConnectionEncryption(true, GetUserHash(), false);
}
else
socket->SetConnectionEncryption(false, NULL, false);
//Try to always tell the socket to WaitForOnConnect before you call Connect.
socket->WaitForOnConnect();
SOCKADDR_IN sockAddr = {0};
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(GetUserPort());
sockAddr.sin_addr.S_un.S_addr = GetConnectIP();
socket->Connect((SOCKADDR*)&sockAddr, sizeof sockAddr);
SendHelloPacket();
}
void CUpDownClient::ConnectionEstablished()
{
m_cFailed = 0; //Xman Downloadmanager / Xtreme Mod // holds the failed connection attempts
//Xman Xtreme Mod
if (m_bUDPPending && !IsRemoteQueueFull()) //Xman maybe the client has now place at its queue .. then it's right to not answer an UDPFilereaskping
{
m_nFailedUDPPackets++;
theApp.downloadqueue->AddFailedUDPFileReasks();
}
m_bUDPPending = false;
//Xman -Reask sources after IP change- v4
//Xman at this point we know, we have a internet-connection -> enable upload
static uint32 lastaskedforip;
if(theApp.internetmaybedown)
{
if(Kademlia::CKademlia::IsConnected()
&& (theApp.uploadqueue->waitinglist.GetSize()>10 //check if we have clients queued, otherwise inetmaybedown gives a wrong value
|| theApp.last_ip_change==0) //we just started the client //Xman new adapter selection
&& theApp.last_ip_change < ::GetTickCount() - MIN2MS(2) //only once in 2 minutes
)
theApp.m_bneedpublicIP=true;
if(theApp.IsConnected()) //only free the upload if we are connected. important! otherwise we would have problems with nafc-adapter on a hotstart
{
theApp.internetmaybedown=false;
theApp.last_traffic_reception=::GetTickCount();
theApp.pBandWidthControl->AddeMuleOut(1); //this reopens the upload (internetmaybedown checks for upload==0
}
}
if(theApp.m_bneedpublicIP==true
&& m_fPeerCache
&& lastaskedforip + SEC2MS(3) < ::GetTickCount() //give the client some time, we shouln't ask more than 2-3 clients after reconnect
)
{
SendPublicIPRequest();
lastaskedforip=::GetTickCount();
AddDebugLogLine(false, _T("Internet-connection was possibly down. ask client for ip: %s"), DbgGetClientInfo());
}
//Xman end
// ok we have a connection, lets see if we want anything from this client
// was this a direct callback?
if (m_nConnectingState == CCS_DIRECTCALLBACK) // TODO LOGREMOVE
DebugLog(_T("Direct Callback succeeded, connection established - %s"), DbgGetClientInfo());
// remove the connecting timer and state
//if (m_nConnectingState == CCS_NONE) // TODO LOGREMOVE
// DEBUG_ONLY( DebugLog(_T("ConnectionEstablished with CCS_NONE (incoming, thats fine)")) );
m_nConnectingState = CCS_NONE;
theApp.clientlist->RemoveConnectingClient(this);
// check if we should use this client to retrieve our public IP
//Xman
/*
if (theApp.GetPublicIP() == 0 && theApp.IsConnected() && m_fPeerCache)
*/
if (theApp.GetPublicIP() == 0 && theApp.serverconnect->IsConnected() && m_fPeerCache)
//Xman end
SendPublicIPRequest();
switch(GetKadState())
{
case KS_CONNECTING_FWCHECK:
SetKadState(KS_CONNECTED_FWCHECK);
break;
case KS_CONNECTING_BUDDY:
case KS_INCOMING_BUDDY:
DEBUG_ONLY( DebugLog(_T("Set KS_CONNECTED_BUDDY for client %s"), DbgGetClientInfo()) );
SetKadState(KS_CONNECTED_BUDDY);
break;
case KS_CONNECTING_FWCHECK_UDP:
SetKadState(KS_FWCHECK_UDP);
DEBUG_ONLY( DebugLog(_T("Set KS_FWCHECK_UDP for client %s"), DbgGetClientInfo()) );
SendFirewallCheckUDPRequest();
break;
}
if (GetChatState() == MS_CONNECTING || GetChatState() == MS_CHATTING)
{
if (GetFriend() != NULL && GetFriend()->IsTryingToConnect()){
GetFriend()->UpdateFriendConnectionState(FCR_ESTABLISHED); // for friends any connectionupdate is handled in the friend class
if (credits != NULL && credits->GetCurrentIdentState(GetConnectIP()) == IS_IDFAILED)
GetFriend()->UpdateFriendConnectionState(FCR_SECUREIDENTFAILED);
}
else
theApp.emuledlg->chatwnd->chatselector.ConnectingResult(this, true); // other clients update directly
}
switch(GetDownloadState())
{
case DS_CONNECTING:
case DS_WAITCALLBACK:
case DS_WAITCALLBACKKAD:
m_bReaskPending = false;
SetDownloadState(DS_CONNECTED);
SendFileRequest();
break;
}
if (m_bReaskPending)
{
m_bReaskPending = false;
if (GetDownloadState() != DS_NONE && GetDownloadState() != DS_DOWNLOADING)
{
SetDownloadState(DS_CONNECTED);
SendFileRequest();
}
}
switch(GetUploadState())
{
case US_CONNECTING:
if (theApp.uploadqueue->IsDownloading(this))
{
SetUploadState(US_UPLOADING);
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__AcceptUploadReq", this);
Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
theStats.AddUpDataOverheadFileRequest(packet->size);
SendPacket(packet,true);
//Xman find best sources
//Xman: in every case, we add this client to our downloadqueue
CKnownFile* partfile = theApp.downloadqueue->GetFileByID(this->GetUploadFileID());
if (partfile && partfile->IsPartFile())
theApp.downloadqueue->CheckAndAddKnownSource((CPartFile*)partfile,this,true);
//Xman end
}
}
if (m_iFileListRequested == 1)
{
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend(m_fSharedDirectories ? "OP__AskSharedDirs" : "OP__AskSharedFiles", this);
Packet* packet = new Packet(m_fSharedDirectories ? OP_ASKSHAREDDIRS : OP_ASKSHAREDFILES,0);
theStats.AddUpDataOverheadOther(packet->size);
SendPacket(packet,true);
}
while (!m_WaitingPackets_list.IsEmpty())
{
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("Buffered Packet", this);
SendPacket(m_WaitingPackets_list.RemoveHead(), true);
}
}
void CUpDownClient::InitClientSoftwareVersion()
{
if (m_pszUsername == NULL){
m_clientSoft = SO_UNKNOWN;
return;
}
int iHashType = GetHashType();
if (m_bEmuleProtocol || iHashType == SO_EMULE){
LPCTSTR pszSoftware;
switch(m_byCompatibleClient){
case SO_CDONKEY:
m_clientSoft = SO_CDONKEY;
pszSoftware = _T("cDonkey");
break;
case SO_XMULE:
m_clientSoft = SO_XMULE;
pszSoftware = _T("xMule");
break;
case SO_AMULE:
m_clientSoft = SO_AMULE;
pszSoftware = _T("aMule");
break;
case SO_SHAREAZA:
// ==> Enhanced Client Recognition [Spike] - Stulle
/*
case 40:
*/
case SO_SHAREAZA2:
case SO_SHAREAZA3:
case SO_SHAREAZA4:
// <== Enhanced Client Recognition [Spike] - Stulle
m_clientSoft = SO_SHAREAZA;
pszSoftware = _T("Shareaza");
break;
case SO_LPHANT:
m_clientSoft = SO_LPHANT;
pszSoftware = _T("lphant");
break;
// ==> Enhanced Client Recognition [Spike] - Stulle
case SO_EMULEPLUS:
m_clientSoft = SO_EMULEPLUS;
pszSoftware = _T("eMule Plus");
break;
case SO_HYDRANODE:
m_clientSoft = SO_HYDRANODE;
pszSoftware = _T("Hydranode");
break;
case SO_TRUSTYFILES:
m_clientSoft = SO_TRUSTYFILES;
pszSoftware = _T("TrustyFiles");
break;
// <== Enhanced Client Recognition [Spike] - Stulle
default:
// ==> Enhanced Client Recognition [Spike] - Stulle
/*
if (m_bIsML || m_byCompatibleClient == SO_MLDONKEY){
*/
if (m_bIsML || m_byCompatibleClient == SO_MLDONKEY || m_byCompatibleClient == SO_MLDONKEY2 || m_byCompatibleClient == SO_MLDONKEY3){
// <== Enhanced Client Recognition [Spike] - Stulle
m_clientSoft = SO_MLDONKEY;
pszSoftware = _T("MLdonkey");
}
// ==> Enhanced Client Recognition [Spike] - Stulle
/*
else if (m_bIsHybrid){
*/
else if (m_bIsHybrid || m_byCompatibleClient == SO_EDONKEYHYBRID){
// <== Enhanced Client Recognition [Spike] - Stulle
m_clientSoft = SO_EDONKEYHYBRID;
pszSoftware = _T("eDonkeyHybrid");
}
else if (m_byCompatibleClient != 0){
// ==> Enhanced Client Recognition [Spike] - Stulle
// Recognize other Shareazas - just to be sure :)
//WiZaRd: this is highly unreliable and thus I removed it
/*
if (StrStrI(m_pszUsername,_T("shareaza")))
{
m_clientSoft = SO_SHAREAZA;
pszSoftware = _T("Shareaza");
}
else
*/
// Recognize all eMulePlus - just to be sure !
if (StrStr(m_strModVersion,_T("Plus 1")))
{
m_clientSoft = SO_EMULEPLUS;
pszSoftware = _T("eMule Plus");
}
else
{
// <== Enhanced Client Recognition [Spike] - Stulle
m_clientSoft = SO_XMULE; // means: 'eMule Compatible'
pszSoftware = _T("eMule Compat");
} // Enhanced Client Recognition [Spike] - Stulle
}
else{
m_clientSoft = SO_EMULE;
pszSoftware = _T("eMule");
}
}
int iLen;
TCHAR szSoftware[128];
if (m_byEmuleVersion == 0){
m_nClientVersion = MAKE_CLIENT_VERSION(0, 0, 0);
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s"), pszSoftware);
}
else if (m_byEmuleVersion != 0x99){
UINT nClientMinVersion = (m_byEmuleVersion >> 4)*10 + (m_byEmuleVersion & 0x0f);
m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v0.%u"), pszSoftware, nClientMinVersion);
}
else{
UINT nClientMajVersion = (m_nClientVersion >> 17) & 0x7f;
UINT nClientMinVersion = (m_nClientVersion >> 10) & 0x7f;
UINT nClientUpVersion = (m_nClientVersion >> 7) & 0x07;
m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
if (m_clientSoft == SO_EMULE)
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u%c"), pszSoftware, nClientMajVersion, nClientMinVersion, _T('a') + nClientUpVersion);
// ==> Enhanced Client Recognition [Spike] - Stulle
else if (m_clientSoft == SO_EMULEPLUS)
{
if(nClientMinVersion == 0)
{
if(nClientUpVersion == 0)
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u"), pszSoftware, nClientMajVersion);
else
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u%c"), pszSoftware, nClientMajVersion, _T('a') + nClientUpVersion - 1);
}
else
{
if(nClientUpVersion == 0)
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u"), pszSoftware, nClientMajVersion, nClientMinVersion);
else
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u%c"), pszSoftware, nClientMajVersion, nClientMinVersion, _T('a') + nClientUpVersion - 1);
}
}
// <== Enhanced Client Recognition [Spike] - Stulle
else if (m_clientSoft == SO_AMULE || nClientUpVersion != 0)
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u.%u"), pszSoftware, nClientMajVersion, nClientMinVersion, nClientUpVersion);
else if (m_clientSoft == SO_LPHANT)
{
if (nClientMinVersion < 10)
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.0%u"), pszSoftware, (nClientMajVersion-1), nClientMinVersion);
else
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u"), pszSoftware, (nClientMajVersion-1), nClientMinVersion);
}
else
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("%s v%u.%u"), pszSoftware, nClientMajVersion, nClientMinVersion);
}
if (iLen > 0){
memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
m_strClientSoftware.ReleaseBuffer(iLen);
}
return;
}
// ==> Enhanced Client Recognition [Spike] - Stulle
/*
if (m_bIsHybrid){
*/
if (m_bIsHybrid || m_byCompatibleClient == SO_EDONKEYHYBRID){
// <== Enhanced Client Recognition [Spike] - Stulle
m_clientSoft = SO_EDONKEYHYBRID;
// seen:
// 105010 0.50.10
// 10501 0.50.1
// 10300 1.3.0
// 10201 1.2.1
// 10103 1.1.3
// 10102 1.1.2
// 10100 1.1
// 1051 0.51.0
// 1002 1.0.2
// 1000 1.0
// 501 0.50.1
UINT nClientMajVersion;
UINT nClientMinVersion;
UINT nClientUpVersion;
if (m_nClientVersion > 100000){
UINT uMaj = m_nClientVersion/100000;
nClientMajVersion = uMaj - 1;
nClientMinVersion = (m_nClientVersion - uMaj*100000) / 100;
nClientUpVersion = m_nClientVersion % 100;
}
// ==> Enhanced Client Recognition [Spike] - Stulle
/*
else if (m_nClientVersion >= 10100 && m_nClientVersion <= 10309){
*/
else if (m_nClientVersion >= 10100 && m_nClientVersion <= 10409){ // netfinity
// <== Enhanced Client Recognition [Spike] - Stulle
UINT uMaj = m_nClientVersion/10000;
nClientMajVersion = uMaj;
nClientMinVersion = (m_nClientVersion - uMaj*10000) / 100;
nClientUpVersion = m_nClientVersion % 10;
}
else if (m_nClientVersion > 10000){
UINT uMaj = m_nClientVersion/10000;
nClientMajVersion = uMaj - 1;
nClientMinVersion = (m_nClientVersion - uMaj*10000) / 10;
nClientUpVersion = m_nClientVersion % 10;
}
else if (m_nClientVersion >= 1000 && m_nClientVersion < 1020){
UINT uMaj = m_nClientVersion/1000;
nClientMajVersion = uMaj;
nClientMinVersion = (m_nClientVersion - uMaj*1000) / 10;
nClientUpVersion = m_nClientVersion % 10;
}
else if (m_nClientVersion > 1000){
UINT uMaj = m_nClientVersion/1000;
nClientMajVersion = uMaj - 1;
nClientMinVersion = m_nClientVersion - uMaj*1000;
nClientUpVersion = 0;
}
else if (m_nClientVersion > 100){
UINT uMin = m_nClientVersion/10;
nClientMajVersion = 0;
nClientMinVersion = uMin;
nClientUpVersion = m_nClientVersion - uMin*10;
}
else{
nClientMajVersion = 0;
nClientMinVersion = m_nClientVersion;
nClientUpVersion = 0;
}
m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
int iLen;
TCHAR szSoftware[128];
if (nClientUpVersion)
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("eDonkeyHybrid v%u.%u.%u"), nClientMajVersion, nClientMinVersion, nClientUpVersion);
else
iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("eDonkeyHybrid v%u.%u"), nClientMajVersion, nClientMinVersion);
if (iLen > 0){
memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
m_strClientSoftware.ReleaseBuffer(iLen);
}
return;
}
if (m_bIsML || iHashType == SO_MLDONKEY){
m_clientSoft = SO_MLDONKEY;
UINT nClientMinVersion = m_nClientVersion;
m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
TCHAR szSoftware[128];
int iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("MLdonkey v0.%u"), nClientMinVersion);
if (iLen > 0){
memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
m_strClientSoftware.ReleaseBuffer(iLen);
}
return;
}
if (iHashType == SO_OLDEMULE){
m_clientSoft = SO_OLDEMULE;
UINT nClientMinVersion = m_nClientVersion;
m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
TCHAR szSoftware[128];
int iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("Old eMule v0.%u"), nClientMinVersion);
if (iLen > 0){
memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
m_strClientSoftware.ReleaseBuffer(iLen);
}
return;
}
m_clientSoft = SO_EDONKEY;
UINT nClientMinVersion = m_nClientVersion;
m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
TCHAR szSoftware[128];
int iLen = _sntprintf(szSoftware, ARRSIZE(szSoftware), _T("eDonkey v0.%u"), nClientMinVersion);
if (iLen > 0){
memcpy(m_strClientSoftware.GetBuffer(iLen), szSoftware, iLen*sizeof(TCHAR));
m_strClientSoftware.ReleaseBuffer(iLen);
}
}
int CUpDownClient::GetHashType() const
{
if (m_achUserHash[5] == 13 && m_achUserHash[14] == 110)
return SO_OLDEMULE;
else if (m_achUserHash[5] == 14 && m_achUserHash[14] == 111)
return SO_EMULE;
else if (m_achUserHash[5] == 'M' && m_achUserHash[14] == 'L')
return SO_MLDONKEY;
else
return SO_UNKNOWN;
}
void CUpDownClient::SetUserName(LPCTSTR pszNewName)
{
free(m_pszUsername);
if (pszNewName)
m_pszUsername = _tcsdup(pszNewName);
else
m_pszUsername = NULL;
UpdateFunnyNick(); //Xman Funny-Nick (Stulle/Morph)
}
void CUpDownClient::RequestSharedFileList()
{
if (m_iFileListRequested == 0){
AddLogLine(true, GetResString(IDS_SHAREDFILES_REQUEST), GetUserName());
m_iFileListRequested = 1;
TryToConnect(true);
}
else{
LogWarning(LOG_STATUSBAR, _T("Requesting shared files from user %s (%u) is already in progress"), GetUserName(), GetUserIDHybrid());
}
}
void CUpDownClient::ProcessSharedFileList(const uchar* pachPacket, uint32 nSize, LPCTSTR pszDirectory)
{
if (m_iFileListRequested > 0)
{
m_iFileListRequested--;
theApp.searchlist->ProcessSearchAnswer(pachPacket,nSize,this,NULL,pszDirectory);
}
}
void CUpDownClient::SetUserHash(const uchar* pucUserHash)
{
if( pucUserHash == NULL ){
md4clr(m_achUserHash);
return;
}
md4cpy(m_achUserHash, pucUserHash);
}
void CUpDownClient::SetBuddyID(const uchar* pucBuddyID)
{
if( pucBuddyID == NULL ){
md4clr(m_achBuddyID);
m_bBuddyIDValid = false;
return;
}
m_bBuddyIDValid = true;
md4cpy(m_achBuddyID, pucBuddyID);
}
void CUpDownClient::SendPublicKeyPacket()
{
// send our public key to the client who requested it
if (socket == NULL || credits == NULL || m_SecureIdentState != IS_KEYANDSIGNEEDED){
//zz_fly :: see the optimizes in clientcreditlist
/*
ASSERT ( false );
*/
//zz_fly :: see the optimizes in clientcreditlist
return;
}
if (!theApp.clientcredits->CryptoAvailable())
return;
Packet* packet = new Packet(OP_PUBLICKEY,theApp.clientcredits->GetPubKeyLen() + 1,OP_EMULEPROT);
theStats.AddUpDataOverheadOther(packet->size);
memcpy(packet->pBuffer+1,theApp.clientcredits->GetPublicKey(), theApp.clientcredits->GetPubKeyLen());
packet->pBuffer[0] = theApp.clientcredits->GetPubKeyLen();
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__PublicKey", this);
SendPacket(packet, true);
m_SecureIdentState = IS_SIGNATURENEEDED;
}
void CUpDownClient::SendSignaturePacket()
{
// signate the public key of this client and send it
if (socket == NULL || credits == NULL || m_SecureIdentState == 0){
//zz_fly :: see the optimizes in clientcreditlist
/*
ASSERT ( false );
*/
//zz_fly :: see the optimizes in clientcreditlist
return;
}
if (!theApp.clientcredits->CryptoAvailable())
return;
if (credits->GetSecIDKeyLen() == 0)
return; // We don't have his public key yet, will be back here later
// do we have a challenge value received (actually we should if we are in this function)
if (credits->m_dwCryptRndChallengeFrom == 0){
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("Want to send signature but challenge value is invalid ('%s')"), GetUserName());
return;
}
// v2
// we will use v1 as default, except if only v2 is supported
bool bUseV2;
if ( (m_bySupportSecIdent&1) == 1 )
bUseV2 = false;
else
bUseV2 = true;
uint8 byChaIPKind = 0;
uint32 ChallengeIP = 0;
if (bUseV2){
if (theApp.serverconnect->GetClientID() == 0 || theApp.serverconnect->IsLowID()){
// we cannot do not know for sure our public ip, so use the remote clients one
ChallengeIP = GetIP();
byChaIPKind = CRYPT_CIP_REMOTECLIENT;
}
else{
ChallengeIP = theApp.serverconnect->GetClientID();
byChaIPKind = CRYPT_CIP_LOCALCLIENT;
}
}
//end v2
uchar achBuffer[250];
uint8 siglen = theApp.clientcredits->CreateSignature(credits, achBuffer, 250, ChallengeIP, byChaIPKind );
if (siglen == 0){
ASSERT ( false );
return;
}
Packet* packet = new Packet(OP_SIGNATURE,siglen + 1+ ( (bUseV2)? 1:0 ),OP_EMULEPROT);
theStats.AddUpDataOverheadOther(packet->size);
memcpy(packet->pBuffer+1,achBuffer, siglen);
packet->pBuffer[0] = siglen;
if (bUseV2)
packet->pBuffer[1+siglen] = byChaIPKind;
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__Signature", this);
SendPacket(packet, true);
m_SecureIdentState = IS_ALLREQUESTSSEND;
}
void CUpDownClient::ProcessPublicKeyPacket(const uchar* pachPacket, uint32 nSize)
{
theApp.clientlist->AddTrackClient(this);
if (socket == NULL || credits == NULL || pachPacket[0] != nSize-1
|| nSize < 10 || nSize > 250){
//zz_fly :: see the optimizes in clientcreditlist
/*
ASSERT ( false );
*/
//zz_fly :: see the optimizes in clientcreditlist
return;
}
if (!theApp.clientcredits->CryptoAvailable())
return;
// the function will handle everything (mulitple key etc)
if (credits->SetSecureIdent(pachPacket+1, pachPacket[0])){
// if this client wants a signature, now we can send him one
if (m_SecureIdentState == IS_SIGNATURENEEDED){
SendSignaturePacket();
}
else if(m_SecureIdentState == IS_KEYANDSIGNEEDED)
{
// something is wrong
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("Invalid State error: IS_KEYANDSIGNEEDED in ProcessPublicKeyPacket"));
}
}
else
{
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("Failed to use new received public key"));
}
}
void CUpDownClient::ProcessSignaturePacket(const uchar* pachPacket, uint32 nSize)
{
// here we spread the good guys from the bad ones ;)
if (socket == NULL || credits == NULL || nSize > 250 || nSize < 10){
//zz_fly :: see the optimizes in clientcreditlist
/*
ASSERT ( false );
*/
//zz_fly :: see the optimizes in clientcreditlist
return;
}
uint8 byChaIPKind;
if (pachPacket[0] == nSize-1)
byChaIPKind = 0;
else if (pachPacket[0] == nSize-2 && (m_bySupportSecIdent & 2) > 0) //v2
byChaIPKind = pachPacket[nSize-1];
else{
ASSERT ( false );
return;
}
if (!theApp.clientcredits->CryptoAvailable())
return;
// we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions
if (m_dwLastSignatureIP == GetIP())
{
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("received multiple signatures from one client"));
return;
}
// also make sure this client has a public key
if (credits->GetSecIDKeyLen() == 0)
{
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("received signature for client without public key"));
return;
}
// and one more check: did we ask for a signature and sent a challange packet?
if (credits->m_dwCryptRndChallengeFor == 0)
{
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("received signature for client with invalid challenge value ('%s')"), GetUserName());
return;
}
if (theApp.clientcredits->VerifyIdent(credits, pachPacket+1, pachPacket[0], GetIP(), byChaIPKind ) ){
// result is saved in function abouve
//if (thePrefs.GetLogSecureIdent())
// AddDebugLogLine(false, _T("'%s' has passed the secure identification, V2 State: %i"), GetUserName(), byChaIPKind);
// inform our friendobject if needed
if (GetFriend() != NULL && GetFriend()->IsTryingToConnect())
GetFriend()->UpdateFriendConnectionState(FCR_USERHASHVERIFIED);
}
else
{
if (GetFriend() != NULL && GetFriend()->IsTryingToConnect())
GetFriend()->UpdateFriendConnectionState(FCR_SECUREIDENTFAILED);
if (thePrefs.GetLogSecureIdent())
AddDebugLogLine(false, _T("'%s' has failed the secure identification, V2 State: %i"), GetUserName(), byChaIPKind);
}
m_dwLastSignatureIP = GetIP();
}
void CUpDownClient::SendSecIdentStatePacket()
{
// check if we need public key and signature
uint8 nValue = 0;
if (credits){
if (theApp.clientcredits->CryptoAvailable()){
if (credits->GetSecIDKeyLen() == 0)
nValue = IS_KEYANDSIGNEEDED;
else if (m_dwLastSignatureIP != GetIP())
nValue = IS_SIGNATURENEEDED;
}
if (nValue == 0){
//if (thePrefs.GetLogSecureIdent())
// AddDebugLogLine(false, _T("Not sending SecIdentState Packet, because State is Zero"));
return;
}
// crypt: send random data to sign
uint32 dwRandom = rand()+1;
credits->m_dwCryptRndChallengeFor = dwRandom;
Packet* packet = new Packet(OP_SECIDENTSTATE,5,OP_EMULEPROT);
theStats.AddUpDataOverheadOther(packet->size);
packet->pBuffer[0] = nValue;
PokeUInt32(packet->pBuffer+1, dwRandom);
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__SecIdentState", this);
SendPacket(packet, true);
}
else
ASSERT ( false );
}
void CUpDownClient::ProcessSecIdentStatePacket(const uchar* pachPacket, uint32 nSize)
{
if (nSize != 5)
return;
if (!credits){
//zz_fly :: see the optimizes in clientcreditlist
/*
ASSERT ( false );
*/
//zz_fly :: see the optimizes in clientcreditlist
return;
}
switch(pachPacket[0]){
case 0:
m_SecureIdentState = IS_UNAVAILABLE;
break;
case 1:
m_SecureIdentState = IS_SIGNATURENEEDED;
break;
case 2:
m_SecureIdentState = IS_KEYANDSIGNEEDED;
break;
}
credits->m_dwCryptRndChallengeFrom = PeekUInt32(pachPacket+1);
}
void CUpDownClient::InfoPacketsReceived()
{
// indicates that both Information Packets has been received
// needed for actions, which process data from both packets
ASSERT ( m_byInfopacketsReceived == IP_BOTH );
m_byInfopacketsReceived = IP_NONE;
if (m_bySupportSecIdent){
SendSecIdentStatePacket();
}
}
void CUpDownClient::ResetFileStatusInfo()
{
delete[] m_abyPartStatus;
m_abyPartStatus = NULL;
//Xman Xtreme Downloadmanager
// Maella -Unnecessary Protocol Overload-
//m_dwLastAskedTime = 0; we don't reset this value, to decide if a droped client may reenter the queue, see CheckAndAdd
m_dwLastUDPReaskTime = 0;
m_dwNextTCPAskedTime = 0;
// Maella end
//Xman Xtreme Mod
//at this point there can't be UDPpending... only if we remove the source.. and then we have to reset this value
m_bUDPPending=false;
/*
m_nRemoteQueueRank = 0;
*/
SetRemoteQueueRank(0,false);
oldQR=0; //Xman DiffQR
//Xman end
m_nPartCount = 0;
m_strClientFilename.Empty();
m_bCompleteSource = false;
m_uFileRating = 0;
m_strFileComment.Empty();
delete m_pReqFileAICHHash;
m_pReqFileAICHHash = NULL;
if(reqfile != NULL) reqfile->RemoveSourceFileName(this); // Follow The Majority [AndCycle/Stulle] - Stulle
}
bool CUpDownClient::IsBanned() const
{
//Xman official bugfix
/*
return theApp.clientlist->IsBannedClient(GetIP());
*/
return theApp.clientlist->IsBannedClient(GetConnectIP());
//Xman end
}
void CUpDownClient::SendPreviewRequest(const CAbstractFile* pForFile)
{
if (m_fPreviewReqPending == 0){
m_fPreviewReqPending = 1;
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__RequestPreview", this, pForFile->GetFileHash());
Packet* packet = new Packet(OP_REQUESTPREVIEW,16,OP_EMULEPROT);
md4cpy(packet->pBuffer,pForFile->GetFileHash());
theStats.AddUpDataOverheadOther(packet->size);
SafeConnectAndSendPacket(packet);
}
else{
LogWarning(LOG_STATUSBAR, GetResString(IDS_ERR_PREVIEWALREADY));
}
}
void CUpDownClient::SendPreviewAnswer(const CKnownFile* pForFile, CxImage** imgFrames, uint8 nCount)
{
m_fPreviewAnsPending = 0;
CSafeMemFile data(1024);
if (pForFile){
data.WriteHash16(pForFile->GetFileHash());
}
else{
static const uchar _aucZeroHash[16] = {0};
data.WriteHash16(_aucZeroHash);
}
data.WriteUInt8(nCount);
for (int i = 0; i != nCount; i++){
if (imgFrames == NULL){
ASSERT ( false );
return;
}
CxImage* cur_frame = imgFrames[i];
if (cur_frame == NULL){
ASSERT ( false );
return;
}
BYTE* abyResultBuffer = NULL;
long nResultSize = 0;
if (!cur_frame->Encode(abyResultBuffer, nResultSize, CXIMAGE_FORMAT_PNG)){
ASSERT ( false );
return;
}
data.WriteUInt32(nResultSize);
data.Write(abyResultBuffer, nResultSize);
free(abyResultBuffer);
}
Packet* packet = new Packet(&data, OP_EMULEPROT);
packet->opcode = OP_PREVIEWANSWER;
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__PreviewAnswer", this, (uchar*)packet->pBuffer);
theStats.AddUpDataOverheadOther(packet->size);
SafeConnectAndSendPacket(packet);
}
void CUpDownClient::ProcessPreviewReq(const uchar* pachPacket, uint32 nSize)
{
if (nSize < 16)
throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
if (m_fPreviewAnsPending || thePrefs.CanSeeShares()==vsfaNobody || (thePrefs.CanSeeShares()==vsfaFriends && !IsFriend()))
return;
m_fPreviewAnsPending = 1;
CKnownFile* previewFile = theApp.sharedfiles->GetFileByID(pachPacket);
if (previewFile == NULL){
SendPreviewAnswer(NULL, NULL, 0);
}
else{
previewFile->GrabImage(4,0,true,450,this);
}
}
void CUpDownClient::ProcessPreviewAnswer(const uchar* pachPacket, uint32 nSize)
{
if (m_fPreviewReqPending == 0)
return;
m_fPreviewReqPending = 0;
CSafeMemFile data(pachPacket,nSize);
uchar Hash[16];
data.ReadHash16(Hash);
uint8 nCount = data.ReadUInt8();
if (nCount == 0){
LogError(LOG_STATUSBAR, GetResString(IDS_ERR_PREVIEWFAILED), GetUserName());
return;
}
CSearchFile* sfile = theApp.searchlist->GetSearchFileByHash(Hash);
if (sfile == NULL){
//already deleted
return;
}
BYTE* pBuffer = NULL;
try{
for (int i = 0; i != nCount; i++){
uint32 nImgSize = data.ReadUInt32();
if (nImgSize > nSize)
throw CString(_T("CUpDownClient::ProcessPreviewAnswer - Provided image size exceeds limit"));
pBuffer = new BYTE[nImgSize];
data.Read(pBuffer, nImgSize);
CxImage* image = new CxImage(pBuffer, nImgSize, CXIMAGE_FORMAT_PNG);
delete[] pBuffer;
pBuffer = NULL;
if (image->IsValid())
sfile->AddPreviewImg(image);
else
delete image;
}
}
catch(...){
if(pBuffer) //zz_fly :: from ACAT
delete[] pBuffer;
throw;
}
(new PreviewDlg())->SetFile(sfile);
}
// sends a packet, if needed it will establish a connection before
// options used: ignore max connections, control packet, delete packet
// !if the functions returns false that client object was deleted because the connection try failed and the object wasn't needed anymore.
bool CUpDownClient::SafeConnectAndSendPacket(Packet* packet)
{
if (socket != NULL && socket->IsConnected())
{
socket->SendPacket(packet, true, true);
return true;
}
else
{
m_WaitingPackets_list.AddTail(packet);
return TryToConnect(true);
}
}
bool CUpDownClient::SendPacket(Packet* packet, bool bDeletePacket, bool bVerifyConnection)
{
if (socket != NULL && (!bVerifyConnection || socket->IsConnected()))
{
socket->SendPacket(packet, bDeletePacket, true);
return true;
}
else
{
DebugLogError(_T("Outgoing packet (0x%X) discarded because expected socket or connection does not exists %s"), packet->opcode, DbgGetClientInfo());
if (bDeletePacket)
delete packet;
return false;
}
}
#ifdef _DEBUG
void CUpDownClient::AssertValid() const
{
CObject::AssertValid();
CHECK_OBJ(socket);
CHECK_PTR(credits);
CHECK_PTR(m_Friend);
CHECK_OBJ(reqfile);
(void)m_abyUpPartStatus;
m_OtherRequests_list.AssertValid();
m_OtherNoNeeded_list.AssertValid();
(void)m_lastPartAsked;
(void)m_cMessagesReceived;
(void)m_cMessagesSent;
(void)m_dwUserIP;
(void)m_dwServerIP;
(void)m_nUserIDHybrid;
(void)m_nUserPort;
(void)m_nServerPort;
(void)m_nClientVersion;
(void)m_nUpDatarate;
(void)m_byEmuleVersion;
(void)m_byDataCompVer;
CHECK_BOOL(m_bEmuleProtocol);
CHECK_BOOL(m_bIsHybrid);
(void)m_pszUsername;
(void)m_achUserHash;
(void)m_achBuddyID;
(void)m_nBuddyIP;
(void)m_nBuddyPort;
(void)m_nUDPPort;
(void)m_nKadPort;
(void)m_byUDPVer;
(void)m_bySourceExchange1Ver;
(void)m_byAcceptCommentVer;
(void)m_byExtendedRequestsVer;
CHECK_BOOL(m_bFriendSlot);
CHECK_BOOL(m_bCommentDirty);
CHECK_BOOL(m_bIsML);
//ASSERT( m_clientSoft >= SO_EMULE && m_clientSoft <= SO_SHAREAZA || m_clientSoft == SO_MLDONKEY || m_clientSoft >= SO_EDONKEYHYBRID && m_clientSoft <= SO_UNKNOWN );
(void)m_strClientSoftware;
(void)m_dwLastSourceRequest;
(void)m_dwLastSourceAnswer;
(void)m_dwLastAskedForSources;
(void)m_iFileListRequested;
(void)m_byCompatibleClient;
m_WaitingPackets_list.AssertValid();
m_DontSwap_list.AssertValid();
(void)m_lastRefreshedDLDisplay;
ASSERT( m_SecureIdentState >= IS_UNAVAILABLE && m_SecureIdentState <= IS_KEYANDSIGNEEDED );
(void)m_dwLastSignatureIP;
ASSERT( (m_byInfopacketsReceived & ~IP_BOTH) == 0 );
(void)m_bySupportSecIdent;
(void)m_nTransferredUp;
ASSERT( m_nUploadState >= US_UPLOADING && m_nUploadState <= US_NONE );
(void)m_dwUploadTime;
(void)m_cAsked;
(void)m_dwLastUpRequest;
(void)m_nCurSessionUp;
(void)m_nCurQueueSessionPayloadUp;
(void)m_addedPayloadQueueSession;
(void)m_nUpPartCount;
(void)m_nUpCompleteSourcesCount;
//Xman
/*
(void)s_UpStatusBar;
*/
//Xman end
(void)requpfileid;
(void)m_lastRefreshedULDisplay;
//Xman
/*
m_AvarageUDR_list.AssertValid();
*/
//Xman end
m_BlockRequests_queue.AssertValid();
m_DoneBlocks_list.AssertValid();
m_RequestedFiles_list.AssertValid();
ASSERT( m_nDownloadState >= DS_DOWNLOADING && m_nDownloadState <= DS_NONE );
(void)m_cDownAsked;
(void)m_abyPartStatus;
(void)m_strClientFilename;
(void)m_nTransferredDown;
(void)m_nCurSessionPayloadDown;
(void)m_dwDownStartTime;
(void)m_nLastBlockOffset;
(void)m_nDownDatarate;
//Xman
/*
(void)m_nDownDataRateMS;
(void)m_nSumForAvgDownDataRate;
(void)m_cShowDR;
*/
//Xman end
(void)m_nRemoteQueueRank;
(void)m_dwLastBlockReceived;
(void)m_nPartCount;
ASSERT( m_nSourceFrom >= SF_SERVER && m_nSourceFrom <= SF_LINK );
CHECK_BOOL(m_bRemoteQueueFull);
CHECK_BOOL(m_bCompleteSource);
CHECK_BOOL(m_bReaskPending);
CHECK_BOOL(m_bUDPPending);
CHECK_BOOL(m_bTransferredDownMini);
CHECK_BOOL(m_bUnicodeSupport);
ASSERT( m_nKadState >= KS_NONE && m_nKadState <= KS_CONNECTING_FWCHECK_UDP);
//Xman
/*
m_AvarageDDR_list.AssertValid();
(void)m_nSumForAvgUpDataRate;
*/
//Xman end
m_PendingBlocks_list.AssertValid();
m_DownloadBlocks_list.AssertValid();
//Xman
/*
(void)s_StatusBar;
*/
//Xman end
ASSERT( m_nChatstate >= MS_NONE && m_nChatstate <= MS_UNABLETOCONNECT );
(void)m_strFileComment;
(void)m_uFileRating;
CHECK_BOOL(m_bCollectionUploadSlot);
CHECK_BOOL(m_bAntiUploaderCaseThree); // Anti Uploader Ban [Stulle] - Stulle
#undef CHECK_PTR
#undef CHECK_BOOL
}
#endif
#ifdef _DEBUG
void CUpDownClient::Dump(CDumpContext& dc) const
{
CObject::Dump(dc);
}
#endif
LPCTSTR CUpDownClient::DbgGetDownloadState() const
{
const static LPCTSTR apszState[] =
{
_T("Downloading"),
_T("OnQueue"),
_T("Connected"),
_T("Connecting"),
_T("WaitCallback"),
_T("WaitCallbackKad"),
_T("ReqHashSet"),
_T("NoNeededParts"),
_T("TooManyConns"),
_T("TooManyConnsKad"),
_T("LowToLowIp"),
_T("Banned"),
_T("Error"),
_T("None"),
_T("RemoteQueueFull")
};
if (GetDownloadState() >= ARRSIZE(apszState))
return _T("*Unknown*");
return apszState[GetDownloadState()];
}
LPCTSTR CUpDownClient::DbgGetUploadState() const
{
const static LPCTSTR apszState[] =
{
_T("Uploading"),
_T("OnUploadQueue"),
_T("Connecting"),
_T("Banned"),
_T("None")
};
if (GetUploadState() >= ARRSIZE(apszState))
return _T("*Unknown*");
return apszState[GetUploadState()];
}
LPCTSTR CUpDownClient::DbgGetKadState() const
{
const static LPCTSTR apszState[] =
{
_T("None"),
_T("FwCheckQueued"),
_T("FwCheckConnecting"),
_T("FwCheckConnected"),
_T("BuddyQueued"),
_T("BuddyIncoming"),
_T("BuddyConnecting"),
_T("BuddyConnected"),
_T("QueuedFWCheckUDP"),
_T("FWCheckUDP"),
_T("FwCheckConnectingUDP")
};
if (GetKadState() >= ARRSIZE(apszState))
return _T("*Unknown*");
return apszState[GetKadState()];
}
CString CUpDownClient::DbgGetFullClientSoftVer() const
{
if (GetClientModVer().IsEmpty())
return GetClientSoftVer();
return GetClientSoftVer() + _T(" [") + GetClientModVer() + _T(']');
}
CString CUpDownClient::DbgGetClientInfo(bool bFormatIP) const
{
CString str;
if (this != NULL)
{
try{
if (HasLowID())
{
if (GetConnectIP())
{
str.Format(_T("%u@%s (%s) '%s' (%s,%s/%s/%s)"),
GetUserIDHybrid(), ipstr(GetServerIP()),
ipstr(GetConnectIP()),
GetUserName(),
DbgGetFullClientSoftVer(),
DbgGetDownloadState(), DbgGetUploadState(), DbgGetKadState());
}
else
{
str.Format(_T("%u@%s '%s' (%s,%s/%s/%s)"),
GetUserIDHybrid(), ipstr(GetServerIP()),
GetUserName(),
DbgGetFullClientSoftVer(),
DbgGetDownloadState(), DbgGetUploadState(), DbgGetKadState());
}
}
else
{
str.Format(bFormatIP ? _T("%-15s '%s' (%s,%s/%s/%s)") : _T("%s '%s' (%s,%s/%s/%s)"),
ipstr(GetConnectIP()),
GetUserName(),
DbgGetFullClientSoftVer(),
DbgGetDownloadState(), DbgGetUploadState(), DbgGetKadState());
}
}
catch(...){
str.Format(_T("%p - Invalid client instance"), this);
}
}
return str;
}
bool CUpDownClient::CheckHandshakeFinished() const
{
if (m_bHelloAnswerPending)
{
// 24-Nov-2004 [bc]: The reason for this is that 2 clients are connecting to each other at the same..
//if (thePrefs.GetVerbose())
// AddDebugLogLine(DLP_VERYLOW, false, _T("Handshake not finished - while processing packet: %s; %s"), DbgGetClientTCPOpcode(protocol, opcode), DbgGetClientInfo());
return false;
}
return true;
}
void CUpDownClient::CheckForGPLEvilDoer()
{
if (!m_strModVersion.IsEmpty()){
LPCTSTR pszModVersion = (LPCTSTR)m_strModVersion;
// skip leading spaces
while (*pszModVersion == _T(' '))
pszModVersion++;
// check for known major gpl breaker
if (_tcsnicmp(pszModVersion, _T("LH"), 2)==0 || _tcsnicmp(pszModVersion, _T("LIO"), 3)==0 || _tcsnicmp(pszModVersion, _T("PLUS PLUS"), 9)==0)
m_bGPLEvildoer = true;
}
}
void CUpDownClient::OnSocketConnected(int /*nErrorCode*/)
{
}
CString CUpDownClient::GetDownloadStateDisplayString() const
{
CString strState;
switch (GetDownloadState())
{
case DS_CONNECTING:
strState = GetResString(IDS_CONNECTING);
break;
case DS_CONNECTED:
strState = GetResString(IDS_ASKING);
break;
case DS_WAITCALLBACK:
strState = GetResString(IDS_CONNVIASERVER);
break;
case DS_ONQUEUE:
if (IsRemoteQueueFull())
strState = GetResString(IDS_QUEUEFULL);
else
// ==> {diffQR} [Max]
//strState = GetResString(IDS_ONQUEUE);
{
if ( GetRemoteQueueRank())
{
if(GetDiffQR()<=0)
{
strState.Format(_T("QR: %u (%i)"), GetRemoteQueueRank(), GetDiffQR());
}
else
{
strState.Format(_T("QR: %u (+%i)"), GetRemoteQueueRank(), GetDiffQR());// +QR [Max]
}
}
else
{
strState = GetResString(IDS_ONQUEUE);
}
}
// <== {diffQR} [Max]
break;
case DS_DOWNLOADING:
strState = GetResString(IDS_TRANSFERRING);
break;
case DS_REQHASHSET:
strState = GetResString(IDS_RECHASHSET);
break;
case DS_NONEEDEDPARTS:
strState = GetResString(IDS_NONEEDEDPARTS);
break;
case DS_LOWTOLOWIP:
strState = GetResString(IDS_NOCONNECTLOW2LOW);
break;
case DS_TOOMANYCONNS:
strState = GetResString(IDS_TOOMANYCONNS);
break;
case DS_ERROR:
strState = GetResString(IDS_ERROR);
break;
case DS_WAITCALLBACKKAD:
strState = GetResString(IDS_KAD_WAITCBK);
break;
case DS_TOOMANYCONNSKAD:
strState = GetResString(IDS_KAD_TOOMANDYKADLKPS);
break;
}
//Xman
/*
if (thePrefs.GetPeerCacheShow())
{
*/
//Xman end
switch (m_ePeerCacheDownState)
{
case PCDS_WAIT_CLIENT_REPLY:
strState += _T(" ")+GetResString(IDS_PCDS_CLIENTWAIT);
break;
case PCDS_WAIT_CACHE_REPLY:
strState += _T(" ")+GetResString(IDS_PCDS_CACHEWAIT);
break;
case PCDS_DOWNLOADING:
strState += _T(" ")+GetResString(IDS_CACHE);
break;
}
if (m_ePeerCacheDownState != PCDS_NONE && m_bPeerCacheDownHit)
strState += _T(" Hit");
//Xman
/*
}
*/
//Xman end
//Xman 4.2
if(GetUploadState()==US_UPLOADING)
strState = _T(">>") + strState;
//Xman end
return strState;
}
CString CUpDownClient::GetUploadStateDisplayString() const
{
CString strState;
switch (GetUploadState()){
case US_ONUPLOADQUEUE:
strState = GetResString(IDS_ONQUEUE);
break;
case US_BANNED:
strState = GetResString(IDS_BANNED);
break;
case US_CONNECTING:
strState = GetResString(IDS_CONNECTING);
break;
case US_UPLOADING:
//Xman Xtreme Upload
/*
if(GetPayloadInBuffer() == 0 && GetNumberOfRequestedBlocksInQueue() == 0 && thePrefs.IsExtControlsEnabled()) {
strState = GetResString(IDS_US_STALLEDW4BR);
} else if(GetPayloadInBuffer() == 0 && thePrefs.IsExtControlsEnabled()) {
strState = GetResString(IDS_US_STALLEDREADINGFDISK);
} else if(GetSlotNumber() <= theApp.uploadqueue->GetActiveUploadsCount()) {
strState = GetResString(IDS_TRANSFERRING);
} else {
strState = GetResString(IDS_TRICKLING);
}
*/
if(GetPayloadInBuffer() == 0 && GetNumberOfRequestedBlocksInQueue() == 0 && thePrefs.IsExtControlsEnabled())
strState = GetResString(IDS_US_STALLEDW4BR);
else if(GetPayloadInBuffer() == 0 && thePrefs.IsExtControlsEnabled())
strState = GetResString(IDS_US_STALLEDREADINGFDISK);
else
strState = GetResString(IDS_TRANSFERRING);
//Xman end
break;
}
//Xman
/*
if (thePrefs.GetPeerCacheShow())
*/
//Xman end
{
switch (m_ePeerCacheUpState)
{
case PCUS_WAIT_CACHE_REPLY:
strState += _T(" CacheWait");
break;
case PCUS_UPLOADING:
//Xman
/*
strState += _T(" Cache");
*/
strState += _T(" PeerCache");
//Xman end
break;
}
if (m_ePeerCacheUpState != PCUS_NONE && m_bPeerCacheUpHit)
strState += _T(" Hit");
}
// ==> Spread Credits Slot [Stulle] - Stulle
if( thePrefs.GetSpreadCreditsSlot() && thePrefs.TransferFullChunks() )
{
switch(GetSpreadClient())
{
case 1:
strState += _T(" @Spr N");
break;
case 2:
strState += _T(" @Spr O");
break;
case 0:
default:
break;
}
}
// <== Spread Credits Slot [Stulle] - Stulle
//Xman 4.2
if(GetDownloadState()==DS_DOWNLOADING)
strState = _T("<<") + strState;
//Xman end
return strState;
}
void CUpDownClient::SendPublicIPRequest(){
if (socket && socket->IsConnected()){
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__PublicIPReq", this);
Packet* packet = new Packet(OP_PUBLICIP_REQ,0,OP_EMULEPROT);
theStats.AddUpDataOverheadOther(packet->size);
SendPacket(packet, true);
m_fNeedOurPublicIP = 1;
}
}
void CUpDownClient::ProcessPublicIPAnswer(const BYTE* pbyData, UINT uSize){
if (uSize != 4)
throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
uint32 dwIP = PeekUInt32(pbyData);
if (m_fNeedOurPublicIP == 1){ // did we?
m_fNeedOurPublicIP = 0;
//Xman: we have a problem if our IP ends with 0. The Check for IsLowID() would be true and
//the code can't work (also official part)
//Fix: if we receive a LowID we do a recheck
/*
if (theApp.GetPublicIP() == 0 && !::IsLowID(dwIP) )
theApp.SetPublicIP(dwIP);
*/
if(dwIP==0) return; //thats wrong in every case
if(IsLowID(dwIP) && dwIP!=theApp.recheck_ip)
{
//check if still needed:
if(theApp.m_bneedpublicIP
|| theApp.serverconnect->IsConnected() && theApp.GetPublicIP() == 0)
theApp.recheck_ip=dwIP;
return; //will force a new request
}
//Xman -Reask sources after IP change- v4
if(theApp.m_bneedpublicIP /*&& !::IsLowID(dwIP)*/) //this is the case we have kad-only but no upload->inet down ?
{
//Xman new adapter selection
{
uint32 test=dwIP;
CString tmp;
tmp.Format(_T("received an IP from a client: %u.%u.%u.%u, NAFC-Adapter will be checked"), (uint8)test, (uint8)(test>>8), (uint8)(test>>16), (uint8)(test>>24));
AddLogLine(false,tmp);
theApp.pBandWidthControl->checkAdapterIndex(dwIP);
}
//Xman end
if(theApp.last_valid_ip!=0 && theApp.last_valid_ip != dwIP)
{
//if we had a lowID we asume we get it again. Then let the server trigger
if((theApp.serverconnect->IsConnecting() && IsLowID(theApp.last_valid_serverid))
|| (theApp.serverconnect->IsConnected() && theApp.serverconnect->IsLowID() && theApp.GetPublicIP(true)!=dwIP))
{
//don't trigger
}
else
{
// ==> Quick start [TPT] - Max
if(thePrefs.GetQuickStart() && thePrefs.GetQuickStartAfterIPChange())
{
theApp.downloadqueue->quickflag = 0;
theApp.downloadqueue->quickflags = 0;
}
// <== Quick start [TPT] - Max
if(GetTickCount() - theApp.last_ip_change > FILEREASKTIME + 60000)
{
theApp.clientlist->TrigReaskForDownload(true);
AddLogLine(false, _T("Kad Connection detected IP-change, changed IP from %s to %s, all sources will be reasked immediately"), ipstr(theApp.last_valid_ip), ipstr(dwIP));
}
else
{
theApp.clientlist->TrigReaskForDownload(false);
AddLogLine(false, _T("Kad Connection detected IP-change, changed IP from %s to %s, all sources will be reasked within the next 10 minutes"), ipstr(theApp.last_valid_ip), ipstr(dwIP));
}
SetNextTCPAskedTime(::GetTickCount() + FILEREASKTIME); //not for this source
}
// ==> UPnP support [MoNKi] - leuk_he
/*
//zz_fly :: Rebind UPnP on IP-change :: start
#ifdef DUAL_UPNP //zz_fly :: dual upnp
//UPnP chooser
if (thePrefs.m_bUseACATUPnPCurrent){
//ACAT UPnP
if(thePrefs.GetUPnPNat() && thePrefs.GetUPnPNatRebind()){
theApp.clientudp->RebindUPnP();
theApp.listensocket->RebindUPnP();
}
}
else
#endif //zz_fly :: dual upnp
{
//Official UPNP
// we don't want to trigger it twice, do we?!
theApp.emuledlg->RefreshUPnP(false); // refresh the UPnP mappings once
}
//zz_fly :: Rebind UPnP on IP-change :: end
*/
// <== UPnP support [MoNKi] - leuk_he
// Xman reconnect Kad on IP-change
if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetPrefs()->GetIPAddress())
if(ntohl(Kademlia::CKademlia::GetIPAddress()) != dwIP)
{
if(Kademlia::CKademlia::GetIPAddress()!=0)
{
AddDebugLogLine(DLP_DEFAULT, false, _T("Public IP Address reported from Kademlia (%s) differs from new found (%s), restart Kad"),ipstr(ntohl(Kademlia::CKademlia::GetIPAddress())),ipstr(dwIP));
Kademlia::CKademlia::Stop();
Kademlia::CKademlia::Start();
}
//Kad loaded the old IP, we must reset
if(Kademlia::CKademlia::IsRunning()) //one more check
{
Kademlia::CKademlia::GetPrefs()->SetIPAddress(0);
Kademlia::CKademlia::GetPrefs()->SetIPAddress(htonl(dwIP));
}
}
//Xman end
//on some routers it needs endless time until a server-reconnect is initiated after ip-change
if(theApp.serverconnect->IsConnected() && theApp.GetPublicIP(true)!=dwIP)
{
theApp.serverconnect->Disconnect();
theApp.serverconnect->ConnectToAnyServer();
}
}
theApp.last_valid_ip=dwIP;
theApp.m_bneedpublicIP=false;
theApp.last_ip_change=::GetTickCount(); //remark: this is set when ever inet was down, even we receive the old ip
}
if(theApp.serverconnect->IsConnected())//remark: this is the case we have a lowid-server-connect
if (theApp.GetPublicIP() == 0 /*&& !::IsLowID(dwIP)*/ )
{
theApp.SetPublicIP(dwIP);
theApp.last_valid_ip=dwIP;
}
//Xman end
//Xman fix
theApp.recheck_ip=0;
}
}
void CUpDownClient::CheckFailedFileIdReqs(const uchar* aucFileHash)
{
if ( aucFileHash != NULL && (theApp.sharedfiles->IsUnsharedFile(aucFileHash) || theApp.downloadqueue->GetFileByID(aucFileHash)) )
return;
//if (GetDownloadState() != DS_DOWNLOADING) // filereq floods are never allowed!
{
if (m_fFailedFileIdReqs < 6)// NOTE: Do not increase this nr. without increasing the bits for 'm_fFailedFileIdReqs'
m_fFailedFileIdReqs++;
if (m_fFailedFileIdReqs == 6)
{
//Xman we filter not ban!
/*
if (theApp.clientlist->GetBadRequests(this) < 2)
theApp.clientlist->TrackBadRequest(this, 1);
if (theApp.clientlist->GetBadRequests(this) == 2){
theApp.clientlist->TrackBadRequest(this, -2); // reset so the client will not be rebanned right after the ban is lifted
Ban(_T("FileReq flood"));
}
throw CString(thePrefs.GetLogBannedClients() ? _T("FileReq flood") : _T(""));
*/
throw CString(_T("FileReq flood"));
//Xman end
}
}
}
EUtf8Str CUpDownClient::GetUnicodeSupport() const
{
if (m_bUnicodeSupport)
return utf8strRaw;
return utf8strNone;
}
void CUpDownClient::SetSpammer(bool bVal){
if (bVal)
Ban(_T("Identified as Spammer"));
else if (IsBanned() && m_fIsSpammer)
UnBan();
m_fIsSpammer = bVal ? 1 : 0;
}
void CUpDownClient::SetMessageFiltered(bool bVal) {
m_fMessageFiltered = bVal ? 1 : 0;
}
bool CUpDownClient::IsObfuscatedConnectionEstablished() const {
if (socket != NULL && socket->IsConnected())
return socket->IsObfusicating();
else
return false;
}
bool CUpDownClient::ShouldReceiveCryptUDPPackets() const {
return (thePrefs.IsClientCryptLayerSupported() && SupportsCryptLayer() && theApp.GetPublicIP() != 0
&& HasValidHash() && (thePrefs.IsClientCryptLayerRequested() || RequestsCryptLayer()) );
}
void CUpDownClient::ProcessChatMessage(CSafeMemFile* data, uint32 nLength)
{
//filter me?
if ( (thePrefs.MsgOnlyFriends() && !IsFriend()) || (thePrefs.MsgOnlySecure() && GetUserName()==NULL) )
{
if (!GetMessageFiltered()){
if (thePrefs.GetVerbose())
AddDebugLogLine(false,_T("Filtered Message from '%s' (IP:%s)"), GetUserName(), ipstr(GetConnectIP()));
}
SetMessageFiltered(true);
return;
}
CString strMessage(data->ReadString(GetUnicodeSupport()!=utf8strNone, nLength));
if (thePrefs.GetDebugClientTCPLevel() > 0)
Debug(_T(" %s\n"), strMessage);
// default filtering
CString strMessageCheck(strMessage);
//Xman Anti-Leecher
//Xman DLP
if(GetUploadState()==US_BANNED)
return; //just to be sure
if(GetMessagesReceived()==0 && //it's the first message we receive
IsFriend()==false && //and it isn't a friend
thePrefs.GetAntiLeecherspammer() &&
theApp.dlp->IsDLPavailable()
)
{
LPCTSTR reason=theApp.dlp->DLPCheckMessageSpam(strMessageCheck);
if(reason)
{
theApp.emuledlg->chatwnd->chatselector.EndSession(this);
BanLeecher(_T(""),0); //dirty trick to get the message
BanLeecher(reason,7);
ProcessBanMessage();
return;
}
}
//Xman end
strMessageCheck.MakeLower();
CString resToken;
int curPos = 0;
resToken = thePrefs.GetMessageFilter().Tokenize(_T("|"), curPos);
while (!resToken.IsEmpty())
{
resToken.Trim();
if (strMessageCheck.Find(resToken.MakeLower()) > -1){
if ( thePrefs.IsAdvSpamfilterEnabled() && !IsFriend() && GetMessagesSent() == 0 ){
SetSpammer(true);
theApp.emuledlg->chatwnd->chatselector.EndSession(this);
}
return;
}
resToken = thePrefs.GetMessageFilter().Tokenize(_T("|"), curPos);
}
// advanced spamfilter check
if (thePrefs.IsChatCaptchaEnabled() && !IsFriend()) {
// captcha checks outrank any further checks - if the captcha has been solved, we assume its no spam
// first check if we need to sent a captcha request to this client
if (GetMessagesSent() == 0 && GetMessagesReceived() == 0 && GetChatCaptchaState() != CA_CAPTCHASOLVED)
{
// we have never sent a message to this client, and no message from him has ever passed our filters
if (GetChatCaptchaState() != CA_CHALLENGESENT)
{
// we also aren't currently expecting a cpatcha response
if (m_fSupportsCaptcha != NULL)
{
// and he supports captcha, so send him on and store the message (without showing for now)
if (m_cCaptchasSent < 3) // no more than 3 tries
{
m_strCaptchaPendingMsg = strMessage;
CSafeMemFile fileAnswer(1024);
fileAnswer.WriteUInt8(0); // no tags, for future use
CCaptchaGenerator captcha(4);
if (captcha.WriteCaptchaImage(fileAnswer)){
m_strCaptchaChallenge = captcha.GetCaptchaText();
m_nChatCaptchaState = CA_CHALLENGESENT;
m_cCaptchasSent++;
Packet* packet = new Packet(&fileAnswer, OP_EMULEPROT, OP_CHATCAPTCHAREQ);
theStats.AddUpDataOverheadOther(packet->size);
if (!SafeConnectAndSendPacket(packet))
return; // deleted client while connecting
}
else{
ASSERT( false );
DebugLogError(_T("Failed to create Captcha for client %s"), DbgGetClientInfo());
}
}
}
else
{
// client doesn't supports captchas, but we require them, tell him that its not going to work out
// with an answer message (will not be shown and doesn't counts as sent message)
if (m_cCaptchasSent < 1) // dont sent this notifier more than once
{
m_cCaptchasSent++;
// always sent in english
CString rstrMessage = _T("In order to avoid spam messages, this user requires you to solve a captcha before you can send a message to him. However your client does not support captchas, so you will not be able to chat with this user.");
DebugLog(_T("Received message from client not supporting captchs, filtered and sent notifier (%s)"), DbgGetClientInfo());
SendChatMessage(rstrMessage); // could delete client
}
else
DebugLog(_T("Received message from client not supporting captchs, filtered, didn't sent notifier (%s)"), DbgGetClientInfo());
}
return;
}
else //(GetChatCaptchaState() == CA_CHALLENGESENT)
{
// this message must be the answer to the captcha request we send him, lets verify
ASSERT( !m_strCaptchaChallenge.IsEmpty() );
if (m_strCaptchaChallenge.CompareNoCase(strMessage.Trim().Right(min(strMessage.GetLength(), m_strCaptchaChallenge.GetLength()))) == 0){
// allright
DebugLog(_T("Captcha solved, showing withheld message (%s)"), DbgGetClientInfo());
m_nChatCaptchaState = CA_CAPTCHASOLVED; // this state isn't persitent, but the messagecounter will be used to determine later if the captcha has been solved
// replace captchaanswer with withheld message and show it
strMessage = m_strCaptchaPendingMsg;
m_cCaptchasSent = 0;
m_strCaptchaChallenge = _T("");
Packet* packet = new Packet(OP_CHATCAPTCHARES, 1, OP_EMULEPROT, false);
packet->pBuffer[0] = 0; // status response
theStats.AddUpDataOverheadOther(packet->size);
if (!SafeConnectAndSendPacket(packet)) {
ASSERT( false ); // deleted client while connecting
return;
}
}
else{ // wrong, cleanup and ignore
DebugLogWarning(_T("Captcha answer failed (%s)"), DbgGetClientInfo());
m_nChatCaptchaState = CA_NONE;
m_strCaptchaChallenge = _T("");
m_strCaptchaPendingMsg = _T("");
Packet* packet = new Packet(OP_CHATCAPTCHARES, 1, OP_EMULEPROT, false);
packet->pBuffer[0] = (m_cCaptchasSent < 3)? 1 : 2; // status response
theStats.AddUpDataOverheadOther(packet->size);
SafeConnectAndSendPacket(packet);
return; // nothing more todo
}
}
}
else
DEBUG_ONLY( DebugLog(_T("Message passed CaptchaFilter - already solved or not needed (%s)"), DbgGetClientInfo()) );
}
if (thePrefs.IsAdvSpamfilterEnabled() && !IsFriend()) // friends are never spammer... (but what if two spammers are friends :P )
{
bool bIsSpam = false;
if (IsSpammer())
bIsSpam = true;
else
{
// first fixed criteria: If a client sends me an URL in his first message before I response to him
// there is a 99,9% chance that it is some poor guy advising his leech mod, or selling you .. well you know :P
if (GetMessagesSent() == 0){
int curPos=0;
CString resToken = CString(URLINDICATOR).Tokenize(_T("|"), curPos);
while (resToken != _T("")){
if (strMessage.Find(resToken) > (-1) )
bIsSpam = true;
resToken= CString(URLINDICATOR).Tokenize(_T("|"),curPos);
}
// second fixed criteria: he sent me 4 or more messages and I didn't answered him once
if (GetMessagesReceived() > 3)
bIsSpam = true;
}
}
if (bIsSpam)
{
if (IsSpammer()){
if (thePrefs.GetVerbose())
//Xman
/*
AddDebugLogLine(false, _T("'%s' has been marked as spammer"), GetUserName());
*/
AddLeecherLogLine(false, _T("'%s' has been marked as spammer"), GetUserName());
//Xman end
}
SetSpammer(true);
theApp.emuledlg->chatwnd->chatselector.EndSession(this);
return;
}
}
theApp.emuledlg->chatwnd->chatselector.ProcessMessage(this, strMessage);
}
void CUpDownClient::ProcessCaptchaRequest(CSafeMemFile* data){
// received a captcha request, check if we actually accept it (only after sending a message ourself to this client)
if (GetChatCaptchaState() == CA_ACCEPTING && GetChatState() != MS_NONE
&& theApp.emuledlg->chatwnd->chatselector.GetItemByClient(this) != NULL)
{
// read tags (for future use)
uint8 nTagCount = data->ReadUInt8();
for (uint32 i = 0; i < nTagCount; i++)
CTag tag(data, true);
// sanitize checks - we want a small captcha not a wallpaper
uint32 nSize = (uint32)(data->GetLength() - data->GetPosition());
if ( nSize > 128 && nSize < 4096)
{
ULONGLONG pos = data->GetPosition();
BYTE* byBuffer = data->Detach();
CxImage imgCaptcha(&byBuffer[pos], nSize, CXIMAGE_FORMAT_BMP);
//free(byBuffer);
if (imgCaptcha.IsValid() && imgCaptcha.GetHeight() > 10 && imgCaptcha.GetHeight() < 50
&& imgCaptcha.GetWidth() > 10 && imgCaptcha.GetWidth() < 150 )
{
HBITMAP hbmp = imgCaptcha.MakeBitmap();
if (hbmp != NULL){
m_nChatCaptchaState = CA_CAPTCHARECV;
theApp.emuledlg->chatwnd->chatselector.ShowCaptchaRequest(this, hbmp);
DeleteObject(hbmp);
}
else
DebugLogWarning(_T("Received captcha request from client, Creating bitmap failed (%s)"), DbgGetClientInfo());
}
else
DebugLogWarning(_T("Received captcha request from client, processing image failed or invalid pixel size (%s)"), DbgGetClientInfo());
}
else
DebugLogWarning(_T("Received captcha request from client, size sanitize check failed (%u) (%s)"), nSize, DbgGetClientInfo());
}
else
DebugLogWarning(_T("Received captcha request from client, but don't accepting it at this time (%s)"), DbgGetClientInfo());
}
void CUpDownClient::ProcessCaptchaReqRes(uint8 nStatus)
{
if (GetChatCaptchaState() == CA_SOLUTIONSENT && GetChatState() != MS_NONE
&& theApp.emuledlg->chatwnd->chatselector.GetItemByClient(this) != NULL)
{
ASSERT( nStatus < 3 );
m_nChatCaptchaState = CA_NONE;
theApp.emuledlg->chatwnd->chatselector.ShowCaptchaResult(this, GetResString((nStatus == 0) ? IDS_CAPTCHASOLVED : IDS_CAPTCHAFAILED));
}
else {
m_nChatCaptchaState = CA_NONE;
DebugLogWarning(_T("Received captcha result from client, but don't accepting it at this time (%s)"), DbgGetClientInfo());
}
}
CFriend* CUpDownClient::GetFriend() const
{
if (m_Friend != NULL && theApp.friendlist->IsValid(m_Friend))
return m_Friend;
else if (m_Friend != NULL)
ASSERT( FALSE );
return NULL;
}
void CUpDownClient::SendChatMessage(CString strMessage)
{
CSafeMemFile data;
data.WriteString(strMessage, GetUnicodeSupport());
Packet* packet = new Packet(&data, OP_EDONKEYPROT, OP_MESSAGE);
theStats.AddUpDataOverheadOther(packet->size);
SafeConnectAndSendPacket(packet);
}
bool CUpDownClient::HasPassedSecureIdent(bool bPassIfUnavailable) const
{
if (credits != NULL)
{
if (credits->GetCurrentIdentState(GetConnectIP()) == IS_IDENTIFIED
|| (credits->GetCurrentIdentState(GetConnectIP()) == IS_NOTAVAILABLE && bPassIfUnavailable))
{
return true;
}
}
return false;
}
void CUpDownClient::SendFirewallCheckUDPRequest()
{
ASSERT( GetKadState() == KS_FWCHECK_UDP );
if (!Kademlia::CKademlia::IsRunning()){
SetKadState(KS_NONE);
return;
}
else if (GetUploadState() != US_NONE || GetDownloadState() != DS_NONE || GetChatState() != MS_NONE
|| GetKadVersion() <= KADEMLIA_VERSION5_48a || GetKadPort() == 0)
{
Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, ntohl(GetIP()), 0); // inform the tester that this test was cancelled
SetKadState(KS_NONE);
return;
}
CSafeMemFile data;
data.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetInternKadPort());
data.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetExternalKadPort());
data.WriteUInt32(Kademlia::CKademlia::GetPrefs()->GetUDPVerifyKey(GetConnectIP()));
Packet* packet = new Packet(&data, OP_EMULEPROT, OP_FWCHECKUDPREQ);
theStats.AddUpDataOverheadKad(packet->size);
SafeConnectAndSendPacket(packet);
}
void CUpDownClient::ProcessFirewallCheckUDPRequest(CSafeMemFile* data){
if (!Kademlia::CKademlia::IsRunning() || Kademlia::CKademlia::GetUDPListener() == NULL){
DebugLogWarning(_T("Ignored Kad Firewallrequest UDP because Kad is not running (%s)"), DbgGetClientInfo());
return;
}
// first search if we know this IP already, if so the result might be biased and we need tell the requester
bool bErrorAlreadyKnown = false;
if (GetUploadState() != US_NONE || GetDownloadState() != DS_NONE || GetChatState() != MS_NONE)
bErrorAlreadyKnown = true;
else if (Kademlia::CKademlia::GetRoutingZone()->GetContact(ntohl(GetConnectIP()), 0, false) != NULL)
bErrorAlreadyKnown = true;
uint16 nRemoteInternPort = data->ReadUInt16();
uint16 nRemoteExternPort = data->ReadUInt16();
uint32 dwSenderKey = data->ReadUInt32();
if (nRemoteInternPort == 0){
DebugLogError(_T("UDP Firewallcheck requested with Intern Port == 0 (%s)"), DbgGetClientInfo());
return;
}
if (dwSenderKey == 0)
DebugLogWarning(_T("UDP Firewallcheck requested with SenderKey == 0 (%s)"), DbgGetClientInfo());
CSafeMemFile fileTestPacket1;
fileTestPacket1.WriteUInt8(bErrorAlreadyKnown ? 1 : 0);
fileTestPacket1.WriteUInt16(nRemoteInternPort);
if (thePrefs.GetDebugClientKadUDPLevel() > 0)
DebugSend("KADEMLIA2_FIREWALLUDP", ntohl(GetConnectIP()), nRemoteInternPort);
Kademlia::CKademlia::GetUDPListener()->SendPacket(&fileTestPacket1, KADEMLIA2_FIREWALLUDP, ntohl(GetConnectIP())
, nRemoteInternPort, Kademlia::CKadUDPKey(dwSenderKey, theApp.GetPublicIP(false)), NULL);
// if the client has a router with PAT (and therefore a different extern port than intern), test this port too
if (nRemoteExternPort != 0 && nRemoteExternPort != nRemoteInternPort){
CSafeMemFile fileTestPacket2;
fileTestPacket2.WriteUInt8(bErrorAlreadyKnown ? 1 : 0);
fileTestPacket2.WriteUInt16(nRemoteExternPort);
if (thePrefs.GetDebugClientKadUDPLevel() > 0)
DebugSend("KADEMLIA2_FIREWALLUDP", ntohl(GetConnectIP()), nRemoteExternPort);
Kademlia::CKademlia::GetUDPListener()->SendPacket(&fileTestPacket2, KADEMLIA2_FIREWALLUDP, ntohl(GetConnectIP())
, nRemoteExternPort, Kademlia::CKadUDPKey(dwSenderKey, theApp.GetPublicIP(false)), NULL);
}
DebugLog(_T("Answered UDP Firewallcheck request (%s)"), DbgGetClientInfo());
}
void CUpDownClient::SetConnectOptions(uint8 byOptions, bool bEncryption, bool bCallback)
{
SetCryptLayerSupport((byOptions & 0x01) != 0 && bEncryption);
SetCryptLayerRequest((byOptions & 0x02) != 0 && bEncryption);
SetCryptLayerRequires((byOptions & 0x04) != 0 && bEncryption);
SetDirectUDPCallbackSupport((byOptions & 0x08) != 0 && bCallback);
}
void CUpDownClient::SendSharedDirectories()
{
//TODO: Don't send shared directories which do not contain any files
// add shared directories
CString strDir;
CStringArray arFolders;
POSITION pos = thePrefs.shareddir_list.GetHeadPosition();
while (pos)
{
strDir = theApp.sharedfiles->GetPseudoDirName(thePrefs.shareddir_list.GetNext(pos));
if (!strDir.IsEmpty())
arFolders.Add(strDir);
}
// add incoming folders
for (int iCat = 0; iCat < thePrefs.GetCatCount(); iCat++)
{
strDir = theApp.sharedfiles->GetPseudoDirName(thePrefs.GetCategory(iCat)->strIncomingPath);
if (!strDir.IsEmpty())
arFolders.Add(strDir);
}
// add temporary folder if there are any temp files
if (theApp.downloadqueue->GetFileCount() > 0)
arFolders.Add(CString(OP_INCOMPLETE_SHARED_FILES));
// add "Other" folder (for single shared files) if there are any single shared files
if (theApp.sharedfiles->ProbablyHaveSingleSharedFiles())
arFolders.Add(CString(OP_OTHER_SHARED_FILES));
// build packet
CSafeMemFile tempfile(80);
tempfile.WriteUInt32(arFolders.GetCount());
for (int i = 0; i < arFolders.GetCount(); i++)
tempfile.WriteString(arFolders.GetAt(i), GetUnicodeSupport());
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__AskSharedDirsAnswer", this);
Packet* replypacket = new Packet(&tempfile);
replypacket->opcode = OP_ASKSHAREDDIRSANS;
theStats.AddUpDataOverheadOther(replypacket->size);
VERIFY( SendPacket(replypacket, true, true) );
}
//EastShare Start - added by AndCycle, IP to Country
// Superlexx - client's location
CString CUpDownClient::GetCountryName(bool longName) const {
return theApp.ip2country->GetCountryNameFromRef(m_structUserCountry,longName);
}
int CUpDownClient::GetCountryFlagIndex() const {
return m_structUserCountry->FlagIndex;
}
//MORPH START - Changed by SiRoB, ProxyClient
void CUpDownClient::ResetIP2Country(uint32 m_dwIP){
m_structUserCountry = theApp.ip2country->GetCountryFromIP((m_dwIP)?m_dwIP:m_dwUserIP);
}
//MORPH END - Changed by SiRoB, ProxyClient
//EastShare End - added by AndCycle, IP to Country
//Xman Anti-Leecher
bool CUpDownClient::ProcessUnknownHelloTag(CTag *tag, CString &pszReason)
{
#ifndef LOGTAG
//Xman DLP
if(pszReason.IsEmpty()==false)
return false;
//Xman end
#endif
//Xman DLP
if(theApp.dlp->IsDLPavailable()==false)
return false;
bool foundmd4=false;
LPCTSTR strSnafuTag=theApp.dlp->DLPCheckHelloTag(tag->GetNameID());
if (strSnafuTag!=NULL)
{
pszReason.Format(_T("Suspect Hello-Tag: %s"),strSnafuTag);
}
//Xman end
if (strSnafuTag==NULL && tag->IsStr() && tag->GetStr().GetLength() >= 32)
foundmd4=true;
#ifdef LOGTAG
if(m_byCompatibleClient==0 && GetHashType() == SO_EMULE )
{
AddDebugLogLine(false,_T("Unknown HelloTag: 0x%x, %s, client:%s"), tag->GetNameID(), tag->GetFullInfo(), DbgGetClientInfo());
}
#endif
return foundmd4;
}
void CUpDownClient::ProcessUnknownInfoTag(CTag *tag, CString &pszReason)
{
#ifndef LOGTAG
//Xman DLP
if(pszReason.IsEmpty()==false)
return;
//Xman end
#endif
//Xman DLP
if(theApp.dlp->IsDLPavailable()==false)
return;
LPCTSTR strSnafuTag=theApp.dlp->DLPCheckInfoTag(tag->GetNameID());
if (strSnafuTag!=NULL)
{
pszReason.Format(_T("Suspect eMuleInfo-Tag: %s"),strSnafuTag);
}
//Xman end
#ifdef LOGTAG
if(m_byCompatibleClient==0 && GetHashType() == SO_EMULE )
{
AddDebugLogLine(false,_T("Unknown InfoTag: 0x%x, %s, client:%s"), tag->GetNameID(), tag->GetFullInfo(), DbgGetClientInfo());
}
#endif
}
//Xman end
//Xman
// - show requested files (sivka)
void CUpDownClient::ShowRequestedFiles()
{
CString fileList;
fileList += _T("[")+GetResString(IDS_CLIENT)+_T(": ")+(GetUserName())+_T("]");
fileList += _T("\n\nList of Downloading Files:\n");
fileList += _T("__________________________\n\n") ;
if (reqfile && reqfile->IsPartFile())
{
fileList += reqfile->GetFileName();
for(POSITION pos = m_OtherRequests_list.GetHeadPosition();pos!=0;m_OtherRequests_list.GetNext(pos))
{
fileList += _T("\n") ;
fileList += m_OtherRequests_list.GetAt(pos)->GetFileName();
}
for(POSITION pos = m_OtherNoNeeded_list.GetHeadPosition();pos!=0;m_OtherNoNeeded_list.GetNext(pos))
{
fileList += _T("\n") ;
fileList += m_OtherNoNeeded_list.GetAt(pos)->GetFileName();
}
}
else
fileList += _T("You have not requested a file from this user.");
fileList += _T("\n\n\nList of Uploading Files:\n");
fileList += _T("__________________________\n\n") ;
// ==> requpfile optimization [SiRoB] - Stulle
/*
CKnownFile* uploadfile = theApp.sharedfiles->GetFileByID(GetUploadFileID());
*/
CKnownFile* uploadfile = CheckAndGetReqUpFile();
// <== requpfile optimization [SiRoB] - Stulle
if(uploadfile)
fileList += uploadfile->GetFileName();
else
fileList += _T("This user has not requested a file from you.");
AfxMessageBox(fileList,MB_OK);
}
//Xman end
//Xman Anti-Leecher: simple Anti-Thief
//gives back the Xtreme-Mod Version as float
//0 if it isn't a Xtreme-Mod
//remark: highest subversion allowed is 9!
float CUpDownClient::GetXtremeVersion(CString modversion) const
{
// ==> ModID [itsonlyme/SiRoB] - Stulle
/*
if(modversion.GetLength()<10)
return 0.0f;
if(modversion.Left(7).CompareNoCase(_T("Xtreme "))!=0)
return 0.0f;
return (float)_tstof(modversion.Mid(7));
*/
uint8 temp = (uint8)(theApp.m_strModVersion.GetLength());
if(modversion.GetLength() Emulate others [WiZaRd/Spike/shadow2004] - Stulle
//seeing that MLDonkey has a reask which is ~3 times as fast as eMules and MLDonkey downloads ~3 times as much from each other as an eMule client
//this seems to be a sensible approach, though hammering is NOT a good solution...
if (GetClientSoft() == SO_MLDONKEY && thePrefs.IsEmuMLDonkey())
m_jitteredFileReaskTime = MIN_REQUESTTIME;
// Shareaza allows its users to lower the ReaskTime down to 20 Minutes !! Okay, so do we.... but hardcoded.
else if (GetClientSoft() == SO_SHAREAZA && thePrefs.IsEmuShareaza())
m_jitteredFileReaskTime = MIN_REQUESTTIME*2;
// no change for eMule Plus as they do use the same system like eMule
else
// <== Emulate others [WiZaRd/Spike/shadow2004] - Stulle
if(longer==false)
{
// Maella -Unnecessary Protocol Overload-
// Remark: a client will be remove from an upload queue after 3*FILEREASKTIME (~1 hour)
// a two small value increases the traffic + causes a banishment if lower than 10 minutes
// srand() is already called a few times..
uint32 jitter = rand() * (35*6) / RAND_MAX; // 0..3.5 minutes, keep in mind integer overflow
m_jitteredFileReaskTime = FILEREASKTIME - (60*1000) + 1000*jitter - (2*60*1000); // -2..+2 minutes, keep the same average overload
//Xman: result between 26 and 29.5 this is useful to use TCP-Connection from older clients
// ==> Timer for ReAsk File Sources [Stulle] - Stulle
if(GetModClient() != MOD_SCAR && GetModClient() != MOD_MEPHISTO && GetModClient() != MOD_XTREME)
m_jitteredFileReaskTime += thePrefs.GetReAskTimeDif();
// <== Timer for ReAsk File Sources [Stulle] - Stulle
}
else
m_jitteredFileReaskTime = FILEREASKTIME + (3*60*1000); //32 min
//this gives the client the chance to connect first
//this connection can be used by Xtreme, see partfile->process
}
//Xman end
//Xman Funny-Nick (Stulle/Morph)
void CUpDownClient::UpdateFunnyNick()
{
if(m_pszUsername == NULL ||
!IsEd2kClient() || //MORPH - Changed by Stulle, no FunnyNick for http DL
_tcsnicmp(m_pszUsername, _T("http://emule"),12) != 0 &&
_tcsicmp(m_pszUsername, _T("")) != 0)
return;
if(m_pszFunnyNick!=NULL)
return; //why generate a new one ? userhash can't change without getting banned
// preffix table
const static LPCTSTR apszPreFix[] =
{
_T("ATX-"), //0
_T("Gameboy "),
_T("PS/2-"),
_T("USB-"),
_T("Angry "),
_T("Atrocious "),
_T("Attractive "),
_T("Bad "),
_T("Barbarious "),
_T("Beautiful "),
_T("Black "), //10
_T("Blond "),
_T("Blue "),
_T("Bright "),
_T("Brown "),
_T("Cool "),
_T("Cruel "),
_T("Cubic "),
_T("Cute "),
_T("Dance "),
_T("Dark "), //20
_T("Dinky "),
_T("Drunk "),
_T("Dumb "),
_T("E"),
_T("Electro "),
_T("Elite "),
_T("Fast "),
_T("Flying "),
_T("Fourios "),
_T("Frustraded "), //30
_T("Funny "),
_T("Furious "),
_T("Giant "),
_T("Giga "),
_T("Green "),
_T("Handsome "),
_T("Hard "),
_T("Harsh "),
_T("Hiphop "),
_T("Holy "), //40
_T("Horny "),
_T("Hot "),
_T("House "),
_T("I"),
_T("Lame "),
_T("Leaking "),
_T("Lone "),
_T("Lovely "),
_T("Lucky "),
_T("Micro "), //50
_T("Mighty "),
_T("Mini "),
_T("Nice "),
_T("Orange "),
_T("Pretty "),
_T("Red "),
_T("Sexy "),
_T("Slow "),
_T("Smooth "),
_T("Stinky "), //60
_T("Strong "),
_T("Super "),
_T("Unholy "),
_T("White "),
_T("Wild "),
_T("X"),
_T("XBox "),
_T("Yellow "),
_T("Kentucky Fried "),
_T("Mc"), //70
_T("Alien "),
_T("Bavarian "),
_T("Crazy "),
_T("Death "),
_T("Drunken "),
_T("Fat "),
_T("Hazardous "),
_T("Holy "),
_T("Infested "),
_T("Insane "), //80
_T("Mutated "),
_T("Nasty "),
_T("Purple "),
_T("Radioactive "),
_T("Ugly "),
_T("Green "), //86
};
#define NB_PREFIX 87
#define MAX_PREFIXSIZE 15
// suffix table
const static LPCTSTR apszSuffix[] =
{
_T("16"), //0
_T("3"),
_T("6"),
_T("7"),
_T("Abe"),
_T("Bee"),
_T("Bird"),
_T("Boy"),
_T("Cat"),
_T("Cow"),
_T("Crow"), //10
_T("DJ"),
_T("Dad"),
_T("Deer"),
_T("Dog"),
_T("Donkey"),
_T("Duck"),
_T("Eagle"),
_T("Elephant"),
_T("Fly"),
_T("Fox"), //20
_T("Frog"),
_T("Girl"),
_T("Girlie"),
_T("Guinea Pig"),
_T("Hasi"),
_T("Hawk"),
_T("Jackal"),
_T("Lizard"),
_T("MC"),
_T("Men"), //30
_T("Mom"),
_T("Mouse"),
_T("Mule"),
_T("Pig"),
_T("Rabbit"),
_T("Rat"),
_T("Rhino"),
_T("Smurf"),
_T("Snail"),
_T("Snake"), //40
_T("Star"),
_T("Tiger"),
_T("Wolf"),
_T("Butterfly"),
_T("Elk"),
_T("Godzilla"),
_T("Horse"),
_T("Penguin"),
_T("Pony"),
_T("Reindeer"), //50
_T("Sheep"),
_T("Sock Puppet"),
_T("Worm"),
_T("Bermuda") //54
};
#define NB_SUFFIX 55
#define MAX_SUFFIXSIZE 11
//--- if we get an id, we can generate the same random name for this user over and over... so much about randomness :) ---
if(m_achUserHash)
{
uint32 x=0x7d726d62; // < xrmb :)
uint8 a=m_achUserHash[5] ^ m_achUserHash[7] ^ m_achUserHash[15] ^ m_achUserHash[4];
uint8 b=m_achUserHash[11] ^ m_achUserHash[9] ^ m_achUserHash[12] ^ m_achUserHash[1];
uint8 c=m_achUserHash[3] ^ m_achUserHash[14] ^ m_achUserHash[6] ^ m_achUserHash[13];
uint8 d=m_achUserHash[2] ^ m_achUserHash[0] ^ m_achUserHash[10] ^ m_achUserHash[8];
uint32 e=(a<<24) + (b<<16) + (c<<8) + d;
srand(e^x);
}
if (m_pszFunnyNick) {
delete[] m_pszFunnyNick;
m_pszFunnyNick = NULL;
}
// ==> FunnyNick Tags - Stulle
/*
CString tag = _T("[FN]");;
uint8 uTagLength = 4+2; //one space + /0
*/
CString tag = _T("");
uint8 uTagLength = 0;
switch (thePrefs.GetFnTag()) {
case CS_NONE:
break;
case CS_SHORT:
tag= _T("[FN]");
uTagLength = 4+2;
break;
case CS_FULL:
tag= _T("[FunnyNick]");
uTagLength = 11+2;
break;
case CS_CUST:
tag= (thePrefs.GetFnCustomTag());
uTagLength = (uint8)(tag.GetLength()+2);
break;
}
// <== FunnyNick Tags - Stulle
m_pszFunnyNick = new TCHAR[uTagLength+MAX_PREFIXSIZE+MAX_SUFFIXSIZE];
// pick random suffix and prefix
// ==> FunnyNick Tags - Stulle
if(uTagLength==0)
{
_tcscpy(m_pszFunnyNick, apszPreFix[rand()%NB_PREFIX]);
_tcscat(m_pszFunnyNick, apszSuffix[rand()%NB_SUFFIX]);
}
else if (!thePrefs.GetFnTagAtEnd())
// <== FunnyNick Tags - Stulle
{
_tcscpy(m_pszFunnyNick, tag);
_tcscat(m_pszFunnyNick, _T(" "));
_tcscat(m_pszFunnyNick, apszPreFix[rand()%NB_PREFIX]);
_tcscat(m_pszFunnyNick, apszSuffix[rand()%NB_SUFFIX]);
}
// ==> FunnyNick Tags - Stulle
else
{
_tcscpy(m_pszFunnyNick, apszPreFix[rand()%NB_PREFIX]);
_tcscat(m_pszFunnyNick, apszSuffix[rand()%NB_SUFFIX]);
_tcscat(m_pszFunnyNick, _T(" "));
_tcscat(m_pszFunnyNick, tag);
}
// <== FunnyNick Tags - Stulle
//--- make the rand random again ---
if(m_achUserHash)
srand((unsigned)time(NULL));
}
//Xman end
//Xman Anti-Leecher
//Xman DLP (no more extra tags inside this function)
void CUpDownClient::TestLeecher(){
//Xman DLP
if(theApp.dlp->IsDLPavailable()==false)
return;
//Xman end
// ==> Anti Uploader Ban [Stulle] - Stulle
if (AntiUploaderBanActive())
{
m_bLeecher = 0; // no leecher
return;
}
// <== Anti Uploader Ban [Stulle] - Stulle
if (thePrefs.GetAntiLeecherMod())
{
if(old_m_strClientSoftwareFULL.IsEmpty() || old_m_strClientSoftwareFULL!= DbgGetFullClientSoftVer() )
{
old_m_strClientSoftwareFULL = DbgGetFullClientSoftVer();
LPCTSTR reason=theApp.dlp->DLPCheckModstring_Hard(m_strModVersion,m_strClientSoftware);
if(reason)
{
BanLeecher(reason,5); //hard ban
return;
}
reason=theApp.dlp->DLPCheckModstring_Soft(m_strModVersion,m_strClientSoftware);
if(reason)
{
BanLeecher(reason,4); //soft ban
return;
}
else if(IsLeecher()==4)
{
m_bLeecher=0; //unban, because it is now a good mod
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
old_m_pszUsername.Empty(); //force recheck
}
}
}
else if(IsLeecher()==4)
{
m_bLeecher=0; //unban, because user doesn't want to check it anymore
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
old_m_pszUsername.Empty(); //force recheck
old_m_strClientSoftwareFULL.Empty(); //force recheck if user re enable function
}
if(thePrefs.GeTAntiLeecheruserhash() && HasValidHash())
{
PBYTE uhash=(PBYTE)GetUserHash();
LPCTSTR reason=theApp.dlp->DLPCheckUserhash(uhash);
if(reason)
{
BanLeecher(_T("*AJ*"),18);
return;
}
}
if (thePrefs.GetAntiLeecherName())
{
//Xman Anti-Nick-Changer
if(m_pszUsername!=NULL && old_m_pszUsername.IsEmpty()==false)
{
if(old_m_pszUsername!=m_pszUsername)
{
if(IsLeecher()==0 && m_strModVersion.IsEmpty() //check only if it isn't a known leecher and doesn't send modversion
&& ::GetTickCount() - m_ulastNickChage < HR2MS(3)) //last nickchane was in less than 3 hours
{
m_uNickchanges++;
if(m_uNickchanges >=3)
{
BanLeecher(_T("Nick-Changer"),5); //hard ban
return;
}
}
}
else
{
//decrease the value if it's the same nick
if(m_uNickchanges>0)
m_uNickchanges--;
}
}
//Xman end Anti-Nick-Changer
if(m_bLeecher!=4 && m_pszUsername!=NULL && (old_m_pszUsername.IsEmpty() || old_m_pszUsername!=m_pszUsername)) //remark: because old_m_pszUsername is CString and there operator != is defined, it isn't a pointer comparison
{
old_m_pszUsername = m_pszUsername;
m_ulastNickChage=::GetTickCount(); //Xman Anti-Nick-Changer
//find gamer snake
if (HasValidHash())
{
CString struserhash=md4str(GetUserHash());
LPCTSTR reason=theApp.dlp->DLPCheckNameAndHashAndMod(m_pszUsername,struserhash,m_strModVersion);
if(reason)
{
BanLeecher(reason,10); //soft ban
return;
}
}
LPCTSTR reason=theApp.dlp->DLPCheckUsername_Soft(m_pszUsername);
if(reason)
{
BanLeecher(reason,10); //soft ban
return;
}
reason=theApp.dlp->DLPCheckUsername_Hard(m_pszUsername);
if(reason)
{
BanLeecher(reason,5); //hard ban
return;
}
if(IsLeecher()==10 && reason==NULL)
{
m_bLeecher=0; //unban it is a good mod now
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
}
}
}
else if(IsLeecher()==10)
{
m_bLeecher=0; //unban, because user doesn't want to check it anymore
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
old_m_pszUsername.Empty(); //force recheck if user re enable function
}
//X-Ray :: Fincan Hash Detection :: Start
if(thePrefs.GetAntiLeecherFincan()){
if(HasValidHash() && theApp.dlp->CheckForFincanHash(md4str(GetUserHash()))){
BanLeecher(_T("Fincan Community"),20);
return;
}
}
else if(IsLeecher()==20){
m_bLeecher=0; //unban, because user doesn't want to check it anymore
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
}
//X-Ray :: Fincan Hash Detection :: End
if (m_nClientVersion > MAKE_CLIENT_VERSION(0, 30, 0) && m_byEmuleVersion > 0 && m_byEmuleVersion != 0x99 && m_clientSoft == SO_EMULE)
{
BanLeecher(_T("Fake emuleVersion"),9);
return;
} else
//Xman Anti-Leecher: simple Anti-Thief
if(m_bLeecher==0 || m_bLeecher==6 || m_bLeecher==11 ) //only check if not banned by other criterion
{
// ==> ModID [itsonlyme/SiRoB] - Stulle
/*
static const float MOD_FLOAT_VERSION= (float)_tstof(CString(MOD_VERSION).Mid(7)) ;
const float xtremeversion=GetXtremeVersion(m_strModVersion);
if(thePrefs.GetAntiLeecherThief())
{
if(xtremeversion==MOD_FLOAT_VERSION && !StrStrI(m_strClientSoftware,MOD_MAJOR_VERSION))
{
BanLeecher(_T("Mod-ID Faker"),6);
return;
}
if(xtremeversion>=4.4f && CString(m_pszUsername).Right(m_strModVersion.GetLength()+1)!=m_strModVersion + _T("\xBB"))
{
BanLeecher(_T("MOD-ID Faker(advanced)"),6);
return;
}
}
*/
static const float MOD_FLOAT_VERSION= (float)_tstof(theApp.m_strModVersion.Mid(theApp.m_uModLength)) ;
const float xtremeversion=GetXtremeVersion(m_strModVersion);
if(thePrefs.GetAntiLeecherThief())
{
if(xtremeversion==MOD_FLOAT_VERSION && m_nClientVersion != MAKE_CLIENT_VERSION(CemuleApp::m_nVersionMjr, CemuleApp::m_nVersionMin, CemuleApp::m_nVersionUpd))
{
BanLeecher(_T("Mod-ID Faker"),6);
return;
}
if(xtremeversion>=1.0f && CString(m_pszUsername).Right(m_strModVersion.GetLength()+1)!=m_strModVersion + _T("\xBB"))
{
BanLeecher(_T("MOD-ID Faker(advanced)"),6);
return;
}
// <== ModID [itsonlyme/SiRoB] - Stulle
if(IsLeecher()==6)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban it isn't anymore a mod faker
}
}
else if(IsLeecher()==6)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, user doesn't want to ban it anymore
}
//Xman new Anti-Nick-Thief
if(thePrefs.GetAntiLeecherThief() )
{
if(StrStrI(m_pszUsername, str_ANTAddOn))
{
BanLeecher(_T("Nick Thief"),11);
return;
}
if(IsLeecher()==11)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, it isn't a nickthief anymore
}
}
else if(IsLeecher()==11)
{
m_strBanMessage.Format(_T("unban - Client %s"),DbgGetClientInfo());
m_bLeecher=0; //unban, user doesn't want to ban it anymore
}
}
//Xman end simple Anti-Thief
}
//Xman end
void CUpDownClient::ProcessBanMessage()
{
if(m_strBanMessage.IsEmpty()==false)
{
//zz_fly :: fix a possible crash when username contain %s :: DolpinX :: start
/*
AddLeecherLogLine(false,m_strBanMessage);
*/
AddLeecherLogLine(false, _T("%s"), m_strBanMessage);
//zz_fly :: end
theApp.emuledlg->transferwnd->GetQueueList()->RefreshClient(this);
}
m_strBanMessage.Empty();
}
//Xman end
// ==> Design Settings [eWombat/Stulle] - Stulle
int CUpDownClient::GetClientStyle(bool bDl, bool bUl, bool bShare, bool bOwnCredits) const
{
int iClientStyle = style_c_default;
if(IsFriend() && thePrefs.GetStyleOnOff(client_styles, style_c_friend)!=0)
iClientStyle = style_c_friend;
else if(GetPowerShared() && bShare && thePrefs.GetStyleOnOff(client_styles, style_c_powershare)!=0)
iClientStyle = style_c_powershare;
else if(GetPowerReleased() && bShare && thePrefs.GetStyleOnOff(client_styles, style_c_powerrelease)!=0)
iClientStyle = style_c_powerrelease;
else if(GetDownloadState() == DS_DOWNLOADING && bDl && thePrefs.GetStyleOnOff(client_styles, style_c_downloading)!=0)
iClientStyle = style_c_downloading;
else if(GetUploadState() == US_UPLOADING && bUl && thePrefs.GetStyleOnOff(client_styles, style_c_uploading)!=0)
iClientStyle = style_c_uploading;
else if(IsLeecher()>0 && thePrefs.GetStyleOnOff(client_styles, style_c_leecher)!=0)
iClientStyle = style_c_leecher;
else if(HasLowID() && thePrefs.GetStyleOnOff(client_styles, style_c_lowid)!=0)
iClientStyle = style_c_lowid;
else if(Credits() && thePrefs.GetStyleOnOff(client_styles, style_c_credits)!=0)
{
if (
(!bOwnCredits && credits->GetHasScore(this))
||
( bOwnCredits && credits->GetMyScoreRatio(GetIP())>1)
)
iClientStyle = style_c_credits;
}
return iClientStyle;
}
// <== Design Settings [eWombat/Stulle] - Stulle
// ==> Display reason for zero score [Stulle] - Stulle
CString CUpDownClient::GetZeroScoreString() const
{
if (!m_pszUsername)
return _T("NULL Username");
if(GetUploadFileID() == NULL)
return _T("NULL UploadFileID");
if (credits == 0){
return _T("NULL credits");
}
// ==> requpfile optimization [SiRoB] - Stulle
/*
CKnownFile* currequpfile = theApp.sharedfiles->GetFileByID(requpfileid);
*/
CKnownFile* currequpfile = CheckAndGetReqUpFile();
// <== requpfile optimization [SiRoB] - Stulle
if(!currequpfile)
return _T("NULL reqfile");
if (credits->GetCurrentIdentState(GetIP()) == IS_IDBADGUY)
return _T("Bad guy");
if (m_nUploadState==US_BANNED)
return _T("Banned");
if (m_bGPLEvildoer)
return _T("GPL evildoer");
return _T("Unknown");
}
// <== Display reason for zero score [Stulle] - Stulle
// ==> Anti Uploader Ban [Stulle] - Stulle
bool CUpDownClient::AntiUploaderBanActive()
{
// credits->GetDownloadedTotal() <== data amount the other client gave us
// credits->GetUploadedTotal() <== data amount the other client got from us
if (thePrefs.GetAntiUploaderBanLimit() != 0 &&
credits != NULL &&
credits->GetDownloadedTotal() >= 1048576) // we got at least a megabyte
{
switch (thePrefs.GetAntiUploaderBanCase())
{
case CS_1:{
// check if he got more than we set
return (credits->GetDownloadedTotal() >= (uint64)thePrefs.GetAntiUploaderBanLimit()<<20);
} break;
case CS_2:{
if(credits->GetUploadedTotal() < credits->GetDownloadedTotal())
// check how much more he gave us
return ((credits->GetDownloadedTotal() - credits->GetUploadedTotal()) >= (uint64)thePrefs.GetAntiUploaderBanLimit()<<20);
else
return false;
} break;
case CS_3:{
if(credits->GetUploadedTotal() < credits->GetDownloadedTotal())// he got less from us than what we got from him
{
if (GetAntiUploaderCaseThree()) // he already got the state
return true;
// not got the state
// check how much more he gave us
else if ((credits->GetDownloadedTotal() - credits->GetUploadedTotal()) >= (uint64)thePrefs.GetAntiUploaderBanLimit()<<20)
{
m_bAntiUploaderCaseThree = true;
return true;
}
else // obviously he didn't gave us enough here
return false;
}
else if(GetAntiUploaderCaseThree())
{
m_bAntiUploaderCaseThree = false;
return false;
}
} break;
}
}
return false;
}
// <== Anti Uploader Ban [Stulle] - Stulle