Postfix3.3.1
qmgr_transport.c
[詳解]
1 /*++
2 /* NAME
3 /* qmgr_transport 3
4 /* SUMMARY
5 /* per-transport data structures
6 /* SYNOPSIS
7 /* #include "qmgr.h"
8 /*
9 /* QMGR_TRANSPORT *qmgr_transport_create(name)
10 /* const char *name;
11 /*
12 /* QMGR_TRANSPORT *qmgr_transport_find(name)
13 /* const char *name;
14 /*
15 /* QMGR_TRANSPORT *qmgr_transport_select()
16 /*
17 /* void qmgr_transport_alloc(transport, notify)
18 /* QMGR_TRANSPORT *transport;
19 /* void (*notify)(QMGR_TRANSPORT *transport, VSTREAM *fp);
20 /*
21 /* void qmgr_transport_throttle(transport, dsn)
22 /* QMGR_TRANSPORT *transport;
23 /* DSN *dsn;
24 /*
25 /* void qmgr_transport_unthrottle(transport)
26 /* QMGR_TRANSPORT *transport;
27 /* DESCRIPTION
28 /* This module organizes the world by message transport type.
29 /* Each transport can have zero or more destination queues
30 /* associated with it.
31 /*
32 /* qmgr_transport_create() instantiates a data structure for the
33 /* named transport type.
34 /*
35 /* qmgr_transport_find() looks up an existing message transport
36 /* data structure.
37 /*
38 /* qmgr_transport_select() attempts to find a transport that
39 /* has messages pending delivery. This routine implements
40 /* round-robin search among transports.
41 /*
42 /* qmgr_transport_alloc() allocates a delivery process for the
43 /* specified transport type. Allocation is performed asynchronously.
44 /* When a process becomes available, the application callback routine
45 /* is invoked with as arguments the transport and a stream that
46 /* is connected to a delivery process. It is an error to call
47 /* qmgr_transport_alloc() while delivery process allocation for
48 /* the same transport is in progress.
49 /*
50 /* qmgr_transport_throttle blocks further allocation of delivery
51 /* processes for the named transport. Attempts to throttle a
52 /* throttled transport are ignored.
53 /*
54 /* qmgr_transport_unthrottle() undoes qmgr_transport_throttle().
55 /* Attempts to unthrottle a non-throttled transport are ignored.
56 /* DIAGNOSTICS
57 /* Panic: consistency check failure. Fatal: out of memory.
58 /* LICENSE
59 /* .ad
60 /* .fi
61 /* The Secure Mailer license must be distributed with this software.
62 /* AUTHOR(S)
63 /* Wietse Venema
64 /* IBM T.J. Watson Research
65 /* P.O. Box 704
66 /* Yorktown Heights, NY 10598, USA
67 /*
68 /* Preemptive scheduler enhancements:
69 /* Patrik Rak
70 /* Modra 6
71 /* 155 00, Prague, Czech Republic
72 /*
73 /* Wietse Venema
74 /* Google, Inc.
75 /* 111 8th Avenue
76 /* New York, NY 10011, USA
77 /*--*/
78 
79 /* System library. */
80 
81 #include <sys_defs.h>
82 #include <unistd.h>
83 
84 #include <sys/time.h> /* FD_SETSIZE */
85 #include <sys/types.h> /* FD_SETSIZE */
86 #include <unistd.h> /* FD_SETSIZE */
87 
88 #ifdef USE_SYS_SELECT_H
89 #include <sys/select.h> /* FD_SETSIZE */
90 #endif
91 
92 /* Utility library. */
93 
94 #include <msg.h>
95 #include <htable.h>
96 #include <events.h>
97 #include <mymalloc.h>
98 #include <vstream.h>
99 #include <iostuff.h>
100 
101 /* Global library. */
102 
103 #include <mail_proto.h>
104 #include <recipient_list.h>
105 #include <mail_conf.h>
106 #include <mail_params.h>
107 
108 /* Application-specific. */
109 
110 #include "qmgr.h"
111 
112 HTABLE *qmgr_transport_byname; /* transport by name */
113 QMGR_TRANSPORT_LIST qmgr_transport_list;/* transports, round robin */
114 
115  /*
116  * A local structure to remember a delivery process allocation request.
117  */
119 
120 struct QMGR_TRANSPORT_ALLOC {
121  QMGR_TRANSPORT *transport; /* transport context */
122  VSTREAM *stream; /* delivery service stream */
123  QMGR_TRANSPORT_ALLOC_NOTIFY notify; /* application call-back routine */
124 };
125 
126  /*
127  * Connections to delivery agents are managed asynchronously. Each delivery
128  * agent connection goes through multiple wait states:
129  *
130  * - With Linux/Solaris and old queue manager implementations only, wait for
131  * the server to invoke accept().
132  *
133  * - Wait for the delivery agent's announcement that it is ready to receive a
134  * delivery request.
135  *
136  * - Wait for the delivery request completion status.
137  *
138  * Older queue manager implementations had only one pending delivery agent
139  * connection per transport. With low-latency destinations, the output rates
140  * were reduced on Linux/Solaris systems that had the extra wait state.
141  *
142  * To maximize delivery agent output rates with low-latency destinations, the
143  * following changes were made to the queue manager by the end of the 2.4
144  * development cycle:
145  *
146  * - The Linux/Solaris accept() wait state was eliminated.
147  *
148  * - A pipeline was implemented for pending delivery agent connections. The
149  * number of pending delivery agent connections was increased from one to
150  * two: the number of before-delivery wait states, plus one extra pipeline
151  * slot to prevent the pipeline from stalling easily. Increasing the
152  * pipeline much further actually hurt performance.
153  *
154  * - To reduce queue manager disk competition with delivery agents, the queue
155  * scanning algorithm was modified to import only one message per interrupt.
156  * The incoming and deferred queue scans now happen on alternate interrupts.
157  *
158  * Simplistically reasoned, a non-zero (incoming + active) queue length is
159  * equivalent to a time shift for mail deliveries; this is undesirable when
160  * delivery agents are not fully utilized.
161  *
162  * On the other hand a non-empty active queue is what allows us to do clever
163  * things such as queue file prefetch, concurrency windows, and connection
164  * caching; the idea is that such "thinking time" is affordable only after
165  * the output channels are maxed out.
166  */
167 #ifndef QMGR_TRANSPORT_MAX_PEND
168 #define QMGR_TRANSPORT_MAX_PEND 2
169 #endif
170 
171  /*
172  * Important note on the _transport_rate_delay implementation: after
173  * qmgr_transport_alloc() sets the QMGR_TRANSPORT_STAT_RATE_LOCK flag, all
174  * code paths must directly or indirectly invoke qmgr_transport_unthrottle()
175  * or qmgr_transport_throttle(). Otherwise, transports with non-zero
176  * _transport_rate_delay will become stuck.
177  */
178 
179 /* qmgr_transport_unthrottle_wrapper - in case (char *) != (struct *) */
180 
181 static void qmgr_transport_unthrottle_wrapper(int unused_event, void *context)
182 {
184 }
185 
186 /* qmgr_transport_unthrottle - open the throttle */
187 
189 {
190  const char *myname = "qmgr_transport_unthrottle";
191 
192  /*
193  * This routine runs after expiration of the timer set by
194  * qmgr_transport_throttle(), or whenever a delivery transport has been
195  * used without malfunction. In either case, we enable delivery again if
196  * the transport was throttled. We always reset the transport rate lock.
197  */
198  if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0) {
199  if (msg_verbose)
200  msg_info("%s: transport %s", myname, transport->name);
201  transport->flags &= ~QMGR_TRANSPORT_STAT_DEAD;
202  if (transport->dsn == 0)
203  msg_panic("%s: transport %s: null reason",
204  myname, transport->name);
205  dsn_free(transport->dsn);
206  transport->dsn = 0;
207  event_cancel_timer(qmgr_transport_unthrottle_wrapper,
208  (void *) transport);
209  }
210  if (transport->flags & QMGR_TRANSPORT_STAT_RATE_LOCK)
211  transport->flags &= ~QMGR_TRANSPORT_STAT_RATE_LOCK;
212 }
213 
214 /* qmgr_transport_throttle - disable delivery process allocation */
215 
217 {
218  const char *myname = "qmgr_transport_throttle";
219 
220  /*
221  * We are unable to connect to a deliver process for this type of message
222  * transport. Instead of hosing the system by retrying in a tight loop,
223  * back off and disable this transport type for a while.
224  */
225  if ((transport->flags & QMGR_TRANSPORT_STAT_DEAD) == 0) {
226  if (msg_verbose)
227  msg_info("%s: transport %s: status: %s reason: %s",
228  myname, transport->name, dsn->status, dsn->reason);
229  transport->flags |= QMGR_TRANSPORT_STAT_DEAD;
230  if (transport->dsn)
231  msg_panic("%s: transport %s: spurious reason: %s",
232  myname, transport->name, transport->dsn->reason);
233  transport->dsn = DSN_COPY(dsn);
234  event_request_timer(qmgr_transport_unthrottle_wrapper,
235  (void *) transport, var_transport_retry_time);
236  }
237 }
238 
239 /* qmgr_transport_abort - transport connect watchdog */
240 
241 static void qmgr_transport_abort(int unused_event, void *context)
242 {
243  QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context;
244 
245  msg_fatal("timeout connecting to transport: %s", alloc->transport->name);
246 }
247 
248 /* qmgr_transport_rate_event - delivery process availability notice */
249 
250 static void qmgr_transport_rate_event(int unused_event, void *context)
251 {
252  QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context;
253 
254  alloc->notify(alloc->transport, alloc->stream);
255  myfree((void *) alloc);
256 }
257 
258 /* qmgr_transport_event - delivery process availability notice */
259 
260 static void qmgr_transport_event(int unused_event, void *context)
261 {
262  QMGR_TRANSPORT_ALLOC *alloc = (QMGR_TRANSPORT_ALLOC *) context;
263 
264  /*
265  * This routine notifies the application when the request given to
266  * qmgr_transport_alloc() completes.
267  */
268  if (msg_verbose)
269  msg_info("transport_event: %s", alloc->transport->name);
270 
271  /*
272  * Connection request completed. Stop the watchdog timer.
273  */
274  event_cancel_timer(qmgr_transport_abort, context);
275 
276  /*
277  * Disable further read events that end up calling this function, and
278  * free up this pending connection pipeline slot.
279  */
280  if (alloc->stream) {
283  }
284  alloc->transport->pending -= 1;
285 
286  /*
287  * Notify the requestor.
288  */
289  if (alloc->transport->xport_rate_delay > 0) {
290  if ((alloc->transport->flags & QMGR_TRANSPORT_STAT_RATE_LOCK) == 0)
291  msg_panic("transport_event: missing rate lock for transport %s",
292  alloc->transport->name);
293  event_request_timer(qmgr_transport_rate_event, (void *) alloc,
294  alloc->transport->xport_rate_delay);
295  } else {
296  alloc->notify(alloc->transport, alloc->stream);
297  myfree((void *) alloc);
298  }
299 }
300 
301 /* qmgr_transport_select - select transport for allocation */
302 
304 {
305  QMGR_TRANSPORT *xport;
306  QMGR_QUEUE *queue;
307  int need;
308 
309  /*
310  * If we find a suitable transport, rotate the list of transports to
311  * effectuate round-robin selection. See similar selection code in
312  * qmgr_peer_select().
313  *
314  * This function is called repeatedly until all transports have maxed out
315  * the number of pending delivery agent connections, until all delivery
316  * agent concurrency windows are maxed out, or until we run out of "todo"
317  * queue entries.
318  */
319 #define MIN5af51743e4eef(x, y) ((x) < (y) ? (x) : (y))
320 
321  for (xport = qmgr_transport_list.next; xport; xport = xport->peers.next) {
322  if ((xport->flags & QMGR_TRANSPORT_STAT_DEAD) != 0
323  || (xport->flags & QMGR_TRANSPORT_STAT_RATE_LOCK) != 0
324  || xport->pending >= QMGR_TRANSPORT_MAX_PEND)
325  continue;
326  need = xport->pending + 1;
327  for (queue = xport->queue_list.next; queue; queue = queue->peers.next) {
328  if (QMGR_QUEUE_READY(queue) == 0)
329  continue;
330  if ((need -= MIN5af51743e4eef(queue->window - queue->busy_refcount,
331  queue->todo_refcount)) <= 0) {
332  QMGR_LIST_ROTATE(qmgr_transport_list, xport, peers);
333  if (msg_verbose)
334  msg_info("qmgr_transport_select: %s", xport->name);
335  return (xport);
336  }
337  }
338  }
339  return (0);
340 }
341 
342 /* qmgr_transport_alloc - allocate delivery process */
343 
345 {
346  QMGR_TRANSPORT_ALLOC *alloc;
347 
348  /*
349  * Sanity checks.
350  */
351  if (transport->flags & QMGR_TRANSPORT_STAT_DEAD)
352  msg_panic("qmgr_transport: dead transport: %s", transport->name);
353  if (transport->flags & QMGR_TRANSPORT_STAT_RATE_LOCK)
354  msg_panic("qmgr_transport: rate-locked transport: %s", transport->name);
355  if (transport->pending >= QMGR_TRANSPORT_MAX_PEND)
356  msg_panic("qmgr_transport: excess allocation: %s", transport->name);
357 
358  /*
359  * When this message delivery transport is rate-limited, do not select it
360  * again before the end of a message delivery transaction.
361  */
362  if (transport->xport_rate_delay > 0)
363  transport->flags |= QMGR_TRANSPORT_STAT_RATE_LOCK;
364 
365  /*
366  * Connect to the well-known port for this delivery service, and wake up
367  * when a process announces its availability. Allow only a limited number
368  * of delivery process allocation attempts for this transport. In case of
369  * problems, back off. Do not hose the system when it is in trouble
370  * already.
371  *
372  * Use non-blocking connect(), so that Linux won't block the queue manager
373  * until the delivery agent calls accept().
374  *
375  * When the connection to delivery agent cannot be completed, notify the
376  * event handler so that it can throttle the transport and defer the todo
377  * queues, just like it does when communication fails *after* connection
378  * completion.
379  *
380  * Before Postfix 2.4, the event handler was not invoked after connect()
381  * error, and mail was not deferred. Because of this, mail would be stuck
382  * in the active queue after triggering a "connection refused" condition.
383  */
384  alloc = (QMGR_TRANSPORT_ALLOC *) mymalloc(sizeof(*alloc));
385  alloc->transport = transport;
386  alloc->notify = notify;
387  transport->pending += 1;
388  if ((alloc->stream = mail_connect(MAIL_CLASS_PRIVATE, transport->name,
389  NON_BLOCKING)) == 0) {
390  msg_warn("connect to transport %s/%s: %m",
391  MAIL_CLASS_PRIVATE, transport->name);
392  event_request_timer(qmgr_transport_event, (void *) alloc, 0);
393  return;
394  }
395 #if (EVENTS_STYLE != EVENTS_STYLE_SELECT) && defined(CA_VSTREAM_CTL_DUPFD)
396 #ifndef THRESHOLD_FD_WORKAROUND
397 #define THRESHOLD_FD_WORKAROUND 128
398 #endif
399  vstream_control(alloc->stream,
400  CA_VSTREAM_CTL_DUPFD(THRESHOLD_FD_WORKAROUND),
402 #endif
403  event_enable_read(vstream_fileno(alloc->stream), qmgr_transport_event,
404  (void *) alloc);
405 
406  /*
407  * Guard against broken systems.
408  */
409  event_request_timer(qmgr_transport_abort, (void *) alloc,
411 }
412 
413 /* qmgr_transport_create - create transport instance */
414 
416 {
417  QMGR_TRANSPORT *transport;
418 
419  if (htable_find(qmgr_transport_byname, name) != 0)
420  msg_panic("qmgr_transport_create: transport exists: %s", name);
421  transport = (QMGR_TRANSPORT *) mymalloc(sizeof(QMGR_TRANSPORT));
422  transport->flags = 0;
423  transport->pending = 0;
424  transport->name = mystrdup(name);
425 
426  /*
427  * Use global configuration settings or transport-specific settings.
428  */
429  transport->dest_concurrency_limit =
431  var_dest_con_limit, 0, 0);
432  transport->recipient_limit =
434  var_dest_rcpt_limit, 0, 0);
435  transport->init_dest_concurrency =
440  's', 0, 0);
443  's', 0, 0);
444 
445  if (transport->rate_delay > 0)
446  transport->dest_concurrency_limit = 1;
447  if (transport->dest_concurrency_limit != 0
448  && transport->dest_concurrency_limit < transport->init_dest_concurrency)
449  transport->init_dest_concurrency = transport->dest_concurrency_limit;
450 
452  var_delivery_slot_cost, 0, 0);
454  var_delivery_slot_loan, 0, 0);
455  transport->slot_loan_factor =
459  var_min_delivery_slots, 0, 0);
461  var_xport_rcpt_limit, 0, 0);
463  var_stack_rcpt_limit, 0, 0);
465  var_xport_refill_limit, 1, 0);
467  var_xport_refill_delay, 's', 1, 0);
468 
469  transport->queue_byname = htable_create(0);
470  QMGR_LIST_INIT(transport->queue_list);
471  transport->job_byname = htable_create(0);
472  QMGR_LIST_INIT(transport->job_list);
473  QMGR_LIST_INIT(transport->job_bytime);
474  transport->job_current = 0;
475  transport->job_next_unread = 0;
476  transport->candidate_cache = 0;
477  transport->candidate_cache_current = 0;
478  transport->candidate_cache_time = (time_t) 0;
479  transport->blocker_tag = 1;
480  transport->dsn = 0;
485  transport->fail_cohort_limit =
487  var_conc_cohort_limit, 0, 0);
488  if (qmgr_transport_byname == 0)
489  qmgr_transport_byname = htable_create(10);
490  htable_enter(qmgr_transport_byname, name, (void *) transport);
491  QMGR_LIST_PREPEND(qmgr_transport_list, transport, peers);
492  if (msg_verbose)
493  msg_info("qmgr_transport_create: %s concurrency %d recipients %d",
494  transport->name, transport->dest_concurrency_limit,
495  transport->recipient_limit);
496  return (transport);
497 }
498 
499 /* qmgr_transport_find - find transport instance */
500 
502 {
503  return ((QMGR_TRANSPORT *) htable_find(qmgr_transport_byname, name));
504 }
struct HTABLE * job_byname
Definition: qmgr.h:190
int msg_verbose
Definition: msg.c:177
void event_enable_read(int fd, EVENT_NOTIFY_RDWR_FN callback, void *context)
Definition: events.c:729
QMGR_TRANSPORT * next
Definition: qmgr.h:98
int var_xport_refill_limit
Definition: qmgr.c:488
QMGR_JOB_LIST job_bytime
Definition: qmgr.h:193
int dest_concurrency_limit
Definition: qmgr.h:156
void myfree(void *ptr)
Definition: mymalloc.c:207
int var_delivery_slot_loan
Definition: qmgr.c:491
#define _CONC_NEG_FDBACK
Definition: mail_params.h:3503
QMGR_JOB * job_current
Definition: qmgr.h:194
int pending
Definition: qmgr.h:154
int rcpt_unused
Definition: qmgr.h:178
char * mystrdup(const char *str)
Definition: mymalloc.c:225
#define _MIN_DELIVERY_SLOTS
Definition: mail_params.h:827
HTABLE * qmgr_transport_byname
#define _STACK_RCPT_LIMIT
Definition: mail_params.h:794
int fail_cohort_limit
Definition: qmgr.h:165
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
const char * reason
Definition: dsn.h:20
#define _CONC_POS_FDBACK
Definition: mail_params.h:3498
#define _XPORT_RCPT_LIMIT
Definition: mail_params.h:789
VSTREAM * mail_connect(const char *class, const char *name, int block_mode)
Definition: mail_connect.c:79
#define MIN5af51743e4eef(x, y)
int slot_cost
Definition: qmgr.h:182
#define QMGR_TRANSPORT_MAX_PEND
#define _CONC_COHORT_LIM
Definition: mail_params.h:3511
#define VAR_CONC_NEG_FDBACK
Definition: mail_params.h:3502
QMGR_TRANSPORT * qmgr_transport_find(const char *name)
#define DSN_COPY(dsn)
Definition: dsn.h:68
QMGR_FEEDBACK neg_feedback
Definition: qmgr.h:164
int var_init_dest_concurrency
Definition: qmgr.c:417
int xport_rate_delay
Definition: qmgr.h:166
Definition: htable.h:25
int var_stack_rcpt_limit
Definition: qmgr.c:487
char * var_conc_pos_feedback
Definition: qmgr.c:427
QMGR_JOB_LIST job_list
Definition: qmgr.h:191
int init_dest_concurrency
Definition: qmgr.h:157
#define QMGR_LIST_INIT(head)
Definition: qmgr.h:88
QMGR_QUEUE * next
Definition: qmgr.h:148
#define _XPORT_REFILL_LIMIT
Definition: mail_params.h:799
QMGR_TRANSPORT_LIST qmgr_transport_list
int var_xport_rcpt_limit
Definition: qmgr.c:486
HTABLE * htable_create(ssize_t size)
Definition: htable.c:179
int slot_loan
Definition: qmgr.h:184
int rcpt_per_stack
Definition: qmgr.h:176
#define QMGR_LIST_ROTATE(head, object)
Definition: qmgr.h:46
int busy_refcount
Definition: qmgr.h:203
QMGR_QUEUE_LIST peers
Definition: qmgr.h:211
char * var_conc_neg_feedback
Definition: qmgr.c:428
struct HTABLE * queue_byname
Definition: qmgr.h:159
#define _DEST_RATE_DELAY
Definition: mail_params.h:3520
int var_dest_rcpt_limit
Definition: qmgr.c:420
int flags
Definition: qmgr.h:153
void dsn_free(DSN *dsn)
Definition: dsn.c:179
int var_xport_rate_delay
Definition: qmgr.c:431
#define _XPORT_RATE_DELAY
Definition: mail_params.h:3525
int var_xport_refill_delay
Definition: qmgr.c:489
#define _XPORT_REFILL_DELAY
Definition: mail_params.h:804
int var_dest_con_limit
Definition: qmgr.c:419
int var_dest_rate_delay
Definition: qmgr.c:432
int get_mail_conf_time2(const char *, const char *, int, int, int, int)
void msg_warn(const char *fmt,...)
Definition: msg.c:215
int var_min_delivery_slots
Definition: qmgr.c:493
int var_delivery_slot_cost
Definition: qmgr.c:490
int recipient_limit
Definition: qmgr.h:158
#define VAR_CONC_POS_FDBACK
Definition: mail_params.h:3497
QMGR_TRANSPORT_LIST peers
Definition: qmgr.h:161
QMGR_JOB * job_next_unread
Definition: qmgr.h:195
void * htable_find(HTABLE *table, const char *key)
Definition: htable.c:227
QMGR_JOB * candidate_cache
Definition: qmgr.h:196
char * name
Definition: qmgr.h:155
time_t candidate_cache_time
Definition: qmgr.h:199
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define _DELIVERY_SLOT_DISCOUNT
Definition: mail_params.h:822
const char * status
Definition: dsn.h:18
int todo_refcount
Definition: qmgr.h:202
int get_mail_conf_int2(const char *, const char *, int, int, int)
DSN * dsn
Definition: qmgr.h:162
void qmgr_transport_unthrottle(QMGR_TRANSPORT *transport)
#define NON_BLOCKING
Definition: iostuff.h:49
void qmgr_transport_alloc(QMGR_TRANSPORT *transport, QMGR_TRANSPORT_ALLOC_NOTIFY notify)
QMGR_QUEUE_LIST queue_list
Definition: qmgr.h:160
void qmgr_feedback_init(QMGR_FEEDBACK *, const char *, const char *, const char *, const char *)
QMGR_TRANSPORT * qmgr_transport_select(void)
QMGR_TRANSPORT * qmgr_transport_create(const char *name)
#define _DEST_RCPT_LIMIT
Definition: mail_params.h:856
int non_blocking(int, int)
Definition: non_blocking.c:55
Definition: dsn.h:17
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
QMGR_TRANSPORT * transport
#define QMGR_TRANSPORT_STAT_DEAD
Definition: qmgr.h:170
int refill_delay
Definition: qmgr.h:181
#define QMGR_TRANSPORT_STAT_RATE_LOCK
Definition: qmgr.h:171
#define vstream_fileno(vp)
Definition: vstream.h:115
#define _INIT_DEST_CON
Definition: mail_params.h:839
int var_daemon_timeout
Definition: mail_params.c:284
int var_delivery_slot_discount
Definition: qmgr.c:492
QMGR_JOB * candidate_cache_current
Definition: qmgr.h:198
#define QMGR_LIST_PREPEND(head, object)
Definition: qmgr.h:77
int slot_loan_factor
Definition: qmgr.h:185
#define CA_VSTREAM_CTL_END
Definition: vstream.h:155
int window
Definition: qmgr.h:204
int rate_delay
Definition: qmgr.h:167
QMGR_FEEDBACK pos_feedback
Definition: qmgr.h:163
void qmgr_transport_throttle(QMGR_TRANSPORT *transport, DSN *dsn)
#define _DELIVERY_SLOT_LOAN
Definition: mail_params.h:817
void vstream_control(VSTREAM *stream, int name,...)
Definition: vstream.c:1372
void event_disable_readwrite(int fd)
Definition: events.c:839
#define QMGR_QUEUE_READY(q)
Definition: qmgr.h:244
#define _DELIVERY_SLOT_COST
Definition: mail_params.h:812
#define BLOCKING
Definition: iostuff.h:48
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
Definition: events.c:965
int blocker_tag
Definition: qmgr.h:201
void(* QMGR_TRANSPORT_ALLOC_NOTIFY)(QMGR_TRANSPORT *, VSTREAM *)
Definition: qmgr.h:173
#define MAIL_CLASS_PRIVATE
Definition: mail_proto.h:96
int min_slots
Definition: qmgr.h:186
int refill_limit
Definition: qmgr.h:179
int var_transport_retry_time
Definition: qmgr.c:418
#define _DEST_CON_LIMIT
Definition: mail_params.h:844
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
int var_conc_cohort_limit
Definition: qmgr.c:429
QMGR_TRANSPORT_ALLOC_NOTIFY notify
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
Definition: htable.c:212
void msg_info(const char *fmt,...)
Definition: msg.c:199