/* These flags indicate whether the Control and Transport layers are initialized */
CO_FL_CTRL_READY = 0x00000100, /* FD was registered, fd_delete() needed */
- CO_FL_XPRT_READY = 0x00000200, /* xprt_init() done, xprt_close() needed */
+ CO_FL_XPRT_READY = 0x00000200, /* xprt_start() done, xprt can be used */
/* unused : 0x00000400 */
void (*shutw)(struct connection *conn, void *xprt_ctx, int); /* shutw function */
void (*close)(struct connection *conn, void *xprt_ctx); /* close the transport layer */
int (*init)(struct connection *conn, void **ctx); /* initialize the transport layer */
+ int (*start)(struct connection *conn, void *ctx); /* Start the transport layer, if needed */
int (*prepare_bind_conf)(struct bind_conf *conf); /* prepare a whole bind_conf */
void (*destroy_bind_conf)(struct bind_conf *conf); /* destroy a whole bind_conf */
int (*prepare_srv)(struct server *srv); /* prepare a server context */
extern struct idle_conns idle_conns[MAX_THREADS];
-/* returns true is the transport layer is ready */
+/* returns true if the transport layer is ready */
static inline int conn_xprt_ready(const struct connection *conn)
{
return (conn->flags & CO_FL_XPRT_READY);
}
-/* returns true is the control layer is ready */
+/* returns true if the control layer is ready */
static inline int conn_ctrl_ready(const struct connection *conn)
{
return (conn->flags & CO_FL_CTRL_READY);
}
-/* Calls the init() function of the transport layer if any and if not done yet,
- * and sets the CO_FL_XPRT_READY flag to indicate it was properly initialized.
- * Returns <0 in case of error.
- */
-static inline int conn_xprt_init(struct connection *conn)
+/*
+ * Calls the start() function of the transport layer, if needed.
+ * Returns < 0 in case of error.
+*/
+
+static inline int conn_xprt_start(struct connection *conn)
{
int ret = 0;
- if (!conn_xprt_ready(conn) && conn->xprt && conn->xprt->init)
- ret = conn->xprt->init(conn, &conn->xprt_ctx);
+ if (!conn_xprt_ready(conn) && conn->xprt && conn->xprt->start)
+ ret = conn->xprt->start(conn, conn->xprt_ctx);
if (ret >= 0)
conn->flags |= CO_FL_XPRT_READY;
}
/* Calls the close() function of the transport layer if any and if not done
- * yet, and clears the CO_FL_XPRT_READY flag. However this is not done if the
- * CO_FL_XPRT_TRACKED flag is set, which allows logs to take data from the
- * transport layer very late if needed.
+ * yet, and clears the CO_FL_XPRT_READY flags
+ * However this is not done if the CO_FL_XPRT_TRACKED flag is set,
+ * which allows logs to take data from the transport layer very late if needed.
*/
static inline void conn_xprt_close(struct connection *conn)
{
- if ((conn->flags & (CO_FL_XPRT_READY|CO_FL_XPRT_TRACKED)) == CO_FL_XPRT_READY) {
+ if (conn->xprt && !(conn->flags & CO_FL_XPRT_TRACKED)) {
if (conn->xprt->close)
conn->xprt->close(conn, conn->xprt_ctx);
conn->xprt_ctx = NULL;
conn->flags &= ~CO_FL_XPRT_READY;
+ conn->xprt = NULL;
}
}
*/
static inline void conn_ctrl_close(struct connection *conn)
{
- if ((conn->flags & (CO_FL_XPRT_READY|CO_FL_CTRL_READY)) == CO_FL_CTRL_READY) {
+ if (!conn->xprt && (conn->flags & CO_FL_CTRL_READY)) {
conn->flags &= ~CO_FL_CTRL_READY;
if (conn->ctrl->ctrl_close)
conn->ctrl->ctrl_close(conn);
* set prior to calling this function so that the function may make use of it
* in the future to refine the mux choice if needed.
*/
-static inline void conn_prepare(struct connection *conn, const struct protocol *proto, const struct xprt_ops *xprt)
+static inline int conn_prepare(struct connection *conn, const struct protocol *proto, const struct xprt_ops *xprt)
{
+ int ret = 0;
+
conn->ctrl = proto;
conn->xprt = xprt;
conn->mux = NULL;
conn->xprt_ctx = NULL;
conn->ctx = NULL;
+ if (xprt->init) {
+ ret = xprt->init(conn, &conn->xprt_ctx);
+ if (ret < 0)
+ conn->xprt = NULL;
+ }
+ return ret;
}
/*
conn->proxy_unique_id = IST_NULL;
conn->qc = NULL;
conn->hash_node = NULL;
+ conn->xprt = NULL;
}
static inline struct conn_hash_node *conn_alloc_hash_node(struct connection *conn)
static inline const char *conn_get_xprt_name(const struct connection *conn)
{
- if (!conn || !conn_xprt_ready(conn))
+ if (!conn || !conn->xprt)
return "NONE";
return conn->xprt->name;
}
/* Copy network namespace from client connection */
srv_conn->proxy_netns = cli_conn ? cli_conn->proxy_netns : NULL;
- if (!conn_xprt_ready(srv_conn) && !srv_conn->mux) {
+ if (!srv_conn->xprt) {
/* set the correct protocol on the output stream interface */
- if (srv)
- conn_prepare(srv_conn, protocol_by_family(srv_conn->dst->ss_family), srv->xprt);
- else if (obj_type(s->target) == OBJ_TYPE_PROXY) {
+ if (srv) {
+ if (conn_prepare(srv_conn, protocol_by_family(srv_conn->dst->ss_family), srv->xprt)) {
+ conn_free(srv_conn);
+ return SF_ERR_INTERNAL;
+ }
+ } else if (obj_type(s->target) == OBJ_TYPE_PROXY) {
+ int ret;
+
/* proxies exclusively run on raw_sock right now */
- conn_prepare(srv_conn, protocol_by_family(srv_conn->dst->ss_family), xprt_get(XPRT_RAW));
- if (!(srv_conn->ctrl)) {
+ ret = conn_prepare(srv_conn, protocol_by_family(srv_conn->dst->ss_family), xprt_get(XPRT_RAW));
+ if (ret < 0 || !(srv_conn->ctrl)) {
conn_free(srv_conn);
return SF_ERR_INTERNAL;
}
srv_conn->flags |= CO_FL_SOCKS4;
}
}
- else if (!conn_xprt_ready(srv_conn)) {
- if (srv_conn->mux->reset)
- srv_conn->mux->reset(srv_conn);
- }
else {
/* Currently there seems to be no known cases of xprt ready
* without the mux installed here.
return SF_ERR_INTERNAL;
}
}
+ conn_xprt_start(srv_conn);
/* We have to defer the mux initialization until after si_connect()
* has been called, as we need the xprt to have been properly
fd_cant_recv(fd);
}
- if (conn_xprt_init(conn) < 0) {
- conn_full_close(conn);
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_RESOURCE;
- }
-
return SF_ERR_NONE; /* connection is OK */
}
conn_ctrl_init(conn); /* registers the FD */
fdtab[fd].linger_risk = 0; /* no need to disable lingering */
- if (conn_xprt_init(conn) < 0) {
- conn_full_close(conn);
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_RESOURCE;
- }
-
return SF_ERR_NONE; /* connection is OK */
}
fd_cant_recv(fd);
}
- if (conn_xprt_init(conn) < 0) {
- conn_full_close(conn);
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_RESOURCE;
- }
-
return SF_ERR_NONE; /* connection is OK */
}
fd_cant_recv(fd);
}
- if (conn_xprt_init(conn) < 0) {
- conn_full_close(conn);
- conn->flags |= CO_FL_ERROR;
- return SF_ERR_RESOURCE;
- }
-
return SF_ERR_NONE; /* connection is OK */
}
struct session *sess;
cli_conn->proxy_netns = l->rx.settings->netns;
- conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt);
+ if (conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt) < 0)
+ goto out_free_conn;
/* This flag is ordinarily set by conn_ctrl_init() which cannot
* be called for now.
if (l->options & LI_O_ACC_CIP)
cli_conn->flags |= CO_FL_ACCEPT_CIP;
- if (conn_xprt_init(cli_conn) < 0)
- goto out_free_conn;
-
/* Add the handshake pseudo-XPRT */
if (cli_conn->flags & (CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP)) {
if (xprt_add_hs(cli_conn) != 0)
goto out_free_conn;
}
+
+ if (conn_xpt_start(cli_conn < 0))
+ goto out_free_conn;
+
sess = session_new(p, l, &cli_conn->obj_type);
if (!sess)
goto out_free_conn;
cli_conn->proxy_netns = l->rx.settings->netns;
- conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt);
+ if (conn_prepare(cli_conn, l->rx.proto, l->bind_conf->xprt) < 0)
+ goto out_free_conn;
+
conn_ctrl_init(cli_conn);
/* wait for a PROXY protocol header */
if (l->options & LI_O_ACC_CIP)
cli_conn->flags |= CO_FL_ACCEPT_CIP;
- if (conn_xprt_init(cli_conn) < 0)
- goto out_free_conn;
-
/* Add the handshake pseudo-XPRT */
if (cli_conn->flags & (CO_FL_ACCEPT_PROXY | CO_FL_ACCEPT_CIP)) {
if (xprt_add_hs(cli_conn) != 0)
ret = 0; /* successful termination */
goto out_free_sess;
}
+ /* TCP rules may flag the connection as needing proxy protocol, now that it's done we can start ourxprt */
+ if (conn_xprt_start(cli_conn) < 0)
+ goto out_free_conn;
/* Adjust some socket options */
if (l->rx.addr.ss_family == AF_INET || l->rx.addr.ss_family == AF_INET6) {
if (*xprt_ctx)
return 0;
- if (!conn_ctrl_ready(conn))
- return 0;
-
ctx = pool_alloc(ssl_sock_ctx_pool);
if (!ctx) {
conn->err_code = CO_ER_SSL_NO_MEM;
? xprt_get(XPRT_SSL)
: ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT) ? check->xprt : xprt_get(XPRT_RAW)));
- conn_prepare(conn, proto, xprt);
+ if (conn_prepare(conn, proto, xprt) < 0) {
+ status = SF_ERR_RESOURCE;
+ goto fail_check;
+ }
+
cs_attach(cs, check, &check_conn_cb);
if ((connect->options & TCPCHK_OPT_SOCKS4) && s && (s->flags & SRV_F_SOCKS4_PROXY)) {
status = SF_ERR_RESOURCE;
}
+ if (conn_xprt_start(conn) < 0) {
+ status = SF_ERR_RESOURCE;
+ goto fail_check;
+ }
+
/* The mux may be initialized now if there isn't server attached to the
* check (email alerts) or if there is a mux proto specified or if there
* is no alpn.
/* already initialized */
if (*xprt_ctx)
return 0;
- if (!conn_ctrl_ready(conn))
- return 0;
ctx = pool_alloc(xprt_handshake_ctx_pool);
if (!ctx) {
if (*xprt_ctx)
goto out;
- if (!conn_ctrl_ready(conn))
- goto out;
-
ctx = pool_alloc(pool_head_quic_conn_ctx);
if (!ctx) {
conn->err_code = CO_ER_SYS_MEMLIM;