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
scache_single_free_endp(SCACHE_SINGLE * sp)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
scache_single_expire_endp(int unused_event,void * context)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
scache_single_save_endp(SCACHE * scache,int endp_ttl,const char * endp_label,const char * endp_prop,int fd)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
scache_single_find_endp(SCACHE * scache,const char * endp_label,VSTRING * endp_prop)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
scache_single_free_dest(SCACHE_SINGLE * sp)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
scache_single_expire_dest(int unused_event,void * context)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
scache_single_save_dest(SCACHE * scache,int dest_ttl,const char * dest_label,const char * dest_prop,const char * endp_label)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
scache_single_find_dest(SCACHE * scache,const char * dest_label,VSTRING * dest_prop,VSTRING * endp_prop)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
scache_single_size(SCACHE * scache,SCACHE_SIZE * size)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
scache_single_free(SCACHE * scache)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
scache_single_create(void)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