Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/global/   (Postfix Mailserver Version 3.11©)  Datei vom 7.11.2014 mit Größe 14 kB image not shown  

Quelle  scache_multi.c

  Sprache: C
 

/*++
/* NAME
/* scache_multi 3
/* SUMMARY
/* multi-session cache
/* SYNOPSIS
/* #include <scache.h>
/* DESCRIPTION
/* SCACHE *scache_multi_create()
/* DESCRIPTION
/* This module implements an in-memory, multi-session cache.
/*
/* scache_multi_create() instantiates a session cache that
/* stores multiple sessions.
/* DIAGNOSTICS
/* Fatal error: memory allocation problem;
/* panic: internal consistency failure.
/* SEE ALSO
/* scache(3), generic session cache API
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <unistd.h>
#include <stddef.h>   /* offsetof() */
#include <string.h>

/* Utility library. */

#include <msg.h>
#include <ring.h>
#include <htable.h>
#include <vstring.h>
#include <mymalloc.h>
#include <events.h>

/*#define msg_verbose 1*/

/* Global library. */

#include <scache.h>

/* Application-specific. */

 /*
  * SCACHE_MULTI is a derived type from the SCACHE super-class.
  * 
  * Each destination has an entry in the destination hash table, and each
  * destination->endpoint binding is kept in a circular list under its
  * destination hash table entry.
  * 
  * Likewise, each endpoint has an entry in the endpoint hash table, and each
  * endpoint->session binding is kept in a circular list under its endpoint
  * hash table entry.
  * 
  * We do not attempt to limit the number of destination or endpoint entries,
  * nor do we attempt to limit the number of sessions. Doing so would require
  * a write-through cache. Currently, the CTABLE cache module supports only
  * read-through caching.
  * 
  * This is no problem because the number of cached destinations is limited by
  * design. Sites that specify a wild-card domain pattern, and thus cache
  * every session in recent history, may be in for a surprise.
  */

typedef struct {
    SCACHE  scache[1];   /* super-class */
    HTABLE *dest_cache;   /* destination->endpoint bindings */
    HTABLE *endp_cache;   /* endpoint->session bindings */
    int     sess_count;   /* number of cached sessions */
} SCACHE_MULTI;

 /*
  * Storage for a destination or endpoint list head. Each list head knows its
  * own hash table entry name, so that we can remove the list when it becomes
  * empty. List items are stored in a circular list under the list head.
  */

typedef struct {
    RING    ring[1];   /* circular list linkage */
    char   *parent_key;   /* parent linkage: hash table */
    SCACHE_MULTI *cache;  /* parent linkage: cache */
} SCACHE_MULTI_HEAD;

#define RING_TO_MULTI_HEAD(p) RING_TO_APPL((p), SCACHE_MULTI_HEAD, ring)

 /*
  * Storage for a destination->endpoint binding. This is an element in a
  * circular list, whose list head specifies the destination.
  */

typedef struct {
    RING    ring[1];   /* circular list linkage */
    SCACHE_MULTI_HEAD *head;  /* parent linkage: list head */
    char   *endp_label;   /* endpoint name */
    char   *dest_prop;   /* binding properties */
} SCACHE_MULTI_DEST;

#define RING_TO_MULTI_DEST(p) RING_TO_APPL((p), SCACHE_MULTI_DEST, ring)

static void scache_multi_expire_dest(intvoid *);

 /*
  * Storage for an endpoint->session binding. This is an element in a
  * circular list, whose list head specifies the endpoint.
  */

typedef struct {
    RING    ring[1];   /* circular list linkage */
    SCACHE_MULTI_HEAD *head;  /* parent linkage: list head */
    int     fd;    /* cached session */
    char   *endp_prop;   /* binding properties */
} SCACHE_MULTI_ENDP;

#define RING_TO_MULTI_ENDP(p) RING_TO_APPL((p), SCACHE_MULTI_ENDP, ring)

static void scache_multi_expire_endp(intvoid *);

 /*
  * When deleting a circular list element, are we deleting the entire
  * circular list, or are we removing a single list element. We need this
  * distinction to avoid a re-entrancy problem between htable_delete() and
  * htable_free().
  */

