//======================================================================= // // Copyright (c) 2001 Microsoft Corporation. All Rights Reserved. // // File: internet.cpp // // Creator: PeterWi // // Purpose: internet functions. // //======================================================================= #pragma hdrstop #include #include // for LPWSADATA, struct hostent #include // for InternetGetConnectedState(), InternetQueryOptionA() #include // for IPAddr #include // for NETWORK_ALIVE_* #include // for LOG_Block, LOG_Error and LOG_Internet #include // USES_IU_CONVERSION, T2A(), MemAlloc #include #include // UrlGetPart #include #include #define ARRAYSIZE(a) (sizeof(a)/sizeof((a)[0])) typedef BOOL (WINAPI * ISNETWORKALIVE)(LPDWORD); //typedef BOOL (WINAPI * INETCONNECTSTATE)(LPDWORD, DWORD); //typedef BOOL (WINAPI * INETQUERYOPTION)(HINTERNET, DWORD, LPVOID, LPDWORD); typedef DWORD (WINAPI * GETBESTINTERFACE)(IPAddr, DWORD *); typedef ULONG (WINAPI * INET_ADDR)(const char FAR *); typedef struct hostent FAR * (WINAPI * GETHOSTBYNAME)(const char FAR *name); typedef int (WINAPI * WSASTARTUP)(WORD, LPWSADATA); typedef int (WINAPI * WSACLEANUP)(void); #ifdef DBG typedef int (WINAPI * WSAGETLASTERROR)(void); #endif const char c_szWU_PING_URL[] = "207.46.226.17"; // current ip addr for windowsupdate.microsoft.com // forward declarations BOOL IsConnected_2_0(void); // HKLM\Software\Microsoft\Windows\CurrentVersion\WindowsUpdate\IsConnected DWORD reg value #define ISCONNECTEDMODE_Unknown -1 // static variable not initialized yet #define ISCONNECTEDMODE_Default 0 // live: use AU 2.0 logic // test = InternetGetConnectedState + InternetQueryOption + GetBestInterface on static IP // CorpWU: same as ISCONNECTEDMODE_IsNetworkAliveAndGetBestInterface #define ISCONNECTEDMODE_AlwaysConnected 1 // live/CorpWU: Assume the destination is always reachable. e.g. via D-tap connection. #define ISCONNECTEDMODE_IsNetworkAliveOnly 2 // live/CorpWU: test = IsNetworkAlive. #define ISCONNECTEDMODE_IsNetworkAliveAndGetBestInterface 3 // live: test = IsNetworkAlive + GetBestInterface on static IP // CorpWU: test = IsNetworkAlive + gethostbyname + GetBestInterface #define ISCONNECTEDMODE_MinValue 0 #define ISCONNECTEDMODE_MaxValue 3 inline DWORD GetIsConnectedMode(void) { static DWORD s_dwIsConnectedMode = ISCONNECTEDMODE_Unknown; if (ISCONNECTEDMODE_Unknown == s_dwIsConnectedMode) { // Assume using default connection detection mechanism s_dwIsConnectedMode = ISCONNECTEDMODE_Default; const TCHAR c_tszRegKeyWU[] = _T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate"); const TCHAR c_tszRegUrlLogIsConnectedMode[] = _T("IsConnectedMode"); HKEY hkey; if (NO_ERROR == RegOpenKeyEx( HKEY_LOCAL_MACHINE, c_tszRegKeyWU, 0, KEY_QUERY_VALUE, &hkey)) { DWORD dwSize = sizeof(s_dwIsConnectedMode); DWORD dwType; if (NO_ERROR != RegQueryValueEx( hkey, c_tszRegUrlLogIsConnectedMode, 0, &dwType, (LPBYTE) &s_dwIsConnectedMode, &dwSize) || REG_DWORD != dwType || sizeof(s_dwIsConnectedMode) != dwSize || // comment out the next line to avoid error C4296: '>' : expression is always false // ISCONNECTEDMODE_MinValue > s_dwIsConnectedMode || ISCONNECTEDMODE_MaxValue < s_dwIsConnectedMode) { s_dwIsConnectedMode = ISCONNECTEDMODE_Default; } RegCloseKey(hkey); } } return s_dwIsConnectedMode; } // ---------------------------------------------------------------------------------- // IsConnected() // detect if there is a connection currently that can be used to // connect to Windows Update site. // If yes, we activate the shedule DLL // // Input : ptszUrl - Url containing host name to check for connection // fLive - whether the destination is the live site // Output: None // Return: TRUE if we are connected and we can reach the web site. // FALSE if we cannot reach the site or we are not connected. // ---------------------------------------------------------------------------------- BOOL IsConnected(LPCTSTR ptszUrl, BOOL fLive) { BOOL bRet = FALSE; DWORD dwFlags = 0; ISNETWORKALIVE pIsNetworkAlive = NULL; HMODULE hIphlp = NULL, hSock = NULL, hSens = NULL; DWORD dwIsConnectedMode = GetIsConnectedMode(); LOG_Block("IsConnected"); if (ISCONNECTEDMODE_AlwaysConnected == dwIsConnectedMode) { LOG_Internet(_T("AlwaysConnected")); bRet = TRUE; goto lFinish; } if (fLive && ISCONNECTEDMODE_Default == dwIsConnectedMode) { LOG_Internet(_T("Use 2.0 algorithm")); bRet = IsConnected_2_0(); goto lFinish; } // InternetGetConnectedState() returns FALSE if Wininet/IE AutoDial is configured. // Thus we can't rely on it to see if we have network connectivity. #if 0 DWORD dwConnMethod = 0, dwState = 0, dwSize = sizeof(DWORD); bRet = InternetGetConnectedState(&dwConnMethod, 0); #ifdef DBG LOG_Internet(_T("Connection Method is %#lx"), dwConnMethod); LOG_Internet(_T("InternetGetConnectedState() return value %d"), bRet); if (dwConnMethod & INTERNET_CONNECTION_MODEM) { LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_MODEM")); } if (dwConnMethod & INTERNET_CONNECTION_LAN ) { LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_LAN")); } if (dwConnMethod & INTERNET_CONNECTION_PROXY ) { LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_PROXY")); } if (dwConnMethod & INTERNET_CONNECTION_MODEM_BUSY ) { LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_MODEM_BUSY")); } #endif if (bRet) { // modem is dialing if (dwConnMethod & INTERNET_CONNECTION_MODEM_BUSY) { bRet = FALSE; goto lFinish; } // check if there is a proxy but currently user is offline if (dwConnMethod & INTERNET_CONNECTION_PROXY) { if (InternetQueryOptionA(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize)) { if (dwState & (INTERNET_STATE_DISCONNECTED_BY_USER | INTERNET_STATE_DISCONNECTED)) { bRet = FALSE; goto lFinish; } } else { LOG_Error(_T("IsConnected() fail to get InternetQueryOption (%#lx)"), GetLastError()); } } } else { // // further test the case that user didn't run icw but is using a modem connection // const DWORD dwModemConn = (INTERNET_CONNECTION_MODEM | INTERNET_CONNECTION_MODEM_BUSY); if ((dwConnMethod & dwModemConn) == dwModemConn) { bRet = TRUE; } } //one final check for connectivity by pinging microsoft.com //if (bRet) //{ // bRet = CheckByPing(szURL); //} //bugfix for InternetGetConnectedState API - if LAN card is disabled it still returns LAN connection //use GetBestInterface and see if there is any error trying to reach an outside IP address //this may fix scenarios in homelan case where there is no actual connection to internet?? if (!bRet || (dwConnMethod & INTERNET_CONNECTION_LAN)) //LAN card present //bug 299338 { // do gethostbyname and GetBestInterface } #endif if (NULL == (hSens = LoadLibraryFromSystemDir(TEXT("sensapi.dll"))) || NULL == (pIsNetworkAlive = (ISNETWORKALIVE)::GetProcAddress(hSens, "IsNetworkAlive"))) { LOG_Error(_T("failed to load IsNetworkAlive() from sensapi.dll")); goto lFinish; } if (pIsNetworkAlive(&dwFlags)) { #ifdef DBG if (NETWORK_ALIVE_LAN & dwFlags) { LOG_Internet(_T("active LAN card(s) detected")); } if (NETWORK_ALIVE_WAN & dwFlags) { LOG_Internet(_T("active RAS connection(s) detected")); } if (NETWORK_ALIVE_AOL & dwFlags) { LOG_Internet(_T("AOL connection detected")); } #endif if (ISCONNECTEDMODE_IsNetworkAliveOnly == dwIsConnectedMode) { LOG_Internet(_T("IsNetworkAliveOnly ok")); bRet = TRUE; goto lFinish; } // can't be moved into where ptszHostName and pszHostName are // MemAlloc'ed since pszHostName will be used outside that block. USES_IU_CONVERSION; GETBESTINTERFACE pGetBestInterface = NULL; INET_ADDR pInetAddr = NULL; LPCSTR pszHostName = NULL; if (fLive && ISCONNECTEDMODE_IsNetworkAliveAndGetBestInterface == dwIsConnectedMode) { pszHostName = c_szWU_PING_URL; } else { // !fLive && (ISCONNECTEDMODE_Default == dwIsConnectedMode || // ISCONNECTEDMODE_IsNetworkAliveAndGetBestInterface == dwIsConnectedMode) if (NULL == ptszUrl || _T('\0') == ptszUrl[0]) { LOG_Error(_T("IsConnected() invalid parameter")); } else { TCHAR tszHostName[40]; // arbitrary buffer size that should work with most domain names DWORD dwCchHostName = ARRAYSIZE(tszHostName); LPTSTR ptszHostName = tszHostName; HRESULT hr = UrlGetPart(ptszUrl, tszHostName, &dwCchHostName, URL_PART_HOSTNAME, 0); if (E_POINTER == hr) { if (NULL != (ptszHostName = (LPTSTR) MemAlloc(sizeof(TCHAR) * dwCchHostName))) { hr = UrlGetPart(ptszUrl, ptszHostName, &dwCchHostName, URL_PART_HOSTNAME, 0); } else { hr = E_OUTOFMEMORY; } } if (FAILED(hr)) { LOG_Error(_T("failed to extract hostname (error %#lx)"), hr); } else { pszHostName = T2A(ptszHostName); } } } if (NULL == pszHostName) { LOG_Error(_T("call to T2A (IU version) failed")); } else if ( NULL != (hIphlp = LoadLibraryFromSystemDir(TEXT("iphlpapi.dll"))) && NULL != (hSock = LoadLibraryFromSystemDir(TEXT("ws2_32.dll"))) && NULL != (pGetBestInterface = (GETBESTINTERFACE)::GetProcAddress(hIphlp, "GetBestInterface")) && NULL != (pInetAddr = (INET_ADDR)::GetProcAddress(hSock, "inet_addr"))) { IPAddr dest; LOG_Internet(_T("checking connection to %hs..."), pszHostName); //fixcode: should check against broadcasting IP addresses if (INADDR_NONE == (dest = pInetAddr(pszHostName))) { GETHOSTBYNAME pGetHostByName = NULL; WSASTARTUP pWSAStartup = NULL; WSACLEANUP pWSACleanup = NULL; #ifdef DBG WSAGETLASTERROR pWSAGetLastError = NULL; #endif WSADATA wsaData; int iErr = 0; if (NULL != (pGetHostByName = (GETHOSTBYNAME)::GetProcAddress(hSock, "gethostbyname")) && #ifdef DBG NULL != (pWSAGetLastError = (WSAGETLASTERROR)::GetProcAddress(hSock, "WSAGetLastError")) && #endif NULL != (pWSAStartup = (WSASTARTUP)::GetProcAddress(hSock, "WSAStartup")) && NULL != (pWSACleanup = (WSACLEANUP)::GetProcAddress(hSock, "WSACleanup")) && //fixcode: should be called at the constructor of CUrlLog and when IU (when online) or AU starts. 0 == pWSAStartup(MAKEWORD(1, 1), &wsaData)) { #ifdef DBG DWORD dwStartTime = GetTickCount(); #endif struct hostent *ptHost = pGetHostByName(pszHostName); if (NULL != ptHost && AF_INET == ptHost->h_addrtype && sizeof(IPAddr) == ptHost->h_length && NULL != ptHost->h_addr_list && NULL != ptHost->h_addr) { // take the first IP address dest = *((IPAddr FAR *) ptHost->h_addr); #ifdef DBG LOG_Internet( _T("Host name %hs resolved to be %d.%d.%d.%d, took %d msecs"), pszHostName, (BYTE) ((ptHost->h_addr)[0]), (BYTE) ((ptHost->h_addr)[1]), (BYTE) ((ptHost->h_addr)[2]), (BYTE) ((ptHost->h_addr)[3]), GetTickCount() - dwStartTime); #endif } #ifdef DBG else { LOG_Internet(_T("Host name %hs couldn't be resolved (error %d), took %d msecs"), pszHostName, pWSAGetLastError(), GetTickCount() - dwStartTime); } #endif //fixcode: should be called at the destructor of CUrlLog and when IU (when online) or AU ends. if (iErr = pWSACleanup()) { LOG_Error(_T("failed to clean up winsock (error %d)"), iErr); } } else { LOG_Error(_T("failed to load winsock procs or WSAStartup() failed")); } } if (INADDR_NONE != dest) { DWORD dwErr, dwIndex; if (bRet = (NO_ERROR == (dwErr = pGetBestInterface(dest, &dwIndex)))) { LOG_Internet(_T("route found on interface #%d"), dwIndex); } else { LOG_Internet(_T("GetBestInterface() failed w/ error %d"), dwErr); } } } else { LOG_Error(_T("failed to load procs from winsock/ip helper (error %d)"), GetLastError()); } } else { LOG_Internet(_T("no active connection detected")); } lFinish: if (hIphlp != NULL) { FreeLibrary(hIphlp); } if (hSock != NULL) { FreeLibrary(hSock); } if (hSens != NULL) { FreeLibrary(hSens); } return (bRet); } // ---------------------------------------------------------------------------------- // // Function IsConnected_2_0() // detect if there is a cunection currently can be used to // connect to live Windows Update site. // If yes, we activate the shedule DLL // // Input : None // Output: None // Return: TRUE if we are connected and we can reach the web site. // FALSE if we cannot reach the live site or we are not connected. // // // ---------------------------------------------------------------------------------- BOOL IsConnected_2_0() { BOOL bRet = FALSE; DWORD dwConnMethod, dwState = 0, dwSize = sizeof(DWORD), dwErr, dwIndex; GETBESTINTERFACE pGetBestInterface = NULL; INET_ADDR pInet_addr = NULL; HMODULE hIphlp = NULL, hSock = NULL; LOG_Block("IsConnected"); bRet = InternetGetConnectedState(&dwConnMethod, 0); /* #ifdef DBG LOG_Internet(_T("Connection Method is %#lx"), dwConnMethod); LOG_Internet(_T("InternetGetConnectedState() return value %d"), bRet); if (dwConnMethod & INTERNET_CONNECTION_MODEM) { LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_MODEM")); } if (dwConnMethod & INTERNET_CONNECTION_LAN ) { LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_LAN")); } if (dwConnMethod & INTERNET_CONNECTION_PROXY ) { LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_PROXY")); } if (dwConnMethod & INTERNET_CONNECTION_MODEM_BUSY ) { LOG_Internet(_T("\t%s"), _T("INTERNET_CONNECTION_MODEM_BUSY")); } #endif */ if (bRet) { // modem is dialing if (dwConnMethod & INTERNET_CONNECTION_MODEM_BUSY) { bRet = FALSE; goto lFinish; } // check if there is a proxy but currently user is offline if (dwConnMethod & INTERNET_CONNECTION_PROXY) { if (InternetQueryOptionA(NULL, INTERNET_OPTION_CONNECTED_STATE, &dwState, &dwSize)) { if (dwState & (INTERNET_STATE_DISCONNECTED_BY_USER | INTERNET_STATE_DISCONNECTED)) { bRet = FALSE; goto lFinish; } } else { LOG_Error(_T("IsConnected() fail to get InternetQueryOption (%#lx)"), GetLastError()); } } } else { // // further test the case that user didn't run icw but is using a modem connection // const DWORD dwModemConn = (INTERNET_CONNECTION_MODEM | INTERNET_CONNECTION_MODEM_BUSY); if ((dwConnMethod & dwModemConn) == dwModemConn) { bRet = TRUE; } } //one final check for connectivity by pinging microsoft.com //if (bRet) //{ // bRet = CheckByPing(szURL); //} //bugfix for InternetGetConnectedState API - if LAN card is disabled it still returns LAN connection //use GetBestInterface and see if there is any error trying to reach an outside IP address //this may fix scenarios in homelan case where there is no actual connection to internet?? if ((bRet && (dwConnMethod & INTERNET_CONNECTION_LAN)) || //LAN card present (!bRet)) //bug 299338 { struct sockaddr_in dest; hSock = LoadLibraryFromSystemDir(TEXT("ws2_32.dll")); hIphlp = LoadLibraryFromSystemDir(TEXT("iphlpapi.dll")); if ((hIphlp == NULL) || (hSock == NULL)) { goto lFinish; } pGetBestInterface = (GETBESTINTERFACE)::GetProcAddress(hIphlp, "GetBestInterface"); pInet_addr = (INET_ADDR)::GetProcAddress(hSock, "inet_addr"); if ((pGetBestInterface == NULL) || (pInet_addr == NULL)) { goto lFinish; } if ((dest.sin_addr.s_addr = pInet_addr(c_szWU_PING_URL)) == INADDR_ANY) { goto lFinish; } if (NO_ERROR != (dwErr = pGetBestInterface(dest.sin_addr.s_addr, &dwIndex))) { LOG_ErrorMsg(dwErr); bRet = FALSE; //any error bail out for now /* if (dwErr == ERROR_NETWORK_UNREACHABLE) //winerror.h { bRet = FALSE; } */ } else { bRet = TRUE; } } lFinish: if (hIphlp != NULL) { FreeLibrary(hIphlp); } if (hSock != NULL) { FreeLibrary(hSock); } LOG_Internet(_T("%s"), bRet ? _T("Connected") : _T("Not connected")); return (bRet); }