⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cache.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include <ssdppch.h>
#pragma hdrstop



#define BUF_SIZE 100
#define CACHE_RESULT_SIZE 2

// To-Do: Set cache size limit and clean up cache when it reaches the limit.

// USN is the key to the list, no duplicate USNs.

static LIST_ENTRY listCache;
static CRITICAL_SECTION CSListCache;
static CTETimer timerCleanup;
static PSSDP_CACHE_ENTRY pCacheEntryFirst; 

#ifndef UNDER_CE
static LPCTSTR g_szSystemDir = TEXT("windir");
#else
static const TCHAR g_szWinDir[] = TEXT("\\windows");
#endif
static LPCTSTR g_szCacheFileName = TEXT("\\ssdpcache.txt"); 

BOOL CacheEntryExpired(SSDP_CACHE_ENTRY *CacheEntry);
VOID FreeSsdpCacheEntry(PSSDP_CACHE_ENTRY CacheEntry);
VOID PrintListCache();
VOID RemoveFromListCache(PSSDP_CACHE_ENTRY CacheEntry, PSSDP_REQUEST pSsdpRequest);
VOID RemoveEntryWithNotification(PSSDP_CACHE_ENTRY CacheEntry, PSSDP_REQUEST pSsdpRequest);
VOID FileTimeToString(FILETIME FileTime, CHAR *szBuf, INT BufSize);

VOID CacheTimerProc (CTETimer *Timer, VOID *Arg)
{
    PSSDP_CACHE_ENTRY pCacheEntryExpired = (PSSDP_CACHE_ENTRY) Arg;

    TraceTag(ttidSsdpCache, "+Enter CacheTimerProc %x", pCacheEntryExpired);

    EnterCriticalSection(&CSListCache);

    ConvertToByebyeNotify(&pCacheEntryExpired->SsdpRequest); 

    if (pCacheEntryExpired == pCacheEntryFirst)
    {
        TraceTag(ttidSsdpCache, "+Expired entry %x is the current ealiest %x",
                 pCacheEntryExpired, pCacheEntryFirst);

        RemoveFromListCache(pCacheEntryExpired, &pCacheEntryExpired->SsdpRequest); 
    } else 
    {
        // This can only happen if update occurred while we are in this proc,
        // but before EnterCriticalSection.  The update was treated as adding
        // a new item and a cleanup timer is already restarted as a result. 
        
        TraceTag(ttidSsdpCache, "+Expired entry %x is not the current ealiest %x",
                 pCacheEntryExpired, pCacheEntryFirst);

        RemoveEntryWithNotification(pCacheEntryExpired, &pCacheEntryExpired->SsdpRequest); 
    }
    LeaveCriticalSection(&CSListCache);

    TraceTag(ttidSsdpCache, "-Leave CacheTimerProc %x", pCacheEntryExpired);

}

VOID InitializeListCache()
{
    InitializeCriticalSection(&CSListCache);
    EnterCriticalSection(&CSListCache);
    InitializeListHead(&listCache);
    CTEInitTimer(&timerCleanup);
    pCacheEntryFirst = NULL; 
    LeaveCriticalSection(&CSListCache);
}

// This should only be called during service shut down.
// Call CleanupListCache to clean up the cache while service is running.
VOID DestroyListCache()
{
    CTEStopTimer(&timerCleanup);
    CleanupListCache();
    DeleteCriticalSection(&CSListCache);
}

#if 0
VOID CheckListCacheForNotification(PSSDP_NOTIFY_REQUEST pNotifyRequest)
{
    PLIST_ENTRY p;
    PLIST_ENTRY pListHead = &listCache;

    TraceTag(ttidSsdpCache, "----- Check List Cache for Notification -----");

    EnterCriticalSection(&CSListCache);
    for (p = pListHead->Flink; p != pListHead;)
    {

        PSSDP_CACHE_ENTRY CacheEntry;

        CacheEntry = CONTAINING_RECORD (p, SSDP_CACHE_ENTRY, linkage);

        p = p->Flink;

        if (IsMatchingAliveByebye(pNotifyRequest, &CacheEntry->SsdpRequest) == TRUE)
        {
             QueuePendingNotification(pNotifyRequest, &CacheEntry->SsdpRequest); 
        }
    }

    LeaveCriticalSection(&CSListCache);

}
#endif

