Postfix3.3.1
abounce.c
[詳解]
1 /*++
2 /* NAME
3 /* abounce 3
4 /* SUMMARY
5 /* asynchronous bounce/defer/trace service client
6 /* SYNOPSIS
7 /* #include <abounce.h>
8 /*
9 /* void abounce_flush(flags, queue, id, encoding, smtputf8, sender,
10 /* dsn_envid, dsn_ret, callback, context)
11 /* int flags;
12 /* const char *queue;
13 /* const char *id;
14 /* const char *encoding;
15 /* int smtputf8;
16 /* const char *sender;
17 /* const char *dsn_envid;
18 /* int dsn_ret;
19 /* void (*callback)(int status, void *context);
20 /* void *context;
21 /*
22 /* void abounce_flush_verp(flags, queue, id, encoding, smtputf8, sender,
23 /* dsn_envid, dsn_ret, verp, callback, context)
24 /* int flags;
25 /* const char *queue;
26 /* const char *id;
27 /* const char *encoding;
28 /* int smtputf8;
29 /* const char *sender;
30 /* const char *dsn_envid;
31 /* int dsn_ret;
32 /* const char *verp;
33 /* void (*callback)(int status, void *context);
34 /* void *context;
35 /*
36 /* void adefer_flush(flags, queue, id, encoding, smtputf8, sender,
37 /* dsn_envid, dsn_ret, callback, context)
38 /* int flags;
39 /* const char *queue;
40 /* const char *id;
41 /* const char *encoding;
42 /* int smtputf8;
43 /* const char *sender;
44 /* const char *dsn_envid;
45 /* int dsn_ret;
46 /* void (*callback)(int status, void *context);
47 /* void *context;
48 /*
49 /* void adefer_flush_verp(flags, queue, id, encoding, smtputf8, sender,
50 /* dsn_envid, dsn_ret, verp, callback, context)
51 /* int flags;
52 /* const char *queue;
53 /* const char *id;
54 /* const char *encoding;
55 /* int smtputf8;
56 /* const char *sender;
57 /* const char *dsn_envid;
58 /* int dsn_ret;
59 /* const char *verp;
60 /* void (*callback)(int status, void *context);
61 /* void *context;
62 /*
63 /* void adefer_warn(flags, queue, id, encoding, smtputf8, sender,
64 /* dsn_envid, dsn_ret, callback, context)
65 /* int flags;
66 /* const char *queue;
67 /* const char *id;
68 /* const char *encoding;
69 /* int smtputf8;
70 /* const char *sender;
71 /* const char *dsn_envid;
72 /* int dsn_ret;
73 /* void (*callback)(int status, void *context);
74 /* void *context;
75 /*
76 /* void atrace_flush(flags, queue, id, encoding, smtputf8, sender,
77 /* dsn_envid, dsn_ret, callback, context)
78 /* int flags;
79 /* const char *queue;
80 /* const char *id;
81 /* const char *encoding;
82 /* int smtputf8;
83 /* const char *sender;
84 /* const char *dsn_envid;
85 /* int dsn_ret;
86 /* void (*callback)(int status, void *context);
87 /* void *context;
88 /* DESCRIPTION
89 /* This module implements an asynchronous interface to the
90 /* bounce/defer/trace service for submitting sender notifications
91 /* without waiting for completion of the request.
92 /*
93 /* abounce_flush() bounces the specified message to
94 /* the specified sender, including the bounce log that was
95 /* built with bounce_append().
96 /*
97 /* abounce_flush_verp() is like abounce_flush() but sends
98 /* one VERP style notification per undeliverable recipient.
99 /*
100 /* adefer_flush() bounces the specified message to
101 /* the specified sender, including the defer log that was
102 /* built with defer_append().
103 /* adefer_flush() requests that the deferred recipients are deleted
104 /* from the original queue file.
105 /*
106 /* adefer_flush_verp() is like adefer_flush() but sends
107 /* one VERP style notification per undeliverable recipient.
108 /*
109 /* adefer_warn() sends a "mail is delayed" notification to
110 /* the specified sender, including the defer log that was
111 /* built with defer_append().
112 /*
113 /* atrace_flush() returns the specified message to the specified
114 /* sender, including the message delivery record log that was
115 /* built with vtrace_append().
116 /*
117 /* Arguments:
118 /* .IP flags
119 /* The bitwise OR of zero or more of the following (specify
120 /* BOUNCE_FLAG_NONE to request no special processing):
121 /* .RS
122 /* .IP BOUNCE_FLAG_CLEAN
123 /* Delete the bounce log in case of an error (as in: pretend
124 /* that we never even tried to bounce this message).
125 /* .IP BOUNCE_FLAG_DELRCPT
126 /* When specified with a flush operation, request that
127 /* recipients be deleted from the queue file.
128 /*
129 /* Note: the bounce daemon ignores this request when the
130 /* recipient queue file offset is <= 0.
131 /* .IP BOUNCE_FLAG_COPY
132 /* Request that a postmaster copy is sent.
133 /* .RE
134 /* .IP queue
135 /* The message queue name of the original message file.
136 /* .IP id
137 /* The message queue id if the original message file. The bounce log
138 /* file has the same name as the original message file.
139 /* .IP encoding
140 /* The body content encoding: MAIL_ATTR_ENC_{7BIT,8BIT,NONE}.
141 /* .IP smtputf8
142 /* The level of SMTPUTF8 support (to be defined).
143 /* .IP sender
144 /* The sender envelope address.
145 /* .IP dsn_envid
146 /* Optional DSN envelope ID.
147 /* .IP ret
148 /* Optional DSN return full/headers option.
149 /* .IP verp
150 /* VERP delimiter characters.
151 /* .IP callback
152 /* Name of a routine that receives the notification status as
153 /* documented for bounce_flush() or defer_flush().
154 /* .IP context
155 /* Application-specific context that is passed through to the
156 /* callback routine. Use proper casts or the world will come
157 /* to an end.
158 /* DIAGNOSTICS
159 /* In case of success, these functions log the action, and return a
160 /* zero result via the callback routine. Otherwise, the functions
161 /* return a non-zero result via the callback routine, and when
162 /* BOUNCE_FLAG_CLEAN is disabled, log that message delivery is deferred.
163 /* LICENSE
164 /* .ad
165 /* .fi
166 /* The Secure Mailer license must be distributed with this software.
167 /* AUTHOR(S)
168 /* Wietse Venema
169 /* IBM T.J. Watson Research
170 /* P.O. Box 704
171 /* Yorktown Heights, NY 10598, USA
172 /*--*/
173 
174 /* System library. */
175 
176 #include <sys_defs.h>
177 
178 /* Utility library. */
179 
180 #include <msg.h>
181 #include <mymalloc.h>
182 #include <events.h>
183 #include <vstream.h>
184 
185 /* Global library. */
186 
187 #include <mail_params.h>
188 #include <mail_proto.h>
189 #include <abounce.h>
190 
191 /* Application-specific. */
192 
193  /*
194  * Each bounce/defer flush/warn request is implemented by sending the
195  * request to the bounce/defer server, and by creating a pseudo thread that
196  * suspends itself until the server replies (or dies). Upon wakeup, the
197  * pseudo thread delivers the request completion status to the application
198  * and destroys itself. The structure below maintains all the necessary
199  * request state while the pseudo thread is suspended.
200  */
201 typedef struct {
202  int command; /* bounce request type */
203  int flags; /* bounce options */
204  char *id; /* queue ID for logging */
205  ABOUNCE_FN callback; /* application callback */
206  void *context; /* application context */
207  VSTREAM *fp; /* server I/O handle */
208 } ABOUNCE;
209 
210  /*
211  * Encapsulate common code.
212  */
213 #define ABOUNCE_EVENT_ENABLE(fd, callback, context, timeout) do { \
214  event_enable_read((fd), (callback), (context)); \
215  event_request_timer((callback), (context), (timeout)); \
216  } while (0)
217 
218 #define ABOUNCE_EVENT_DISABLE(fd, callback, context) do { \
219  event_cancel_timer((callback), (context)); \
220  event_disable_readwrite(fd); \
221  } while (0)
222 
223  /*
224  * If we set the reply timeout too short, then we make the problem worse by
225  * increasing overload. With 1000s timeout mail will keep flowing, but there
226  * will be a large number of blocked bounce processes, and some resource is
227  * likely to run out.
228  */
229 #define ABOUNCE_TIMEOUT 1000
230 
231 /* abounce_done - deliver status to application and clean up pseudo thread */
232 
233 static void abounce_done(ABOUNCE *ap, int status)
234 {
235  (void) vstream_fclose(ap->fp);
236  if (status != 0 && (ap->flags & BOUNCE_FLAG_CLEAN) == 0)
237  msg_info("%s: status=deferred (%s failed)", ap->id,
238  ap->command == BOUNCE_CMD_FLUSH ? "bounce" :
239  ap->command == BOUNCE_CMD_WARN ? "delay warning" :
240  ap->command == BOUNCE_CMD_VERP ? "verp" :
241  ap->command == BOUNCE_CMD_TRACE ? "trace" :
242  "whatever");
243  ap->callback(status, ap->context);
244  myfree(ap->id);
245  myfree((void *) ap);
246 }
247 
248 /* abounce_event - resume pseudo thread after server reply event */
249 
250 static void abounce_event(int event, void *context)
251 {
252  ABOUNCE *ap = (ABOUNCE *) context;
253  int status;
254 
255  ABOUNCE_EVENT_DISABLE(vstream_fileno(ap->fp), abounce_event, context);
256  abounce_done(ap, (event != EVENT_TIME
257  && attr_scan(ap->fp, ATTR_FLAG_STRICT,
259  ATTR_TYPE_END) == 1) ? status : -1);
260 }
261 
262 /* abounce_request_verp - suspend pseudo thread until server reply event */
263 
264 static void abounce_request_verp(const char *class, const char *service,
265  int command, int flags,
266  const char *queue, const char *id,
267  const char *encoding,
268  int smtputf8,
269  const char *sender,
270  const char *dsn_envid,
271  int dsn_ret,
272  const char *verp,
273  ABOUNCE_FN callback,
274  void *context)
275 {
276  ABOUNCE *ap;
277 
278  /*
279  * Save pseudo thread state. Connect to the server. Send the request and
280  * suspend the pseudo thread until the server replies (or dies).
281  */
282  ap = (ABOUNCE *) mymalloc(sizeof(*ap));
283  ap->command = command;
284  ap->flags = flags;
285  ap->id = mystrdup(id);
286  ap->callback = callback;
287  ap->context = context;
288  ap->fp = mail_connect_wait(class, service);
289 
290  if (attr_print(ap->fp, ATTR_FLAG_NONE,
291  SEND_ATTR_INT(MAIL_ATTR_NREQ, command),
301  ATTR_TYPE_END) == 0
302  && vstream_fflush(ap->fp) == 0) {
303  ABOUNCE_EVENT_ENABLE(vstream_fileno(ap->fp), abounce_event,
304  (void *) ap, ABOUNCE_TIMEOUT);
305  } else {
306  abounce_done(ap, -1);
307  }
308 }
309 
310 /* abounce_flush_verp - asynchronous bounce flush */
311 
312 void abounce_flush_verp(int flags, const char *queue, const char *id,
313  const char *encoding, int smtputf8,
314  const char *sender, const char *dsn_envid,
315  int dsn_ret, const char *verp,
316  ABOUNCE_FN callback,
317  void *context)
318 {
319  abounce_request_verp(MAIL_CLASS_PRIVATE, var_bounce_service,
320  BOUNCE_CMD_VERP, flags, queue, id, encoding, smtputf8,
321  sender, dsn_envid, dsn_ret, verp, callback, context);
322 }
323 
324 /* adefer_flush_verp - asynchronous defer flush */
325 
326 void adefer_flush_verp(int flags, const char *queue, const char *id,
327  const char *encoding, int smtputf8,
328  const char *sender, const char *dsn_envid,
329  int dsn_ret, const char *verp,
330  ABOUNCE_FN callback, void *context)
331 {
332  flags |= BOUNCE_FLAG_DELRCPT;
333  abounce_request_verp(MAIL_CLASS_PRIVATE, var_defer_service,
334  BOUNCE_CMD_VERP, flags, queue, id, encoding, smtputf8,
335  sender, dsn_envid, dsn_ret, verp, callback, context);
336 }
337 
338 /* abounce_request - suspend pseudo thread until server reply event */
339 
340 static void abounce_request(const char *class, const char *service,
341  int command, int flags,
342  const char *queue, const char *id,
343  const char *encoding, int smtputf8,
344  const char *sender,
345  const char *dsn_envid, int dsn_ret,
346  ABOUNCE_FN callback, void *context)
347 {
348  ABOUNCE *ap;
349 
350  /*
351  * Save pseudo thread state. Connect to the server. Send the request and
352  * suspend the pseudo thread until the server replies (or dies).
353  */
354  ap = (ABOUNCE *) mymalloc(sizeof(*ap));
355  ap->command = command;
356  ap->flags = flags;
357  ap->id = mystrdup(id);
358  ap->callback = callback;
359  ap->context = context;
360  ap->fp = mail_connect_wait(class, service);
361 
362  if (attr_print(ap->fp, ATTR_FLAG_NONE,
363  SEND_ATTR_INT(MAIL_ATTR_NREQ, command),
372  ATTR_TYPE_END) == 0
373  && vstream_fflush(ap->fp) == 0) {
374  ABOUNCE_EVENT_ENABLE(vstream_fileno(ap->fp), abounce_event,
375  (void *) ap, ABOUNCE_TIMEOUT);
376  } else {
377  abounce_done(ap, -1);
378  }
379 }
380 
381 /* abounce_flush - asynchronous bounce flush */
382 
383 void abounce_flush(int flags, const char *queue, const char *id,
384  const char *encoding, int smtputf8,
385  const char *sender, const char *dsn_envid,
386  int dsn_ret, ABOUNCE_FN callback,
387  void *context)
388 {
390  flags, queue, id, encoding, smtputf8, sender, dsn_envid,
391  dsn_ret, callback, context);
392 }
393 
394 /* adefer_flush - asynchronous defer flush */
395 
396 void adefer_flush(int flags, const char *queue, const char *id,
397  const char *encoding, int smtputf8,
398  const char *sender, const char *dsn_envid,
399  int dsn_ret, ABOUNCE_FN callback, void *context)
400 {
401  flags |= BOUNCE_FLAG_DELRCPT;
403  flags, queue, id, encoding, smtputf8, sender, dsn_envid,
404  dsn_ret, callback, context);
405 }
406 
407 /* adefer_warn - send copy of defer log to sender as warning bounce */
408 
409 void adefer_warn(int flags, const char *queue, const char *id,
410  const char *encoding, int smtputf8,
411  const char *sender, const char *dsn_envid,
412  int dsn_ret, ABOUNCE_FN callback, void *context)
413 {
415  flags, queue, id, encoding, smtputf8, sender, dsn_envid,
416  dsn_ret, callback, context);
417 }
418 
419 /* atrace_flush - asynchronous trace flush */
420 
421 void atrace_flush(int flags, const char *queue, const char *id,
422  const char *encoding, int smtputf8,
423  const char *sender, const char *dsn_envid,
424  int dsn_ret, ABOUNCE_FN callback, void *context)
425 {
427  flags, queue, id, encoding, smtputf8, sender, dsn_envid,
428  dsn_ret, callback, context);
429 }
void abounce_flush_verp(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, const char *verp, ABOUNCE_FN callback, void *context)
Definition: abounce.c:312
void abounce_flush(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, ABOUNCE_FN callback, void *context)
Definition: abounce.c:383
#define ATTR_FLAG_NONE
Definition: attr.h:98
void myfree(void *ptr)
Definition: mymalloc.c:207
VSTREAM * mail_connect_wait(const char *class, const char *name)
Definition: mail_connect.c:108
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define MAIL_ATTR_ENCODING
Definition: mail_proto.h:202
void * context
Definition: abounce.c:206
ABOUNCE_FN callback
Definition: abounce.c:205
#define BOUNCE_CMD_TRACE
Definition: bounce.h:48
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
void atrace_flush(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, ABOUNCE_FN callback, void *context)
Definition: abounce.c:421
int command
Definition: abounce.c:202
#define ABOUNCE_TIMEOUT
Definition: abounce.c:229
#define ABOUNCE_EVENT_ENABLE(fd, callback, context, timeout)
Definition: abounce.c:213
#define BOUNCE_FLAG_CLEAN
Definition: bounce.h:61
#define MAIL_ATTR_QUEUE
Definition: mail_proto.h:129
void(* ABOUNCE_FN)(int, void *)
Definition: abounce.h:22
#define attr_print
Definition: attr.h:109
char * id
Definition: abounce.c:204
#define MAIL_ATTR_NREQ
Definition: mail_proto.h:125
char * var_trace_service
Definition: mail_params.c:311
int vstream_fclose(VSTREAM *stream)
Definition: vstream.c:1268
#define MAIL_ATTR_SMTPUTF8
Definition: mail_proto.h:277
#define BOUNCE_CMD_VERP
Definition: bounce.h:46
#define MAIL_ATTR_DSN_RET
Definition: mail_proto.h:274
#define ABOUNCE_EVENT_DISABLE(fd, callback, context)
Definition: abounce.c:218
#define BOUNCE_CMD_WARN
Definition: bounce.h:45
char * var_bounce_service
Definition: mail_params.c:301
char * var_defer_service
Definition: mail_params.c:303
#define MAIL_ATTR_DSN_ENVID
Definition: mail_proto.h:273
#define MAIL_ATTR_STATUS
Definition: mail_proto.h:126
#define SEND_ATTR_INT(name, val)
Definition: attr.h:63
VSTREAM * fp
Definition: abounce.c:207
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
void adefer_flush(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, ABOUNCE_FN callback, void *context)
Definition: abounce.c:396
#define EVENT_TIME
Definition: events.h:43
#define BOUNCE_CMD_FLUSH
Definition: bounce.h:44
#define MAIL_ATTR_SENDER
Definition: mail_proto.h:131
int flags
Definition: abounce.c:203
#define vstream_fileno(vp)
Definition: vstream.h:115
void adefer_flush_verp(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, const char *verp, ABOUNCE_FN callback, void *context)
Definition: abounce.c:326
#define MAIL_ATTR_QUEUEID
Definition: mail_proto.h:130
#define attr_scan
Definition: attr.h:111
#define MAIL_ATTR_VERPDL
Definition: mail_proto.h:136
#define BOUNCE_FLAG_DELRCPT
Definition: bounce.h:62
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
void adefer_warn(int flags, const char *queue, const char *id, const char *encoding, int smtputf8, const char *sender, const char *dsn_envid, int dsn_ret, ABOUNCE_FN callback, void *context)
Definition: abounce.c:409
#define MAIL_ATTR_FLAGS
Definition: mail_proto.h:128
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
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