1/*++ 2/* NAME 3/* scache_single 3 4/* SUMMARY 5/* single-item session cache 6/* SYNOPSIS 7/* #include <scache.h> 8/* DESCRIPTION 9/* SCACHE *scache_single_create() 10/* DESCRIPTION 11/* This module implements an in-memory, single-session cache. 12/* 13/* scache_single_create() creates a session cache instance 14/* that stores a single session. 15/* DIAGNOSTICS 16/* Fatal error: memory allocation problem; 17/* panic: internal consistency failure. 18/* SEE ALSO 19/* scache(3), generic session cache API 20/* LICENSE 21/* .ad 22/* .fi 23/* The Secure Mailer license must be distributed with this software. 24/* AUTHOR(S) 25/* Wietse Venema 26/* IBM T.J. Watson Research 27/* P.O. Box 704 28/* Yorktown Heights, NY 10598, USA 29/*--*/ 30 31/* System library. */ 32 33#include <sys_defs.h> 34#include <unistd.h> 35#include <string.h> 36 37/* Utility library. */ 38 39#include <msg.h> 40#include <vstring.h> 41#include <mymalloc.h> 42#include <events.h> 43 44/*#define msg_verbose 1*/ 45 46/* Global library. */ 47 48#include <scache.h> 49 50/* Application-specific. */ 51 52 /* 53 * Data structure for one saved connection. It is left up to the application 54 * to serialize attributes upon passivation, and to de-serialize them upon 55 * re-activation. 56 */ 57typedef struct { 58 VSTRING *endp_label; /* physical endpoint name */ 59 VSTRING *endp_prop; /* endpoint properties, serialized */ 60 int fd; /* the session */ 61} SCACHE_SINGLE_ENDP; 62 63 /* 64 * Data structure for a logical name to physical endpoint binding. It is 65 * left up to the application to serialize attributes upon passivation, and 66 * to de-serialize then upon re-activation. 67 */ 68typedef struct { 69 VSTRING *dest_label; /* logical destination name */ 70 VSTRING *dest_prop; /* binding properties, serialized */ 71 VSTRING *endp_label; /* physical endpoint name */ 72} SCACHE_SINGLE_DEST; 73 74 /* 75 * SCACHE_SINGLE is a derived type from the SCACHE super-class. 76 */ 77typedef struct { 78 SCACHE scache[1]; /* super-class */ 79 SCACHE_SINGLE_ENDP endp; /* one cached session */ 80 SCACHE_SINGLE_DEST dest; /* one cached binding */ 81} SCACHE_SINGLE; 82 83static void scache_single_expire_endp(int, char *); 84static void scache_single_expire_dest(int, char *); 85 86#define SCACHE_SINGLE_ENDP_BUSY(sp) (VSTRING_LEN(sp->endp.endp_label) > 0) 87#define SCACHE_SINGLE_DEST_BUSY(sp) (VSTRING_LEN(sp->dest.dest_label) > 0) 88 89#define STR(x) vstring_str(x) 90 91/* scache_single_free_endp - discard endpoint */ 92 93static void scache_single_free_endp(SCACHE_SINGLE *sp) 94{ 95 const char *myname = "scache_single_free_endp"; 96 97 if (msg_verbose) 98 msg_info("%s: %s", myname, STR(sp->endp.endp_label)); 99 100 event_cancel_timer(scache_single_expire_endp, (char *) sp); 101 if (sp->endp.fd >= 0 && close(sp->endp.fd) < 0) 102 msg_warn("close session endpoint %s: %m", STR(sp->endp.endp_label)); 103 VSTRING_RESET(sp->endp.endp_label); 104 VSTRING_TERMINATE(sp->endp.endp_label); 105 VSTRING_RESET(sp->endp.endp_prop); 106 VSTRING_TERMINATE(sp->endp.endp_prop); 107 sp->endp.fd = -1; 108} 109 110/* scache_single_expire_endp - discard expired session */ 111 112static void scache_single_expire_endp(int unused_event, char *context) 113{ 114 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) context; 115 116 scache_single_free_endp(sp); 117} 118 119/* scache_single_save_endp - save endpoint */ 120 121static void scache_single_save_endp(SCACHE *scache, int endp_ttl, 122 const char *endp_label, 123 const char *endp_prop, int fd) 124{ 125 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; 126 const char *myname = "scache_single_save_endp"; 127 128 if (endp_ttl <= 0) 129 msg_panic("%s: bad endp_ttl: %d", myname, endp_ttl); 130 131 if (SCACHE_SINGLE_ENDP_BUSY(sp)) 132 scache_single_free_endp(sp); /* dump the cached fd */ 133 134 vstring_strcpy(sp->endp.endp_label, endp_label); 135 vstring_strcpy(sp->endp.endp_prop, endp_prop); 136 sp->endp.fd = fd; 137 event_request_timer(scache_single_expire_endp, (char *) sp, endp_ttl); 138 139 if (msg_verbose) 140 msg_info("%s: %s fd=%d", myname, endp_label, fd); 141} 142 143/* scache_single_find_endp - look up cached session */ 144 145static int scache_single_find_endp(SCACHE *scache, const char *endp_label, 146 VSTRING *endp_prop) 147{ 148 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; 149 const char *myname = "scache_single_find_endp"; 150 int fd; 151 152 if (!SCACHE_SINGLE_ENDP_BUSY(sp)) { 153 if (msg_verbose) 154 msg_info("%s: no endpoint cache: %s", myname, endp_label); 155 return (-1); 156 } 157 if (strcmp(STR(sp->endp.endp_label), endp_label) == 0) { 158 vstring_strcpy(endp_prop, STR(sp->endp.endp_prop)); 159 fd = sp->endp.fd; 160 sp->endp.fd = -1; 161 scache_single_free_endp(sp); 162 if (msg_verbose) 163 msg_info("%s: found: %s fd=%d", myname, endp_label, fd); 164 return (fd); 165 } 166 if (msg_verbose) 167 msg_info("%s: not found: %s", myname, endp_label); 168 return (-1); 169} 170 171/* scache_single_free_dest - discard destination/endpoint association */ 172 173static void scache_single_free_dest(SCACHE_SINGLE *sp) 174{ 175 const char *myname = "scache_single_free_dest"; 176 177 if (msg_verbose) 178 msg_info("%s: %s -> %s", myname, STR(sp->dest.dest_label), 179 STR(sp->dest.endp_label)); 180 181 event_cancel_timer(scache_single_expire_dest, (char *) sp); 182 VSTRING_RESET(sp->dest.dest_label); 183 VSTRING_TERMINATE(sp->dest.dest_label); 184 VSTRING_RESET(sp->dest.dest_prop); 185 VSTRING_TERMINATE(sp->dest.dest_prop); 186 VSTRING_RESET(sp->dest.endp_label); 187 VSTRING_TERMINATE(sp->dest.endp_label); 188} 189 190/* scache_single_expire_dest - discard expired destination/endpoint binding */ 191 192static void scache_single_expire_dest(int unused_event, char *context) 193{ 194 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) context; 195 196 scache_single_free_dest(sp); 197} 198 199/* scache_single_save_dest - create destination/endpoint association */ 200 201static void scache_single_save_dest(SCACHE *scache, int dest_ttl, 202 const char *dest_label, 203 const char *dest_prop, 204 const char *endp_label) 205{ 206 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; 207 const char *myname = "scache_single_save_dest"; 208 int refresh; 209 210 if (dest_ttl <= 0) 211 msg_panic("%s: bad dest_ttl: %d", myname, dest_ttl); 212 213 /* 214 * Optimize: reset timer only, if nothing has changed. 215 */ 216 refresh = 217 (SCACHE_SINGLE_DEST_BUSY(sp) 218 && strcmp(STR(sp->dest.dest_label), dest_label) == 0 219 && strcmp(STR(sp->dest.dest_prop), dest_prop) == 0 220 && strcmp(STR(sp->dest.endp_label), endp_label) == 0); 221 222 if (refresh == 0) { 223 vstring_strcpy(sp->dest.dest_label, dest_label); 224 vstring_strcpy(sp->dest.dest_prop, dest_prop); 225 vstring_strcpy(sp->dest.endp_label, endp_label); 226 } 227 event_request_timer(scache_single_expire_dest, (char *) sp, dest_ttl); 228 229 if (msg_verbose) 230 msg_info("%s: %s -> %s%s", myname, dest_label, endp_label, 231 refresh ? " (refreshed)" : ""); 232} 233 234/* scache_single_find_dest - look up cached session */ 235 236static int scache_single_find_dest(SCACHE *scache, const char *dest_label, 237 VSTRING *dest_prop, VSTRING *endp_prop) 238{ 239 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; 240 const char *myname = "scache_single_find_dest"; 241 int fd; 242 243 if (!SCACHE_SINGLE_DEST_BUSY(sp)) { 244 if (msg_verbose) 245 msg_info("%s: no destination cache: %s", myname, dest_label); 246 return (-1); 247 } 248 if (strcmp(STR(sp->dest.dest_label), dest_label) == 0) { 249 if (msg_verbose) 250 msg_info("%s: found: %s", myname, dest_label); 251 if ((fd = scache_single_find_endp(scache, STR(sp->dest.endp_label), endp_prop)) >= 0) { 252 vstring_strcpy(dest_prop, STR(sp->dest.dest_prop)); 253 return (fd); 254 } 255 } 256 if (msg_verbose) 257 msg_info("%s: not found: %s", myname, dest_label); 258 return (-1); 259} 260 261/* scache_single_size - size of single-element cache :-) */ 262 263static void scache_single_size(SCACHE *scache, SCACHE_SIZE *size) 264{ 265 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; 266 267 size->dest_count = (!SCACHE_SINGLE_DEST_BUSY(sp) ? 0 : 1); 268 size->endp_count = (!SCACHE_SINGLE_ENDP_BUSY(sp) ? 0 : 1); 269 size->sess_count = (sp->endp.fd < 0 ? 0 : 1); 270} 271 272/* scache_single_free - destroy single-element cache object */ 273 274static void scache_single_free(SCACHE *scache) 275{ 276 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) scache; 277 278 vstring_free(sp->endp.endp_label); 279 vstring_free(sp->endp.endp_prop); 280 if (sp->endp.fd >= 0) 281 close(sp->endp.fd); 282 283 vstring_free(sp->dest.dest_label); 284 vstring_free(sp->dest.dest_prop); 285 vstring_free(sp->dest.endp_label); 286 287 myfree((char *) sp); 288} 289 290/* scache_single_create - initialize */ 291 292SCACHE *scache_single_create(void) 293{ 294 SCACHE_SINGLE *sp = (SCACHE_SINGLE *) mymalloc(sizeof(*sp)); 295 296 sp->scache->save_endp = scache_single_save_endp; 297 sp->scache->find_endp = scache_single_find_endp; 298 sp->scache->save_dest = scache_single_save_dest; 299 sp->scache->find_dest = scache_single_find_dest; 300 sp->scache->size = scache_single_size; 301 sp->scache->free = scache_single_free; 302 303 sp->endp.endp_label = vstring_alloc(10); 304 sp->endp.endp_prop = vstring_alloc(10); 305 sp->endp.fd = -1; 306 307 sp->dest.dest_label = vstring_alloc(10); 308 sp->dest.dest_prop = vstring_alloc(10); 309 sp->dest.endp_label = vstring_alloc(10); 310 311 return (sp->scache); 312} 313