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.
diff --git a/include/haproxy/check.h b/include/haproxy/check.h
index 66023ce..637909c 100644
--- a/include/haproxy/check.h
+++ b/include/haproxy/check.h
@@ -25,44 +25,26 @@
#include <haproxy/action-t.h>
#include <haproxy/check-t.h>
#include <haproxy/list-t.h>
-#include <haproxy/mailers.h>
#include <haproxy/proxy-t.h>
#include <haproxy/server-t.h>
+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 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 5daad86..43db167 100644
--- a/include/haproxy/mailers.h
+++ b/include/haproxy/mailers.h
@@ -28,7 +28,14 @@
#define _HAPROXY_MAILERS_H
#include <haproxy/mailers-t.h>
+#include <haproxy/proxy-t.h>
+#include <haproxy/server-t.h>
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 0bb4f2b..fa85401 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -57,7 +57,7 @@
#include <haproxy/lb_map.h>
#include <haproxy/listener.h>
#include <haproxy/log.h>
-#include <haproxy/mailers-t.h>
+#include <haproxy/mailers.h>
#include <haproxy/obj_type-t.h>
#include <haproxy/peers-t.h>
#include <haproxy/pool.h>
diff --git a/src/check.c b/src/check.c
index f8df0e9..fa608c9 100644
--- a/src/check.c
+++ b/src/check.c
@@ -38,6 +38,7 @@
#include <haproxy/dns.h>
#include <haproxy/istbuf.h>
#include <haproxy/list.h>
+#include <haproxy/mailers.h>
#include <haproxy/queue.h>
#include <haproxy/regex.h>
#include <haproxy/tools.h>
@@ -79,8 +80,7 @@
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 @@
* 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 @@
}
/* 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 @@
/**************************************************************************/
/************************** 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 @@
/* 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 @@
}
}
-
-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 <p> using <mls> 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 @@
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;
@@ -5749,161 +5603,18 @@
LIST_ADDQ(rules->list, &tcpcheck->list);
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);
+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 (len < 0 || len >= sizeof(buf)) {
- ha_alert("Email alert [%s] could not format message\n", p->id);
- return;
- }
+REGISTER_SERVER_DEINIT(deinit_srv_check);
+REGISTER_SERVER_DEINIT(deinit_srv_agent_check);
+REGISTER_PROXY_DEINIT(deinit_proxy_tcpcheck);
+REGISTER_POST_DEINIT(deinit_tcpchecks);
- enqueue_email_alert(p, s, buf);
-}
/**************************************************************************/
/************************** Check sample fetches **************************/
diff --git a/src/mailers.c b/src/mailers.c
index 6014894..39818ca 100644
--- a/src/mailers.c
+++ b/src/mailers.c
@@ -2,6 +2,7 @@
* Mailer management.
*
* Copyright 2015 Horms Solutions Ltd, Simon Horman <horms@verge.net.au>
+ * Copyright 2020 Willy Tarreau <w@1wt.eu>
*
* 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 <stdlib.h>
-#include <haproxy/mailers-t.h>
+#include <haproxy/action-t.h>
+#include <haproxy/api.h>
+#include <haproxy/check.h>
+#include <haproxy/list.h>
+#include <haproxy/mailers.h>
+#include <haproxy/pool.h>
+#include <haproxy/tools.h>
+#include <haproxy/time.h>
+#include <haproxy/thread.h>
+#include <haproxy/log.h>
+#include <haproxy/proxy-t.h>
+#include <haproxy/server-t.h>
+#include <haproxy/task.h>
+
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 <p> using <mls> 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 0d9b533..b2c2853 100644
--- a/src/server.c
+++ b/src/server.c
@@ -27,6 +27,7 @@
#include <haproxy/dns.h>
#include <haproxy/errors.h>
#include <haproxy/global.h>
+#include <haproxy/mailers.h>
#include <haproxy/namespace.h>
#include <haproxy/queue.h>
#include <haproxy/sample.h>