📄 autodial.c
字号:
DWORD HangUpIdleConnectionThread(LPVOID lpv)
{
RAS_STATS pppStats;
DWORD cbPPPStats = sizeof(pppStats);
DWORD dwActualOut;
__int64 ftCur; // treated as a FILETIME, current time
RASCONNSTATUS rasConnStatus;
pppStats.dwSize = sizeof(pppStats);
rasConnStatus.dwSize = sizeof (RASCONNSTATUS);
while ( WAIT_TIMEOUT == WaitForSingleObject(g_AutoDialConn.m_hTimerEvent,HANGUP_SLEEP_INTERVAL))
{
// If the connection came down in another way (for instance someone unplugging phone)
// then we need to shut down AutoDial stuff.
EnterCriticalSection(&g_GlobalCS);
ASSERT(g_fState == STATE_ON || g_fState == STATE_SHUTTING_DOWN || g_fState == STATE_STARTING_UP);
if (g_fState == STATE_SHUTTING_DOWN || g_fState == STATE_STARTING_UP)
{
// In this state the timer fired after we initiated a shutdown
// but before we could kill this thread from AutodialEndConnection,
// so just keep going through loop in this case.
DEBUGMSG(ZONE_WARN,(TEXT("AutoDial: HangupIdleConnectionThread called when state=STATE_SHUTTING_DOWN or STATE_STARTING_UP\r\n")));
LeaveCriticalSection(&g_GlobalCS);
continue;
}
if (g_fState != STATE_ON)
{
DEBUGMSG(ZONE_ERROR | ZONE_CONNECTION,(TEXT("AutoDial: Warning, leaving HangUpIdleConnectionThread because g_fState is not on. Invalid case\r\n")));
LeaveCriticalSection(&g_GlobalCS);
return 0;
}
if (ERROR_SUCCESS != RasGetConnectStatus(g_AutoDialConn.m_hRasConn,&rasConnStatus) ||
(rasConnStatus.rasconnstate == RASCS_Disconnected))
{
DEBUGMSG(ZONE_CONNECTION,(TEXT("AutoDial: Leaving HangUpIdleConnectionThread because connection has been disconnected\r\n")));
LeaveCriticalSection(&g_GlobalCS);
AutoDialEndConnectionInternal(TRUE);
return 0;
}
LeaveCriticalSection(&g_GlobalCS);
GetCurrentFT((FILETIME *) &ftCur);
RasIOControl(g_AutoDialConn.m_hRasConn,RASCNTL_STATISTICS,0,0,(PVOID) &pppStats,cbPPPStats,&dwActualOut);
DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:+HangUpIdleConnectionThread. pppStats.dwBytesXmited=%d, pppStats.dwBytesRcved=%d,g_AutoDialConn.m_dwBytesTxRx=%d\r\n"),
pppStats.dwBytesXmited,pppStats.dwBytesRcved,g_AutoDialConn.m_dwBytesTxRx));
// Has there been activity since the last time this thread ran?
if (pppStats.dwBytesXmited + pppStats.dwBytesRcved - g_AutoDialConn.m_dwBytesTxRx > 0)
{
g_AutoDialConn.m_dwBytesTxRx = pppStats.dwBytesXmited +
pppStats.dwBytesRcved;
g_AutoDialConn.m_ftLastActivity = ftCur;
}
else if (ftCur - g_AutoDialConn.m_ftLastActivity > g_AutoDialConn.m_ftIdleTimeout)
{
DEBUGMSG(ZONE_CONNECTION,(TEXT("Autodial: Disconnecting RAS connection due to long idle time\r\n")));
AutoDialEndConnectionInternal(TRUE);
break;
}
}
return 0;
}
// Returns TRUE if it found connection (and sets pConnState), FALSE otherwise.
BOOL GetConnectedStatus(TCHAR *szEntryName, RASCONNSTATUS *lpRasConn, HRASCONN *phRasConn)
{
DWORD dwConnections;
DWORD dwErr;
LPRASCONN pRasConn;
BYTE RasConnData[10*sizeof(RASCONN)];
DWORD cb;
DWORD i;
DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:+CheckConnected\r\n")));
// This will create the default entries if the key does not exist.
RasEnumEntries (NULL, NULL, NULL, &cb, NULL);
pRasConn = (LPRASCONN) RasConnData;
pRasConn->dwSize = sizeof(RASCONN);
cb = sizeof(RasConnData);
// Get a list of all connections
if (ERROR_SUCCESS != (dwErr = RasEnumConnections(pRasConn,&cb,&dwConnections)))
{
DEBUGMSG(ZONE_ERROR,(L"RasEnumConnections failed, error=0x%08x\r\n",dwErr));
return FALSE;
}
// Look through the list for a value of szEntryName.
for (i = 0; i < dwConnections; i++)
{
if (! (_tcsncmp (szEntryName,pRasConn[i].szEntryName,RAS_MaxEntryName)))
break;
}
if (i == dwConnections)
return FALSE; // did not find szEntryName in current active connections.
lpRasConn->dwSize = sizeof(RASCONNSTATUS);
if (ERROR_SUCCESS != (dwErr = RasGetConnectStatus(pRasConn[i].hrasconn,lpRasConn)))
{
DEBUGMSG(ZONE_ERROR,(L"RasGetConnectStatus failed, error=0x%08x\r\n",dwErr));
return FALSE;
}
*phRasConn = pRasConn[i].hrasconn;
return TRUE;
}
// This function takes the entry name and makes sure that no existing connections
// exist with it yet.
DWORD CheckConnected(TCHAR *szEntryName)
{
RASCONNSTATUS RasConnStatus;
HRASCONN hRasConn;
if (GetConnectedStatus(szEntryName,&RasConnStatus,&hRasConn) && (RasConnStatus.rasconnstate != RASCS_Disconnected))
{
DEBUGMSG(ZONE_ERROR,(TEXT("AutoDial: Checking to see if %s connectoid connection returns ERROR_DIAL_ALREADY_IN_PROGRESS")
TEXT("will not initiate dial\r\n"),szEntryName));
return ERROR_DIAL_ALREADY_IN_PROGRESS;
}
return ERROR_SUCCESS;
}
// It's possible another process is using autodial (i.e. device.exe
// IPNat loaded autodial, but we're doing this query from services.exe NATAdmin).
// In this case see if the connection is active and fill in state appropriatly.
DWORD DetermineIfAutodialConnectionsActive(RASCONNSTATUS *lpRasConnStatus, TCHAR *szRasName, HRASCONN *phRasConn)
{
AUTODIAL_CONNECTION_INFO adConnInfo;
TCHAR szEntryName1[RAS_MaxEntryName + 1];
TCHAR szEntryName2[RAS_MaxEntryName + 1];
DWORD dwRet;
szEntryName1[0] = szEntryName2[0] = 0;
if (ERROR_SUCCESS == AutodialReadRegistrySettings(NULL,szEntryName1,szEntryName2,&adConnInfo))
{
DEBUGCHK(szEntryName1[0]);
if (GetConnectedStatus(szEntryName1,lpRasConnStatus,phRasConn))
{
_tcscpy(szRasName,szEntryName1);
dwRet = ERROR_SUCCESS;
}
else if (szEntryName2[0] && GetConnectedStatus(szEntryName2,lpRasConnStatus,phRasConn))
{
_tcscpy(szRasName,szEntryName2);
dwRet = ERROR_SUCCESS;
}
else
{
dwRet = ERROR_NO_CONNECTION;
}
}
else
{
lpRasConnStatus->rasconnstate = RASCS_Disconnected;
szRasName[0] = 0;
dwRet = ERROR_NO_CONNECTION;
}
return dwRet;
}
// SetFailTime and CheckFailRetry are functions that help maintain and check
// the last time of failure list. The idea here is that we don't want autodial
// to keep trying to dial again and again if it constantly fails.
// Called on failure of Autodial to establish a connection.
void SetFailTime(void)
{
__int64 ftNow; // treated as a FILETIME
DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:+SetFailTime\r\n")));
if (!g_AutoDialConn.m_ftFailRetryWait)
return;
GetCurrentFT((FILETIME *) &ftNow);
if (ftNow - g_AutoDialConn.g_ftLastFailTime < g_AutoDialConn.m_ftFailRetryWait)
{
g_AutoDialConn.m_iLastFailIndex += 1;
}
else
{
g_AutoDialConn.g_ftLastFailTime = ftNow;
g_AutoDialConn.m_iLastFailIndex = 1;
}
}
// Called on initilization, makes sure numerous calls to the autodialer haven't
// failed in a short time frame.
BOOL CheckFailRetry(void)
{
__int64 ftNow; // treated as a FILETIME
DEBUGMSG(ZONE_FUNCTION,(TEXT("AutoDial:+CheckFailRetry\r\n")));
if (!g_AutoDialConn.m_ftFailRetryWait ||
g_AutoDialConn.m_iLastFailIndex < FAIL_RETRY_ATTEMPTS)
{
return TRUE;
}
GetCurrentFT((FILETIME *) &ftNow);
if (ftNow - g_AutoDialConn.g_ftLastFailTime < g_AutoDialConn.m_ftFailRetryWait)
{
DEBUGMSG(ZONE_ERROR,(TEXT("Autodial:CheckFailRetry has failed, too many retries\r\n")));
return FALSE;
}
return TRUE;
}
typedef DWORD (WINAPI *PFN_GETINTERFACEINFO)(IN PIP_INTERFACE_INFO pIfTable, OUT PULONG dwOutBufLen);
typedef DWORD (WINAPI *PFN_IPRELEASEADDRESS)(PIP_ADAPTER_INDEX_MAP AdapterInfo);
typedef DWORD (WINAPI *PFN_IPRENEWADDRESS)(PIP_ADAPTER_INDEX_MAP AdapterInfo);
PFN_GETINTERFACEINFO pfnGetInterfaceInfo;
PFN_IPRELEASEADDRESS pfnIpReleaseAddress;
PFN_IPRENEWADDRESS pfnIpRenewAddress;
// Connection Sharing (i.e. NAT, i.e. ICS, i.e. Home Gateway) determines whether
// to enable Address translation when it receives a LanaUp call on a given
// interface based on whether the reg key HKLM\Comm\ConnectionSharing\PublicInterface
// mateches the name of interface coming up. Before we call RasDial we reset
// this reg key.
void SetAsPublicInterface(TCHAR *szEntryName)
{
HKEY hKey;
static TCHAR PrimaryPublicInterface[257];
static DWORD dwTypePublicInterface;
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, ICSRegKey, 0,
KEY_ALL_ACCESS, &hKey))
{
return;
}
if(szEntryName != NULL)
{
//
// Store the name of our primary public interface before overriding it with autodial adapter
//
if(PrimaryPublicInterface[0] == TEXT('\x0'))
{
DWORD dw = sizeof(PrimaryPublicInterface);
RegQueryValueEx(hKey, ICSRegPublicInterface, 0, &dwTypePublicInterface, (LPBYTE)PrimaryPublicInterface, &dw);
}
//
// Set PublicInterface registry value to the name of autodial network adapter
//
RegSetValueEx(hKey, ICSRegPublicInterface, 0, REG_SZ, (LPBYTE)szEntryName, sizeof(TCHAR)*(lstrlen(szEntryName)+1));
}
else
{
//
// Restore PublicInterface registry value to our primary public interface
//
RegSetValueEx(hKey, ICSRegPublicInterface, 0, dwTypePublicInterface, (LPBYTE)PrimaryPublicInterface, sizeof(TCHAR)*(lstrlen(PrimaryPublicInterface)+1));
if(pfnGetInterfaceInfo && pfnIpReleaseAddress && pfnIpRenewAddress)
{
DWORD dwSize = 0;
if(ERROR_INSUFFICIENT_BUFFER == (*pfnGetInterfaceInfo)(NULL, &dwSize))
{
PIP_INTERFACE_INFO pIfTable;
if(pIfTable = (PIP_INTERFACE_INFO)LocalAlloc(LMEM_FIXED, dwSize))
{
if(ERROR_SUCCESS == (*pfnGetInterfaceInfo)(pIfTable, &dwSize))
{
int i;
for(i = 0; i < pIfTable->NumAdapters; ++i)
{
if(0 == wcscmp(pIfTable->Adapter[i].Name, PrimaryPublicInterface))
{
//
// Release and immediately renew IP address of the primary public interface
// so that NAT can reinitialize itself to use the primary interface.
//
(*pfnIpReleaseAddress)(&pIfTable->Adapter[i]);
(*pfnIpRenewAddress)(&pIfTable->Adapter[i]);
break;
}
}
}
LocalFree(pIfTable);
}
}
}
PrimaryPublicInterface[0] = TEXT('\x0');
}
RegCloseKey(hKey);
return;
}
BOOL WINAPI DllEntry( HANDLE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
{
static HANDLE hIphplapi = NULL;
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
#ifdef UNDER_CE
DEBUGREGISTER((HINSTANCE)hInstDll);
#endif
g_hInstance = hInstDll;
DisableThreadLibraryCalls ((HMODULE)hInstDll);
if(hIphplapi = LoadLibrary(L"iphlpapi.dll"))
{
pfnGetInterfaceInfo = (PFN_GETINTERFACEINFO) GetProcAddress(hIphplapi, L"GetInterfaceInfo");
pfnIpReleaseAddress = (PFN_IPRELEASEADDRESS) GetProcAddress(hIphplapi, L"IpReleaseAddress");
pfnIpRenewAddress = (PFN_IPRENEWADDRESS) GetProcAddress(hIphplapi, L"IpRenewAddress");
}
break;
case DLL_PROCESS_DETACH:
if(hIphplapi)
FreeLibrary(hIphplapi);
break;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -