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