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