📄 clientlist.cpp
字号:
void CClientList::AddTrackClient(CUpDownClient* toadd){
CDeletedClient* pResult = 0;
if (m_trackedClientsList.Lookup(toadd->GetIP(), pResult)){
pResult->m_dwInserted = ::GetTickCount();
for (int i = 0; i != pResult->m_ItemsList.GetCount(); i++){
if (pResult->m_ItemsList[i].nPort == toadd->GetUserPort()){
// already tracked, update
pResult->m_ItemsList[i].pHash = toadd->Credits();
return;
}
}
PORTANDHASH porthash = { toadd->GetUserPort(), toadd->Credits()};
pResult->m_ItemsList.Add(porthash);
}
else{
m_trackedClientsList.SetAt(toadd->GetIP(), new CDeletedClient(toadd));
}
}
// true = everything ok, hash didn't changed
// false = hash changed
bool CClientList::ComparePriorUserhash(uint32 dwIP, uint16 nPort, void* pNewHash){
CDeletedClient* pResult = 0;
if (m_trackedClientsList.Lookup(dwIP, pResult)){
for (int i = 0; i != pResult->m_ItemsList.GetCount(); i++){
if (pResult->m_ItemsList[i].nPort == nPort){
if (pResult->m_ItemsList[i].pHash != pNewHash)
return false;
else
break;
}
}
}
return true;
}
UINT CClientList::GetClientsFromIP(uint32 dwIP) const
{
CDeletedClient* pResult;
if (m_trackedClientsList.Lookup(dwIP, pResult))
return pResult->m_ItemsList.GetCount();
return 0;
}
void CClientList::TrackBadRequest(const CUpDownClient* upcClient, sint32 nIncreaseCounter){
CDeletedClient* pResult = NULL;
if (upcClient->GetIP() == 0){
ASSERT( false );
return;
}
if (m_trackedClientsList.Lookup(upcClient->GetIP(), pResult)){
pResult->m_dwInserted = ::GetTickCount();
pResult->m_cBadRequest += nIncreaseCounter;
}
else{
CDeletedClient* ccToAdd = new CDeletedClient(upcClient);
ccToAdd->m_cBadRequest = nIncreaseCounter;
m_trackedClientsList.SetAt(upcClient->GetIP(), ccToAdd);
}
}
uint32 CClientList::GetBadRequests(const CUpDownClient* upcClient) const{
CDeletedClient* pResult = NULL;
if (upcClient->GetIP() == 0){
ASSERT( false );
return 0;
}
if (m_trackedClientsList.Lookup(upcClient->GetIP(), pResult)){
return pResult->m_cBadRequest;
}
else
return 0;
}
void CClientList::Process(){
const uint32 cur_tick = ::GetTickCount();
if (m_dwLastBannCleanUp + BAN_CLEANUP_TIME < cur_tick){
m_dwLastBannCleanUp = cur_tick;
POSITION pos = m_bannedList.GetStartPosition();
uint32 nKey;
uint32 dwBantime;
while (pos != NULL){
m_bannedList.GetNextAssoc( pos, nKey, dwBantime );
if (dwBantime + CLIENTBANTIME < cur_tick )
RemoveBannedClient(nKey);
}
}
if (m_dwLastTrackedCleanUp + TRACKED_CLEANUP_TIME < cur_tick ){
m_dwLastTrackedCleanUp = cur_tick;
if (thePrefs.GetLogBannedClients())
AddDebugLogLine(false, _T("Cleaning up TrackedClientList, %i clients on List..."), m_trackedClientsList.GetCount());
POSITION pos = m_trackedClientsList.GetStartPosition();
uint32 nKey;
CDeletedClient* pResult;
while (pos != NULL){
m_trackedClientsList.GetNextAssoc( pos, nKey, pResult );
if (pResult->m_dwInserted + KEEPTRACK_TIME < cur_tick ){
m_trackedClientsList.RemoveKey(nKey);
delete pResult;
}
}
if (thePrefs.GetLogBannedClients())
AddDebugLogLine(false, _T("...done, %i clients left on list"), m_trackedClientsList.GetCount());
}
//We need to try to connect to the clients in KadList
//If connected, remove them from the list and send a message back to Kad so we can send a ACK.
//If we don't connect, we need to remove the client..
//The sockets timeout should delete this object.
POSITION pos1, pos2;
bool buddy = false;
for (pos1 = KadList.GetHeadPosition();( pos2 = pos1 ) != NULL;)
{
KadList.GetNext(pos1);
CUpDownClient* cur_client = KadList.GetAt(pos2);
if( !Kademlia::CKademlia::getUDPListener() )
{
//Clear out this list if we stop running Kad.
cur_client->SetKadState(KS_NONE);
}
switch(cur_client->GetKadState())
{
case KS_QUEUED_FWCHECK:
//I removed the self check here because we already did it when we added the client object.
cur_client->TryToConnect(true);
break;
case KS_CONNECTING_FWCHECK:
//Ignore this state as we are just waiting for results.
break;
case KS_CONNECTED_FWCHECK:
//Send the Kademlia client a TCP connection ack!
Kademlia::CKademlia::getUDPListener()->sendNullPacket(KADEMLIA_FIREWALLED_ACK, ntohl(cur_client->GetIP()), cur_client->GetKadPort());
cur_client->SetKadState(KS_NONE);
break;
case KS_INCOMING_BUDDY:
if( m_bHaveBuddy == 2)
cur_client->SetKadState(KS_NONE);
break;
case KS_QUEUED_BUDDY:
if( m_bHaveBuddy == 0 )
{
buddy = true;
m_bHaveBuddy = 1;
cur_client->SetKadState(KS_CONNECTING_BUDDY);
cur_client->TryToConnect(true);
theApp.emuledlg->serverwnd->UpdateMyInfo();
}
else if( m_bHaveBuddy == 2 )
cur_client->SetKadState(KS_NONE);
//a potential buddy client wanting to let me in the Kad network
break;
case KS_CONNECTING_BUDDY:
if( m_bHaveBuddy == 2 )
cur_client->SetKadState(KS_NONE);
else
buddy = true;
break;
case KS_CONNECTED_BUDDY:
//a potential connected buddy client wanting to me in the Kad network
//Not working at the moment so just set to none..
buddy = true;
if( m_bHaveBuddy != 2 )
{
m_pBuddy = cur_client;
m_bHaveBuddy = 2;
theApp.emuledlg->serverwnd->UpdateMyInfo();
}
break;
default:
RemoveFromKadList(cur_client);
}
}
//We either never had a buddy, or lost our buddy..
if( !buddy )
{
if( m_bHaveBuddy )
{
m_bHaveBuddy = 0;
theApp.emuledlg->serverwnd->UpdateMyInfo();
}
}
//Check if we are a lowID and need a buddy..
if ( !m_bHaveBuddy && Kademlia::CKademlia::isConnected() && Kademlia::CKademlia::isFirewalled() )
{
ASSERT( Kademlia::CKademlia::getPrefs() != NULL );
if( Kademlia::CKademlia::getPrefs()->getFindBuddy() )
{
Kademlia::CSearch *findBuddy = new Kademlia::CSearch;
findBuddy->setSearchTypes(Kademlia::CSearch::FINDBUDDY);
Kademlia::CUInt128 ID(true);
ID.xor(Kademlia::CKademlia::getPrefs()->getKadID());
findBuddy->setTargetID(ID);
Kademlia::CSearchManager::startSearch(findBuddy);
}
}
CleanUpClientList();
}
#ifdef _DEBUG
void CClientList::Debug_SocketDeleted(CClientReqSocket* deleted){
for (POSITION pos = list.GetHeadPosition(); pos != NULL;){
CUpDownClient* cur_client = list.GetNext(pos);
if (!AfxIsValidAddress(cur_client, sizeof(CUpDownClient))) {
AfxDebugBreak();
}
if (thePrefs.m_iDbgHeap >= 2)
ASSERT_VALID(cur_client);
if (cur_client->socket == deleted){
AfxDebugBreak();
}
}
}
#endif
bool CClientList::IsValidClient(CUpDownClient* tocheck)
{
if (thePrefs.m_iDbgHeap >= 2)
ASSERT_VALID(tocheck);
return list.Find(tocheck);
}
void CClientList::RequestTCP(Kademlia::CContact* contact)
{
uint32 nContactIP = ntohl(contact->getIPAddress());
// don't connect ourself
if (theApp.serverconnect->GetLocalIP() == nContactIP && thePrefs.GetPort() == contact->getTCPPort())
return;
CUpDownClient* pNewClient = FindClientByIP(nContactIP, contact->getTCPPort());
if (!pNewClient)
pNewClient = new CUpDownClient(0, contact->getTCPPort(), contact->getIPAddress(), 0, 0, false );
//Add client to the lists to be processed.
pNewClient->SetKadPort(contact->getUDPPort());
pNewClient->SetKadState(KS_QUEUED_FWCHECK);
KadList.AddTail(pNewClient);
//This method checks if this is a dup already.
AddClient(pNewClient);
}
void CClientList::RequestBuddy(Kademlia::CContact* contact)
{
uint32 nContactIP = ntohl(contact->getIPAddress());
// don't connect ourself
if (theApp.serverconnect->GetLocalIP() == nContactIP && thePrefs.GetPort() == contact->getTCPPort())
return;
CUpDownClient* pNewClient = FindClientByIP(nContactIP, contact->getTCPPort());
if (!pNewClient)
pNewClient = new CUpDownClient(0, contact->getTCPPort(), contact->getIPAddress(), 0, 0, false );
//Add client to the lists to be processed.
pNewClient->SetKadPort(contact->getUDPPort());
pNewClient->SetKadState(KS_QUEUED_BUDDY);
byte ID[16];
contact->getClientID().toByteArray(ID);
pNewClient->SetUserHash(ID);
AddToKadList(pNewClient);
//This method checks if this is a dup already.
AddClient(pNewClient);
}
void CClientList::IncomingBuddy(Kademlia::CContact* contact, Kademlia::CUInt128* buddyID )
{
uint32 nContactIP = ntohl(contact->getIPAddress());
//If eMule already knows this client, abort this.. It could cause conflicts.
//Although the odds of this happening is very small, it could still happen.
if (FindClientByIP(nContactIP, contact->getTCPPort()))
{
return;
}
// don't connect ourself
if (theApp.serverconnect->GetLocalIP() == nContactIP && thePrefs.GetPort() == contact->getTCPPort())
return;
//Add client to the lists to be processed.
CUpDownClient* pNewClient = new CUpDownClient(0, contact->getTCPPort(), contact->getIPAddress(), 0, 0, false );
pNewClient->SetKadPort(contact->getUDPPort());
pNewClient->SetKadState(KS_INCOMING_BUDDY);
byte ID[16];
contact->getClientID().toByteArray(ID);
pNewClient->SetUserHash(ID);
buddyID->toByteArray(ID);
pNewClient->SetBuddyID(ID);
AddToKadList(pNewClient);
AddClient(pNewClient);
}
void CClientList::RemoveFromKadList(CUpDownClient* torem){
POSITION pos = KadList.Find(torem);
if(pos)
{
if(torem == m_pBuddy)
{
m_pBuddy = NULL;
theApp.emuledlg->serverwnd->UpdateMyInfo();
}
KadList.RemoveAt(pos);
}
}
void CClientList::AddToKadList(CUpDownClient* toadd){
if(!toadd)
return;
POSITION pos = KadList.Find(toadd);
if(pos)
{
return;
}
KadList.AddTail(toadd);
}
void CClientList::CleanUpClientList(){
// we remove clients which are not needed any more by time
// this check is also done on CUpDownClient::Disconnected, however it will not catch all
// cases (if a client changes the state without beeing connected
//
// Adding this check directly to every point where any state changes would be more effective,
// is however not compatible with the current code, because there are points where a client has
// no state for some code lines and the code is also not prepared that a client object gets
// invalid while working with it (aka setting a new state)
// so this way is just the easy and safe one to go (as long as emule is basically single threaded)
const uint32 cur_tick = ::GetTickCount();
if (m_dwLastClientCleanUp + CLIENTLIST_CLEANUP_TIME < cur_tick ){
m_dwLastClientCleanUp = cur_tick;
POSITION pos1, pos2;
uint32 cDeleted = 0;
for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
list.GetNext(pos1);
CUpDownClient* pCurClient = list.GetAt(pos2);
if ((pCurClient->GetUploadState() == US_NONE || pCurClient->GetUploadState() == US_BANNED && !pCurClient->IsBanned())
&& pCurClient->GetDownloadState() == DS_NONE
&& pCurClient->GetChatState() == MS_NONE
&& pCurClient->GetKadState() == KS_NONE
&& pCurClient->socket == NULL)
{
cDeleted++;
delete pCurClient;
}
}
DEBUG_ONLY(AddDebugLogLine(false,_T("Cleaned ClientList, removed %i not used known clients"), cDeleted));
}
}
CDeletedClient::CDeletedClient(const CUpDownClient* pClient)
{
m_cBadRequest = 0;
m_dwInserted = ::GetTickCount();
PORTANDHASH porthash = { pClient->GetUserPort(), pClient->Credits()};
m_ItemsList.Add(porthash);
}
//EastShare Start - added by AndCycle, IP to Country
void CClientList::ResetIP2Country(){
CUpDownClient *cur_client;
for(POSITION pos = list.GetHeadPosition(); pos != NULL; list.GetNext(pos)) {
cur_client = theApp.clientlist->list.GetAt(pos);
cur_client->ResetIP2Country();
}
}
//EastShare End - added by AndCycle, IP to Country
// ZZ:DownloadManager -->
void CClientList::ProcessA4AFClients() {
//if(thePrefs.GetLogA4AF()) AddDebugLogLine(false, _T(">>> Starting A4AF check"));
POSITION pos1, pos2;
for (pos1 = list.GetHeadPosition();( pos2 = pos1 ) != NULL;){
list.GetNext(pos1);
CUpDownClient* cur_client = list.GetAt(pos2);
if(cur_client->GetDownloadState() != DS_DOWNLOADING &&
cur_client->GetDownloadState() != DS_CONNECTED &&
(!cur_client->m_OtherRequests_list.IsEmpty() || !cur_client->m_OtherNoNeeded_list.IsEmpty())) {
//AddDebugLogLine(false, _T("+++ ZZ:DownloadManager: Trying for better file for source: %s '%s'"), cur_client->GetUserName(), cur_client->reqfile->GetFileName());
cur_client->SwapToAnotherFile(_T("Periodic A4AF check CClientList::ProcessA4AFClients()"), false, false, false, NULL, true, false);
}
}
//if(thePrefs.GetLogA4AF()) AddDebugLogLine(false, _T(">>> Done with A4AF check"));
}
// <-- ZZ:DownloadManager
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -