|
|
#include "wsdueng.h"
DWORD WINAPI DownloadThreadProc(LPVOID lpv);
// private helper function forward declaration
// RogerJ --- Use this function to avoid auto disconnection
void IndicateDialmonActivity(void);
DWORD CDynamicUpdate::OpenHttpConnection(LPCSTR pszDownloadUrl, BOOL fGetRequest) { LOG_block("CDynamicUpdate::OpenHttpConnection()"); URL_COMPONENTSA UrlComponents; DWORD dwErr, dwStatus, dwLength; LPSTR AcceptTypes[] = {"*/*", NULL};
LOG_out("Opening HTTP URL %s", pszDownloadUrl);
dwErr = dwStatus = dwLength = 0; // Buffers used to Break the URL into its different components for Internet API calls
char szServerName[INTERNET_MAX_URL_LENGTH + 1]; char szObject[INTERNET_MAX_URL_LENGTH + 1]; char szUserName[UNLEN+1]; char szPasswd[UNLEN+1];
// We need to break down the Passed in URL into its various components for the InternetAPI Calls. Specifically we
// Need the server name, object to download, username and password information.
ZeroMemory(szServerName, INTERNET_MAX_URL_LENGTH + 1); ZeroMemory(szObject, INTERNET_MAX_URL_LENGTH + 1); ZeroMemory(&UrlComponents, sizeof(UrlComponents)); UrlComponents.dwStructSize = sizeof(UrlComponents); UrlComponents.lpszHostName = szServerName; UrlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH + 1; UrlComponents.lpszUrlPath = szObject; UrlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH + 1; UrlComponents.lpszUserName = szUserName; UrlComponents.dwUserNameLength = UNLEN + 1; UrlComponents.lpszPassword = szPasswd; UrlComponents.dwPasswordLength = UNLEN + 1;
if (! InternetCrackUrlA(pszDownloadUrl, 0, 0, &UrlComponents) ) { dwErr = GetLastError(); LOG_error("InternetCrackUrl() Failed, Error: %d", dwErr); return dwErr; }
// If the connection has already been established re-use it.
if (NULL == m_hInternet) { if (! (m_hInternet = InternetOpenA("Dynamic Update", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)) ) { dwErr = GetLastError(); LOG_error("InternetOpen() Failed, Error: %d", dwErr); return dwErr; } }
dwStatus = 30 * 1000; // 30 seconds in milliseconds
dwLength = sizeof(dwStatus); InternetSetOptionA(m_hInternet, INTERNET_OPTION_SEND_TIMEOUT, &dwStatus, dwLength);
if (NULL == m_hConnect || 0 != lstrcmpi(m_szCurrentConnectedServer, szServerName)) { // No connection established yet, or we are connecting to a new server.
SafeInternetCloseHandle(m_hConnect); if (! (m_hConnect = InternetConnectA(m_hInternet, szServerName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPasswd, INTERNET_SERVICE_HTTP, INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0)) ) { dwErr = GetLastError(); LOG_error("InternetConnect() Failed, Error: %d", dwErr); return dwErr; } lstrcpy(m_szCurrentConnectedServer, szServerName); }
SafeInternetCloseHandle(m_hOpenRequest); // make sure there is no open request before creating the new one.
if (! (m_hOpenRequest = HttpOpenRequestA(m_hConnect, (fGetRequest) ? NULL : "HEAD", szObject, NULL, NULL, (LPCSTR *)AcceptTypes, INTERNET_FLAG_NO_UI, 0)) ) { dwErr = GetLastError(); // log result
return dwErr; }
int nNumOfTrial = 0; do { if (! HttpSendRequestA(m_hOpenRequest, NULL, 0, NULL, 0) ) { dwErr = GetLastError(); // log result
return dwErr; }
dwLength = sizeof(dwStatus); if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwStatus, &dwLength, NULL) ) { dwErr = GetLastError(); // log result
return dwErr; } nNumOfTrial ++; } while (NeedRetry(dwStatus) && nNumOfTrial < DU_CONNECTION_RETRY);
// If the Request did not succeed we'll assume we have no internet connection and return the Error Code
// that Setup will trigger a warning to the user to manually establish a connection.
if ((HTTP_STATUS_OK != dwStatus) && (HTTP_STATUS_PARTIAL_CONTENT != dwStatus)) { LOG_error("Http Status NOT OK, Status %d", dwStatus); if (HTTP_STATUS_NOT_FOUND == dwStatus) return ERROR_INTERNET_INVALID_URL; else return ERROR_CONNECTION_UNAVAIL; }
return ERROR_SUCCESS; }
DWORD CDynamicUpdate::DownloadFilesAsync() { LOG_block("CDynamicUpdate::DownloadFileAsync()"); DWORD dwThreadID; DWORD dwErr;
SafeCloseHandle(m_hDownloadThreadProc); m_hDownloadThreadProc = CreateThread(NULL, 0, DownloadThreadProc, (void *)this, 0, &dwThreadID); if (NULL == m_hDownloadThreadProc) { dwErr = GetLastError(); LOG_error("Unable to CreateThread for ASynch Download, Error %d", dwErr); return dwErr; }
SetThreadPriority(m_hDownloadThreadProc, THREAD_PRIORITY_NORMAL); return ERROR_SUCCESS; }
DWORD CDynamicUpdate::DownloadFile(LPCSTR pszDownloadUrl, LPCSTR pszLocalFile, BOOL fDecompress, BOOL fCheckTrust) { LOG_block("CDynamicUpdate::DownloadFile()"); DWORD dwErr, dwFileSize, dwLength; DWORD dwBytesRead, dwBytesWritten; DWORD dwCount1, dwCount2, dwTimeElapsed; SYSTEMTIME st; FILETIME ft; HANDLE hTargetFile;
SetLastError(0); dwErr = OpenHttpConnection(pszDownloadUrl, FALSE); if (ERROR_SUCCESS != dwErr) { // log error
return dwErr; }
dwLength = sizeof(st); if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME, (LPVOID)&st, &dwLength, NULL) ) { dwErr = GetLastError(); LOG_error("HttpQueryInfo Failed on File %s, Error %d", pszDownloadUrl, dwErr); SafeInternetCloseHandle(m_hOpenRequest); return dwErr; }
SystemTimeToFileTime(&st, &ft);
// Now Get the FileSize information from the Server
dwLength = sizeof(dwFileSize); if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwFileSize, &dwLength, NULL) ) { dwErr = GetLastError(); LOG_error("HttpQueryInfo Failed on File %s, Error %d", pszDownloadUrl, dwErr); SafeInternetCloseHandle(m_hOpenRequest); return dwErr; }
if (IsServerFileNewer(ft, dwFileSize, pszLocalFile)) { dwErr = OpenHttpConnection(pszDownloadUrl, TRUE); // need to download the file, send the GET request this time
if (ERROR_SUCCESS != dwErr) { // log error
return dwErr; } #define DOWNLOAD_BUFFER_LENGTH 32 * 1024
PBYTE lpBuffer = (PBYTE) GlobalAlloc(GMEM_ZEROINIT, DOWNLOAD_BUFFER_LENGTH); if (NULL == lpBuffer) { dwErr = GetLastError(); LOG_error("Failed to Allocate Memory for Download Buffer, Error %d", dwErr); SafeInternetCloseHandle(m_hOpenRequest); return dwErr; }
hTargetFile = CreateFileA(pszLocalFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hTargetFile) { dwErr = GetLastError(); LOG_error("Failed to Open Target File %s, Error %d", pszLocalFile, dwErr); SafeGlobalFree(lpBuffer); SafeInternetCloseHandle(m_hOpenRequest); return dwErr; }
// Download the File
BOOL fRet; while (fRet = InternetReadFile(m_hOpenRequest, lpBuffer, DOWNLOAD_BUFFER_LENGTH, &dwBytesRead)) { if (0 == dwBytesRead) { // Make one final call to InternetReadFile to commit the file to Cache (download is not complete otherwise)
BYTE bTemp[32]; InternetReadFile(m_hOpenRequest, &bTemp, 32, &dwBytesRead); // set the file time to match the server file time since we just downloaded it.
// If we don't do this the file time will be set to the current system time.
SetFileTime(hTargetFile, &ft, NULL, NULL); break; // done reading.
} if (!WriteFile(hTargetFile, lpBuffer, dwBytesRead, &dwBytesWritten, NULL)) { LOG_error("Failed to Write to File %s, Error %d", pszLocalFile, dwErr); dwErr = GetLastError(); SafeGlobalFree(lpBuffer); SafeInternetCloseHandle(m_hOpenRequest); SafeCloseHandle(hTargetFile); return dwErr; } }
if (!fRet) { dwErr = GetLastError(); SafeCloseHandle(hTargetFile); DeleteFile(pszLocalFile); // delete the file that we just had an error during downloading
SafeGlobalFree(lpBuffer); LOG_error("InternetReadFile Failed, Error %d", dwErr); return dwErr; } SafeGlobalFree(lpBuffer); SafeCloseHandle(hTargetFile);
// check for decompress requested
if (fCheckTrust) { // Use VerifyFile() to verifty the cert of the downloaded component
// change made by ROGERJ at Sept. 25th, 2000
if (FAILED(VerifyFile(pszLocalFile, FALSE))) { LOG_error("CabFile %s does not have a valid Signature", pszLocalFile); DeleteFile(pszLocalFile); // not trusted, nuke it.
} }
if (fDecompress) { char szLocalDir[MAX_PATH]; lstrcpy(szLocalDir, pszLocalFile); PathRemoveFileSpec(szLocalDir); fdi(const_cast<char *>(pszLocalFile), szLocalDir); } }
// Always close the Request when the file is finished.
// We intentionally leave the connection to the server Open though, seems more
// efficient when requesting multiple files from the same server.
SafeInternetCloseHandle(m_hOpenRequest);
return ERROR_SUCCESS; }
DWORD CDynamicUpdate::DownloadFileToMem(LPCSTR pszDownloadUrl, PBYTE *lpBuffer, DWORD *pdwAllocatedLength, BOOL fDecompress, LPSTR pszFileName, LPSTR pszDecompresedFileName) { LOG_block("CDynamicUpdate::DownloadFileToMem()"); DWORD dwErr, dwFileSize, dwLength; DWORD dwBytesRead, dwBytesWritten; DWORD dwCount1, dwCount2, dwTimeElapsed; SYSTEMTIME st; FILETIME ft; HANDLE hTargetFile;
dwErr = OpenHttpConnection(pszDownloadUrl, TRUE); if (ERROR_SUCCESS != dwErr) { // log error
SetLastError(dwErr); return dwErr; }
dwLength = sizeof(st); if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME, (LPVOID)&st, &dwLength, NULL) ) { dwErr = GetLastError(); // log error
SafeInternetCloseHandle(m_hOpenRequest); return dwErr; }
SystemTimeToFileTime(&st, &ft);
// Now Get the FileSize information from the Server
dwLength = sizeof(dwFileSize); if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwFileSize, &dwLength, NULL) ) { dwErr = GetLastError(); // log error
SafeInternetCloseHandle(m_hOpenRequest); return dwErr; }
*lpBuffer = (PBYTE) GlobalAlloc(GMEM_ZEROINIT, dwFileSize); if (NULL == *lpBuffer) { dwErr = GetLastError(); // log error
SafeInternetCloseHandle(m_hOpenRequest); return dwErr; } *pdwAllocatedLength = dwFileSize;
// Read the whole file
if (!InternetReadFile(m_hOpenRequest, *lpBuffer, dwFileSize, &dwBytesRead)) { dwErr = GetLastError(); LOG_error("Internet Read File Failed, Error %d", dwErr); SafeInternetCloseHandle(m_hOpenRequest); return dwErr; }
if (fDecompress) { char szLocalFile[MAX_PATH]; char szLocalFileTmp[MAX_PATH]; if (NULL != pszDecompresedFileName) { char szCatalogName[MAX_PATH]; PathCombine(szLocalFile, m_szTempPath, pszDecompresedFileName); wsprintf(szCatalogName, "%s.tmp", pszFileName); PathCombine(szLocalFileTmp, m_szTempPath, szCatalogName); } else { PathCombine(szLocalFile, m_szTempPath, pszFileName); wsprintf(szLocalFileTmp, "%s.tmp", szLocalFile); } HANDLE hFile = CreateFile(szLocalFileTmp, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { LOG_error("Unable to write temp file for decompress"); return GetLastError(); } DWORD dwTmp; WriteFile(hFile, *lpBuffer, dwFileSize, &dwTmp, NULL); FlushFileBuffers(hFile); SafeCloseHandle(hFile); if (fdi(szLocalFileTmp, m_szTempPath)) { // file was decompressed
hFile = CreateFile(szLocalFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hFile) { LOG_error("Unable to Read decompressed file %s", szLocalFile); SafeInternetCloseHandle(m_hOpenRequest); DeleteFile(szLocalFileTmp); return GetLastError(); } dwFileSize = GetFileSize(hFile, NULL); SafeGlobalFree(*lpBuffer); *lpBuffer = (PBYTE) GlobalAlloc(GMEM_ZEROINIT, dwFileSize); *pdwAllocatedLength = dwFileSize; if (!ReadFile(hFile, *lpBuffer, dwFileSize, &dwTmp, NULL)) { dwErr = GetLastError(); LOG_error("ReadFile %s Failed, Error %d", szLocalFile, dwErr); SafeInternetCloseHandle(m_hOpenRequest); SafeCloseHandle(hFile); DeleteFile(szLocalFile); DeleteFile(szLocalFileTmp); return dwErr; }
SafeCloseHandle(hFile); DeleteFile(szLocalFile); } DeleteFile(szLocalFileTmp); }
// Make one final call to InternetReadFile to commit the file to Cache (downloaded is not complete otherwise)
BYTE bTemp[32]; InternetReadFile(m_hOpenRequest, &bTemp, 32, &dwBytesRead);
// Always close the Request when the file is finished.
// We intentionally leave the connection to the server Open though, seems more
// efficient when requesting multiple files from the same server.
SafeInternetCloseHandle(m_hOpenRequest); return ERROR_SUCCESS; }
BOOL CDynamicUpdate::IsServerFileNewer(FILETIME ftServerTime, DWORD dwServerFileSize, LPCSTR pszLocalFile) { HANDLE hFile = INVALID_HANDLE_VALUE; FILETIME ftCreateTime; LONG lTime; DWORD dwLocalFileSize;
hFile = CreateFile(pszLocalFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE != hFile) { dwLocalFileSize = GetFileSize(hFile, NULL); if (dwLocalFileSize != dwServerFileSize) { SafeCloseHandle(hFile); return TRUE; // server and local files do not match, download server file.
} if (GetFileTime(hFile, &ftCreateTime, NULL, NULL)) { lTime = CompareFileTime(&ftCreateTime, &ftServerTime); if (lTime < 0) { SafeCloseHandle(hFile); return TRUE; // local file is 'older' than the server file
} else { SafeCloseHandle(hFile); return FALSE; // local file is either equal or newer, leave it.
} } } // if we couldn't find the file, or we couldn't get the time, assume the server file is newer
SafeCloseHandle(hFile); return TRUE; }
DWORD CDynamicUpdate::AsyncDownloadProc() { LOG_block("CDynamicUpdate::AsyncDownloadProc()"); char szServerFile[INTERNET_MAX_URL_LENGTH]; char szLocalFile[MAX_PATH]; DWORD dwErr = 0, dwFileSize = 0, dwLength = 0; DWORD dwBytesRead = 0, dwBytesWritten = 0; SYSTEMTIME st; FILETIME ft; HANDLE hTargetFile = INVALID_HANDLE_VALUE; BOOL fAbort = FALSE; BOOL fRet = TRUE; // The Download Thread Proc handles downloading all the files from the DownloadItemList in the DynamicUpdate object.
// It will enumerate the list of items to download, make callbacks to the HWND in the dynamic update object in 1% intervals
// and a final callback when it is complete. It will also check for cancel requests after downloading each 1k block from the
// server. We do this in this small of a block to retain some responsiveness to the UI requests.
EnterCriticalSection(&m_csDownload);
DOWNLOADITEM *pCurrent = m_pDownloadItemList; while (pCurrent) { // Update the Cab Size for the Current Item and Recalc the total download size
// We do this because the Estimated Download Size can be 'less' than the real download size.
// When providing progress this causes the progress bar to go beyond 100%, which is wrong.
LPSTR pszCabFile = pCurrent->mszFileList; DWORD dwCurrentItemSize = 0; for (int i = 0; i < pCurrent->iNumberOfCabs; i++) { DuUrlCombine(szServerFile, m_pV3->m_szCabPoolUrl, pszCabFile); dwErr = OpenHttpConnection(szServerFile, FALSE); if (ERROR_SUCCESS != dwErr) { LeaveCriticalSection(&m_csDownload); LOG_error("Failed to Open Connection for %s, Error Was %d", szServerFile, dwErr); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); // Send Ping Back Status - Failed Item
PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE); return dwErr; } // Now Get the FileSize information from the Server
dwLength = sizeof(dwFileSize); if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwFileSize, &dwLength, NULL) ) { dwErr = GetLastError(); LOG_error("HttpQueryInfo Failed on File %s, Error %d, Skipping Item", szServerFile, dwErr); SafeInternetCloseHandle(m_hOpenRequest); LeaveCriticalSection(&m_csDownload); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); // Send Ping Back Status - Failed Item
PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE); return dwErr; } SafeInternetCloseHandle(m_hOpenRequest); dwCurrentItemSize += dwFileSize; pszCabFile += lstrlen(pszCabFile) + 2; // advance to the next cab.
} pCurrent->dwTotalFileSize = dwCurrentItemSize; // download size in Bytes.
pCurrent = pCurrent->pNext; }
m_dwCurrentBytesDownloaded = 0; UpdateDownloadItemSize(); // We want to Send a Progress Message Every 1 Percent of the Download.
DWORD dwBytesPerPercent = m_dwTotalDownloadSize / 100; // in case the
if (0 == dwBytesPerPercent) { dwBytesPerPercent = 1; // must be at least 1 byte, cannot be zero
} DWORD dwCurrentPercentComplete = 0;
// Now we will start looping through the Items and Download the Files.
pCurrent = m_pDownloadItemList; while (pCurrent) { EnterCriticalSection(&m_cs); fAbort = m_fAbortDownload; LeaveCriticalSection(&m_cs); if (fAbort) { // check for abort for each item
LeaveCriticalSection(&m_csDownload); SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM) DU_STATUS_ABORT, (LPARAM) NULL); SafeInternetCloseHandle(m_hConnect); SafeInternetCloseHandle(m_hInternet); m_fAbortDownload = FALSE; // reset
return ERROR_SUCCESS; } // RogerJ --- call IndicateDialmonActivity() to avoid auto disconnection
else IndicateDialmonActivity();
// Each 'Item' can have more than one Cab. The Setup Item itself will usually have 3 cabs, Drivers will probably only have 1 cab.
LPSTR pszCabFile = pCurrent->mszFileList; for (int i = 0; i < pCurrent->iNumberOfCabs; i++) { pCurrent->iCurrentCab = i; DuUrlCombine(szServerFile, m_pV3->m_szCabPoolUrl, pszCabFile); // current cab is the null terminated cab name in the list
WUCRC_HASH crc; char szShortName[MAX_PATH]; // for trimmed filename
if (FAILED(SplitCRCName((LPCSTR)pszCabFile, &crc, szShortName))) { lstrcpy(szShortName, pszCabFile); // probably not a CRC'd file
}
PathCombine(szLocalFile, m_szDownloadPath, szShortName);
// Now open the HttpConnection to get this file
dwErr = OpenHttpConnection(szServerFile, FALSE); if (ERROR_SUCCESS != dwErr) { LeaveCriticalSection(&m_csDownload); LOG_error("Failed to Open Connection for %s, Error Was %d", szServerFile, dwErr); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); // Send Ping Back Status - Failed Item
PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE); return dwErr; }
dwLength = sizeof(st); if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_LAST_MODIFIED | HTTP_QUERY_FLAG_SYSTEMTIME, (LPVOID)&st, &dwLength, NULL) ) { LeaveCriticalSection(&m_csDownload); dwErr = GetLastError(); LOG_error("HttpQueryInfo Failed on File %s, Error %d, Skipping Item", szServerFile, dwErr); SafeInternetCloseHandle(m_hOpenRequest); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); // Send Ping Back Status - Failed Item
PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE); return dwErr; }
SystemTimeToFileTime(&st, &ft);
// Now Get the FileSize information from the Server
dwLength = sizeof(dwFileSize); if (! HttpQueryInfoA(m_hOpenRequest, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwFileSize, &dwLength, NULL) ) { dwErr = GetLastError(); LOG_error("HttpQueryInfo Failed on File %s, Error %d, Skipping Item", szServerFile, dwErr); SafeInternetCloseHandle(m_hOpenRequest); LeaveCriticalSection(&m_csDownload); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); // Send Ping Back Status - Failed Item
PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE); return dwErr; }
if (IsServerFileNewer(ft, dwFileSize, szLocalFile)) { dwErr = OpenHttpConnection(szServerFile, TRUE); if (ERROR_SUCCESS != dwErr) { LeaveCriticalSection(&m_csDownload); LOG_error("Failed to Open Connection for %s, Error Was %d", szServerFile, dwErr); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); return dwErr; }
#define ASYNC_DOWNLOAD_BUFFER_LENGTH 1 * 1024 // download in 1k blocks to maintain UI responsiveness to a cancel request.
PBYTE lpBuffer = (PBYTE) GlobalAlloc(GMEM_ZEROINIT, ASYNC_DOWNLOAD_BUFFER_LENGTH); if (NULL == lpBuffer) { dwErr = GetLastError(); LOG_error("Failed to Allocate Memory for Download Buffer, Error %d", dwErr); SafeInternetCloseHandle(m_hOpenRequest); LeaveCriticalSection(&m_csDownload); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); return dwErr; }
hTargetFile = CreateFileA(szLocalFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == hTargetFile) { dwErr = GetLastError(); LOG_error("Failed to Open Target File %s, Error %d", szLocalFile, dwErr); SafeGlobalFree(lpBuffer); SafeInternetCloseHandle(m_hOpenRequest); LeaveCriticalSection(&m_csDownload); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); return dwErr; }
// Download the File
while (fRet = InternetReadFile(m_hOpenRequest, lpBuffer, ASYNC_DOWNLOAD_BUFFER_LENGTH, &dwBytesRead)) { if (0 == dwBytesRead) // done reading
{ // Make one final call to InternetReadFile to commit the file to Cache (download is not complete otherwise)
BYTE bTemp[32]; InternetReadFile(m_hOpenRequest, &bTemp, 32, &dwBytesRead); break; // done reading.
}
EnterCriticalSection(&m_cs); fAbort = m_fAbortDownload; LeaveCriticalSection(&m_cs); if (fAbort) { // Download Abort Requested, Clean Up, Signal the Complete Message and exit the Thread Proc
SafeCloseHandle(hTargetFile); DeleteFile(szLocalFile); // file not complete
SafeInternetCloseHandle(m_hOpenRequest); SafeInternetCloseHandle(m_hConnect); SafeInternetCloseHandle(m_hInternet); SafeGlobalFree(lpBuffer); LeaveCriticalSection(&m_csDownload); m_fAbortDownload = FALSE; // reset
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_ABORT , (LPARAM) NULL); return ERROR_SUCCESS; // cancel is not an error
} // RogerJ --- call IndicateDialmonActivity() to avoid auto disconnection
else IndicateDialmonActivity();
if (!WriteFile(hTargetFile, lpBuffer, dwBytesRead, &dwBytesWritten, NULL)) { dwErr = GetLastError(); LOG_error("Failed to Write to File %s, Error %d", szLocalFile, dwErr); SafeGlobalFree(lpBuffer); SafeInternetCloseHandle(m_hOpenRequest); SafeCloseHandle(hTargetFile); DeleteFile(szLocalFile); // incomplete download
LeaveCriticalSection(&m_csDownload); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); return dwErr; } m_dwCurrentBytesDownloaded += dwBytesRead; dwCurrentPercentComplete = m_dwCurrentBytesDownloaded / dwBytesPerPercent; if (dwCurrentPercentComplete != m_dwLastPercentComplete) { // We've downloaded another percent of the total size.. Send a Progress Message
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_PROGRESS, (WPARAM)m_dwTotalDownloadSize, (LPARAM)m_dwCurrentBytesDownloaded); m_dwLastPercentComplete = dwCurrentPercentComplete; } }
// indicates error during InternetReadFile process
if (!fRet) { dwErr = GetLastError(); LOG_error("InternetReadFile Failed, Error %d", dwErr); SafeGlobalFree(lpBuffer); SafeInternetCloseHandle(m_hOpenRequest); SafeCloseHandle(hTargetFile); DeleteFile(szLocalFile); // incomplete download
LeaveCriticalSection(&m_csDownload); // Tell Setup that we're Stopping the Download
SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM)DU_STATUS_FAILED, (LPARAM) dwErr); // Send Ping Back Status - Failed Item
PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE); return dwErr; }
// set the file time to match the server file time since we just downloaded it.
// If we don't do this the file time will be set to the current system time.
SetFileTime(hTargetFile, &ft, NULL, NULL); SafeGlobalFree(lpBuffer); SafeCloseHandle(hTargetFile);
// RogerJ --- Add certificate checking code here
if (FAILED(VerifyFile(szLocalFile, FALSE))) { // Send Ping Back Status - Failed Item
PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, FALSE);
LOG_error("CabFile %s does not have a valid Signature, deleted", szLocalFile); if (!DeleteFile(szLocalFile)) { LOG_error("Failed to delete file %s --- %d", szLocalFile, GetLastError()); } } else { // File Successfully Downloaded and CheckTrusted
PingBack(DU_PINGBACK_DOWNLOADSTATUS, pCurrent->puid, NULL, TRUE); } } else { // File Currently on the System is Already Up to Date
// Send Progress Message with with this file size indicating it was downloaded. This keeps the progress bar
// accurate, even if we didn't actually have to download the bits.
m_dwCurrentBytesDownloaded += dwFileSize; SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_PROGRESS, (WPARAM) m_dwTotalDownloadSize, (LPARAM) m_dwCurrentBytesDownloaded); }
// Always close the Request when the file is finished.
// We intentionally leave the connection to the server Open though, seems more
// efficient when requesting multiple files from the same server.
SafeInternetCloseHandle(m_hOpenRequest); pszCabFile += lstrlen(pszCabFile) + 2; // advance to the next cab.
} // for ()
pCurrent = pCurrent->pNext; } // while ()
LeaveCriticalSection(&m_csDownload); ClearDownloadItemList(); SendMessage(m_hwndClientNotify, WM_DYNAMIC_UPDATE_COMPLETE, (WPARAM) DU_STATUS_SUCCESS, (LPARAM) NULL); SafeInternetCloseHandle(m_hConnect); SafeInternetCloseHandle(m_hInternet); return ERROR_SUCCESS; }
DWORD WINAPI DownloadThreadProc(LPVOID lpv) { LOG_block("DownloadThreadProc()");
if (NULL == lpv) { return ERROR_INVALID_PARAMETER; }
CDynamicUpdate *pDu = (CDynamicUpdate *)lpv; return pDu->AsyncDownloadProc(); }
// RogerJ
// -------------------------------------------------------------------------------------------
// Function Name: IndicateDialmonActivity
// Function Description: Call this function to avoid auto disconnect
// Function Parameter: None
// Return Value: None
void IndicateDialmonActivity(void) { static HWND hwndDialmon = NULL; HWND hwndMonitor;
// dialmon lives forever - find it once and we're set
if(NULL == hwndDialmon) hwndDialmon = FindWindow(c_szDialmonClass, NULL); if(hwndDialmon) PostMessage(hwndDialmon, WM_WINSOCK_ACTIVITY, 0, 0); }
DWORD CDynamicUpdate::PingBack(int iPingBackType, PUID puid, LPCSTR pszPnPID, BOOL fSucceeded) { LOG_block("CDynamicUpdate::PingBack()"); URL_COMPONENTSA UrlComponents; DWORD dwErr, dwStatus, dwLength; LPSTR AcceptTypes[] = {"*/*", NULL};
// Buffers used to Break the URL into its different components for Internet API calls
char szServerName[INTERNET_MAX_URL_LENGTH + 1]; char szServerRelPath[INTERNET_MAX_URL_LENGTH + 1]; char szObject[INTERNET_MAX_URL_LENGTH + 1]; char szUserName[UNLEN+1]; char szPasswd[UNLEN+1];
// We need to break down the Passed in URL into its various components for the InternetAPI Calls. Specifically we
// Need the server name, object to download, username and password information.
ZeroMemory(szServerName, INTERNET_MAX_URL_LENGTH + 1); ZeroMemory(szObject, INTERNET_MAX_URL_LENGTH + 1); ZeroMemory(&UrlComponents, sizeof(UrlComponents)); ZeroMemory(szServerRelPath, INTERNET_MAX_URL_LENGTH + 1); UrlComponents.dwStructSize = sizeof(UrlComponents); UrlComponents.lpszHostName = szServerName; UrlComponents.dwHostNameLength = INTERNET_MAX_URL_LENGTH + 1; UrlComponents.lpszUrlPath = szServerRelPath; UrlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH + 1; UrlComponents.lpszUserName = szUserName; UrlComponents.dwUserNameLength = UNLEN + 1; UrlComponents.lpszPassword = szPasswd; UrlComponents.dwPasswordLength = UNLEN + 1;
if (! InternetCrackUrlA(m_pV3->m_szV31RootUrl, 0, 0, &UrlComponents) ) { dwErr = GetLastError(); LOG_error("InternetCrackUrl() Failed, Error: %d", dwErr); return dwErr; }
// If the connection has already been established re-use it.
if (NULL == m_hInternet) { if (! (m_hInternet = InternetOpenA("Dynamic Update", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0)) ) { dwErr = GetLastError(); LOG_error("InternetOpen() Failed, Error: %d", dwErr); return dwErr; } }
dwStatus = 30 * 1000; // 30 seconds in milliseconds
dwLength = sizeof(dwStatus); InternetSetOptionA(m_hInternet, INTERNET_OPTION_SEND_TIMEOUT, &dwStatus, dwLength);
if (NULL == m_hConnect || 0 != lstrcmpi(m_szCurrentConnectedServer, szServerName)) { // No connection established yet, or we are connecting to a new server.
SafeInternetCloseHandle(m_hConnect); if (! (m_hConnect = InternetConnectA(m_hInternet, szServerName, INTERNET_DEFAULT_HTTP_PORT, szUserName, szPasswd, INTERNET_SERVICE_HTTP, INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0)) ) { dwErr = GetLastError(); LOG_error("InternetConnect() Failed, Error: %d", dwErr); return dwErr; } lstrcpy(m_szCurrentConnectedServer, szServerName); }
SafeInternetCloseHandle(m_hOpenRequest); // make sure there is no open request before creating the new one.
switch(iPingBackType) { case DU_PINGBACK_DOWNLOADSTATUS: { wsprintfA(szObject, "%s/wutrack.bin?PUID=%d&PLAT=%d&LOCALE=0x%08x&STATUS=%s&GUID=&PNPID=", szServerRelPath, puid, m_iPlatformID, (long)m_lcidLocaleID, fSucceeded ? "DU_DOWNLOAD_SUCCESS" : "DU_DOWNLOAD_FAILURE"); break; } case DU_PINGBACK_DRIVERNOTFOUND: { // driver not found pingback
wsprintfA(szObject, "%s/wutrack.bin?PUID=0&PLAT=%d&LOCALE=0x%08x&STATUS=DUNODRIVER&GUID=0&PNPID=%s", szServerRelPath, m_iPlatformID, (long)m_lcidLocaleID, pszPnPID); break; } case DU_PINGBACK_SETUPDETECTIONFAILED: { // this is a detection failed pingback (no specific item info)
wsprintfA(szObject, "%s/wutrack.bin?PUID=0&PLAT=%d&LOCALE=0x%08x&STATUS=DUSETUPDETECTIONFAILED&GUID=&PNPID=", szServerRelPath, m_iPlatformID, (long)m_lcidLocaleID); break; } case DU_PINGBACK_DRIVERDETECTIONFAILED: { // this is a detection failed pingback (no specific item info)
wsprintfA(szObject, "%s/wutrack.bin?PUID=0&PLAT=%d&LOCALE=0x%08x&STATUS=DUDRIVERDETECTIONFAILED&GUID=&PNPID=", szServerRelPath, m_iPlatformID, (long)m_lcidLocaleID); break; } }
LOG_out("contact server %s", szObject); if (! (m_hOpenRequest = HttpOpenRequestA(m_hConnect, NULL, szObject, NULL, NULL, (LPCSTR *)AcceptTypes, INTERNET_FLAG_NO_UI | INTERNET_FLAG_RELOAD, 0)) ) { dwErr = GetLastError(); // log result
return dwErr; }
if (! HttpSendRequestA(m_hOpenRequest, NULL, 0, NULL, 0) ) { dwErr = GetLastError(); // log result
return dwErr; } SafeInternetCloseHandle(m_hOpenRequest); return ERROR_SUCCESS;
}
BOOL CDynamicUpdate::NeedRetry(DWORD dwErrCode) { BOOL bRetry = FALSE; bRetry = ((dwErrCode == ERROR_INTERNET_CONNECTION_RESET) //most common
|| (dwErrCode == HTTP_STATUS_NOT_FOUND) //404
|| (dwErrCode == ERROR_HTTP_HEADER_NOT_FOUND) //seen sometimes
|| (dwErrCode == ERROR_INTERNET_OPERATION_CANCELLED) //dont know if..
|| (dwErrCode == ERROR_INTERNET_ITEM_NOT_FOUND) //..these occur..
|| (dwErrCode == ERROR_INTERNET_OUT_OF_HANDLES) //..but seem most..
|| (dwErrCode == ERROR_INTERNET_TIMEOUT)); //..likely bet
return bRetry; }
|