From 062df2c23ab509b507484e3e9bcf232699077fd8 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Fri, 10 Jan 2020 06:17:03 +0100 Subject: [PATCH] MEDIUM: backend: move the connection finalization step to back_handle_st_con() Currently there's still lots of code in conn_complete_server() that performs one half of the connection setup, which is then checked and finalized in back_handle_st_con(). There isn't a valid reason for this anymore, we can simplify this and make sure that conn_complete_server() only wakes the stream up to inform it about the fact the whole connection stack is set up so that back_handle_st_con() finishes its job at the stream-int level. It looks like the there could even be further simplified, but for now it was moved straight out of conn_complete_server() with no modification. --- src/backend.c | 75 ++++++++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/src/backend.c b/src/backend.c index 719f4ae4b5..0a91a68756 100644 --- a/src/backend.c +++ b/src/backend.c @@ -1077,16 +1077,13 @@ static void assign_tproxy_address(struct stream *s) } #if defined(USE_OPENSSL) && defined(TLSEXT_TYPE_application_layer_protocol_negotiation) -/* - * Pick the right mux once the connection is established, we should now have - * an alpn if available, so we are now able to choose. In this specific case - * the connection's context is &si[i].end. +/* Wake the stream up to finish the connection (attach the mux etc). We should + * now have an alpn if available, so we are now able to choose. In this specific + * case the connection's context is &si[i].end. */ static int conn_complete_server(struct connection *conn) { - struct conn_stream *cs = NULL; struct stream *s = container_of(conn->ctx, struct stream, si[1].end); - struct server *srv; task_wakeup(s->task, TASK_WOKEN_IO); conn_clear_xprt_done_cb(conn); @@ -1094,33 +1091,7 @@ static int conn_complete_server(struct connection *conn) if (unlikely(!(conn->flags & (CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN | CO_FL_CONNECTED)))) conn->flags |= CO_FL_CONNECTED; - if (conn->flags & CO_FL_ERROR) - goto fail; - si_detach_endpoint(&s->si[1]); - cs = si_alloc_cs(&s->si[1], conn); - if (!cs) - goto fail; - if (conn_install_mux_be(conn, cs, s->sess) < 0) - goto fail; - srv = objt_server(s->target); - if (srv && ((s->be->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR) && - conn->mux->avail_streams(conn) > 0) - LIST_ADD(&srv->idle_conns[tid], &conn->list); - return 0; - -fail: - si_detach_endpoint(&s->si[1]); - - if (cs) - cs_free(cs); - /* kill the connection now */ - conn_stop_tracking(conn); - conn_full_close(conn); - conn_free(conn); - /* Let process_stream know it went wrong */ - s->si[1].flags |= SI_FL_ERR; - return -1; } #endif @@ -1972,6 +1943,9 @@ void back_handle_st_req(struct stream *s) * SI_ST_CER (error), SI_ST_DIS (abort), and SI_ST_CON (no change). This only * works with connection-based streams. We know that there were no I/O event * when reaching this function. Timeouts and errors are *not* cleared. + * We might have been woken up as part of the confirmation of a full-stack + * connection setup (e.g. raw+PP+TLS+ALPN). It will then be our role to install + * a mux on this connection based on what ALPN could have been negotiated. */ void back_handle_st_con(struct stream *s) { @@ -1994,10 +1968,44 @@ void back_handle_st_con(struct stream *s) s->srv_error(s, si); /* Note: state = SI_ST_DIS now */ DBG_TRACE_STATE("client abort during connection attempt", STRM_EV_STRM_PROC|STRM_EV_SI_ST|STRM_EV_STRM_ERR, s); + goto end; } + /* first, let's see if we've made any progress on this connection */ + if (!conn->mux && (conn->flags & CO_FL_CONNECTED)) { + /* connection finished to set up */ + struct server *srv; + + if (conn->flags & CO_FL_ERROR) + goto fail; + si_detach_endpoint(&s->si[1]); + srv_cs = si_alloc_cs(&s->si[1], conn); + if (!srv_cs) + goto fail; + if (conn_install_mux_be(conn, srv_cs, s->sess) < 0) + goto fail; + srv = objt_server(s->target); + if (srv && ((s->be->options & PR_O_REUSE_MASK) != PR_O_REUSE_NEVR) && + conn->mux->avail_streams(conn) > 0) + LIST_ADD(&srv->idle_conns[tid], &conn->list); + goto done; + + fail: + si_detach_endpoint(&s->si[1]); + if (srv_cs) + cs_free(srv_cs); + /* kill the connection now */ + conn_stop_tracking(conn); + conn_full_close(conn); + conn_free(conn); + conn = NULL; + /* Let process_stream know it went wrong */ + s->si[1].flags |= SI_FL_ERR; + } + + done: /* retryable error ? */ - else if (si->flags & (SI_FL_EXP|SI_FL_ERR)) { + if (si->flags & (SI_FL_EXP|SI_FL_ERR)) { if (!(s->flags & SF_SRV_REUSED) && conn) { conn_stop_tracking(conn); conn_full_close(conn); @@ -2014,6 +2022,7 @@ void back_handle_st_con(struct stream *s) DBG_TRACE_STATE("connection failed, retry", STRM_EV_STRM_PROC|STRM_EV_SI_ST|STRM_EV_STRM_ERR, s); } + end: DBG_TRACE_LEAVE(STRM_EV_STRM_PROC|STRM_EV_SI_ST, s); } -- 2.39.5