1/*++ 2/* NAME 3/* anvil_clnt 3 4/* SUMMARY 5/* connection count and rate management client interface 6/* SYNOPSIS 7/* #include <anvil_clnt.h> 8/* 9/* ANVIL_CLNT *anvil_clnt_create(void) 10/* 11/* void anvil_clnt_free(anvil_clnt) 12/* ANVIL_CLNT *anvil_clnt; 13/* 14/* int anvil_clnt_connect(anvil_clnt, service, addr, 15/* count, rate) 16/* ANVIL_CLNT *anvil_clnt; 17/* const char *service; 18/* const char *addr; 19/* int *count; 20/* int *rate; 21/* 22/* int anvil_clnt_mail(anvil_clnt, service, addr, msgs) 23/* ANVIL_CLNT *anvil_clnt; 24/* const char *service; 25/* const char *addr; 26/* int *msgs; 27/* 28/* int anvil_clnt_rcpt(anvil_clnt, service, addr, rcpts) 29/* ANVIL_CLNT *anvil_clnt; 30/* const char *service; 31/* const char *addr; 32/* int *rcpts; 33/* 34/* int anvil_clnt_newtls(anvil_clnt, service, addr, newtls) 35/* ANVIL_CLNT *anvil_clnt; 36/* const char *service; 37/* const char *addr; 38/* int *newtls; 39/* 40/* int anvil_clnt_newtls_stat(anvil_clnt, service, addr, newtls) 41/* ANVIL_CLNT *anvil_clnt; 42/* const char *service; 43/* const char *addr; 44/* int *newtls; 45/* 46/* int anvil_clnt_disconnect(anvil_clnt, service, addr) 47/* ANVIL_CLNT *anvil_clnt; 48/* const char *service; 49/* const char *addr; 50/* 51/* int anvil_clnt_lookup(anvil_clnt, service, addr, 52/* count, rate, msgs, rcpts) 53/* ANVIL_CLNT *anvil_clnt; 54/* const char *service; 55/* const char *addr; 56/* int *count; 57/* int *rate; 58/* int *msgs; 59/* int *rcpts; 60/* DESCRIPTION 61/* anvil_clnt_create() instantiates a local anvil service 62/* client endpoint. 63/* 64/* anvil_clnt_connect() informs the anvil server that a 65/* remote client has connected, and returns the current 66/* connection count and connection rate for that remote client. 67/* 68/* anvil_clnt_mail() registers a MAIL FROM event and 69/* returns the current MAIL FROM rate for the specified remote 70/* client. 71/* 72/* anvil_clnt_rcpt() registers a RCPT TO event and 73/* returns the current RCPT TO rate for the specified remote 74/* client. 75/* 76/* anvil_clnt_newtls() registers a remote client request 77/* to negotiate a new (uncached) TLS session and returns the 78/* current newtls request rate for the specified remote client. 79/* 80/* anvil_clnt_newtls_stat() returns the current newtls request 81/* rate for the specified remote client. 82/* 83/* anvil_clnt_disconnect() informs the anvil server that a remote 84/* client has disconnected. 85/* 86/* anvil_clnt_lookup() returns the current count and rate 87/* information for the specified client. 88/* 89/* anvil_clnt_free() destroys a local anvil service client 90/* endpoint. 91/* 92/* Arguments: 93/* .IP anvil_clnt 94/* Client rate control service handle. 95/* .IP service 96/* The service that the remote client is connected to. 97/* .IP addr 98/* Null terminated string that identifies the remote client. 99/* .IP count 100/* Pointer to storage for the current number of connections from 101/* this remote client. 102/* .IP rate 103/* Pointer to storage for the current connection rate for this 104/* remote client. 105/* .IP msgs 106/* Pointer to storage for the current message rate for this 107/* remote client. 108/* .IP rcpts 109/* Pointer to storage for the current recipient rate for this 110/* remote client. 111/* .IP newtls 112/* Pointer to storage for the current "new TLS session" rate 113/* for this remote client. 114/* DIAGNOSTICS 115/* The update and status query routines return 116/* ANVIL_STAT_OK in case of success, ANVIL_STAT_FAIL otherwise 117/* (either the communication with the server is broken or the 118/* server experienced a problem). 119/* SEE ALSO 120/* anvil(8), connection/rate limiting 121/* LICENSE 122/* .ad 123/* .fi 124/* The Secure Mailer license must be distributed with this software. 125/* AUTHOR(S) 126/* Wietse Venema 127/* IBM T.J. Watson Research 128/* P.O. Box 704 129/* Yorktown Heights, NY 10598, USA 130/*--*/ 131 132/* System library. */ 133 134#include <sys_defs.h> 135 136/* Utility library. */ 137 138#include <mymalloc.h> 139#include <msg.h> 140#include <attr_clnt.h> 141#include <stringops.h> 142 143/* Global library. */ 144 145#include <mail_proto.h> 146#include <mail_params.h> 147#include <anvil_clnt.h> 148 149/* Application specific. */ 150 151#define ANVIL_IDENT(service, addr) \ 152 printable(concatenate(service, ":", addr, (char *) 0), '?') 153 154/* anvil_clnt_create - instantiate connection rate service client */ 155 156ANVIL_CLNT *anvil_clnt_create(void) 157{ 158 ATTR_CLNT *anvil_clnt; 159 160 /* 161 * Use whatever IPC is preferred for internal use: UNIX-domain sockets or 162 * Solaris streams. 163 */ 164#ifndef VAR_ANVIL_SERVICE 165 anvil_clnt = attr_clnt_create("local:" ANVIL_CLASS "/" ANVIL_SERVICE, 166 var_ipc_timeout, 0, 0); 167#else 168 anvil_clnt = attr_clnt_create(var_anvil_service, var_ipc_timeout, 0, 0); 169#endif 170 return ((ANVIL_CLNT *) anvil_clnt); 171} 172 173/* anvil_clnt_free - destroy connection rate service client */ 174 175void anvil_clnt_free(ANVIL_CLNT *anvil_clnt) 176{ 177 attr_clnt_free((ATTR_CLNT *) anvil_clnt); 178} 179 180/* anvil_clnt_lookup - status query */ 181 182int anvil_clnt_lookup(ANVIL_CLNT *anvil_clnt, const char *service, 183 const char *addr, int *count, int *rate, 184 int *msgs, int *rcpts, int *newtls) 185{ 186 char *ident = ANVIL_IDENT(service, addr); 187 int status; 188 189 if (attr_clnt_request((ATTR_CLNT *) anvil_clnt, 190 ATTR_FLAG_NONE, /* Query attributes. */ 191 ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_LOOKUP, 192 ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, 193 ATTR_TYPE_END, 194 ATTR_FLAG_MISSING, /* Reply attributes. */ 195 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 196 ATTR_TYPE_INT, ANVIL_ATTR_COUNT, count, 197 ATTR_TYPE_INT, ANVIL_ATTR_RATE, rate, 198 ATTR_TYPE_INT, ANVIL_ATTR_MAIL, msgs, 199 ATTR_TYPE_INT, ANVIL_ATTR_RCPT, rcpts, 200 ATTR_TYPE_INT, ANVIL_ATTR_NTLS, newtls, 201 ATTR_TYPE_END) != 6) 202 status = ANVIL_STAT_FAIL; 203 else if (status != ANVIL_STAT_OK) 204 status = ANVIL_STAT_FAIL; 205 myfree(ident); 206 return (status); 207} 208 209/* anvil_clnt_connect - heads-up and status query */ 210 211int anvil_clnt_connect(ANVIL_CLNT *anvil_clnt, const char *service, 212 const char *addr, int *count, int *rate) 213{ 214 char *ident = ANVIL_IDENT(service, addr); 215 int status; 216 217 if (attr_clnt_request((ATTR_CLNT *) anvil_clnt, 218 ATTR_FLAG_NONE, /* Query attributes. */ 219 ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_CONN, 220 ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, 221 ATTR_TYPE_END, 222 ATTR_FLAG_MISSING, /* Reply attributes. */ 223 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 224 ATTR_TYPE_INT, ANVIL_ATTR_COUNT, count, 225 ATTR_TYPE_INT, ANVIL_ATTR_RATE, rate, 226 ATTR_TYPE_END) != 3) 227 status = ANVIL_STAT_FAIL; 228 else if (status != ANVIL_STAT_OK) 229 status = ANVIL_STAT_FAIL; 230 myfree(ident); 231 return (status); 232} 233 234/* anvil_clnt_mail - heads-up and status query */ 235 236int anvil_clnt_mail(ANVIL_CLNT *anvil_clnt, const char *service, 237 const char *addr, int *msgs) 238{ 239 char *ident = ANVIL_IDENT(service, addr); 240 int status; 241 242 if (attr_clnt_request((ATTR_CLNT *) anvil_clnt, 243 ATTR_FLAG_NONE, /* Query attributes. */ 244 ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_MAIL, 245 ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, 246 ATTR_TYPE_END, 247 ATTR_FLAG_MISSING, /* Reply attributes. */ 248 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 249 ATTR_TYPE_INT, ANVIL_ATTR_RATE, msgs, 250 ATTR_TYPE_END) != 2) 251 status = ANVIL_STAT_FAIL; 252 else if (status != ANVIL_STAT_OK) 253 status = ANVIL_STAT_FAIL; 254 myfree(ident); 255 return (status); 256} 257 258/* anvil_clnt_rcpt - heads-up and status query */ 259 260int anvil_clnt_rcpt(ANVIL_CLNT *anvil_clnt, const char *service, 261 const char *addr, int *rcpts) 262{ 263 char *ident = ANVIL_IDENT(service, addr); 264 int status; 265 266 if (attr_clnt_request((ATTR_CLNT *) anvil_clnt, 267 ATTR_FLAG_NONE, /* Query attributes. */ 268 ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_RCPT, 269 ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, 270 ATTR_TYPE_END, 271 ATTR_FLAG_MISSING, /* Reply attributes. */ 272 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 273 ATTR_TYPE_INT, ANVIL_ATTR_RATE, rcpts, 274 ATTR_TYPE_END) != 2) 275 status = ANVIL_STAT_FAIL; 276 else if (status != ANVIL_STAT_OK) 277 status = ANVIL_STAT_FAIL; 278 myfree(ident); 279 return (status); 280} 281 282/* anvil_clnt_newtls - heads-up and status query */ 283 284int anvil_clnt_newtls(ANVIL_CLNT *anvil_clnt, const char *service, 285 const char *addr, int *newtls) 286{ 287 char *ident = ANVIL_IDENT(service, addr); 288 int status; 289 290 if (attr_clnt_request((ATTR_CLNT *) anvil_clnt, 291 ATTR_FLAG_NONE, /* Query attributes. */ 292 ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_NTLS, 293 ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, 294 ATTR_TYPE_END, 295 ATTR_FLAG_MISSING, /* Reply attributes. */ 296 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 297 ATTR_TYPE_INT, ANVIL_ATTR_RATE, newtls, 298 ATTR_TYPE_END) != 2) 299 status = ANVIL_STAT_FAIL; 300 else if (status != ANVIL_STAT_OK) 301 status = ANVIL_STAT_FAIL; 302 myfree(ident); 303 return (status); 304} 305 306/* anvil_clnt_newtls_stat - status query */ 307 308int anvil_clnt_newtls_stat(ANVIL_CLNT *anvil_clnt, const char *service, 309 const char *addr, int *newtls) 310{ 311 char *ident = ANVIL_IDENT(service, addr); 312 int status; 313 314 if (attr_clnt_request((ATTR_CLNT *) anvil_clnt, 315 ATTR_FLAG_NONE, /* Query attributes. */ 316 ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_NTLS_STAT, 317 ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, 318 ATTR_TYPE_END, 319 ATTR_FLAG_MISSING, /* Reply attributes. */ 320 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 321 ATTR_TYPE_INT, ANVIL_ATTR_RATE, newtls, 322 ATTR_TYPE_END) != 2) 323 status = ANVIL_STAT_FAIL; 324 else if (status != ANVIL_STAT_OK) 325 status = ANVIL_STAT_FAIL; 326 myfree(ident); 327 return (status); 328} 329 330/* anvil_clnt_disconnect - heads-up only */ 331 332int anvil_clnt_disconnect(ANVIL_CLNT *anvil_clnt, const char *service, 333 const char *addr) 334{ 335 char *ident = ANVIL_IDENT(service, addr); 336 int status; 337 338 if (attr_clnt_request((ATTR_CLNT *) anvil_clnt, 339 ATTR_FLAG_NONE, /* Query attributes. */ 340 ATTR_TYPE_STR, ANVIL_ATTR_REQ, ANVIL_REQ_DISC, 341 ATTR_TYPE_STR, ANVIL_ATTR_IDENT, ident, 342 ATTR_TYPE_END, 343 ATTR_FLAG_MISSING, /* Reply attributes. */ 344 ATTR_TYPE_INT, ANVIL_ATTR_STATUS, &status, 345 ATTR_TYPE_END) != 1) 346 status = ANVIL_STAT_FAIL; 347 else if (status != ANVIL_STAT_OK) 348 status = ANVIL_STAT_FAIL; 349 myfree(ident); 350 return (status); 351} 352 353#ifdef TEST 354 355 /* 356 * Stand-alone client for testing. 357 */ 358#include <unistd.h> 359#include <string.h> 360#include <msg_vstream.h> 361#include <mail_conf.h> 362#include <mail_params.h> 363#include <vstring_vstream.h> 364 365static void usage(void) 366{ 367 vstream_printf("usage: " 368 ANVIL_REQ_CONN " service addr | " 369 ANVIL_REQ_DISC " service addr | " 370 ANVIL_REQ_MAIL " service addr | " 371 ANVIL_REQ_RCPT " service addr | " 372 ANVIL_REQ_NTLS " service addr | " 373 ANVIL_REQ_NTLS_STAT " service addr | " 374 ANVIL_REQ_LOOKUP " service addr\n"); 375} 376 377int main(int unused_argc, char **argv) 378{ 379 VSTRING *inbuf = vstring_alloc(1); 380 char *bufp; 381 char *cmd; 382 ssize_t cmd_len; 383 char *service; 384 char *addr; 385 int count; 386 int rate; 387 int msgs; 388 int rcpts; 389 int newtls; 390 ANVIL_CLNT *anvil; 391 392 msg_vstream_init(argv[0], VSTREAM_ERR); 393 394 mail_conf_read(); 395 msg_info("using config files in %s", var_config_dir); 396 if (chdir(var_queue_dir) < 0) 397 msg_fatal("chdir %s: %m", var_queue_dir); 398 399 msg_verbose++; 400 401 anvil = anvil_clnt_create(); 402 403 while (vstring_fgets_nonl(inbuf, VSTREAM_IN)) { 404 bufp = vstring_str(inbuf); 405 if ((cmd = mystrtok(&bufp, " ")) == 0 || *bufp == 0 406 || (service = mystrtok(&bufp, " ")) == 0 || *service == 0 407 || (addr = mystrtok(&bufp, " ")) == 0 || *addr == 0 408 || mystrtok(&bufp, " ") != 0) { 409 vstream_printf("bad command syntax\n"); 410 usage(); 411 vstream_fflush(VSTREAM_OUT); 412 continue; 413 } 414 cmd_len = strlen(cmd); 415 if (strncmp(cmd, ANVIL_REQ_CONN, cmd_len) == 0) { 416 if (anvil_clnt_connect(anvil, service, addr, &count, &rate) != ANVIL_STAT_OK) 417 msg_warn("error!"); 418 else 419 vstream_printf("count=%d, rate=%d\n", count, rate); 420 } else if (strncmp(cmd, ANVIL_REQ_MAIL, cmd_len) == 0) { 421 if (anvil_clnt_mail(anvil, service, addr, &msgs) != ANVIL_STAT_OK) 422 msg_warn("error!"); 423 else 424 vstream_printf("rate=%d\n", msgs); 425 } else if (strncmp(cmd, ANVIL_REQ_RCPT, cmd_len) == 0) { 426 if (anvil_clnt_rcpt(anvil, service, addr, &rcpts) != ANVIL_STAT_OK) 427 msg_warn("error!"); 428 else 429 vstream_printf("rate=%d\n", rcpts); 430 } else if (strncmp(cmd, ANVIL_REQ_NTLS, cmd_len) == 0) { 431 if (anvil_clnt_newtls(anvil, service, addr, &newtls) != ANVIL_STAT_OK) 432 msg_warn("error!"); 433 else 434 vstream_printf("rate=%d\n", newtls); 435 } else if (strncmp(cmd, ANVIL_REQ_NTLS_STAT, cmd_len) == 0) { 436 if (anvil_clnt_newtls_stat(anvil, service, addr, &newtls) != ANVIL_STAT_OK) 437 msg_warn("error!"); 438 else 439 vstream_printf("rate=%d\n", newtls); 440 } else if (strncmp(cmd, ANVIL_REQ_DISC, cmd_len) == 0) { 441 if (anvil_clnt_disconnect(anvil, service, addr) != ANVIL_STAT_OK) 442 msg_warn("error!"); 443 else 444 vstream_printf("OK\n"); 445 } else if (strncmp(cmd, ANVIL_REQ_LOOKUP, cmd_len) == 0) { 446 if (anvil_clnt_lookup(anvil, service, addr, &count, &rate, 447 &msgs, &rcpts, &newtls) != ANVIL_STAT_OK) 448 msg_warn("error!"); 449 else 450 vstream_printf("count=%d, rate=%d msgs=%d rcpts=%d newtls=%d\n", 451 count, rate, msgs, rcpts, newtls); 452 } else { 453 vstream_printf("bad command: \"%s\"\n", cmd); 454 usage(); 455 } 456 vstream_fflush(VSTREAM_OUT); 457 } 458 vstring_free(inbuf); 459 anvil_clnt_free(anvil); 460 return (0); 461} 462 463#endif 464