MAJOR: session: introduce embryonic sessions

When an incoming connection request is accepted, a connection
structure is needed to store its state. However we don't want to
fully initialize a session until the data layer is about to be
ready.

As long as the connection is physically stored into the session,
it's not easy to split both allocations.

As such, we only initialize the minimum requirements of a session,
which results in what we call an embryonic session. Then once the
data layer is ready, we can complete the function's initialization.

Doing so avoids buffers allocation and ensures that a session only
sees ready connections.

The frontend's client timeout is used as the handshake timeout. It
is likely that another timeout will be used in the future.
diff --git a/src/connection.c b/src/connection.c
index 0abbe42..9e3d79e 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -15,6 +15,7 @@
 
 #include <proto/connection.h>
 #include <proto/proto_tcp.h>
+#include <proto/session.h>
 #include <proto/stream_interface.h>
 
 /* I/O callback for fd-based connections. It calls the read/write handlers
@@ -25,7 +26,7 @@
 	struct connection *conn = fdtab[fd].owner;
 
 	if (unlikely(!conn))
-		goto leave;
+		return 0;
 
  process_handshake:
 	/* The handshake callbacks are called in sequence. If either of them is
@@ -47,6 +48,14 @@
 	if (!(conn->flags & CO_FL_POLL_SOCK))
 		__conn_sock_stop_both(conn);
 
+	/* Maybe we need to finish initializing an incoming session. The
+	 * function may fail and cause the connection to be destroyed, thus
+	 * we must not use it anymore and should immediately leave instead.
+	 */
+	if ((conn->flags & CO_FL_INIT_SESS) &&
+	    conn_session_initialize(conn, CO_FL_INIT_SESS) < 0)
+		return 0;
+
 	if (fdtab[fd].ev & (FD_POLL_IN | FD_POLL_HUP | FD_POLL_ERR))
 		conn->app_cb->recv(conn);
 
@@ -80,6 +89,13 @@
 	}
 
  leave:
+	/* we may need to release the connection which is an embryonic session */
+	if ((conn->flags & (CO_FL_ERROR|CO_FL_INIT_SESS)) == (CO_FL_ERROR|CO_FL_INIT_SESS)) {
+		conn->flags |= CO_FL_ERROR;
+		conn_session_complete(conn, CO_FL_INIT_SESS);
+		return 0;
+	}
+
 	if (conn->flags & CO_FL_NOTIFY_SI)
 		conn_notify_si(conn);