xref: /netbsd-src/external/ibm-public/postfix/dist/src/global/scache_single.c (revision e89934bbf778a6d6d6894877c4da59d0c7835b0f)
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