#define BOTTOM_UP 1  /* one item */
#define TOP_DOWN 2  /* whole list */

/* scache_multi_drop_endp - destroy endpoint->session binding */

static void scache_multi_drop_endp(SCACHE_MULTI_ENDP *endp, int direction)
{
    const char *myname = "scache_multi_drop_endp";
    SCACHE_MULTI_HEAD *head;

    if (msg_verbose)
 msg_info("%s: endp_prop=%s fd=%d", myname,
   endp->endp_prop, endp->fd);

    /*
     * Stop the timer.
     */

    event_cancel_timer(scache_multi_expire_endp, (void *) endp);

    /*
     * In bottom-up mode, remove the list head from the endpoint hash when
     * the list becomes empty. Otherwise, remove the endpoint->session
     * binding from the list.
     */

    ring_detach(endp->ring);
    head = endp->head;
    head->cache->sess_count--;
    if (direction == BOTTOM_UP && ring_pred(head->ring) == head->ring)
 htable_delete(head->cache->endp_cache, head->parent_key, myfree);

    /*
     * Destroy the endpoint->session binding.
     */

    if (endp->fd >= 0 && close(endp->fd) != 0)
 msg_warn("%s: close(%d): %m", myname, endp->fd);
    myfree(endp->endp_prop);

    myfree((void *) endp);
}

/* scache_multi_expire_endp - event timer call-back */

static void scache_multi_expire_endp(int unused_event, void *context)
{
    SCACHE_MULTI_ENDP *endp = (SCACHE_MULTI_ENDP *) context;

    scache_multi_drop_endp(endp, BOTTOM_UP);
}

/* scache_multi_free_endp - hash table destructor call-back */

static void scache_multi_free_endp(void *ptr)
{
    SCACHE_MULTI_HEAD *head = (SCACHE_MULTI_HEAD *) ptr;
    SCACHE_MULTI_ENDP *endp;
    RING   *ring;

    /*
     * Delete each endpoint->session binding in the list, then delete the
     * list head. Note: this changes the list, so we must iterate carefully.
     */

    while ((ring = ring_succ(head->ring)) != head->ring) {
 endp = RING_TO_MULTI_ENDP(ring);
 scache_multi_drop_endp(endp, TOP_DOWN);
    }
    myfree((void *) head);
}

/* scache_multi_save_endp - save endpoint->session binding */

static void scache_multi_save_endp(SCACHE *scache, int ttl,
               const char *endp_label,
               const char *endp_prop, int fd)
{
    const char *myname = "scache_multi_save_endp";
    SCACHE_MULTI *sp = (SCACHE_MULTI *) scache;
    SCACHE_MULTI_HEAD *head;
    SCACHE_MULTI_ENDP *endp;

    if (ttl < 0)
 msg_panic("%s: bad ttl: %d", myname, ttl);

    /*
     * Look up or instantiate the list head with the endpoint name.
     */

    if ((head = (SCACHE_MULTI_HEAD *)
  htable_find(sp->endp_cache, endp_label)) == 0) {
 head = (SCACHE_MULTI_HEAD *) mymalloc(sizeof(*head));
 ring_init(head->ring);
 head->parent_key =
     htable_enter(sp->endp_cache, endp_label, (void *) head)->key;
 head->cache = sp;
    }

    /*
     * Add the endpoint->session binding to the list. There can never be a
     * duplicate, because each session must have a different file descriptor.
     */

    endp = (SCACHE_MULTI_ENDP *) mymalloc(sizeof(*endp));
    endp->head = head;
    endp->fd = fd;
    endp->endp_prop = mystrdup(endp_prop);
    ring_prepend(head->ring, endp->ring);
    sp->sess_count++;

    /*
     * Make sure this binding will go away eventually.
     */

    event_request_timer(scache_multi_expire_endp, (void *) endp, ttl);

    if (msg_verbose)
 msg_info("%s: endp_label=%s -> endp_prop=%s fd=%d",
   myname, endp_label, endp_prop, fd);
}

/* scache_multi_find_endp - look up session for named endpoint */

