1 /* $NetBSD: anvil_clnt.c,v 1.1.1.1 2009/06/23 10:08:44 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* anvil_clnt 3 6 /* SUMMARY 7 /* connection count and rate management client interface 8 /* SYNOPSIS 9 /* #include <anvil_clnt.h> 10 /* 11 /* ANVIL_CLNT *anvil_clnt_create(void) 12 /* 13 /* void anvil_clnt_free(anvil_clnt) 14 /* ANVIL_CLNT *anvil_clnt; 15 /* 16 /* int anvil_clnt_connect(anvil_clnt, service, addr, 17 /* count, rate) 18 /* ANVIL_CLNT *anvil_clnt; 19 /* const char *service; 20 /* const char *addr; 21 /* int *count; 22 /* int *rate; 23 /* 24 /* int anvil_clnt_mail(anvil_clnt, service, addr, msgs) 25 /* ANVIL_CLNT *anvil_clnt; 26 /* const char *service; 27 /* const char *addr; 28 /* int *msgs; 29 /* 30 /* int anvil_clnt_rcpt(anvil_clnt, service, addr, rcpts) 31 /* ANVIL_CLNT *anvil_clnt; 32 /* const char *service; 33 /* const char *addr; 34 /* int *rcpts; 35 /* 36 /* int anvil_clnt_newtls(anvil_clnt, service, addr, newtls) 37 /* ANVIL_CLNT *anvil_clnt; 38 /* const char *service; 39 /* const char *addr; 40 /* int *newtls; 41 /* 42 /* int anvil_clnt_newtls_stat(anvil_clnt, service, addr, newtls) 43 /* ANVIL_CLNT *anvil_clnt; 44 /* const char *service; 45 /* const char *addr; 46 /* int *newtls; 47 /* 48 /* int anvil_clnt_disconnect(anvil_clnt, service, addr) 49 /* ANVIL_CLNT *anvil_clnt; 50 /* const char *service; 51 /* const char *addr; 52 /* 53 /* int anvil_clnt_lookup(anvil_clnt, service, addr, 54 /* count, rate, msgs, rcpts) 55 /* ANVIL_CLNT *anvil_clnt; 56 /* const char *service; 57 /* const char *addr; 58 /* int *count; 59 /* int *rate; 60 /* int *msgs; 61 /* int *rcpts; 62 /* DESCRIPTION 63 /* anvil_clnt_create() instantiates a local anvil service 64 /* client endpoint. 65 /* 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. 69 /* 70 /* anvil_clnt_mail() registers a MAIL FROM event and 71 /* returns the current MAIL FROM rate for the specified remote 72 /* client. 73 /* 74 /* anvil_clnt_rcpt() registers a RCPT TO event and 75 /* returns the current RCPT TO rate for the specified remote 76 /* client. 77 /* 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. 81 /* 82 /* anvil_clnt_newtls_stat() returns the current newtls request 83 /* rate for the specified remote client. 84 /* 85 /* anvil_clnt_disconnect() informs the anvil server that a remote 86 /* client has disconnected. 87 /* 88 /* anvil_clnt_lookup() returns the current count and rate 89 /* information for the specified client. 90 /* 91 /* anvil_clnt_free() destroys a local anvil service client 92 /* endpoint. 93 /* 94 /* Arguments: 95 /* .IP anvil_clnt 96 /* Client rate control service handle. 97 /* .IP service 98 /* The service that the remote client is connected to. 99 /* .IP addr 100 /* Null terminated string that identifies the remote client. 101 /* .IP count 102 /* Pointer to storage for the current number of connections from 103 /* this remote client. 104 /* .IP rate 105 /* Pointer to storage for the current connection rate for this 106 /* remote client. 107 /* .IP msgs 108 /* Pointer to storage for the current message rate for this 109 /* remote client. 110 /* .IP rcpts 111 /* Pointer to storage for the current recipient rate for this 112 /* remote client. 113 /* .IP newtls 114 /* Pointer to storage for the current "new TLS session" rate 115 /* for this remote client. 116 /* DIAGNOSTICS 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). 121 /* SEE ALSO 122 /* anvil(8), connection/rate limiting 123 /* LICENSE 124 /* .ad 125 /* .fi 126 /* The Secure Mailer license must be distributed with this software. 127 /* AUTHOR(S) 128 /* Wietse Venema 129 /* IBM T.J. Watson Research 130 /* P.O. Box 704 131 /* Yorktown Heights, NY 10598, USA 132 /*--*/ 133 134 /* System library. */ 135 136 #include <sys_defs.h> 137 138 /* Utility library. */ 139 140 #include <mymalloc.h> 141 #include <msg.h> 142 #include <attr_clnt.h> 143 #include <stringops.h> 144 145 /* Global library. */ 146 147 #include <mail_proto.h> 148 #include <mail_params.h> 149 #include <anvil_clnt.h> 150 151 /* Application specific. */ 152 153 #define ANVIL_IDENT(service, addr) \ 154 printable(concatenate(service, ":", addr, (char *) 0), '?') 155 156 /* anvil_clnt_create - instantiate connection rate service client */ 157 158 ANVIL_CLNT *anvil_clnt_create(void) 159 { 160 ATTR_CLNT *anvil_clnt; 161 162 /* 163 * Use whatever IPC is preferred for internal use: UNIX-domain sockets or 164 * Solaris streams. 165 */ 166 #ifndef VAR_ANVIL_SERVICE 167 anvil_clnt = attr_clnt_create("local:" ANVIL_CLASS "/" ANVIL_SERVICE, 168 var_ipc_timeout, 0, 0); 169 #else 170 anvil_clnt = attr_clnt_create(var_anvil_service, var_ipc_timeout, 0, 0); 171 #endif 172 return ((ANVIL_CLNT *) anvil_clnt); 173 } 174 175 /* anvil_clnt_free - destroy connection rate service client */ 176 177 void anvil_clnt_free(ANVIL_CLNT *anvil_clnt) 178 { 179 attr_clnt_free((ATTR_CLNT *) anvil_clnt); 180 } 181 182 /* anvil_clnt_lookup - status query */ 183 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) 187 { 188 char *ident = ANVIL_IDENT(service, addr); 189 int status; 190 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, 195 ATTR_TYPE_END, 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, 203 ATTR_TYPE_END) != 6) 204 status = ANVIL_STAT_FAIL; 205 else if (status != ANVIL_STAT_OK) 206 status = ANVIL_STAT_FAIL; 207 myfree(ident); 208 return (status); 209 } 210 211 /* anvil_clnt_connect - heads-up and status query */ 212 213 int anvil_clnt_connect(ANVIL_CLNT *anvil_clnt, const char *service, 214 const char *addr, int *count, int *rate) 215 { 216 char *ident = ANVIL_IDENT(service, addr); 217 int status; 218 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, 223 ATTR_TYPE_END, 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, 228 ATTR_TYPE_END) != 3) 229 status = ANVIL_STAT_FAIL; 230 else if (status != ANVIL_STAT_OK) 231 status = ANVIL_STAT_FAIL; 232 myfree(ident); 233 return (status); 234 } 235 236 /* anvil_clnt_mail - heads-up and status query */ 237 238 int anvil_clnt_mail(ANVIL_CLNT *anvil_clnt, const char *service, 239 const char *addr, int *msgs) 240 { 241 char *ident = ANVIL_IDENT(service, addr); 242 int status; 243 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, 248 ATTR_TYPE_END, 249 ATTR_FLAG_MISSING, /* Reply attributes. */ 250 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 251 ATTR_TYPE_INT, ANVIL_ATTR_RATE, msgs, 252 ATTR_TYPE_END) != 2) 253 status = ANVIL_STAT_FAIL; 254 else if (status != ANVIL_STAT_OK) 255 status = ANVIL_STAT_FAIL; 256 myfree(ident); 257 return (status); 258 } 259 260 /* anvil_clnt_rcpt - heads-up and status query */ 261 262 int anvil_clnt_rcpt(ANVIL_CLNT *anvil_clnt, const char *service, 263 const char *addr, int *rcpts) 264 { 265 char *ident = ANVIL_IDENT(service, addr); 266 int status; 267 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, 272 ATTR_TYPE_END, 273 ATTR_FLAG_MISSING, /* Reply attributes. */ 274 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 275 ATTR_TYPE_INT, ANVIL_ATTR_RATE, rcpts, 276 ATTR_TYPE_END) != 2) 277 status = ANVIL_STAT_FAIL; 278 else if (status != ANVIL_STAT_OK) 279 status = ANVIL_STAT_FAIL; 280 myfree(ident); 281 return (status); 282 } 283 284 /* anvil_clnt_newtls - heads-up and status query */ 285 286 int anvil_clnt_newtls(ANVIL_CLNT *anvil_clnt, const char *service, 287 const char *addr, int *newtls) 288 { 289 char *ident = ANVIL_IDENT(service, addr); 290 int status; 291 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, 296 ATTR_TYPE_END, 297 ATTR_FLAG_MISSING, /* Reply attributes. */ 298 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 299 ATTR_TYPE_INT, ANVIL_ATTR_RATE, newtls, 300 ATTR_TYPE_END) != 2) 301 status = ANVIL_STAT_FAIL; 302 else if (status != ANVIL_STAT_OK) 303 status = ANVIL_STAT_FAIL; 304 myfree(ident); 305 return (status); 306 } 307 308 /* anvil_clnt_newtls_stat - status query */ 309 310 int anvil_clnt_newtls_stat(ANVIL_CLNT *anvil_clnt, const char *service, 311 const char *addr, int *newtls) 312 { 313 char *ident = ANVIL_IDENT(service, addr); 314 int status; 315 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, 320 ATTR_TYPE_END, 321 ATTR_FLAG_MISSING, /* Reply attributes. */ 322 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 323 ATTR_TYPE_INT, ANVIL_ATTR_RATE, newtls, 324 ATTR_TYPE_END) != 2) 325 status = ANVIL_STAT_FAIL; 326 else if (status != ANVIL_STAT_OK) 327 status = ANVIL_STAT_FAIL; 328 myfree(ident); 329 return (status); 330 } 331 332 /* anvil_clnt_disconnect - heads-up only */ 333 334 int anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service, 335 const char *addr) 336 { 337 char *ident = ANVIL_IDENT(service, addr); 338 int status; 339 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, 344 ATTR_TYPE_END, 345 ATTR_FLAG_MISSING, /* Reply attributes. */ 346 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 347 ATTR_TYPE_END) != 1) 348 status = ANVIL_STAT_FAIL; 349 else if (status != ANVIL_STAT_OK) 350 status = ANVIL_STAT_FAIL; 351 myfree(ident); 352 return (status); 353 } 354 355 #ifdef TEST 356 357 /* 358 * Stand-alone client for testing. 359 */ 360 #include <unistd.h> 361 #include <string.h> 362 #include <msg_vstream.h> 363 #include <mail_conf.h> 364 #include <mail_params.h> 365 #include <vstring_vstream.h> 366 367 static void usage(void) 368 { 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"); 377 } 378 379 int main(int unused_argc, char **argv) 380 { 381 VSTRING *inbuf = vstring_alloc(1); 382 char *bufp; 383 char *cmd; 384 ssize_t cmd_len; 385 char *service; 386 char *addr; 387 int count; 388 int rate; 389 int msgs; 390 int rcpts; 391 int newtls; 392 ANVIL_CLNT *anvil; 393 394 msg_vstream_init(argv[0], VSTREAM_ERR); 395 396 mail_conf_read(); 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); 400 401 msg_verbose++; 402 403 anvil = anvil_clnt_create(); 404 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"); 412 usage(); 413 vstream_fflush(VSTREAM_OUT); 414 continue; 415 } 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) 419 msg_warn("error!"); 420 else 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) 424 msg_warn("error!"); 425 else 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) 429 msg_warn("error!"); 430 else 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) 434 msg_warn("error!"); 435 else 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) 439 msg_warn("error!"); 440 else 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) 444 msg_warn("error!"); 445 else 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) 450 msg_warn("error!"); 451 else 452 vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d newtls=%d\n", 453 count, rate, msgs, rcpts, newtls); 454 } else { 455 vstream_printf("bad command: \"%s\"\n", cmd); 456 usage(); 457 } 458 vstream_fflush(VSTREAM_OUT); 459 } 460 vstring_free(inbuf); 461 anvil_clnt_free(anvil); 462 return (0); 463 } 464 465 #endif 466