diff --git a/include/haproxy/tcpcheck-t.h b/include/haproxy/tcpcheck-t.h index 22310eee0..f01d512eb 100644 --- a/include/haproxy/tcpcheck-t.h +++ b/include/haproxy/tcpcheck-t.h @@ -36,6 +36,7 @@ #define TCPCHK_OPT_IMPLICIT 0x0010 /* Implicit connect */ #define TCPCHK_OPT_SOCKS4 0x0020 /* check the connection via socks4 proxy */ #define TCPCHK_OPT_HAS_DATA 0x0040 /* data should be sent after connection */ +#define TCPCHK_MASK_OPTS_CONNECT 0x0027 /* mask for any options which overrides default connect params */ enum tcpcheck_send_type { TCPCHK_SEND_UNDEF = 0, /* Send is not parsed. */ diff --git a/src/backend.c b/src/backend.c index 4b3eeec2a..80b651510 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1547,11 +1547,14 @@ static int be_reuse_mode(struct proxy *be, struct server *srv) /* Calculate hash to select a matching connection for reuse. Here is the list * of input parameters : * - is the server instance. Can be NULL on dispatch/transparent proxy. - * - is the stream instance. + * - is the stream instance. Can be NULL if no stream is used. * - is the bind address if an explicit source address is used. * - is the destination address. Must be set in every cases, except on * reverse HTTP. * + * Note that all input parameters can be NULL. The only requirement is that + * it's not possible to have both and NULL at the same time. + * * Returns the calculated hash. */ int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm, @@ -1592,7 +1595,7 @@ int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm, hash_params.src_addr = src; /* 5. proxy protocol */ - if (srv && srv->pp_opts & SRV_PP_ENABLED) { + if (strm && srv && srv->pp_opts & SRV_PP_ENABLED) { struct connection *cli_conn = objt_conn(strm_orig(strm)); int proxy_line_ret = make_proxy_line(trash.area, trash.size, srv, cli_conn, strm, sess); @@ -1603,7 +1606,7 @@ int64_t be_calculate_conn_hash(struct server *srv, struct stream *strm, } /* 6. Custom mark, tos? */ - if (strm->flags & (SF_BC_MARK | SF_BC_TOS)) { + if (strm && (strm->flags & (SF_BC_MARK | SF_BC_TOS))) { /* mark: 32bits, tos: 8bits = 40bits * last 2 bits are there to indicate if mark and/or tos are set * total: 42bits: diff --git a/src/tcpcheck.c b/src/tcpcheck.c index a366b9e59..754f41448 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -1206,6 +1207,20 @@ enum tcpcheck_eval_ret tcpcheck_agent_expect_reply(struct check *check, struct t goto out; } +/* Returns true if or rule uses any specific connect options + * which may differ from their underlying server counterparts. + */ +static inline int tcpcheck_use_nondefault_connect(const struct check *check, + const struct tcpcheck_connect *connect) +{ + return check->mux_proto || connect->mux_proto || + is_addr(&check->addr) || is_addr(&connect->addr) || + check->port || connect->port || connect->port_expr || + check->use_ssl || check->sni || connect->sni || check->alpn_len || connect->alpn_len || + check->send_proxy || check->via_socks4 || + (connect->options & TCPCHK_MASK_OPTS_CONNECT); +} + /* Evaluates a TCPCHK_ACT_CONNECT rule. Returns TCPCHK_EVAL_WAIT to wait the * connection establishment, TCPCHK_EVAL_CONTINUE to evaluate the next rule or * TCPCHK_EVAL_STOP if an error occurred. @@ -1249,6 +1264,32 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec check_release_buf(check, &check->bi); check_release_buf(check, &check->bo); + if (!(check->state & CHK_ST_AGENT) && check->reuse_pool && + !tcpcheck_use_nondefault_connect(check, connect)) { + int64_t hash; + int conn_err; + + TRACE_DEVEL("trying connection reuse for check", CHK_EV_TCPCHK_CONN, check); + + hash = be_calculate_conn_hash(s, NULL, check->sess, NULL, NULL); + conn_err = be_reuse_connection(hash, check->sess, s->proxy, s, + check->sc, &s->obj_type, 0); + if (conn_err == SF_ERR_INTERNAL) { + TRACE_ERROR("error during connection reuse", CHK_EV_TCPCHK_CONN|CHK_EV_TCPCHK_ERR, check); + set_server_check_status(check, HCHK_STATUS_SOCKERR, trash.area); + ret = TCPCHK_EVAL_STOP; + goto out; + } + else if (conn_err == SF_ERR_NONE) { + TRACE_STATE("check performed with connection reuse", CHK_EV_TCPCHK_CONN, check); + conn = __sc_conn(check->sc); + conn_set_owner(conn, check->sess, NULL); + /* connection will be reinsert in idle conn pool due to missing conn_set_private(). */ + status = SF_ERR_NONE; + goto skip_connect; + } + } + /* No connection, prepare a new one */ conn = conn_new((s ? &s->obj_type : &proxy->obj_type)); if (!conn) { @@ -1414,6 +1455,7 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec } fail_check: + skip_connect: /* It can return one of : * - SF_ERR_NONE if everything's OK * - SF_ERR_SRVTO if there are no more servers