VOID CleanupListCache()
{
    PLIST_ENTRY p;
    PLIST_ENTRY pListHead = &listCache;

    TraceTag(ttidSsdpCache, "----- Cleanup SSDP Cache List -----");

    EnterCriticalSection(&CSListCache);
    for (p = pListHead->Flink; p != pListHead;)
    {

        PSSDP_CACHE_ENTRY CacheEntry;

        CacheEntry = CONTAINING_RECORD (p, SSDP_CACHE_ENTRY, linkage);

        p = p->Flink;

        RemoveEntryList(&(CacheEntry->linkage));

        FreeSsdpCacheEntry(CacheEntry);
    }

    LeaveCriticalSection(&CSListCache);

    // To-Do: Stop the cache cleanup timer. 
}

BOOL UpdateExpireTime(PSSDP_CACHE_ENTRY CacheEntry, SSDP_REQUEST *SsdpRequest)
{
    INT Temp;

    FILETIME TempTime;

#ifdef DBG
    CHAR szBuf[BUF_SIZE];
#endif // DBG

    Temp = GetMaxAgeFromCacheControl(SsdpRequest->Headers[SSDP_CACHECONTROL]);

    if (Temp <= 0)
    {
        TraceTag(ttidSsdpCache, "Negative value of max_age %s",
                 SsdpRequest->Headers[SSDP_CACHECONTROL]);
        return FALSE;
    }

    GetSystemTimeAsFileTime(&TempTime);

    // FILETIME is in 100 nano seconds, max-age is in seconds.
    CacheEntry->ExpireTime = ULONGLONG_FROM_FILETIME(TempTime) + (((ULONGLONG) Temp) * 10000000);

#ifdef DBG

    FileTimeToString(TempTime, szBuf, BUF_SIZE);

    TraceTag(ttidSsdpCache, "Current Time is %s", szBuf);

    FileTimeToString(FILETIME_FROM_ULONGLONG(CacheEntry->ExpireTime), szBuf, BUF_SIZE);

    TraceTag(ttidSsdpCache, "Expire Time is %s", szBuf);

#endif //DBG

    return TRUE;
}

SSDP_CACHE_ENTRY *CreateCacheEntryFromRequest(SSDP_REQUEST *SsdpRequest, ULONGLONG ExpireTime)
{

    PSSDP_CACHE_ENTRY CacheEntry;

    INT Size;

    Size = sizeof(SSDP_CACHE_ENTRY);

    CacheEntry = (PSSDP_CACHE_ENTRY) malloc (Size);

    if (CacheEntry == NULL)
    {
        TraceTag(ttidSsdpCache, "Couldn't allocate memory for CacheEntry "
                 "of %s", SsdpRequest->Headers[SSDP_NT]);
        return NULL;
    }
    CacheEntry->Type =  SSDP_CACHE_ENTRY_SIGNATURE;

    CacheEntry->Size = Size;

    if (ExpireTime != 0)
    {
        CacheEntry->ExpireTime = ExpireTime; 
    } else {
        if (UpdateExpireTime(CacheEntry, SsdpRequest) == FALSE)
        {
            free(CacheEntry);
            return NULL;
        }
    }

    CacheEntry->SsdpRequest = (* SsdpRequest);

    return CacheEntry;
}

VOID FreeSsdpCacheEntry(PSSDP_CACHE_ENTRY CacheEntry)
{
    Assert(CacheEntry);
    FreeSsdpRequest(&CacheEntry->SsdpRequest);
    free(CacheEntry);
}
// Pre-Condition: The lock for cache list is held. 

BOOL UpdateCacheEntry(PSSDP_CACHE_ENTRY pCacheEntry, SSDP_REQUEST *pSsdpRequest)
{
    if (UpdateExpireTime(pCacheEntry, pSsdpRequest) == FALSE)
    {
        return FALSE;
    }

    if (CompareSsdpRequest(&pCacheEntry->SsdpRequest, pSsdpRequest) == FALSE)
    {
        CheckListNotifyForAliveByebye(pSsdpRequest); 
    }

    FreeSsdpRequest(&pCacheEntry->SsdpRequest);

    pCacheEntry->SsdpRequest = (* pSsdpRequest);

    return TRUE;
}