static int scache_multi_find_endp(SCACHE *scache, const char *endp_label,
              VSTRING *endp_prop)
{
    const char *myname = "scache_multi_find_endp";
    SCACHE_MULTI *sp = (SCACHE_MULTI *) scache;
    SCACHE_MULTI_HEAD *head;
    SCACHE_MULTI_ENDP *endp;
    RING   *ring;
    int     fd;

    /*
     * Look up the list head with the endpoint name.
     */

    if ((head = (SCACHE_MULTI_HEAD *)
  htable_find(sp->endp_cache, endp_label)) == 0) {
 if (msg_verbose)
     msg_info("%s: no endpoint cache: endp_label=%s",
       myname, endp_label);
 return (-1);
    }

    /*
     * Use the first available session. Remove the session from the cache
     * because we're giving it to someone else.
     */

    if ((ring = ring_succ(head->ring)) != head->ring) {
 endp = RING_TO_MULTI_ENDP(ring);
 fd = endp->fd;
 endp->fd = -1;
 vstring_strcpy(endp_prop, endp->endp_prop);
 if (msg_verbose)
     msg_info("%s: found: endp_label=%s -> endp_prop=%s fd=%d",
       myname, endp_label, endp->endp_prop, fd);
 scache_multi_drop_endp(endp, BOTTOM_UP);
 return (fd);
    }
    if (msg_verbose)
 msg_info("%s: not found: endp_label=%s", myname, endp_label);
    return (-1);
}

/* scache_multi_drop_dest - delete destination->endpoint binding */

static void scache_multi_drop_dest(SCACHE_MULTI_DEST *dest, int direction)
{
    const char *myname = "scache_multi_drop_dest";
    SCACHE_MULTI_HEAD *head;

    if (msg_verbose)
 msg_info("%s: dest_prop=%s endp_label=%s",
   myname, dest->dest_prop, dest->endp_label);

    /*
     * Stop the timer.
     */

    event_cancel_timer(scache_multi_expire_dest, (void *) dest);

    /*
     * In bottom-up mode, remove the list head from the destination hash when
     * the list becomes empty. Otherwise, remove the destination->endpoint
     * binding from the list.
     */

    ring_detach(dest->ring);
    head = dest->head;
    if (direction == BOTTOM_UP && ring_pred(head->ring) == head->ring)
 htable_delete(head->cache->dest_cache, head->parent_key, myfree);

    /*
     * Destroy the destination->endpoint binding.
     */

    myfree(dest->dest_prop);
    myfree(dest->endp_label);

    myfree((void *) dest);
}

/* scache_multi_expire_dest - event timer call-back */

static void scache_multi_expire_dest(int unused_event, void *context)
{
    SCACHE_MULTI_DEST *dest = (SCACHE_MULTI_DEST *) context;

    scache_multi_drop_dest(dest, BOTTOM_UP);
}

/* scache_multi_free_dest - hash table destructor call-back */

static void scache_multi_free_dest(void *ptr)
{
    SCACHE_MULTI_HEAD *head = (SCACHE_MULTI_HEAD *) ptr;
    SCACHE_MULTI_DEST *dest;
    RING   *ring;

    /*
     * Delete each destination->endpoint binding in the list, then delete the
     * list head. Note: this changes the list, so we must iterate carefully.
     */

    while ((ring = ring_succ(head->ring)) != head->ring) {
 dest = RING_TO_MULTI_DEST(ring);
 scache_multi_drop_dest(dest, TOP_DOWN);
    }
    myfree((void *) head);
}

/* scache_multi_save_dest - save destination->endpoint binding */

