rc = PR_CAP_LISTEN;
else if (!strcmp(args[0], "frontend"))
rc = PR_CAP_FE | PR_CAP_RS;
- else if (!strcmp(args[0], "backend"))
+ else if (!strcmp(args[0], "backend"))
rc = PR_CAP_BE | PR_CAP_RS;
else if (!strcmp(args[0], "ruleset"))
rc = PR_CAP_RS;
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
err_code |= ERR_WARN;
- if (strcmp(args[1], "connect") == 0) {
+ if (strcmp(args[1], "comment") == 0) {
+ int cur_arg;
+ struct tcpcheck_rule *tcpcheck;
+
+ cur_arg = 1;
+ tcpcheck = (struct tcpcheck_rule *)calloc(1, sizeof(*tcpcheck));
+ tcpcheck->action = TCPCHK_ACT_COMMENT;
+
+ if (!*args[cur_arg + 1]) {
+ Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
+ file, linenum, args[cur_arg]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
+ tcpcheck->comment = strdup(args[cur_arg + 1]);
+
+ LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
+ }
+ else if (strcmp(args[1], "connect") == 0) {
const char *ptr_arg;
int cur_arg;
struct tcpcheck_rule *tcpcheck;
l = (struct list *)&curproxy->tcpcheck_rules;
if (l->p != l->n) {
tcpcheck = (struct tcpcheck_rule *)l->n;
+ while (tcpcheck->action == TCPCHK_ACT_COMMENT) {
+ tcpcheck = (struct tcpcheck_rule *)tcpcheck->list.n;
+ }
+ /* we've reached the end of the list, and the list is full of comments */
+ if (tcpcheck == (struct tcpcheck_rule *)l)
+ tcpcheck = NULL;
+
if (tcpcheck && tcpcheck->action != TCPCHK_ACT_CONNECT) {
Alert("parsing [%s:%d] : first step MUST also be a 'connect' when there is a 'connect' step in the tcp-check ruleset.\n",
file, linenum);
cur_arg++;
}
#endif /* USE_OPENSSL */
+ /* comment for this tcpcheck line */
+ else if (strcmp(args[cur_arg], "comment") == 0) {
+ if (!*args[cur_arg + 1]) {
+ Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
+ file, linenum, args[cur_arg]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ tcpcheck->comment = strdup(args[cur_arg + 1]);
+ cur_arg += 2;
+ }
else {
#ifdef USE_OPENSSL
- Alert("parsing [%s:%d] : '%s %s' expects 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
+ Alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or 'ssl' but got '%s' as argument.\n",
#else /* USE_OPENSSL */
- Alert("parsing [%s:%d] : '%s %s' expects 'port', 'send-proxy' or but got '%s' as argument.\n",
+ Alert("parsing [%s:%d] : '%s %s' expects 'comment', 'port', 'send-proxy' or but got '%s' as argument.\n",
#endif /* USE_OPENSSL */
file, linenum, args[0], args[1], args[cur_arg]);
err_code |= ERR_ALERT | ERR_FATAL;
tcpcheck->string = strdup(args[2]);
tcpcheck->expect_regex = NULL;
+ /* comment for this tcpcheck line */
+ if (strcmp(args[3], "comment") == 0) {
+ if (!*args[4]) {
+ Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
+ file, linenum, args[3]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ tcpcheck->comment = strdup(args[4]);
+ }
+
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
}
}
}
tcpcheck->expect_regex = NULL;
+ /* comment for this tcpcheck line */
+ if (strcmp(args[3], "comment") == 0) {
+ if (!*args[4]) {
+ Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
+ file, linenum, args[3]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ tcpcheck->comment = strdup(args[4]);
+ }
+
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
}
}
tcpcheck->expect_regex = NULL;
tcpcheck->inverse = inverse;
+ /* tcpcheck comment */
+ cur_arg += 2;
+ if (strcmp(args[cur_arg], "comment") == 0) {
+ if (!*args[cur_arg + 1]) {
+ Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
+ file, linenum, args[cur_arg + 1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ tcpcheck->comment = strdup(args[cur_arg + 1]);
+ }
+
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
}
else if (strcmp(ptr_arg, "string") == 0) {
tcpcheck->expect_regex = NULL;
tcpcheck->inverse = inverse;
+ /* tcpcheck comment */
+ cur_arg += 2;
+ if (strcmp(args[cur_arg], "comment") == 0) {
+ if (!*args[cur_arg + 1]) {
+ Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
+ file, linenum, args[cur_arg + 1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ tcpcheck->comment = strdup(args[cur_arg + 1]);
+ }
+
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
}
else if (strcmp(ptr_arg, "rstring") == 0) {
}
tcpcheck->inverse = inverse;
+ /* tcpcheck comment */
+ cur_arg += 2;
+ if (strcmp(args[cur_arg], "comment") == 0) {
+ if (!*args[cur_arg + 1]) {
+ Alert("parsing [%s:%d] : '%s' expects a comment string.\n",
+ file, linenum, args[cur_arg + 1]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ tcpcheck->comment = strdup(args[cur_arg + 1]);
+ }
+
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
}
else {
}
}
else {
- Alert("parsing [%s:%d] : '%s' only supports 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
+ Alert("parsing [%s:%d] : '%s' only supports 'comment', 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
err_code |= ERR_ALERT | ERR_FATAL;
goto out;
}
static int httpchk_expect(struct server *s, int done);
static int tcpcheck_get_step_id(struct check *);
+static char * tcpcheck_get_step_comment(struct check *, int);
static void tcpcheck_main(struct connection *);
static const struct check_status check_statuses[HCHK_STATUS_SIZE] = {
const char *err_msg;
struct chunk *chk;
int step;
+ char *comment;
if (check->result != CHK_RES_UNKNOWN)
return;
else if (check->last_started_step && check->last_started_step->action == TCPCHK_ACT_SEND) {
chunk_appendf(chk, " (send)");
}
+
+ comment = tcpcheck_get_step_comment(check, step);
+ if (comment)
+ chunk_appendf(chk, " comment: '%s'", comment);
}
}
return i;
}
+/*
+ * return the latest known comment before (including) the given stepid
+ * returns NULL if no comment found
+ */
+static char * tcpcheck_get_step_comment(struct check *check, int stepid)
+{
+ struct tcpcheck_rule *cur = NULL;
+ char *ret = NULL;
+ int i = 0;
+
+ /* not even started anything yet, return latest comment found before any action */
+ if (!check->current_step) {
+ list_for_each_entry(cur, check->tcpcheck_rules, list) {
+ if (cur->action == TCPCHK_ACT_COMMENT)
+ ret = cur->comment;
+ else
+ goto return_comment;
+ }
+ }
+
+ i = 1;
+ list_for_each_entry(cur, check->tcpcheck_rules, list) {
+ if (cur->comment)
+ ret = cur->comment;
+
+ if (i >= stepid)
+ goto return_comment;
+
+ ++i;
+ }
+
+ return_comment:
+ return ret;
+}
+
static void tcpcheck_main(struct connection *conn)
{
- char *contentptr;
+ char *contentptr, *comment;
struct tcpcheck_rule *cur, *next;
int done = 0, ret = 0, step = 0;
struct check *check = conn->owner;
/* have 'next' point to the next rule or NULL if we're on the last one */
next = (struct tcpcheck_rule *)cur->list.n;
+
+ /* bypass all comment rules */
+ while (next->action == TCPCHK_ACT_COMMENT)
+ next = (struct tcpcheck_rule *)next->list.n;
+
+ /* NULL if we're on the last rule */
if (&next->list == head)
next = NULL;
step = tcpcheck_get_step_id(check);
chunk_printf(&trash, "TCPCHK error establishing connection at step %d: %s",
step, strerror(errno));
+ comment = tcpcheck_get_step_comment(check, step);
+ if (comment)
+ chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_L4CON, trash.str);
goto out_end_tcpcheck;
case SF_ERR_PRXCOND:
case SF_ERR_INTERNAL:
step = tcpcheck_get_step_id(check);
chunk_printf(&trash, "TCPCHK error establishing connection at step %d", step);
+ comment = tcpcheck_get_step_comment(check, step);
+ if (comment)
+ chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.str);
goto out_end_tcpcheck;
}
/* allow next rule */
cur = (struct tcpcheck_rule *)cur->list.n;
+
+ /* bypass all comment rules */
+ while (cur->action == TCPCHK_ACT_COMMENT)
+ cur = (struct tcpcheck_rule *)cur->list.n;
+
check->current_step = cur;
/* don't do anything until the connection is established */
/* go to next rule and try to send */
cur = (struct tcpcheck_rule *)cur->list.n;
+
+ /* bypass all comment rules */
+ while (cur->action == TCPCHK_ACT_COMMENT)
+ cur = (struct tcpcheck_rule *)cur->list.n;
+
check->current_step = cur;
} /* end 'send' */
else if (check->current_step->action == TCPCHK_ACT_EXPECT) {
/* empty response */
step = tcpcheck_get_step_id(check);
chunk_printf(&trash, "TCPCHK got an empty response at step %d", step);
+ comment = tcpcheck_get_step_comment(check, step);
+ if (comment)
+ chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str);
goto out_end_tcpcheck;
/* we were looking for a regex */
chunk_printf(&trash, "TCPCHK matched unwanted content (regex) at step %d", step);
}
+ comment = tcpcheck_get_step_comment(check, step);
+ if (comment)
+ chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str);
goto out_end_tcpcheck;
}
/* matched and was supposed to => OK, next step */
else {
- cur = (struct tcpcheck_rule*)cur->list.n;
+ /* allow next rule */
+ cur = (struct tcpcheck_rule *)cur->list.n;
+
+ /* bypass all comment rules */
+ while (cur->action == TCPCHK_ACT_COMMENT)
+ cur = (struct tcpcheck_rule *)cur->list.n;
+
check->current_step = cur;
+
if (check->current_step->action == TCPCHK_ACT_EXPECT)
goto tcpcheck_expect;
__conn_data_stop_recv(conn);
/* not matched */
/* not matched and was not supposed to => OK, next step */
if (cur->inverse) {
+ /* allow next rule */
+ cur = (struct tcpcheck_rule *)cur->list.n;
+
+ /* bypass all comment rules */
+ while (cur->action == TCPCHK_ACT_COMMENT)
+ cur = (struct tcpcheck_rule *)cur->list.n;
+
+ check->current_step = cur;
+
cur = (struct tcpcheck_rule*)cur->list.n;
check->current_step = cur;
if (check->current_step->action == TCPCHK_ACT_EXPECT)
chunk_printf(&trash, "TCPCHK did not match content (regex) at step %d",
step);
}
+ comment = tcpcheck_get_step_comment(check, step);
+ if (comment)
+ chunk_appendf(&trash, " comment: '%s'", comment);
set_server_check_status(check, HCHK_STATUS_L7RSP, trash.str);
goto out_end_tcpcheck;
}