From cee013e4e018493003efc4fac3efcd4b22fa59ba Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 5 Jun 2020 11:40:38 +0200 Subject: [PATCH] REORG: check: move the e-mail alerting code to mailers.c check.c is one of the largest file and contains too many things. The e-mail alerting code is stored there while nothing is in mailers.c. Let's move this code out. That's only 4% of the code but a good start. In order to do so, a few tcp-check functions had to be exported. --- include/haproxy/check.h | 57 +++---- include/haproxy/mailers.h | 7 + src/cfgparse.c | 2 +- src/check.c | 321 ++------------------------------------ src/mailers.c | 306 +++++++++++++++++++++++++++++++++++- src/server.c | 1 + 6 files changed, 360 insertions(+), 334 deletions(-) diff --git a/include/haproxy/check.h b/include/haproxy/check.h index 66023ce59..637909cb5 100644 --- a/include/haproxy/check.h +++ b/include/haproxy/check.h @@ -25,44 +25,26 @@ #include #include #include -#include #include #include +extern struct action_kw_list tcp_check_keywords; +extern struct pool_head *pool_head_tcpcheck_rule; + const char *get_check_status_description(short check_status); const char *get_check_status_info(short check_status); void __health_adjust(struct server *s, short status); +struct task *process_chk(struct task *t, void *context, unsigned short state); -/* Use this one only. This inline version only ensures that we don't - * call the function when the observe mode is disabled. - */ -static inline void health_adjust(struct server *s, short status) -{ - HA_SPIN_LOCK(SERVER_LOCK, &s->lock); - /* return now if observing nor health check is not enabled */ - if (!s->observe || !s->check.task) { - HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock); - return; - } - - __health_adjust(s, status); - HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock); -} - +const char *init_check(struct check *check, int type); void free_check(struct check *check); - -int init_email_alert(struct mailers *mailers, struct proxy *p, char **err); -void send_email_alert(struct server *s, int priority, const char *format, ...) - __attribute__ ((format(printf, 3, 4))); - -extern struct action_kw_list tcp_check_keywords; -static inline void tcp_check_keywords_register(struct action_kw_list *kw_list) -{ - LIST_ADDQ(&tcp_check_keywords.list, &kw_list->list); -} +void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool); void deinit_proxy_tcpcheck(struct proxy *px); int dup_tcpcheck_vars(struct list *dst, struct list *src); +void free_tcpcheck_vars(struct list *vars); +int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str); +int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * const *strs); /* Declared here, but the definitions are in flt_spoe.c */ int spoe_prepare_healthcheck_request(char **req, int *len); @@ -91,6 +73,27 @@ int proxy_parse_external_check_opt(char **args, int cur_arg, struct proxy *curpx int set_srv_agent_send(struct server *srv, const char *send); +/* Use this one only. This inline version only ensures that we don't + * call the function when the observe mode is disabled. + */ +static inline void health_adjust(struct server *s, short status) +{ + HA_SPIN_LOCK(SERVER_LOCK, &s->lock); + /* return now if observing nor health check is not enabled */ + if (!s->observe || !s->check.task) { + HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock); + return; + } + + __health_adjust(s, status); + HA_SPIN_UNLOCK(SERVER_LOCK, &s->lock); +} + +static inline void tcp_check_keywords_register(struct action_kw_list *kw_list) +{ + LIST_ADDQ(&tcp_check_keywords.list, &kw_list->list); +} + #endif /* _HAPROXY_CHECKS_H */ /* diff --git a/include/haproxy/mailers.h b/include/haproxy/mailers.h index 5daad862f..43db167b6 100644 --- a/include/haproxy/mailers.h +++ b/include/haproxy/mailers.h @@ -28,7 +28,14 @@ #define _HAPROXY_MAILERS_H #include +#include +#include extern struct mailers *mailers; +int init_email_alert(struct mailers *mailers, struct proxy *p, char **err); +void send_email_alert(struct server *s, int priority, const char *format, ...) + __attribute__ ((format(printf, 3, 4))); + + #endif /* _HAPROXY_MAILERS_H */ diff --git a/src/cfgparse.c b/src/cfgparse.c index 0bb4f2bbc..fa8540187 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/check.c b/src/check.c index f8df0e9f0..fa608c9df 100644 --- a/src/check.c +++ b/src/check.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -79,8 +80,7 @@ struct data_cb check_conn_cb = { struct eb_root shared_tcpchecks = EB_ROOT; -DECLARE_STATIC_POOL(pool_head_email_alert, "email_alert", sizeof(struct email_alert)); -DECLARE_STATIC_POOL(pool_head_tcpcheck_rule, "tcpcheck_rule", sizeof(struct tcpcheck_rule)); +DECLARE_POOL(pool_head_tcpcheck_rule, "tcpcheck_rule", sizeof(struct tcpcheck_rule)); /* Dummy frontend used to create all checks sessions. */ static struct proxy checks_fe; @@ -751,7 +751,7 @@ static void free_tcpcheck_http_hdrs(struct list *hdrs) * tcp-check was allocated using a memory pool (it is used to instantiate email * alerts). */ -static void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool) +void free_tcpcheck(struct tcpcheck_rule *rule, int in_pool) { if (!rule) return; @@ -883,7 +883,7 @@ static void free_tcpcheck_var(struct tcpcheck_var *var) } /* Releases a list of preset tcp-check variables */ -static void free_tcpcheck_vars(struct list *vars) +void free_tcpcheck_vars(struct list *vars) { struct tcpcheck_var *var, *back; @@ -4939,7 +4939,7 @@ static int tcpcheck_add_http_rule(struct tcpcheck_rule *chk, struct tcpcheck_rul /**************************************************************************/ /************************** Init/deinit checks ****************************/ /**************************************************************************/ -static const char *init_check(struct check *check, int type) +const char *init_check(struct check *check, int type) { check->type = type; @@ -4980,7 +4980,7 @@ void free_check(struct check *check) /* manages a server health-check. Returns the time the task accepts to wait, or * TIME_ETERNITY for infinity. */ -static struct task *process_chk(struct task *t, void *context, unsigned short state) +struct task *process_chk(struct task *t, void *context, unsigned short state) { struct check *check = context; @@ -5531,153 +5531,7 @@ static void deinit_tcpchecks() } } - -REGISTER_POST_SERVER_CHECK(init_srv_check); -REGISTER_POST_SERVER_CHECK(init_srv_agent_check); -REGISTER_POST_PROXY_CHECK(check_proxy_tcpcheck); -REGISTER_POST_CHECK(start_checks); - -REGISTER_SERVER_DEINIT(deinit_srv_check); -REGISTER_SERVER_DEINIT(deinit_srv_agent_check); -REGISTER_PROXY_DEINIT(deinit_proxy_tcpcheck); -REGISTER_POST_DEINIT(deinit_tcpchecks); - -/**************************************************************************/ -/****************************** Email alerts ******************************/ -/* NOTE: It may be pertinent to use an applet to handle email alerts */ -/* instead of a tcp-check ruleset */ -/**************************************************************************/ -void email_alert_free(struct email_alert *alert) -{ - struct tcpcheck_rule *rule, *back; - - if (!alert) - return; - - if (alert->rules.list) { - list_for_each_entry_safe(rule, back, alert->rules.list, list) { - LIST_DEL(&rule->list); - free_tcpcheck(rule, 1); - } - free_tcpcheck_vars(&alert->rules.preset_vars); - free(alert->rules.list); - alert->rules.list = NULL; - } - pool_free(pool_head_email_alert, alert); -} - -static struct task *process_email_alert(struct task *t, void *context, unsigned short state) -{ - struct check *check = context; - struct email_alertq *q; - struct email_alert *alert; - - q = container_of(check, typeof(*q), check); - - HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock); - while (1) { - if (!(check->state & CHK_ST_ENABLED)) { - if (LIST_ISEMPTY(&q->email_alerts)) { - /* All alerts processed, queue the task */ - t->expire = TICK_ETERNITY; - task_queue(t); - goto end; - } - - alert = LIST_NEXT(&q->email_alerts, typeof(alert), list); - LIST_DEL(&alert->list); - t->expire = now_ms; - check->tcpcheck_rules = &alert->rules; - check->status = HCHK_STATUS_INI; - check->state |= CHK_ST_ENABLED; - } - - process_chk(t, context, state); - if (check->state & CHK_ST_INPROGRESS) - break; - - alert = container_of(check->tcpcheck_rules, typeof(*alert), rules); - email_alert_free(alert); - check->tcpcheck_rules = NULL; - check->server = NULL; - check->state &= ~CHK_ST_ENABLED; - } - end: - HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock); - return t; -} - -/* Initializes mailer alerts for the proxy

