273 #include <sys/time.h>
307 static HTABLE *anvil_remote_map;
342 #define ANVIL_REMOTE_FIRST_CONN(remote, id) \
344 (remote)->ident = mystrdup(id); \
345 (remote)->count = 1; \
346 (remote)->rate = 1; \
347 (remote)->mail = 0; \
348 (remote)->rcpt = 0; \
349 (remote)->ntls = 0; \
350 (remote)->auth = 0; \
351 (remote)->start = event_time(); \
356 #define ANVIL_REMOTE_FREE(remote) \
358 myfree((remote)->ident); \
359 myfree((void *) (remote)); \
364 #define ANVIL_REMOTE_RSET_RATE(remote, _start) \
366 (remote)->rate = 0; \
367 (remote)->mail = 0; \
368 (remote)->rcpt = 0; \
369 (remote)->ntls = 0; \
370 (remote)->auth = 0; \
371 (remote)->start = _start; \
374 #define ANVIL_REMOTE_INCR_RATE(remote, _what) \
376 time_t _now = event_time(); \
377 if ((remote)->start + var_anvil_time_unit < _now) \
378 ANVIL_REMOTE_RSET_RATE((remote), _now); \
379 if ((remote)->_what < INT_MAX) \
380 (remote)->_what += 1; \
385 #define ANVIL_REMOTE_NEXT_CONN(remote) \
387 ANVIL_REMOTE_INCR_RATE((remote), rate); \
388 if ((remote)->count == 0) \
389 event_cancel_timer(anvil_remote_expire, (void *) remote); \
393 #define ANVIL_REMOTE_INCR_MAIL(remote) ANVIL_REMOTE_INCR_RATE((remote), mail)
395 #define ANVIL_REMOTE_INCR_RCPT(remote) ANVIL_REMOTE_INCR_RATE((remote), rcpt)
397 #define ANVIL_REMOTE_INCR_NTLS(remote) ANVIL_REMOTE_INCR_RATE((remote), ntls)
399 #define ANVIL_REMOTE_INCR_AUTH(remote) ANVIL_REMOTE_INCR_RATE((remote), auth)
403 #define ANVIL_REMOTE_DROP_ONE(remote) \
405 if ((remote) && (remote)->count > 0) { \
406 if (--(remote)->count == 0) \
407 event_request_timer(anvil_remote_expire, (void *) remote, \
408 var_anvil_time_unit); \
414 #define ANVIL_LOCAL_INIT(local) \
416 (local)->anvil_remote = 0; \
421 #define ANVIL_LOCAL_ADD_ONE(local, remote) \
424 if ((local)->anvil_remote) \
425 ANVIL_REMOTE_DROP_ONE((local)->anvil_remote); \
426 (local)->anvil_remote = (remote); \
431 #define ANVIL_LOCAL_REMOTE_LINKED(local, remote) \
432 ((local)->anvil_remote == (remote))
436 #define ANVIL_LOCAL_DROP_ONE(local, remote) \
439 if ((local)->anvil_remote == (remote)) \
440 (local)->anvil_remote = 0; \
445 #define ANVIL_LOCAL_DROP_ALL(stream, local) \
448 if ((local)->anvil_remote) \
449 anvil_remote_disconnect((stream), (local)->anvil_remote->ident); \
479 static int max_cache_size;
480 static time_t max_cache_time;
484 #define ANVIL_MAX_UPDATE(_max, _value, _ident) \
486 _max.value = _value; \
487 if (_max.ident == 0) { \
488 _max.ident = mystrdup(_ident); \
489 } else if (!STREQ(_max.ident, _ident)) { \
490 myfree(_max.ident); \
491 _max.ident = mystrdup(_ident); \
493 _max.when = event_time(); \
496 #define ANVIL_MAX_RATE_REPORT(_max, _name) \
498 if (_max.value > 0) { \
499 msg_info("statistics: max " _name " rate %d/%ds for (%s) at %.15s", \
500 _max.value, var_anvil_time_unit, \
501 _max.ident, ctime(&_max.when) + 4); \
506 #define ANVIL_MAX_COUNT_REPORT(_max, _name) \
508 if (_max.value > 0) { \
509 msg_info("statistics: max " _name " count %d for (%s) at %.15s", \
510 _max.value, _max.ident, ctime(&_max.when) + 4); \
518 #define STR(x) vstring_str(x)
519 #define STREQ(x,y) (strcmp((x), (y)) == 0)
523 static void anvil_remote_expire(
int unused_event,
void *context)
526 const char *myname =
"anvil_remote_expire";
531 if (anvil_remote->
count != 0)
532 msg_panic(
"%s: bad connection count: %d",
533 myname, anvil_remote->
count);
536 (void (*) (
void *)) 0);
540 msg_info(
"%s: anvil_remote_map used=%ld",
541 myname, (
long) anvil_remote_map->
used);
546 static void anvil_remote_lookup(
VSTREAM *client_stream,
const char *ident)
549 const char *myname =
"anvil_remote_lookup";
552 msg_info(
"%s fd=%d stream=0x%lx ident=%s",
554 (
unsigned long) client_stream, ident);
575 if (anvil_remote->
start != 0
596 const char *myname =
"anvil_remote_conn_update";
599 msg_info(
"%s fd=%d stream=0x%lx ident=%s",
601 (
unsigned long) client_stream, ident);
613 htable_enter(anvil_remote_map, ident, (
void *) anvil_remote);
614 if (max_cache_size < anvil_remote_map->used) {
615 max_cache_size = anvil_remote_map->
used;
636 myname, (
unsigned long) anvil_local);
638 return (anvil_remote);
643 static void anvil_remote_connect(
VSTREAM *client_stream,
const char *ident)
650 anvil_remote = anvil_remote_conn_update(client_stream, ident);
664 if (anvil_remote->
rate > max_conn_rate.
value)
666 if (anvil_remote->
count > max_conn_count.
value)
672 static void anvil_remote_mail(
VSTREAM *client_stream,
const char *ident)
681 anvil_remote = anvil_remote_conn_update(client_stream, ident);
695 if (anvil_remote->
mail > max_mail_rate.
value)
701 static void anvil_remote_rcpt(
VSTREAM *client_stream,
const char *ident)
710 anvil_remote = anvil_remote_conn_update(client_stream, ident);
724 if (anvil_remote->
rcpt > max_rcpt_rate.
value)
730 static void anvil_remote_auth(
VSTREAM *client_stream,
const char *ident)
739 anvil_remote = anvil_remote_conn_update(client_stream, ident);
753 if (anvil_remote->
auth > max_auth_rate.
value)
759 static void anvil_remote_newtls(
VSTREAM *client_stream,
const char *ident)
768 anvil_remote = anvil_remote_conn_update(client_stream, ident);
782 if (anvil_remote->
ntls > max_ntls_rate.
value)
788 static void anvil_remote_newtls_stat(
VSTREAM *client_stream,
const char *ident)
805 if (anvil_remote->
start != 0
808 rate = anvil_remote->
ntls;
822 static void anvil_remote_disconnect(
VSTREAM *client_stream,
const char *ident)
826 const char *myname =
"anvil_remote_disconnect";
829 msg_info(
"%s fd=%d stream=0x%lx ident=%s",
831 (
unsigned long) client_stream, ident);
846 myname, (
unsigned long) anvil_local);
858 static void anvil_service_done(
VSTREAM *client_stream,
char *unused_service,
862 const char *myname =
"anvil_service_done";
867 (
unsigned long) client_stream);
877 myname, (
unsigned long) anvil_local);
879 myfree((
void *) anvil_local);
881 msg_info(
"client socket not found for fd=%d",
887 static void anvil_status_dump(
char *unused_name,
char **unused_argv)
896 if (max_cache_size > 0) {
897 msg_info(
"statistics: max cache size %d at %.15s",
898 max_cache_size, ctime(&max_cache_time) + 4);
905 static void anvil_status_update(
int unused_event,
void *context)
907 anvil_status_dump((
char *) 0, (
char **) 0);
913 static void anvil_service(
VSTREAM *client_stream,
char *unused_service,
char **argv)
934 msg_fatal(
"unexpected command-line argument: %s", argv[0]);
957 for (rp = request_table; ; rp++) {
959 msg_warn(
"unrecognized request: \"%s\", ignored",
STR(request));
981 static void post_jail_init(
char *unused_name,
char **unused_argv)
#define ANVIL_REMOTE_DROP_ONE(remote)
#define ANVIL_REMOTE_FREE(remote)
#define ANVIL_LOCAL_INIT(local)
#define ANVIL_MAX_COUNT_REPORT(_max, _name)
#define ANVIL_REMOTE_INCR_AUTH(remote)
#define ANVIL_REMOTE_FIRST_CONN(remote, id)
NORETURN msg_panic(const char *fmt,...)
#define ATTR_FLAG_MISSING
int main(int argc, char **argv)
#define CA_MAIL_SERVER_EXIT(v)
#define CA_VSTREAM_CTL_CONTEXT(v)
void multi_server_disconnect(VSTREAM *)
#define VAR_ANVIL_STAT_TIME
#define ANVIL_MAX_UPDATE(_max, _value, _ident)
NORETURN multi_server_main(int, char **, MULTI_SERVER_FN,...)
#define vstream_context(vp)
HTABLE * htable_create(ssize_t size)
#define CA_MAIL_SERVER_POST_INIT(v)
#define ANVIL_LOCAL_REMOTE_LINKED(local, remote)
#define CA_MAIL_SERVER_PRE_DISCONN(v)
#define DEF_ANVIL_STAT_TIME
#define VAR_ANVIL_TIME_UNIT
#define ANVIL_LOCAL_DROP_ONE(local, remote)
void msg_warn(const char *fmt,...)
VSTRING * vstring_alloc(ssize_t len)
#define MAIL_VERSION_STAMP_ALLOCATE
void * htable_find(HTABLE *table, const char *key)
void(* action)(VSTREAM *, const char *)
int attr_print_plain(VSTREAM *, int,...)
#define CA_MAIL_SERVER_TIME_TABLE(v)
#define ANVIL_LOCAL_ADD_ONE(local, remote)
#define SEND_ATTR_INT(name, val)
#define ANVIL_MAX_RATE_REPORT(_max, _name)
#define ANVIL_REMOTE_INCR_NTLS(remote)
MAIL_VERSION_STAMP_DECLARE
NORETURN msg_fatal(const char *fmt,...)
#define ANVIL_ATTR_STATUS
#define ANVIL_REMOTE_INCR_RCPT(remote)
int vstream_fflush(VSTREAM *stream)
#define ANVIL_REMOTE_NEXT_CONN(remote)
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
#define ANVIL_LOCAL_DROP_ALL(stream, local)
#define CA_MAIL_SERVER_SOLITARY
#define vstream_fileno(vp)
ANVIL_REMOTE * anvil_remote
#define CA_VSTREAM_CTL_END
int WARN_UNUSED_RESULT attr_scan_plain(VSTREAM *, int,...)
void vstream_control(VSTREAM *stream, int name,...)
#define DEF_ANVIL_TIME_UNIT
void htable_delete(HTABLE *table, const char *key, void(*free_fn)(void *))
#define ANVIL_REMOTE_RSET_RATE(remote, _start)
#define ANVIL_REQ_NTLS_STAT
#define ANVIL_REMOTE_INCR_MAIL(remote)
#define RECV_ATTR_STR(name, val)
void * mymalloc(ssize_t len)
HTABLE_INFO * htable_enter(HTABLE *table, const char *key, void *value)
void msg_info(const char *fmt,...)