/******************************************************************** Copyright (c) 2001 Microsoft Corporation Module Name: pcache.cpp Revision History: DerekM created 11/26/01 ********************************************************************/ #if defined(UNICODE) #include #include "dlcache.h" #include #include // ************************************************************************** inline DWORD RolloverSubtract(DWORD dwA, DWORD dwB) { return (dwA >= dwB) ? (dwA - dwB) : (dwA + ((DWORD)-1 - dwB)); } // ************************************************************************** CWUDLProxyCache::CWUDLProxyCache() { m_rgpObj = NULL; } // ************************************************************************** CWUDLProxyCache::~CWUDLProxyCache() { this->Empty(); } // ************************************************************************** SWUDLProxyCacheObj *CWUDLProxyCache::internalFind(LPCWSTR wszSrv) { SWUDLProxyCacheObj *pObj = m_rgpObj; SWUDLProxyCacheObj **ppNextPtr = &m_rgpObj; // see if it exists while(pObj != NULL) { if (pObj->wszSrv != NULL && _wcsicmp(pObj->wszSrv, wszSrv) == 0) { // detach it from the list *ppNextPtr = pObj->pNext; pObj->pNext = NULL; break; } ppNextPtr = &pObj->pNext; pObj = pObj->pNext; } return pObj; } // ************************************************************************** BOOL CWUDLProxyCache::Set(LPCWSTR wszSrv, LPCWSTR wszProxy, LPCWSTR wszBypass, DWORD dwAccessType) { SWUDLProxyCacheObj *pObj = NULL; HRESULT hr = NOERROR; DWORD cbProxy = 0, cbBypass = 0, cbSrv, cbNeed; BOOL fRet = FALSE; if (wszSrv == NULL || *wszSrv == L'\0') { SetLastError(ERROR_INVALID_PARAMETER); goto done; } cbSrv = (wcslen(wszSrv) + 1) * sizeof(WCHAR); cbNeed = cbSrv + sizeof(SWUDLProxyCacheObj); if (wszProxy != NULL) { cbProxy = (wcslen(wszProxy) + 1) * sizeof(WCHAR); cbNeed += cbProxy; if (wszBypass != NULL) { cbBypass = (wcslen(wszBypass) + 1) * sizeof(WCHAR); cbNeed += cbBypass; } } // Now, in theory, we should look for an existing object in the list for this // server, but a couple things make it unnecessary: // 1. we only use this class in one place // 2. we will always attempt a find first // 3. we will only get to this function if find returns NULL // 4. if one exists, but it's outdated, find will delete it and return NULL // // Given the above, there should never be an existing object when Set is // called. pObj = (SWUDLProxyCacheObj *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNeed); if (pObj == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto done; } // set up pointers into the blob for the strings & copy the data down pObj->wszSrv = (LPWSTR)((LPBYTE)pObj + sizeof(SWUDLProxyCacheObj)); hr = StringCbCopyExW(pObj->wszSrv, cbSrv, wszSrv, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); goto done; } if (wszProxy != NULL) { pObj->wszProxy = (LPWSTR)((LPBYTE)pObj->wszSrv + cbSrv); hr = StringCbCopyExW(pObj->wszProxy, cbProxy, wszProxy, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); goto done; } if (wszBypass != NULL) { pObj->wszBypass = (LPWSTR)((LPBYTE)pObj->wszProxy + cbProxy); hr = StringCbCopyExW(pObj->wszBypass, cbBypass, wszBypass, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); goto done; } } } pObj->dwLastCacheTime = GetTickCount(); pObj->dwAccessType = dwAccessType; pObj->cbBypass = cbBypass; pObj->cbProxy = cbProxy; pObj->iLastKnownGood = (DWORD)-1; pObj->pNext = m_rgpObj; m_rgpObj = pObj; pObj = NULL; fRet = TRUE; done: if (pObj != NULL) HeapFree(GetProcessHeap(), 0, pObj); return fRet; } // ************************************************************************** BOOL CWUDLProxyCache::Find(LPCWSTR wszSrv, LPWSTR *pwszProxy, LPWSTR *pwszBypass, DWORD *pdwAccessType) { SWUDLProxyCacheObj *pObj = NULL; HRESULT hr = NOERROR; LPWSTR wszProxy = NULL; LPWSTR wszBypass = NULL; DWORD dwNow; BOOL fRet = FALSE, fFreeObjMemory = FALSE; if (wszSrv == NULL || pwszProxy == NULL || pwszBypass == NULL || pdwAccessType == NULL) { SetLastError(ERROR_INVALID_PARAMETER); goto done; } *pdwAccessType = 0; *pwszBypass = NULL; *pwszProxy = NULL; // does it exist? pObj = this->internalFind(wszSrv); if (pObj == NULL) goto done; // has the object expired? dwNow = GetTickCount(); if (RolloverSubtract(dwNow, pObj->dwLastCacheTime) > c_dwProxyCacheTimeLimit) { fFreeObjMemory = TRUE; goto done; } // reset object to front of list pObj->pNext = m_rgpObj; m_rgpObj = pObj; // need to use GloablAlloc here cuz that's what WinHttp uses and we need // to match it if (pObj->cbBypass > 0 && pObj->wszBypass != NULL) { wszBypass = (LPWSTR)GlobalAlloc(GMEM_FIXED, pObj->cbBypass); if (wszBypass == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto done; } hr = StringCbCopyExW(wszBypass, pObj->cbBypass, pObj->wszBypass, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); goto done; } } if (pObj->cbProxy > 0 && pObj->wszProxy != NULL) { wszProxy = (LPWSTR)GlobalAlloc(GMEM_FIXED, pObj->cbProxy); if (wszProxy == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto done; } hr = StringCbCopyExW(wszProxy, pObj->cbProxy, pObj->wszProxy, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); goto done; } } *pdwAccessType = pObj->dwAccessType; *pwszBypass = wszBypass; *pwszProxy = wszProxy; wszBypass = NULL; wszProxy = NULL; pObj = NULL; fRet = TRUE; done: if (fFreeObjMemory && pObj != NULL) HeapFree(GetProcessHeap(), 0, pObj); if (wszProxy != NULL) GlobalFree(wszProxy); if (wszBypass != NULL) GlobalFree(wszBypass); return fRet; } // ************************************************************************** BOOL CWUDLProxyCache::SetLastGoodProxy(LPCWSTR wszSrv, DWORD iProxy) { SWUDLProxyCacheObj *pObj = NULL; BOOL fRet = FALSE; // does it exist? pObj = this->internalFind(wszSrv); if (pObj == NULL) goto done; // reset object to front of list pObj->pNext = m_rgpObj; m_rgpObj = pObj; pObj->iLastKnownGood = iProxy; fRet = TRUE; done: return fRet; } // ************************************************************************** BOOL CWUDLProxyCache::GetLastGoodProxy(LPCWSTR wszSrv, SAUProxySettings *paups) { SWUDLProxyCacheObj *pObj = NULL; HRESULT hr = NOERROR; LPWSTR wszBypass = NULL, wszProxy = NULL; BOOL fRet = FALSE; if (wszSrv == NULL || paups == NULL) { SetLastError(ERROR_INVALID_PARAMETER); goto done; } // does it exist? pObj = this->internalFind(wszSrv); if (pObj == NULL) { SetLastError(ERROR_FILE_NOT_FOUND); goto done; } // reset object to front of list pObj->pNext = m_rgpObj; m_rgpObj = pObj; // need to use GloablAlloc here cuz that's what WinHttp uses and we need // to match it if (pObj->cbBypass > 0 && pObj->wszBypass != NULL) { wszBypass = (LPWSTR)GlobalAlloc(GMEM_FIXED, pObj->cbBypass); if (wszBypass == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto done; } hr = StringCbCopyExW(wszBypass, pObj->cbBypass, pObj->wszBypass, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); goto done; } } if (pObj->cbProxy > 0 && pObj->wszProxy != NULL) { wszProxy = (LPWSTR)GlobalAlloc(GMEM_FIXED, pObj->cbProxy); if (wszProxy == NULL) { SetLastError(ERROR_OUTOFMEMORY); goto done; } hr = StringCbCopyExW(wszProxy, pObj->cbProxy, pObj->wszProxy, NULL, NULL, MISTSAFE_STRING_FLAGS); if (FAILED(hr)) { SetLastError(HRESULT_CODE(hr)); goto done; } } ZeroMemory(paups, sizeof(SAUProxySettings)); paups->dwAccessType = pObj->dwAccessType; paups->wszBypass = wszBypass; paups->wszProxyOrig = wszProxy; paups->iProxy = pObj->iLastKnownGood; wszBypass = NULL; wszProxy = NULL; fRet = TRUE; done: if (wszProxy != NULL) GlobalFree(wszProxy); if (wszBypass != NULL) GlobalFree(wszBypass); return fRet; } // ************************************************************************** BOOL CWUDLProxyCache::Empty(void) { SWUDLProxyCacheObj *pObj = m_rgpObj; while (pObj != NULL) { m_rgpObj = pObj->pNext; HeapFree(GetProcessHeap(), 0, pObj); pObj = m_rgpObj; } return TRUE; } #endif