Postfix3.3.1
attr_clnt.c
[詳解]
1 /*++
2 /* NAME
3 /* attr_clnt 3
4 /* SUMMARY
5 /* attribute query-reply client
6 /* SYNOPSIS
7 /* #include <attr_clnt.h>
8 /*
9 /* typedef int (*ATTR_CLNT_PRINT_FN) (VSTREAM *, int, va_list);
10 /* typedef int (*ATTR_CLNT_SCAN_FN) (VSTREAM *, int, va_list);
11 /*
12 /* ATTR_CLNT *attr_clnt_create(server, timeout, max_idle, max_ttl)
13 /* const char *server;
14 /* int timeout;
15 /* int max_idle;
16 /* int max_ttl;
17 /*
18 /* int attr_clnt_request(client,
19 /* send_flags, send_type, send_name, ..., ATTR_TYPE_END,
20 /* recv_flags, recv_type, recv_name, ..., ATTR_TYPE_END)
21 /* ATTR_CLNT *client;
22 /* int send_flags;
23 /* int send_type;
24 /* const char *send_name;
25 /* int recv_flags;
26 /* int recv_type;
27 /* const char *recv_name;
28 /*
29 /* void attr_clnt_free(client)
30 /* ATTR_CLNT *client;
31 /*
32 /* void attr_clnt_control(client, name, value, ... ATTR_CLNT_CTL_END)
33 /* ATTR_CLNT *client;
34 /* int name;
35 /* DESCRIPTION
36 /* This module implements a client for a simple attribute-based
37 /* protocol. The default protocol is described in attr_scan_plain(3).
38 /*
39 /* attr_clnt_create() creates a client handle. See auto_clnt(3) for
40 /* a description of the arguments.
41 /*
42 /* attr_clnt_request() sends the specified request attributes and
43 /* receives a reply. The reply argument specifies a name-value table.
44 /* The other arguments are as described in attr_print_plain(3). The
45 /* result is the number of attributes received or -1 in case of trouble.
46 /*
47 /* attr_clnt_free() destroys a client handle and closes its connection.
48 /*
49 /* attr_clnt_control() allows the user to fine tune the behavior of
50 /* the specified client. The arguments are a list of (name, value)
51 /* terminated with ATTR_CLNT_CTL_END.
52 /* The following lists the names and the types of the corresponding
53 /* value arguments.
54 /* .IP "ATTR_CLNT_CTL_PROTO(ATTR_CLNT_PRINT_FN, ATTR_CLNT_SCAN_FN)"
55 /* Specifies alternatives for the attr_plain_print() and
56 /* attr_plain_scan() functions.
57 /* .IP "ATTR_CLNT_CTL_REQ_LIMIT(int)"
58 /* The maximal number of requests per connection (default: 0,
59 /* i.e. no limit). To enable the limit, specify a value greater
60 /* than zero.
61 /* .IP "ATTR_CLNT_CTL_TRY_LIMIT(int)"
62 /* The maximal number of attempts to send a request before
63 /* giving up (default: 2). To disable the limit, specify a
64 /* value equal to zero.
65 /* .IP "ATTR_CLNT_CTL_TRY_DELAY(int)"
66 /* The time in seconds between attempts to send a request
67 /* (default: 1). Specify a value greater than zero.
68 /* DIAGNOSTICS
69 /* Warnings: communication failure.
70 /* SEE ALSO
71 /* auto_clnt(3), client endpoint management
72 /* attr_scan_plain(3), attribute protocol
73 /* attr_print_plain(3), attribute protocol
74 /* LICENSE
75 /* .ad
76 /* .fi
77 /* The Secure Mailer license must be distributed with this software.
78 /* AUTHOR(S)
79 /* Wietse Venema
80 /* IBM T.J. Watson Research
81 /* P.O. Box 704
82 /* Yorktown Heights, NY 10598, USA
83 /*--*/
84 
85 /* System library. */
86 
87 #include <sys_defs.h>
88 #include <unistd.h>
89 #include <errno.h>
90 
91 /* Utility library. */
92 
93 #include <msg.h>
94 #include <mymalloc.h>
95 #include <vstream.h>
96 #include <htable.h>
97 #include <attr.h>
98 #include <iostuff.h>
99 #include <compat_va_copy.h>
100 #include <auto_clnt.h>
101 #include <attr_clnt.h>
102 
103 /* Application-specific. */
104 
105 struct ATTR_CLNT {
107  /* Remaining properties are set with attr_clnt_control(). */
114 };
115 
116 #define ATTR_CLNT_DEF_REQ_LIMIT (0) /* default per-session request limit */
117 #define ATTR_CLNT_DEF_TRY_LIMIT (2) /* default request (re)try limit */
118 #define ATTR_CLNT_DEF_TRY_DELAY (1) /* default request (re)try delay */
119 
120 /* attr_clnt_free - destroy attribute client */
121 
123 {
124  auto_clnt_free(client->auto_clnt);
125  myfree((void *) client);
126 }
127 
128 /* attr_clnt_create - create attribute client */
129 
130 ATTR_CLNT *attr_clnt_create(const char *service, int timeout,
131  int max_idle, int max_ttl)
132 {
133  ATTR_CLNT *client;
134 
135  client = (ATTR_CLNT *) mymalloc(sizeof(*client));
136  client->auto_clnt = auto_clnt_create(service, timeout, max_idle, max_ttl);
137  client->scan = attr_vscan_plain;
138  client->print = attr_vprint_plain;
140  client->req_count = 0;
143  return (client);
144 }
145 
146 /* attr_clnt_request - send query, receive reply */
147 
148 int attr_clnt_request(ATTR_CLNT *client, int send_flags,...)
149 {
150  const char *myname = "attr_clnt_request";
151  VSTREAM *stream;
152  int count = 0;
153  va_list saved_ap;
154  va_list ap;
155  int type;
156  int recv_flags;
157  int err;
158  int ret;
159 
160  /*
161  * XXX If the stream is readable before we send anything, then assume the
162  * remote end disconnected.
163  *
164  * XXX For some reason we can't simply call the scan routine after the print
165  * routine, that messes up the argument list.
166  */
167 #define SKIP_ARG(ap, type) { \
168  (void) va_arg(ap, char *); \
169  (void) va_arg(ap, type); \
170  }
171 #define SKIP_ARG2(ap, t1, t2) { \
172  SKIP_ARG(ap, t1); \
173  (void) va_arg(ap, t2); \
174  }
175 
176  /* Finalize argument lists before returning. */
177  va_start(saved_ap, send_flags);
178  for (;;) {
179  errno = 0;
180  if ((stream = auto_clnt_access(client->auto_clnt)) != 0
181  && readable(vstream_fileno(stream)) == 0) {
182  errno = 0;
183  VA_COPY(ap, saved_ap);
184  err = (client->print(stream, send_flags, ap) != 0
185  || vstream_fflush(stream) != 0);
186  va_end(ap);
187  if (err == 0) {
188  VA_COPY(ap, saved_ap);
189  while ((type = va_arg(ap, int)) != ATTR_TYPE_END) {
190  switch (type) {
191  case ATTR_TYPE_STR:
192  SKIP_ARG(ap, char *);
193  break;
194  case ATTR_TYPE_DATA:
195  SKIP_ARG2(ap, ssize_t, char *);
196  break;
197  case ATTR_TYPE_INT:
198  SKIP_ARG(ap, int);
199  break;
200  case ATTR_TYPE_LONG:
201  SKIP_ARG(ap, long);
202  break;
203  case ATTR_TYPE_HASH:
204  (void) va_arg(ap, HTABLE *);
205  break;
206  default:
207  msg_panic("%s: unexpected attribute type %d",
208  myname, type);
209  }
210  }
211  recv_flags = va_arg(ap, int);
212  ret = client->scan(stream, recv_flags, ap);
213  va_end(ap);
214  /* Finalize argument lists before returning. */
215  if (ret > 0) {
216  if (client->req_limit > 0
217  && (client->req_count += 1) >= client->req_limit) {
218  auto_clnt_recover(client->auto_clnt);
219  client->req_count = 0;
220  }
221  break;
222  }
223  }
224  }
225  if ((++count >= client->try_limit && client->try_limit > 0)
226  || msg_verbose
227  || (errno && errno != EPIPE && errno != ENOENT && errno != ECONNRESET))
228  msg_warn("problem talking to server %s: %m",
229  auto_clnt_name(client->auto_clnt));
230  /* Finalize argument lists before returning. */
231  if (count >= client->try_limit && client->try_limit > 0) {
232  ret = -1;
233  break;
234  }
235  sleep(client->try_delay);
236  auto_clnt_recover(client->auto_clnt);
237  client->req_count = 0;
238  }
239  /* Finalize argument lists before returning. */
240  va_end(saved_ap);
241  return (ret);
242 }
243 
244 /* attr_clnt_control - fine control */
245 
246 void attr_clnt_control(ATTR_CLNT *client, int name,...)
247 {
248  const char *myname = "attr_clnt_control";
249  va_list ap;
250 
251  for (va_start(ap, name); name != ATTR_CLNT_CTL_END; name = va_arg(ap, int)) {
252  switch (name) {
253  case ATTR_CLNT_CTL_PROTO:
254  client->print = va_arg(ap, ATTR_CLNT_PRINT_FN);
255  client->scan = va_arg(ap, ATTR_CLNT_SCAN_FN);
256  break;
258  client->req_limit = va_arg(ap, int);
259  if (client->req_limit < 0)
260  msg_panic("%s: bad request limit: %d",
261  myname, client->req_limit);
262  if (msg_verbose)
263  msg_info("%s: new request limit %d",
264  myname, client->req_limit);
265  break;
267  client->try_limit = va_arg(ap, int);
268  if (client->try_limit < 0)
269  msg_panic("%s: bad retry limit: %d", myname, client->try_limit);
270  if (msg_verbose)
271  msg_info("%s: new retry limit %d", myname, client->try_limit);
272  break;
274  client->try_delay = va_arg(ap, int);
275  if (client->try_delay <= 0)
276  msg_panic("%s: bad retry delay: %d", myname, client->try_delay);
277  if (msg_verbose)
278  msg_info("%s: new retry delay %d", myname, client->try_delay);
279  break;
280  default:
281  msg_panic("%s: bad name %d", myname, name);
282  }
283  }
284  va_end(ap);
285 }
int msg_verbose
Definition: msg.c:177
#define ATTR_CLNT_CTL_TRY_LIMIT
Definition: attr_clnt.h:39
VSTREAM * auto_clnt_access(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:251
#define ATTR_CLNT_CTL_PROTO
Definition: attr_clnt.h:37
void myfree(void *ptr)
Definition: mymalloc.c:207
void attr_clnt_free(ATTR_CLNT *client)
Definition: attr_clnt.c:122
const char * auto_clnt_name(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:309
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
int req_count
Definition: attr_clnt.c:111
#define ATTR_CLNT_CTL_END
Definition: attr_clnt.h:36
int(* ATTR_CLNT_PRINT_FN)(VSTREAM *, int, va_list)
Definition: attr_clnt.h:28
#define ATTR_TYPE_END
Definition: attr.h:39
int WARN_UNUSED_RESULT attr_vscan_plain(VSTREAM *, int, va_list)
int try_delay
Definition: attr_clnt.c:113
Definition: htable.h:25
#define readable(fd)
Definition: iostuff.h:36
#define VA_COPY(dest, src)
#define ATTR_CLNT_DEF_REQ_LIMIT
Definition: attr_clnt.c:116
ATTR_CLNT_PRINT_FN print
Definition: attr_clnt.c:108
ATTR_CLNT * attr_clnt_create(const char *service, int timeout, int max_idle, int max_ttl)
Definition: attr_clnt.c:130
AUTO_CLNT * auto_clnt
Definition: attr_clnt.c:106
#define ATTR_CLNT_DEF_TRY_LIMIT
Definition: attr_clnt.c:117
#define ATTR_TYPE_INT
Definition: attr.h:40
void attr_clnt_control(ATTR_CLNT *client, int name,...)
Definition: attr_clnt.c:246
#define ATTR_TYPE_HASH
Definition: attr.h:43
#define ATTR_CLNT_CTL_TRY_DELAY
Definition: attr_clnt.h:40
AUTO_CLNT * auto_clnt_create(const char *service, int timeout, int max_idle, int max_ttl)
Definition: auto_clnt.c:271
#define ATTR_CLNT_CTL_REQ_LIMIT
Definition: attr_clnt.h:38
void msg_warn(const char *fmt,...)
Definition: msg.c:215
#define ATTR_CLNT_DEF_TRY_DELAY
Definition: attr_clnt.c:118
int(* ATTR_CLNT_SCAN_FN)(VSTREAM *, int, va_list)
Definition: attr_clnt.h:29
#define ATTR_TYPE_STR
Definition: attr.h:42
void auto_clnt_free(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:316
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
#define SKIP_ARG(ap, type)
int attr_clnt_request(ATTR_CLNT *client, int send_flags,...)
Definition: attr_clnt.c:148
void auto_clnt_recover(AUTO_CLNT *auto_clnt)
Definition: auto_clnt.c:239
int req_limit
Definition: attr_clnt.c:110
#define SKIP_ARG2(ap, t1, t2)
#define vstream_fileno(vp)
Definition: vstream.h:115
#define ATTR_TYPE_LONG
Definition: attr.h:45
#define ATTR_TYPE_DATA
Definition: attr.h:46
int attr_vprint_plain(VSTREAM *, int, va_list)
ATTR_CLNT_SCAN_FN scan
Definition: attr_clnt.c:109
int try_limit
Definition: attr_clnt.c:112
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
void msg_info(const char *fmt,...)
Definition: msg.c:199