windows-nt/Source/XPSP1/NT/enduser/windows.com/wuv3/wsdu/wsdueng/download.cpp
2020-09-26 16:20:57 +08:00

941 lines
37 KiB
C++

#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;
}