mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 07:37:02 +02:00
MEDIUM: tcp-check new feature: connect
A new tcp-check rule type: connect. It allows HAProxy to test applications which stand on multiple ports or multiple applications load-balanced through the same backend.
This commit is contained in:
parent
7e4086dc18
commit
69e273f3fc
@ -1220,6 +1220,7 @@ http-check expect - - X X
|
|||||||
http-check send-state X - X X
|
http-check send-state X - X X
|
||||||
http-request - X X X
|
http-request - X X X
|
||||||
http-response - X X X
|
http-response - X X X
|
||||||
|
tcp-check connect - - X X
|
||||||
tcp-check expect - - X X
|
tcp-check expect - - X X
|
||||||
tcp-check send - - X X
|
tcp-check send - - X X
|
||||||
tcp-check send-binary - - X X
|
tcp-check send-binary - - X X
|
||||||
@ -3021,6 +3022,63 @@ http-response { allow | deny | add-header <name> <fmt> | set-nice <nice> |
|
|||||||
ACL usage.
|
ACL usage.
|
||||||
|
|
||||||
|
|
||||||
|
tcp-check connect [params*]
|
||||||
|
Opens a new connection
|
||||||
|
May be used in sections: defaults | frontend | listen | backend
|
||||||
|
no | no | yes | yes
|
||||||
|
|
||||||
|
When an application lies on more than a single TCP port or when HAProxy
|
||||||
|
load-balance many services in a single backend, it makes sense to probe all
|
||||||
|
the services individually before considering a server as operational.
|
||||||
|
|
||||||
|
When there are no TCP port configured on the server line neither server port
|
||||||
|
directive, then the 'tcp-check connect port <port>' must be the first step
|
||||||
|
of the sequence.
|
||||||
|
|
||||||
|
In a tcp-check ruleset a 'connect' is required, it is also mandatory to start
|
||||||
|
the ruleset with a 'connect' rule. Purpose is to ensure admin know what they
|
||||||
|
do.
|
||||||
|
|
||||||
|
Parameters :
|
||||||
|
They are optional and can be used to describe how HAProxy should open and
|
||||||
|
use the TCP connection.
|
||||||
|
|
||||||
|
port if not set, check port or server port is used.
|
||||||
|
It tells HAProxy where to open the connection to.
|
||||||
|
<port> must be a valid TCP port source integer, from 1 to 65535.
|
||||||
|
|
||||||
|
send-proxy send a PROXY protocol string
|
||||||
|
|
||||||
|
ssl opens a ciphered connection
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
# check HTTP and HTTPs services on a server.
|
||||||
|
# first open port 80 thanks to server line port directive, then
|
||||||
|
# tcp-check opens port 443, ciphered and run a request on it:
|
||||||
|
option tcp-check
|
||||||
|
tcp-check connect
|
||||||
|
tcp-check send GET\ /\ HTTP/1.0\r\n
|
||||||
|
tcp-check send Host:\ haproxy.1wt.eu\r\n
|
||||||
|
tcp-check send \r\n
|
||||||
|
tcp-check expect rstring (2..|3..)
|
||||||
|
tcp-check connect port 443 ssl
|
||||||
|
tcp-check send GET\ /\ HTTP/1.0\r\n
|
||||||
|
tcp-check send Host:\ haproxy.1wt.eu\r\n
|
||||||
|
tcp-check send \r\n
|
||||||
|
tcp-check expect rstring (2..|3..)
|
||||||
|
server www 10.0.0.1 check port 80
|
||||||
|
|
||||||
|
# check both POP and IMAP from a single server:
|
||||||
|
option tcp-check
|
||||||
|
tcp-check connect port 110
|
||||||
|
tcp-check expect string +OK\ POP3\ ready
|
||||||
|
tcp-check connect port 143
|
||||||
|
tcp-check expect string *\ OK\ IMAP4\ ready
|
||||||
|
server mail 10.0.0.1 check
|
||||||
|
|
||||||
|
See also : "option tcp-check", "tcp-check send", "tcp-check expect"
|
||||||
|
|
||||||
|
|
||||||
tcp-check expect [!] <match> <pattern>
|
tcp-check expect [!] <match> <pattern>
|
||||||
Specify data to be collected and analysed during a generic health check
|
Specify data to be collected and analysed during a generic health check
|
||||||
May be used in sections: defaults | frontend | listen | backend
|
May be used in sections: defaults | frontend | listen | backend
|
||||||
@ -3098,8 +3156,8 @@ tcp-check expect [!] <match> <pattern>
|
|||||||
tcp-check expect string +OK
|
tcp-check expect string +OK
|
||||||
|
|
||||||
|
|
||||||
See also : "option tcp-check", "tcp-check send", "http-check expect",
|
See also : "option tcp-check", "tcp-check connect", "tcp-check send",
|
||||||
tune.chksize
|
"tcp-check send-binary", "http-check expect", tune.chksize
|
||||||
|
|
||||||
|
|
||||||
tcp-check send <data>
|
tcp-check send <data>
|
||||||
@ -3116,8 +3174,8 @@ tcp-check send <data>
|
|||||||
tcp-check send info\ replication\r\n
|
tcp-check send info\ replication\r\n
|
||||||
tcp-check expect string role:master
|
tcp-check expect string role:master
|
||||||
|
|
||||||
See also : "option tcp-check", "tcp-check expect", "tcp-check send-binary",
|
See also : "option tcp-check", "tcp-check connect", "tcp-check expect",
|
||||||
tune.chksize
|
"tcp-check send-binary", tune.chksize
|
||||||
|
|
||||||
|
|
||||||
tcp-check send-binary <hexastring>
|
tcp-check send-binary <hexastring>
|
||||||
@ -3141,9 +3199,8 @@ tcp-check send-binary <hexastring>
|
|||||||
tcp-check expect binary 2b504F4e47 # +PONG
|
tcp-check expect binary 2b504F4e47 # +PONG
|
||||||
|
|
||||||
|
|
||||||
See also : "option tcp-check", "tcp-check expect", "tcp-check send",
|
See also : "option tcp-check", "tcp-check connect", "tcp-check expect",
|
||||||
tune.chksize
|
"tcp-check send", tune.chksize
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
http-send-name-header [<header>]
|
http-send-name-header [<header>]
|
||||||
|
@ -135,6 +135,7 @@ struct check {
|
|||||||
int use_ssl; /* use SSL for health checks */
|
int use_ssl; /* use SSL for health checks */
|
||||||
int send_proxy; /* send a PROXY protocol header with checks */
|
int send_proxy; /* send a PROXY protocol header with checks */
|
||||||
struct tcpcheck_rule *current_step; /* current step when using tcpcheck */
|
struct tcpcheck_rule *current_step; /* current step when using tcpcheck */
|
||||||
|
struct tcpcheck_rule *last_started_step;/* pointer to latest tcpcheck rule started */
|
||||||
int inter, fastinter, downinter; /* checks: time in milliseconds */
|
int inter, fastinter, downinter; /* checks: time in milliseconds */
|
||||||
enum chk_result result; /* health-check result : CHK_RES_* */
|
enum chk_result result; /* health-check result : CHK_RES_* */
|
||||||
int state; /* state of the check : CHK_ST_* */
|
int state; /* state of the check : CHK_ST_* */
|
||||||
@ -160,8 +161,14 @@ struct analyze_status {
|
|||||||
enum {
|
enum {
|
||||||
TCPCHK_ACT_SEND = 0, /* send action, regular string format */
|
TCPCHK_ACT_SEND = 0, /* send action, regular string format */
|
||||||
TCPCHK_ACT_EXPECT, /* expect action, either regular or binary string */
|
TCPCHK_ACT_EXPECT, /* expect action, either regular or binary string */
|
||||||
|
TCPCHK_ACT_CONNECT, /* connect action, to probe a new port */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* flags used by tcpcheck_rule->conn_opts */
|
||||||
|
#define TCPCHK_OPT_NONE 0x0000 /* no options specified, default */
|
||||||
|
#define TCPCHK_OPT_SEND_PROXY 0x0001 /* send proxy-protocol string */
|
||||||
|
#define TCPCHK_OPT_SSL 0x0002 /* SSL connection */
|
||||||
|
|
||||||
struct tcpcheck_rule {
|
struct tcpcheck_rule {
|
||||||
struct list list; /* list linked to from the proxy */
|
struct list list; /* list linked to from the proxy */
|
||||||
int action; /* action: send or expect */
|
int action; /* action: send or expect */
|
||||||
@ -171,6 +178,8 @@ struct tcpcheck_rule {
|
|||||||
int string_len; /* string lenght */
|
int string_len; /* string lenght */
|
||||||
regex_t *expect_regex; /* expected */
|
regex_t *expect_regex; /* expected */
|
||||||
int inverse; /* 0 = regular match, 1 = inverse match */
|
int inverse; /* 0 = regular match, 1 = inverse match */
|
||||||
|
unsigned short port; /* port to connect to */
|
||||||
|
unsigned short conn_opts; /* options when setting up a new connection */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _TYPES_CHECKS_H */
|
#endif /* _TYPES_CHECKS_H */
|
||||||
|
@ -104,8 +104,7 @@ enum pr_mode {
|
|||||||
#define PR_O_HTTP_TUN 0x04000000 /* HTTP tunnel mode : no analysis past first request/response */
|
#define PR_O_HTTP_TUN 0x04000000 /* HTTP tunnel mode : no analysis past first request/response */
|
||||||
/* unassigned values : 0x05000000, 0x06000000, 0x07000000 */
|
/* unassigned values : 0x05000000, 0x06000000, 0x07000000 */
|
||||||
#define PR_O_HTTP_MODE 0x07000000 /* MASK to retrieve the HTTP mode */
|
#define PR_O_HTTP_MODE 0x07000000 /* MASK to retrieve the HTTP mode */
|
||||||
|
#define PR_O_TCPCHK_SSL 0x08000000 /* at least one TCPCHECK connect rule requires SSL */
|
||||||
/* unused: 0x08000000 */
|
|
||||||
#define PR_O_CONTSTATS 0x10000000 /* continous counters */
|
#define PR_O_CONTSTATS 0x10000000 /* continous counters */
|
||||||
#define PR_O_HTTP_PROXY 0x20000000 /* Enable session to use HTTP proxy operations */
|
#define PR_O_HTTP_PROXY 0x20000000 /* Enable session to use HTTP proxy operations */
|
||||||
#define PR_O_DISABLE404 0x40000000 /* Disable a server on a 404 response to a health-check */
|
#define PR_O_DISABLE404 0x40000000 /* Disable a server on a 404 response to a health-check */
|
||||||
|
@ -4089,7 +4089,70 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
|
if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL))
|
||||||
err_code |= ERR_WARN;
|
err_code |= ERR_WARN;
|
||||||
|
|
||||||
if (strcmp(args[1], "send") == 0) {
|
if (strcmp(args[1], "connect") == 0) {
|
||||||
|
const char *ptr_arg;
|
||||||
|
int cur_arg;
|
||||||
|
struct tcpcheck_rule *tcpcheck;
|
||||||
|
struct list *l;
|
||||||
|
|
||||||
|
/* check if first rule is also a 'connect' action */
|
||||||
|
l = (struct list *)&curproxy->tcpcheck_rules;
|
||||||
|
if (l->p != l->n) {
|
||||||
|
tcpcheck = (struct tcpcheck_rule *)l->n;
|
||||||
|
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);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cur_arg = 2;
|
||||||
|
tcpcheck = (struct tcpcheck_rule *)calloc(1, sizeof(*tcpcheck));
|
||||||
|
tcpcheck->action = TCPCHK_ACT_CONNECT;
|
||||||
|
|
||||||
|
/* parsing each parameters to fill up the rule */
|
||||||
|
while (*(ptr_arg = args[cur_arg])) {
|
||||||
|
/* tcp port */
|
||||||
|
if (strcmp(args[cur_arg], "port") == 0) {
|
||||||
|
if ( (atol(args[cur_arg + 1]) > 65535) ||
|
||||||
|
(atol(args[cur_arg + 1]) < 1) ){
|
||||||
|
Alert("parsing [%s:%d] : '%s %s %s' expects a valid TCP port (from range 1 to 65535), got %s.\n",
|
||||||
|
file, linenum, args[0], args[1], "port", args[cur_arg + 1]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
tcpcheck->port = atol(args[cur_arg + 1]);
|
||||||
|
cur_arg += 2;
|
||||||
|
}
|
||||||
|
/* send proxy protocol */
|
||||||
|
else if (strcmp(args[cur_arg], "send-proxy") == 0) {
|
||||||
|
tcpcheck->conn_opts |= TCPCHK_OPT_SEND_PROXY;
|
||||||
|
cur_arg++;
|
||||||
|
}
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
else if (strcmp(args[cur_arg], "ssl") == 0) {
|
||||||
|
curproxy->options |= PR_O_TCPCHK_SSL;
|
||||||
|
tcpcheck->conn_opts |= TCPCHK_OPT_SSL;
|
||||||
|
cur_arg++;
|
||||||
|
}
|
||||||
|
#endif /* USE_OPENSSL */
|
||||||
|
else {
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
Alert("parsing [%s:%d] : '%s %s' expects '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",
|
||||||
|
#endif /* USE_OPENSSL */
|
||||||
|
file, linenum, args[0], args[1], args[cur_arg]);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
LIST_ADDQ(&curproxy->tcpcheck_rules, &tcpcheck->list);
|
||||||
|
}
|
||||||
|
else if (strcmp(args[1], "send") == 0) {
|
||||||
if (! *(args[2]) ) {
|
if (! *(args[2]) ) {
|
||||||
/* SEND string expected */
|
/* SEND string expected */
|
||||||
Alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
|
Alert("parsing [%s:%d] : '%s %s %s' expects <STRING> as argument.\n",
|
||||||
@ -4235,7 +4298,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Alert("parsing [%s:%d] : '%s' only supports 'send' or 'expect'.\n", file, linenum, args[0]);
|
Alert("parsing [%s:%d] : '%s' only supports 'connect', 'send' or 'expect'.\n", file, linenum, args[0]);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -5191,7 +5254,7 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
*/
|
*/
|
||||||
if (!newsrv->check.port && !is_addr(&newsrv->check_common.addr)) {
|
if (!newsrv->check.port && !is_addr(&newsrv->check_common.addr)) {
|
||||||
#ifdef USE_OPENSSL
|
#ifdef USE_OPENSSL
|
||||||
newsrv->check.use_ssl |= newsrv->use_ssl;
|
newsrv->check.use_ssl |= (newsrv->use_ssl || (newsrv->proxy->options & PR_O_TCPCHK_SSL));
|
||||||
#endif
|
#endif
|
||||||
newsrv->check.send_proxy |= (newsrv->state & SRV_SEND_PROXY);
|
newsrv->check.send_proxy |= (newsrv->state & SRV_SEND_PROXY);
|
||||||
}
|
}
|
||||||
@ -5215,12 +5278,41 @@ int cfg_parse_listen(const char *file, int linenum, char **args, int kwm)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* We need at least a service port, a check port or the first tcp-check rule must
|
||||||
|
* be a 'connect' one
|
||||||
|
*/
|
||||||
if (!newsrv->check.port) {
|
if (!newsrv->check.port) {
|
||||||
|
struct tcpcheck_rule *n = NULL, *r = NULL;
|
||||||
|
struct list *l;
|
||||||
|
|
||||||
|
r = (struct tcpcheck_rule *)newsrv->proxy->tcpcheck_rules.n;
|
||||||
|
if (!r) {
|
||||||
Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
|
Alert("parsing [%s:%d] : server %s has neither service port nor check port. Check has been disabled.\n",
|
||||||
file, linenum, newsrv->id);
|
file, linenum, newsrv->id);
|
||||||
err_code |= ERR_ALERT | ERR_FATAL;
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
if ((r->action != TCPCHK_ACT_CONNECT) || !r->port) {
|
||||||
|
Alert("parsing [%s:%d] : server %s has neither service port nor check port nor tcp_check rule 'connect' with port information. Check has been disabled.\n",
|
||||||
|
file, linenum, newsrv->id);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* scan the tcp-check ruleset to ensure a port has been configured */
|
||||||
|
l = &newsrv->proxy->tcpcheck_rules;
|
||||||
|
list_for_each_entry(n, l, list) {
|
||||||
|
r = (struct tcpcheck_rule *)n->list.p;
|
||||||
|
if ((r->action == TCPCHK_ACT_CONNECT) && (!r->port)) {
|
||||||
|
Alert("parsing [%s:%d] : server %s has neither service port nor check port, and a tcp_check rule 'connect' with no port information. Check has been disabled.\n",
|
||||||
|
file, linenum, newsrv->id);
|
||||||
|
err_code |= ERR_ALERT | ERR_FATAL;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* note: check type will be set during the config review phase */
|
/* note: check type will be set during the config review phase */
|
||||||
ret = init_check(&newsrv->check, 0, file, linenum);
|
ret = init_check(&newsrv->check, 0, file, linenum);
|
||||||
|
167
src/checks.c
167
src/checks.c
@ -35,6 +35,11 @@
|
|||||||
|
|
||||||
#include <types/global.h>
|
#include <types/global.h>
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
#include <types/ssl_sock.h>
|
||||||
|
#include <proto/ssl_sock.h>
|
||||||
|
#endif /* USE_OPENSSL */
|
||||||
|
|
||||||
#include <proto/backend.h>
|
#include <proto/backend.h>
|
||||||
#include <proto/checks.h>
|
#include <proto/checks.h>
|
||||||
#include <proto/dumpstats.h>
|
#include <proto/dumpstats.h>
|
||||||
@ -44,6 +49,7 @@
|
|||||||
#include <proto/port_range.h>
|
#include <proto/port_range.h>
|
||||||
#include <proto/proto_http.h>
|
#include <proto/proto_http.h>
|
||||||
#include <proto/proto_tcp.h>
|
#include <proto/proto_tcp.h>
|
||||||
|
#include <proto/protocol.h>
|
||||||
#include <proto/proxy.h>
|
#include <proto/proxy.h>
|
||||||
#include <proto/raw_sock.h>
|
#include <proto/raw_sock.h>
|
||||||
#include <proto/server.h>
|
#include <proto/server.h>
|
||||||
@ -862,7 +868,10 @@ static void chk_report_conn_err(struct connection *conn, int errno_bck, int expi
|
|||||||
if (check->type == PR_O2_TCPCHK_CHK) {
|
if (check->type == PR_O2_TCPCHK_CHK) {
|
||||||
chunk_printf(chk, " at step %d of tcp-check", tcpcheck_get_step_id(check->server));
|
chunk_printf(chk, " at step %d of tcp-check", tcpcheck_get_step_id(check->server));
|
||||||
/* we were looking for a string */
|
/* we were looking for a string */
|
||||||
if (check->current_step && check->current_step->action == TCPCHK_ACT_EXPECT) {
|
if (check->current_step && check->current_step->action == TCPCHK_ACT_CONNECT) {
|
||||||
|
chunk_appendf(chk, " (connect)");
|
||||||
|
}
|
||||||
|
else if (check->current_step && check->current_step->action == TCPCHK_ACT_EXPECT) {
|
||||||
if (check->current_step->string)
|
if (check->current_step->string)
|
||||||
chunk_appendf(chk, " (string '%s')", check->current_step->string);
|
chunk_appendf(chk, " (string '%s')", check->current_step->string);
|
||||||
else if (check->current_step->expect_regex)
|
else if (check->current_step->expect_regex)
|
||||||
@ -1564,7 +1573,15 @@ static struct task *process_chk(struct task *t)
|
|||||||
/* we'll connect to the addr on the server */
|
/* we'll connect to the addr on the server */
|
||||||
conn->addr.to = s->addr;
|
conn->addr.to = s->addr;
|
||||||
|
|
||||||
|
if (check->port) {
|
||||||
set_host_port(&conn->addr.to, check->port);
|
set_host_port(&conn->addr.to, check->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (check->type == PR_O2_TCPCHK_CHK) {
|
||||||
|
tcpcheck_main(conn);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* It can return one of :
|
/* It can return one of :
|
||||||
* - SN_ERR_NONE if everything's OK
|
* - SN_ERR_NONE if everything's OK
|
||||||
@ -1920,7 +1937,7 @@ static int tcpcheck_get_step_id(struct server *s)
|
|||||||
struct tcpcheck_rule *cur = NULL, *next = NULL;
|
struct tcpcheck_rule *cur = NULL, *next = NULL;
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
cur = s->check.current_step;
|
cur = s->check.last_started_step;
|
||||||
|
|
||||||
/* no step => first step */
|
/* no step => first step */
|
||||||
if (cur == NULL)
|
if (cur == NULL)
|
||||||
@ -1948,8 +1965,11 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
struct server *s = check->server;
|
struct server *s = check->server;
|
||||||
struct task *t = check->task;
|
struct task *t = check->task;
|
||||||
|
|
||||||
/* don't do anything until the connection is established */
|
/*
|
||||||
if (!(conn->flags & CO_FL_CONNECTED)) {
|
* don't do anything until the connection is established but if we're running
|
||||||
|
* first step which must be a connect
|
||||||
|
*/
|
||||||
|
if (check->current_step && (!(conn->flags & CO_FL_CONNECTED))) {
|
||||||
/* update expire time, should be done by process_chk */
|
/* update expire time, should be done by process_chk */
|
||||||
/* we allow up to min(inter, timeout.connect) for a connection
|
/* we allow up to min(inter, timeout.connect) for a connection
|
||||||
* to establish but only when timeout.check is set
|
* to establish but only when timeout.check is set
|
||||||
@ -2023,7 +2043,129 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check->current_step->action == TCPCHK_ACT_SEND) {
|
if (check->current_step->action == TCPCHK_ACT_CONNECT) {
|
||||||
|
struct protocol *proto;
|
||||||
|
struct xprt_ops *xprt;
|
||||||
|
|
||||||
|
/* mark the step as started */
|
||||||
|
check->last_started_step = check->current_step;
|
||||||
|
/* first, shut existing connection */
|
||||||
|
conn_force_close(conn);
|
||||||
|
|
||||||
|
/* prepare new connection */
|
||||||
|
/* initialization */
|
||||||
|
conn_init(conn);
|
||||||
|
conn_attach(conn, check, &check_conn_cb);
|
||||||
|
conn->target = &s->obj_type;
|
||||||
|
|
||||||
|
/* no client address */
|
||||||
|
clear_addr(&conn->addr.from);
|
||||||
|
|
||||||
|
if (is_addr(&s->check_common.addr))
|
||||||
|
/* we'll connect to the check addr specified on the server */
|
||||||
|
conn->addr.to = s->check_common.addr;
|
||||||
|
else
|
||||||
|
/* we'll connect to the addr on the server */
|
||||||
|
conn->addr.to = s->addr;
|
||||||
|
|
||||||
|
/* protocol */
|
||||||
|
proto = protocol_by_family(conn->addr.to.ss_family);
|
||||||
|
|
||||||
|
/* port */
|
||||||
|
if (check->current_step->port)
|
||||||
|
set_host_port(&conn->addr.to, check->current_step->port);
|
||||||
|
else if (check->port)
|
||||||
|
set_host_port(&conn->addr.to, check->port);
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
if (check->current_step->conn_opts & TCPCHK_OPT_SSL) {
|
||||||
|
xprt = &ssl_sock;
|
||||||
|
ssl_sock_prepare_srv_ctx(s, s->proxy);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
xprt = &raw_sock;
|
||||||
|
}
|
||||||
|
#else /* USE_OPENSSL */
|
||||||
|
xprt = &raw_sock;
|
||||||
|
#endif /* USE_OPENSSL */
|
||||||
|
conn_prepare(conn, proto, xprt);
|
||||||
|
|
||||||
|
ret = SN_ERR_INTERNAL;
|
||||||
|
if (proto->connect)
|
||||||
|
ret = proto->connect(conn, check->type, (check->type) ? 0 : 2);
|
||||||
|
conn->flags |= CO_FL_WAKE_DATA;
|
||||||
|
if (check->current_step->conn_opts & TCPCHK_OPT_SEND_PROXY) {
|
||||||
|
conn->send_proxy_ofs = 1;
|
||||||
|
conn->flags |= CO_FL_SEND_PROXY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It can return one of :
|
||||||
|
* - SN_ERR_NONE if everything's OK
|
||||||
|
* - SN_ERR_SRVTO if there are no more servers
|
||||||
|
* - SN_ERR_SRVCL if the connection was refused by the server
|
||||||
|
* - SN_ERR_PRXCOND if the connection has been limited by the proxy (maxconn)
|
||||||
|
* - SN_ERR_RESOURCE if a system resource is lacking (eg: fd limits, ports, ...)
|
||||||
|
* - SN_ERR_INTERNAL for any other purely internal errors
|
||||||
|
* Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted.
|
||||||
|
* Note that we try to prevent the network stack from sending the ACK during the
|
||||||
|
* connect() when a pure TCP check is used (without PROXY protocol).
|
||||||
|
*/
|
||||||
|
switch (ret) {
|
||||||
|
case SN_ERR_NONE:
|
||||||
|
/* we allow up to min(inter, timeout.connect) for a connection
|
||||||
|
* to establish but only when timeout.check is set
|
||||||
|
* as it may be to short for a full check otherwise
|
||||||
|
*/
|
||||||
|
t->expire = tick_add(now_ms, MS_TO_TICKS(check->inter));
|
||||||
|
|
||||||
|
if (s->proxy->timeout.check && s->proxy->timeout.connect) {
|
||||||
|
int t_con = tick_add(now_ms, s->proxy->timeout.connect);
|
||||||
|
t->expire = tick_first(t->expire, t_con);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SN_ERR_SRVTO: /* ETIMEDOUT */
|
||||||
|
case SN_ERR_SRVCL: /* ECONNREFUSED, ENETUNREACH, ... */
|
||||||
|
chunk_printf(&trash, "TCPCHK error establishing connection at step %d: %s",
|
||||||
|
tcpcheck_get_step_id(s), strerror(errno));
|
||||||
|
set_server_check_status(check, HCHK_STATUS_L4CON, trash.str);
|
||||||
|
goto out_end_tcpcheck;
|
||||||
|
case SN_ERR_PRXCOND:
|
||||||
|
case SN_ERR_RESOURCE:
|
||||||
|
case SN_ERR_INTERNAL:
|
||||||
|
chunk_printf(&trash, "TCPCHK error establishing connection at step %d",
|
||||||
|
tcpcheck_get_step_id(s));
|
||||||
|
set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.str);
|
||||||
|
goto out_end_tcpcheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allow next rule */
|
||||||
|
cur = (struct tcpcheck_rule *)cur->list.n;
|
||||||
|
check->current_step = cur;
|
||||||
|
|
||||||
|
/* don't do anything until the connection is established */
|
||||||
|
if (!(conn->flags & CO_FL_CONNECTED)) {
|
||||||
|
/* update expire time, should be done by process_chk */
|
||||||
|
/* we allow up to min(inter, timeout.connect) for a connection
|
||||||
|
* to establish but only when timeout.check is set
|
||||||
|
* as it may be to short for a full check otherwise
|
||||||
|
*/
|
||||||
|
while (tick_is_expired(t->expire, now_ms)) {
|
||||||
|
int t_con;
|
||||||
|
|
||||||
|
t_con = tick_add(t->expire, s->proxy->timeout.connect);
|
||||||
|
t->expire = tick_add(t->expire, MS_TO_TICKS(check->inter));
|
||||||
|
|
||||||
|
if (s->proxy->timeout.check)
|
||||||
|
t->expire = tick_first(t->expire, t_con);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end 'connect' */
|
||||||
|
else if (check->current_step->action == TCPCHK_ACT_SEND) {
|
||||||
|
/* mark the step as started */
|
||||||
|
check->last_started_step = check->current_step;
|
||||||
|
|
||||||
/* reset the read buffer */
|
/* reset the read buffer */
|
||||||
if (*check->bi->data != '\0') {
|
if (*check->bi->data != '\0') {
|
||||||
*check->bi->data = '\0';
|
*check->bi->data = '\0';
|
||||||
@ -2076,6 +2218,10 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
goto out_need_io;
|
goto out_need_io;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mark the step as started */
|
||||||
|
check->last_started_step = check->current_step;
|
||||||
|
|
||||||
|
|
||||||
/* Intermediate or complete response received.
|
/* Intermediate or complete response received.
|
||||||
* Terminate string in check->bi->data buffer.
|
* Terminate string in check->bi->data buffer.
|
||||||
*/
|
*/
|
||||||
@ -2186,22 +2332,13 @@ static void tcpcheck_main(struct connection *conn)
|
|||||||
if (conn->flags & CO_FL_ERROR)
|
if (conn->flags & CO_FL_ERROR)
|
||||||
chk_report_conn_err(conn, 0, 0);
|
chk_report_conn_err(conn, 0, 0);
|
||||||
|
|
||||||
/* Close the connection... We absolutely want to perform a hard close
|
/* cleanup before leaving */
|
||||||
* and reset the connection if some data are pending, otherwise we end
|
|
||||||
* up with many TIME_WAITs and eat all the source port range quickly.
|
|
||||||
* To avoid sending RSTs all the time, we first try to drain pending
|
|
||||||
* data.
|
|
||||||
*/
|
|
||||||
if (conn->xprt && conn->xprt->shutw)
|
|
||||||
conn->xprt->shutw(conn, 0);
|
|
||||||
|
|
||||||
check->current_step = NULL;
|
check->current_step = NULL;
|
||||||
|
|
||||||
if (check->result == CHK_RES_FAILED)
|
if (check->result == CHK_RES_FAILED)
|
||||||
conn->flags |= CO_FL_ERROR;
|
conn->flags |= CO_FL_ERROR;
|
||||||
|
|
||||||
__conn_data_stop_both(conn);
|
__conn_data_stop_both(conn);
|
||||||
task_wakeup(t, TASK_WOKEN_IO);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user