VOID AddToListCache(PSSDP_CACHE_ENTRY pCacheEntry)
{
    TraceTag(ttidSsdpCache, "+Enter AddToListCache %x", pCacheEntry);
    EnterCriticalSection(&CSListCache);
    
    if (IsListEmpty(&listCache))
    {
        ULONGLONG Timeout;
        FILETIME ftCurrent; 
        VOID *pTimer;

#ifdef DBG
        CHAR szBuf[BUF_SIZE];
#endif 
        TraceTag(ttidSsdpCache, "The list is empty when adding %x", pCacheEntry);          

        GetSystemTimeAsFileTime(&ftCurrent); 
#ifdef DBG
        FileTimeToString(ftCurrent, szBuf, BUF_SIZE);

        TraceTag(ttidSsdpCache, "Current Time is %s", szBuf);

        FileTimeToString(FILETIME_FROM_ULONGLONG(pCacheEntry->ExpireTime), szBuf, BUF_SIZE);

        TraceTag(ttidSsdpCache, "Expire Time is %s", szBuf);
#endif

        if (pCacheEntry->ExpireTime > ULONGLONG_FROM_FILETIME(ftCurrent))
        {
            TraceTag(ttidSsdpCache, "%x has not expired, insert to list", pCacheEntry);
            InsertHeadList(&listCache, &(pCacheEntry->linkage));
            Timeout = (pCacheEntry->ExpireTime - ULONGLONG_FROM_FILETIME(ftCurrent))/10000;
            pCacheEntryFirst = pCacheEntry; 
            // currently CTEStartTimer only takes 32 bit timeouts
            pTimer = CTEStartTimer(&timerCleanup, (ULONG)Timeout, CacheTimerProc,
                                   (VOID *) pCacheEntry);

            // Check return value of CTEStartTimer. 

            // Queue notifications

            CheckListNotifyForAliveByebye(&pCacheEntry->SsdpRequest); 

        } else {
            TraceTag(ttidSsdpCache, "%x already expired, no need to add", pCacheEntry);
        }
    } else 
    {
        TraceTag(ttidSsdpCache, "The list is NOT empty when adding %x", pCacheEntry);      
        if (pCacheEntry->ExpireTime >= pCacheEntryFirst->ExpireTime)
        {
            TraceTag(ttidSsdpCache, "%x is not ealier than the current earliest, just insert", pCacheEntry);   
            InsertHeadList(&listCache, &(pCacheEntry->linkage));
            CheckListNotifyForAliveByebye(&pCacheEntry->SsdpRequest); 
        } else {
            TraceTag(ttidSsdpCache, "%x is earlier than the current earliest", pCacheEntry);   
            if (CTEStopTimer(&timerCleanup))
            {
                ULONGLONG Timeout;
                FILETIME ftCurrent; 
                VOID *pTimer;

                TraceTag(ttidSsdpCache, "Successfully stopped the cleanup timer", pCacheEntry);   
                InsertHeadList(&listCache, &(pCacheEntry->linkage));
                
                CheckListNotifyForAliveByebye(&pCacheEntry->SsdpRequest); 

                GetSystemTimeAsFileTime(&ftCurrent); 

                if (pCacheEntry->ExpireTime > ULONGLONG_FROM_FILETIME(ftCurrent))
                {
                    Timeout = (pCacheEntry->ExpireTime - ULONGLONG_FROM_FILETIME(ftCurrent))/10000;
                } else 
                {
                    Timeout = 0; 
                }

                pCacheEntryFirst = pCacheEntry; 

                // currently CTEStartTimer only takes 32 bit timeouts
                pTimer = CTEStartTimer(&timerCleanup, (ULONG)Timeout, CacheTimerProc,
                                       (VOID *) pCacheEntry);
            } else {
                // The timer proc is running and I am ealier than the expired entry, 
                // so I am expired as well, thus ignore 
                TraceTag(ttidSsdpCache, "Failed to stop the cleanup timer for %x, skip add", pCacheEntry);   
            }
        }
    }

    LeaveCriticalSection(&CSListCache);

    TraceTag(ttidSsdpCache, "-Leave AddToListCache %x.", pCacheEntry);
}

