MAJOR: stream-int: stop using si->conn and use si->end instead

The connection will only remain there as a pre-allocated entity whose
goal is to be placed in ->end when establishing an outgoing connection.
All connection initialization can be made on this connection, but all
information retrieved should be applied to the end point only.

This change is huge because there were many users of si->conn. Now the
only users are those who initialize the new connection. The difficulty
appears in a few places such as backend.c, proto_http.c, peers.c where
si->conn is used to hold the connection's target address before assigning
the connection to the stream interface. This is why we have to keep
si->conn for now. A future improvement might consist in dynamically
allocating the connection when it is needed.
diff --git a/src/backend.c b/src/backend.c
index 63bd368..65cbcb6 100644
--- a/src/backend.c
+++ b/src/backend.c
@@ -505,7 +505,7 @@
 
 int assign_server(struct session *s)
 {
-
+	struct connection *conn;
 	struct server *conn_slot;
 	struct server *srv, *prev_srv;
 	int err;
@@ -574,14 +574,15 @@
 
 			switch (s->be->lbprm.algo & BE_LB_PARM) {
 			case BE_LB_HASH_SRC:
-				if (s->req->prod->conn->addr.from.ss_family == AF_INET) {
+				conn = objt_conn(s->req->prod->end);
+				if (conn && conn->addr.from.ss_family == AF_INET) {
 					srv = get_server_sh(s->be,
-							    (void *)&((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr,
+							    (void *)&((struct sockaddr_in *)&conn->addr.from)->sin_addr,
 							    4);
 				}
-				else if (s->req->prod->conn->addr.from.ss_family == AF_INET6) {
+				else if (conn && conn->addr.from.ss_family == AF_INET6) {
 					srv = get_server_sh(s->be,
-							    (void *)&((struct sockaddr_in6 *)&s->req->prod->conn->addr.from)->sin6_addr,
+							    (void *)&((struct sockaddr_in6 *)&conn->addr.from)->sin6_addr,
 							    16);
 				}
 				else {
@@ -664,7 +665,8 @@
 		s->target = &s->be->obj_type;
 	}
 	else if ((s->be->options & PR_O_HTTP_PROXY) &&
-		 is_addr(&s->req->cons->conn->addr.to)) {
+		 (conn = objt_conn(s->req->cons->end)) &&
+		 is_addr(&conn->addr.to)) {
 		/* in proxy mode, we need a valid destination address */
 		s->target = &s->be->obj_type;
 	}
@@ -706,9 +708,15 @@
  * Upon successful return, the session flag SN_ADDR_SET is set. This flag is
  * not cleared, so it's to the caller to clear it if required.
  *
+ * The address is set on si->conn only. This connection is expected to be
+ * already allocated and initialized.
+ *
  */
 int assign_server_address(struct session *s)
 {
+	struct connection *cli_conn = objt_conn(s->req->prod->end);
+	struct connection *srv_conn = s->req->cons->conn;
+
 #ifdef DEBUG_FULL
 	fprintf(stderr,"assign_server_address : s=%p\n",s);
 #endif
@@ -718,51 +726,47 @@
 		if (!(s->flags & SN_ASSIGNED))
 			return SRV_STATUS_INTERNAL;
 
-		s->req->cons->conn->addr.to = objt_server(s->target)->addr;
+		srv_conn->addr.to = objt_server(s->target)->addr;
 
-		if (!is_addr(&s->req->cons->conn->addr.to)) {
+		if (!is_addr(&srv_conn->addr.to) && cli_conn) {
 			/* if the server has no address, we use the same address
 			 * the client asked, which is handy for remapping ports
 			 * locally on multiple addresses at once.
 			 */
-			conn_get_to_addr(s->req->prod->conn);
+			conn_get_to_addr(cli_conn);
 
-			if (s->req->prod->conn->addr.to.ss_family == AF_INET) {
-				((struct sockaddr_in *)&s->req->cons->conn->addr.to)->sin_addr = ((struct sockaddr_in *)&s->req->prod->conn->addr.to)->sin_addr;
-			} else if (s->req->prod->conn->addr.to.ss_family == AF_INET6) {
-				((struct sockaddr_in6 *)&s->req->cons->conn->addr.to)->sin6_addr = ((struct sockaddr_in6 *)&s->req->prod->conn->addr.to)->sin6_addr;
+			if (cli_conn->addr.to.ss_family == AF_INET) {
+				((struct sockaddr_in *)&srv_conn->addr.to)->sin_addr = ((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr;
+			} else if (cli_conn->addr.to.ss_family == AF_INET6) {
+				((struct sockaddr_in6 *)&srv_conn->addr.to)->sin6_addr = ((struct sockaddr_in6 *)&cli_conn->addr.to)->sin6_addr;
 			}
 		}
 
 		/* if this server remaps proxied ports, we'll use
 		 * the port the client connected to with an offset. */
-		if (objt_server(s->target)->state & SRV_MAPPORTS) {
+		if ((objt_server(s->target)->state & SRV_MAPPORTS) && cli_conn) {
 			int base_port;
 
-			conn_get_to_addr(s->req->prod->conn);
+			conn_get_to_addr(cli_conn);
 
 			/* First, retrieve the port from the incoming connection */
-			base_port = get_host_port(&s->req->prod->conn->addr.to);
+			base_port = get_host_port(&cli_conn->addr.to);
 
 			/* Second, assign the outgoing connection's port */
-			base_port += get_host_port(&s->req->cons->conn->addr.to);
-			set_host_port(&s->req->cons->conn->addr.to, base_port);
+			base_port += get_host_port(&srv_conn->addr.to);
+			set_host_port(&srv_conn->addr.to, base_port);
 		}
 	}
 	else if (s->be->options & PR_O_DISPATCH) {
 		/* connect to the defined dispatch addr */
-		s->req->cons->conn->addr.to = s->be->dispatch_addr;
+		srv_conn->addr.to = s->be->dispatch_addr;
 	}
-	else if (s->be->options & PR_O_TRANSP) {
+	else if ((s->be->options & PR_O_TRANSP) && cli_conn) {
 		/* in transparent mode, use the original dest addr if no dispatch specified */
-		conn_get_to_addr(s->req->prod->conn);
+		conn_get_to_addr(cli_conn);
 
-		if (s->req->prod->conn->addr.to.ss_family == AF_INET || s->req->prod->conn->addr.to.ss_family == AF_INET6) {
-			memcpy(&s->req->cons->conn->addr.to, &s->req->prod->conn->addr.to, MIN(sizeof(s->req->cons->conn->addr.to), sizeof(s->req->prod->conn->addr.to)));
-		}
-		/* when we support IPv6 on the backend, we may add other tests */
-		//qfprintf(stderr, "Cannot get original server address.\n");
-		//return SRV_STATUS_INTERNAL;
+		if (cli_conn->addr.to.ss_family == AF_INET || cli_conn->addr.to.ss_family == AF_INET6)
+			srv_conn->addr.to = cli_conn->addr.to;
 	}
 	else if (s->be->options & PR_O_HTTP_PROXY) {
 		/* If HTTP PROXY option is set, then server is already assigned
@@ -902,13 +906,16 @@
 
 /* If an explicit source binding is specified on the server and/or backend, and
  * this source makes use of the transparent proxy, then it is extracted now and
- * assigned to the session's req->cons->addr.from entry.
+ * assigned to the session's pending connection. This function assumes that an
+ * outgoing connection has already been allocated into s->req->cons->conn.
  */
 static void assign_tproxy_address(struct session *s)
 {
 #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_TRANSPARENT)
 	struct server *srv = objt_server(s->target);
 	struct conn_src *src;
+	struct connection *cli_conn;
+	struct connection *srv_conn = s->req->cons->conn;
 
 	if (srv && srv->conn_src.opts & CO_SRC_BIND)
 		src = &srv->conn_src;
@@ -919,12 +926,16 @@
 
 	switch (src->opts & CO_SRC_TPROXY_MASK) {
 	case CO_SRC_TPROXY_ADDR:
-		s->req->cons->conn->addr.from = src->tproxy_addr;
+		srv_conn->addr.from = src->tproxy_addr;
 		break;
 	case CO_SRC_TPROXY_CLI:
 	case CO_SRC_TPROXY_CIP:
 		/* FIXME: what can we do if the client connects in IPv6 or unix socket ? */
-		s->req->cons->conn->addr.from = s->req->prod->conn->addr.from;
+		cli_conn = objt_conn(s->req->prod->end);
+		if (cli_conn)
+			srv_conn->addr.from = cli_conn->addr.from;
+		else
+			memset(&srv_conn->addr.from, 0, sizeof(srv_conn->addr.from));
 		break;
 	case CO_SRC_TPROXY_DYN:
 		if (src->bind_hdr_occ) {
@@ -933,21 +944,21 @@
 			int rewind;
 
 			/* bind to the IP in a header */
-			((struct sockaddr_in *)&s->req->cons->conn->addr.from)->sin_family = AF_INET;
-			((struct sockaddr_in *)&s->req->cons->conn->addr.from)->sin_port = 0;
-			((struct sockaddr_in *)&s->req->cons->conn->addr.from)->sin_addr.s_addr = 0;
+			((struct sockaddr_in *)&srv_conn->addr.from)->sin_family = AF_INET;
+			((struct sockaddr_in *)&srv_conn->addr.from)->sin_port = 0;
+			((struct sockaddr_in *)&srv_conn->addr.from)->sin_addr.s_addr = 0;
 
 			b_rew(s->req->buf, rewind = s->req->buf->o);
 			if (http_get_hdr(&s->txn.req, src->bind_hdr_name, src->bind_hdr_len,
 					 &s->txn.hdr_idx, src->bind_hdr_occ, NULL, &vptr, &vlen)) {
-				((struct sockaddr_in *)&s->req->cons->conn->addr.from)->sin_addr.s_addr =
+				((struct sockaddr_in *)&srv_conn->addr.from)->sin_addr.s_addr =
 					htonl(inetaddr_host_lim(vptr, vptr + vlen));
 			}
 			b_adv(s->req->buf, rewind);
 		}
 		break;
 	default:
-		memset(&s->req->cons->conn->addr.from, 0, sizeof(s->req->cons->conn->addr.from));
+		memset(&srv_conn->addr.from, 0, sizeof(srv_conn->addr.from));
 	}
 #endif
 }
@@ -965,9 +976,13 @@
  *  - 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.
+ * The server-facing stream interface is expected to hold a pre-allocated connection
+ * in s->req->cons->conn.
  */
 int connect_server(struct session *s)
 {
+	struct connection *cli_conn;
+	struct connection *srv_conn = s->req->cons->conn;
 	struct server *srv;
 	int err;
 
@@ -978,7 +993,7 @@
 	}
 
 	/* the target was only on the session, assign it to the SI now */
-	s->req->cons->conn->target = s->target;
+	srv_conn->target = s->target;
 
 	/* set the correct protocol on the output stream interface */
 	if (objt_server(s->target)) {
@@ -986,8 +1001,8 @@
 	}
 	else if (obj_type(s->target) == OBJ_TYPE_PROXY) {
 		/* proxies exclusively run on raw_sock right now */
-		si_prepare_conn(s->req->cons, protocol_by_family(s->req->cons->conn->addr.to.ss_family), &raw_sock);
-		if (!s->req->cons->conn->ctrl)
+		si_prepare_conn(s->req->cons, protocol_by_family(srv_conn->addr.to.ss_family), &raw_sock);
+		if (!objt_conn(s->req->cons->end) || !objt_conn(s->req->cons->end)->ctrl)
 			return SN_ERR_INTERNAL;
 	}
 	else
@@ -997,7 +1012,9 @@
 	s->req->cons->send_proxy_ofs = 0;
 	if (objt_server(s->target) && (objt_server(s->target)->state & SRV_SEND_PROXY)) {
 		s->req->cons->send_proxy_ofs = 1; /* must compute size */
-		conn_get_to_addr(s->req->prod->conn);
+		cli_conn = objt_conn(s->req->prod->end);
+		if (cli_conn)
+			conn_get_to_addr(cli_conn);
 	}
 
 	assign_tproxy_address(s);
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 629bf96..6703b9b 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -151,7 +151,7 @@
 extern const char *stat_status_codes[];
 
 /* This function is called from the session-level accept() in order to instanciate
- * a new stats socket. It returns a positive value upon success, 0 if the connection
+ * a new stats socket. It returns a positive value upon success, 0 if the session
  * needs to be closed and ignored, or a negative value upon critical failure.
  */
 static int stats_accept(struct session *s)
@@ -3881,6 +3881,7 @@
 	struct tm tm;
 	extern const char *monthname[12];
 	char pn[INET6_ADDRSTRLEN];
+	struct connection *conn;
 
 	chunk_reset(&trash);
 
@@ -3910,12 +3911,12 @@
 			     sess->uniq_id,
 			     sess->listener && sess->listener->proto->name ? sess->listener->proto->name : "?");
 
-		switch ((obj_type(sess->si[0].end) == OBJ_TYPE_CONN) ?
-			addr_to_str(&sess->si[0].conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
+		conn = objt_conn(sess->si[0].end);
+		switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_appendf(&trash, " source=%s:%d\n",
-				     pn, get_host_port(&sess->si[0].conn->addr.from));
+			              pn, get_host_port(&conn->addr.from));
 			break;
 		case AF_UNIX:
 			chunk_appendf(&trash, " source=unix:%d\n", sess->listener->luid);
@@ -3936,15 +3937,14 @@
 			     sess->listener ? sess->listener->name ? sess->listener->name : "?" : "?",
 			     sess->listener ? sess->listener->luid : 0);
 
-		if (obj_type(sess->si[0].end) == OBJ_TYPE_CONN)
-			conn_get_to_addr(sess->si[0].conn);
+		if (conn)
+			conn_get_to_addr(conn);
 
-		switch ((obj_type(sess->si[0].end) == OBJ_TYPE_CONN) ?
-			addr_to_str(&sess->si[0].conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
+		switch (conn ? addr_to_str(&conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_appendf(&trash, " addr=%s:%d\n",
-				     pn, get_host_port(&sess->si[0].conn->addr.to));
+				     pn, get_host_port(&conn->addr.to));
 			break;
 		case AF_UNIX:
 			chunk_appendf(&trash, " addr=unix:%d\n", sess->listener->luid);
@@ -3963,15 +3963,15 @@
 		else
 			chunk_appendf(&trash, "  backend=<NONE> (id=-1 mode=-)");
 
-		if (obj_type(sess->si[1].end) == OBJ_TYPE_CONN)
-			conn_get_from_addr(sess->si[1].conn);
+		conn = objt_conn(sess->si[1].end);
+		if (conn)
+			conn_get_from_addr(conn);
 
-		switch ((obj_type(sess->si[1].end) == OBJ_TYPE_CONN) ?
-			addr_to_str(&sess->si[1].conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
+		switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_appendf(&trash, " addr=%s:%d\n",
-				     pn, get_host_port(&sess->si[1].conn->addr.from));
+				     pn, get_host_port(&conn->addr.from));
 			break;
 		case AF_UNIX:
 			chunk_appendf(&trash, " addr=unix\n");
@@ -3990,15 +3990,14 @@
 		else
 			chunk_appendf(&trash, "  server=<NONE> (id=-1)");
 
-		if (obj_type(sess->si[1].end) == OBJ_TYPE_CONN)
-			conn_get_to_addr(sess->si[1].conn);
+		if (conn)
+			conn_get_to_addr(conn);
 
-		switch ((obj_type(sess->si[1].end) == OBJ_TYPE_CONN) ?
-			addr_to_str(&sess->si[1].conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
+		switch (conn ? addr_to_str(&conn->addr.to, pn, sizeof(pn)) : AF_UNSPEC) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_appendf(&trash, " addr=%s:%d\n",
-				     pn, get_host_port(&sess->si[1].conn->addr.to));
+				     pn, get_host_port(&conn->addr.to));
 			break;
 		case AF_UNIX:
 			chunk_appendf(&trash, " addr=unix\n");
@@ -4057,42 +4056,44 @@
 			                     TICKS_TO_MS(1000)) : "<NEVER>",
 			     sess->si[1].err_type);
 
-		if (obj_type(sess->si[0].end) == OBJ_TYPE_CONN) {
+		conn = objt_conn(sess->si[0].end);
+		if (conn) {
 			chunk_appendf(&trash,
 			              "  co0=%p ctrl=%s xprt=%s data=%s target=%s:%p\n",
-				      sess->si[0].conn,
-				      get_conn_ctrl_name(sess->si[0].conn),
-				      get_conn_xprt_name(sess->si[0].conn),
-				      get_conn_data_name(sess->si[0].conn),
-			              obj_type_name(sess->si[0].conn->target),
-			              obj_base_ptr(sess->si[0].conn->target));
+				      conn,
+				      get_conn_ctrl_name(conn),
+				      get_conn_xprt_name(conn),
+				      get_conn_data_name(conn),
+			              obj_type_name(conn->target),
+			              obj_base_ptr(conn->target));
 
 			chunk_appendf(&trash,
 			              "      flags=0x%08x fd=%d fd_spec_e=%02x fd_spec_p=%d updt=%d\n",
-			              sess->si[0].conn->flags,
-			              sess->si[0].conn->t.sock.fd,
-			              sess->si[0].conn->t.sock.fd >= 0 ? fdtab[sess->si[0].conn->t.sock.fd].spec_e : 0,
-			              sess->si[0].conn->t.sock.fd >= 0 ? fdtab[sess->si[0].conn->t.sock.fd].spec_p : 0,
-			              sess->si[0].conn->t.sock.fd >= 0 ? fdtab[sess->si[0].conn->t.sock.fd].updated : 0);
+			              conn->flags,
+			              conn->t.sock.fd,
+			              conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].spec_e : 0,
+			              conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].spec_p : 0,
+			              conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].updated : 0);
 		}
 
-		if (obj_type(sess->si[1].end) == OBJ_TYPE_CONN) {
+		conn = objt_conn(sess->si[1].end);
+		if (conn) {
 			chunk_appendf(&trash,
 			              "  co1=%p ctrl=%s xprt=%s data=%s target=%s:%p\n",
-				      sess->si[1].conn,
-				      get_conn_ctrl_name(sess->si[1].conn),
-				      get_conn_xprt_name(sess->si[1].conn),
-				      get_conn_data_name(sess->si[1].conn),
-			              obj_type_name(sess->si[1].conn->target),
-			              obj_base_ptr(sess->si[1].conn->target));
+				      conn,
+				      get_conn_ctrl_name(conn),
+				      get_conn_xprt_name(conn),
+				      get_conn_data_name(conn),
+			              obj_type_name(conn->target),
+			              obj_base_ptr(conn->target));
 
 			chunk_appendf(&trash,
 			              "      flags=0x%08x fd=%d fd_spec_e=%02x fd_spec_p=%d updt=%d\n",
-			              sess->si[1].conn->flags,
-			              sess->si[1].conn->t.sock.fd,
-			              sess->si[1].conn->t.sock.fd >= 0 ? fdtab[sess->si[1].conn->t.sock.fd].spec_e : 0,
-			              sess->si[1].conn->t.sock.fd >= 0 ? fdtab[sess->si[1].conn->t.sock.fd].spec_p : 0,
-			              sess->si[1].conn->t.sock.fd >= 0 ? fdtab[sess->si[1].conn->t.sock.fd].updated : 0);
+			              conn->flags,
+			              conn->t.sock.fd,
+			              conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].spec_e : 0,
+			              conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].spec_p : 0,
+			              conn->t.sock.fd >= 0 ? fdtab[conn->t.sock.fd].updated : 0);
 		}
 
 		chunk_appendf(&trash,
@@ -4171,6 +4172,8 @@
  */
 static int stats_dump_sess_to_buffer(struct stream_interface *si)
 {
+	struct connection *conn;
+
 	if (unlikely(si->ib->flags & (CF_WRITE_ERROR|CF_SHUTW))) {
 		/* If we're forced to shut down, we might have to remove our
 		 * reference to the last session being dumped.
@@ -4240,14 +4243,14 @@
 				     curr_sess->listener->proto->name);
 
 
-			switch ((obj_type(curr_sess->si[0].end) == OBJ_TYPE_CONN) ?
-				addr_to_str(&curr_sess->si[0].conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
+			conn = objt_conn(curr_sess->si[0].end);
+			switch (conn ? addr_to_str(&conn->addr.from, pn, sizeof(pn)) : AF_UNSPEC) {
 			case AF_INET:
 			case AF_INET6:
 				chunk_appendf(&trash,
 					     " src=%s:%d fe=%s be=%s srv=%s",
 					     pn,
-					     get_host_port(&curr_sess->si[0].conn->addr.from),
+					     get_host_port(&conn->addr.from),
 					     curr_sess->fe->id,
 					     (curr_sess->be->cap & PR_CAP_BE) ? curr_sess->be->id : "<NONE>",
 					     objt_server(curr_sess->target) ? objt_server(curr_sess->target)->id : "<none>"
@@ -4312,22 +4315,22 @@
 				     human_time(TICKS_TO_MS(curr_sess->rep->analyse_exp - now_ms),
 						TICKS_TO_MS(1000)) : "");
 
+			conn = objt_conn(curr_sess->si[0].end);
 			chunk_appendf(&trash,
 				     " s0=[%d,%1xh,fd=%d,ex=%s]",
 				     curr_sess->si[0].state,
 				     curr_sess->si[0].flags,
-				     (obj_type(curr_sess->si[0].end) == OBJ_TYPE_CONN) ?
-				      curr_sess->si[0].conn->t.sock.fd : -1,
+				     conn ? conn->t.sock.fd : -1,
 				     curr_sess->si[0].exp ?
 				     human_time(TICKS_TO_MS(curr_sess->si[0].exp - now_ms),
 						TICKS_TO_MS(1000)) : "");
 
+			conn = objt_conn(curr_sess->si[1].end);
 			chunk_appendf(&trash,
 				     " s1=[%d,%1xh,fd=%d,ex=%s]",
 				     curr_sess->si[1].state,
 				     curr_sess->si[1].flags,
-				     (obj_type(curr_sess->si[1].end) == OBJ_TYPE_CONN) ?
-				      curr_sess->si[1].conn->t.sock.fd : -1,
+				     conn ? conn->t.sock.fd : -1,
 				     curr_sess->si[1].exp ?
 				     human_time(TICKS_TO_MS(curr_sess->si[1].exp - now_ms),
 						TICKS_TO_MS(1000)) : "");
diff --git a/src/frontend.c b/src/frontend.c
index 1048052..8a01a4a 100644
--- a/src/frontend.c
+++ b/src/frontend.c
@@ -49,11 +49,13 @@
 /* Finish a session accept() for a proxy (TCP or HTTP). It returns a negative
  * value in case of a critical failure which must cause the listener to be
  * disabled, a positive value in case of success, or zero if it is a success
- * but the session must be closed ASAP (eg: monitoring).
+ * but the session must be closed ASAP (eg: monitoring). It only supports
+ * sessions with a connection in si[0].
  */
 int frontend_accept(struct session *s)
 {
-	int cfd = s->si[0].conn->t.sock.fd;
+	struct connection *conn = __objt_conn(s->si[0].end);
+	int cfd = conn->t.sock.fd;
 
 	tv_zero(&s->logs.tv_request);
 	s->logs.t_queue = -1;
@@ -140,16 +142,16 @@
 		else {
 			char pn[INET6_ADDRSTRLEN], sn[INET6_ADDRSTRLEN];
 
-			conn_get_from_addr(s->req->prod->conn);
-			conn_get_to_addr(s->req->prod->conn);
+			conn_get_from_addr(conn);
+			conn_get_to_addr(conn);
 
-			switch (addr_to_str(&s->req->prod->conn->addr.from, pn, sizeof(pn))) {
+			switch (addr_to_str(&conn->addr.from, pn, sizeof(pn))) {
 			case AF_INET:
 			case AF_INET6:
-				addr_to_str(&s->req->prod->conn->addr.to, sn, sizeof(sn));
+				addr_to_str(&conn->addr.to, sn, sizeof(sn));
 				send_log(s->fe, LOG_INFO, "Connect from %s:%d to %s:%d (%s/%s)\n",
-					 pn, get_host_port(&s->req->prod->conn->addr.from),
-					 sn, get_host_port(&s->req->prod->conn->addr.to),
+					 pn, get_host_port(&conn->addr.from),
+					 sn, get_host_port(&conn->addr.to),
 					 s->fe->id, (s->fe->mode == PR_MODE_HTTP) ? "HTTP" : "TCP");
 				break;
 			case AF_UNIX:
@@ -165,14 +167,14 @@
 	if (unlikely((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
 		char pn[INET6_ADDRSTRLEN];
 
-		conn_get_from_addr(s->req->prod->conn);
+		conn_get_from_addr(conn);
 
-		switch (addr_to_str(&s->req->prod->conn->addr.from, pn, sizeof(pn))) {
+		switch (addr_to_str(&conn->addr.from, pn, sizeof(pn))) {
 		case AF_INET:
 		case AF_INET6:
 			chunk_printf(&trash, "%08x:%s.accept(%04x)=%04x from [%s:%d]\n",
 			             s->uniq_id, s->fe->id, (unsigned short)s->listener->fd, (unsigned short)cfd,
-			             pn, get_host_port(&s->req->prod->conn->addr.from));
+			             pn, get_host_port(&conn->addr.from));
 			break;
 		case AF_UNIX:
 			/* UNIX socket, only the destination is known */
diff --git a/src/log.c b/src/log.c
index 69e495b..ef89dd3 100644
--- a/src/log.c
+++ b/src/log.c
@@ -935,6 +935,7 @@
 		return 0;
 
 	list_for_each_entry(tmp, list_format, list) {
+		struct connection *conn;
 		const char *src = NULL;
 		struct sample *key;
 
@@ -969,8 +970,11 @@
 				break;
 
 			case LOG_FMT_CLIENTIP:  // %ci
-				ret = lf_ip(tmplog, (struct sockaddr *)&s->req->prod->conn->addr.from,
-					    dst + maxsize - tmplog, tmp);
+				conn = objt_conn(s->req->prod->end);
+				if (conn)
+					ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.from, dst + maxsize - tmplog, tmp);
+				else
+					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
 				if (ret == NULL)
 					goto out;
 				tmplog = ret;
@@ -978,12 +982,18 @@
 				break;
 
 			case LOG_FMT_CLIENTPORT:  // %cp
-				if (s->req->prod->conn->addr.from.ss_family == AF_UNIX) {
-					ret = ltoa_o(s->listener->luid, tmplog, dst + maxsize - tmplog);
-				} else {
-					ret = lf_port(tmplog, (struct sockaddr *)&s->req->prod->conn->addr.from,
-						      dst + maxsize - tmplog, tmp);
+				conn = objt_conn(s->req->prod->end);
+				if (conn) {
+					if (conn->addr.from.ss_family == AF_UNIX) {
+						ret = ltoa_o(s->listener->luid, tmplog, dst + maxsize - tmplog);
+					} else {
+						ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.from,
+						              dst + maxsize - tmplog, tmp);
+					}
 				}
+				else
+					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
+
 				if (ret == NULL)
 					goto out;
 				tmplog = ret;
@@ -991,9 +1001,14 @@
 				break;
 
 			case LOG_FMT_FRONTENDIP: // %fi
-				conn_get_to_addr(s->req->prod->conn);
-				ret = lf_ip(tmplog, (struct sockaddr *)&s->req->prod->conn->addr.to,
-					    dst + maxsize - tmplog, tmp);
+				conn = objt_conn(s->req->prod->end);
+				if (conn) {
+					conn_get_to_addr(conn);
+					ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
+				}
+				else
+					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
+
 				if (ret == NULL)
 					goto out;
 				tmplog = ret;
@@ -1001,14 +1016,17 @@
 				break;
 
 			case  LOG_FMT_FRONTENDPORT: // %fp
-				conn_get_to_addr(s->req->prod->conn);
-				if (s->req->prod->conn->addr.to.ss_family == AF_UNIX) {
-					ret = ltoa_o(s->listener->luid,
-						     tmplog, dst + maxsize - tmplog);
-				} else {
-					ret = lf_port(tmplog, (struct sockaddr *)&s->req->prod->conn->addr.to,
-						      dst + maxsize - tmplog, tmp);
+				conn = objt_conn(s->req->prod->end);
+				if (conn) {
+					conn_get_to_addr(conn);
+					if (conn->addr.to.ss_family == AF_UNIX)
+						ret = ltoa_o(s->listener->luid, tmplog, dst + maxsize - tmplog);
+					else
+						ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
 				}
+				else
+					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
+
 				if (ret == NULL)
 					goto out;
 				tmplog = ret;
@@ -1016,8 +1034,12 @@
 				break;
 
 			case LOG_FMT_BACKENDIP:  // %bi
-				ret = lf_ip(tmplog, (struct sockaddr *)&s->req->cons->conn->addr.from,
-					    dst + maxsize - tmplog, tmp);
+				conn = objt_conn(s->req->cons->end);
+				if (conn)
+					ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.from, dst + maxsize - tmplog, tmp);
+				else
+					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
+
 				if (ret == NULL)
 					goto out;
 				tmplog = ret;
@@ -1025,8 +1047,12 @@
 				break;
 
 			case LOG_FMT_BACKENDPORT:  // %bp
-				ret = lf_port(tmplog, (struct sockaddr *)&s->req->cons->conn->addr.from,
-					      dst + maxsize - tmplog, tmp);
+				conn = objt_conn(s->req->cons->end);
+				if (conn)
+					ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.from, dst + maxsize - tmplog, tmp);
+				else
+					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
+
 				if (ret == NULL)
 					goto out;
 				tmplog = ret;
@@ -1034,8 +1060,12 @@
 				break;
 
 			case LOG_FMT_SERVERIP: // %si
-				ret = lf_ip(tmplog, (struct sockaddr *)&s->req->cons->conn->addr.to,
-					    dst + maxsize - tmplog, tmp);
+				conn = objt_conn(s->req->cons->end);
+				if (conn)
+					ret = lf_ip(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
+				else
+					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
+
 				if (ret == NULL)
 					goto out;
 				tmplog = ret;
@@ -1043,8 +1073,12 @@
 				break;
 
 			case LOG_FMT_SERVERPORT: // %sp
-				ret = lf_port(tmplog, (struct sockaddr *)&s->req->cons->conn->addr.to,
-					      dst + maxsize - tmplog, tmp);
+				conn = objt_conn(s->req->cons->end);
+				if (conn)
+					ret = lf_port(tmplog, (struct sockaddr *)&conn->addr.to, dst + maxsize - tmplog, tmp);
+				else
+					ret = lf_text_len(tmplog, NULL, 0, dst + maxsize - tmplog, tmp);
+
 				if (ret == NULL)
 					goto out;
 				tmplog = ret;
@@ -1143,8 +1177,11 @@
 #ifdef USE_OPENSSL
 			case LOG_FMT_SSL_CIPHER: // %sslc
 				src = NULL;
-				if (s->listener->xprt == &ssl_sock)
-					src = ssl_sock_get_cipher_name(s->si[0].conn);
+				conn = objt_conn(s->si[0].end);
+				if (conn) {
+					if (s->listener->xprt == &ssl_sock)
+						src = ssl_sock_get_cipher_name(conn);
+				}
 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
 				if (ret == NULL)
 					goto out;
@@ -1154,8 +1191,11 @@
 
 			case LOG_FMT_SSL_VERSION: // %sslv
 				src = NULL;
-				if (s->listener->xprt == &ssl_sock)
-					src = ssl_sock_get_proto_version(s->si[0].conn);
+				conn = objt_conn(s->si[0].end);
+				if (conn) {
+					if (s->listener->xprt == &ssl_sock)
+						src = ssl_sock_get_proto_version(conn);
+				}
 				ret = lf_text(tmplog, src, dst + maxsize - tmplog, tmp);
 				if (ret == NULL)
 					goto out;
diff --git a/src/peers.c b/src/peers.c
index d265f48..40936e4 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -1076,11 +1076,10 @@
 	task_wakeup(session->task, TASK_WOKEN_MSG);
 }
 
-/*
- * this function is called on a read event from a listen socket, corresponding
- * to an accept. It tries to accept as many connections as possible.
- * It returns a positive value upon success, 0 if the connection needs to be
- * closed and ignored, or a negative value upon critical failure.
+/* Finish a session accept() for a peer. It returns a negative value in case of
+ * a critical failure which must cause the listener to be disabled, a positive
+ * value in case of success, or zero if it is a success but the session must be
+ * closed ASAP and ignored.
  */
 int peer_accept(struct session *s)
 {
@@ -1162,15 +1161,17 @@
 
 	s->req = s->rep = NULL; /* will be allocated later */
 
+	/* si[0] is the applet, we should not need s->si[0].conn anymore soon */
 	s->si[0].conn->obj_type = OBJ_TYPE_CONN;
 	s->si[0].conn->t.sock.fd = -1;
 	s->si[0].conn->flags = CO_FL_NONE;
 	s->si[0].conn->err_code = CO_ER_NONE;
+	s->si[0].conn->target = &l->obj_type;
+
 	s->si[0].owner = t;
 	s->si[0].state = s->si[0].prev_state = SI_ST_EST;
 	s->si[0].err_type = SI_ET_NONE;
 	s->si[0].send_proxy_ofs = 0;
-	s->si[0].conn->target = &l->obj_type;
 	s->si[0].exp = TICK_ETERNITY;
 	s->si[0].flags = SI_FL_NONE;
 	if (s->fe->options2 & PR_O2_INDEPSTR)
@@ -1184,18 +1185,23 @@
 	s->si[1].conn->t.sock.fd = -1; /* just to help with debugging */
 	s->si[1].conn->flags = CO_FL_NONE;
 	s->si[1].conn->err_code = CO_ER_NONE;
+	s->si[1].conn->target = &s->be->obj_type;
+
 	s->si[1].owner = t;
 	s->si[1].state = s->si[1].prev_state = SI_ST_ASS;
 	s->si[1].conn_retries = p->conn_retries;
 	s->si[1].err_type = SI_ET_NONE;
 	s->si[1].send_proxy_ofs = 0;
-	s->si[1].conn->target = &s->be->obj_type;
-	si_prepare_conn(&s->si[1], peer->proto, peer->xprt);
 	s->si[1].exp = TICK_ETERNITY;
 	s->si[1].flags = SI_FL_NONE;
 	if (s->be->options2 & PR_O2_INDEPSTR)
 		s->si[1].flags |= SI_FL_INDEP_STR;
 
+	/* will automatically prepare the stream interface to connect to the
+	 * pre-initialized connection in si->conn.
+	 */
+	si_prepare_conn(&s->si[1], peer->proto, peer->xprt);
+
 	session_init_srv_conn(s);
 	s->target = &s->be->obj_type;
 	s->pend_pos = NULL;
diff --git a/src/proto_http.c b/src/proto_http.c
index 94cf352..af96f41 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -2488,12 +2488,12 @@
 		req->flags |= CF_READ_DONTWAIT; /* try to get back here ASAP */
 		s->rep->flags &= ~CF_EXPECT_MORE; /* speed up sending a previous response */
 #ifdef TCP_QUICKACK
-		if (s->listener->options & LI_O_NOQUICKACK && req->buf->i) {
+		if (s->listener->options & LI_O_NOQUICKACK && req->buf->i && objt_conn(s->req->prod->end)) {
 			/* We need more data, we have to re-enable quick-ack in case we
 			 * previously disabled it, otherwise we might cause the client
 			 * to delay next data.
 			 */
-			setsockopt(s->si[0].conn->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
+			setsockopt(__objt_conn(s->req->prod->end)->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
 		}
 #endif
 
@@ -2969,6 +2969,7 @@
 static struct http_req_rule *
 http_req_get_intercept_rule(struct proxy *px, struct list *rules, struct session *s, struct http_txn *txn)
 {
+	struct connection *cli_conn;
 	struct http_req_rule *rule;
 	struct hdr_ctx ctx;
 
@@ -3014,12 +3015,14 @@
 			break;
 
 		case HTTP_REQ_ACT_SET_TOS:
-			inet_set_tos(s->req->prod->conn->t.sock.fd, s->req->prod->conn->addr.from, rule->arg.tos);
+			if ((cli_conn = objt_conn(s->req->prod->end)))
+				inet_set_tos(cli_conn->t.sock.fd, cli_conn->addr.from, rule->arg.tos);
 			break;
 
 		case HTTP_REQ_ACT_SET_MARK:
 #ifdef SO_MARK
-			setsockopt(s->req->prod->conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark));
+			if ((cli_conn = objt_conn(s->req->prod->end)))
+				setsockopt(cli_conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark));
 #endif
 			break;
 
@@ -3062,6 +3065,7 @@
 static struct http_res_rule *
 http_res_get_intercept_rule(struct proxy *px, struct list *rules, struct session *s, struct http_txn *txn)
 {
+	struct connection *cli_conn;
 	struct http_res_rule *rule;
 	struct hdr_ctx ctx;
 
@@ -3097,12 +3101,14 @@
 			break;
 
 		case HTTP_RES_ACT_SET_TOS:
-			inet_set_tos(s->req->prod->conn->t.sock.fd, s->req->prod->conn->addr.from, rule->arg.tos);
+			if ((cli_conn = objt_conn(s->req->prod->end)))
+				inet_set_tos(cli_conn->t.sock.fd, cli_conn->addr.from, rule->arg.tos);
 			break;
 
 		case HTTP_RES_ACT_SET_MARK:
 #ifdef SO_MARK
-			setsockopt(s->req->prod->conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark));
+			if ((cli_conn = objt_conn(s->req->prod->end)))
+				setsockopt(cli_conn->t.sock.fd, SOL_SOCKET, SO_MARK, &rule->arg.mark, sizeof(rule->arg.mark));
 #endif
 			break;
 
@@ -3684,6 +3690,7 @@
 {
 	struct http_txn *txn = &s->txn;
 	struct http_msg *msg = &txn->req;
+	struct connection *cli_conn = objt_conn(req->prod->end);
 
 	if (unlikely(msg->msg_state < HTTP_MSG_BODY)) {
 		/* we need more data */
@@ -3711,8 +3718,9 @@
 	 */
 
 	/*
-	 * If HTTP PROXY is set we simply get remote server address
-	 * parsing incoming request.
+	 * If HTTP PROXY is set we simply get remote server address parsing
+	 * incoming request. Note that this requires that a connection is
+	 * allocated on the server side.
 	 */
 	if ((s->be->options & PR_O_HTTP_PROXY) && !(s->flags & SN_ADDR_SET)) {
 		url2sa(req->buf->p + msg->sl.rq.u, msg->sl.rq.u_l, &s->req->cons->conn->addr.to);
@@ -3769,19 +3777,19 @@
 			 * and we found it, so don't do anything.
 			 */
 		}
-		else if (s->req->prod->conn->addr.from.ss_family == AF_INET) {
+		else if (cli_conn && cli_conn->addr.from.ss_family == AF_INET) {
 			/* Add an X-Forwarded-For header unless the source IP is
 			 * in the 'except' network range.
 			 */
 			if ((!s->fe->except_mask.s_addr ||
-			     (((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr.s_addr & s->fe->except_mask.s_addr)
+			     (((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr & s->fe->except_mask.s_addr)
 			     != s->fe->except_net.s_addr) &&
 			    (!s->be->except_mask.s_addr ||
-			     (((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr.s_addr & s->be->except_mask.s_addr)
+			     (((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr.s_addr & s->be->except_mask.s_addr)
 			     != s->be->except_net.s_addr)) {
 				int len;
 				unsigned char *pn;
-				pn = (unsigned char *)&((struct sockaddr_in *)&s->req->prod->conn->addr.from)->sin_addr;
+				pn = (unsigned char *)&((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr;
 
 				/* Note: we rely on the backend to get the header name to be used for
 				 * x-forwarded-for, because the header is really meant for the backends.
@@ -3801,14 +3809,14 @@
 					goto return_bad_req;
 			}
 		}
-		else if (s->req->prod->conn->addr.from.ss_family == AF_INET6) {
+		else if (cli_conn && cli_conn->addr.from.ss_family == AF_INET6) {
 			/* FIXME: for the sake of completeness, we should also support
 			 * 'except' here, although it is mostly useless in this case.
 			 */
 			int len;
 			char pn[INET6_ADDRSTRLEN];
 			inet_ntop(AF_INET6,
-				  (const void *)&((struct sockaddr_in6 *)(&s->req->prod->conn->addr.from))->sin6_addr,
+				  (const void *)&((struct sockaddr_in6 *)(&cli_conn->addr.from))->sin6_addr,
 				  pn, sizeof(pn));
 
 			/* Note: we rely on the backend to get the header name to be used for
@@ -3837,22 +3845,22 @@
 	if ((s->fe->options | s->be->options) & PR_O_ORGTO) {
 
 		/* FIXME: don't know if IPv6 can handle that case too. */
-		if (s->req->prod->conn->addr.from.ss_family == AF_INET) {
+		if (cli_conn && cli_conn->addr.from.ss_family == AF_INET) {
 			/* Add an X-Original-To header unless the destination IP is
 			 * in the 'except' network range.
 			 */
-			conn_get_to_addr(s->req->prod->conn);
+			conn_get_to_addr(cli_conn);
 
-			if (s->req->prod->conn->addr.to.ss_family == AF_INET &&
+			if (cli_conn->addr.to.ss_family == AF_INET &&
 			    ((!s->fe->except_mask_to.s_addr ||
-			      (((struct sockaddr_in *)&s->req->prod->conn->addr.to)->sin_addr.s_addr & s->fe->except_mask_to.s_addr)
+			      (((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr.s_addr & s->fe->except_mask_to.s_addr)
 			      != s->fe->except_to.s_addr) &&
 			     (!s->be->except_mask_to.s_addr ||
-			      (((struct sockaddr_in *)&s->req->prod->conn->addr.to)->sin_addr.s_addr & s->be->except_mask_to.s_addr)
+			      (((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr.s_addr & s->be->except_mask_to.s_addr)
 			      != s->be->except_to.s_addr))) {
 				int len;
 				unsigned char *pn;
-				pn = (unsigned char *)&((struct sockaddr_in *)&s->req->prod->conn->addr.to)->sin_addr;
+				pn = (unsigned char *)&((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr;
 
 				/* Note: we rely on the backend to get the header name to be used for
 				 * x-original-to, because the header is really meant for the backends.
@@ -3922,9 +3930,10 @@
 		 * the client to delay further data.
 		 */
 		if ((s->listener->options & LI_O_NOQUICKACK) &&
+		    cli_conn &&
 		    ((msg->flags & HTTP_MSGF_TE_CHNK) ||
 		     (msg->body_len > req->buf->i - txn->req.eoh - 2)))
-			setsockopt(s->si[0].conn->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
+			setsockopt(cli_conn->t.sock.fd, IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
 #endif
 	}
 
@@ -4282,7 +4291,9 @@
 
 	s->target = NULL;
 
+	/* reinitialize the connection to the server */
 	s->req->cons->state     = s->req->cons->prev_state = SI_ST_INI;
+	s->req->cons->end = NULL;
 	s->req->cons->conn->obj_type = OBJ_TYPE_CONN;
 	s->req->cons->conn->t.sock.fd = -1; /* just to help with debugging */
 	s->req->cons->conn->flags = CO_FL_NONE;
@@ -7786,7 +7797,11 @@
 	es->sid  = s->uniq_id;
 	es->srv  = objt_server(s->target);
 	es->oe   = other_end;
-	es->src  = s->req->prod->conn->addr.from;
+	if (objt_conn(s->req->prod->end))
+		es->src  = __objt_conn(s->req->prod->end)->addr.from;
+	else
+		memset(&es->src, 0, sizeof(es->src));
+
 	es->state = state;
 	es->ev_id = error_snapshot_id++;
 	es->b_flags = chn->flags;
@@ -7939,8 +7954,9 @@
 {
 	int max;
 	chunk_printf(&trash, "%08x:%s.%s[%04x:%04x]: ", t->uniq_id, t->be->id,
-		      dir, (unsigned  short)t->req->prod->conn->t.sock.fd,
-		     (unsigned short)t->req->cons->conn->t.sock.fd);
+		      dir,
+		     objt_conn(t->req->prod->end) ? (unsigned short)objt_conn(t->req->prod->end)->t.sock.fd : -1,
+		     objt_conn(t->req->cons->end) ? (unsigned short)objt_conn(t->req->cons->end)->t.sock.fd : -1);
 
 	for (max = 0; start + max < end; max++)
 		if (start[max] == '\r' || start[max] == '\n')
@@ -9264,6 +9280,10 @@
                      const struct arg *args, struct sample *smp, const char *kw)
 {
 	struct chunk *temp;
+	struct connection *cli_conn = objt_conn(l4->si[0].end);
+
+	if (!cli_conn)
+		return 0;
 
 	if (!smp_fetch_base32(px, l4, l7, opt, args, smp, kw))
 		return 0;
@@ -9272,13 +9292,13 @@
 	memcpy(temp->str + temp->len, &smp->data.uint, sizeof(smp->data.uint));
 	temp->len += sizeof(smp->data.uint);
 
-	switch (l4->si[0].conn->addr.from.ss_family) {
+	switch (cli_conn->addr.from.ss_family) {
 	case AF_INET:
-		memcpy(temp->str + temp->len, &((struct sockaddr_in *)&l4->si[0].conn->addr.from)->sin_addr, 4);
+		memcpy(temp->str + temp->len, &((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr, 4);
 		temp->len += 4;
 		break;
 	case AF_INET6:
-		memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)(&l4->si[0].conn->addr.from))->sin6_addr, 16);
+		memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, 16);
 		temp->len += 16;
 		break;
 	default:
@@ -9848,6 +9868,7 @@
                      const struct arg *args, struct sample *smp, const char *kw)
 {
 	struct chunk *temp;
+	struct connection *cli_conn = objt_conn(l4->si[0].end);
 
 	if (!smp_fetch_url32(px, l4, l7, opt, args, smp, kw))
 		return 0;
@@ -9856,13 +9877,13 @@
 	memcpy(temp->str + temp->len, &smp->data.uint, sizeof(smp->data.uint));
 	temp->len += sizeof(smp->data.uint);
 
-	switch (l4->si[0].conn->addr.from.ss_family) {
+	switch (cli_conn->addr.from.ss_family) {
 	case AF_INET:
-		memcpy(temp->str + temp->len, &((struct sockaddr_in *)&l4->si[0].conn->addr.from)->sin_addr, 4);
+		memcpy(temp->str + temp->len, &((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr, 4);
 		temp->len += 4;
 		break;
 	case AF_INET6:
-		memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)(&l4->si[0].conn->addr.from))->sin6_addr, 16);
+		memcpy(temp->str + temp->len, &((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr, 16);
 		temp->len += 16;
 		break;
 	default:
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index a1c69a2..de1e4ae 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1086,16 +1086,20 @@
 /* This function performs the TCP layer4 analysis on the current request. It
  * returns 0 if a reject rule matches, otherwise 1 if either an accept rule
  * matches or if no more rule matches. It can only use rules which don't need
- * any data.
+ * any data. This only works on connection-based client-facing stream interfaces.
  */
 int tcp_exec_req_rules(struct session *s)
 {
 	struct tcp_rule *rule;
 	struct stksess *ts;
 	struct stktable *t = NULL;
+	struct connection *conn = objt_conn(s->si[0].end);
 	int result = 1;
 	enum acl_test_res ret;
 
+	if (!conn)
+		return result;
+
 	list_for_each_entry(rule, &s->fe->tcp_req.l4_rules, list) {
 		ret = ACL_TEST_PASS;
 
@@ -1136,8 +1140,8 @@
 					session_track_stkctr(&s->stkctr[tcp_trk_idx(rule->action)], t, ts);
 			}
 			else if (rule->action == TCP_ACT_EXPECT_PX) {
-				s->si[0].conn->flags |= CO_FL_ACCEPT_PROXY;
-				conn_sock_want_recv(s->si[0].conn);
+				conn->flags |= CO_FL_ACCEPT_PROXY;
+				conn_sock_want_recv(conn);
 			}
 			else {
 				/* otherwise it's an accept */
@@ -1577,13 +1581,18 @@
 smp_fetch_src(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
               const struct arg *args, struct sample *smp, const char *kw)
 {
-	switch (l4->si[0].conn->addr.from.ss_family) {
+	struct connection *cli_conn = objt_conn(l4->si[0].end);
+
+	if (!cli_conn)
+		return 0;
+
+	switch (cli_conn->addr.from.ss_family) {
 	case AF_INET:
-		smp->data.ipv4 = ((struct sockaddr_in *)&l4->si[0].conn->addr.from)->sin_addr;
+		smp->data.ipv4 = ((struct sockaddr_in *)&cli_conn->addr.from)->sin_addr;
 		smp->type = SMP_T_IPV4;
 		break;
 	case AF_INET6:
-		smp->data.ipv6 = ((struct sockaddr_in6 *)(&l4->si[0].conn->addr.from))->sin6_addr;
+		smp->data.ipv6 = ((struct sockaddr_in6 *)&cli_conn->addr.from)->sin6_addr;
 		smp->type = SMP_T_IPV6;
 		break;
 	default:
@@ -1599,8 +1608,13 @@
 smp_fetch_sport(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                 const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *cli_conn = objt_conn(l4->si[0].end);
+
+	if (!cli_conn)
+		return 0;
+
 	smp->type = SMP_T_UINT;
-	if (!(smp->data.uint = get_host_port(&l4->si[0].conn->addr.from)))
+	if (!(smp->data.uint = get_host_port(&cli_conn->addr.from)))
 		return 0;
 
 	smp->flags = 0;
@@ -1612,15 +1626,20 @@
 smp_fetch_dst(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
               const struct arg *args, struct sample *smp, const char *kw)
 {
-	conn_get_to_addr(l4->si[0].conn);
+	struct connection *cli_conn = objt_conn(l4->si[0].end);
 
-	switch (l4->si[0].conn->addr.to.ss_family) {
+	if (!cli_conn)
+		return 0;
+
+	conn_get_to_addr(cli_conn);
+
+	switch (cli_conn->addr.to.ss_family) {
 	case AF_INET:
-		smp->data.ipv4 = ((struct sockaddr_in *)&l4->si[0].conn->addr.to)->sin_addr;
+		smp->data.ipv4 = ((struct sockaddr_in *)&cli_conn->addr.to)->sin_addr;
 		smp->type = SMP_T_IPV4;
 		break;
 	case AF_INET6:
-		smp->data.ipv6 = ((struct sockaddr_in6 *)(&l4->si[0].conn->addr.to))->sin6_addr;
+		smp->data.ipv6 = ((struct sockaddr_in6 *)&cli_conn->addr.to)->sin6_addr;
 		smp->type = SMP_T_IPV6;
 		break;
 	default:
@@ -1636,10 +1655,15 @@
 smp_fetch_dport(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                 const struct arg *args, struct sample *smp, const char *kw)
 {
-	conn_get_to_addr(l4->si[0].conn);
+	struct connection *cli_conn = objt_conn(l4->si[0].end);
+
+	if (!cli_conn)
+		return 0;
+
+	conn_get_to_addr(cli_conn);
 
 	smp->type = SMP_T_UINT;
-	if (!(smp->data.uint = get_host_port(&l4->si[0].conn->addr.to)))
+	if (!(smp->data.uint = get_host_port(&cli_conn->addr.to)))
 		return 0;
 
 	smp->flags = 0;
diff --git a/src/session.c b/src/session.c
index 2184766..a6dd519 100644
--- a/src/session.c
+++ b/src/session.c
@@ -72,6 +72,7 @@
  */
 int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr)
 {
+	struct connection *cli_conn;
 	struct proxy *p = l->frontend;
 	struct session *s;
 	struct task *t;
@@ -83,7 +84,7 @@
 	if (unlikely((s = pool_alloc2(pool2_session)) == NULL))
 		goto out_close;
 
-	if (unlikely((s->si[0].conn = pool_alloc2(pool2_connection)) == NULL))
+	if (unlikely((cli_conn = s->si[0].conn = pool_alloc2(pool2_connection)) == NULL))
 		goto out_fail_conn0;
 
 	if (unlikely((s->si[1].conn = pool_alloc2(pool2_connection)) == NULL))
@@ -104,19 +105,21 @@
 	s->listener = l;
 	s->fe  = p;
 
-	/* OK, we're keeping the session, so let's properly initialize the session */
-	s->si[0].conn->obj_type = OBJ_TYPE_CONN;
-	s->si[0].conn->t.sock.fd = cfd;
-	s->si[0].conn->ctrl = l->proto;
-	s->si[0].conn->flags = CO_FL_NONE | CO_FL_ADDR_FROM_SET;
-	s->si[0].conn->err_code = CO_ER_NONE;
-	s->si[0].conn->addr.from = *addr;
-	s->si[0].conn->target = &l->obj_type;
+	/* OK, we're keeping the session, so let's properly initialize the session.
+	 * We first have to initialize the client-side connection.
+	 */
+	cli_conn->obj_type = OBJ_TYPE_CONN;
+	cli_conn->t.sock.fd = cfd;
+	cli_conn->ctrl = l->proto;
+	cli_conn->flags = CO_FL_NONE | CO_FL_ADDR_FROM_SET;
+	cli_conn->err_code = CO_ER_NONE;
+	cli_conn->addr.from = *addr;
+	cli_conn->target = &l->obj_type;
 
-	/* FIXME: this should be replaced with OBJ_TYPE_NONE once all users check the
-	 * object type before dereferencing the connection pointer.
+	/* The server side is not used yet, but just initialize it to avoid
+	 * confusing some debugging or "show sess" for example.
 	 */
-	s->si[1].conn->obj_type = OBJ_TYPE_CONN;
+	s->si[1].conn->obj_type = OBJ_TYPE_NONE;
 
 	s->logs.accept_date = date; /* user-visible date for logging */
 	s->logs.tv_accept = now;  /* corrected date for internal use */
@@ -178,8 +181,8 @@
 
 	/* wait for a PROXY protocol header */
 	if (l->options & LI_O_ACC_PROXY) {
-		s->si[0].conn->flags |= CO_FL_ACCEPT_PROXY;
-		conn_sock_want_recv(s->si[0].conn);
+		cli_conn->flags |= CO_FL_ACCEPT_PROXY;
+		conn_sock_want_recv(cli_conn);
 	}
 
 	if (unlikely((t = task_new()) == NULL))
@@ -193,14 +196,14 @@
 	 * but not initialized. Also note we need to be careful as the stream
 	 * int is not initialized yet.
 	 */
-	conn_prepare(s->si[0].conn, &sess_conn_cb, l->proto, l->xprt, s);
+	conn_prepare(cli_conn, &sess_conn_cb, l->proto, l->xprt, s);
 
 	/* finish initialization of the accepted file descriptor */
 	fd_insert(cfd);
-	fdtab[cfd].owner = s->si[0].conn;
+	fdtab[cfd].owner = cli_conn;
 	fdtab[cfd].iocb = conn_fd_handler;
-	conn_data_want_recv(s->si[0].conn);
-	if (conn_xprt_init(s->si[0].conn) < 0)
+	conn_data_want_recv(cli_conn);
+	if (conn_xprt_init(cli_conn) < 0)
 		goto out_free_task;
 
 	/* OK, now either we have a pending handshake to execute with and
@@ -209,16 +212,16 @@
 	 * set the I/O timeout to the frontend's client timeout.
 	 */
 
-	if (s->si[0].conn->flags & CO_FL_HANDSHAKE) {
+	if (cli_conn->flags & CO_FL_HANDSHAKE) {
 		t->process = expire_mini_session;
 		t->expire = tick_add_ifset(now_ms, p->timeout.client);
 		task_queue(t);
-		s->si[0].conn->flags |= CO_FL_INIT_DATA | CO_FL_WAKE_DATA;
+		cli_conn->flags |= CO_FL_INIT_DATA | CO_FL_WAKE_DATA;
 		return 1;
 	}
 
 	/* OK let's complete session initialization since there is no handshake */
-	s->si[0].conn->flags |= CO_FL_CONNECTED;
+	cli_conn->flags |= CO_FL_CONNECTED;
 	ret = session_complete(s);
 	if (ret > 0)
 		return ret;
@@ -252,21 +255,24 @@
 }
 
 
-/* prepare the trash with a log prefix for session <s> */
+/* prepare the trash with a log prefix for session <s>. It only works with
+ * embryonic sessions based on a real connection.
+ */
 static void prepare_mini_sess_log_prefix(struct session *s)
 {
 	struct tm tm;
 	char pn[INET6_ADDRSTRLEN];
 	int ret;
 	char *end;
+	struct connection *cli_conn = s->si[0].conn;
 
-	ret = addr_to_str(&s->si[0].conn->addr.from, pn, sizeof(pn));
+	ret = addr_to_str(&cli_conn->addr.from, pn, sizeof(pn));
 	if (ret <= 0)
 		chunk_printf(&trash, "unknown [");
 	else if (ret == AF_UNIX)
 		chunk_printf(&trash, "%s:%d [", pn, s->listener->luid);
 	else
-		chunk_printf(&trash, "%s:%d [", pn, get_host_port(&s->si[0].conn->addr.from));
+		chunk_printf(&trash, "%s:%d [", pn, get_host_port(&cli_conn->addr.from));
 
 	get_localtime(s->logs.accept_date.tv_sec, &tm);
 	end = date2str_log(trash.str + trash.len, &tm, &(s->logs.accept_date), trash.size - trash.len);
@@ -317,7 +323,7 @@
 	}
 
 	/* kill the connection now */
-	conn_full_close(s->si[0].conn);
+	conn_full_close(conn);
 
 	s->fe->feconn--;
 	session_store_counters(s);
@@ -393,6 +399,7 @@
  * be called with an embryonic session. It returns a positive value upon
  * success, 0 if the connection can be ignored, or a negative value upon
  * critical failure. The accepted file descriptor is closed if we return <= 0.
+ * The client-side end point is assumed to be a connection.
  */
 int session_complete(struct session *s)
 {
@@ -462,15 +469,17 @@
 	s->si[1].conn->t.sock.fd = -1; /* just to help with debugging */
 	s->si[1].conn->flags = CO_FL_NONE;
 	s->si[1].conn->err_code = CO_ER_NONE;
+	s->si[1].conn->target = NULL;
 	s->si[1].owner     = t;
 	s->si[1].state     = s->si[1].prev_state = SI_ST_INI;
 	s->si[1].err_type  = SI_ET_NONE;
 	s->si[1].conn_retries = 0;  /* used for logging too */
 	s->si[1].send_proxy_ofs = 0;
-	si_prepare_none(&s->si[1]);
 	s->si[1].exp       = TICK_ETERNITY;
 	s->si[1].flags     = SI_FL_NONE;
 
+	si_prepare_none(&s->si[1]);
+
 	if (likely(s->fe->options2 & PR_O2_INDEPSTR))
 		s->si[1].flags |= SI_FL_INDEP_STR;
 
@@ -549,7 +558,7 @@
 	txn->rsp.chn = s->rep;
 
 	/* finish initialization of the accepted file descriptor */
-	conn_data_want_recv(s->si[0].conn);
+	conn_data_want_recv(__objt_conn(s->si[0].end));
 
 	if (p->accept && (ret = p->accept(s)) <= 0) {
 		/* Either we had an unrecoverable error (<0) or work is
@@ -561,10 +570,10 @@
 
 	/* if logs require transport layer information, note it on the connection */
 	if (s->logs.logwait & LW_XPRT)
-		s->si[0].conn->flags |= CO_FL_XPRT_TRACKED;
+		__objt_conn(s->si[0].end)->flags |= CO_FL_XPRT_TRACKED;
 
 	/* we want the connection handler to notify the stream interface about updates. */
-	s->si[0].conn->flags |= CO_FL_WAKE_DATA;
+	__objt_conn(s->si[0].end)->flags |= CO_FL_WAKE_DATA;
 
 	/* it is important not to call the wakeup function directly but to
 	 * pass through task_wakeup(), because this one knows how to apply
@@ -594,6 +603,7 @@
 	struct http_txn *txn = &s->txn;
 	struct proxy *fe = s->fe;
 	struct bref *bref, *back;
+	struct connection *cli_conn = objt_conn(s->si[0].end);
 	int i;
 
 	if (s->pend_pos)
@@ -636,8 +646,10 @@
 	http_end_txn(s);
 
 	/* ensure the client-side transport layer is destroyed */
-	s->si[0].conn->flags &= ~CO_FL_XPRT_TRACKED;
-	conn_full_close(s->si[0].conn);
+	if (cli_conn) {
+		cli_conn->flags &= ~CO_FL_XPRT_TRACKED;
+		conn_full_close(cli_conn);
+	}
 
 	for (i = 0; i < s->store_count; i++) {
 		if (!s->store[i].ts)
@@ -771,12 +783,13 @@
  * We must check for establishment, error and abort. Possible output states
  * are SI_ST_EST (established), SI_ST_CER (error), SI_ST_DIS (abort), and
  * SI_ST_CON (no change). The function returns 0 if it switches to SI_ST_CER,
- * otherwise 1.
+ * otherwise 1. This only works with connection-based sessions.
  */
 static int sess_update_st_con_tcp(struct session *s, struct stream_interface *si)
 {
 	struct channel *req = si->ob;
 	struct channel *rep = si->ib;
+	struct connection *srv_conn = __objt_conn(si->end);
 
 	/* If we got an error, or if nothing happened and the connection timed
 	 * out, we must give up. The CER state handler will take care of retry
@@ -798,8 +811,8 @@
 		si->exp   = TICK_ETERNITY;
 		si->state = SI_ST_CER;
 
-		si->conn->flags &= ~CO_FL_XPRT_TRACKED;
-		conn_full_close(si->conn);
+		srv_conn->flags &= ~CO_FL_XPRT_TRACKED;
+		conn_full_close(srv_conn);
 
 		if (si->err_type)
 			return 0;
@@ -954,7 +967,7 @@
 
 	rep->analysers |= s->fe->fe_rsp_ana | s->be->be_rsp_ana;
 	rep->flags |= CF_READ_ATTACHED; /* producer is now attached */
-	if (si->conn->ctrl) {
+	if (objt_conn(si->end)) {
 		/* real connections have timeouts */
 		req->wto = s->be->timeout.server;
 		rep->rto = s->be->timeout.server;
@@ -2130,8 +2143,8 @@
 	if (!(s->req->flags & (CF_KERN_SPLICING|CF_SHUTR)) &&
 	    s->req->to_forward &&
 	    (global.tune.options & GTUNE_USE_SPLICE) &&
-	    (s->si[0].conn->xprt && s->si[0].conn->xprt->rcv_pipe && s->si[0].conn->xprt->snd_pipe) &&
-	    (s->si[1].conn->xprt && s->si[1].conn->xprt->rcv_pipe && s->si[1].conn->xprt->snd_pipe) &&
+	    (objt_conn(s->si[0].end) && __objt_conn(s->si[0].end)->xprt && __objt_conn(s->si[0].end)->xprt->rcv_pipe) &&
+	    (objt_conn(s->si[1].end) && __objt_conn(s->si[1].end)->xprt && __objt_conn(s->si[1].end)->xprt->snd_pipe) &&
 	    (pipes_used < global.maxpipes) &&
 	    (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_REQ) ||
 	     (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) &&
@@ -2278,8 +2291,8 @@
 	if (!(s->rep->flags & (CF_KERN_SPLICING|CF_SHUTR)) &&
 	    s->rep->to_forward &&
 	    (global.tune.options & GTUNE_USE_SPLICE) &&
-	    (s->si[0].conn->xprt && s->si[0].conn->xprt->rcv_pipe && s->si[0].conn->xprt->snd_pipe) &&
-	    (s->si[1].conn->xprt && s->si[1].conn->xprt->rcv_pipe && s->si[1].conn->xprt->snd_pipe) &&
+	    (objt_conn(s->si[0].end) && __objt_conn(s->si[0].end)->xprt && __objt_conn(s->si[0].end)->xprt->snd_pipe) &&
+	    (objt_conn(s->si[1].end) && __objt_conn(s->si[1].end)->xprt && __objt_conn(s->si[1].end)->xprt->rcv_pipe) &&
 	    (pipes_used < global.maxpipes) &&
 	    (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_RTR) ||
 	     (((s->fe->options2|s->be->options2) & PR_O2_SPLIC_AUT) &&
@@ -2345,8 +2358,8 @@
 		    s->si[1].prev_state == SI_ST_EST) {
 			chunk_printf(&trash, "%08x:%s.srvcls[%04x:%04x]\n",
 				      s->uniq_id, s->be->id,
-				      (unsigned short)s->si[0].conn->t.sock.fd,
-				      (unsigned short)s->si[1].conn->t.sock.fd);
+			              objt_conn(s->si[0].end) ? (unsigned short)objt_conn(s->si[0].end)->t.sock.fd : -1,
+			              objt_conn(s->si[1].end) ? (unsigned short)objt_conn(s->si[1].end)->t.sock.fd : -1);
 			if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */;
 		}
 
@@ -2354,8 +2367,8 @@
 		    s->si[0].prev_state == SI_ST_EST) {
 			chunk_printf(&trash, "%08x:%s.clicls[%04x:%04x]\n",
 				      s->uniq_id, s->be->id,
-				      (unsigned short)s->si[0].conn->t.sock.fd,
-				      (unsigned short)s->si[1].conn->t.sock.fd);
+			              objt_conn(s->si[0].end) ? (unsigned short)objt_conn(s->si[0].end)->t.sock.fd : -1,
+			              objt_conn(s->si[1].end) ? (unsigned short)objt_conn(s->si[1].end)->t.sock.fd : -1);
 			if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */;
 		}
 	}
@@ -2459,8 +2472,8 @@
 		     (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
 		chunk_printf(&trash, "%08x:%s.closed[%04x:%04x]\n",
 			      s->uniq_id, s->be->id,
-			      (unsigned short)s->req->prod->conn->t.sock.fd,
-			      (unsigned short)s->req->cons->conn->t.sock.fd);
+		              objt_conn(s->si[0].end) ? (unsigned short)objt_conn(s->si[0].end)->t.sock.fd : -1,
+		              objt_conn(s->si[1].end) ? (unsigned short)objt_conn(s->si[1].end)->t.sock.fd : -1);
 		if (write(1, trash.str, trash.len) < 0) /* shut gcc warning */;
 	}
 
@@ -2619,10 +2632,16 @@
 			return NULL;
 	}
 	else if (num > 9) { /* src_* variant, args[0] = table */
-		struct stktable_key *key = addr_to_stktable_key(&l4->si[0].conn->addr.from);
+		struct stktable_key *key;
+		struct connection *conn = objt_conn(l4->si[0].end);
+
+		if (!conn)
+			return NULL;
 
+		key = addr_to_stktable_key(&conn->addr.from);
 		if (!key)
 			return NULL;
+
 		stkctr.table = &args->data.prx->table;
 		stkctr.entry = stktable_lookup_key(stkctr.table, key);
 		return &stkctr;
@@ -2831,11 +2850,15 @@
 smp_fetch_src_updt_conn_cnt(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                             const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *conn = objt_conn(l4->si[0].end);
 	struct stksess *ts;
 	struct stktable_key *key;
 	void *ptr;
 
+	if (!conn)
+		return 0;
+
-	key = addr_to_stktable_key(&l4->si[0].conn->addr.from);
+	key = addr_to_stktable_key(&conn->addr.from);
 	if (!key)
 		return 0;
 
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 9396cbd..5b8fdb9 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -1704,17 +1704,23 @@
 smp_fetch_ssl_fc_has_crt(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                          const struct arg *args, struct sample *smp, const char *kw)
 {
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
+
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	smp->flags = 0;
 	smp->type = SMP_T_BOOL;
-	smp->data.uint = SSL_SOCK_ST_FL_VERIFY_DONE & l4->si[0].conn->xprt_st ? 1 : 0;
+	smp->data.uint = SSL_SOCK_ST_FL_VERIFY_DONE & conn->xprt_st ? 1 : 0;
 
 	return 1;
 }
@@ -1727,17 +1733,22 @@
 	X509 *crt = NULL;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate, it increase X509 * ref count */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -1763,17 +1774,22 @@
 	const EVP_MD *digest;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate, it increase X509 * ref count */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -1798,17 +1814,22 @@
 	X509 *crt = NULL;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate, it increase X509 * ref count */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -1834,17 +1855,22 @@
 	X509_NAME *name;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate, it increase X509 * ref count */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -1884,17 +1910,22 @@
 	X509 *crt = NULL;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate, it increase X509 * ref count */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -1920,17 +1951,22 @@
 	X509_NAME *name;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate, it increase X509 * ref count */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -1968,17 +2004,22 @@
                         const struct arg *args, struct sample *smp, const char *kw)
 {
 	X509 *crt;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (crt) {
 		X509_free(crt);
 	}
@@ -1994,17 +2035,22 @@
                         const struct arg *args, struct sample *smp, const char *kw)
 {
 	X509 *crt;
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate returns a ptr on allocated X509 struct */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		return 0;
 
@@ -2022,17 +2068,22 @@
 {
 	X509 *crt;
 	int nid;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate increase X509 * ref count  */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		return 0;
 
@@ -2058,17 +2109,22 @@
 {
 	X509 *crt;
 	int nid;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_peer_certificate increase X509 * ref count  */
-	crt = SSL_get_peer_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_peer_certificate(conn->xprt_ctx);
 	if (!crt)
 		return 0;
 
@@ -2092,8 +2148,10 @@
 smp_fetch_ssl_fc(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                  const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *conn = objt_conn(l4->si[0].end);
+
 	smp->type = SMP_T_BOOL;
-	smp->data.uint = (l4->si[0].conn->xprt == &ssl_sock);
+	smp->data.uint = (conn && conn->xprt == &ssl_sock);
 	return 1;
 }
 
@@ -2103,10 +2161,12 @@
                          const struct arg *args, struct sample *smp, const char *kw)
 {
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+	struct connection *conn = objt_conn(l4->si[0].end);
+
 	smp->type = SMP_T_BOOL;
-	smp->data.uint = (l4->si[0].conn->xprt == &ssl_sock) &&
-		l4->si[0].conn->xprt_ctx &&
-		SSL_get_servername(l4->si[0].conn->xprt_ctx, TLSEXT_NAMETYPE_host_name) != NULL;
+	smp->data.uint = (conn && conn->xprt == &ssl_sock) &&
+		conn->xprt_ctx &&
+		SSL_get_servername(conn->xprt_ctx, TLSEXT_NAMETYPE_host_name) != NULL;
 	return 1;
 #else
 	return 0;
@@ -2121,16 +2181,21 @@
 	X509 *crt = NULL;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
-	crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -2152,16 +2217,21 @@
 	X509 *crt = NULL;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
-	crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -2184,16 +2254,21 @@
 	X509 *crt = NULL;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
-	crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -2214,17 +2289,22 @@
                            const struct arg *args, struct sample *smp, const char *kw)
 {
 	X509 *crt;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	/* SSL_get_certificate returns a ptr on an SSL * internal sub struct */
-	crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_certificate(conn->xprt_ctx);
 	if (!crt)
 		return 0;
 
@@ -2241,16 +2321,21 @@
 {
 	X509 *crt;
 	int nid;
+	struct connection *conn;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
-	crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_certificate(conn->xprt_ctx);
 	if (!crt)
 		return 0;
 
@@ -2273,16 +2358,21 @@
 {
 	X509 *crt;
 	int nid;
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
-	crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_certificate(conn->xprt_ctx);
 	if (!crt)
 		return 0;
 
@@ -2307,16 +2397,21 @@
 	X509_NAME *name;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
-	crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -2355,16 +2450,21 @@
 	X509_NAME *name;
 	int ret = 0;
 	struct chunk *smp_trash;
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
 
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags |= SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
-	crt = SSL_get_certificate(l4->si[0].conn->xprt_ctx);
+	crt = SSL_get_certificate(conn->xprt_ctx);
 	if (!crt)
 		goto out;
 
@@ -2398,12 +2498,18 @@
 smp_fetch_ssl_fc_cipher(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                         const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *conn;
+
 	smp->flags = 0;
 
+	if (!l4)
+		return 0;
+
-	if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
 		return 0;
 
-	smp->data.str.str = (char *)SSL_get_cipher_name(l4->si[0].conn->xprt_ctx);
+	smp->data.str.str = (char *)SSL_get_cipher_name(conn->xprt_ctx);
 	if (!smp->data.str.str)
 		return 0;
 
@@ -2417,14 +2523,20 @@
 smp_fetch_ssl_fc_alg_keysize(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                              const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *conn;
+
 	smp->flags = 0;
 
-	if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	if (!SSL_get_cipher_bits(l4->si[0].conn->xprt_ctx, (int *)&smp->data.uint))
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
 		return 0;
 
+	if (!SSL_get_cipher_bits(conn->xprt_ctx, (int *)&smp->data.uint))
+		return 0;
+
 	smp->type = SMP_T_UINT;
 
 	return 1;
@@ -2434,12 +2546,18 @@
 smp_fetch_ssl_fc_use_keysize(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                              const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *conn;
+
 	smp->flags = 0;
 
-	if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	smp->data.uint = (unsigned int)SSL_get_cipher_bits(l4->si[0].conn->xprt_ctx, NULL);
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
+		return 0;
+
+	smp->data.uint = (unsigned int)SSL_get_cipher_bits(conn->xprt_ctx, NULL);
 	if (!smp->data.uint)
 		return 0;
 
@@ -2453,14 +2571,20 @@
 smp_fetch_ssl_fc_npn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                      const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *conn;
+
 	smp->flags = 0;
 	smp->type = SMP_T_CSTR;
 
-	if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
+		return 0;
+
 	smp->data.str.str = NULL;
-	SSL_get0_next_proto_negotiated(l4->si[0].conn->xprt_ctx,
+	SSL_get0_next_proto_negotiated(conn->xprt_ctx,
 	                                (const unsigned char **)&smp->data.str.str, (unsigned *)&smp->data.str.len);
 
 	if (!smp->data.str.str)
@@ -2475,14 +2599,20 @@
 smp_fetch_ssl_fc_alpn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                       const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *conn;
+
 	smp->flags = 0;
 	smp->type = SMP_T_CSTR;
 
+	if (!l4)
+		return 0;
+
-	if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock)
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
 		return 0;
 
 	smp->data.str.str = NULL;
-	SSL_get0_alpn_negotiated(l4->si[0].conn->xprt_ctx,
+	SSL_get0_alpn_negotiated(conn->xprt_ctx,
 	                         (const unsigned char **)&smp->data.str.str, (unsigned *)&smp->data.str.len);
 
 	if (!smp->data.str.str)
@@ -2496,12 +2626,18 @@
 smp_fetch_ssl_fc_protocol(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                           const struct arg *args, struct sample *smp, const char *kw)
 {
+	struct connection *conn;
+
 	smp->flags = 0;
 
-	if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	smp->data.str.str = (char *)SSL_get_version(l4->si[0].conn->xprt_ctx);
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
+		return 0;
+
+	smp->data.str.str = (char *)SSL_get_version(conn->xprt_ctx);
 	if (!smp->data.str.str)
 		return 0;
 
@@ -2517,14 +2653,19 @@
 {
 #if OPENSSL_VERSION_NUMBER > 0x0090800fL
 	SSL_SESSION *sess;
+	struct connection *conn;
 
 	smp->flags = 0;
 	smp->type = SMP_T_CBIN;
 
-	if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	sess = SSL_get_session(l4->si[0].conn->xprt_ctx);
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
+		return 0;
+
+	sess = SSL_get_session(conn->xprt_ctx);
 	if (!sess)
 		return 0;
 
@@ -2543,13 +2684,19 @@
                      const struct arg *args, struct sample *smp, const char *kw)
 {
 #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+	struct connection *conn;
+
 	smp->flags = 0;
 	smp->type = SMP_T_CSTR;
 
-	if (!l4 || !l4->si[0].conn->xprt_ctx || l4->si[0].conn->xprt != &ssl_sock)
+	if (!l4)
 		return 0;
 
-	smp->data.str.str = (char *)SSL_get_servername(l4->si[0].conn->xprt_ctx, TLSEXT_NAMETYPE_host_name);
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || !conn->xprt_ctx || conn->xprt != &ssl_sock)
+		return 0;
+
+	smp->data.str.str = (char *)SSL_get_servername(conn->xprt_ctx, TLSEXT_NAMETYPE_host_name);
 	if (!smp->data.str.str)
 		return 0;
 
@@ -2565,16 +2712,22 @@
 smp_fetch_ssl_c_ca_err(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                        const struct arg *args, struct sample *smp, const char *kw)
 {
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	struct connection *conn;
+
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags = SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	smp->type = SMP_T_UINT;
-	smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CA_ERROR(l4->si[0].conn->xprt_st);
+	smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CA_ERROR(conn->xprt_st);
 	smp->flags = 0;
 
 	return 1;
@@ -2585,16 +2738,22 @@
 smp_fetch_ssl_c_ca_err_depth(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                              const struct arg *args, struct sample *smp, const char *kw)
 {
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	struct connection *conn;
+
+	if (!l4)
+		return 0;
+
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags = SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	smp->type = SMP_T_UINT;
-	smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CAEDEPTH(l4->si[0].conn->xprt_st);
+	smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CAEDEPTH(conn->xprt_st);
 	smp->flags = 0;
 
 	return 1;
@@ -2605,16 +2764,22 @@
 smp_fetch_ssl_c_err(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                     const struct arg *args, struct sample *smp, const char *kw)
 {
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	struct connection *conn;
+
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags = SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
 	smp->type = SMP_T_UINT;
-	smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CRTERROR(l4->si[0].conn->xprt_st);
+	smp->data.uint = (unsigned int)SSL_SOCK_ST_TO_CRTERROR(conn->xprt_st);
 	smp->flags = 0;
 
 	return 1;
@@ -2625,19 +2790,25 @@
 smp_fetch_ssl_c_verify(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
                        const struct arg *args, struct sample *smp, const char *kw)
 {
-	if (!l4 || l4->si[0].conn->xprt != &ssl_sock)
+	struct connection *conn;
+
+	if (!l4)
 		return 0;
 
-	if (!(l4->si[0].conn->flags & CO_FL_CONNECTED)) {
+	conn = objt_conn(l4->si[0].end);
+	if (!conn || conn->xprt != &ssl_sock)
+		return 0;
+
+	if (!(conn->flags & CO_FL_CONNECTED)) {
 		smp->flags = SMP_F_MAY_CHANGE;
 		return 0;
 	}
 
-	if (!l4->si[0].conn->xprt_ctx)
+	if (!conn->xprt_ctx)
 		return 0;
 
 	smp->type = SMP_T_UINT;
-	smp->data.uint = (unsigned int)SSL_get_verify_result(l4->si[0].conn->xprt_ctx);
+	smp->data.uint = (unsigned int)SSL_get_verify_result(conn->xprt_ctx);
 	smp->flags = 0;
 
 	return 1;
diff --git a/src/stream_interface.c b/src/stream_interface.c
index d66d301..6932e15 100644
--- a/src/stream_interface.c
+++ b/src/stream_interface.c
@@ -395,7 +395,12 @@
 		 * (which is recomputed every time since it's constant). If
 		 * it is positive, it means we have to send from the start.
 		 */
-		ret = make_proxy_line(trash.str, trash.size, &si->ob->prod->conn->addr.from, &si->ob->prod->conn->addr.to);
+		struct connection *remote = objt_conn(si->ob->prod->end);
+		if (remote)
+			ret = make_proxy_line(trash.str, trash.size, &remote->addr.from, &remote->addr.to);
+		else
+			ret = make_proxy_line(trash.str, trash.size, NULL, NULL);
+
 		if (!ret)
 			goto out_error;
 
@@ -638,6 +643,7 @@
 {
 	struct channel *ib = si->ib;
 	struct channel *ob = si->ob;
+	struct connection *conn = __objt_conn(si->end);
 
 	/* Check if we need to close the read side */
 	if (!(ib->flags & CF_SHUTR)) {
@@ -647,7 +653,7 @@
 			if (!(si->flags & SI_FL_WAIT_ROOM)) {
 				if (!(ib->flags & CF_DONT_READ)) /* full */
 					si->flags |= SI_FL_WAIT_ROOM;
-				conn_data_stop_recv(si->conn);
+				conn_data_stop_recv(conn);
 				ib->rex = TICK_ETERNITY;
 			}
 		}
@@ -658,7 +664,7 @@
 			 * have updated it if there has been a completed I/O.
 			 */
 			si->flags &= ~SI_FL_WAIT_ROOM;
-			conn_data_want_recv(si->conn);
+			conn_data_want_recv(conn);
 			if (!(ib->flags & (CF_READ_NOEXP|CF_DONT_READ)) && !tick_isset(ib->rex))
 				ib->rex = tick_add_ifset(now_ms, ib->rto);
 		}
@@ -672,7 +678,7 @@
 			if (!(si->flags & SI_FL_WAIT_DATA)) {
 				if ((ob->flags & CF_SHUTW_NOW) == 0)
 					si->flags |= SI_FL_WAIT_DATA;
-				conn_data_stop_send(si->conn);
+				conn_data_stop_send(conn);
 				ob->wex = TICK_ETERNITY;
 			}
 		}
@@ -683,7 +689,7 @@
 			 * have updated it if there has been a completed I/O.
 			 */
 			si->flags &= ~SI_FL_WAIT_DATA;
-			conn_data_want_send(si->conn);
+			conn_data_want_send(conn);
 			if (!tick_isset(ob->wex)) {
 				ob->wex = tick_add_ifset(now_ms, ob->wto);
 				if (tick_isset(ib->rex) && !(si->flags & SI_FL_INDEP_STR)) {
@@ -712,7 +718,7 @@
  */
 static void stream_int_shutr_conn(struct stream_interface *si)
 {
-	struct connection *conn = si->conn;
+	struct connection *conn = __objt_conn(si->end);
 
 	si->ib->flags &= ~CF_SHUTR_NOW;
 	if (si->ib->flags & CF_SHUTR)
@@ -754,7 +760,7 @@
  */
 static void stream_int_shutw_conn(struct stream_interface *si)
 {
-	struct connection *conn = si->conn;
+	struct connection *conn = __objt_conn(si->end);
 
 	si->ob->flags &= ~CF_SHUTW_NOW;
 	if (si->ob->flags & CF_SHUTW)
@@ -840,24 +846,25 @@
 static void stream_int_chk_rcv_conn(struct stream_interface *si)
 {
 	struct channel *ib = si->ib;
+	struct connection *conn = __objt_conn(si->end);
 
 	if (unlikely(si->state > SI_ST_EST || (ib->flags & CF_SHUTR)))
 		return;
 
-	conn_refresh_polling_flags(si->conn);
+	conn_refresh_polling_flags(conn);
 
 	if ((ib->flags & CF_DONT_READ) || channel_full(ib)) {
 		/* stop reading */
 		if (!(ib->flags & CF_DONT_READ)) /* full */
 			si->flags |= SI_FL_WAIT_ROOM;
-		__conn_data_stop_recv(si->conn);
+		__conn_data_stop_recv(conn);
 	}
 	else {
 		/* (re)start reading */
 		si->flags &= ~SI_FL_WAIT_ROOM;
-		__conn_data_want_recv(si->conn);
+		__conn_data_want_recv(conn);
 	}
-	conn_cond_update_data_polling(si->conn);
+	conn_cond_update_data_polling(conn);
 }
 
 
@@ -869,6 +876,7 @@
 static void stream_int_chk_snd_conn(struct stream_interface *si)
 {
 	struct channel *ob = si->ob;
+	struct connection *conn = __objt_conn(si->end);
 
 	if (unlikely(si->state > SI_ST_EST || (ob->flags & CF_SHUTW)))
 		return;
@@ -880,7 +888,7 @@
 	    !(si->flags & SI_FL_WAIT_DATA))       /* not waiting for data */
 		return;
 
-	if (si->conn->flags & (CO_FL_DATA_WR_ENA|CO_FL_CURR_WR_ENA)) {
+	if (conn->flags & (CO_FL_DATA_WR_ENA|CO_FL_CURR_WR_ENA)) {
 		/* already subscribed to write notifications, will be called
 		 * anyway, so let's avoid calling it especially if the reader
 		 * is not ready.
@@ -888,20 +896,20 @@
 		return;
 	}
 
-	if (!(si->conn->flags & (CO_FL_HANDSHAKE|CO_FL_WAIT_L4_CONN|CO_FL_WAIT_L6_CONN))) {
+	if (!(conn->flags & (CO_FL_HANDSHAKE|CO_FL_WAIT_L4_CONN|CO_FL_WAIT_L6_CONN))) {
 		/* Before calling the data-level operations, we have to prepare
 		 * the polling flags to ensure we properly detect changes.
 		 */
-		if (si->conn->ctrl)
-			fd_want_send(si->conn->t.sock.fd);
+		if (conn->ctrl)
+			fd_want_send(conn->t.sock.fd);
 
-		conn_refresh_polling_flags(si->conn);
+		conn_refresh_polling_flags(conn);
 
-		si_conn_send(si->conn);
-		if (si->conn->flags & CO_FL_ERROR) {
+		si_conn_send(conn);
+		if (conn->flags & CO_FL_ERROR) {
 			/* Write error on the file descriptor */
-			fd_stop_both(si->conn->t.sock.fd);
-			__conn_data_stop_both(si->conn);
+			fd_stop_both(conn->t.sock.fd);
+			__conn_data_stop_both(conn);
 			si->flags |= SI_FL_ERR;
 			goto out_wakeup;
 		}
@@ -916,7 +924,7 @@
 		 * ->o limit was reached. Maybe we just wrote the last
 		 * chunk and need to close.
 		 */
-		__conn_data_stop_send(si->conn);
+		__conn_data_stop_send(conn);
 		if (((ob->flags & (CF_SHUTW|CF_AUTO_CLOSE|CF_SHUTW_NOW)) ==
 		     (CF_AUTO_CLOSE|CF_SHUTW_NOW)) &&
 		    (si->state == SI_ST_EST)) {
@@ -932,7 +940,7 @@
 		/* Otherwise there are remaining data to be sent in the buffer,
 		 * which means we have to poll before doing so.
 		 */
-		__conn_data_want_send(si->conn);
+		__conn_data_want_send(conn);
 		si->flags &= ~SI_FL_WAIT_DATA;
 		if (!tick_isset(ob->wex))
 			ob->wex = tick_add_ifset(now_ms, ob->wto);
@@ -969,7 +977,7 @@
 	}
 
 	/* commit possible polling changes */
-	conn_cond_update_polling(si->conn);
+	conn_cond_update_polling(conn);
 }
 
 /*
@@ -1205,7 +1213,7 @@
 	if (conn->flags & CO_FL_ERROR)
 		return;
 
-	if (si->conn->flags & CO_FL_HANDSHAKE)
+	if (conn->flags & CO_FL_HANDSHAKE)
 		/* a handshake was requested */
 		return;
 
@@ -1229,6 +1237,8 @@
  */
 void stream_sock_read0(struct stream_interface *si)
 {
+	struct connection *conn = __objt_conn(si->end);
+
 	si->ib->flags &= ~CF_SHUTR_NOW;
 	if (si->ib->flags & CF_SHUTR)
 		return;
@@ -1246,22 +1256,22 @@
 		/* we want to immediately forward this close to the write side */
 		if (si->flags & SI_FL_NOLINGER) {
 			si->flags &= ~SI_FL_NOLINGER;
-			setsockopt(si->conn->t.sock.fd, SOL_SOCKET, SO_LINGER,
+			setsockopt(conn->t.sock.fd, SOL_SOCKET, SO_LINGER,
 				   (struct linger *) &nolinger, sizeof(struct linger));
 		}
 		/* force flag on ssl to keep session in cache */
-		if (si->conn->xprt->shutw)
-			si->conn->xprt->shutw(si->conn, 0);
+		if (conn->xprt->shutw)
+			conn->xprt->shutw(conn, 0);
 		goto do_close;
 	}
 
 	/* otherwise that's just a normal read shutdown */
-	__conn_data_stop_recv(si->conn);
+	__conn_data_stop_recv(conn);
 	return;
 
  do_close:
 	/* OK we completely close the socket here just as if we went through si_shut[rw]() */
-	conn_full_close(si->conn);
+	conn_full_close(conn);
 
 	si->ib->flags &= ~CF_SHUTR_NOW;
 	si->ib->flags |= CF_SHUTR;