Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / scache.c
blob5e1523bf641208edbc37f7806f159e3be1718db5
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* scache 3
6 /* SUMMARY
7 /* generic session cache API
8 /* SYNOPSIS
9 /* #include <scache.h>
10 /* DESCRIPTION
11 /* typedef struct {
12 /* .in +4
13 /* int dest_count;
14 /* int endp_count;
15 /* int sess_count;
16 /* .in -4
17 /* } SCACHE_SIZE;
19 /* unsigned scache_size(scache, size)
20 /* SCACHE *scache;
21 /* SCACHE_SIZE *size;
23 /* void scache_free(scache)
24 /* SCACHE *scache;
26 /* void scache_save_endp(scache, endp_ttl, endp_label, endp_prop, fd)
27 /* SCACHE *scache;
28 /* int endp_ttl;
29 /* const char *endp_label;
30 /* const char *endp_prop;
31 /* int fd;
33 /* int scache_find_endp(scache, endp_label, endp_prop)
34 /* SCACHE *scache;
35 /* const char *endp_label;
36 /* VSTRING *endp_prop;
38 /* void scache_save_dest(scache, dest_ttl, dest_label,
39 /* dest_prop, endp_label)
40 /* SCACHE *scache;
41 /* int dest_ttl;
42 /* const char *dest_label;
43 /* const char *dest_prop;
44 /* const char *endp_label;
46 /* int scache_find_dest(dest_label, dest_prop, endp_prop)
47 /* SCACHE *scache;
48 /* const char *dest_label;
49 /* VSTRING *dest_prop;
50 /* VSTRING *endp_prop;
51 /* DESCRIPTION
52 /* This module implements a generic session cache interface.
53 /* Specific cache types are described in scache_single(3),
54 /* scache_clnt(3) and scache_multi(3). These documents also
55 /* describe now to instantiate a specific session cache type.
57 /* The code maintains two types of association: a) physical
58 /* endpoint to file descriptor, and b) logical endpoint
59 /* to physical endpoint. Physical endpoints are stored and
60 /* looked up under their low-level session details such as
61 /* numerical addresses, while logical endpoints are stored
62 /* and looked up by the domain name that humans use. One logical
63 /* endpoint can refer to multiple physical endpoints, one
64 /* physical endpoint may be referenced by multiple logical
65 /* endpoints, and one physical endpoint may have multiple
66 /* sessions.
68 /* scache_size() returns the number of logical destination
69 /* names, physical endpoint addresses, and cached sessions.
71 /* scache_free() destroys the specified session cache.
73 /* scache_save_endp() stores an open session under the specified
74 /* physical endpoint name.
76 /* scache_find_endp() looks up a saved session under the
77 /* specified physical endpoint name.
79 /* scache_save_dest() associates the specified physical endpoint
80 /* with the specified logical endpoint name.
82 /* scache_find_dest() looks up a saved session under the
83 /* specified physical endpoint name.
85 /* Arguments:
86 /* .IP endp_ttl
87 /* How long the session should be cached. When information
88 /* expires it is purged automatically.
89 /* .IP endp_label
90 /* The transport name and the physical endpoint name under
91 /* which the session is stored and looked up.
93 /* In the case of SMTP, the physical endpoint includes the numerical
94 /* IP address, address family information, and the numerical TCP port.
95 /* .IP endp_prop
96 /* Application-specific data with endpoint attributes. It is up to
97 /* the application to passivate (flatten) and re-activate this content
98 /* upon storage and retrieval, respectively.
99 /* .sp
100 /* In the case of SMTP, the endpoint attributes specify the
101 /* server hostname, IP address, numerical TCP port, as well
102 /* as ESMTP features advertised by the server, and when information
103 /* expires. All this in some application-specific format that is easy
104 /* to unravel when re-activating a cached session.
105 /* .IP dest_ttl
106 /* How long the destination-to-endpoint binding should be
107 /* cached. When information expires it is purged automatically.
108 /* .IP dest_label
109 /* The transport name and the logical destination under which the
110 /* destination-to-endpoint binding is stored and looked up.
112 /* In the case of SMTP, the logical destination is the DNS
113 /* host or domain name with or without [], plus the numerical TCP port.
114 /* .IP dest_prop
115 /* Application-specific attributes that describe features of
116 /* this logical to physical binding. It is up to the application
117 /* to passivate (flatten) and re-activate this content.
118 /* upon storage and retrieval, respectively
119 /* .sp
120 /* In case the of an SMTP logical destination to physical
121 /* endpoint binding, the attributes specify the logical
122 /* destination name, numerical port, whether the physical
123 /* endpoint is best mx host with respect to a logical or
124 /* fall-back destination, and when information expires.
125 /* .IP fd
126 /* File descriptor with session to be cached.
127 /* DIAGNOSTICS
128 /* scache_find_endp() and scache_find_dest() return -1 when
129 /* the lookup fails, and a file descriptor upon success.
131 /* Other diagnostics: fatal error: memory allocation problem;
132 /* panic: internal consistency failure.
133 /* SEE ALSO
134 /* scache_single(3), single-session, in-memory cache
135 /* scache_clnt(3), session cache client
136 /* scache_multi(3), multi-session, in-memory cache
137 /* LICENSE
138 /* .ad
139 /* .fi
140 /* The Secure Mailer license must be distributed with this software.
141 /* AUTHOR(S)
142 /* Wietse Venema
143 /* IBM T.J. Watson Research
144 /* P.O. Box 704
145 /* Yorktown Heights, NY 10598, USA
146 /*--*/
148 /* System library. */
150 #include <sys_defs.h>
151 #include <stdlib.h>
152 #include <unistd.h>
153 #include <string.h>
155 /* Utility library. */
157 #include <msg.h>
158 #include <vstream.h>
159 #include <vstring.h>
160 #include <vstring_vstream.h>
161 #include <argv.h>
162 #include <events.h>
164 /* Global library. */
166 #include <scache.h>
168 #ifdef TEST
171 * Driver program for cache regression tests. Although all variants are
172 * relatively simple to verify by hand for single session storage, more
173 * sophisticated instrumentation is needed to demonstrate that the
174 * multi-session cache manager properly handles collisions in the time
175 * domain and in all the name space domains.
177 static SCACHE *scache;
178 static VSTRING *endp_prop;
179 static VSTRING *dest_prop;
180 static int verbose_level = 3;
183 * Cache mode lookup table. We don't do the client-server variant because
184 * that drags in a ton of configuration junk; the client-server protocol is
185 * relatively easy to verify manually.
187 struct cache_type {
188 char *mode;
189 SCACHE *(*create) (void);
192 static struct cache_type cache_types[] = {
193 "single", scache_single_create,
194 "multi", scache_multi_create,
198 #define STR(x) vstring_str(x)
200 /* cache_type - select session cache type */
202 static void cache_type(ARGV *argv)
204 struct cache_type *cp;
206 if (argv->argc != 2) {
207 msg_error("usage: %s mode", argv->argv[0]);
208 return;
210 if (scache != 0)
211 scache_free(scache);
212 for (cp = cache_types; cp->mode != 0; cp++) {
213 if (strcmp(cp->mode, argv->argv[1]) == 0) {
214 scache = cp->create();
215 return;
218 msg_error("unknown cache type: %s", argv->argv[1]);
221 /* handle_events - handle events while time advances */
223 static void handle_events(ARGV *argv)
225 int delay;
226 time_t before;
227 time_t after;
229 if (argv->argc != 2 || (delay = atoi(argv->argv[1])) <= 0) {
230 msg_error("usage: %s time", argv->argv[0]);
231 return;
233 before = event_time();
234 event_drain(delay);
235 after = event_time();
236 if (after < before + delay)
237 sleep(before + delay - after);
240 /* save_endp - save endpoint->session binding */
242 static void save_endp(ARGV *argv)
244 int ttl;
245 int fd;
247 if (argv->argc != 5
248 || (ttl = atoi(argv->argv[1])) <= 0
249 || (fd = atoi(argv->argv[4])) <= 0) {
250 msg_error("usage: save_endp ttl endpoint endp_props fd");
251 return;
253 if (DUP2(0, fd) < 0)
254 msg_fatal("dup2(0, %d): %m", fd);
255 scache_save_endp(scache, ttl, argv->argv[2], argv->argv[3], fd);
258 /* find_endp - find endpoint->session binding */
260 static void find_endp(ARGV *argv)
262 int fd;
264 if (argv->argc != 2) {
265 msg_error("usage: find_endp endpoint");
266 return;
268 if ((fd = scache_find_endp(scache, argv->argv[1], endp_prop)) >= 0)
269 close(fd);
272 /* save_dest - save destination->endpoint binding */
274 static void save_dest(ARGV *argv)
276 int ttl;
278 if (argv->argc != 5 || (ttl = atoi(argv->argv[1])) <= 0) {
279 msg_error("usage: save_dest ttl destination dest_props endpoint");
280 return;
282 scache_save_dest(scache, ttl, argv->argv[2], argv->argv[3], argv->argv[4]);
285 /* find_dest - find destination->endpoint->session binding */
287 static void find_dest(ARGV *argv)
289 int fd;
291 if (argv->argc != 2) {
292 msg_error("usage: find_dest destination");
293 return;
295 if ((fd = scache_find_dest(scache, argv->argv[1], dest_prop, endp_prop)) >= 0)
296 close(fd);
299 /* verbose - adjust noise level during cache manipulation */
301 static void verbose(ARGV *argv)
303 int level;
305 if (argv->argc != 2 || (level = atoi(argv->argv[1])) < 0) {
306 msg_error("usage: verbose level");
307 return;
309 verbose_level = level;
313 * The command lookup table.
315 struct action {
316 char *command;
317 void (*action) (ARGV *);
318 int flags;
321 #define FLAG_NEED_CACHE (1<<0)
323 static void help(ARGV *);
325 static struct action actions[] = {
326 "cache_type", cache_type, 0,
327 "save_endp", save_endp, FLAG_NEED_CACHE,
328 "find_endp", find_endp, FLAG_NEED_CACHE,
329 "save_dest", save_dest, FLAG_NEED_CACHE,
330 "find_dest", find_dest, FLAG_NEED_CACHE,
331 "sleep", handle_events, 0,
332 "verbose", verbose, 0,
333 "?", help, 0,
337 /* help - list commands */
339 static void help(ARGV *argv)
341 struct action *ap;
343 vstream_printf("commands:");
344 for (ap = actions; ap->command != 0; ap++)
345 vstream_printf(" %s", ap->command);
346 vstream_printf("\n");
347 vstream_fflush(VSTREAM_OUT);
350 /* get_buffer - prompt for input or log input */
352 static int get_buffer(VSTRING *buf, VSTREAM *fp, int interactive)
354 int status;
356 if (interactive) {
357 vstream_printf("> ");
358 vstream_fflush(VSTREAM_OUT);
360 if ((status = vstring_get_nonl(buf, fp)) != VSTREAM_EOF) {
361 if (!interactive) {
362 vstream_printf(">>> %s\n", STR(buf));
363 vstream_fflush(VSTREAM_OUT);
366 return (status);
369 /* at last, the main program */
371 int main(int unused_argc, char **unused_argv)
373 VSTRING *buf = vstring_alloc(1);
374 ARGV *argv;
375 struct action *ap;
376 int interactive = isatty(0);
378 endp_prop = vstring_alloc(1);
379 dest_prop = vstring_alloc(1);
381 vstream_fileno(VSTREAM_ERR) = 1;
383 while (get_buffer(buf, VSTREAM_IN, interactive) != VSTREAM_EOF) {
384 argv = argv_split(STR(buf), " \t\r\n");
385 if (argv->argc > 0 && argv->argv[0][0] != '#') {
386 msg_verbose = verbose_level;
387 for (ap = actions; ap->command != 0; ap++) {
388 if (strcmp(ap->command, argv->argv[0]) == 0) {
389 if ((ap->flags & FLAG_NEED_CACHE) != 0 && scache == 0)
390 msg_error("no session cache");
391 else
392 ap->action(argv);
393 break;
396 msg_verbose = 0;
397 if (ap->command == 0)
398 msg_error("bad command: %s", argv->argv[0]);
400 argv_free(argv);
402 scache_free(scache);
403 vstring_free(endp_prop);
404 vstring_free(dest_prop);
405 vstring_free(buf);
406 exit(0);
409 #endif