📄 lastcommonroutefinder.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include "emule.h"
#include "Opcodes.h"
#include "LastCommonRouteFinder.h"
#include "Server.h"
#include "OtherFunctions.h"
#include "UpDownClient.h"
#include "Preferences.h"
#include "Pinger.h"
#include "emuledlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
LastCommonRouteFinder::LastCommonRouteFinder() {
minUpload = 1;
maxUpload = _UI32_MAX;
m_upload = _UI32_MAX;
m_CurUpload = 1;
m_iPingToleranceMilliseconds = 200;
m_bUseMillisecondPingTolerance = false;
m_iNumberOfPingsForAverage = 0;
m_pingAverage = 0;
m_lowestPing = 0;
m_LowestInitialPingAllowed = 20;
pingDelaysTotal = 0;
m_state = _T("");
needMoreHosts = false;
threadEndedEvent = new CEvent(0, 1);
newTraceRouteHostEvent = new CEvent(0, 0);
prefsEvent = new CEvent(0, 0);
m_enabled = false;
doRun = true;
AfxBeginThread(RunProc, (LPVOID)this);
}
LastCommonRouteFinder::~LastCommonRouteFinder() {
delete threadEndedEvent;
delete newTraceRouteHostEvent;
delete prefsEvent;
}
bool LastCommonRouteFinder::AddHostsToCheck(CTypedPtrList<CPtrList, CServer*> &list) {
if(needMoreHosts) {
addHostLocker.Lock();
if(needMoreHosts) {
if(list.GetCount() >= 10) {
hostsToTraceRoute.RemoveAll();
uint32 startPos = rand()/(RAND_MAX/list.GetCount());
POSITION pos = list.GetHeadPosition();
for(uint32 skipCounter = startPos; skipCounter < (uint32)list.GetCount() && pos != NULL; skipCounter++) {
list.GetNext(pos);
}
uint32 tryCount = 0;
while(pos != NULL && hostsToTraceRoute.GetCount() < 10 && tryCount <= (uint32)list.GetCount()) {
tryCount++;
CServer* server = list.GetNext(pos);
uint32 ip = server->GetIP();
if(IsGoodIP(ip, true)) {
hostsToTraceRoute.AddTail(ip);
}
}
}
if(hostsToTraceRoute.GetCount() >= 10) {
needMoreHosts = false;
// Signal that there's hosts to fetch.
newTraceRouteHostEvent->SetEvent();
addHostLocker.Unlock();
return true; // got enough hosts
} else {
addHostLocker.Unlock();
return false; // didn't get enough hosts
}
} else {
addHostLocker.Unlock();
return true; // allready got enough hosts, don't need more
}
} else {
return true; // allready got enough hosts, don't need more
}
}
bool LastCommonRouteFinder::AddHostsToCheck(CUpDownClientPtrList &list) {
if(needMoreHosts) {
addHostLocker.Lock();
if(needMoreHosts) {
if(list.GetCount() >= 10) {
hostsToTraceRoute.RemoveAll();
uint32 startPos = rand()/(RAND_MAX/list.GetCount());
POSITION pos = list.GetHeadPosition();
for(uint32 skipCounter = startPos; skipCounter < (uint32)list.GetCount() && pos != NULL; skipCounter++) {
list.GetNext(pos);
}
uint32 tryCount = 0;
while(pos != NULL && hostsToTraceRoute.GetCount() < 10 && tryCount <= (uint32)list.GetCount()) {
tryCount++;
CUpDownClient* client = list.GetNext(pos);
uint32 ip = client->GetIP();
if(IsGoodIP(ip, true)) {
hostsToTraceRoute.AddTail(ip);
}
}
}
if(hostsToTraceRoute.GetCount() >= 10) {
needMoreHosts = false;
// Signal that there's hosts to fetch.
newTraceRouteHostEvent->SetEvent();
addHostLocker.Unlock();
return true; // got enough hosts
} else {
addHostLocker.Unlock();
return false; // didn't get enough hosts
}
} else {
addHostLocker.Unlock();
return true; // allready got enough hosts, don't need more
}
} else {
return true; // allready got enough hosts, don't need more
}
}
CurrentPingStruct LastCommonRouteFinder::GetCurrentPing() {
CurrentPingStruct returnVal;
if(m_enabled) {
pingLocker.Lock();
returnVal.state = m_state;
returnVal.latency = m_pingAverage;
returnVal.lowest = m_lowestPing;
returnVal.currentLimit = m_upload;
pingLocker.Unlock();
} else {
returnVal.state = _T("");
returnVal.latency = 0;
returnVal.lowest = 0;
returnVal.currentLimit = 0;
}
return returnVal;
}
bool LastCommonRouteFinder::AcceptNewClient() {
return acceptNewClient || !m_enabled; // if enabled, then return acceptNewClient, otherwise return true
}
void LastCommonRouteFinder::SetPrefs(bool pEnabled, uint32 pCurUpload, uint32 pMinUpload, uint32 pMaxUpload, bool pUseMillisecondPingTolerance, double pPingTolerance, uint32 pPingToleranceMilliseconds, uint32 pGoingUpDivider, uint32 pGoingDownDivider, uint32 pNumberOfPingsForAverage, uint64 pLowestInitialPingAllowed) {
bool sendEvent = false;
prefsLocker.Lock();
if(pMinUpload <= 1024) {
minUpload = 1024;
} else {
minUpload = pMinUpload;
}
if(pMaxUpload != 0) {
maxUpload = pMaxUpload;
if(maxUpload < minUpload) {
minUpload = maxUpload;
}
} else {
maxUpload = pCurUpload+10*1024; //_UI32_MAX;
}
if(pEnabled && m_enabled == false) {
sendEvent = true;
// this will show the area for ping info in status bar.
theApp.emuledlg->SetStatusBarPartsSize();
} else if(pEnabled == false) {
if(m_enabled) {
// this will remove the area for ping info in status bar.
theApp.emuledlg->SetStatusBarPartsSize();
}
//prefsEvent->ResetEvent();
sendEvent = true;
}
// this will resize the area for ping info in status bar.
if(m_bUseMillisecondPingTolerance != pUseMillisecondPingTolerance) {
theApp.emuledlg->SetStatusBarPartsSize();
}
m_enabled = pEnabled;
m_bUseMillisecondPingTolerance = pUseMillisecondPingTolerance;
m_pingTolerance = pPingTolerance;
m_iPingToleranceMilliseconds = pPingToleranceMilliseconds;
m_goingUpDivider = pGoingUpDivider;
m_goingDownDivider = pGoingDownDivider;
m_CurUpload = pCurUpload;
m_iNumberOfPingsForAverage = pNumberOfPingsForAverage;
m_LowestInitialPingAllowed = pLowestInitialPingAllowed;
uploadLocker.Lock();
if (m_upload > maxUpload || pEnabled == false) {
m_upload = maxUpload;
}
uploadLocker.Unlock();
prefsLocker.Unlock();
if(sendEvent) {
prefsEvent->SetEvent();
}
}
uint32 LastCommonRouteFinder::GetUpload() {
uint32 returnValue;
uploadLocker.Lock();
returnValue = m_upload;
uploadLocker.Unlock();
return returnValue;
}
void LastCommonRouteFinder::SetUpload(uint32 newValue) {
uploadLocker.Lock();
m_upload = newValue;
uploadLocker.Unlock();
}
/**
* Make the thread exit. This method will not return until the thread has stopped
* looping.
*/
void LastCommonRouteFinder::EndThread() {
// signal the thread to stop looping and exit.
doRun = false;
prefsEvent->SetEvent();
newTraceRouteHostEvent->SetEvent();
// wait for the thread to signal that it has stopped looping.
threadEndedEvent->Lock();
}
/**
* Start the thread. Called from the constructor in this class.
*
* @param pParam
*
* @return
*/
UINT AFX_CDECL LastCommonRouteFinder::RunProc(LPVOID pParam) {
DbgSetThreadName("LastCommonRouteFinder");
InitThreadLocale();
LastCommonRouteFinder* lastCommonRouteFinder = (LastCommonRouteFinder*)pParam;
return lastCommonRouteFinder->RunInternal();
}
/**
* @return always returns 0.
*/
UINT LastCommonRouteFinder::RunInternal() {
Pinger pinger;
bool hasSucceededAtLeastOnce = false;
while(doRun) {
// wait for updated prefs
prefsEvent->Lock();
bool enabled = m_enabled;
// retry loop. enabled will be set to false in end of this loop, if to many failures (tries too large)
while(doRun && enabled) {
bool foundLastCommonHost = false;
uint32 lastCommonHost = 0;
uint32 lastCommonTTL = 0;
uint32 hostToPing = 0;
bool useUdp = false;
hostsToTraceRoute.RemoveAll();
pingDelays.RemoveAll();
pingDelaysTotal = 0;
pingLocker.Lock();
m_pingAverage = 0;
m_lowestPing = 0;
m_state = _T("Preparing...");
pingLocker.Unlock();
// Calculate a good starting value for the upload control. If the user has entered a max upload value, we use that. Otherwise 10 KBytes/s
int startUpload = (maxUpload != _UI32_MAX)?maxUpload:10*1024;
bool atLeastOnePingSucceded = false;
while(doRun && enabled && foundLastCommonHost == false) {
uint32 traceRouteTries = 0;
while(doRun && enabled && foundLastCommonHost == false && (traceRouteTries < 5 || hasSucceededAtLeastOnce && traceRouteTries < _UI32_MAX) && hostsToTraceRoute.GetCount() < 10) {
traceRouteTries++;
lastCommonHost = 0;
theApp.QueueDebugLogLine(false,_T("UploadSpeedSense: Try #%i. Collecting hosts..."), traceRouteTries);
addHostLocker.Lock();
needMoreHosts = true;
addHostLocker.Unlock();
// wait for hosts to traceroute
newTraceRouteHostEvent->Lock();
theApp.QueueDebugLogLine(false,_T("UploadSpeedSense: Got enough hosts. Listing the hosts that will be tracerouted:"));
POSITION pos = hostsToTraceRoute.GetHeadPosition();
int counter = 0;
while(pos != NULL) {
counter++;
uint32 hostToTraceRoute = hostsToTraceRoute.GetNext(pos);
IN_ADDR stDestAddr;
stDestAddr.s_addr = hostToTraceRoute;
theApp.QueueDebugLogLine(false,_T("UploadSpeedSense: Host #%i: %s"), counter, ipstr(stDestAddr));
}
// find the last common host, using traceroute
theApp.QueueDebugLogLine(false,_T("UploadSpeedSense: Starting traceroutes to find last common host."));
// for the tracerouting phase (preparing...) we need to disable uploads so we get a faster traceroute and better ping values.
SetUpload(2*1024);
Sleep(SEC2MS(1));
if(m_enabled == false) {
enabled = false;
}
bool failed = false;
uint32 curHost = 0;
for(uint32 ttl = 1; doRun && enabled && (curHost != 0 && ttl <= 64 || curHost == 0 && ttl < 5) && foundLastCommonHost == false && failed == false; ttl++) {
theApp.QueueDebugLogLine(false,_T("UploadSpeedSense: Pinging for TTL %i..."), ttl);
useUdp = false; // PENDING: Get default value from prefs?
curHost = 0;
if(m_enabled == false) {
enabled = false;
}
uint32 lastSuccedingPingAddress = 0;
uint32 lastDestinationAddress = 0;
uint32 hostsToTraceRouteCounter = 0;
bool failedThisTtl = false;
POSITION pos = hostsToTraceRoute.GetHeadPosition();
while(doRun && enabled && failed == false && failedThisTtl == false && pos != NULL &&
( lastDestinationAddress == 0 || lastDestinationAddress == curHost)) // || pingStatus.success == false && pingStatus.error == IP_REQ_TIMED_OUT ))
{
PingStatus pingStatus = {0};
POSITION lastPos = pos;
hostsToTraceRouteCounter++;
// this is the current address we send ping to, in loop below.
// PENDING: Don't confuse this with curHost, which is unfortunately almost
// the same name. Will rename one of these variables as soon as possible, to
// get more different names.
uint32 curAddress = hostsToTraceRoute.GetNext(pos);
pingStatus.success = false;
for(int counter = 0; doRun && enabled && counter < 2 && (pingStatus.success == false || pingStatus.success == true && pingStatus.status != IP_SUCCESS && pingStatus.status != IP_TTL_EXPIRED_TRANSIT); counter++) {
pingStatus = pinger.Ping(curAddress, ttl, true, useUdp);
if(doRun && enabled &&
(
pingStatus.success == false ||
pingStatus.success == true &&
pingStatus.status != IP_SUCCESS &&
pingStatus.status != IP_TTL_EXPIRED_TRANSIT
) &&
counter < 3-1)
{
IN_ADDR stDestAddr;
stDestAddr.s_addr = curAddress;
theApp.QueueDebugLogLine(false,_T("UploadSpeedSense: Failure #%i to ping host! (TTL: %i IP: %s error: %i). Sleeping 1 sec before retry. Error info follows."), counter+1, ttl, ipstr(stDestAddr), (pingStatus.success)?pingStatus.status:pingStatus.error);
pinger.PIcmpErr((pingStatus.success)?pingStatus.status:pingStatus.error);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -