netchck.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:36k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hlxclib/windows.h"
  36. #include "prefdefs.h"
  37. #include "netchck.h"
  38. #include "hxtick.h"
  39. #include "hxassert.h"
  40. #include "hxver.h"
  41. #include <raserror.h>     // for ras error codes
  42. #define DEF_DNS_PORT      53 //tcp
  43. #define DIALOG_CLASS "#32770"
  44. #include "hxheap.h"
  45. #ifdef _DEBUG
  46. #undef HX_THIS_FILE
  47. static const char HX_THIS_FILE[] = __FILE__;
  48. #endif
  49. // Comment out this definition for release versions that shouldn't have
  50. // logging code compiled in.
  51. #define USE_NETDETECT_LOG 1
  52. #ifdef USE_NETDETECT_LOG
  53.     #include "hlxclib/fcntl.h"     // for file constants
  54.     #include "chxdataf.h"     // CHXDataFile
  55.     #include "hlxclib/time.h"
  56.     #include "pref.h"     // CPref
  57.     #include "ihxpckts.h"   // IHXBuffer
  58. #endif
  59. namespace NetDetectLog
  60. {
  61.     #ifndef USE_NETDETECT_LOG
  62. #define WRITE_LOG0(format) do {;} while(0)
  63. #define WRITE_LOG1(format, x1) do {;} while(0)
  64. #define INITIALIZE_LOG() do {;} while(0)
  65. #define CLOSE_LOG() do {;} while(0)
  66. #define WRITE_LOG_WINET(result, flags) do {;} while(0)
  67.     #else
  68. #define STR_EOL "rn"
  69. const char* const kszNetdetectLogFileName = "netdtlog.txt";
  70. const char* const kszNetdetectLogPrefKey = "netdetectlog";
  71. static CHXDataFile* g_pLogFile = NULL;
  72. HX_RESULT InitializeLog();
  73. HX_RESULT CloseLog();
  74. HX_RESULT WriteToLog(const CHXString& msg);
  75. HX_RESULT WriteToLogWinInetGetConnected(BOOL result, DWORD flags);
  76. #define INITIALIZE_LOG() do { InitializeLog(); } while(0)
  77. #define CLOSE_LOG() do { CloseLog(); } while(0)
  78. #define WRITE_LOG0(format)
  79.     WriteToLog(format);
  80. #define WRITE_LOG1(format, x1){
  81.     CHXString strFormat;
  82.     strFormat.Format(format, x1);
  83.     WriteToLog(strFormat);}
  84. #define WRITE_LOG_WINET(result, flags)
  85.     WriteToLogWinInetGetConnected(result, flags)
  86. HX_RESULT WriteToLogWinInetGetConnected(BOOL result, DWORD flags)
  87. {
  88.     // Flags for InternetGetConnectedState 
  89.     #define INTERNET_CONNECTION_MODEM           0x01
  90.     #define INTERNET_CONNECTION_LAN             0x02
  91.     #define INTERNET_CONNECTION_PROXY           0x04
  92.     #define INTERNET_CONNECTION_MODEM_BUSY      0x08  /* no longer used */
  93.     #define INTERNET_RAS_INSTALLED              0x10
  94.     #define INTERNET_CONNECTION_OFFLINE         0x20
  95.     #define INTERNET_CONNECTION_CONFIGURED      0x40
  96.     CHXString strFormat;
  97.     if(result) 
  98.     {
  99. CHXString format("InternetGetConnectedState returned TRUE; flag = %s");
  100. if(flags & INTERNET_CONNECTION_MODEM)
  101. {
  102.     strFormat.Format(format, "INTERNET_CONNECTION_MODEM");
  103. }
  104. else if(flags & INTERNET_CONNECTION_LAN)
  105. {
  106.     strFormat.Format(format, "INTERNET_CONNECTION_LAN");
  107. }
  108. else if(flags & INTERNET_CONNECTION_PROXY)
  109. {
  110.     strFormat.Format(format, "INTERNET_CONNECTION_PROXY");
  111. }
  112. else if(flags & INTERNET_CONNECTION_MODEM_BUSY)
  113. {
  114.     strFormat.Format(format, "INTERNET_CONNECTION_MODEM_BUSY");
  115. }
  116. else if(flags & INTERNET_RAS_INSTALLED)
  117. {
  118.     strFormat.Format(format, "INTERNET_RAS_INSTALLED");
  119. }
  120. else if(flags & INTERNET_CONNECTION_OFFLINE)
  121. {
  122.     strFormat.Format(format, "INTERNET_CONNECTION_OFFLINE");
  123. }
  124. else if(flags & INTERNET_CONNECTION_CONFIGURED)
  125. {
  126.     strFormat.Format(format, "INTERNET_CONNECTION_CONFIGURED");
  127. }
  128.     }
  129.     else
  130.     {
  131. strFormat = "InternetGetConnectedState returned FALSE";
  132.     }
  133.     return WriteToLog(strFormat);
  134. }
  135. HX_RESULT InitializeLog()
  136. {
  137.     HX_RESULT res = HXR_FAIL;
  138.     BOOL bShouldWriteLogFile = FALSE;
  139.     // Read from the preferences to see if we should write a log file.
  140.     CPref* pPreferences = CPref::open_shared_pref( HXVER_COMMUNITY );
  141.     if( pPreferences )
  142.     {
  143. IHXBuffer* pBuffer = NULL;
  144. if( SUCCEEDED( pPreferences->read_pref( kszNetdetectLogPrefKey, pBuffer ))) 
  145. {
  146.     bShouldWriteLogFile = 
  147. ( atoi( reinterpret_cast<const char*>(pBuffer->GetBuffer())) == 1 );
  148.     HX_RELEASE(pBuffer);
  149. }
  150. HX_DELETE( pPreferences );
  151.     }
  152.     if( !bShouldWriteLogFile )
  153.     {
  154. return res;
  155.     }
  156.     // First try to open the file for appending.  If that doesn't work,
  157.     // then just create a new one.
  158.     g_pLogFile = CHXDataFile::Construct();
  159.     if (g_pLogFile)
  160.     {
  161. res = g_pLogFile->Open(kszNetdetectLogFileName, 
  162.     O_BINARY | O_WRONLY | O_APPEND, TRUE);
  163. if (FAILED(res))
  164. {
  165.     res = g_pLogFile->Open(kszNetdetectLogFileName, 
  166. O_BINARY | O_CREAT | O_TRUNC | O_WRONLY, TRUE);
  167. }
  168. if( SUCCEEDED( res ))
  169. {
  170.     CHXString strMsg;
  171.     strMsg.Format("%s################################################"
  172. "##############################%s", 
  173. STR_EOL, STR_EOL);
  174.     g_pLogFile->Write(strMsg, strMsg.GetLength());
  175. }
  176. else
  177. {
  178.     HX_DELETE(g_pLogFile);
  179. }
  180.     }
  181.     return res;
  182. }
  183. HX_RESULT CloseLog()
  184. {
  185.     if (g_pLogFile)
  186.     {
  187. g_pLogFile->Close();
  188. HX_DELETE(g_pLogFile);
  189.     }
  190.     return HXR_OK;
  191. }
  192. HX_RESULT WriteToLog(const CHXString& msg)
  193. {
  194.     HX_RESULT res = HXR_FAIL;
  195.     if (g_pLogFile)
  196.     {
  197. time_t now = time(NULL);
  198. struct tm* date = localtime(&now);
  199. char szTime[20] = { 0 }; /* Flawfinder: ignore */
  200. #if !defined(WIN32_PLATFORM_PSPC)
  201. if(date)
  202. {
  203.     strftime(szTime, 19, "%X", date);
  204. }
  205. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  206. CHXString newMsg;
  207. newMsg.Format("%s: %s%s", szTime, (const char*)msg, STR_EOL);
  208. res = (g_pLogFile->Write(newMsg, newMsg.GetLength()) 
  209.     == newMsg.GetLength()) ? HXR_OK : HXR_FAIL;
  210.     }
  211.     return res;
  212. }
  213.     #endif // USE_NETDETECT_LOG
  214.     // "resource aquisition is init" - Init/ Close log file
  215.     class NetDetectLogLib
  216.     {
  217.     public:
  218. NetDetectLogLib() { INITIALIZE_LOG(); }
  219. ~NetDetectLogLib() { CLOSE_LOG(); }
  220.     };
  221. } //NetDetectLog namespace 
  222. CHXNetCheck::CHXNetCheck(UINT32 timeout) : 
  223. XHXNetCheck(timeout)
  224. ,m_pRmaNetServices(0)
  225. , m_pRmaTCPSocket(0)
  226. , m_pContext(0)
  227. , m_fConnected(FALSE)
  228. , m_fFailed(FALSE)
  229. , m_lRefCount(0)
  230. #ifndef _WIN16
  231. , m_hRasApiModule(0)
  232. , m_pRasEnumConnections(0)
  233. #endif
  234. {
  235. }
  236. CHXNetCheck::~CHXNetCheck()
  237. {
  238. if (m_pContext)
  239. m_pContext->Release();
  240. m_pContext = NULL;
  241. if (m_pRmaNetServices)
  242. m_pRmaNetServices->Release();
  243. m_pRmaNetServices = NULL;
  244. if (m_pRmaTCPSocket)
  245. m_pRmaTCPSocket->Release();
  246. m_pRmaTCPSocket = NULL;
  247. }
  248. /////////////////////////////////////////////////////////////////////////
  249. //  Method:
  250. // IUnknown::QueryInterface
  251. //  Purpose:
  252. // Implement this to export the interfaces supported by your 
  253. // object.
  254. //
  255. STDMETHODIMP CHXNetCheck::QueryInterface(REFIID riid, void** ppvObj)
  256. {
  257.     if (IsEqualIID(riid, IID_IUnknown))
  258.     {
  259.     AddRef();
  260.     *ppvObj = this;
  261.     return HXR_OK;
  262.     }
  263.     if (IsEqualIID(riid, IID_IHXTCPResponse))
  264.     {
  265.     AddRef();
  266.     *ppvObj = (IHXTCPResponse*)this;
  267.     return HXR_OK;
  268.     }
  269.     *ppvObj = NULL;
  270.     return HXR_NOINTERFACE;
  271. }
  272. /////////////////////////////////////////////////////////////////////////
  273. //  Method:
  274. // IUnknown::AddRef
  275. //  Purpose:
  276. // Everyone usually implements this the same... feel free to use
  277. // this implementation.
  278. //
  279. STDMETHODIMP_(UINT32) CHXNetCheck::AddRef()
  280. {
  281.     return InterlockedIncrement(&m_lRefCount);
  282. }
  283. /////////////////////////////////////////////////////////////////////////
  284. //  Method:
  285. // IUnknown::Release
  286. //  Purpose:
  287. // Everyone usually implements this the same... feel free to use
  288. // this implementation.
  289. //
  290. STDMETHODIMP_(UINT32) CHXNetCheck::Release()
  291. {
  292.     if (InterlockedDecrement(&m_lRefCount) > 0)
  293.     {
  294.         return m_lRefCount;
  295.     }
  296.     delete this;
  297.     return 0;
  298. }
  299. /*
  300.  * IHXTCPResponse methods
  301.  */
  302. /************************************************************************
  303.  * Method:
  304.  *     IHXTCPResponse::ConnectDone
  305.  * Purpose:
  306.  *     A Connect operation has been completed or an error has occurred.
  307.  */
  308. STDMETHODIMP CHXNetCheck::ConnectDone (HX_RESULT status)
  309. {
  310. HX_ASSERT(m_fConnected == FALSE); // We shouldn't be getting called if 
  311. // we aren't expecting it.
  312. if (status == HXR_OK)
  313. m_fConnected = TRUE;
  314. else
  315. m_fFailed = TRUE;
  316. return HXR_OK;
  317. }
  318. /************************************************************************
  319.  * Method:
  320.  *     IHXTCPResponse::ReadDone
  321.  * Purpose:
  322.  *     A Read operation has been completed or an error has occurred.
  323.  *     The data is returned in the IHXBuffer.
  324.  */
  325. STDMETHODIMP CHXNetCheck::ReadDone (HX_RESULT status,
  326. IHXBuffer* pBuffer)
  327. {
  328. HX_ASSERT(FALSE);
  329. return HXR_OK;
  330. }
  331. /************************************************************************
  332.  * Method:
  333.  *     IHXTCPResponse::WriteReady
  334.  * Purpose:
  335.  *     This is the response method for WantWrite.
  336.  *     If HX_RESULT is ok, then the TCP channel is ok to Write to.
  337.  */
  338. STDMETHODIMP CHXNetCheck::WriteReady (HX_RESULT status)
  339. {
  340. HX_ASSERT(FALSE);
  341. return HXR_OK;
  342. }
  343. /************************************************************************
  344.  * Method:
  345.  *     IHXTCPResponse::Closed
  346.  * Purpose:
  347.  *     This method is called to inform you that the TCP channel has
  348.  *     been closed by the peer or closed due to error.
  349.  */
  350. STDMETHODIMP CHXNetCheck::Closed(HX_RESULT status)
  351. {
  352. m_fConnected = FALSE;
  353. return HXR_OK;
  354. }
  355. //******************************************************************************
  356. //
  357. // Method: CHXNetCheck::Init
  358. //
  359. // Purpose: Sets up the CHXNetCheck object with a context.
  360. //
  361. //
  362. // Notes: n/a
  363. //
  364. //******************************************************************************
  365. HX_RESULT 
  366. CHXNetCheck::Init(IUnknown *pContext)
  367. {
  368. HX_RESULT result = HXR_OK;
  369. if (!pContext)
  370. return HXR_FAILED;
  371. m_pContext = pContext;
  372. m_pContext->AddRef();
  373. return result;
  374. }
  375. //******************************************************************************
  376. //
  377. // Method: CHXNetCheck::FInternetAvailable
  378. //
  379. // Purpose: The function checks if we can attempt a connection without 
  380. //     being prompted to connect.  
  381. // Returns true if we can, false otherwise.
  382. //
  383. // Notes: There is no single function for determining if a machine is 
  384. // connected to the internet, and it is impossible to reliably 
  385. // determine what is happening without side effects - such as 
  386. // automatic network connections taking place.
  387. //
  388. // MSDN article - 
  389. // "HOWTO: Detecting If you have a Connection to the Internet"
  390. //
  391. // "Usually the best way to determine if you have a connection 
  392. // to a particular computer is to attempt the connection. If the 
  393. // autodial feature of Windows is enabled then attempting the 
  394. // connection may cause the default Internet dialup connectoid 
  395. // to be opened, and you will be prompted with your credentials to connect.
  396. //
  397. // To avoid having the default Internet connectoid dialed, 
  398. // the InternetGetConnectedState function can be used to determine 
  399. // if there is a default Internet dialup connectoid configured and 
  400. // whether it is currently active or not. If there is a default 
  401. // Internet dialup connectoid configured and it is not currently 
  402. // active then InternetGetConnectedState will return FALSE. 
  403. // If InternetGetConnectedState returns TRUE then you can attempt 
  404. // to connect to the Internet resource without fear of being prompted 
  405. // to connect to another Internet Service Provider.
  406. //
  407. // You cannot rely solely on the fact that InternetGetConnectedState 
  408. // returning TRUE means that you have a valid active Internet 
  409. // connection. It is impossible for InternetGetConnectedState 
  410. // to determine if the entire connection to the Internet is 
  411. // functioning without sending a request to a server. This is why 
  412. // you need to send a request to determine if you are really connected 
  413. // or not. You can be assured however that if InternetGetConnectedState 
  414. // returns TRUE, that attempting your connection will NOT cause you 
  415. // to be prompted to connect to the default Internet Service Provider.
  416. //
  417. // Be aware that InternetGetConnectedState only reports the status 
  418. // of the default Internet connectoid on Internet Explorer 4.x. 
  419. // If a nondefault connectoid is connected, InternetGetConnectedState 
  420. // always returns FALSE (unless a LAN connection is used). 
  421. // With Internet Explorer 4.x configured to use a LAN connection, 
  422. // InternetGetConectedState always returns TRUE.
  423. //
  424. // Internet Explorer 5 behaves differently. If you are currently dialed 
  425. // into a different dial-up in Internet Explorer 5, InternetGetConnectedState 
  426. // reports dial-up connection status as long as any connectoid is dialed 
  427. // or an active LAN connection exists." 
  428. //
  429. //******************************************************************************
  430. BOOL 
  431. CHXNetCheck::FInternetAvailable(BOOL fPing, BOOL fProxy)
  432. {
  433. using namespace NetDetectLog; 
  434. NetDetectLogLib logLib;
  435. BOOL fRet = FALSE;
  436. UINT16 nPort = DEF_HTTP_PORT;
  437. #ifndef _WIN16
  438. WRITE_LOG0("FInternetAvailable fc entered...");
  439. HKEY hKey = 0 ;
  440. DWORD fAutoDial = 0 ;
  441. DWORD regType = 0 ;
  442. DWORD cbBuf;
  443. #if !defined(WIN32_PLATFORM_PSPC)
  444. // set the error mode since we'll do some DLL loading and we want the OS to be
  445. // quiet whhen we do this
  446. UINT oldErrorMode = ::SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  447. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  448. // XXXSO - agreed to use InternetGetConnectedState function only.
  449. // The rest of the code should be called when this function is not available.
  450. BOOL fConnected = FALSE;
  451. if( SUCCEEDED( WinInetGetConnected( fConnected )))
  452. {
  453.     fRet = fPing ? SmartPing() : fConnected;
  454.     goto Ret;
  455. }
  456. // XXXKM - agreed to remove proxy impact on net detect; instead let the following code determine
  457. // if we are connected or not - doing so will alleviate issues with proxy and dialup
  458. #if 0
  459. if (fProxy)
  460.     return TRUE;
  461. #endif
  462. WRITE_LOG0("Old algorithm entered ... ");
  463. WRITE_LOG0("Checking autodial flag ...");
  464. // XXXKM - check this early; if autodial is set, then return FALSE temporarily
  465. // check the autodial bit in the registry.
  466. cbBuf = sizeof(fAutoDial);
  467. if (RegOpenKey(HKEY_CURRENT_USER, OS_STRING("Software\Microsoft\Windows\CurrentVersion\Internet Settings"),
  468. &hKey) == ERROR_SUCCESS)
  469. {
  470.     OSVERSIONINFO osv;
  471.     memset(&osv, 0, sizeof(osv));
  472.     osv.dwOSVersionInfoSize = sizeof(osv);
  473.     GetVersionEx(&osv);
  474.     if (osv.dwPlatformId != VER_PLATFORM_WIN32_NT)
  475.     {
  476. WRITE_LOG0("Checking Win95/98 EnableAutodial flag in HKCU/Software/Microsoft/Windows"
  477.     "/Current Version/Internet Settings...");
  478. // check for the Win95/98 flag
  479. RegQueryValueEx(hKey, OS_STRING("EnableAutodial"), NULL, &regType, (BYTE *) &fAutoDial, &cbBuf);
  480.     }
  481.     else
  482.     {
  483. WRITE_LOG0("Checking for the RAS key on NT.");
  484. // XXXKM - check for the RAS key on NT; only way I could find around the assert/crash in rasapi32.dll
  485. // in situations where the dll existed, but ras was disabled/removed on the machine
  486. HKEY hRasKey = 0;
  487. if (::RegOpenKey(HKEY_LOCAL_MACHINE, OS_STRING("SOFTWARE\Microsoft\RAS"), &hRasKey) == ERROR_SUCCESS)
  488. {
  489.     // close the ras key
  490.     ::RegCloseKey(hRasKey);
  491.     // initialize to FALSE so this works the way it always has if something doesn't go right
  492.     fAutoDial = FALSE;
  493.     if (!m_hRasApiModule)
  494. m_hRasApiModule = ::LoadLibrary(OS_STRING("rasapi32.dll"));
  495.     if (m_hRasApiModule)
  496.     {
  497. WRITE_LOG0("rasapi32.dll loaded...");
  498. // try and get the API to enumerate RAS devices
  499. FPRASENUMDEVICES fpRasEnumDevices = (FPRASENUMDEVICES)GetProcAddress(m_hRasApiModule,
  500.     OS_STRING("RasEnumDevicesA"));
  501. if (!fpRasEnumDevices)
  502. {
  503.     fpRasEnumDevices  = (FPRASENUMDEVICES)GetProcAddress(m_hRasApiModule,
  504.     OS_STRING("RasEnumDevicesW"));
  505. }
  506. // we use this to see if there is a RAS enabled device on this system and also to 
  507. // check for initialization of the RAS subsystem since it will return an error if 
  508. // RAS is disabled or fails to initialize for whatever reason
  509. // XXXKM - this was added to prevent crashing on Win NT systems in the EnumEntries call
  510. // on machines where RAS has been disabled due to hardware profiles
  511. if (fpRasEnumDevices)
  512. {
  513.     WRITE_LOG0("Checking the RAS enabled devices...");
  514.     
  515.     RASDEVINFO rasDevInfo[1];
  516.     rasDevInfo[0].dwSize = sizeof(rasDevInfo);
  517.     DWORD bufferSize = sizeof(rasDevInfo);
  518.     DWORD numEntries = 0;
  519.     DWORD retVal = fpRasEnumDevices(rasDevInfo, &bufferSize, &numEntries);
  520.     // check if there was actually a RAS enabled device; this API will return an error
  521.     // if there are no RAS devices enabled, or if the RAS subsystem couldn't be initialized
  522.     if (retVal == ERROR_BUFFER_TOO_SMALL || retVal == ERROR_SUCCESS && numEntries == 1)
  523.     {
  524. // find the right entrypoint in the rasapi32.dll
  525. FPRASENUMENTRIES fpRasEnumEntries = (FPRASENUMENTRIES)GetProcAddress(m_hRasApiModule,
  526.     OS_STRING("RasEnumEntriesA"));
  527. if (!fpRasEnumEntries)
  528. {
  529.     fpRasEnumEntries = (FPRASENUMENTRIES)GetProcAddress(m_hRasApiModule,
  530.     OS_STRING("RasEnumEntriesW"));
  531. }
  532. // if we've got the RAS entries function, then call it
  533. if (fpRasEnumEntries)
  534. {
  535.     WRITE_LOG0("Calling RasEnumEntries function...");
  536.     
  537.     // setup the RAS entry structure for a single dialup item
  538.     RASENTRYNAME rasEntryName[1];
  539.     rasEntryName[0].dwSize = sizeof(rasEntryName);
  540.     bufferSize = sizeof(rasEntryName);
  541.     numEntries = 0;
  542.     // call the function to see how many dialup entries there are
  543.     retVal = fpRasEnumEntries(NULL, NULL, rasEntryName, &bufferSize, &numEntries);
  544.     // if our buffer is too small (i.e. there are more than one phone book entries)
  545.     // or we get a single item, then we have dialup, so set autodial to TRUE so 
  546.     // we'll tread lightly
  547.     if (retVal == ERROR_BUFFER_TOO_SMALL || (numEntries == 1 && retVal == ERROR_SUCCESS))
  548. fAutoDial = TRUE;
  549. }
  550.     }
  551. }
  552.     }
  553. }
  554.     }
  555.     // close the key when we're done with it
  556.     ::RegCloseKey(hKey);
  557. }
  558. WRITE_LOG1("Checked AUTODIAL flag = %d.", fAutoDial);
  559. // XXXKM - only check netcard active status if autodial is not on; if it's on, then
  560. // assume we are doing stuff through RAS connection only and ignore netcard for now;
  561. // only temporary
  562. if (!fAutoDial && FNetCardActive())
  563. {
  564.     WRITE_LOG0("FNetCardActive fc returned TRUE. goto exit ...");
  565.     fRet = TRUE;
  566.     goto Ret;
  567. }
  568. if (!fAutoDial) //  if it's not set, go ahead and try the network
  569. {
  570.     if (fPing)
  571. fRet = SmartPing();
  572.     else 
  573. fRet = TRUE;
  574.     goto Ret;
  575. }
  576. else // See if we have an active RAS connection
  577. {
  578.     WRITE_LOG0("Any active RAS connection?");
  579.     DWORD cRasConns = 0;
  580.     RASCONN rgRasConn[5];
  581.     DWORD cb = sizeof(rgRasConn);
  582.     
  583.     if (!m_hRasApiModule)
  584.     m_hRasApiModule= LoadLibrary(OS_STRING("rasapi32.dll"));
  585.     // add this code if this ever gets into win16; win16 will return nonnull on error from load library  #if _WIN16 if (m_handle < HINSTANCE_ERROR) m_handle = NULL; #endif
  586.     if (!m_hRasApiModule) // Dialup networking is not installed.
  587.     {
  588.     WRITE_LOG0("Dialup networking not installed ...");
  589.          if (fPing)
  590.      fRet = SmartPing();
  591.          else 
  592.      fRet = TRUE;
  593.     goto Ret;
  594.     }
  595.     if (!m_pRasEnumConnections)
  596.     m_pRasEnumConnections =
  597. (FPRASENUMCONNECTIONS)GetProcAddress(m_hRasApiModule,OS_STRING("RasEnumConnectionsA"));
  598.     if (!m_pRasEnumConnections) // Dialup networking is not installed.
  599.     {
  600.     WRITE_LOG0("Cannot load RasEnumConnections fc...");
  601.     if (fPing)
  602.      fRet = SmartPing();
  603.          else 
  604.      fRet = TRUE;
  605.     goto Ret;
  606.     }
  607.     rgRasConn[0].dwSize = sizeof(RASCONN);
  608.     m_pRasEnumConnections(rgRasConn, &cb, &cRasConns);
  609.     
  610.     WRITE_LOG1("RasEnumConnections found %d connections...", cRasConns);
  611.     if (cRasConns)
  612.     {
  613.          if (fPing)
  614.      fRet = SmartPing();
  615.          else 
  616.      fRet = TRUE;
  617.     goto Ret;
  618.     }
  619.     else
  620.     {
  621.     fRet = FALSE;
  622.     goto Ret;
  623.     }
  624. }
  625. Ret:
  626. // free up the library if loaded
  627. if (m_hRasApiModule)
  628. {
  629.     ::FreeLibrary(m_hRasApiModule);
  630.     m_hRasApiModule = NULL;
  631. }
  632. #if !defined(WIN32_PLATFORM_PSPC)
  633. // reset the error mode to the old value
  634. ::SetErrorMode(oldErrorMode);
  635. #endif /* !defined(WIN32_PLATFORM_PSPC) */
  636. WRITE_LOG1("FInternetAvailable terminated with %s value...", 
  637.     fRet ? "TRUE" : "FALSE");
  638. return(fRet);
  639. #else
  640. // Win16 section
  641. // =-=w16.0  for win16 always returns true, since there is no popup dialog in the way
  642. return (TRUE);
  643. #endif
  644. }
  645. //******************************************************************************
  646. //
  647. // Method: CHXNetCheck::Ping
  648. //
  649. // Purpose: Tests to see if we can open a TCP connection to the given hostname. 
  650. // if fAynchronous is true, we call back a response object provided by
  651. // the caller (through Init).  Otherwise we block.
  652. //
  653. //
  654. // Notes: n/a
  655. //
  656. //******************************************************************************
  657. BOOL CHXNetCheck::Ping(const char *szHostName, UINT16 nPort, BOOL fAsynchronous)
  658. {
  659. ULONG32 ulStartTime, ulCurrentTime, ulElapsedTime;
  660. BOOL fRet = FALSE;
  661. // If we don't have the network services interface yet than try and get it here
  662. if (m_pContext && !m_pRmaNetServices)
  663.     m_pContext->QueryInterface(IID_IHXNetworkServices, (void**)&m_pRmaNetServices);
  664. if (!m_pRmaTCPSocket && m_pRmaNetServices)
  665. m_pRmaNetServices->CreateTCPSocket(&m_pRmaTCPSocket);
  666. if (!m_pRmaTCPSocket)
  667. return FALSE;
  668. m_fFailed = m_fConnected = FALSE;
  669. m_pRmaTCPSocket->Init(this);
  670. m_pRmaTCPSocket->Connect(szHostName, nPort);
  671. ulElapsedTime = 0;
  672. // Get start time
  673. ulStartTime = HX_GET_TICKCOUNT();
  674. while (!m_fFailed && !m_fConnected && (ulElapsedTime < m_Timeout))
  675. {
  676. SleepWell(1000);
  677.     ulCurrentTime = HX_GET_TICKCOUNT();
  678. ulElapsedTime = CALCULATE_ELAPSED_TICKS(ulStartTime, ulCurrentTime);
  679. }
  680. fRet = m_fConnected;
  681. m_pRmaTCPSocket->Release();
  682. m_pRmaTCPSocket = NULL;
  683. return (fRet);
  684. }
  685. //******************************************************************************
  686. //
  687. // Method: CHXNetCheck::SleepWell
  688. //
  689. // Purpose: This method sleeps but continues to pump messages.  This allows us to 
  690. // block properly, even under such platforms as Win16.
  691. //
  692. //
  693. // Notes: n/a
  694. //
  695. //******************************************************************************
  696. void CHXNetCheck::SleepWell(ULONG32 ulInterval)
  697. {
  698. ULONG32 ulStartTime, ulCurrentTime;
  699. MSG     msg;
  700. char szClassName[16] = ""; /* Flawfinder: ignore */
  701. HWND hActiveWindow = NULL;
  702. // Get start time
  703. ulStartTime = HX_GET_TICKCOUNT();
  704. do
  705. {
  706.     // Keep pumping messages
  707.         if(PeekMessage(&msg, NULL,0,0,PM_REMOVE))
  708.     {
  709. if(msg.message == WM_QUIT) 
  710. {
  711.     PostQuitMessage(0);
  712.     break;
  713. }
  714. else
  715. {
  716.     // XXXJDL Since we are pumping messages through here while we block elsewhere in the calling code
  717.     // we need to get the free dialog navigation support from windows for modeless dialog boxes.  Modal dialog
  718.     // boxes are fine since they will not go through this message loop.  I have been using this method
  719.     // in the main player application and it seems to work ok.  Let me know if this causes pain for anyone.
  720.     // Basically if the active window is a dialog box class then we are assuming it is a modeless dialog box
  721.     // and calling IsDialogMessage with this handle.  If the active window is neither a dialog class or
  722.     // doesn't process the dialog message then we do the normal message dispatching
  723.     hActiveWindow = ::GetActiveWindow();
  724.     szClassName[0] = '';
  725.     ::GetClassName(hActiveWindow,
  726.    OS_STRING2(szClassName,sizeof(szClassName)),
  727.    sizeof(szClassName));
  728.     if (strcmp(szClassName,DIALOG_CLASS) || !IsDialogMessage(hActiveWindow, &msg))
  729.     {
  730. TranslateMessage(&msg);
  731.         DispatchMessage(&msg);
  732.     }
  733. }
  734.     }
  735.     // If we have waited ulInterval time then drop out
  736.     ulCurrentTime = HX_GET_TICKCOUNT();
  737. } while (CALCULATE_ELAPSED_TICKS(ulStartTime, ulCurrentTime) < ulInterval);
  738. }
  739. //******************************************************************************
  740. //
  741. // Method: CHXNetCheck::GetDNSAddress
  742. //
  743. // Purpose: Determines the IP address of the user's primary DNS server.
  744. //
  745. // Notes: Returns IP address in numeric form, in a CHXString. An empty
  746. // string is returned when the IP address cannot be determined.
  747. //
  748. //******************************************************************************
  749. void CHXNetCheck::GetDNSAddress(CHXString& strDNS)
  750. {
  751. #ifndef _WIN16
  752.     strDNS.Empty();
  753.     HKEY hKey = 0;
  754.     // Win95/98 likes it here
  755.     RegOpenKey(HKEY_LOCAL_MACHINE, "System\CurrentControlSet\Services\VxD\MSTCP\Parameters",
  756.     &hKey);
  757.     if (hKey != NULL)
  758.     {
  759.      GetNameServerKey(hKey, "NameServer", strDNS);
  760. if (strDNS.IsEmpty())
  761.      GetNameServerKey(hKey, "DhcpNameServer", strDNS);
  762. RegCloseKey(hKey);
  763.     }
  764.     // Some Win 95/98 machines put it here..
  765.     if (strDNS.IsEmpty())
  766.     {
  767.      RegOpenKey(HKEY_LOCAL_MACHINE, OS_STRING("System\CurrentControlSet\Services\VxD\MSTCP"),
  768.      &hKey);
  769.     
  770.      if (hKey != NULL)
  771.      {
  772.          GetNameServerKey(hKey, "NameServer", strDNS);
  773. if (strDNS.IsEmpty())
  774.      GetNameServerKey(hKey, "DhcpNameServer", strDNS);
  775. RegCloseKey(hKey);
  776.      }
  777.     }
  778.     // Try WinNT registry location.
  779.     if (strDNS.IsEmpty())
  780.     {
  781. RegOpenKey(HKEY_LOCAL_MACHINE, OS_STRING("System\CurrentControlSet\Services\Tcpip\Parameters"),
  782. &hKey);
  783.     
  784.      if (hKey != NULL)
  785.      {
  786.          GetNameServerKey(hKey, "NameServer", strDNS);
  787. if (strDNS.IsEmpty())
  788.      GetNameServerKey(hKey, "DhcpNameServer", strDNS);
  789. RegCloseKey(hKey);
  790.      }
  791.     }
  792.     // Another  WinNT registry location.
  793.     if (strDNS.IsEmpty())
  794.     {
  795. RegOpenKey(HKEY_LOCAL_MACHINE, OS_STRING("System\CurrentControlSet\Services\Tcpip"),
  796. &hKey);
  797.      if (hKey != NULL)
  798.      {
  799.          GetNameServerKey(hKey, "NameServer", strDNS);
  800. if (strDNS.IsEmpty())
  801.      GetNameServerKey(hKey, "DhcpNameServer", strDNS);
  802. RegCloseKey(hKey);
  803.      }
  804.     }
  805.     // I want to make sure this technique of getting DNS address works. Email bpitzel
  806.     // if it fails.
  807.     HX_ASSERT( !strDNS.IsEmpty() );
  808. #endif
  809. }
  810. #ifndef _WIN16
  811. void CHXNetCheck::GetNameServerKey(HKEY hKey, const char* szKeyName, CHXString& strDNS)
  812. {
  813.     char szDNS[MAX_PATH]; /* Flawfinder: ignore */
  814.     DWORD regType = 0 ;
  815.     DWORD cbuf;
  816.     cbuf = sizeof(szDNS);
  817.     if (ERROR_SUCCESS == RegQueryValueEx(hKey, OS_STRING(szKeyName), NULL, &regType, (BYTE *) szDNS, &cbuf))
  818.     {
  819. strDNS = szDNS;
  820. // Win95/98 separate multiple DNS addresses with ","
  821. // WinNT separate multiple DNS addresses with ","
  822. // We will grab the first IP address in the list
  823. strDNS = strDNS.SpanExcluding(" ,");
  824. strDNS.TrimLeft();
  825. strDNS.TrimRight();
  826.     }
  827. }
  828. #endif /* _WIN16 */
  829. BOOL 
  830. CHXNetCheck::SmartPing()
  831. {
  832.     using namespace NetDetectLog; 
  833.     WRITE_LOG0("SmartPing fc entered ...");
  834.     UINT16 nPort = DEF_HTTP_PORT;
  835.     // try to get DNS address to ping.
  836.     CHXString strPingAddr;
  837.     GetDNSAddress(strPingAddr);
  838.     nPort = DEF_DNS_PORT;
  839.     
  840.     // No DNS address? Default to a known web server.
  841.     // XXXBJP pinging video.real.com, used in Beta 1, should be
  842.     // changed for Beta 2!!
  843.     if (strPingAddr.IsEmpty())
  844.     {
  845.     strPingAddr = "209.66.98.23"; // video.real.com .. UGHHHH!!
  846.     nPort = DEF_HTTP_PORT;
  847.     }
  848.     return (Ping(strPingAddr, nPort, FALSE));
  849. }
  850. BOOL 
  851. CHXNetCheck::FNetCardActive()
  852. {
  853. #if defined(_WIN16) || defined(WIN32_PLATFORM_PSPC)
  854.     return TRUE;
  855. #else
  856. char szEnum_Name[ENUM_MAX][20] = {REGSTR_KEY_ROOTENUM, REGSTR_KEY_BIOSENUM, /* Flawfinder: ignore */
  857. REGSTR_KEY_PCIENUM, REGSTR_KEY_ISAENUM, REGSTR_KEY_EISAENUM,
  858. REGSTR_KEY_PCMCIAENUM};
  859.     using namespace NetDetectLog;
  860.     WRITE_LOG0("FNetCardActive entered ...");
  861.     char szClass[64]; /* Flawfinder: ignore */
  862.     ULONG ulType;
  863.     ULONG32 cbData;
  864.     CHXString sCurrentKey;
  865.     CHXString sCurrentFiles;
  866.     CHXString sDeviceID;
  867.     char szCurrentDeviceNode[STRINGSIZE]; /* Flawfinder: ignore */
  868.     char szCurrentDevice[STRINGSIZE]; /* Flawfinder: ignore */
  869.     char szSoftwareKey[STRINGSIZE]; /* Flawfinder: ignore */
  870.     BOOL bFoundKey = FALSE;
  871.     int i;
  872.     OSVERSIONINFO osv;
  873.     memset(&osv, 0, sizeof(osv));
  874.     osv.dwOSVersionInfoSize = sizeof(osv);
  875.     GetVersionEx(&osv);
  876.     if (osv.dwPlatformId == VER_PLATFORM_WIN32_NT)
  877.      return FALSE;
  878.     using namespace NetDetectLog; 
  879.     WRITE_LOG0("Win95/98 : Looking for devices of the Net class...");
  880.     // we want to look through the ENUMBIOS, ENUMISAPNP, and ENUMPCI
  881.     // trees for devices of the Net class.  For each display device
  882.     // we find we will ask the Device manager if it is active.
  883.     for (i = 0; i < ENUM_MAX && !bFoundKey; i++)
  884.     {
  885. HKEY hBusKey = 0;
  886. sCurrentKey = (CHXString)REGSTR_KEY_ENUM + BACKSLASH + szEnum_Name[i];
  887. // Start reading the devices
  888. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, OS_STRING(sCurrentKey), 0, KEY_READ, &hBusKey))
  889. {
  890.     cbData = sizeof(szCurrentDeviceNode);
  891.     ULONG32 dwDevNodeEnumIndex = 0;
  892.     HKEY hDeviceNodeKey;
  893.     // Enumerate all of the devices on the bus
  894.     while (!bFoundKey &&
  895. !RegEnumKeyEx(hBusKey, dwDevNodeEnumIndex, 
  896.       OS_STRING2(szCurrentDeviceNode, cbData), 
  897.       &cbData, NULL, NULL, NULL, NULL))
  898.     {
  899. // get the registry key for the current device node
  900. hDeviceNodeKey = 0;
  901. sCurrentKey = (CHXString)REGSTR_KEY_ENUM + BACKSLASH + szEnum_Name[i] + BACKSLASH + (CHXString)szCurrentDeviceNode;
  902. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, OS_STRING(sCurrentKey), 0, KEY_READ, &hDeviceNodeKey))
  903. {
  904.     cbData = sizeof(szCurrentDevice);
  905.     ULONG32 dwHWDeviceEnumIndex = 0;
  906.     HKEY hHWDeviceKey;
  907.     // enumerate all of the hardware devices in this Device Node
  908.     while (!bFoundKey &&
  909. !RegEnumKeyEx(hDeviceNodeKey, dwHWDeviceEnumIndex, 
  910.       OS_STRING2(szCurrentDevice, cbData),
  911.       &cbData, NULL, NULL, NULL, NULL))
  912.     {
  913. // get the registry key for the current hardware device
  914. int nBaseKeyLength = sCurrentKey.GetLength();
  915. hHWDeviceKey = 0;
  916. sCurrentKey += BACKSLASH + (CHXString) szCurrentDevice;
  917. if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, OS_STRING(sCurrentKey), 0, KEY_READ, &hHWDeviceKey))
  918. {
  919.     // Ask if this device is a "Net" device by checking it's class
  920.     cbData = sizeof(szClass);
  921.     szClass[0] = 0;
  922.     if (!RegQueryValueEx(hHWDeviceKey, OS_STRING("Class"), 0, &ulType, (LPBYTE) szClass, &cbData)
  923. && !stricmp(szClass, "Net"))
  924.     {
  925. // if it is a display device then we want to find out if it is
  926. // the active device for this class.
  927. cbData = sizeof(szSoftwareKey);
  928. sDeviceID = (CHXString) szEnum_Name[i] + BACKSLASH + (CHXString)szCurrentDeviceNode
  929.     + BACKSLASH + (CHXString) szCurrentDevice;
  930. // get the registry key name for the software key for the device, if it is not
  931. // null and this is the active device then we are done.
  932. if (!RegQueryValueEx(hHWDeviceKey, OS_STRING("Driver"), 0, &ulType, (LPBYTE) szSoftwareKey, &cbData)
  933.     && szSoftwareKey[0] != '0'
  934.     && DevNodeIsActive((sDeviceID))) // Call Config Manager in 16-bit code
  935. {
  936.     bFoundKey = TRUE;
  937.     WRITE_LOG1("Found active node %s...", (char const*) sDeviceID);
  938. }
  939.     }
  940. }
  941. // reset the key to the base for the next time through the loop
  942. sCurrentKey = sCurrentKey.Left(nBaseKeyLength);
  943. if (hHWDeviceKey)
  944. {
  945.     RegCloseKey(hHWDeviceKey);
  946.     hHWDeviceKey = 0;
  947. }
  948. // move to next device key
  949. dwHWDeviceEnumIndex++;
  950. // reset size to szCurrentDevice size
  951. cbData = sizeof(szCurrentDevice);
  952.     }
  953. }
  954. if (hDeviceNodeKey)
  955. {
  956.     RegCloseKey(hDeviceNodeKey);
  957.     hDeviceNodeKey = 0;
  958. }
  959. // move to the next device node
  960. dwDevNodeEnumIndex++;
  961. // reset the size to szCurrentDeviceNode size
  962. cbData = sizeof(szCurrentDeviceNode);
  963.     }
  964. }
  965. if (hBusKey)
  966. {
  967.     RegCloseKey(hBusKey);
  968.     hBusKey = 0;
  969. }
  970.     }
  971.     return bFoundKey;
  972. #endif
  973. }
  974. BOOL
  975. CHXNetCheck::DevNodeIsActive(const char *szDeviceID)
  976. {
  977. #ifdef _WIN16
  978.     HX_ASSERT (FALSE); // should never get called in win16
  979.     return TRUE;
  980. #else
  981.     HINSTANCE hDevNodeInst;
  982.     DWORD dwStatus;
  983.     DWORD dwProblemNumber;
  984.     DWORD cr;
  985.     DWORD (WINAPI * pGetDevNodeStatus32Call) (const char *, LPDWORD, LPDWORD);
  986.     // 10 is a magic number for the configuration manager api
  987.     // that eventually gets called in the 16 bit dll.
  988.     dwStatus = dwProblemNumber = cr = 10;
  989.     pGetDevNodeStatus32Call = 0;
  990.     hDevNodeInst = LoadLibrary(OS_STRING(_32BIT_DLLNAME));
  991.     // add this code if this ever gets into win16; win16 will return nonnull on error from load library  #if _WIN16 if (m_handle < HINSTANCE_ERROR) m_handle = NULL; #endif
  992.     if (hDevNodeInst)
  993.     {
  994. (FARPROC &) pGetDevNodeStatus32Call = GetProcAddress(hDevNodeInst, OS_STRING("GetDevNodeStatus32Call"));
  995. if (pGetDevNodeStatus32Call)
  996. {
  997.     cr = pGetDevNodeStatus32Call(szDeviceID, &dwStatus, &dwProblemNumber);
  998. }
  999. FreeLibrary(hDevNodeInst);
  1000.     }
  1001.     if (cr == 0
  1002. && dwProblemNumber == 0)
  1003. return TRUE;
  1004.     else
  1005. return FALSE;
  1006. #endif
  1007. }
  1008. HX_RESULT CHXNetCheck::WinInetGetConnected(BOOL& bConnected)
  1009. {
  1010.     using namespace NetDetectLog; 
  1011.     WRITE_LOG0("WinInetGetConnected fc entered...");
  1012.     HINSTANCE hWinInet;
  1013.     BOOL (WINAPI * pInternetGetConnectedState) (LPDWORD lpdwFlags, DWORD dwReserved);
  1014.     hWinInet= LoadLibrary(OS_STRING(WININET_DLL));
  1015.     if (!hWinInet)
  1016.     {
  1017. WRITE_LOG0("WinInet not present ...");
  1018.      return HXR_FAIL;
  1019.     }
  1020.     (FARPROC &) pInternetGetConnectedState = GetProcAddress(hWinInet, OS_STRING("InternetGetConnectedState"));
  1021.     if (!pInternetGetConnectedState )
  1022.     {
  1023. WRITE_LOG0("InternetGetConnectedState fc cannot be loaded ...");
  1024.     
  1025. FreeLibrary(hWinInet);
  1026.      return HXR_FAIL;
  1027.     }
  1028.     DWORD dwFlags;
  1029.     bConnected = pInternetGetConnectedState(&dwFlags, 0);
  1030.     FreeLibrary(hWinInet);
  1031.     
  1032.     WRITE_LOG_WINET(bConnected, dwFlags);
  1033.     
  1034.     return HXR_OK;
  1035. }