Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1071 lines
33 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 2000
  6. //
  7. // File: wuaueng.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. //Handle for Download Events
  13. ENGINE_EVENTS EngineEvents;
  14. AUCatalog *gpAUcatalog;
  15. inline BOOL FServiceDisabled(void)
  16. {
  17. return (AUSTATE_DISABLED == gpState->GetState());
  18. }
  19. //cancel download if any
  20. void CancelDownload(void)
  21. {
  22. if (NULL != gpAUcatalog && gpAUcatalog->m_audownloader.getID() != GUID_NULL)
  23. {
  24. gpAUcatalog->m_audownloader.DrizzleOperation(DRIZZLEOPS_CANCEL);
  25. }
  26. gpState->SetDisconnected(FALSE); //In case the disabled happened during TRANSIENT_ERROR we don't want to keep the flag set to disconnected
  27. }
  28. DWORD RandomWaitTimeBeforeDetect()
  29. {
  30. return (ULONGLONG)AU_TWENTY_TWO_HOURS - ((ULONGLONG) AU_TWENTY_TWO_HOURS * rand() * AU_RANDOMIZATION_WINDOW ) /( (ULONGLONG) RAND_MAX * 100); //precision to hundredth
  31. }
  32. //void setAuStateDisconnected(BOOL fDisconnected);
  33. BOOL FDisabledDuringDownload(void)
  34. {
  35. BOOL fRet = FALSE;
  36. if (FServiceDisabled())
  37. {
  38. DEBUGMSG("WUAUENG Detected Disabled State during download");
  39. CancelDownload();
  40. fRet = TRUE;
  41. }
  42. return fRet;
  43. }
  44. #define ISERVICE_FINISHED 0
  45. #define ISERVICE_DISABLED 1
  46. #define WAIT_SERVICE_FINISHED 0
  47. #define WAIT_SERVICE_DISABLED 1
  48. #define WAIT_NOT_NEEDED 2
  49. #define WAIT_CONNECTION_FOUND 3
  50. #define WAIT_DONE 4
  51. //fixcode: don't always need to persist in registry
  52. DWORD MWFMO(DWORD dwTimeout, DWORD dwMinTimeout = 1)
  53. {
  54. HANDLE hEvents[2];
  55. hEvents[ISERVICE_FINISHED] = ghServiceFinished;
  56. hEvents[ISERVICE_DISABLED] = ghServiceDisabled;
  57. if (FAILED(setLastWaitTimeout(dwTimeout)))
  58. {
  59. DEBUGMSG("WUAUENG setLastWaitTimeout failed with error %d", GetLastError());
  60. }
  61. return MsgWaitForMultipleObjectsEx(2, hEvents, dwTimeToWait(dwTimeout, dwMinTimeout), QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
  62. }
  63. DWORD _MyMWFMO(DWORD dwTimeout, DWORD dwMinTimeout = 1);
  64. //dwTimeout in seconds
  65. #define MyMWFMO(dwTimeout) _MyMWFMO(dwTimeout)
  66. // wait until a timeout happens or we get a service finished event
  67. DWORD _MyMWFMO(DWORD dwTimeout, DWORD dwMinTimeout)
  68. {
  69. DWORD dwRet = WAIT_TIMEOUT;
  70. while (1)
  71. {
  72. dwRet = MWFMO(dwTimeout, dwMinTimeout);
  73. if (WAIT_TIMEOUT == dwRet)
  74. {
  75. DEBUGMSG("WUAUENG MWFMO timed out");
  76. // dwRet = WAIT_TIMEOUT;
  77. goto Done;
  78. }
  79. else if (WAIT_OBJECT_0 + ISERVICE_FINISHED == dwRet)
  80. {
  81. DEBUGMSG("WUAUENG MWFMO Service Finished");
  82. dwRet = WAIT_SERVICE_FINISHED;
  83. goto Done;
  84. }
  85. else if (WAIT_OBJECT_0 + ISERVICE_DISABLED == dwRet)
  86. {
  87. DEBUGMSG("WUAUENG MWFMO Engine Changed to Disabled\n");
  88. dwRet = WAIT_SERVICE_DISABLED;
  89. goto Done;
  90. }
  91. else
  92. {
  93. //we expect possible meaningful message here
  94. //leave it untouch in the queue
  95. MSG msg;
  96. if (0 == PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  97. {
  98. DEBUGMSG("MyMWFMO got no message. Possible error!");
  99. continue; //no message got
  100. }
  101. if ( ((AUMSG_ENG_START <= msg.message) && (AUMSG_ENG_END >= msg.message))
  102. || (WM_QUIT == msg.message))
  103. {
  104. DEBUGMSG("MyMWFMO got user msg %#lx, repost it to the queue", msg.message);
  105. PostThreadMessage(gdwWorkerThreadId, msg.message, msg.wParam, msg.lParam);
  106. dwRet = msg.message;
  107. goto Done;
  108. }
  109. else
  110. {
  111. DEBUGMSG("WUAUENG MWFMO got system message %#lx", msg.message);
  112. TranslateMessage( &msg );
  113. DispatchMessage( &msg );
  114. }
  115. }
  116. }
  117. Done:
  118. if (WAIT_SERVICE_FINISHED != dwRet)
  119. {
  120. removeLastWaitKey();
  121. }
  122. return dwRet;
  123. }
  124. //** WaitForConnection() will wait for connection or
  125. //** will bail out if Service Finished or service disabled or getting a msg if fIgnoreNonDetectMsg is FALSE
  126. DWORD WaitForConnection(BOOL fIngoreNonDetectMsg = FALSE)
  127. {
  128. static BOOL s_fWasConnected = FALSE;
  129. DWORD dwRet;
  130. DEBUGMSG("WUAUENG : Polling for connection");
  131. do
  132. {
  133. do
  134. {
  135. if (AUSTATE_DETECT_PENDING == gpState->GetState() &&
  136. gpState->IsUnableToConnect())
  137. {
  138. CAUEventLog aueventlog(g_hInstance);
  139. aueventlog.LogEvent(
  140. EVENTLOG_WARNING_TYPE,
  141. IDS_MSG_Download,
  142. IDS_MSG_UnableToConnect);
  143. gpState->SetDetectionStartTime(TRUE);
  144. }
  145. if (IsConnected(gpState->GetIdentServerURL(), !gpState->fInCorpWU()))
  146. {
  147. break;
  148. }
  149. dwRet = MyMWFMO(AU_TEN_MINS);
  150. if (WAIT_TIMEOUT != dwRet)
  151. {
  152. if (!fIngoreNonDetectMsg ||!IsValidAUMsg(dwRet) || AUMSG_DETECT == dwRet )
  153. {
  154. goto Done;
  155. }
  156. }
  157. s_fWasConnected = FALSE;
  158. }
  159. while (1);
  160. if (!s_fWasConnected)
  161. {
  162. DEBUGMSG("Found Connection");
  163. if (AUSTATE_DOWNLOAD_PENDING != gpState->GetState())
  164. {
  165. BOOL fWait = TRUE;
  166. #ifdef DBG
  167. //wait 5 mins by Default if 'ConnectWait' regvalue does not exist
  168. // or is set to 1
  169. DWORD dwConnectWait;
  170. if (SUCCEEDED(GetRegDWordValue(REG_AUCONNECTWAIT, &dwConnectWait))
  171. && 0 == dwConnectWait)
  172. {
  173. fWait = FALSE;
  174. }
  175. #endif
  176. if (fWait)
  177. {
  178. DEBUGMSG("Wait for 5 mins ");
  179. dwRet = MyMWFMO(AU_FIVE_MINS);
  180. if (WAIT_TIMEOUT != dwRet)
  181. {
  182. if (!fIngoreNonDetectMsg || !IsValidAUMsg(dwRet) || AUMSG_DETECT == dwRet)
  183. {
  184. goto Done;
  185. }
  186. }
  187. }
  188. if (!IsConnected(gpState->GetIdentServerURL(), !gpState->fInCorpWU()))
  189. {
  190. continue;
  191. }
  192. }
  193. s_fWasConnected = TRUE;
  194. }
  195. break;
  196. }
  197. while (1);
  198. DEBUGMSG("WUAUENG : Connection found. Polling end");
  199. dwRet = WAIT_CONNECTION_FOUND;
  200. Done:
  201. return dwRet;
  202. }
  203. HRESULT PauseDownload(BOOL fPause)
  204. {
  205. HRESULT hrRet = E_FAIL;
  206. if (NULL != gpAUcatalog)
  207. {
  208. hrRet = gpAUcatalog->m_audownloader.DrizzleOperation(fPause? DRIZZLEOPS_PAUSE: DRIZZLEOPS_RESUME);
  209. }
  210. DEBUGMSG("PauseDownload return %#lx", hrRet);
  211. return hrRet;
  212. }
  213. HRESULT GetEvtHandles(AUEVTHANDLES *pAuEvtHandles)
  214. {
  215. HRESULT hr = E_FAIL;
  216. HANDLE hSourceProcess = NULL;
  217. //#define IEVT_ENGINESTATE 0
  218. #define IEVT_NOTIFYCLIENT 0
  219. struct
  220. {
  221. HANDLE hSource;
  222. HANDLE hTarget;
  223. } rhandles [] = {/*{ghEngineState,0},*/{ghNotifyClient,0}};
  224. if (NULL == ghClientHandles.hClientProcess())
  225. {
  226. goto Done;
  227. }
  228. hSourceProcess = GetCurrentProcess();
  229. for ( int i = 0; i < (ARRAYSIZE(rhandles)); i++)
  230. {
  231. if (!DuplicateHandle(
  232. hSourceProcess, // handle to source process
  233. rhandles[i].hSource, // handle to duplicate
  234. ghClientHandles.hClientProcess(), // handle to target process
  235. &rhandles[i].hTarget, // duplicate handle
  236. 0, // requested access
  237. FALSE, // handle inheritance option
  238. DUPLICATE_SAME_ACCESS // optional actions
  239. ))
  240. {
  241. DEBUGMSG("WUAUENG DuplicateHandle for rhandles[%d] failed with %#lx", i, GetLastError());
  242. //should not close target handle cuz it is in target process
  243. goto Done;
  244. }
  245. }
  246. #ifdef _WIN64
  247. pAuEvtHandles->ulNotifyClient = (LONG64) rhandles[IEVT_NOTIFYCLIENT].hTarget;
  248. #else
  249. pAuEvtHandles->ulNotifyClient = (LONG) rhandles[IEVT_NOTIFYCLIENT].hTarget;
  250. #endif
  251. hr = S_OK;
  252. Done:
  253. return hr;
  254. }
  255. DWORD AvailableSessions(void)
  256. {
  257. DWORD dwRet = 0;
  258. //
  259. // For win2K, because we're not deleting sessions as soon as we receive
  260. // logoff notifications, the array gAdminSesssion might be out-of-date
  261. // in a given point in time. We need to validate the array before
  262. // saying to client things about it.
  263. // Remove any old sessions from our array if there's any
  264. //
  265. if (IsWin2K())
  266. {
  267. DEBUGMSG("WUAUENG Client is querying the number of sessions available; forcing rebuilt of the session cache (win2k)");
  268. gAdminSessions.ValidateCachedSessions();
  269. }
  270. for (int iSession = 0; iSession < gAdminSessions.CSessions(); iSession++)
  271. {
  272. DWORD dwAdminSession;
  273. if (gAdminSessions.m_FGetNextSession(&dwAdminSession) && FSessionActive(dwAdminSession))
  274. {
  275. dwRet ++;
  276. }
  277. }
  278. // DEBUGMSG("AvailableSessions return %d", dwRet);
  279. return dwRet;
  280. }
  281. HRESULT HrCreateNewCatalog()
  282. {
  283. HRESULT hr = E_FAIL;
  284. SafeDeleteNULL(gpAUcatalog);
  285. gpAUcatalog = new AUCatalog;
  286. if (NULL == gpAUcatalog)
  287. {
  288. goto Done;
  289. }
  290. if (FAILED(hr = gpAUcatalog->Init()))
  291. {
  292. SafeDeleteNULL(gpAUcatalog);
  293. }
  294. Done:
  295. return hr;
  296. }
  297. /* This function will return only in case of selfupdate. Normally it will keep on looping
  298. * sleeping on various timeouts when necessary
  299. */
  300. DWORD CompleteLastMyMWFMO(void)
  301. {
  302. DWORD dwRet = WAIT_NOT_NEEDED;
  303. DWORD dwTimeout;
  304. HRESULT hr;
  305. hr = getLastWaitTimeout(&dwTimeout);
  306. MyMWFMO(0); //call user api to create the thread queue
  307. SetEvent(ghWorkerThreadMsgQueueCreation);
  308. if (FAILED(hr))
  309. {
  310. DEBUGMSG("WUAUENG no need to complete last wait");
  311. goto Done;
  312. }
  313. DEBUGMSG("WUAUENG is going to complete last wait %d ", dwTimeout);
  314. dwRet = MyMWFMO(dwTimeout);
  315. Done:
  316. return dwRet;
  317. }
  318. //////////////////////////////////////////////////////////////////////////////////////////////////
  319. // return S_FALSE if selfupdate happens
  320. // return S_OK otherwise
  321. // pdwRet points to return code: service finish, service disabled, selfupdate done, or detect msg
  322. HRESULT PerformSelfUpdate(DWORD *pdwRet)
  323. {
  324. HRESULT hr= S_OK;
  325. DEBUGMSG("Doing selfupdate");
  326. DEBUGMSG("Selfupdate waiting for connection");
  327. DEBUGMSG("Wait for internet connection...");
  328. while ( WAIT_CONNECTION_FOUND == (*pdwRet = WaitForConnection(TRUE))
  329. && ((hr = SelfUpdate()) != S_OK) )
  330. {
  331. switch (hr)
  332. {
  333. case S_FALSE: //selfupdate happens
  334. DEBUGMSG("Telling wuauserv.dll to reload wuaueng.dll");
  335. gPingStatus.PingSelfUpdate(TRUE, URLLOGSTATUS_Pending, 0);
  336. *pdwRet = WAIT_DONE;
  337. goto Done;
  338. default:
  339. DEBUGMSG("Error during selfupdate (%#lx), timeout=%d secs", hr, dwTimeToWait(AU_ONE_DAY));
  340. gPingStatus.PingSelfUpdate(TRUE, URLLOGSTATUS_Failed, hr);
  341. *pdwRet = MyMWFMO(AU_ONE_DAY);
  342. if (WAIT_TIMEOUT != *pdwRet)
  343. {
  344. DEBUGMSG("WUAUENG need to abort wait during SelfUpdate");
  345. goto Done;
  346. }
  347. break;
  348. }
  349. }
  350. if (WAIT_CONNECTION_FOUND == *pdwRet)
  351. {
  352. *pdwRet = WAIT_DONE;
  353. }
  354. DEBUGMSG("Finished self update cycle");
  355. Done:
  356. return hr;
  357. }
  358. void ResumeDownloadIfNeccesary(void)
  359. {
  360. if (FDownloadIsPaused())
  361. {
  362. PauseDownload(FALSE);
  363. DEBUGMSG("WUAUENG Resuming download job");
  364. }
  365. }
  366. void PingSuccessfulDownloads(void)
  367. {
  368. UINT uItemCount = gpAUcatalog->m_ItemList.Count();
  369. for (UINT i = 0; i < uItemCount; i++)
  370. {
  371. AUCatalogItem &item = gpAUcatalog->m_ItemList[i];
  372. if (item.fSelected())
  373. {
  374. BSTR bstrItemId = item.bstrID();
  375. if (NULL != bstrItemId)
  376. {
  377. USES_IU_CONVERSION;
  378. gPingStatus.PingDownload(
  379. TRUE,
  380. URLLOGSTATUS_Success,
  381. 0,
  382. W2T(bstrItemId));
  383. }
  384. #ifdef DBG
  385. else
  386. {
  387. DEBUGMSG("WUAUENG title for item %d is NULL!", i);
  388. }
  389. #endif
  390. }
  391. }
  392. }
  393. void ResetState(void)
  394. {
  395. gpState->SetState(AUSTATE_DETECT_PENDING);
  396. PostThreadMessage(gdwWorkerThreadId, AUMSG_DETECT, 0, 0);
  397. }
  398. void ResetState(BOOL *pfWaitB4Detect, DWORD *pdwWaitB4Detect, BOOL fError)
  399. {
  400. AUASSERT(NULL != pfWaitB4Detect);
  401. AUASSERT(NULL != pdwWaitB4Detect);
  402. *pfWaitB4Detect = TRUE;
  403. *pdwWaitB4Detect = fError ? AU_FIVE_HOURS : RandomWaitTimeBeforeDetect();
  404. ResetState();
  405. }
  406. HRESULT UpdateProc(WORKER_THREAD_INIT_DATA & initData)
  407. {
  408. HRESULT hr = S_OK;
  409. DWORD dwRet;
  410. DWORD dwLastWait ;
  411. BOOL fReloadAfterSelfUpdate = FALSE;
  412. MSG msg;
  413. UINT uFirstMsg;
  414. static BOOL s_fWaitBeforeDetect;
  415. static DWORD s_dwWaitB4Detect;
  416. uFirstMsg = initData.uFirstMsg;
  417. s_fWaitBeforeDetect = initData.fWaitB4Detect;
  418. s_dwWaitB4Detect = initData.dwWaitB4Detect;
  419. dwLastWait = CompleteLastMyMWFMO();
  420. switch (dwLastWait)
  421. {
  422. case WAIT_SERVICE_FINISHED:
  423. goto Done;
  424. case WAIT_TIMEOUT:
  425. case WAIT_NOT_NEEDED:
  426. if (IsValidAUMsg(uFirstMsg))
  427. {
  428. DEBUGMSG("Update post first msg %#x", uFirstMsg);
  429. PostThreadMessage(gdwWorkerThreadId, uFirstMsg, 0, 0);
  430. }
  431. break;
  432. case WAIT_SERVICE_DISABLED:
  433. default: //msg got
  434. break;
  435. }
  436. DWORD dwRet2 ;
  437. while(WAIT_OBJECT_0 + 1 == (dwRet2 = MsgWaitForMultipleObjectsEx(1, &ghServiceFinished, INFINITE, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE )))
  438. {
  439. if (0 == PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  440. {
  441. DEBUGMSG("WUAUENG no message to retrieve. Possible error!");
  442. continue;
  443. }
  444. if (WM_QUIT == msg.message)
  445. {
  446. break;
  447. }
  448. switch(msg.message)
  449. {
  450. case AUMSG_INIT:
  451. {
  452. //we wait for the first connection so that we don't prompt users who never
  453. //make a connection to the internet. no need to have them config AU if they have no
  454. //intention of using the internet
  455. dwRet = WaitForConnection();
  456. switch (dwRet)
  457. {
  458. case WAIT_SERVICE_FINISHED:
  459. DEBUGMSG("WUAUENG detected that Service finished during WaitForConnection in AUSTATE_OUTOFBOX");
  460. goto Done;
  461. case WAIT_CONNECTION_FOUND:
  462. break;
  463. case WAIT_SERVICE_DISABLED:
  464. default:
  465. continue;
  466. }
  467. dwRet = dwLastWait;
  468. if (WAIT_NOT_NEEDED == dwLastWait)
  469. {
  470. //there was no previous wait for 24 hours
  471. DEBUGMSG("WUAUENG Out of box, waiting 24 hours (%d secs)", dwSecsToWait(AU_ONE_DAY));
  472. dwRet = MyMWFMO(AU_ONE_DAY);
  473. }
  474. switch (dwRet)
  475. {
  476. case WAIT_TIMEOUT:
  477. {
  478. #if 0 //commented out for bug 493789
  479. DWORD dwRet4;
  480. hr = PerformSelfUpdate(&dwRet4);
  481. if (WAIT_SERVICE_FINISHED == dwRet4)
  482. {
  483. setLastWaitTimeout(0); //no wait next time
  484. goto Done;
  485. }
  486. #endif
  487. gpState->SetState(AUSTATE_NOT_CONFIGURED);
  488. DEBUGMSG("WUAUENG waiting for user to configure AU");
  489. #if 0 //commented out for bug 493789
  490. if (S_FALSE == hr)
  491. {
  492. fReloadAfterSelfUpdate = TRUE;
  493. goto Done;
  494. }
  495. #endif
  496. break;
  497. }
  498. case WAIT_SERVICE_FINISHED:
  499. goto Done;
  500. case WAIT_SERVICE_DISABLED:
  501. default:
  502. continue;
  503. }
  504. break;
  505. }
  506. case AUMSG_EULA_ACCEPTED:
  507. DEBUGMSG("WUAUENG Msg:Eula accepted, state -> Detect Pending");
  508. ResetState();
  509. break;
  510. case AUMSG_DETECT:
  511. if (s_fWaitBeforeDetect)
  512. {
  513. s_fWaitBeforeDetect = FALSE;
  514. DEBUGMSG("WUAUENG Wait %d secs before detection", s_dwWaitB4Detect);
  515. DWORD dwRet3 = MyMWFMO(s_dwWaitB4Detect);
  516. s_dwWaitB4Detect = 0;
  517. if (WAIT_SERVICE_DISABLED == dwRet3)
  518. {
  519. break;
  520. }
  521. if (WAIT_SERVICE_FINISHED == dwRet3)
  522. {
  523. goto Done;
  524. }
  525. }
  526. DEBUGMSG("WUAUENG Msg:Detect");
  527. DEBUGMSG("--------------------------------------------------------");
  528. DEBUGMSG("Set new detection start time");
  529. gpState->SetDetectionStartTime(FALSE);
  530. DEBUGMSG("Read in au option");
  531. if (FAILED(hr = gpState->HrInit()))
  532. {
  533. DEBUGMSG("AU state object fail to init with error %#lx", hr);
  534. goto Done;
  535. }
  536. CancelDownload();
  537. if (FAILED(HrCreateNewCatalog()))
  538. { //fixcode: what is the expected behavior here?
  539. return E_FAIL;
  540. }
  541. hr = PerformSelfUpdate(&dwRet);
  542. if (S_FALSE == hr)
  543. {
  544. fReloadAfterSelfUpdate = TRUE;
  545. goto Done;
  546. }
  547. switch (dwRet)
  548. {
  549. case WAIT_SERVICE_FINISHED:
  550. goto Done;
  551. case WAIT_SERVICE_DISABLED:
  552. gpState->RemoveDetectionStartTime();
  553. continue;
  554. case WAIT_DONE:
  555. break;
  556. default: //detect msg got
  557. DEBUGMSG("Detect msg got while detecting");
  558. continue;
  559. }
  560. hr = gpAUcatalog->DetectItems();
  561. if (FServiceDisabled())
  562. {
  563. gpState->RemoveDetectionStartTime();
  564. break;
  565. }
  566. if (SUCCEEDED(hr))
  567. {
  568. //Restart counting period w/ no connection at the beginning of the next cycle.
  569. gpState->RemoveDetectionStartTime();
  570. }
  571. if (S_OK == hr)
  572. {
  573. DEBUGMSG("WUAUENG Catalog built");
  574. gpState->SetState(AUSTATE_DETECT_COMPLETE);
  575. DEBUGMSG("WUAUENG State->Detect complete");
  576. }
  577. else if (S_FALSE == hr)
  578. {
  579. DEBUGMSG("WUAUENG No items in catalog, sleeping a while before next detection");
  580. ResetState(&s_fWaitBeforeDetect,&s_dwWaitB4Detect, FALSE); //wait normal interval time
  581. }
  582. else
  583. {
  584. DEBUGMSG("WUAUENG Couldn't build catalog");
  585. ResetState(&s_fWaitBeforeDetect, &s_dwWaitB4Detect, TRUE); //wait shorter time cuz of error
  586. }
  587. break;
  588. case AUMSG_DOWNLOAD:
  589. {
  590. DEBUGMSG("WUAUENG Msg:Download");
  591. gfDownloadStarted = FALSE;
  592. gpState->SetState(AUSTATE_DOWNLOAD_PENDING);
  593. dwRet =WaitForConnection(TRUE);
  594. switch (dwRet)
  595. {
  596. case WAIT_SERVICE_FINISHED:
  597. DEBUGMSG("WUAUENG detected that Service finished during WaitForConnection in AUMSG_DOWNLOAD");
  598. goto Done;
  599. case WAIT_CONNECTION_FOUND:
  600. break;
  601. case WAIT_SERVICE_DISABLED:
  602. default:
  603. continue;
  604. }
  605. if (S_OK != gpAUcatalog->ValidateItems(TRUE))
  606. {
  607. DEBUGMSG("WUAUENG Catalog validation failed or no items, State->Detect Pending");
  608. ResetState();
  609. break;
  610. }
  611. DEBUGMSG("WUAUENG catalog:validateCatalog finished");
  612. EngineEvents.CreateEvents();
  613. // queue up items for download
  614. if (S_OK != (hr = gpAUcatalog->DownloadItems()))
  615. {
  616. if (S_FALSE == hr)
  617. {
  618. DEBUGMSG("WUAUENG Catalog download items skipped because no items were selected");
  619. }
  620. else
  621. {
  622. DEBUGMSG("WUAUENG Catalog download items failed");
  623. }
  624. EngineEvents.CloseEvents();
  625. ResetState(&s_fWaitBeforeDetect,&s_dwWaitB4Detect, FALSE);
  626. break;
  627. }
  628. gfDownloadStarted = TRUE;
  629. ghClientHandles.ClientStateChange(); //notify client again for status change
  630. do
  631. {
  632. dwRet = MsgWaitForMultipleObjectsEx( EngineEvents.cEvents(), EngineEvents.grEventHandles(), INFINITE, QS_POSTMESSAGE, MWMO_INPUTAVAILABLE );
  633. if (WAIT_OBJECT_0 + IDOWNLOAD_COMPLETE_EVT == dwRet) //Download finished
  634. {
  635. if (FDisabledDuringDownload())
  636. {
  637. goto CloseHandle;
  638. }
  639. DEBUGMSG("WUAUENG file download done");
  640. ghClientHandles.ClientRemoveTrayIcon();
  641. //Validate downloaded cabs before continuing
  642. AUASSERT(gpAUcatalog);
  643. BSTR bstrErrorItemId = NULL; //should not be freed
  644. if(FAILED(hr = gpAUcatalog->ValidateDownloadedCabs(&bstrErrorItemId)))
  645. {
  646. USES_IU_CONVERSION;
  647. DEBUGMSG("ValidateDownloadedCabs: Checksum failed, error: %#lx", hr);
  648. //bstrErrorItemId will be NULL if it was some error other than ERROR_CRC
  649. if(NULL != bstrErrorItemId)
  650. {
  651. //Pingback failure with itemId
  652. gPingStatus.PingDownload(
  653. TRUE,
  654. URLLOGSTATUS_Failed,
  655. hr,
  656. W2T(bstrErrorItemId));
  657. }
  658. //Reset to detect pending
  659. ResetState(&s_fWaitBeforeDetect,&s_dwWaitB4Detect, TRUE); //wait shorter time cuz of error
  660. goto CloseHandle;
  661. }
  662. if (!gpState->fOptionSchedInstall())
  663. {
  664. DEBUGMSG("WUAUENG download complete, ready for UNSCHEDULED install");
  665. LogEvent_ItemList(
  666. EVENTLOG_INFORMATION_TYPE,
  667. IDS_MSG_Installation,
  668. IDS_MSG_InstallReady_Unscheduled);
  669. }
  670. PingSuccessfulDownloads();
  671. DEBUGMSG("WUAUENG validating items to prune out items already installed");
  672. if ( gpAUcatalog->ValidateItems(FALSE) != S_OK)
  673. {
  674. DEBUGMSG("WUAUENG Validation failed OR no items left in catalog, State->Detect Pending");
  675. ResetState();
  676. }
  677. else
  678. {
  679. DEBUGMSG(" Items still applicable, State->Download Complete");
  680. gpState->SetState(AUSTATE_DOWNLOAD_COMPLETE);
  681. }
  682. break;
  683. }
  684. else if (((WAIT_OBJECT_0 + IDOWNLOAD_TRANSIENT_ERROR_EVT) == dwRet) || //Transient error - connection lost
  685. ((WAIT_OBJECT_0 + IDOWNLOAD_DOWNLOAD_IN_PROGRESS) == dwRet)) //Download in progress - connection recuperated
  686. {
  687. BOOL fCheckDisconnect;
  688. fCheckDisconnect = ((WAIT_OBJECT_0 + IDOWNLOAD_DOWNLOAD_IN_PROGRESS) == dwRet);
  689. //AuStateAux = GetState();
  690. // setState again (and trigger Engine Change State) only if:
  691. // - It is not disconnected and you got Transient Error Event
  692. // - It is disconnected and you got a Download in Progress Event
  693. if ( fCheckDisconnect == gpState->fDisconnected() )
  694. {
  695. gpState->SetDisconnected(!fCheckDisconnect);
  696. gpState->SetState(AUSTATE_DOWNLOAD_PENDING); //relaunch client if it is not launched and notify client of new state
  697. }
  698. }
  699. else if ((WAIT_OBJECT_0 + IDOWNLOAD_SERVICE_FINISH) == dwRet) //Service Finished
  700. {
  701. DEBUGMSG("WUAUENG Detected Service Finished while wating for download to be done");
  702. goto Done;
  703. }
  704. else if ((WAIT_OBJECT_0 + IDOWNLOAD_SERVICE_DISABLED) == dwRet) //Engine State, should be due to disabled
  705. {
  706. if (FDisabledDuringDownload())
  707. {
  708. goto CloseHandle;
  709. }
  710. }
  711. else if ((WAIT_OBJECT_0 + IDOWNLOAD_DOWNLOAD_CANCELED) == dwRet)
  712. {
  713. if (JOB_ERROR == gpAUcatalog->m_audownloader.m_FinishReason)
  714. {
  715. DEBUGMSG("WUAUENG got error during download, wait for sometime b4 redetect");
  716. ResetState(&s_fWaitBeforeDetect,&s_dwWaitB4Detect, TRUE); //wait shorter time cuz of error
  717. }
  718. else
  719. {
  720. DEBUGMSG("WUAUENG download job got canceled, State -> Detect Pending");
  721. ResetState();
  722. }
  723. goto CloseHandle;
  724. }
  725. else if ((WAIT_OBJECT_0 + IDOWNLOAD_MESSAGE) == dwRet) //Messages
  726. {
  727. MSG msg2;
  728. PeekMessage(&msg2, NULL, NULL, NULL, PM_REMOVE); //we don't expect meaningful message here
  729. TranslateMessage(&msg2);// Translates virtual key codes
  730. DispatchMessage(&msg2); // Dispatches message to window
  731. if ( msg2.message != WM_USER ) //WM_USER is the one to pump to drizzle for processing
  732. {
  733. DEBUGMSG("WUAUENG dispatched message %#lx during downloading", msg2.message);
  734. }
  735. }
  736. else if (((WAIT_ABANDONED_0 + IDOWNLOAD_COMPLETE_EVT) == dwRet) ||
  737. ((WAIT_ABANDONED_0 + IDOWNLOAD_TRANSIENT_ERROR_EVT) == dwRet)||
  738. ((WAIT_ABANDONED_0 + IDOWNLOAD_DOWNLOAD_IN_PROGRESS) == dwRet)||
  739. ((WAIT_ABANDONED_0 + IDOWNLOAD_SERVICE_FINISH) == dwRet)||
  740. (WAIT_FAILED == dwRet))
  741. { //fixcode: when will this actually happen?
  742. DEBUGMSG("WUAUENG Error in Download Loop with MsgWaitForMultipleObjectsEx");
  743. ResetState();
  744. goto CloseHandle;
  745. }
  746. else
  747. {
  748. DEBUGMSG("WUAUENG Unexpected returned value dwRet = %d in n Download Loop with MsgWaitForMultipleObjectsEx", dwRet);
  749. }
  750. }
  751. while ( 1 );
  752. CloseHandle:
  753. EngineEvents.CloseEvents();
  754. }
  755. break;
  756. case AUMSG_POST_INSTALL:
  757. {
  758. DEBUGMSG("WUAUENG install done, sleeping a while before next detection");
  759. // fixcode: should use ResetState() instead
  760. s_fWaitBeforeDetect = TRUE;
  761. s_dwWaitB4Detect = RandomWaitTimeBeforeDetect();
  762. PostThreadMessage(gdwWorkerThreadId, AUMSG_DETECT, 0, 0);
  763. break;
  764. }
  765. case AUMSG_VALIDATE_CATALOG:
  766. DEBUGMSG("WUAUENG: validating catalog offline");
  767. if ( gpAUcatalog->ValidateItems(FALSE) != S_OK)
  768. {
  769. DEBUGMSG("WUAUENG Validation failed OR no items left in catalog, State->Detect Pending");
  770. ResetState();
  771. }
  772. SetEvent(ghValidateCatalog);
  773. break;
  774. case AUMSG_LOG_EVENT:
  775. DEBUGMSG("WUAUENG: logging the Ready To Install (Scheduled) event");
  776. if (gpState->fShouldScheduledInstall())
  777. {
  778. LogEvent_ScheduledInstall();
  779. }
  780. break;
  781. default:
  782. DEBUGMSG("WUAUENG Received unknown msg %#lx", msg.message);
  783. TranslateMessage( &msg );
  784. DispatchMessage( &msg );
  785. break;
  786. }
  787. }
  788. if (WAIT_OBJECT_0 == dwRet2)
  789. {
  790. DEBUGMSG("Update() exit in response to service finish event");
  791. }
  792. Done:
  793. DEBUGMSG("WUAUENG Update func returning");
  794. // we may ask wuauserv.dll to reload us.
  795. return fReloadAfterSelfUpdate ? S_FALSE : S_OK;
  796. }
  797. void saveSelection(VARIANT *selection)
  798. {
  799. // fixcode this return should return an error
  800. long n = 0;
  801. DEBUGMSG("Start saveSelection");
  802. WaitForSingleObject(ghMutex, INFINITE);
  803. if ( FAILED(SafeArrayGetUBound(selection->parray, 1, &n)))
  804. {
  805. DEBUGMSG("WUAUENG SafeArrayGetUBond failed");
  806. goto done;
  807. }
  808. if (((n + 1) / 2) != gpAUcatalog->m_ItemList.Count())
  809. {
  810. AUASSERT(FALSE);
  811. DEBUGMSG("WUAUENG got unmatched number of items from client");
  812. goto done;
  813. }
  814. for ( long i = 0; i < (n + 1) / 2; i++ )
  815. {
  816. long dex = i * 2;
  817. VARIANT var;
  818. VariantInit(&var);
  819. if ( FAILED(SafeArrayGetElement(selection->parray, &dex, &var)) )
  820. {
  821. DEBUGMSG("SafeArrayGetElement failed");
  822. continue;
  823. }
  824. BOOL fMatch = (WUCompareStringI(var.bstrVal, gpAUcatalog->m_ItemList[i].bstrID()) == CSTR_EQUAL);
  825. VariantClear(&var);
  826. if ( fMatch )
  827. {
  828. if ( SUCCEEDED(SafeArrayGetElement(selection->parray, &++dex, &var)) )
  829. {
  830. gpAUcatalog->m_ItemList[i].SetStatus(var.lVal);
  831. // DEBUGMSG("Status for item %S is now %d", gpAUcatalog->m_ItemList[i].bstrID(), gpAUcatalog->m_ItemList[i].dwStatus());
  832. }
  833. }
  834. else
  835. {
  836. DEBUGMSG("item ids did not match for saving selections");
  837. }
  838. }
  839. // gpAUcatalog->m_ItemList.DbgDump();
  840. gpAUcatalog->Serialize();
  841. done:
  842. ReleaseMutex(ghMutex);
  843. DEBUGMSG("End saveSelection");
  844. }
  845. HRESULT StartDownload(void)
  846. {
  847. //DEBUGMSG("WUAUENG ::StartDownload called");
  848. if ( AUSTATE_DETECT_COMPLETE != gpState->GetState() )
  849. {
  850. DEBUGMSG("WUAUENG ::StartDownload state incorrect");
  851. return E_FAIL;
  852. }
  853. PostThreadMessage(gdwWorkerThreadId, AUMSG_DOWNLOAD, 0, 0);
  854. return S_OK;
  855. }
  856. HRESULT GetUpdatesList(VARIANT *vList)
  857. {
  858. HRESULT hr = E_FAIL;
  859. DWORD dwWait;
  860. dwWait = WaitForSingleObject(ghMutex, INFINITE);
  861. if (WAIT_FAILED == dwWait)
  862. {
  863. DEBUGMSG("WUAUENG GetUpdateList got WAIT_ABANDONED");
  864. }
  865. else
  866. DEBUGMSG("WUAUENG Getting Updates list dWait=%d",dwWait);
  867. if ( (AUSTATE_DETECT_COMPLETE != gpState->GetState()) && (AUSTATE_DOWNLOAD_COMPLETE != gpState->GetState()) )
  868. {
  869. goto Done;
  870. }
  871. hr = gpAUcatalog->getUpdatesList(vList);
  872. Done:
  873. ReleaseMutex(ghMutex);
  874. return hr;
  875. }
  876. HRESULT GetInstallXML(/*[out]*/ BSTR *pbstrCatalogXML, /*[out]*/ BSTR *pbstrDownloadXML)
  877. {
  878. // DEBUGMSG("::GetInstallXML");
  879. HRESULT hr = E_FAIL;
  880. DWORD dwWait;
  881. dwWait = WaitForSingleObject(ghMutex, INFINITE);
  882. if (WAIT_FAILED == dwWait)
  883. {
  884. DEBUGMSG("WUAUENG GetInstallXML got WAIT_ABANDONED");
  885. }
  886. else
  887. {
  888. DEBUGMSG("WUAUENG Getting Updates list dWait=%d",dwWait);
  889. }
  890. hr = gpAUcatalog->GetInstallXML(pbstrCatalogXML, pbstrDownloadXML);
  891. //Done:
  892. ReleaseMutex(ghMutex);
  893. return hr;
  894. }
  895. HRESULT GetDownloadStatus(UINT *pPercentage, DWORD *pdwnldStatus, BOOL fCareAboutConnection)
  896. {
  897. DWORD dwComplete;
  898. DWORD dwstatus;
  899. HRESULT hr;
  900. if ( AUSTATE_DOWNLOAD_PENDING != gpState->GetState() )
  901. {
  902. *pPercentage = (AUSTATE_DOWNLOAD_COMPLETE == gpState->GetState()) ? 100 : 0 ;
  903. *pdwnldStatus = DWNLDSTATUS_DOWNLOADING; //for trayicon to show 100%
  904. //DEBUGMSG("WUAUENG %% complete = %d", *pPercentage);
  905. return S_OK;
  906. }
  907. *pPercentage = 0;
  908. if (fCareAboutConnection && !gfDownloadStarted)
  909. {
  910. DEBUGMSG("WUAUENG Download status is checking for connection");
  911. *pdwnldStatus = DWNLDSTATUS_CHECKING_CONNECTION;
  912. return S_OK;
  913. }
  914. WaitForSingleObject(ghMutex, INFINITE);
  915. hr = gpAUcatalog->m_audownloader.getStatus(&dwComplete, &dwstatus);
  916. ReleaseMutex(ghMutex);
  917. if (FAILED(hr))
  918. {
  919. *pdwnldStatus = DWNLDSTATUS_NOT_DOWNLOADING;
  920. return S_OK;
  921. }
  922. *pPercentage = (int)dwComplete;
  923. //DEBUGMSG("WUAUENG %% complete = %d", *pPercentage);
  924. switch (dwstatus)
  925. {
  926. case BG_JOB_STATE_TRANSFERRING:
  927. case BG_JOB_STATE_TRANSFERRED: //for trayicon to show 100%, as in the beginning of the routine
  928. {
  929. *pdwnldStatus = DWNLDSTATUS_DOWNLOADING;
  930. break;
  931. }
  932. case BG_JOB_STATE_SUSPENDED:
  933. {
  934. *pdwnldStatus = DWNLDSTATUS_PAUSED;
  935. break;
  936. }
  937. case BG_JOB_STATE_ERROR:
  938. case BG_JOB_STATE_TRANSIENT_ERROR:
  939. case BG_JOB_STATE_ACKNOWLEDGED:
  940. case BG_JOB_STATE_CANCELLED:
  941. case BG_JOB_STATE_QUEUED:
  942. case BG_JOB_STATE_CONNECTING:
  943. {
  944. *pdwnldStatus = DWNLDSTATUS_NOT_DOWNLOADING;
  945. break;
  946. }
  947. default:
  948. {
  949. DEBUGMSG("WUAUENG GetDownloadStatus got an unexpected BG_JOB_STATE %d", dwstatus);
  950. *pdwnldStatus = DWNLDSTATUS_NOT_DOWNLOADING;
  951. }
  952. }
  953. return S_OK;
  954. }