diff options
Diffstat (limited to 'src/global/scache_single.c')
-rw-r--r-- | src/global/scache_single.c | 312 |
1 files changed, 312 insertions, 0 deletions
diff --git a/src/global/scache_single.c b/src/global/scache_single.c new file mode 100644 index 0000000..2a3864b --- /dev/null +++ b/src/global/scache_single.c @@ -0,0 +1,312 @@ +/*++ +/* NAME +/* scache_single 3 +/* SUMMARY +/* single-item session cache +/* SYNOPSIS +/* #include <scache.h> +/* DESCRIPTION +/* SCACHE *scache_single_create() +/* DESCRIPTION +/* This module implements an in-memory, single-session cache. +/* +/* scache_single_create() creates a session cache instance +/* that stores a single session. +/* 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 <string.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <mymalloc.h> +#include <events.h> + +/*#define msg_verbose 1*/ + +/* Global library. */ + +#include <scache.h> + +/* Application-specific. */ + + /* + * Data structure for one saved connection. It is left up to the application + * to serialize attributes upon passivation, and to de-serialize them upon + * re-activation. + */ +typedef struct { + VSTRING *endp_label; /* physical endpoint name */ + VSTRING *endp_prop; /* endpoint properties, serialized */ + int fd; /* the session */ +} SCACHE_SINGLE_ENDP; + + /* + * Data structure for a logical name to physical endpoint binding. It is + * left up to the application to serialize attributes upon passivation, and + * to de-serialize then upon re-activation. + */ +typedef struct { + VSTRING *dest_label; /* logical destination name */ + VSTRING *dest_prop; /* binding properties, serialized */ + VSTRING *endp_label; /* physical endpoint name */ +} SCACHE_SINGLE_DEST; + + /* + * SCACHE_SINGLE is a derived type from the SCACHE super-class. + */ +typedef struct { + SCACHE scache[1]; /* super-class */ + SCACHE_SINGLE_ENDP endp; /* one cached session */ + SCACHE_SINGLE_DEST dest; /* one cached binding */ +} SCACHE_SINGLE; + +static void scache_single_expire_endp(int, void *); +static void scache_single_expire_dest(int, void *); + +#define SCACHE_SINGLE_ENDP_BUSY(sp) (VSTRING_LEN(sp->endp.endp_label) > 0) +#define SCACHE_SINGLE_DEST_BUSY(sp) (VSTRING_LEN(sp->dest.dest_label) > 0) + +#define STR(x) vstring_str(x) + +/* scache_single_free_endp - discard endpoint */ + +static void scache_single_free_endp(SCACHE_SINGLE *sp) +{ + const char *myname = "scache_single_free_endp"; + + if (msg_verbose) + msg_info("%s: %s", myname, STR(sp->endp.endp_label)); + + event_cancel_timer(scache_single_expire_endp, (void *) sp); + if (sp->endp.fd >= 0 && close(sp->endp.fd) < 0) + msg_warn("close session endpoint %s: %m", STR(sp->endp.endp_label)); + VSTRING_RESET(sp->endp.endp_label); + VSTRING_TERMINATE(sp->endp.endp_label); + VSTRING_RESET(sp->endp.endp_prop); + VSTRING_TERMINATE(sp->endp.endp_prop); + sp->endp.fd = -1; +} + +/* scache_single_expire_endp - discard expired session */ + +static void scache_single_expire_endp(int unused_event, void *context) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) context; + + scache_single_free_endp(sp); +} + +/* scache_single_save_endp - save endpoint */ + +static void scache_single_save_endp(SCACHE *scache, int endp_ttl, + const char *endp_label, + const char *endp_prop, int fd) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; + const char *myname = "scache_single_save_endp"; + + if (endp_ttl <= 0) + msg_panic("%s: bad endp_ttl: %d", myname, endp_ttl); + + if (SCACHE_SINGLE_ENDP_BUSY(sp)) + scache_single_free_endp(sp); /* dump the cached fd */ + + vstring_strcpy(sp->endp.endp_label, endp_label); + vstring_strcpy(sp->endp.endp_prop, endp_prop); + sp->endp.fd = fd; + event_request_timer(scache_single_expire_endp, (void *) sp, endp_ttl); + + if (msg_verbose) + msg_info("%s: %s fd=%d", myname, endp_label, fd); +} + +/* scache_single_find_endp - look up cached session */ + +static int scache_single_find_endp(SCACHE *scache, const char *endp_label, + VSTRING *endp_prop) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; + const char *myname = "scache_single_find_endp"; + int fd; + + if (!SCACHE_SINGLE_ENDP_BUSY(sp)) { + if (msg_verbose) + msg_info("%s: no endpoint cache: %s", myname, endp_label); + return (-1); + } + if (strcmp(STR(sp->endp.endp_label), endp_label) == 0) { + vstring_strcpy(endp_prop, STR(sp->endp.endp_prop)); + fd = sp->endp.fd; + sp->endp.fd = -1; + scache_single_free_endp(sp); + if (msg_verbose) + msg_info("%s: found: %s fd=%d", myname, endp_label, fd); + return (fd); + } + if (msg_verbose) + msg_info("%s: not found: %s", myname, endp_label); + return (-1); +} + +/* scache_single_free_dest - discard destination/endpoint association */ + +static void scache_single_free_dest(SCACHE_SINGLE *sp) +{ + const char *myname = "scache_single_free_dest"; + + if (msg_verbose) + msg_info("%s: %s -> %s", myname, STR(sp->dest.dest_label), + STR(sp->dest.endp_label)); + + event_cancel_timer(scache_single_expire_dest, (void *) sp); + VSTRING_RESET(sp->dest.dest_label); + VSTRING_TERMINATE(sp->dest.dest_label); + VSTRING_RESET(sp->dest.dest_prop); + VSTRING_TERMINATE(sp->dest.dest_prop); + VSTRING_RESET(sp->dest.endp_label); + VSTRING_TERMINATE(sp->dest.endp_label); +} + +/* scache_single_expire_dest - discard expired destination/endpoint binding */ + +static void scache_single_expire_dest(int unused_event, void *context) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) context; + + scache_single_free_dest(sp); +} + +/* scache_single_save_dest - create destination/endpoint association */ + +static void scache_single_save_dest(SCACHE *scache, int dest_ttl, + const char *dest_label, + const char *dest_prop, + const char *endp_label) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; + const char *myname = "scache_single_save_dest"; + int refresh; + + if (dest_ttl <= 0) + msg_panic("%s: bad dest_ttl: %d", myname, dest_ttl); + + /* + * Optimize: reset timer only, if nothing has changed. + */ + refresh = + (SCACHE_SINGLE_DEST_BUSY(sp) + && strcmp(STR(sp->dest.dest_label), dest_label) == 0 + && strcmp(STR(sp->dest.dest_prop), dest_prop) == 0 + && strcmp(STR(sp->dest.endp_label), endp_label) == 0); + + if (refresh == 0) { + vstring_strcpy(sp->dest.dest_label, dest_label); + vstring_strcpy(sp->dest.dest_prop, dest_prop); + vstring_strcpy(sp->dest.endp_label, endp_label); + } + event_request_timer(scache_single_expire_dest, (void *) sp, dest_ttl); + + if (msg_verbose) + msg_info("%s: %s -> %s%s", myname, dest_label, endp_label, + refresh ? " (refreshed)" : ""); +} + +/* scache_single_find_dest - look up cached session */ + +static int scache_single_find_dest(SCACHE *scache, const char *dest_label, + VSTRING *dest_prop, VSTRING *endp_prop) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; + const char *myname = "scache_single_find_dest"; + int fd; + + if (!SCACHE_SINGLE_DEST_BUSY(sp)) { + if (msg_verbose) + msg_info("%s: no destination cache: %s", myname, dest_label); + return (-1); + } + if (strcmp(STR(sp->dest.dest_label), dest_label) == 0) { + if (msg_verbose) + msg_info("%s: found: %s", myname, dest_label); + if ((fd = scache_single_find_endp(scache, STR(sp->dest.endp_label), endp_prop)) >= 0) { + vstring_strcpy(dest_prop, STR(sp->dest.dest_prop)); + return (fd); + } + } + if (msg_verbose) + msg_info("%s: not found: %s", myname, dest_label); + return (-1); +} + +/* scache_single_size - size of single-element cache :-) */ + +static void scache_single_size(SCACHE *scache, SCACHE_SIZE *size) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; + + size->dest_count = (!SCACHE_SINGLE_DEST_BUSY(sp) ? 0 : 1); + size->endp_count = (!SCACHE_SINGLE_ENDP_BUSY(sp) ? 0 : 1); + size->sess_count = (sp->endp.fd < 0 ? 0 : 1); +} + +/* scache_single_free - destroy single-element cache object */ + +static void scache_single_free(SCACHE *scache) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; + + vstring_free(sp->endp.endp_label); + vstring_free(sp->endp.endp_prop); + if (sp->endp.fd >= 0) + close(sp->endp.fd); + + vstring_free(sp->dest.dest_label); + vstring_free(sp->dest.dest_prop); + vstring_free(sp->dest.endp_label); + + myfree((void *) sp); +} + +/* scache_single_create - initialize */ + +SCACHE *scache_single_create(void) +{ + SCACHE_SINGLE *sp = (SCACHE_SINGLE *) mymalloc(sizeof(*sp)); + + sp->scache->save_endp = scache_single_save_endp; + sp->scache->find_endp = scache_single_find_endp; + sp->scache->save_dest = scache_single_save_dest; + sp->scache->find_dest = scache_single_find_dest; + sp->scache->size = scache_single_size; + sp->scache->free = scache_single_free; + + sp->endp.endp_label = vstring_alloc(10); + sp->endp.endp_prop = vstring_alloc(10); + sp->endp.fd = -1; + + sp->dest.dest_label = vstring_alloc(10); + sp->dest.dest_prop = vstring_alloc(10); + sp->dest.endp_label = vstring_alloc(10); + + return (sp->scache); +} |