Postfix3.3.1
scache_clnt.c
[詳解]
1 /*++
2 /* NAME
3 /* scache_clnt 3
4 /* SUMMARY
5 /* session cache manager client
6 /* SYNOPSIS
7 /* #include <scache.h>
8 /* DESCRIPTION
9 /* SCACHE *scache_clnt_create(server, timeout, idle_limit, ttl_limit)
10 /* const char *server;
11 /* int timeout;
12 /* int idle_limit;
13 /* int ttl_limit;
14 /* DESCRIPTION
15 /* This module implements the client-side protocol of the
16 /* session cache service.
17 /*
18 /* scache_clnt_create() creates a session cache service client.
19 /*
20 /* Arguments:
21 /* .IP server
22 /* The session cache service name.
23 /* .IP timeout
24 /* Time limit for connect, send or receive operations.
25 /* .IP idle_limit
26 /* Idle time after which the client disconnects.
27 /* .IP ttl_limit
28 /* Upper bound on the time that a connection is allowed to persist.
29 /* DIAGNOSTICS
30 /* Fatal error: memory allocation problem;
31 /* warning: communication error;
32 /* panic: internal consistency failure.
33 /* SEE ALSO
34 /* scache(3), generic session cache API
35 /* LICENSE
36 /* .ad
37 /* .fi
38 /* The Secure Mailer license must be distributed with this software.
39 /* AUTHOR(S)
40 /* Wietse Venema
41 /* IBM T.J. Watson Research
42 /* P.O. Box 704
43 /* Yorktown Heights, NY 10598, USA
44 /*--*/
45 
46 /* System library. */
47 
48 #include <sys_defs.h>
49 #include <errno.h>
50 
51 /* Utility library. */
52 
53 #include <msg.h>
54 #include <mymalloc.h>
55 #include <auto_clnt.h>
56 #include <stringops.h>
57 
58 /*#define msg_verbose 1*/
59 
60 /* Global library. */
61 
62 #include <mail_proto.h>
63 #include <mail_params.h>
64 #include <scache.h>
65 
66 /* Application-specific. */
67 
68  /*
69  * SCACHE_CLNT is a derived type from the SCACHE super-class.
70  */
71 typedef struct {
72  SCACHE scache[1]; /* super-class */
73  AUTO_CLNT *auto_clnt; /* client endpoint */
74 #ifdef CANT_WRITE_BEFORE_SENDING_FD
75  VSTRING *dummy; /* dummy buffer */
76 #endif
77 } SCACHE_CLNT;
78 
79 #define STR(x) vstring_str(x)
80 
81 #define SCACHE_MAX_TRIES 2
82 
83 /* scache_clnt_save_endp - save endpoint */
84 
85 static void scache_clnt_save_endp(SCACHE *scache, int endp_ttl,
86  const char *endp_label,
87  const char *endp_prop, int fd)
88 {
89  SCACHE_CLNT *sp = (SCACHE_CLNT *) scache;
90  const char *myname = "scache_clnt_save_endp";
91  VSTREAM *stream;
92  int status;
93  int tries;
94  int count = 0;
95 
96  if (msg_verbose)
97  msg_info("%s: endp=%s prop=%s fd=%d",
98  myname, endp_label, endp_prop, fd);
99 
100  /*
101  * Sanity check.
102  */
103  if (endp_ttl <= 0)
104  msg_panic("%s: bad endp_ttl: %d", myname, endp_ttl);
105 
106  /*
107  * Try a few times before disabling the cache. We use synchronous calls;
108  * the session cache service is CPU bound and making the client
109  * asynchronous would just complicate the code.
110  */
111  for (tries = 0; sp->auto_clnt != 0; tries++) {
112  if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
113  errno = 0;
114  count += 1;
115  if (attr_print(stream, ATTR_FLAG_NONE,
117  SEND_ATTR_INT(MAIL_ATTR_TTL, endp_ttl),
118  SEND_ATTR_STR(MAIL_ATTR_LABEL, endp_label),
119  SEND_ATTR_STR(MAIL_ATTR_PROP, endp_prop),
120  ATTR_TYPE_END) != 0
121  || vstream_fflush(stream)
123  || attr_scan(stream, ATTR_FLAG_STRICT,
124  RECV_ATTR_STR(MAIL_ATTR_DUMMY, sp->dummy),
125  ATTR_TYPE_END) != 1
126 #endif
127  || LOCAL_SEND_FD(vstream_fileno(stream), fd) < 0
128  || attr_scan(stream, ATTR_FLAG_STRICT,
130  ATTR_TYPE_END) != 1) {
131  if (msg_verbose || count > 1 || (errno && errno != EPIPE && errno != ENOENT))
132  msg_warn("problem talking to service %s: %m",
133  VSTREAM_PATH(stream));
134  /* Give up or recover. */
135  } else {
136  if (msg_verbose && status != 0)
137  msg_warn("%s: descriptor save failed with status %d",
138  myname, status);
139  break;
140  }
141  }
142  /* Give up or recover. */
143  if (tries >= SCACHE_MAX_TRIES - 1) {
144  msg_warn("disabling connection caching");
146  sp->auto_clnt = 0;
147  break;
148  }
149  sleep(1); /* XXX make configurable */
151  }
152  /* Always close the descriptor before returning. */
153  if (close(fd) < 0)
154  msg_warn("%s: close(%d): %m", myname, fd);
155 }
156 
157 /* scache_clnt_find_endp - look up cached session */
158 
159 static int scache_clnt_find_endp(SCACHE *scache, const char *endp_label,
160  VSTRING *endp_prop)
161 {
162  SCACHE_CLNT *sp = (SCACHE_CLNT *) scache;
163  const char *myname = "scache_clnt_find_endp";
164  VSTREAM *stream;
165  int status;
166  int tries;
167  int fd;
168 
169  /*
170  * Try a few times before disabling the cache. We use synchronous calls;
171  * the session cache service is CPU bound and making the client
172  * asynchronous would just complicate the code.
173  */
174  for (tries = 0; sp->auto_clnt != 0; tries++) {
175  if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
176  errno = 0;
177  if (attr_print(stream, ATTR_FLAG_NONE,
179  SEND_ATTR_STR(MAIL_ATTR_LABEL, endp_label),
180  ATTR_TYPE_END) != 0
181  || vstream_fflush(stream)
182  || attr_scan(stream, ATTR_FLAG_STRICT,
184  RECV_ATTR_STR(MAIL_ATTR_PROP, endp_prop),
185  ATTR_TYPE_END) != 2) {
186  if (msg_verbose || (errno != EPIPE && errno != ENOENT))
187  msg_warn("problem talking to service %s: %m",
188  VSTREAM_PATH(stream));
189  /* Give up or recover. */
190  } else if (status != 0) {
191  if (msg_verbose)
192  msg_info("%s: not found: %s", myname, endp_label);
193  return (-1);
194  } else if (
196  attr_print(stream, ATTR_FLAG_NONE,
198  ATTR_TYPE_END) != 0
199  || vstream_fflush(stream) != 0
200  || read_wait(vstream_fileno(stream),
201  stream->timeout) < 0 || /* XXX */
202 #endif
203  (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
204  if (msg_verbose || (errno != EPIPE && errno != ENOENT))
205  msg_warn("problem talking to service %s: %m",
206  VSTREAM_PATH(stream));
207  /* Give up or recover. */
208  } else {
209 #ifdef MUST_READ_AFTER_SENDING_FD
210  (void) attr_print(stream, ATTR_FLAG_NONE,
212  ATTR_TYPE_END);
213  (void) vstream_fflush(stream);
214 #endif
215  if (msg_verbose)
216  msg_info("%s: endp=%s prop=%s fd=%d",
217  myname, endp_label, STR(endp_prop), fd);
218  return (fd);
219  }
220  }
221  /* Give up or recover. */
222  if (tries >= SCACHE_MAX_TRIES - 1) {
223  msg_warn("disabling connection caching");
225  sp->auto_clnt = 0;
226  return (-1);
227  }
228  sleep(1); /* XXX make configurable */
230  }
231  return (-1);
232 }
233 
234 /* scache_clnt_save_dest - create destination/endpoint association */
235 
236 static void scache_clnt_save_dest(SCACHE *scache, int dest_ttl,
237  const char *dest_label,
238  const char *dest_prop,
239  const char *endp_label)
240 {
241  SCACHE_CLNT *sp = (SCACHE_CLNT *) scache;
242  const char *myname = "scache_clnt_save_dest";
243  VSTREAM *stream;
244  int status;
245  int tries;
246 
247  if (msg_verbose)
248  msg_info("%s: dest_label=%s dest_prop=%s endp_label=%s",
249  myname, dest_label, dest_prop, endp_label);
250 
251  /*
252  * Sanity check.
253  */
254  if (dest_ttl <= 0)
255  msg_panic("%s: bad dest_ttl: %d", myname, dest_ttl);
256 
257  /*
258  * Try a few times before disabling the cache. We use synchronous calls;
259  * the session cache service is CPU bound and making the client
260  * asynchronous would just complicate the code.
261  */
262  for (tries = 0; sp->auto_clnt != 0; tries++) {
263  if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
264  errno = 0;
265  if (attr_print(stream, ATTR_FLAG_NONE,
267  SEND_ATTR_INT(MAIL_ATTR_TTL, dest_ttl),
268  SEND_ATTR_STR(MAIL_ATTR_LABEL, dest_label),
269  SEND_ATTR_STR(MAIL_ATTR_PROP, dest_prop),
270  SEND_ATTR_STR(MAIL_ATTR_LABEL, endp_label),
271  ATTR_TYPE_END) != 0
272  || vstream_fflush(stream)
273  || attr_scan(stream, ATTR_FLAG_STRICT,
275  ATTR_TYPE_END) != 1) {
276  if (msg_verbose || (errno != EPIPE && errno != ENOENT))
277  msg_warn("problem talking to service %s: %m",
278  VSTREAM_PATH(stream));
279  /* Give up or recover. */
280  } else {
281  if (msg_verbose && status != 0)
282  msg_warn("%s: destination save failed with status %d",
283  myname, status);
284  break;
285  }
286  }
287  /* Give up or recover. */
288  if (tries >= SCACHE_MAX_TRIES - 1) {
289  msg_warn("disabling connection caching");
291  sp->auto_clnt = 0;
292  break;
293  }
294  sleep(1); /* XXX make configurable */
296  }
297 }
298 
299 /* scache_clnt_find_dest - look up cached session */
300 
301 static int scache_clnt_find_dest(SCACHE *scache, const char *dest_label,
302  VSTRING *dest_prop,
303  VSTRING *endp_prop)
304 {
305  SCACHE_CLNT *sp = (SCACHE_CLNT *) scache;
306  const char *myname = "scache_clnt_find_dest";
307  VSTREAM *stream;
308  int status;
309  int tries;
310  int fd;
311 
312  /*
313  * Try a few times before disabling the cache. We use synchronous calls;
314  * the session cache service is CPU bound and making the client
315  * asynchronous would just complicate the code.
316  */
317  for (tries = 0; sp->auto_clnt != 0; tries++) {
318  if ((stream = auto_clnt_access(sp->auto_clnt)) != 0) {
319  errno = 0;
320  if (attr_print(stream, ATTR_FLAG_NONE,
322  SEND_ATTR_STR(MAIL_ATTR_LABEL, dest_label),
323  ATTR_TYPE_END) != 0
324  || vstream_fflush(stream)
325  || attr_scan(stream, ATTR_FLAG_STRICT,
327  RECV_ATTR_STR(MAIL_ATTR_PROP, dest_prop),
328  RECV_ATTR_STR(MAIL_ATTR_PROP, endp_prop),
329  ATTR_TYPE_END) != 3) {
330  if (msg_verbose || (errno != EPIPE && errno != ENOENT))
331  msg_warn("problem talking to service %s: %m",
332  VSTREAM_PATH(stream));
333  /* Give up or recover. */
334  } else if (status != 0) {
335  if (msg_verbose)
336  msg_info("%s: not found: %s", myname, dest_label);
337  return (-1);
338  } else if (
340  attr_print(stream, ATTR_FLAG_NONE,
342  ATTR_TYPE_END) != 0
343  || vstream_fflush(stream) != 0
344  || read_wait(vstream_fileno(stream),
345  stream->timeout) < 0 || /* XXX */
346 #endif
347  (fd = LOCAL_RECV_FD(vstream_fileno(stream))) < 0) {
348  if (msg_verbose || (errno != EPIPE && errno != ENOENT))
349  msg_warn("problem talking to service %s: %m",
350  VSTREAM_PATH(stream));
351  /* Give up or recover. */
352  } else {
353 #ifdef MUST_READ_AFTER_SENDING_FD
354  (void) attr_print(stream, ATTR_FLAG_NONE,
356  ATTR_TYPE_END);
357  (void) vstream_fflush(stream);
358 #endif
359  if (msg_verbose)
360  msg_info("%s: dest=%s dest_prop=%s endp_prop=%s fd=%d",
361  myname, dest_label, STR(dest_prop), STR(endp_prop), fd);
362  return (fd);
363  }
364  }
365  /* Give up or recover. */
366  if (tries >= SCACHE_MAX_TRIES - 1) {
367  msg_warn("disabling connection caching");
369  sp->auto_clnt = 0;
370  return (-1);
371  }
372  sleep(1); /* XXX make configurable */
374  }
375  return (-1);
376 }
377 
378 /* scache_clnt_size - dummy */
379 
380 static void scache_clnt_size(SCACHE *unused_scache, SCACHE_SIZE *size)
381 {
382  /* XXX Crap in a hurry. */
383  size->dest_count = 0;
384  size->endp_count = 0;
385  size->sess_count = 0;
386 }
387 
388 /* scache_clnt_free - destroy cache */
389 
390 static void scache_clnt_free(SCACHE *scache)
391 {
392  SCACHE_CLNT *sp = (SCACHE_CLNT *) scache;
393 
394  if (sp->auto_clnt)
396 #ifdef CANT_WRITE_BEFORE_SENDING_FD
397  vstring_free(sp->dummy);
398 #endif
399  myfree((void *) sp);
400 }
401 
402 /* scache_clnt_create - initialize */
403 
404 SCACHE *scache_clnt_create(const char *server, int timeout,
405  int idle_limit, int ttl_limit)
406 {
407  SCACHE_CLNT *sp = (SCACHE_CLNT *) mymalloc(sizeof(*sp));
408  char *service;
409 
410  sp->scache->save_endp = scache_clnt_save_endp;
411  sp->scache->find_endp = scache_clnt_find_endp;
412  sp->scache->save_dest = scache_clnt_save_dest;
413  sp->scache->find_dest = scache_clnt_find_dest;
414  sp->scache->size = scache_clnt_size;
415  sp->scache->free = scache_clnt_free;
416 
417  service = concatenate("local:private/", server, (char *) 0);
418  sp->auto_clnt = auto_clnt_create(service, timeout, idle_limit, ttl_limit);
419  myfree(service);
420 
421 #ifdef CANT_WRITE_BEFORE_SENDING_FD
422  sp->dummy = vstring_alloc(1);
423 #endif
424 
425  return (sp->scache);
426 }
int msg_verbose
Definition: msg.c:177
VSTREAM * auto_clnt_access(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:251
#define LOCAL_RECV_FD
Definition: sys_defs.h:1427
#define ATTR_FLAG_NONE
Definition: attr.h:98
#define SCACHE_REQ_SAVE_DEST
Definition: scache.h:140
void myfree(void *ptr)
Definition: mymalloc.c:207
int dest_count
Definition: scache.h:94
void(* size)(struct SCACHE *, SCACHE_SIZE *)
Definition: scache.h:108
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define MAIL_ATTR_REQ
Definition: mail_proto.h:124
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
int timeout
Definition: vstream.h:58
#define VSTREAM_PATH(vp)
Definition: vstream.h:126
SCACHE_FIND_DEST_FN find_dest
Definition: scache.h:107
#define LOCAL_SEND_FD
Definition: sys_defs.h:1426
#define SCACHE_REQ_FIND_ENDP
Definition: scache.h:137
#define attr_print
Definition: attr.h:109
int sess_count
Definition: scache.h:96
#define CANT_WRITE_BEFORE_SENDING_FD
Definition: sys_defs.h:1704
AUTO_CLNT * auto_clnt_create(const char *service, int timeout, int max_idle, int max_ttl)
Definition: auto_clnt.c:271
#define MAIL_ATTR_DUMMY
Definition: mail_proto.h:160
#define read_wait(fd, timeout)
Definition: iostuff.h:39
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define MAIL_ATTR_TTL
Definition: mail_proto.h:169
SCACHE scache[1]
Definition: scache_clnt.c:72
#define SCACHE_REQ_FIND_DEST
Definition: scache.h:139
#define MAIL_ATTR_LABEL
Definition: mail_proto.h:170
SCACHE_SAVE_ENDP_FN save_endp
Definition: scache.h:104
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
#define SCACHE_REQ_SAVE_ENDP
Definition: scache.h:138
void auto_clnt_free(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:316
SCACHE * scache_clnt_create(const char *server, int timeout, int idle_limit, int ttl_limit)
Definition: scache_clnt.c:404
SCACHE_SAVE_DEST_FN save_dest
Definition: scache.h:106
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
char * concatenate(const char *arg0,...)
Definition: concatenate.c:42
int endp_count
Definition: scache.h:95
SCACHE_FIND_ENDP_FN find_endp
Definition: scache.h:105
void auto_clnt_recover(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:239
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
#define MAIL_ATTR_PROP
Definition: mail_proto.h:171
Definition: scache.h:103
#define STR(x)
Definition: scache_clnt.c:79
#define vstream_fileno(vp)
Definition: vstream.h:115
void(* free)(struct SCACHE *)
Definition: scache.h:109
#define SCACHE_MAX_TRIES
Definition: scache_clnt.c:81
#define attr_scan
Definition: attr.h:111
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
AUTO_CLNT * auto_clnt
Definition: scache_clnt.c:73
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
#define ATTR_FLAG_STRICT
Definition: attr.h:103
void msg_info(const char *fmt,...)
Definition: msg.c:199