static void scache_multi_save_dest(SCACHE *scache, int ttl,
               const char *dest_label,
               const char *dest_prop,
               const char *endp_label)
{
    const char *myname = "scache_multi_save_dest";
    SCACHE_MULTI *sp = (SCACHE_MULTI *) scache;
    SCACHE_MULTI_HEAD *head;
    SCACHE_MULTI_DEST *dest;
    RING   *ring;
    int     refresh = 0;

    if (ttl < 0)
 msg_panic("%s: bad ttl: %d", myname, ttl);

    /*
     * Look up or instantiate the list head with the destination name.
     */

    if ((head = (SCACHE_MULTI_HEAD *)
  htable_find(sp->dest_cache, dest_label)) == 0) {
 head = (SCACHE_MULTI_HEAD *) mymalloc(sizeof(*head));
 ring_init(head->ring);
 head->parent_key =
     htable_enter(sp->dest_cache, dest_label, (void *) head)->key;
 head->cache = sp;
    }

    /*
     * Look up or instantiate the destination->endpoint binding. Update the
     * expiration time if this destination->endpoint binding already exists.
     */

    RING_FOREACH(ring, head->ring) {
 dest = RING_TO_MULTI_DEST(ring);
 if (strcmp(dest->endp_label, endp_label) == 0
     && strcmp(dest->dest_prop, dest_prop) == 0) {
     refresh = 1;
     break;
 }
    }
    if (refresh == 0) {
 dest = (SCACHE_MULTI_DEST *) mymalloc(sizeof(*dest));
 dest->head = head;
 dest->endp_label = mystrdup(endp_label);
 dest->dest_prop = mystrdup(dest_prop);
 ring_prepend(head->ring, dest->ring);
    }

    /*
     * Make sure this binding will go away eventually.
     */

    event_request_timer(scache_multi_expire_dest, (void *) dest, ttl);

    if (msg_verbose)
 msg_info("%s: dest_label=%s -> dest_prop=%s endp_label=%s%s",
   myname, dest_label, dest_prop, endp_label,
   refresh ? " (refreshed)" : "");
}

/* scache_multi_find_dest - look up session for named destination */

static int scache_multi_find_dest(SCACHE *scache, const char *dest_label,
              VSTRING *dest_prop,
              VSTRING *endp_prop)
{
    const char *myname = "scache_multi_find_dest";
    SCACHE_MULTI *sp = (SCACHE_MULTI *) scache;
    SCACHE_MULTI_HEAD *head;
    SCACHE_MULTI_DEST *dest;
    RING   *ring;
    int     fd;

    /*
     * Look up the list head with the destination name.
     */

    if ((head = (SCACHE_MULTI_HEAD *)
  htable_find(sp->dest_cache, dest_label)) == 0) {
 if (msg_verbose)
     msg_info("%s: no destination cache: dest_label=%s",
       myname, dest_label);
 return (-1);
    }

    /*
     * Search endpoints for the first available session.
     */

    RING_FOREACH(ring, head->ring) {
 dest = RING_TO_MULTI_DEST(ring);
 fd = scache_multi_find_endp(scache, dest->endp_label, endp_prop);
 if (fd >= 0) {
     vstring_strcpy(dest_prop, dest->dest_prop);
     return (fd);
 }
    }
    if (msg_verbose)
 msg_info("%s: not found: dest_label=%s", myname, dest_label);
    return (-1);
}

/* scache_multi_size - size of multi-element cache object */

static void scache_multi_size(SCACHE *scache, SCACHE_SIZE *size)
{
    SCACHE_MULTI *sp = (SCACHE_MULTI *) scache;

    size->dest_count = sp->dest_cache->used;
    size->endp_count = sp->endp_cache->used;
    size->sess_count = sp->sess_count;
}

/* scache_multi_free - destroy multi-element cache object */

static void scache_multi_free(SCACHE *scache)
{
    SCACHE_MULTI *sp = (SCACHE_MULTI *) scache;

    htable_free(sp->dest_cache, scache_multi_free_dest);
    htable_free(sp->endp_cache, scache_multi_free_endp);

    myfree((void *) sp);
}

/* scache_multi_create - initialize */

SCACHE *scache_multi_create(void)
{
    SCACHE_MULTI *sp = (SCACHE_MULTI *) mymalloc(sizeof(*sp));

    sp->scache->save_endp = scache_multi_save_endp;
    sp->scache->find_endp = scache_multi_find_endp;
    sp->scache->save_dest = scache_multi_save_dest;
    sp->scache->find_dest = scache_multi_find_dest;
    sp->scache->size = scache_multi_size;
    sp->scache->free = scache_multi_free;

    sp->dest_cache = htable_create(1);
    sp->endp_cache = htable_create(1);
    sp->sess_count = 0;

    return (sp->scache);
}

Messung V0.5 in Prozent
C=89 H=98 G=93

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.