Postfix3.3.1
scache.c
[詳解]
1 /*++
2 /* NAME
3 /* scache 8
4 /* SUMMARY
5 /* Postfix shared connection cache server
6 /* SYNOPSIS
7 /* \fBscache\fR [generic Postfix daemon options]
8 /* DESCRIPTION
9 /* The \fBscache\fR(8) server maintains a shared multi-connection
10 /* cache. This information can be used by, for example, Postfix
11 /* SMTP clients or other Postfix delivery agents.
12 /*
13 /* The connection cache is organized into logical destination
14 /* names, physical endpoint names, and connections.
15 /*
16 /* As a specific example, logical SMTP destinations specify
17 /* (transport, domain, port), and physical SMTP endpoints
18 /* specify (transport, IP address, port). An SMTP connection
19 /* may be saved after a successful mail transaction.
20 /*
21 /* In the general case, one logical destination may refer to
22 /* zero or more physical endpoints, one physical endpoint may
23 /* be referenced by zero or more logical destinations, and
24 /* one endpoint may refer to zero or more connections.
25 /*
26 /* The exact syntax of a logical destination or endpoint name
27 /* is application dependent; the \fBscache\fR(8) server does
28 /* not care. A connection is stored as a file descriptor together
29 /* with application-dependent information that is needed to
30 /* re-activate a connection object. Again, the \fBscache\fR(8)
31 /* server is completely unaware of the details of that
32 /* information.
33 /*
34 /* All information is stored with a finite time to live (ttl).
35 /* The connection cache daemon terminates when no client is
36 /* connected for \fBmax_idle\fR time units.
37 /*
38 /* This server implements the following requests:
39 /* .IP "\fBsave_endp\fI ttl endpoint endpoint_properties file_descriptor\fR"
40 /* Save the specified file descriptor and connection property data
41 /* under the specified endpoint name. The endpoint properties
42 /* are used by the client to re-activate a passivated connection
43 /* object.
44 /* .IP "\fBfind_endp\fI endpoint\fR"
45 /* Look up cached properties and a cached file descriptor for the
46 /* specified endpoint.
47 /* .IP "\fBsave_dest\fI ttl destination destination_properties endpoint\fR"
48 /* Save the binding between a logical destination and an
49 /* endpoint under the destination name, together with destination
50 /* specific connection properties. The destination properties
51 /* are used by the client to re-activate a passivated connection
52 /* object.
53 /* .IP "\fBfind_dest\fI destination\fR"
54 /* Look up cached destination properties, cached endpoint properties,
55 /* and a cached file descriptor for the specified logical destination.
56 /* SECURITY
57 /* .ad
58 /* .fi
59 /* The \fBscache\fR(8) server is not security-sensitive. It does not
60 /* talk to the network, and it does not talk to local users.
61 /* The \fBscache\fR(8) server can run chrooted at fixed low privilege.
62 /*
63 /* The \fBscache\fR(8) server is not a trusted process. It must
64 /* not be used to store information that is security sensitive.
65 /* DIAGNOSTICS
66 /* Problems and transactions are logged to \fBsyslogd\fR(8).
67 /* BUGS
68 /* The session cache cannot be shared among multiple machines.
69 /*
70 /* When a connection expires from the cache, it is closed without
71 /* the appropriate protocol specific handshake.
72 /* CONFIGURATION PARAMETERS
73 /* .ad
74 /* .fi
75 /* Changes to \fBmain.cf\fR are picked up automatically as \fBscache\fR(8)
76 /* processes run for only a limited amount of time. Use the command
77 /* "\fBpostfix reload\fR" to speed up a change.
78 /*
79 /* The text below provides only a parameter summary. See
80 /* \fBpostconf\fR(5) for more details including examples.
81 /* RESOURCE CONTROLS
82 /* .ad
83 /* .fi
84 /* .IP "\fBconnection_cache_ttl_limit (2s)\fR"
85 /* The maximal time-to-live value that the \fBscache\fR(8) connection
86 /* cache server
87 /* allows.
88 /* .IP "\fBconnection_cache_status_update_time (600s)\fR"
89 /* How frequently the \fBscache\fR(8) server logs usage statistics with
90 /* connection cache hit and miss rates for logical destinations and for
91 /* physical endpoints.
92 /* MISCELLANEOUS CONTROLS
93 /* .ad
94 /* .fi
95 /* .IP "\fBconfig_directory (see 'postconf -d' output)\fR"
96 /* The default location of the Postfix main.cf and master.cf
97 /* configuration files.
98 /* .IP "\fBdaemon_timeout (18000s)\fR"
99 /* How much time a Postfix daemon process may take to handle a
100 /* request before it is terminated by a built-in watchdog timer.
101 /* .IP "\fBipc_timeout (3600s)\fR"
102 /* The time limit for sending or receiving information over an internal
103 /* communication channel.
104 /* .IP "\fBmax_idle (100s)\fR"
105 /* The maximum amount of time that an idle Postfix daemon process waits
106 /* for an incoming connection before terminating voluntarily.
107 /* .IP "\fBprocess_id (read-only)\fR"
108 /* The process ID of a Postfix command or daemon process.
109 /* .IP "\fBprocess_name (read-only)\fR"
110 /* The process name of a Postfix command or daemon process.
111 /* .IP "\fBsyslog_facility (mail)\fR"
112 /* The syslog facility of Postfix logging.
113 /* .IP "\fBsyslog_name (see 'postconf -d' output)\fR"
114 /* A prefix that is prepended to the process name in syslog
115 /* records, so that, for example, "smtpd" becomes "prefix/smtpd".
116 /* .PP
117 /* Available in Postfix 3.3 and later:
118 /* .IP "\fBservice_name (read-only)\fR"
119 /* The master.cf service name of a Postfix daemon process.
120 /* SEE ALSO
121 /* smtp(8), SMTP client
122 /* postconf(5), configuration parameters
123 /* master(8), process manager
124 /* syslogd(8), system logging
125 /* README FILES
126 /* .ad
127 /* .fi
128 /* Use "\fBpostconf readme_directory\fR" or
129 /* "\fBpostconf html_directory\fR" to locate this information.
130 /* .na
131 /* .nf
132 /* CONNECTION_CACHE_README, Postfix connection cache
133 /* LICENSE
134 /* .ad
135 /* .fi
136 /* The Secure Mailer license must be distributed with this software.
137 /* HISTORY
138 /* This service was introduced with Postfix version 2.2.
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 /* Wietse Venema
146 /* Google, Inc.
147 /* 111 8th Avenue
148 /* New York, NY 10011, USA
149 /*--*/
150 
151 /* System library. */
152 
153 #include <sys_defs.h>
154 #include <time.h>
155 
156 /* Utility library. */
157 
158 #include <msg.h>
159 #include <iostuff.h>
160 #include <htable.h>
161 #include <ring.h>
162 #include <events.h>
163 
164 /* Global library. */
165 
166 #include <mail_params.h>
167 #include <mail_version.h>
168 #include <mail_proto.h>
169 #include <scache.h>
170 
171 /* Single server skeleton. */
172 
173 #include <mail_server.h>
174 #include <mail_conf.h>
175 
176 /* Application-specific. */
177 
178  /*
179  * Tunable parameters.
180  */
183 
184  /*
185  * Request parameters.
186  */
187 static VSTRING *scache_request;
188 static VSTRING *scache_dest_label;
189 static VSTRING *scache_dest_prop;
190 static VSTRING *scache_endp_label;
191 static VSTRING *scache_endp_prop;
192 
193 #ifdef CANT_WRITE_BEFORE_SENDING_FD
194 static VSTRING *scache_dummy;
195 
196 #endif
197 
198  /*
199  * Session cache instance.
200  */
201 static SCACHE *scache;
202 
203  /*
204  * Statistics.
205  */
206 static int scache_dest_hits;
207 static int scache_dest_miss;
208 static int scache_dest_count;
209 static int scache_endp_hits;
210 static int scache_endp_miss;
211 static int scache_endp_count;
212 static int scache_sess_count;
214 
215  /*
216  * Silly little macros.
217  */
218 #define STR(x) vstring_str(x)
219 #define VSTREQ(x,y) (strcmp(STR(x),y) == 0)
220 
221 /* scache_save_endp_service - protocol to save endpoint->stream binding */
222 
223 static void scache_save_endp_service(VSTREAM *client_stream)
224 {
225  const char *myname = "scache_save_endp_service";
226  int ttl;
227  int fd;
228  SCACHE_SIZE size;
229 
230  if (attr_scan(client_stream,
233  RECV_ATTR_STR(MAIL_ATTR_LABEL, scache_endp_label),
234  RECV_ATTR_STR(MAIL_ATTR_PROP, scache_endp_prop),
235  ATTR_TYPE_END) != 3
236  || ttl <= 0) {
237  msg_warn("%s: bad or missing request parameter", myname);
238  attr_print(client_stream, ATTR_FLAG_NONE,
240  ATTR_TYPE_END);
241  return;
242  } else if (
244  attr_print(client_stream, ATTR_FLAG_NONE,
246  ATTR_TYPE_END) != 0
247  || vstream_fflush(client_stream) != 0
248  || read_wait(vstream_fileno(client_stream),
249  client_stream->timeout) < 0 /* XXX */
250  ||
251 #endif
252  (fd = LOCAL_RECV_FD(vstream_fileno(client_stream))) < 0) {
253  msg_warn("%s: unable to receive file descriptor: %m", myname);
254  (void) attr_print(client_stream, ATTR_FLAG_NONE,
256  ATTR_TYPE_END);
257  return;
258  } else {
259  scache_save_endp(scache,
261  STR(scache_endp_label), STR(scache_endp_prop), fd);
262  (void) attr_print(client_stream, ATTR_FLAG_NONE,
264  ATTR_TYPE_END);
265  scache_size(scache, &size);
266  if (size.endp_count > scache_endp_count)
267  scache_endp_count = size.endp_count;
268  if (size.sess_count > scache_sess_count)
269  scache_sess_count = size.sess_count;
270  return;
271  }
272 }
273 
274 /* scache_find_endp_service - protocol to find connection for endpoint */
275 
276 static void scache_find_endp_service(VSTREAM *client_stream)
277 {
278  const char *myname = "scache_find_endp_service";
279  int fd;
280 
281  if (attr_scan(client_stream,
283  RECV_ATTR_STR(MAIL_ATTR_LABEL, scache_endp_label),
284  ATTR_TYPE_END) != 1) {
285  msg_warn("%s: bad or missing request parameter", myname);
286  attr_print(client_stream, ATTR_FLAG_NONE,
289  ATTR_TYPE_END);
290  return;
291  } else if ((fd = scache_find_endp(scache, STR(scache_endp_label),
292  scache_endp_prop)) < 0) {
293  attr_print(client_stream, ATTR_FLAG_NONE,
296  ATTR_TYPE_END);
297  scache_endp_miss++;
298  return;
299  } else {
300  attr_print(client_stream, ATTR_FLAG_NONE,
302  SEND_ATTR_STR(MAIL_ATTR_PROP, STR(scache_endp_prop)),
303  ATTR_TYPE_END);
304  if (vstream_fflush(client_stream) != 0
306  || attr_scan(client_stream, ATTR_FLAG_STRICT,
307  RECV_ATTR_STR(MAIL_ATTR_DUMMY, scache_dummy),
308  ATTR_TYPE_END) != 1
309 #endif
310  || LOCAL_SEND_FD(vstream_fileno(client_stream), fd) < 0
312  || attr_scan(client_stream, ATTR_FLAG_STRICT,
313  RECV_ATTR_STR(MAIL_ATTR_DUMMY, scache_dummy),
314  ATTR_TYPE_END) != 1
315 #endif
316  )
317  msg_warn("%s: cannot send file descriptor: %m", myname);
318  if (close(fd) < 0)
319  msg_warn("close(%d): %m", fd);
320  scache_endp_hits++;
321  return;
322  }
323 }
324 
325 /* scache_save_dest_service - protocol to save destination->endpoint binding */
326 
327 static void scache_save_dest_service(VSTREAM *client_stream)
328 {
329  const char *myname = "scache_save_dest_service";
330  int ttl;
331  SCACHE_SIZE size;
332 
333  if (attr_scan(client_stream,
336  RECV_ATTR_STR(MAIL_ATTR_LABEL, scache_dest_label),
337  RECV_ATTR_STR(MAIL_ATTR_PROP, scache_dest_prop),
338  RECV_ATTR_STR(MAIL_ATTR_LABEL, scache_endp_label),
339  ATTR_TYPE_END) != 4
340  || ttl <= 0) {
341  msg_warn("%s: bad or missing request parameter", myname);
342  attr_print(client_stream, ATTR_FLAG_NONE,
344  ATTR_TYPE_END);
345  return;
346  } else {
347  scache_save_dest(scache,
349  STR(scache_dest_label), STR(scache_dest_prop),
350  STR(scache_endp_label));
351  attr_print(client_stream, ATTR_FLAG_NONE,
353  ATTR_TYPE_END);
354  scache_size(scache, &size);
355  if (size.dest_count > scache_dest_count)
356  scache_dest_count = size.dest_count;
357  if (size.endp_count > scache_endp_count)
358  scache_endp_count = size.endp_count;
359  return;
360  }
361 }
362 
363 /* scache_find_dest_service - protocol to find connection for destination */
364 
365 static void scache_find_dest_service(VSTREAM *client_stream)
366 {
367  const char *myname = "scache_find_dest_service";
368  int fd;
369 
370  if (attr_scan(client_stream,
372  RECV_ATTR_STR(MAIL_ATTR_LABEL, scache_dest_label),
373  ATTR_TYPE_END) != 1) {
374  msg_warn("%s: bad or missing request parameter", myname);
375  attr_print(client_stream, ATTR_FLAG_NONE,
379  ATTR_TYPE_END);
380  return;
381  } else if ((fd = scache_find_dest(scache, STR(scache_dest_label),
382  scache_dest_prop,
383  scache_endp_prop)) < 0) {
384  attr_print(client_stream, ATTR_FLAG_NONE,
388  ATTR_TYPE_END);
389  scache_dest_miss++;
390  return;
391  } else {
392  attr_print(client_stream, ATTR_FLAG_NONE,
394  SEND_ATTR_STR(MAIL_ATTR_PROP, STR(scache_dest_prop)),
395  SEND_ATTR_STR(MAIL_ATTR_PROP, STR(scache_endp_prop)),
396  ATTR_TYPE_END);
397  if (vstream_fflush(client_stream) != 0
399  || attr_scan(client_stream, ATTR_FLAG_STRICT,
400  RECV_ATTR_STR(MAIL_ATTR_DUMMY, scache_dummy),
401  ATTR_TYPE_END) != 1
402 #endif
403  || LOCAL_SEND_FD(vstream_fileno(client_stream), fd) < 0
405  || attr_scan(client_stream, ATTR_FLAG_STRICT,
406  RECV_ATTR_STR(MAIL_ATTR_DUMMY, scache_dummy),
407  ATTR_TYPE_END) != 1
408 #endif
409  )
410  msg_warn("%s: cannot send file descriptor: %m", myname);
411  if (close(fd) < 0)
412  msg_warn("close(%d): %m", fd);
413  scache_dest_hits++;
414  return;
415  }
416 }
417 
418 /* scache_service - perform service for client */
419 
420 static void scache_service(VSTREAM *client_stream, char *unused_service,
421  char **argv)
422 {
423 
424  /*
425  * Sanity check. This service takes no command-line arguments.
426  */
427  if (argv[0])
428  msg_fatal("unexpected command-line argument: %s", argv[0]);
429 
430  /*
431  * This routine runs whenever a client connects to the UNIX-domain socket
432  * dedicated to the scache service. All connection-management stuff is
433  * handled by the common code in multi_server.c.
434  *
435  * XXX Workaround: with some requests, the client sends a dummy message
436  * after the server replies (yes that's a botch). When the scache server
437  * is slow, this dummy message may become concatenated with the next
438  * request from the same client. The do-while loop below will repeat
439  * instead of discarding the client request. We must process it now
440  * because there will be no select() notification.
441  */
442  do {
443  if (attr_scan(client_stream,
445  RECV_ATTR_STR(MAIL_ATTR_REQ, scache_request),
446  ATTR_TYPE_END) == 1) {
447  if (VSTREQ(scache_request, SCACHE_REQ_SAVE_DEST)) {
448  scache_save_dest_service(client_stream);
449  } else if (VSTREQ(scache_request, SCACHE_REQ_FIND_DEST)) {
450  scache_find_dest_service(client_stream);
451  } else if (VSTREQ(scache_request, SCACHE_REQ_SAVE_ENDP)) {
452  scache_save_endp_service(client_stream);
453  } else if (VSTREQ(scache_request, SCACHE_REQ_FIND_ENDP)) {
454  scache_find_endp_service(client_stream);
455  } else {
456  msg_warn("unrecognized request: \"%s\", ignored",
457  STR(scache_request));
458  attr_print(client_stream, ATTR_FLAG_NONE,
460  ATTR_TYPE_END);
461  }
462  }
463  } while (vstream_peek(client_stream) > 0);
464  vstream_fflush(client_stream);
465 }
466 
467 /* scache_status_dump - log and reset cache statistics */
468 
469 static void scache_status_dump(char *unused_name, char **unused_argv)
470 {
471  if (scache_dest_hits || scache_dest_miss
472  || scache_endp_hits || scache_endp_miss
473  || scache_dest_count || scache_endp_count
474  || scache_sess_count)
475  msg_info("statistics: start interval %.15s",
476  ctime(&scache_start_time) + 4);
477 
478  if (scache_dest_hits || scache_dest_miss) {
479  msg_info("statistics: domain lookup hits=%d miss=%d success=%d%%",
480  scache_dest_hits, scache_dest_miss,
481  scache_dest_hits * 100
482  / (scache_dest_hits + scache_dest_miss));
483  scache_dest_hits = scache_dest_miss = 0;
484  }
485  if (scache_endp_hits || scache_endp_miss) {
486  msg_info("statistics: address lookup hits=%d miss=%d success=%d%%",
487  scache_endp_hits, scache_endp_miss,
488  scache_endp_hits * 100
489  / (scache_endp_hits + scache_endp_miss));
490  scache_endp_hits = scache_endp_miss = 0;
491  }
492  if (scache_dest_count || scache_endp_count || scache_sess_count) {
493  msg_info("statistics: max simultaneous domains=%d addresses=%d connection=%d",
494  scache_dest_count, scache_endp_count, scache_sess_count);
495  scache_dest_count = 0;
496  scache_endp_count = 0;
497  scache_sess_count = 0;
498  }
500 }
501 
502 /* scache_status_update - log and reset cache statistics periodically */
503 
504 static void scache_status_update(int unused_event, void *context)
505 {
506  scache_status_dump((char *) 0, (char **) 0);
507  event_request_timer(scache_status_update, context, var_scache_stat_time);
508 }
509 
510 /* post_jail_init - initialization after privilege drop */
511 
512 static void post_jail_init(char *unused_name, char **unused_argv)
513 {
514 
515  /*
516  * Pre-allocate the cache instance.
517  */
518  scache = scache_multi_create();
519 
520  /*
521  * Pre-allocate buffers.
522  */
523  scache_request = vstring_alloc(10);
524  scache_dest_label = vstring_alloc(10);
525  scache_dest_prop = vstring_alloc(10);
526  scache_endp_label = vstring_alloc(10);
527  scache_endp_prop = vstring_alloc(10);
528 #ifdef CANT_WRITE_BEFORE_SENDING_FD
529  scache_dummy = vstring_alloc(10);
530 #endif
531 
532  /*
533  * Disable the max_use limit. We still terminate when no client is
534  * connected for $idle_limit time units.
535  */
536  var_use_limit = 0;
537 
538  /*
539  * Dump and reset cache statistics every so often.
540  */
541  event_request_timer(scache_status_update, (void *) 0, var_scache_stat_time);
543 }
544 
546 
547 /* main - pass control to the multi-threaded skeleton */
548 
549 int main(int argc, char **argv)
550 {
551  static const CONFIG_TIME_TABLE time_table[] = {
554  0,
555  };
556 
557  /*
558  * Fingerprint executables and core dumps.
559  */
561 
562  multi_server_main(argc, argv, scache_service,
563  CA_MAIL_SERVER_TIME_TABLE(time_table),
564  CA_MAIL_SERVER_POST_INIT(post_jail_init),
565  CA_MAIL_SERVER_EXIT(scache_status_dump),
567  0);
568 }
#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
int dest_count
Definition: scache.h:94
int main(int argc, char **argv)
Definition: scache.c:549
#define scache_find_dest(scache, dest_label, dest_prop, endp_prop)
Definition: scache.h:122
#define STR(x)
Definition: scache.c:218
#define SCACHE_STAT_BAD
Definition: scache.h:146
#define MAIL_ATTR_REQ
Definition: mail_proto.h:124
MAIL_VERSION_STAMP_DECLARE
Definition: scache.c:545
#define SCACHE_STAT_OK
Definition: scache.h:145
#define CA_MAIL_SERVER_EXIT(v)
Definition: mail_server.h:67
#define RECV_ATTR_INT(name, val)
Definition: attr.h:71
#define ATTR_TYPE_END
Definition: attr.h:39
#define VAR_SCACHE_STAT_TIME
Definition: mail_params.h:2779
int timeout
Definition: vstream.h:58
#define SCACHE_STAT_FAIL
Definition: scache.h:147
NORETURN multi_server_main(int, char **, MULTI_SERVER_FN,...)
Definition: multi_server.c:530
#define LOCAL_SEND_FD
Definition: sys_defs.h:1426
#define SCACHE_REQ_FIND_ENDP
Definition: scache.h:137
#define CA_MAIL_SERVER_POST_INIT(v)
Definition: mail_server.h:65
int var_scache_stat_time
Definition: scache.c:182
#define VAR_SCACHE_TTL_LIM
Definition: mail_params.h:2775
#define attr_print
Definition: attr.h:109
SCACHE * scache_multi_create(void)
Definition: scache_multi.c:477
#define VSTREQ(x, y)
Definition: scache.c:219
#define DEF_SCACHE_STAT_TIME
Definition: mail_params.h:2780
int sess_count
Definition: scache.h:96
#define CANT_WRITE_BEFORE_SENDING_FD
Definition: sys_defs.h:1704
#define MAIL_ATTR_DUMMY
Definition: mail_proto.h:160
int var_scache_ttl_lim
Definition: scache.c:181
#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 scache_save_endp(scache, ttl, endp_label, endp_prop, fd)
Definition: scache.h:116
#define MAIL_ATTR_TTL
Definition: mail_proto.h:169
int var_use_limit
Definition: mail_params.c:248
#define MAIL_VERSION_STAMP_ALLOCATE
Definition: mail_version.h:67
#define SCACHE_REQ_FIND_DEST
Definition: scache.h:139
#define MAIL_ATTR_LABEL
Definition: mail_proto.h:170
#define CA_MAIL_SERVER_TIME_TABLE(v)
Definition: mail_server.h:59
#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
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define MUST_READ_AFTER_SENDING_FD
Definition: sys_defs.h:1713
time_t scache_start_time
Definition: scache.c:213
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
time_t event_time(void)
Definition: events.c:647
int endp_count
Definition: scache.h:95
#define vstream_peek(vp)
Definition: vstream.h:232
#define scache_find_endp(scache, endp_label, endp_prop)
Definition: scache.h:118
#define DEF_SCACHE_TTL_LIM
Definition: mail_params.h:2776
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
#define MAIL_ATTR_PROP
Definition: mail_proto.h:171
Definition: scache.h:103
#define CA_MAIL_SERVER_SOLITARY
Definition: mail_server.h:69
#define vstream_fileno(vp)
Definition: vstream.h:115
#define scache_save_dest(scache, ttl, dest_label, dest_prop, endp_label)
Definition: scache.h:120
#define attr_scan
Definition: attr.h:111
#define ATTR_FLAG_MORE
Definition: attr.h:101
#define scache_size(scache, stats)
Definition: scache.h:124
#define SEND_ATTR_STR(name, val)
Definition: attr.h:64
#define RECV_ATTR_STR(name, val)
Definition: attr.h:72
#define ATTR_FLAG_STRICT
Definition: attr.h:103
void msg_info(const char *fmt,...)
Definition: msg.c:199