VOID RemoveEntryWithNotification(PSSDP_CACHE_ENTRY CacheEntry, PSSDP_REQUEST pSsdpRequest)
{
    RemoveEntryList(&(CacheEntry->linkage));
    
    CheckListNotifyForAliveByebye(pSsdpRequest); 

    FreeSsdpCacheEntry(CacheEntry);

}
VOID StartCacheCleanupTimer()
{
    EnterCriticalSection(&CSListCache);

    if (IsListEmpty(&listCache)) {
        TraceTag(ttidSsdpCache, "No more cache entry left."); 
    } else 
    {
        ULONGLONG ullFirst = _UI64_MAX; 
        PLIST_ENTRY p;
        PLIST_ENTRY pListHead = &listCache; 

        TraceTag(ttidSsdpCache, "Cache list is not empty after removing"); 
        
        for (p = pListHead->Flink; p != pListHead;)
        {
            PSSDP_CACHE_ENTRY CacheEntry;

            CacheEntry = CONTAINING_RECORD (p, SSDP_CACHE_ENTRY, linkage);

            p = p->Flink;

            if (CacheEntry->ExpireTime <= ullFirst) {
                ullFirst = CacheEntry->ExpireTime; 
                pCacheEntryFirst = CacheEntry; 
            }
        }

        TraceTag(ttidSsdpCache, "The new earliest cache entry is %x", pCacheEntryFirst); 

        Assert(pCacheEntryFirst != NULL); 

        ULONGLONG Timeout;
        FILETIME ftCurrent; 
        VOID *pTimer;

        GetSystemTimeAsFileTime(&ftCurrent); 

        if (ullFirst > ULONGLONG_FROM_FILETIME(ftCurrent))
        {
            Timeout = (ullFirst - ULONGLONG_FROM_FILETIME(ftCurrent))/10000; 
        } else {
            // Expired
            Timeout = 0; 
        }

        // currently CTEStartTimer only takes 32 bit timeouts
        pTimer = CTEStartTimer(&timerCleanup, (ULONG)Timeout,CacheTimerProc,
                               (VOID *) pCacheEntryFirst);
    }
    LeaveCriticalSection(&CSListCache);
}

VOID RemoveFromListCache(PSSDP_CACHE_ENTRY CacheEntry, PSSDP_REQUEST pSsdpRequest)
{
    TraceTag(ttidSsdpCache, "+Enter RemoveFromListCache %x", CacheEntry);

    EnterCriticalSection(&CSListCache);

    RemoveEntryWithNotification(CacheEntry, pSsdpRequest); 

    pCacheEntryFirst = NULL; 

    StartCacheCleanupTimer(); 

    LeaveCriticalSection(&CSListCache);
    
}

//+---------------------------------------------------------------------------
//
//  Function:   UpdateListCache
//
//  Purpose:    Update the cache with ssdp:alive messagesand M-SEARCH results
//
//  Arguments:
//
//  Returns:    TRUE if listCache takes ownership of the memory within 
//              SsdpRequest; FALSE to have caller free the memory. 
//
//  Author:     tingcai   22 Nov 1999
//
//  Notes:
//
//  If no CacheControl header, don't cache. 
//  If exists in cache, update if alive or search result, remove if byebye, 
//  If not in cache, add to the cache if subscribed and it is alive 
//  Don't do bRetVal = FALSE, in case you have to, make sure you don't 
//  override a TRUE; 

BOOL UpdateListCache(PSSDP_REQUEST pSsdpRequest, BOOL IsSubscribed)
{
    PLIST_ENTRY p;
    LIST_ENTRY *pListHead = &listCache;
    BOOL found = FALSE;
    BOOL IsByebye;
    BOOL bRetVal = FALSE; 

    if (pSsdpRequest->Headers[SSDP_NTS] != NULL &&
        strcmp(pSsdpRequest->Headers[SSDP_NTS], "ssdp:byebye") == 0)
    {
        IsByebye = TRUE;
    }
    else
    {
        IsByebye = FALSE;
    }

    if (pSsdpRequest->Headers[SSDP_CACHECONTROL] == NULL)
    {
        // To-Do: 

        TraceTag(ttidSsdpCache, "Couldn't find cache control header, not cachable");
        return bRetVal;
    }

    EnterCriticalSection(&CSListCache);

    for (p = pListHead->Flink; p != pListHead; )
    {
        SSDP_CACHE_ENTRY *CacheEntry;

        CacheEntry = CONTAINING_RECORD (p, SSDP_CACHE_ENTRY, linkage);

        p = p->Flink;

        if (strcmp(CacheEntry->SsdpRequest.Headers[SSDP_USN],
                   pSsdpRequest->Headers[SSDP_USN]) == 0)
        {
            found = TRUE;  // even if update fails.

            TraceTag(ttidSsdpCache, "Found matching cache entry %x", CacheEntry);

            if (IsByebye)
            {
                // byebye
                if (CacheEntry == pCacheEntryFirst)
                {
                    TraceTag(ttidSsdpCache, "Byebye is for the current earliest %x", CacheEntry); 

                    if (CTEStopTimer(&timerCleanup))
                    {
                        TraceTag(ttidSsdpCache, "Stopped cleanup timer for %x", CacheEntry); 
                        RemoveFromListCache(CacheEntry, pSsdpRequest); 
                    } else {
                        TraceTag(ttidSsdpCache, "Received byebye for cache entry %x, timer \

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -