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

📄 cache.c

📁 是一个手机功能的模拟程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright (C) Ericsson Mobile Communications AB, 2000.
 * Licensed to AU-System AB.
 * All rights reserved.
 *
 * This software is covered by the license agreement between
 * the end user and AU-System AB, and may be used and copied
 * only in accordance with the terms of the said agreement.
 *
 * Neither Ericsson Mobile Communications AB nor AU-System AB
 * assumes any responsibility or liability for any errors or inaccuracies in
 * this software, or any consequential, incidental or indirect damage arising
 * out of the use of the Generic WAP Client software.
 */
/*
 * cache.c
 *
 * Module for storing and retrieving WML pages in a cache.
 *
 * Created by Anders Edenbrandt.
 *
 * Revision history: 
 *   990926, AED: Complete rewrite to utilize the new Storage module.
 *   991110, AED: All public routines now test if the cache has
 *                been initialized. The behaviour of
 *                Cache_PrepareSizeChange has changed to effect a
 *                shutdown of the cache, freeing all associated
 *                data structures.
 *   991123, AED: added new function, Cache_DeleteMatchingPrefix.
 *   991227, IPN: A minor changes in Cache_Write when the 
 *                Must-Revalidate flag is set.
 *   991229, IPN: Changes in Cache_GetParameters. Added two new 
 *                parameters (Date and ETag), Check at CacheControl-MaxAge 
 *                when calculating Expire values.
 *   000114, AED: Added handling of Date and ETag. Both items can
 *                be stored in the cache block, and the function
 *                Cache_URLisPresent now returns the etag as well as
 *                the last modified date, in case the entry should
 *                be revalidated. Furthermore, Cache_Write will not
 *                replace an entry that has a more recent date-field.
 *   000125, AED: Cache_PrepareSizeChange now calls MEMa_cachePrepared
 *                even if the cache is not currently initialized.
 *   000127, IPN: A minor changes in Cache_GetParameters 
 *   000128, AED: The ETag string extracted from the request headers
 *                is handled as a dynamically allocated, temporary string.
 *   000321, IPN: A minor correction in Expire-calculation.
 *   000411, IPN: Handles MaxAge and MustRevalidate simultaneous in a response. 
 *   000511, AED: Should be possible to call Cache_Init after a restart.
 *   000808, IPN: Added WmlBackNav parameter to Cache_URLisPresent. The normal
 *                caching rules is not used when request comes from the history.
 *   001107, HEAD:Different handling of expire in cache_getParameters
 *   001120, AED: New parameter in Cache_URLisPresent and Cache_Write,
 *                to distinguish between content belonging to WTA and
 *                normal content.
 *                Removed Cache_ConfirmURL. No longer used.
 *                Correction in Cache_Write, the alternative that does
 *                  compaction.
 *                Correction in Cache_Init, potential memory leak.
 *   001212, AED: Added use of File API. Configured with FILE_CACHE.
 *   010403, IPN: Changes in Cache_GetParameters. Check also after CacheControl -
 *                EncodingVersion 1.3 and 1.4
 *   010410, IPN: The function Cache_GetParameters is now available outside this file.
 *	 010430, MALU:Cast warnings removed.
 *   010507, IPN: Removed some varnings.
 *                
 */
#include "confvars.h"
#include "cache.h"

#ifdef FILE_CACHE
#include "aapifile.h"
#else
#include "storage.h"
#endif

#include "aapimem.h"

#include "cmmnrsrc.h"
#include "waedef.h"
#include "url.h"
#include "hdrutil.h"
#include "wml_uafn.h"

/* Flag values for the 'flags' field in the cache records. */
#define PRESENT         0x01    /* The record has not been deleted. */
#define HASREAD         0x02    /* The record has been read at least once. */
#define MUSTREVALIDATE  0x04    /* This record must be revalidated. */
#define BELONGS_TO_WTA  0x08

/* Each record in the cache starts with this: */
typedef struct {
  UINT32 url_hash;       /* The hash value of the URL */
  UINT16 url_len;        /* The size of the URL, in bytes. */
  UINT16 header_len;     /* The size of the header. */
  UINT32 body_len;       /* The size of the body. */
  UINT32 etag_len;       /* Length of Entity Tag, in bytes. */
  UINT32 expire;         /* The expiration date, or 0 if it has none. */
  UINT32 date;           /* Date of response to request. */
  UINT32 last_mod;       /* The last modified date of the record. */
  UINT16 flags;          /* Flag values, see above. */
#ifdef FILE_CACHE
  UINT32 creation_time;  /* Used for evicting the oldest when cache is full. */
#endif
} CacheRecord;


/* Some information about each record in the cache is kept in memory,
 * in a doubly linked list. The list is ordered by IDs, which means
 * it has the oldest cached value first. */
typedef struct lnode {
  struct lnode *next, *prev;
#ifdef FILE_CACHE
  UINT32       creation_time;
#endif
  UINT32       id;             /* To identify the Storage block */
  UINT32       hashval;        /* Hashed value of the URL */
  UINT8        isWTA;          /* The WTA flag is set */
} ListNode;

#ifdef FILE_CACHE
static ListNode reclist = {&reclist, &reclist, 0, 0, 0, 0};
#else
static ListNode reclist = {&reclist, &reclist, 0, 0, 0};
#endif

/* Macros to add and remove nodes from the list. */
#define list_out(p) do { \
  (p)->next->prev = (p)->prev; \
  (p)->prev->next = (p)->next; \
} while (0)

#define list_addbefore(p, pb) do { \
  (p)->prev = (pb)->prev; \
  (p)->next = (pb); \
  (pb)->prev->next = (p); \
  (pb)->prev = (p); \
} while (0)


/*
 * The Cache: implemented as a Storage Object.
 */
static struct {
  UINT8         isInitialized;
#ifdef FILE_CACHE
  UINT32        size;
#else
  StorageObject store;
#endif
  WAEMAINOBJECT *waeMainObj;
} theCache = {0};


/*
 * Cache_Find
 *
 * Locate a record with a specific URL in the cache.
 * "url" is the URL, as a null-terminated byte string.
 * Returns a pointer to the node in the list, or NULL if it was not found.
 * Also, the record for the found cache entry is stored in the location
 * pointed to by "rec".
 */
static ListNode *
Cache_Find (BYTE *url, CacheRecord *rec, INT16 isWTA)
{
  BYTE      *tmp_url;
  ListNode *p;
  UINT32    hv;

  if (!b_HashURL (url, &hv))
    return NULL;

  for (p = reclist.next; p != &reclist; p = p->next) {
    if (((isWTA < 0) || (isWTA == p->isWTA)) && (p->hashval == hv)) {
#ifdef FILE_CACHE
      if (FILEa_read ('C', p->id, rec, 0, sizeof (CacheRecord))
          != sizeof (CacheRecord)) {
#else      
      if (!Storage_Get (&(theCache.store), p->id, 0,
                        sizeof (CacheRecord), rec)) {
#endif
        return NULL;
      }
      if ((tmp_url = NEWARRAY (BYTE, rec->url_len + 1)) == NULL) {
        return NULL;
      }
#ifdef FILE_CACHE
      if (FILEa_read ('C', p->id, tmp_url, sizeof (CacheRecord),
                      rec->url_len) != rec->url_len) {
#else
      if (!Storage_Get (&(theCache.store), p->id, sizeof (CacheRecord),
                        rec->url_len, tmp_url)) {
#endif
        DEALLOC (&tmp_url);
        return NULL;
      }
      tmp_url[rec->url_len] = '\0';
      if (b_EqualURL (url, tmp_url, ALL_COMP)) {
        DEALLOC (&tmp_url);
        return p;
      }
      DEALLOC (&tmp_url);
    }
  }

  return NULL;
}


/*
 * Cache_Init
 *
 * This function should be called once the WAP Client's physical
 * cachememory is ready to be accessed. If the new size is less
 * than the previous size, then arbitrary data might be lost.
 * This function also sets the new size in the WAEMAINOBJECT.
 * If iFirstInit is equal to 1, the HASREAD flag in each cache
 * record is cleared.
 */
VOID
Cache_Init (UINT32 liNewSize,      /* The new size of the cache */
            VOID   *pvWAEMaStruct, /* Pointer to the WAEMAINOBJECT */
            UINT16  iFirstInit     /* Flag */
            )
{
  CacheRecord rec;
  UINT32      *ida;
  INT16       i;
  ListNode    *p, *q;
  UINT16      len;

  theCache.waeMainObj = (WAEMAINOBJECT*) pvWAEMaStruct;
  if (theCache.waeMainObj != NULL) {
    theCache.waeMainObj->liCacheSize = liNewSize;
  }

#ifndef FILE_CACHE
  if (!Storage_Init (&(theCache.store), liNewSize,
                     (ReadFunction *)MEMa_readCache,
                     (WriteFunction *)MEMa_writeCache)) {
    return;
  }
#endif

  /* Set list of cached records to be empty. */
  reclist.next = &reclist;
  reclist.prev = &reclist;

#ifdef FILE_CACHE
  theCache.size = 0;
  if ((i = FILEa_getFileIds ('C', NULL, 0)) < 0) {
    return;
  }
  len = (UINT16)i;
  ida = OSConnectorAlloc (sizeof (UINT32) * len);
  if (ida == NULL) {
    return;
  }
  if ((i = FILEa_getFileIds ('C', ida, len)) < 0) {
    OSConnectorFree (ida);
    return;
  }
  len = (UINT16)i;
#else  
  if (!Storage_GetAllBlockIds (&(theCache.store), &ida, &len)) {
    return;
  }
#endif

  for (i = 0; i < len; i++) {
#ifdef FILE_CACHE
    if (ida[i] == 0)
      continue;
#endif
    p = NEWARRAY (ListNode, 1);
    if (p == NULL)
      return;
    p->id = ida[i];
#ifdef FILE_CACHE
    theCache.size += FILEa_getSize ('C', ida[i]);
    if (FILEa_read ('C', ida[i], &rec, 0, sizeof (CacheRecord))
        != sizeof (CacheRecord)) {
#else
    if (!Storage_Get (&(theCache.store), ida[i], 0,
                      sizeof (CacheRecord), &rec)) {
#endif
      DEALLOC (&p);
      return;
    }
#ifdef FILE_CACHE
    p->creation_time = rec.creation_time;
#endif
    p->hashval = rec.url_hash;
    p->isWTA = ((rec.flags & BELONGS_TO_WTA) ? 1 : 0);

    /* Sort into reclist, sort ascending after creation time. */
#ifdef FILE_CACHE
    for (q = reclist.next; (q != &reclist) &&
           (q->creation_time < p->creation_time);
         q = q->next);
#else
    for (q = reclist.next; (q != &reclist) && (q->id < p->id);
         q = q->next);
#endif
    list_addbefore (p, q);

    if (iFirstInit && (rec.flags & HASREAD)) {
      rec.flags &= ~HASREAD;
#ifdef FILE_CACHE
      if (FILEa_write ('C', ida[i], &rec, 0, sizeof (CacheRecord))
          != sizeof (CacheRecord)) {
#else
      if (!Storage_Put (&(theCache.store), ida[i], 0,
                        sizeof (CacheRecord), &rec)) {
#endif
        OSConnectorFree (ida);
        return;
      }
    }
  }
#ifdef FILE_CACHE
  while (theCache.size > liNewSize) {
    p = reclist.next;
    if (p == &reclist)
      break;
    list_out (p);
    theCache.size -= FILEa_getSize ('C', p->id);
    FILEa_delete ('C', p->id);
    DEALLOC (&p);
  }
#endif
  OSConnectorFree (ida);
  theCache.isInitialized = 1;
}


/*
 * Cache_PrepareSizeChange
 *
 * This function prepares the cache to be shut down,
 * possibly changing its size. After a call to this function the cache
 * cannot be accessed without first calling Cache_Init.
 * At the time of call, the old size is still in effect.
 * If the new size is less than the previous size, then
 * cache records that do not fit are removed on a first-in first-out basis.
 */
VOID
Cache_PrepareSizeChange (UINT32 liNewSize)
{
  ListNode *p;

  if (!theCache.isInitialized) {
    MEMa_cachePrepared ();
    return;
  }

#ifdef FILE_CACHE
  while (theCache.size > liNewSize) {
    p = reclist.next;
    if (p == &reclist)
      break;
    list_out (p);
    theCache.size -= FILEa_getSize ('C', p->id);
    FILEa_delete ('C', p->id);
    DEALLOC (&p);
  }
#else
  /* Remove oldest until bytesUsed is less than liNewSize */
  while (Storage_BytesUsed (&(theCache.store)) > liNewSize) {
    p = reclist.next;
    if (p == &reclist)
      break;
    list_out (p);
    Storage_DeleteBlock (&(theCache.store), p->id);
    DEALLOC (&p);
  }

  /* Do a complete compaction */
  while (Storage_Compact (&(theCache.store))) {
  }

  Storage_ChangeSize (&(theCache.store), liNewSize);
#endif
  theCache.waeMainObj->liCacheSize = liNewSize;

  /* Free the list of cached records */
  while (reclist.next != &reclist) {
    p = reclist.next;
    list_out (p);
    DEALLOC (&p);
  }
#ifndef FILE_CACHE
  Storage_Finalize (&(theCache.store));
#endif

  theCache.isInitialized = 0;

  MEMa_cachePrepared ();
}


/*
 * Cache_ URLisPresent
 *
 * Check if a URL is in the cache.
 * "pvUrl" is the URL as a null-terminated byte string.
 * "iWmlBackNav" the normal caching rules is not used when

⌨️ 快捷键说明

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