7 /* connection count and rate management client interface
9 /* #include <anvil_clnt.h>
11 /* ANVIL_CLNT *anvil_clnt_create(void)
13 /* void anvil_clnt_free(anvil_clnt)
14 /* ANVIL_CLNT *anvil_clnt;
16 /* int anvil_clnt_connect(anvil_clnt, service, addr,
18 /* ANVIL_CLNT *anvil_clnt;
19 /* const char *service;
24 /* int anvil_clnt_mail(anvil_clnt, service, addr, msgs)
25 /* ANVIL_CLNT *anvil_clnt;
26 /* const char *service;
30 /* int anvil_clnt_rcpt(anvil_clnt, service, addr, rcpts)
31 /* ANVIL_CLNT *anvil_clnt;
32 /* const char *service;
36 /* int anvil_clnt_newtls(anvil_clnt, service, addr, newtls)
37 /* ANVIL_CLNT *anvil_clnt;
38 /* const char *service;
42 /* int anvil_clnt_newtls_stat(anvil_clnt, service, addr, newtls)
43 /* ANVIL_CLNT *anvil_clnt;
44 /* const char *service;
48 /* int anvil_clnt_disconnect(anvil_clnt, service, addr)
49 /* ANVIL_CLNT *anvil_clnt;
50 /* const char *service;
53 /* int anvil_clnt_lookup(anvil_clnt, service, addr,
54 /* count, rate, msgs, rcpts)
55 /* ANVIL_CLNT *anvil_clnt;
56 /* const char *service;
63 /* anvil_clnt_create() instantiates a local anvil service
66 /* anvil_clnt_connect() informs the anvil server that a
67 /* remote client has connected, and returns the current
68 /* connection count and connection rate for that remote client.
70 /* anvil_clnt_mail() registers a MAIL FROM event and
71 /* returns the current MAIL FROM rate for the specified remote
74 /* anvil_clnt_rcpt() registers a RCPT TO event and
75 /* returns the current RCPT TO rate for the specified remote
78 /* anvil_clnt_newtls() registers a remote client request
79 /* to negotiate a new (uncached) TLS session and returns the
80 /* current newtls request rate for the specified remote client.
82 /* anvil_clnt_newtls_stat() returns the current newtls request
83 /* rate for the specified remote client.
85 /* anvil_clnt_disconnect() informs the anvil server that a remote
86 /* client has disconnected.
88 /* anvil_clnt_lookup() returns the current count and rate
89 /* information for the specified client.
91 /* anvil_clnt_free() destroys a local anvil service client
96 /* Client rate control service handle.
98 /* The service that the remote client is connected to.
100 /* Null terminated string that identifies the remote client.
102 /* Pointer to storage for the current number of connections from
103 /* this remote client.
105 /* Pointer to storage for the current connection rate for this
108 /* Pointer to storage for the current message rate for this
111 /* Pointer to storage for the current recipient rate for this
114 /* Pointer to storage for the current "new TLS session" rate
115 /* for this remote client.
117 /* The update and status query routines return
118 /* ANVIL_STAT_OK in case of success, ANVIL_STAT_FAIL otherwise
119 /* (either the communication with the server is broken or the
120 /* server experienced a problem).
122 /* anvil(8), connection/rate limiting
126 /* The Secure Mailer license must be distributed with this software.
129 /* IBM T.J. Watson Research
131 /* Yorktown Heights, NY 10598, USA
134 /* System library. */
136 #include <sys_defs.h>
138 /* Utility library. */
140 #include <mymalloc.h>
142 #include <attr_clnt.h>
143 #include <stringops.h>
145 /* Global library. */
147 #include <mail_proto.h>
148 #include <mail_params.h>
149 #include <anvil_clnt.h>
151 /* Application specific. */
153 #define ANVIL_IDENT(service, addr) \
154 printable(concatenate(service, ":", addr, (char *) 0), '?')
156 /* anvil_clnt_create - instantiate connection rate service client */
158 ANVIL_CLNT
*anvil_clnt_create(void)
160 ATTR_CLNT
*anvil_clnt
;
163 * Use whatever IPC is preferred for internal use: UNIX-domain sockets or
166 #ifndef VAR_ANVIL_SERVICE
167 anvil_clnt
= attr_clnt_create("local:" ANVIL_CLASS
"/" ANVIL_SERVICE
,
168 var_ipc_timeout
, 0, 0);
170 anvil_clnt
= attr_clnt_create(var_anvil_service
, var_ipc_timeout
, 0, 0);
172 return ((ANVIL_CLNT
*) anvil_clnt
);
175 /* anvil_clnt_free - destroy connection rate service client */
177 void anvil_clnt_free(ANVIL_CLNT
*anvil_clnt
)
179 attr_clnt_free((ATTR_CLNT
*) anvil_clnt
);
182 /* anvil_clnt_lookup - status query */
184 int anvil_clnt_lookup(ANVIL_CLNT
*anvil_clnt
, const char *service
,
185 const char *addr
, int *count
, int *rate
,
186 int *msgs
, int *rcpts
, int *newtls
)
188 char *ident
= ANVIL_IDENT(service
, addr
);
191 if (attr_clnt_request((ATTR_CLNT
*) anvil_clnt
,
192 ATTR_FLAG_NONE
, /* Query attributes. */
193 ATTR_TYPE_STR
, ANVIL_ATTR_REQ
, ANVIL_REQ_LOOKUP
,
194 ATTR_TYPE_STR
, ANVIL_ATTR_IDENT
, ident
,
196 ATTR_FLAG_MISSING
, /* Reply attributes. */
197 ATTR_TYPE_INT
, ANVIL_ATTR_STATUS
, &status
,
198 ATTR_TYPE_INT
, ANVIL_ATTR_COUNT
, count
,
199 ATTR_TYPE_INT
, ANVIL_ATTR_RATE
, rate
,
200 ATTR_TYPE_INT
, ANVIL_ATTR_MAIL
, msgs
,
201 ATTR_TYPE_INT
, ANVIL_ATTR_RCPT
, rcpts
,
202 ATTR_TYPE_INT
, ANVIL_ATTR_NTLS
, newtls
,
204 status
= ANVIL_STAT_FAIL
;
205 else if (status
!= ANVIL_STAT_OK
)
206 status
= ANVIL_STAT_FAIL
;
211 /* anvil_clnt_connect - heads-up and status query */
213 int anvil_clnt_connect(ANVIL_CLNT
*anvil_clnt
, const char *service
,
214 const char *addr
, int *count
, int *rate
)
216 char *ident
= ANVIL_IDENT(service
, addr
);
219 if (attr_clnt_request((ATTR_CLNT
*) anvil_clnt
,
220 ATTR_FLAG_NONE
, /* Query attributes. */
221 ATTR_TYPE_STR
, ANVIL_ATTR_REQ
, ANVIL_REQ_CONN
,
222 ATTR_TYPE_STR
, ANVIL_ATTR_IDENT
, ident
,
224 ATTR_FLAG_MISSING
, /* Reply attributes. */
225 ATTR_TYPE_INT
, ANVIL_ATTR_STATUS
, &status
,
226 ATTR_TYPE_INT
, ANVIL_ATTR_COUNT
, count
,
227 ATTR_TYPE_INT
, ANVIL_ATTR_RATE
, rate
,
229 status
= ANVIL_STAT_FAIL
;
230 else if (status
!= ANVIL_STAT_OK
)
231 status
= ANVIL_STAT_FAIL
;
236 /* anvil_clnt_mail - heads-up and status query */
238 int anvil_clnt_mail(ANVIL_CLNT
*anvil_clnt
, const char *service
,
239 const char *addr
, int *msgs
)
241 char *ident
= ANVIL_IDENT(service
, addr
);
244 if (attr_clnt_request((ATTR_CLNT
*) anvil_clnt
,
245 ATTR_FLAG_NONE
, /* Query attributes. */
246 ATTR_TYPE_STR
, ANVIL_ATTR_REQ
, ANVIL_REQ_MAIL
,
247 ATTR_TYPE_STR
, ANVIL_ATTR_IDENT
, ident
,
249 ATTR_FLAG_MISSING
, /* Reply attributes. */
250 ATTR_TYPE_INT
, ANVIL_ATTR_STATUS
, &status
,
251 ATTR_TYPE_INT
, ANVIL_ATTR_RATE
, msgs
,
253 status
= ANVIL_STAT_FAIL
;
254 else if (status
!= ANVIL_STAT_OK
)
255 status
= ANVIL_STAT_FAIL
;
260 /* anvil_clnt_rcpt - heads-up and status query */
262 int anvil_clnt_rcpt(ANVIL_CLNT
*anvil_clnt
, const char *service
,
263 const char *addr
, int *rcpts
)
265 char *ident
= ANVIL_IDENT(service
, addr
);
268 if (attr_clnt_request((ATTR_CLNT
*) anvil_clnt
,
269 ATTR_FLAG_NONE
, /* Query attributes. */
270 ATTR_TYPE_STR
, ANVIL_ATTR_REQ
, ANVIL_REQ_RCPT
,
271 ATTR_TYPE_STR
, ANVIL_ATTR_IDENT
, ident
,
273 ATTR_FLAG_MISSING
, /* Reply attributes. */
274 ATTR_TYPE_INT
, ANVIL_ATTR_STATUS
, &status
,
275 ATTR_TYPE_INT
, ANVIL_ATTR_RATE
, rcpts
,
277 status
= ANVIL_STAT_FAIL
;
278 else if (status
!= ANVIL_STAT_OK
)
279 status
= ANVIL_STAT_FAIL
;
284 /* anvil_clnt_newtls - heads-up and status query */
286 int anvil_clnt_newtls(ANVIL_CLNT
*anvil_clnt
, const char *service
,
287 const char *addr
, int *newtls
)
289 char *ident
= ANVIL_IDENT(service
, addr
);
292 if (attr_clnt_request((ATTR_CLNT
*) anvil_clnt
,
293 ATTR_FLAG_NONE
, /* Query attributes. */
294 ATTR_TYPE_STR
, ANVIL_ATTR_REQ
, ANVIL_REQ_NTLS
,
295 ATTR_TYPE_STR
, ANVIL_ATTR_IDENT
, ident
,
297 ATTR_FLAG_MISSING
, /* Reply attributes. */
298 ATTR_TYPE_INT
, ANVIL_ATTR_STATUS
, &status
,
299 ATTR_TYPE_INT
, ANVIL_ATTR_RATE
, newtls
,
301 status
= ANVIL_STAT_FAIL
;
302 else if (status
!= ANVIL_STAT_OK
)
303 status
= ANVIL_STAT_FAIL
;
308 /* anvil_clnt_newtls_stat - status query */
310 int anvil_clnt_newtls_stat(ANVIL_CLNT
*anvil_clnt
, const char *service
,
311 const char *addr
, int *newtls
)
313 char *ident
= ANVIL_IDENT(service
, addr
);
316 if (attr_clnt_request((ATTR_CLNT
*) anvil_clnt
,
317 ATTR_FLAG_NONE
, /* Query attributes. */
318 ATTR_TYPE_STR
, ANVIL_ATTR_REQ
, ANVIL_REQ_NTLS_STAT
,
319 ATTR_TYPE_STR
, ANVIL_ATTR_IDENT
, ident
,
321 ATTR_FLAG_MISSING
, /* Reply attributes. */
322 ATTR_TYPE_INT
, ANVIL_ATTR_STATUS
, &status
,
323 ATTR_TYPE_INT
, ANVIL_ATTR_RATE
, newtls
,
325 status
= ANVIL_STAT_FAIL
;
326 else if (status
!= ANVIL_STAT_OK
)
327 status
= ANVIL_STAT_FAIL
;
332 /* anvil_clnt_disconnect - heads-up only */
334 int anvil_clnt_disconnect(ANVIL_CLNT
*anvil_clnt
, const char *service
,
337 char *ident
= ANVIL_IDENT(service
, addr
);
340 if (attr_clnt_request((ATTR_CLNT
*) anvil_clnt
,
341 ATTR_FLAG_NONE
, /* Query attributes. */
342 ATTR_TYPE_STR
, ANVIL_ATTR_REQ
, ANVIL_REQ_DISC
,
343 ATTR_TYPE_STR
, ANVIL_ATTR_IDENT
, ident
,
345 ATTR_FLAG_MISSING
, /* Reply attributes. */
346 ATTR_TYPE_INT
, ANVIL_ATTR_STATUS
, &status
,
348 status
= ANVIL_STAT_FAIL
;
349 else if (status
!= ANVIL_STAT_OK
)
350 status
= ANVIL_STAT_FAIL
;
358 * Stand-alone client for testing.
362 #include <msg_vstream.h>
363 #include <mail_conf.h>
364 #include <mail_params.h>
365 #include <vstring_vstream.h>
367 static void usage(void)
369 vstream_printf("usage: "
370 ANVIL_REQ_CONN
" service addr | "
371 ANVIL_REQ_DISC
" service addr | "
372 ANVIL_REQ_MAIL
" service addr | "
373 ANVIL_REQ_RCPT
" service addr | "
374 ANVIL_REQ_NTLS
" service addr | "
375 ANVIL_REQ_NTLS_STAT
" service addr | "
376 ANVIL_REQ_LOOKUP
" service addr\n");
379 int main(int unused_argc
, char **argv
)
381 VSTRING
*inbuf
= vstring_alloc(1);
394 msg_vstream_init(argv
[0], VSTREAM_ERR
);
397 msg_info("using config files in %s", var_config_dir
);
398 if (chdir(var_queue_dir
) < 0)
399 msg_fatal("chdir %s: %m", var_queue_dir
);
403 anvil
= anvil_clnt_create();
405 while (vstring_fgets_nonl(inbuf
, VSTREAM_IN
)) {
406 bufp
= vstring_str(inbuf
);
407 if ((cmd
= mystrtok(&bufp
, " ")) == 0 || *bufp
== 0
408 || (service
= mystrtok(&bufp
, " ")) == 0 || *service
== 0
409 || (addr
= mystrtok(&bufp
, " ")) == 0 || *addr
== 0
410 || mystrtok(&bufp
, " ") != 0) {
411 vstream_printf("bad command syntax\n");
413 vstream_fflush(VSTREAM_OUT
);
416 cmd_len
= strlen(cmd
);
417 if (strncmp(cmd
, ANVIL_REQ_CONN
, cmd_len
) == 0) {
418 if (anvil_clnt_connect(anvil
, service
, addr
, &count
, &rate
) != ANVIL_STAT_OK
)
421 vstream_printf("count=%d, rate=%d\n", count
, rate
);
422 } else if (strncmp(cmd
, ANVIL_REQ_MAIL
, cmd_len
) == 0) {
423 if (anvil_clnt_mail(anvil
, service
, addr
, &msgs
) != ANVIL_STAT_OK
)
426 vstream_printf("rate=%d\n", msgs
);
427 } else if (strncmp(cmd
, ANVIL_REQ_RCPT
, cmd_len
) == 0) {
428 if (anvil_clnt_rcpt(anvil
, service
, addr
, &rcpts
) != ANVIL_STAT_OK
)
431 vstream_printf("rate=%d\n", rcpts
);
432 } else if (strncmp(cmd
, ANVIL_REQ_NTLS
, cmd_len
) == 0) {
433 if (anvil_clnt_newtls(anvil
, service
, addr
, &newtls
) != ANVIL_STAT_OK
)
436 vstream_printf("rate=%d\n", newtls
);
437 } else if (strncmp(cmd
, ANVIL_REQ_NTLS_STAT
, cmd_len
) == 0) {
438 if (anvil_clnt_newtls_stat(anvil
, service
, addr
, &newtls
) != ANVIL_STAT_OK
)
441 vstream_printf("rate=%d\n", newtls
);
442 } else if (strncmp(cmd
, ANVIL_REQ_DISC
, cmd_len
) == 0) {
443 if (anvil_clnt_disconnect(anvil
, service
, addr
) != ANVIL_STAT_OK
)
446 vstream_printf("OK\n");
447 } else if (strncmp(cmd
, ANVIL_REQ_LOOKUP
, cmd_len
) == 0) {
448 if (anvil_clnt_lookup(anvil
, service
, addr
, &count
, &rate
,
449 &msgs
, &rcpts
, &newtls
) != ANVIL_STAT_OK
)
452 vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d newtls=%d\n",
453 count
, rate
, msgs
, rcpts
, newtls
);
455 vstream_printf("bad command: \"%s\"\n", cmd
);
458 vstream_fflush(VSTREAM_OUT
);
461 anvil_clnt_free(anvil
);