Source code of Windows XP (NT5)
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.

940 lines
37 KiB

  1. #include "wsdueng.h"
  2. DWORD WINAPI DownloadThreadProc(LPVOID lpv);
  3. // private helper function forward declaration
  4. // RogerJ --- Use this function to avoid auto disconnection
  5. void IndicateDialmonActivity(void);
  6. DWORD CDynamicUpdate::OpenHttpConnection(LPCSTR pszDownloadUrl, BOOL fGetRequest)
  7. {
  8. LOG_block("CDynamicUpdate::OpenHttpConnection()");
  9. URL_COMPONENTSA UrlComponents;
  10. DWORD dwErr, dwStatus, dwLength;
  11. LPSTR AcceptTypes[] = {"*/*", NULL};
  12. LOG_out("Opening HTTP URL %s", pszDownloadUrl);
  13. dwErr = dwStatus = dwLength = 0;
  14. // Buffers used to Break the URL into its different components for Internet API calls
  15. char szServerName[INTERNET_MAX_URL_LENGTH + 1];
  16. char szObject[INTERNET_MAX_URL_LENGTH + 1];
  17. char szUserName[UNLEN+1];
  18. char szPasswd[UNLEN+1];
  19. // We need to break down the Passed in URL into its various components for the InternetAPI Calls. Specifically we
  20. // Need the server name, object to download, username and password information.
  21. ZeroMemory(szServerName, INTERNET_MAX_URL_LENGTH + 1);
  22. ZeroMemory(szObject, INTERNET_MAX_URL_LENGTH + 1);
  23. ZeroMemory(&UrlComponents, sizeof(UrlComponents));
  24. UrlComponents.dwStructSize = sizeof(UrlComponents);
  25. UrlComponents.lpszHostName = szServerName;
  26. UrlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH + 1;
  27. UrlComponents.lpszUrlPath = szObject;
  28. UrlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH + 1;
  29. UrlComponents.lpszUserName = szUserName;
  30. UrlComponents.dwUserNameLength = UNLEN + 1;
  31. UrlComponents.lpszPassword = szPasswd;
  32. UrlComponents.dwPasswordLength = UNLEN + 1;
  33. if (! InternetCrackUrlA(pszDownloadUrl, 0, 0, &UrlComponents) )
  34. {
  35. dwErr = GetLastError();
  36. LOG_error("InternetCrackUrl() Failed, Error: %d", dwErr);
  37. return dwErr;
  38. }
  39. // If the connection has already been established re-use it.
  40. if (NULL == m_hInternet)
  41. {
  42. if (! (m_hInternet = InternetOpenA("Dynamic Update", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)) )
  43. {
  44. dwErr = GetLastError();
  45. LOG_error("InternetOpen() Failed, Error: %d", dwErr);
  46. return dwErr;
  47. }
  48. }
  49. dwStatus = 30 * 1000; // 30 seconds in milliseconds
  50. dwLength = sizeof(dwStatus);
  51. InternetSetOptionA(m_hInternet, INTERNET_OPTION_SEND_TIMEOUT, &dwStatus, dwLength);
  52. if (NULL == m_hConnect || 0 != lstrcmpi(m_szCurrentConnectedServer, szServerName))
  53. {
  54. // No connection established yet, or we are connecting to a new server.
  55. SafeInternetCloseHandle(m_hConnect);
  56. if (! (m_hConnect = InternetConnectA(m_hInternet, szServerName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPasswd,
  57. INTERNET_SERVICE_HTTP, INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0)) )
  58. {
  59. dwErr = GetLastError();
  60. LOG_error("InternetConnect() Failed, Error: %d", dwErr);
  61. return dwErr;
  62. }
  63. lstrcpy(m_szCurrentConnectedServer, szServerName);
  64. }
  65. SafeInternetCloseHandle(m_hOpenRequest); // make sure there is no open request before creating the new one.
  66. if (! (m_hOpenRequest = HttpOpenRequestA(m_hConnect,
  67. (fGetRequest) ? NULL : "HEAD",
  68. szObject,
  69. NULL,
  70. NULL,
  71. (LPCSTR *)AcceptTypes,
  72. INTERNET_FLAG_NO_UI,
  73. 0)) )
  74. {
  75. dwErr = GetLastError();
  76. // log result
  77. return dwErr;
  78. }
  79. int nNumOfTrial = 0;
  80. do
  81. {
  82. if (! HttpSendRequestA(m_hOpenRequest, NULL, 0, NULL, 0) )
  83. {
  84. dwErr = GetLastError();
  85. // log result
  86. return dwErr;
  87. }
  88. dwLength = sizeof(dwStatus);
  89. if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
  90. (LPVOID)&dwStatus, &dwLength, NULL) )
  91. {
  92. dwErr = GetLastError();
  93. // log result
  94. return dwErr;
  95. }
  96. nNumOfTrial ++;
  97. } while (NeedRetry(dwStatus) && nNumOfTrial < DU_CONNECTION_RETRY);
  98. // If the Request did not succeed we'll assume we have no internet connection and return the Error Code
  99. // that Setup will trigger a warning to the user to manually establish a connection.
  100. if ((HTTP_STATUS_OK != dwStatus) && (HTTP_STATUS_PARTIAL_CONTENT != dwStatus))
  101. {
  102. LOG_error("Http Status NOT OK, Status %d", dwStatus);
  103. if (HTTP_STATUS_NOT_FOUND == dwStatus)
  104. return ERROR_INTERNET_INVALID_URL;
  105. else return ERROR_CONNECTION_UNAVAIL;
  106. }
  107. return ERROR_SUCCESS;
  108. }
  109. DWORD CDynamicUpdate::DownloadFilesAsync()
  110. {
  111. LOG_block("CDynamicUpdate::DownloadFileAsync()");
  112. DWORD dwThreadID;
  113. DWORD dwErr;
  114. SafeCloseHandle(m_hDownloadThreadProc);
  115. m_hDownloadThreadProc = CreateThread(NULL, 0, DownloadThreadProc, (void *)this, 0, &dwThreadID);
  116. if (NULL == m_hDownloadThreadProc)
  117. {
  118. dwErr = GetLastError();
  119. LOG_error("Unable to CreateThread for ASynch Download, Error %d", dwErr);
  120. return dwErr;
  121. }
  122. SetThreadPriority(m_hDownloadThreadProc, THREAD_PRIORITY_NORMAL);
  123. return ERROR_SUCCESS;
  124. }
  125. DWORD CDynamicUpdate::DownloadFile(LPCSTR pszDownloadUrl, LPCSTR pszLocalFile, BOOL fDecompress, BOOL fCheckTrust)
  126. {
  127. LOG_block("CDynamicUpdate::DownloadFile()");
  128. DWORD dwErr, dwFileSize, dwLength;
  129. DWORD dwBytesRead, dwBytesWritten;
  130. DWORD dwCount1, dwCount2, dwTimeElapsed;
  131. SYSTEMTIME st;
  132. FILETIME ft;
  133. HANDLE hTargetFile;
  134. SetLastError(0);
  135. dwErr = OpenHttpConnection(pszDownloadUrl, FALSE);
  136. if (ERROR_SUCCESS != dwErr)
  137. {
  138. // log error
  139. return dwErr;
  140. }
  141. dwLength = sizeof(st);
  142. if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME,
  143. (LPVOID)&st, &dwLength, NULL) )
  144. {
  145. dwErr = GetLastError();
  146. LOG_error("HttpQueryInfo Failed on File %s, Error %d", pszDownloadUrl, dwErr);
  147. SafeInternetCloseHandle(m_hOpenRequest);
  148. return dwErr;
  149. }
  150. SystemTimeToFileTime(&st, &ft);
  151. // Now Get the FileSize information from the Server
  152. dwLength = sizeof(dwFileSize);
  153. if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
  154. (LPVOID)&dwFileSize, &dwLength, NULL) )
  155. {
  156. dwErr = GetLastError();
  157. LOG_error("HttpQueryInfo Failed on File %s, Error %d", pszDownloadUrl, dwErr);
  158. SafeInternetCloseHandle(m_hOpenRequest);
  159. return dwErr;
  160. }
  161. if (IsServerFileNewer(ft, dwFileSize, pszLocalFile))
  162. {
  163. dwErr = OpenHttpConnection(pszDownloadUrl, TRUE); // need to download the file, send the GET request this time
  164. if (ERROR_SUCCESS != dwErr)
  165. {
  166. // log error
  167. return dwErr;
  168. }
  169. #define DOWNLOAD_BUFFER_LENGTH 32 * 1024
  170. PBYTE lpBuffer = (PBYTE) GlobalAlloc(GMEM_ZEROINIT, DOWNLOAD_BUFFER_LENGTH);
  171. if (NULL == lpBuffer)
  172. {
  173. dwErr = GetLastError();
  174. LOG_error("Failed to Allocate Memory for Download Buffer, Error %d", dwErr);
  175. SafeInternetCloseHandle(m_hOpenRequest);
  176. return dwErr;
  177. }
  178. hTargetFile = CreateFileA(pszLocalFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  179. if (INVALID_HANDLE_VALUE == hTargetFile)
  180. {
  181. dwErr = GetLastError();
  182. LOG_error("Failed to Open Target File %s, Error %d", pszLocalFile, dwErr);
  183. SafeGlobalFree(lpBuffer);
  184. SafeInternetCloseHandle(m_hOpenRequest);
  185. return dwErr;
  186. }
  187. // Download the File
  188. BOOL fRet;
  189. while (fRet = InternetReadFile(m_hOpenRequest, lpBuffer, DOWNLOAD_BUFFER_LENGTH, &dwBytesRead))
  190. {
  191. if (0 == dwBytesRead)
  192. {
  193. // Make one final call to InternetReadFile to commit the file to Cache (download is not complete otherwise)
  194. BYTE bTemp[32];
  195. InternetReadFile(m_hOpenRequest, &bTemp, 32, &dwBytesRead);
  196. // set the file time to match the server file time since we just downloaded it.
  197. // If we don't do this the file time will be set to the current system time.
  198. SetFileTime(hTargetFile, &ft, NULL, NULL);
  199. break; // done reading.
  200. }
  201. if (!WriteFile(hTargetFile, lpBuffer, dwBytesRead, &dwBytesWritten, NULL))
  202. {
  203. LOG_error("Failed to Write to File %s, Error %d", pszLocalFile, dwErr);
  204. dwErr = GetLastError();
  205. SafeGlobalFree(lpBuffer);
  206. SafeInternetCloseHandle(m_hOpenRequest);
  207. SafeCloseHandle(hTargetFile);
  208. return dwErr;
  209. }
  210. }
  211. if (!fRet)
  212. {
  213. dwErr = GetLastError();
  214. SafeCloseHandle(hTargetFile);
  215. DeleteFile(pszLocalFile); // delete the file that we just had an error during downloading
  216. SafeGlobalFree(lpBuffer);
  217. LOG_error("InternetReadFile Failed, Error %d", dwErr);
  218. return dwErr;
  219. }
  220. SafeGlobalFree(lpBuffer);
  221. SafeCloseHandle(hTargetFile);
  222. // check for decompress requested
  223. if (fCheckTrust)
  224. {
  225. // Use VerifyFile() to verifty the cert of the downloaded component
  226. // change made by ROGERJ at Sept. 25th, 2000
  227. if (FAILED(VerifyFile(pszLocalFile, FALSE)))
  228. {
  229. LOG_error("CabFile %s does not have a valid Signature", pszLocalFile);
  230. DeleteFile(pszLocalFile); // not trusted, nuke it.
  231. }
  232. }
  233. if (fDecompress)
  234. {
  235. char szLocalDir[MAX_PATH];
  236. lstrcpy(szLocalDir, pszLocalFile);
  237. PathRemoveFileSpec(szLocalDir);
  238. fdi(const_cast<char *>(pszLocalFile), szLocalDir);
  239. }
  240. }
  241. // Always close the Request when the file is finished.
  242. // We intentionally leave the connection to the server Open though, seems more
  243. // efficient when requesting multiple files from the same server.
  244. SafeInternetCloseHandle(m_hOpenRequest);
  245. return ERROR_SUCCESS;
  246. }
  247. DWORD CDynamicUpdate::DownloadFileToMem(LPCSTR pszDownloadUrl, PBYTE *lpBuffer, DWORD *pdwAllocatedLength, BOOL fDecompress, LPSTR pszFileName, LPSTR pszDecompresedFileName)
  248. {
  249. LOG_block("CDynamicUpdate::DownloadFileToMem()");
  250. DWORD dwErr, dwFileSize, dwLength;
  251. DWORD dwBytesRead, dwBytesWritten;
  252. DWORD dwCount1, dwCount2, dwTimeElapsed;
  253. SYSTEMTIME st;
  254. FILETIME ft;
  255. HANDLE hTargetFile;
  256. dwErr = OpenHttpConnection(pszDownloadUrl, TRUE);
  257. if (ERROR_SUCCESS != dwErr)
  258. {
  259. // log error
  260. SetLastError(dwErr);
  261. return dwErr;
  262. }
  263. dwLength = sizeof(st);
  264. if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME,
  265. (LPVOID)&st, &dwLength, NULL) )
  266. {
  267. dwErr = GetLastError();
  268. // log error
  269. SafeInternetCloseHandle(m_hOpenRequest);
  270. return dwErr;
  271. }
  272. SystemTimeToFileTime(&st, &ft);
  273. // Now Get the FileSize information from the Server
  274. dwLength = sizeof(dwFileSize);
  275. if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
  276. (LPVOID)&dwFileSize, &dwLength, NULL) )
  277. {
  278. dwErr = GetLastError();
  279. // log error
  280. SafeInternetCloseHandle(m_hOpenRequest);
  281. return dwErr;
  282. }
  283. *lpBuffer = (PBYTE) GlobalAlloc(GMEM_ZEROINIT, dwFileSize);
  284. if (NULL == *lpBuffer)
  285. {
  286. dwErr = GetLastError();
  287. // log error
  288. SafeInternetCloseHandle(m_hOpenRequest);
  289. return dwErr;
  290. }
  291. *pdwAllocatedLength = dwFileSize;
  292. // Read the whole file
  293. if (!InternetReadFile(m_hOpenRequest, *lpBuffer, dwFileSize, &dwBytesRead))
  294. {
  295. dwErr = GetLastError();
  296. LOG_error("Internet Read File Failed, Error %d", dwErr);
  297. SafeInternetCloseHandle(m_hOpenRequest);
  298. return dwErr;
  299. }
  300. if (fDecompress)
  301. {
  302. char szLocalFile[MAX_PATH];
  303. char szLocalFileTmp[MAX_PATH];
  304. if (NULL != pszDecompresedFileName)
  305. {
  306. char szCatalogName[MAX_PATH];
  307. PathCombine(szLocalFile, m_szTempPath, pszDecompresedFileName);
  308. wsprintf(szCatalogName, "%s.tmp", pszFileName);
  309. PathCombine(szLocalFileTmp, m_szTempPath, szCatalogName);
  310. }
  311. else
  312. {
  313. PathCombine(szLocalFile, m_szTempPath, pszFileName);
  314. wsprintf(szLocalFileTmp, "%s.tmp", szLocalFile);
  315. }
  316. HANDLE hFile = CreateFile(szLocalFileTmp, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  317. if (INVALID_HANDLE_VALUE == hFile)
  318. {
  319. LOG_error("Unable to write temp file for decompress");
  320. return GetLastError();
  321. }
  322. DWORD dwTmp;
  323. WriteFile(hFile, *lpBuffer, dwFileSize, &dwTmp, NULL);
  324. FlushFileBuffers(hFile);
  325. SafeCloseHandle(hFile);
  326. if (fdi(szLocalFileTmp, m_szTempPath))
  327. {
  328. // file was decompressed
  329. hFile = CreateFile(szLocalFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  330. if (INVALID_HANDLE_VALUE == hFile)
  331. {
  332. LOG_error("Unable to Read decompressed file %s", szLocalFile);
  333. SafeInternetCloseHandle(m_hOpenRequest);
  334. DeleteFile(szLocalFileTmp);
  335. return GetLastError();
  336. }
  337. dwFileSize = GetFileSize(hFile, NULL);
  338. SafeGlobalFree(*lpBuffer);
  339. *lpBuffer = (PBYTE) GlobalAlloc(GMEM_ZEROINIT, dwFileSize);
  340. *pdwAllocatedLength = dwFileSize;
  341. if (!ReadFile(hFile, *lpBuffer, dwFileSize, &dwTmp, NULL))
  342. {
  343. dwErr = GetLastError();
  344. LOG_error("ReadFile %s Failed, Error %d", szLocalFile, dwErr);
  345. SafeInternetCloseHandle(m_hOpenRequest);
  346. SafeCloseHandle(hFile);
  347. DeleteFile(szLocalFile);
  348. DeleteFile(szLocalFileTmp);
  349. return dwErr;
  350. }
  351. SafeCloseHandle(hFile);
  352. DeleteFile(szLocalFile);
  353. }
  354. DeleteFile(szLocalFileTmp);
  355. }
  356. // Make one final call to InternetReadFile to commit the file to Cache (downloaded is not complete otherwise)
  357. BYTE bTemp[32];
  358. InternetReadFile(m_hOpenRequest, &bTemp, 32, &dwBytesRead);
  359. // Always close the Request when the file is finished.
  360. // We intentionally leave the connection to the server Open though, seems more
  361. // efficient when requesting multiple files from the same server.
  362. SafeInternetCloseHandle(m_hOpenRequest);
  363. return ERROR_SUCCESS;
  364. }
  365. BOOL CDynamicUpdate::IsServerFileNewer(FILETIME ftServerTime, DWORD dwServerFileSize, LPCSTR pszLocalFile)
  366. {
  367. HANDLE hFile = INVALID_HANDLE_VALUE;
  368. FILETIME ftCreateTime;
  369. LONG lTime;
  370. DWORD dwLocalFileSize;
  371. hFile = CreateFile(pszLocalFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  372. if (INVALID_HANDLE_VALUE != hFile)
  373. {
  374. dwLocalFileSize = GetFileSize(hFile, NULL);
  375. if (dwLocalFileSize != dwServerFileSize)
  376. {
  377. SafeCloseHandle(hFile);
  378. return TRUE; // server and local files do not match, download server file.
  379. }
  380. if (GetFileTime(hFile, &ftCreateTime, NULL, NULL))
  381. {
  382. lTime = CompareFileTime(&ftCreateTime, &ftServerTime);
  383. if (lTime < 0)
  384. {
  385. SafeCloseHandle(hFile);
  386. return TRUE; // local file is 'older' than the server file
  387. }
  388. else
  389. {
  390. SafeCloseHandle(hFile);
  391. return FALSE; // local file is either equal or newer, leave it.
  392. }
  393. }
  394. }
  395. // if we couldn't find the file, or we couldn't get the time, assume the server file is newer
  396. SafeCloseHandle(hFile);
  397. return TRUE;
  398. }
  399. DWORD CDynamicUpdate::AsyncDownloadProc()
  400. {
  401. LOG_block("CDynamicUpdate::AsyncDownloadProc()");
  402. char szServerFile[INTERNET_MAX_URL_LENGTH];
  403. char szLocalFile[MAX_PATH];
  404. DWORD dwErr = 0, dwFileSize = 0, dwLength = 0;
  405. DWORD dwBytesRead = 0, dwBytesWritten = 0;
  406. SYSTEMTIME st;
  407. FILETIME ft;
  408. HANDLE hTargetFile = INVALID_HANDLE_VALUE;
  409. BOOL fAbort = FALSE;
  410. BOOL fRet = TRUE;
  411. // The Download Thread Proc handles downloading all the files from the DownloadItemList in the DynamicUpdate object.
  412. // It will enumerate the list of items to download, make callbacks to the HWND in the dynamic update object in 1% intervals
  413. // and a final callback when it is complete. It will also check for cancel requests after downloading each 1k block from the
  414. // server. We do this in this small of a block to retain some responsiveness to the UI requests.
  415. EnterCriticalSection(&m_csDownload);
  416. DOWNLOADITEM *pCurrent = m_pDownloadItemList;
  417. while (pCurrent)
  418. {
  419. // Update the Cab Size for the Current Item and Recalc the total download size
  420. // We do this because the Estimated Download Size can be 'less' than the real download size.
  421. // When providing progress this causes the progress bar to go beyond 100%, which is wrong.
  422. LPSTR pszCabFile = pCurrent->mszFileList;
  423. DWORD dwCurrentItemSize = 0;
  424. for (int i = 0; i < pCurrent->iNumberOfCabs; i++)
  425. {
  426. DuUrlCombine(szServerFile, m_pV3->m_szCabPoolUrl, pszCabFile);
  427. dwErr = OpenHttpConnection(szServerFile, FALSE);
  428. if (ERROR_SUCCESS != dwErr)
  429. {
  430. LeaveCriticalSection(&m_csDownload);
  431. LOG_error("Failed to Open Connection for %s, Error Was %d", szServerFile, dwErr);
  432. // Tell Setup that we're Stopping the Download
  433. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  434. // Send Ping Back Status - Failed Item
  435. PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE);
  436. return dwErr;
  437. }
  438. // Now Get the FileSize information from the Server
  439. dwLength = sizeof(dwFileSize);
  440. if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
  441. (LPVOID)&dwFileSize, &dwLength, NULL) )
  442. {
  443. dwErr = GetLastError();
  444. LOG_error("HttpQueryInfo Failed on File %s, Error %d, Skipping Item", szServerFile, dwErr);
  445. SafeInternetCloseHandle(m_hOpenRequest);
  446. LeaveCriticalSection(&m_csDownload);
  447. // Tell Setup that we're Stopping the Download
  448. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  449. // Send Ping Back Status - Failed Item
  450. PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE);
  451. return dwErr;
  452. }
  453. SafeInternetCloseHandle(m_hOpenRequest);
  454. dwCurrentItemSize += dwFileSize;
  455. pszCabFile += lstrlen(pszCabFile) + 2; // advance to the next cab.
  456. }
  457. pCurrent->dwTotalFileSize = dwCurrentItemSize; // download size in Bytes.
  458. pCurrent = pCurrent->pNext;
  459. }
  460. m_dwCurrentBytesDownloaded = 0;
  461. UpdateDownloadItemSize();
  462. // We want to Send a Progress Message Every 1 Percent of the Download.
  463. DWORD dwBytesPerPercent = m_dwTotalDownloadSize / 100; // in case the
  464. if (0 == dwBytesPerPercent)
  465. {
  466. dwBytesPerPercent = 1; // must be at least 1 byte, cannot be zero
  467. }
  468. DWORD dwCurrentPercentComplete = 0;
  469. // Now we will start looping through the Items and Download the Files.
  470. pCurrent = m_pDownloadItemList;
  471. while (pCurrent)
  472. {
  473. EnterCriticalSection(&m_cs);
  474. fAbort = m_fAbortDownload;
  475. LeaveCriticalSection(&m_cs);
  476. if (fAbort)
  477. {
  478. // check for abort for each item
  479. LeaveCriticalSection(&m_csDownload);
  480. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM) DU_STATUS_ABORT, (LPARAM) NULL);
  481. SafeInternetCloseHandle(m_hConnect);
  482. SafeInternetCloseHandle(m_hInternet);
  483. m_fAbortDownload = FALSE; // reset
  484. return ERROR_SUCCESS;
  485. }
  486. // RogerJ --- call IndicateDialmonActivity() to avoid auto disconnection
  487. else
  488. IndicateDialmonActivity();
  489. // Each 'Item' can have more than one Cab. The Setup Item itself will usually have 3 cabs, Drivers will probably only have 1 cab.
  490. LPSTR pszCabFile = pCurrent->mszFileList;
  491. for (int i = 0; i < pCurrent->iNumberOfCabs; i++)
  492. {
  493. pCurrent->iCurrentCab = i;
  494. DuUrlCombine(szServerFile, m_pV3->m_szCabPoolUrl, pszCabFile); // current cab is the null terminated cab name in the list
  495. WUCRC_HASH crc;
  496. char szShortName[MAX_PATH]; // for trimmed filename
  497. if (FAILED(SplitCRCName((LPCSTR)pszCabFile, &crc, szShortName)))
  498. {
  499. lstrcpy(szShortName, pszCabFile); // probably not a CRC'd file
  500. }
  501. PathCombine(szLocalFile, m_szDownloadPath, szShortName);
  502. // Now open the HttpConnection to get this file
  503. dwErr = OpenHttpConnection(szServerFile, FALSE);
  504. if (ERROR_SUCCESS != dwErr)
  505. {
  506. LeaveCriticalSection(&m_csDownload);
  507. LOG_error("Failed to Open Connection for %s, Error Was %d", szServerFile, dwErr);
  508. // Tell Setup that we're Stopping the Download
  509. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  510. // Send Ping Back Status - Failed Item
  511. PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE);
  512. return dwErr;
  513. }
  514. dwLength = sizeof(st);
  515. if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME,
  516. (LPVOID)&st, &dwLength, NULL) )
  517. {
  518. LeaveCriticalSection(&m_csDownload);
  519. dwErr = GetLastError();
  520. LOG_error("HttpQueryInfo Failed on File %s, Error %d, Skipping Item", szServerFile, dwErr);
  521. SafeInternetCloseHandle(m_hOpenRequest);
  522. // Tell Setup that we're Stopping the Download
  523. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  524. // Send Ping Back Status - Failed Item
  525. PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE);
  526. return dwErr;
  527. }
  528. SystemTimeToFileTime(&st, &ft);
  529. // Now Get the FileSize information from the Server
  530. dwLength = sizeof(dwFileSize);
  531. if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
  532. (LPVOID)&dwFileSize, &dwLength, NULL) )
  533. {
  534. dwErr = GetLastError();
  535. LOG_error("HttpQueryInfo Failed on File %s, Error %d, Skipping Item", szServerFile, dwErr);
  536. SafeInternetCloseHandle(m_hOpenRequest);
  537. LeaveCriticalSection(&m_csDownload);
  538. // Tell Setup that we're Stopping the Download
  539. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  540. // Send Ping Back Status - Failed Item
  541. PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE);
  542. return dwErr;
  543. }
  544. if (IsServerFileNewer(ft, dwFileSize, szLocalFile))
  545. {
  546. dwErr = OpenHttpConnection(szServerFile, TRUE);
  547. if (ERROR_SUCCESS != dwErr)
  548. {
  549. LeaveCriticalSection(&m_csDownload);
  550. LOG_error("Failed to Open Connection for %s, Error Was %d", szServerFile, dwErr);
  551. // Tell Setup that we're Stopping the Download
  552. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  553. return dwErr;
  554. }
  555. #define ASYNC_DOWNLOAD_BUFFER_LENGTH 1 * 1024 // download in 1k blocks to maintain UI responsiveness to a cancel request.
  556. PBYTE lpBuffer = (PBYTE) GlobalAlloc(GMEM_ZEROINIT, ASYNC_DOWNLOAD_BUFFER_LENGTH);
  557. if (NULL == lpBuffer)
  558. {
  559. dwErr = GetLastError();
  560. LOG_error("Failed to Allocate Memory for Download Buffer, Error %d", dwErr);
  561. SafeInternetCloseHandle(m_hOpenRequest);
  562. LeaveCriticalSection(&m_csDownload);
  563. // Tell Setup that we're Stopping the Download
  564. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  565. return dwErr;
  566. }
  567. hTargetFile = CreateFileA(szLocalFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  568. if (INVALID_HANDLE_VALUE == hTargetFile)
  569. {
  570. dwErr = GetLastError();
  571. LOG_error("Failed to Open Target File %s, Error %d", szLocalFile, dwErr);
  572. SafeGlobalFree(lpBuffer);
  573. SafeInternetCloseHandle(m_hOpenRequest);
  574. LeaveCriticalSection(&m_csDownload);
  575. // Tell Setup that we're Stopping the Download
  576. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  577. return dwErr;
  578. }
  579. // Download the File
  580. while (fRet = InternetReadFile(m_hOpenRequest, lpBuffer, ASYNC_DOWNLOAD_BUFFER_LENGTH, &dwBytesRead))
  581. {
  582. if (0 == dwBytesRead) // done reading
  583. {
  584. // Make one final call to InternetReadFile to commit the file to Cache (download is not complete otherwise)
  585. BYTE bTemp[32];
  586. InternetReadFile(m_hOpenRequest, &bTemp, 32, &dwBytesRead);
  587. break; // done reading.
  588. }
  589. EnterCriticalSection(&m_cs);
  590. fAbort = m_fAbortDownload;
  591. LeaveCriticalSection(&m_cs);
  592. if (fAbort)
  593. {
  594. // Download Abort Requested, Clean Up, Signal the Complete Message and exit the Thread Proc
  595. SafeCloseHandle(hTargetFile);
  596. DeleteFile(szLocalFile); // file not complete
  597. SafeInternetCloseHandle(m_hOpenRequest);
  598. SafeInternetCloseHandle(m_hConnect);
  599. SafeInternetCloseHandle(m_hInternet);
  600. SafeGlobalFree(lpBuffer);
  601. LeaveCriticalSection(&m_csDownload);
  602. m_fAbortDownload = FALSE; // reset
  603. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_ABORT , (LPARAM) NULL);
  604. return ERROR_SUCCESS; // cancel is not an error
  605. }
  606. // RogerJ --- call IndicateDialmonActivity() to avoid auto disconnection
  607. else
  608. IndicateDialmonActivity();
  609. if (!WriteFile(hTargetFile, lpBuffer, dwBytesRead, &dwBytesWritten, NULL))
  610. {
  611. dwErr = GetLastError();
  612. LOG_error("Failed to Write to File %s, Error %d", szLocalFile, dwErr);
  613. SafeGlobalFree(lpBuffer);
  614. SafeInternetCloseHandle(m_hOpenRequest);
  615. SafeCloseHandle(hTargetFile);
  616. DeleteFile(szLocalFile); // incomplete download
  617. LeaveCriticalSection(&m_csDownload);
  618. // Tell Setup that we're Stopping the Download
  619. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  620. return dwErr;
  621. }
  622. m_dwCurrentBytesDownloaded += dwBytesRead;
  623. dwCurrentPercentComplete = m_dwCurrentBytesDownloaded / dwBytesPerPercent;
  624. if (dwCurrentPercentComplete != m_dwLastPercentComplete)
  625. {
  626. // We've downloaded another percent of the total size.. Send a Progress Message
  627. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_PROGRESS, (WPARAM)m_dwTotalDownloadSize, (LPARAM)m_dwCurrentBytesDownloaded);
  628. m_dwLastPercentComplete = dwCurrentPercentComplete;
  629. }
  630. }
  631. // indicates error during InternetReadFile process
  632. if (!fRet)
  633. {
  634. dwErr = GetLastError();
  635. LOG_error("InternetReadFile Failed, Error %d", dwErr);
  636. SafeGlobalFree(lpBuffer);
  637. SafeInternetCloseHandle(m_hOpenRequest);
  638. SafeCloseHandle(hTargetFile);
  639. DeleteFile(szLocalFile); // incomplete download
  640. LeaveCriticalSection(&m_csDownload);
  641. // Tell Setup that we're Stopping the Download
  642. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr);
  643. // Send Ping Back Status - Failed Item
  644. PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE);
  645. return dwErr;
  646. }
  647. // set the file time to match the server file time since we just downloaded it.
  648. // If we don't do this the file time will be set to the current system time.
  649. SetFileTime(hTargetFile, &ft, NULL, NULL);
  650. SafeGlobalFree(lpBuffer);
  651. SafeCloseHandle(hTargetFile);
  652. // RogerJ --- Add certificate checking code here
  653. if (FAILED(VerifyFile(szLocalFile, FALSE)))
  654. {
  655. // Send Ping Back Status - Failed Item
  656. PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE);
  657. LOG_error("CabFile %s does not have a valid Signature, deleted", szLocalFile);
  658. if (!DeleteFile(szLocalFile))
  659. {
  660. LOG_error("Failed to delete file %s --- %d", szLocalFile, GetLastError());
  661. }
  662. }
  663. else
  664. {
  665. // File Successfully Downloaded and CheckTrusted
  666. PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, TRUE);
  667. }
  668. }
  669. else
  670. {
  671. // File Currently on the System is Already Up to Date
  672. // Send Progress Message with with this file size indicating it was downloaded. This keeps the progress bar
  673. // accurate, even if we didn't actually have to download the bits.
  674. m_dwCurrentBytesDownloaded += dwFileSize;
  675. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_PROGRESS, (WPARAM) m_dwTotalDownloadSize, (LPARAM) m_dwCurrentBytesDownloaded);
  676. }
  677. // Always close the Request when the file is finished.
  678. // We intentionally leave the connection to the server Open though, seems more
  679. // efficient when requesting multiple files from the same server.
  680. SafeInternetCloseHandle(m_hOpenRequest);
  681. pszCabFile += lstrlen(pszCabFile) + 2; // advance to the next cab.
  682. } // for ()
  683. pCurrent = pCurrent->pNext;
  684. } // while ()
  685. LeaveCriticalSection(&m_csDownload);
  686. ClearDownloadItemList();
  687. SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM) DU_STATUS_SUCCESS, (LPARAM) NULL);
  688. SafeInternetCloseHandle(m_hConnect);
  689. SafeInternetCloseHandle(m_hInternet);
  690. return ERROR_SUCCESS;
  691. }
  692. DWORD WINAPI DownloadThreadProc(LPVOID lpv)
  693. {
  694. LOG_block("DownloadThreadProc()");
  695. if (NULL == lpv)
  696. {
  697. return ERROR_INVALID_PARAMETER;
  698. }
  699. CDynamicUpdate *pDu = (CDynamicUpdate *)lpv;
  700. return pDu->AsyncDownloadProc();
  701. }
  702. // RogerJ
  703. // -------------------------------------------------------------------------------------------
  704. // Function Name: IndicateDialmonActivity
  705. // Function Description: Call this function to avoid auto disconnect
  706. // Function Parameter: None
  707. // Return Value: None
  708. void IndicateDialmonActivity(void)
  709. {
  710. static HWND hwndDialmon = NULL;
  711. HWND hwndMonitor;
  712. // dialmon lives forever - find it once and we're set
  713. if(NULL == hwndDialmon)
  714. hwndDialmon = FindWindow(c_szDialmonClass, NULL);
  715. if(hwndDialmon)
  716. PostMessage(hwndDialmon, WM_WINSOCK_ACTIVITY, 0, 0);
  717. }
  718. DWORD CDynamicUpdate::PingBack(int iPingBackType, PUID puid, LPCSTR pszPnPID, BOOL fSucceeded)
  719. {
  720. LOG_block("CDynamicUpdate::PingBack()");
  721. URL_COMPONENTSA UrlComponents;
  722. DWORD dwErr, dwStatus, dwLength;
  723. LPSTR AcceptTypes[] = {"*/*", NULL};
  724. // Buffers used to Break the URL into its different components for Internet API calls
  725. char szServerName[INTERNET_MAX_URL_LENGTH + 1];
  726. char szServerRelPath[INTERNET_MAX_URL_LENGTH + 1];
  727. char szObject[INTERNET_MAX_URL_LENGTH + 1];
  728. char szUserName[UNLEN+1];
  729. char szPasswd[UNLEN+1];
  730. // We need to break down the Passed in URL into its various components for the InternetAPI Calls. Specifically we
  731. // Need the server name, object to download, username and password information.
  732. ZeroMemory(szServerName, INTERNET_MAX_URL_LENGTH + 1);
  733. ZeroMemory(szObject, INTERNET_MAX_URL_LENGTH + 1);
  734. ZeroMemory(&UrlComponents, sizeof(UrlComponents));
  735. ZeroMemory(szServerRelPath, INTERNET_MAX_URL_LENGTH + 1);
  736. UrlComponents.dwStructSize = sizeof(UrlComponents);
  737. UrlComponents.lpszHostName = szServerName;
  738. UrlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH + 1;
  739. UrlComponents.lpszUrlPath = szServerRelPath;
  740. UrlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH + 1;
  741. UrlComponents.lpszUserName = szUserName;
  742. UrlComponents.dwUserNameLength = UNLEN + 1;
  743. UrlComponents.lpszPassword = szPasswd;
  744. UrlComponents.dwPasswordLength = UNLEN + 1;
  745. if (! InternetCrackUrlA(m_pV3->m_szV31RootUrl, 0, 0, &UrlComponents) )
  746. {
  747. dwErr = GetLastError();
  748. LOG_error("InternetCrackUrl() Failed, Error: %d", dwErr);
  749. return dwErr;
  750. }
  751. // If the connection has already been established re-use it.
  752. if (NULL == m_hInternet)
  753. {
  754. if (! (m_hInternet = InternetOpenA("Dynamic Update", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)) )
  755. {
  756. dwErr = GetLastError();
  757. LOG_error("InternetOpen() Failed, Error: %d", dwErr);
  758. return dwErr;
  759. }
  760. }
  761. dwStatus = 30 * 1000; // 30 seconds in milliseconds
  762. dwLength = sizeof(dwStatus);
  763. InternetSetOptionA(m_hInternet, INTERNET_OPTION_SEND_TIMEOUT, &dwStatus, dwLength);
  764. if (NULL == m_hConnect || 0 != lstrcmpi(m_szCurrentConnectedServer, szServerName))
  765. {
  766. // No connection established yet, or we are connecting to a new server.
  767. SafeInternetCloseHandle(m_hConnect);
  768. if (! (m_hConnect = InternetConnectA(m_hInternet, szServerName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPasswd,
  769. INTERNET_SERVICE_HTTP, INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0)) )
  770. {
  771. dwErr = GetLastError();
  772. LOG_error("InternetConnect() Failed, Error: %d", dwErr);
  773. return dwErr;
  774. }
  775. lstrcpy(m_szCurrentConnectedServer, szServerName);
  776. }
  777. SafeInternetCloseHandle(m_hOpenRequest); // make sure there is no open request before creating the new one.
  778. switch(iPingBackType)
  779. {
  780. case DU_PINGBACK_DOWNLOADSTATUS:
  781. {
  782. wsprintfA(szObject, "%s/wutrack.bin?PUID=%d&PLAT=%d&LOCALE=0x%08x&STATUS=%s&GUID=&PNPID=",
  783. szServerRelPath, puid, m_iPlatformID, (long)m_lcidLocaleID, fSucceeded ? "DU_DOWNLOAD_SUCCESS" : "DU_DOWNLOAD_FAILURE");
  784. break;
  785. }
  786. case DU_PINGBACK_DRIVERNOTFOUND:
  787. {
  788. // driver not found pingback
  789. wsprintfA(szObject, "%s/wutrack.bin?PUID=0&PLAT=%d&LOCALE=0x%08x&STATUS=DUNODRIVER&GUID=0&PNPID=%s",
  790. szServerRelPath, m_iPlatformID, (long)m_lcidLocaleID, pszPnPID);
  791. break;
  792. }
  793. case DU_PINGBACK_SETUPDETECTIONFAILED:
  794. {
  795. // this is a detection failed pingback (no specific item info)
  796. wsprintfA(szObject, "%s/wutrack.bin?PUID=0&PLAT=%d&LOCALE=0x%08x&STATUS=DUSETUPDETECTIONFAILED&GUID=&PNPID=",
  797. szServerRelPath, m_iPlatformID, (long)m_lcidLocaleID);
  798. break;
  799. }
  800. case DU_PINGBACK_DRIVERDETECTIONFAILED:
  801. {
  802. // this is a detection failed pingback (no specific item info)
  803. wsprintfA(szObject, "%s/wutrack.bin?PUID=0&PLAT=%d&LOCALE=0x%08x&STATUS=DUDRIVERDETECTIONFAILED&GUID=&PNPID=",
  804. szServerRelPath, m_iPlatformID, (long)m_lcidLocaleID);
  805. break;
  806. }
  807. }
  808. LOG_out("contact server %s", szObject);
  809. if (! (m_hOpenRequest = HttpOpenRequestA(m_hConnect, NULL, szObject, NULL, NULL, (LPCSTR *)AcceptTypes,
  810. INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0)) )
  811. {
  812. dwErr = GetLastError();
  813. // log result
  814. return dwErr;
  815. }
  816. if (! HttpSendRequestA(m_hOpenRequest, NULL, 0, NULL, 0) )
  817. {
  818. dwErr = GetLastError();
  819. // log result
  820. return dwErr;
  821. }
  822. SafeInternetCloseHandle(m_hOpenRequest);
  823. return ERROR_SUCCESS;
  824. }
  825. BOOL CDynamicUpdate::NeedRetry(DWORD dwErrCode)
  826. {
  827. BOOL bRetry = FALSE;
  828. bRetry = ((dwErrCode == ERROR_INTERNET_CONNECTION_RESET) //most common
  829. || (dwErrCode == HTTP_STATUS_NOT_FOUND) //404
  830. || (dwErrCode == ERROR_HTTP_HEADER_NOT_FOUND) //seen sometimes
  831. || (dwErrCode == ERROR_INTERNET_OPERATION_CANCELLED) //dont know if..
  832. || (dwErrCode == ERROR_INTERNET_ITEM_NOT_FOUND) //..these occur..
  833. || (dwErrCode == ERROR_INTERNET_OUT_OF_HANDLES) //..but seem most..
  834. || (dwErrCode == ERROR_INTERNET_TIMEOUT)); //..likely bet
  835. return bRetry;
  836. }