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