using parameters. - * - * The function returns 1 in success case, otherwise, it returns 0 and err is - * filled. - */ -int init_email_alert(struct mailers *mls, struct proxy *p, char **err) -{ - struct mailer *mailer; - struct email_alertq *queues; - const char *err_str; - int i = 0; - - if ((queues = calloc(mls->count, sizeof(*queues))) == NULL) { - memprintf(err, "out of memory while allocating mailer alerts queues"); - goto fail_no_queue; - } - - for (mailer = mls->mailer_list; mailer; i++, mailer = mailer->next) { - struct email_alertq *q = &queues[i]; - struct check *check = &q->check; - struct task *t; - - LIST_INIT(&q->email_alerts); - HA_SPIN_INIT(&q->lock); - check->inter = mls->timeout.mail; - check->rise = DEF_AGENT_RISETIME; - check->proxy = p; - check->fall = DEF_AGENT_FALLTIME; - if ((err_str = init_check(check, PR_O2_TCPCHK_CHK))) { - memprintf(err, "%s", err_str); - goto error; - } - - check->xprt = mailer->xprt; - check->addr = mailer->addr; - check->port = get_host_port(&mailer->addr); - - if ((t = task_new(MAX_THREADS_MASK)) == NULL) { - memprintf(err, "out of memory while allocating mailer alerts task"); - goto error; - } - - check->task = t; - t->process = process_email_alert; - t->context = check; - - /* check this in one ms */ - t->expire = TICK_ETERNITY; - check->start = now; - task_queue(t); - } - - mls->users++; - free(p->email_alert.mailers.name); - p->email_alert.mailers.m = mls; - p->email_alert.queues = queues; - return 0; - - error: - for (i = 0; i < mls->count; i++) { - struct email_alertq *q = &queues[i]; - struct check *check = &q->check; - - free_check(check); - } - free(queues); - fail_no_queue: - return 1; -} - -static int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str) +int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str) { struct tcpcheck_rule *tcpcheck, *prev_check; struct tcpcheck_expect *expect; @@ -5717,7 +5571,7 @@ static int add_tcpcheck_expect_str(struct tcpcheck_rules *rules, const char *str return 1; } -static int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * const *strs) +int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * const *strs) { struct tcpcheck_rule *tcpcheck; struct tcpcheck_send *send; @@ -5751,159 +5605,16 @@ static int add_tcpcheck_send_strs(struct tcpcheck_rules *rules, const char * con return 1; } -static int enqueue_one_email_alert(struct proxy *p, struct server *s, - struct email_alertq *q, const char *msg) -{ - struct email_alert *alert; - struct tcpcheck_rule *tcpcheck; - struct check *check = &q->check; +REGISTER_POST_SERVER_CHECK(init_srv_check); +REGISTER_POST_SERVER_CHECK(init_srv_agent_check); +REGISTER_POST_PROXY_CHECK(check_proxy_tcpcheck); +REGISTER_POST_CHECK(start_checks); - if ((alert = pool_alloc(pool_head_email_alert)) == NULL) - goto error; - LIST_INIT(&alert->list); - alert->rules.flags = TCPCHK_RULES_TCP_CHK; - alert->rules.list = calloc(1, sizeof(*alert->rules.list)); - if (!alert->rules.list) - goto error; - LIST_INIT(alert->rules.list); - LIST_INIT(&alert->rules.preset_vars); /* unused for email alerts */ - alert->srv = s; +REGISTER_SERVER_DEINIT(deinit_srv_check); +REGISTER_SERVER_DEINIT(deinit_srv_agent_check); +REGISTER_PROXY_DEINIT(deinit_proxy_tcpcheck); +REGISTER_POST_DEINIT(deinit_tcpchecks); - if ((tcpcheck = pool_alloc(pool_head_tcpcheck_rule)) == NULL) - goto error; - memset(tcpcheck, 0, sizeof(*tcpcheck)); - tcpcheck->action = TCPCHK_ACT_CONNECT; - tcpcheck->comment = NULL; - - LIST_ADDQ(alert->rules.list, &tcpcheck->list); - - if (!add_tcpcheck_expect_str(&alert->rules, "220 ")) - goto error; - - { - const char * const strs[4] = { "EHLO ", p->email_alert.myhostname, "\r\n" }; - if (!add_tcpcheck_send_strs(&alert->rules, strs)) - goto error; - } - - if (!add_tcpcheck_expect_str(&alert->rules, "250 ")) - goto error; - - { - const char * const strs[4] = { "MAIL FROM:<", p->email_alert.from, ">\r\n" }; - if (!add_tcpcheck_send_strs(&alert->rules, strs)) - goto error; - } - - if (!add_tcpcheck_expect_str(&alert->rules, "250 ")) - goto error; - - { - const char * const strs[4] = { "RCPT TO:<", p->email_alert.to, ">\r\n" }; - if (!add_tcpcheck_send_strs(&alert->rules, strs)) - goto error; - } - - if (!add_tcpcheck_expect_str(&alert->rules, "250 ")) - goto error; - - { - const char * const strs[2] = { "DATA\r\n" }; - if (!add_tcpcheck_send_strs(&alert->rules, strs)) - goto error; - } - - if (!add_tcpcheck_expect_str(&alert->rules, "354 ")) - goto error; - - { - struct tm tm; - char datestr[48]; - const char * const strs[18] = { - "From: ", p->email_alert.from, "\r\n", - "To: ", p->email_alert.to, "\r\n", - "Date: ", datestr, "\r\n", - "Subject: [HAproxy Alert] ", msg, "\r\n", - "\r\n", - msg, "\r\n", - "\r\n", - ".\r\n", - NULL - }; - - get_localtime(date.tv_sec, &tm); - - if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %T %z (%Z)", &tm) == 0) { - goto error; - } - - if (!add_tcpcheck_send_strs(&alert->rules, strs)) - goto error; - } - - if (!add_tcpcheck_expect_str(&alert->rules, "250 ")) - goto error; - - { - const char * const strs[2] = { "QUIT\r\n" }; - if (!add_tcpcheck_send_strs(&alert->rules, strs)) - goto error; - } - - if (!add_tcpcheck_expect_str(&alert->rules, "221 ")) - goto error; - - HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock); - task_wakeup(check->task, TASK_WOKEN_MSG); - LIST_ADDQ(&q->email_alerts, &alert->list); - HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock); - return 1; - -error: - email_alert_free(alert); - return 0; -} - -static void enqueue_email_alert(struct proxy *p, struct server *s, const char *msg) -{ - int i; - struct mailer *mailer; - - for (i = 0, mailer = p->email_alert.mailers.m->mailer_list; - i < p->email_alert.mailers.m->count; i++, mailer = mailer->next) { - if (!enqueue_one_email_alert(p, s, &p->email_alert.queues[i], msg)) { - ha_alert("Email alert [%s] could not be enqueued: out of memory\n", p->id); - return; - } - } - - return; -} - -/* - * Send email alert if configured. - */ -void send_email_alert(struct server *s, int level, const char *format, ...) -{ - va_list argp; - char buf[1024]; - int len; - struct proxy *p = s->proxy; - - if (!p->email_alert.mailers.m || level > p->email_alert.level || format == NULL) - return; - - va_start(argp, format); - len = vsnprintf(buf, sizeof(buf), format, argp); - va_end(argp); - - if (len < 0 || len >= sizeof(buf)) { - ha_alert("Email alert [%s] could not format message\n", p->id); - return; - } - - enqueue_email_alert(p, s, buf); -} /**************************************************************************/ /************************** Check sample fetches **************************/ diff --git a/src/mailers.c b/src/mailers.c index 601489481..39818ca0b 100644 --- a/src/mailers.c +++ b/src/mailers.c @@ -2,6 +2,7 @@ * Mailer management. * * Copyright 2015 Horms Solutions Ltd, Simon Horman + * Copyright 2020 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -12,6 +13,309 @@ #include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + struct mailers *mailers = NULL; + +DECLARE_STATIC_POOL(pool_head_email_alert, "email_alert", sizeof(struct email_alert)); + +/****************************** Email alerts ******************************/ +/* NOTE: It may be pertinent to use an applet to handle email alerts */ +/* instead of a tcp-check ruleset */ +/**************************************************************************/ +void email_alert_free(struct email_alert *alert) +{ + struct tcpcheck_rule *rule, *back; + + if (!alert) + return; + + if (alert->rules.list) { + list_for_each_entry_safe(rule, back, alert->rules.list, list) { + LIST_DEL(&rule->list); + free_tcpcheck(rule, 1); + } + free_tcpcheck_vars(&alert->rules.preset_vars); + free(alert->rules.list); + alert->rules.list = NULL; + } + pool_free(pool_head_email_alert, alert); +} + +static struct task *process_email_alert(struct task *t, void *context, unsigned short state) +{ + struct check *check = context; + struct email_alertq *q; + struct email_alert *alert; + + q = container_of(check, typeof(*q), check); + + HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock); + while (1) { + if (!(check->state & CHK_ST_ENABLED)) { + if (LIST_ISEMPTY(&q->email_alerts)) { + /* All alerts processed, queue the task */ + t->expire = TICK_ETERNITY; + task_queue(t); + goto end; + } + + alert = LIST_NEXT(&q->email_alerts, typeof(alert), list); + LIST_DEL(&alert->list); + t->expire = now_ms; + check->tcpcheck_rules = &alert->rules; + check->status = HCHK_STATUS_INI; + check->state |= CHK_ST_ENABLED; + } + + process_chk(t, context, state); + if (check->state & CHK_ST_INPROGRESS) + break; + + alert = container_of(check->tcpcheck_rules, typeof(*alert), rules); + email_alert_free(alert); + check->tcpcheck_rules = NULL; + check->server = NULL; + check->state &= ~CHK_ST_ENABLED; + } + end: + HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock); + return t; +} + +/* Initializes mailer alerts for the proxy

using parameters. + * + * The function returns 1 in success case, otherwise, it returns 0 and err is + * filled. + */ +int init_email_alert(struct mailers *mls, struct proxy *p, char **err) +{ + struct mailer *mailer; + struct email_alertq *queues; + const char *err_str; + int i = 0; + + if ((queues = calloc(mls->count, sizeof(*queues))) == NULL) { + memprintf(err, "out of memory while allocating mailer alerts queues"); + goto fail_no_queue; + } + + for (mailer = mls->mailer_list; mailer; i++, mailer = mailer->next) { + struct email_alertq *q = &queues[i]; + struct check *check = &q->check; + struct task *t; + + LIST_INIT(&q->email_alerts); + HA_SPIN_INIT(&q->lock); + check->inter = mls->timeout.mail; + check->rise = DEF_AGENT_RISETIME; + check->proxy = p; + check->fall = DEF_AGENT_FALLTIME; + if ((err_str = init_check(check, PR_O2_TCPCHK_CHK))) { + memprintf(err, "%s", err_str); + goto error; + } + + check->xprt = mailer->xprt; + check->addr = mailer->addr; + check->port = get_host_port(&mailer->addr); + + if ((t = task_new(MAX_THREADS_MASK)) == NULL) { + memprintf(err, "out of memory while allocating mailer alerts task"); + goto error; + } + + check->task = t; + t->process = process_email_alert; + t->context = check; + + /* check this in one ms */ + t->expire = TICK_ETERNITY; + check->start = now; + task_queue(t); + } + + mls->users++; + free(p->email_alert.mailers.name); + p->email_alert.mailers.m = mls; + p->email_alert.queues = queues; + return 0; + + error: + for (i = 0; i < mls->count; i++) { + struct email_alertq *q = &queues[i]; + struct check *check = &q->check; + + free_check(check); + } + free(queues); + fail_no_queue: + return 1; +} + +static int enqueue_one_email_alert(struct proxy *p, struct server *s, + struct email_alertq *q, const char *msg) +{ + struct email_alert *alert; + struct tcpcheck_rule *tcpcheck; + struct check *check = &q->check; + + if ((alert = pool_alloc(pool_head_email_alert)) == NULL) + goto error; + LIST_INIT(&alert->list); + alert->rules.flags = TCPCHK_RULES_TCP_CHK; + alert->rules.list = calloc(1, sizeof(*alert->rules.list)); + if (!alert->rules.list) + goto error; + LIST_INIT(alert->rules.list); + LIST_INIT(&alert->rules.preset_vars); /* unused for email alerts */ + alert->srv = s; + + if ((tcpcheck = pool_alloc(pool_head_tcpcheck_rule)) == NULL) + goto error; + memset(tcpcheck, 0, sizeof(*tcpcheck)); + tcpcheck->action = TCPCHK_ACT_CONNECT; + tcpcheck->comment = NULL; + + LIST_ADDQ(alert->rules.list, &tcpcheck->list); + + if (!add_tcpcheck_expect_str(&alert->rules, "220 ")) + goto error; + + { + const char * const strs[4] = { "EHLO ", p->email_alert.myhostname, "\r\n" }; + if (!add_tcpcheck_send_strs(&alert->rules, strs)) + goto error; + } + + if (!add_tcpcheck_expect_str(&alert->rules, "250 ")) + goto error; + + { + const char * const strs[4] = { "MAIL FROM:<", p->email_alert.from, ">\r\n" }; + if (!add_tcpcheck_send_strs(&alert->rules, strs)) + goto error; + } + + if (!add_tcpcheck_expect_str(&alert->rules, "250 ")) + goto error; + + { + const char * const strs[4] = { "RCPT TO:<", p->email_alert.to, ">\r\n" }; + if (!add_tcpcheck_send_strs(&alert->rules, strs)) + goto error; + } + + if (!add_tcpcheck_expect_str(&alert->rules, "250 ")) + goto error; + + { + const char * const strs[2] = { "DATA\r\n" }; + if (!add_tcpcheck_send_strs(&alert->rules, strs)) + goto error; + } + + if (!add_tcpcheck_expect_str(&alert->rules, "354 ")) + goto error; + + { + struct tm tm; + char datestr[48]; + const char * const strs[18] = { + "From: ", p->email_alert.from, "\r\n", + "To: ", p->email_alert.to, "\r\n", + "Date: ", datestr, "\r\n", + "Subject: [HAproxy Alert] ", msg, "\r\n", + "\r\n", + msg, "\r\n", + "\r\n", + ".\r\n", + NULL + }; + + get_localtime(date.tv_sec, &tm); + + if (strftime(datestr, sizeof(datestr), "%a, %d %b %Y %T %z (%Z)", &tm) == 0) { + goto error; + } + + if (!add_tcpcheck_send_strs(&alert->rules, strs)) + goto error; + } + + if (!add_tcpcheck_expect_str(&alert->rules, "250 ")) + goto error; + + { + const char * const strs[2] = { "QUIT\r\n" }; + if (!add_tcpcheck_send_strs(&alert->rules, strs)) + goto error; + } + + if (!add_tcpcheck_expect_str(&alert->rules, "221 ")) + goto error; + + HA_SPIN_LOCK(EMAIL_ALERTS_LOCK, &q->lock); + task_wakeup(check->task, TASK_WOKEN_MSG); + LIST_ADDQ(&q->email_alerts, &alert->list); + HA_SPIN_UNLOCK(EMAIL_ALERTS_LOCK, &q->lock); + return 1; + +error: + email_alert_free(alert); + return 0; +} + +static void enqueue_email_alert(struct proxy *p, struct server *s, const char *msg) +{ + int i; + struct mailer *mailer; + + for (i = 0, mailer = p->email_alert.mailers.m->mailer_list; + i < p->email_alert.mailers.m->count; i++, mailer = mailer->next) { + if (!enqueue_one_email_alert(p, s, &p->email_alert.queues[i], msg)) { + ha_alert("Email alert [%s] could not be enqueued: out of memory\n", p->id); + return; + } + } + + return; +} + +/* + * Send email alert if configured. + */ +void send_email_alert(struct server *s, int level, const char *format, ...) +{ + va_list argp; + char buf[1024]; + int len; + struct proxy *p = s->proxy; + + if (!p->email_alert.mailers.m || level > p->email_alert.level || format == NULL) + return; + + va_start(argp, format); + len = vsnprintf(buf, sizeof(buf), format, argp); + va_end(argp); + + if (len < 0 || len >= sizeof(buf)) { + ha_alert("Email alert [%s] could not format message\n", p->id); + return; + } + + enqueue_email_alert(p, s, buf); +} diff --git a/src/server.c b/src/server.c index 0d9b53303..b2c2853fc 100644 --- a/src/server.c +++ b/src/server.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include