MEDIUM: applet: Set the appctx owner during allocation

The appctx owner is now always a conn-stream. Thus, it can be set during the
appctx allocation. But, to do so, the conn-stream must be created first. It
is not a problem on the server side because the conn-stream is created with
the stream. On the client side, we must take care to create the conn-stream
first.

This change should ease other changes about the applets bootstrapping.
diff --git a/include/haproxy/applet.h b/include/haproxy/applet.h
index 97b9c34..97164ac 100644
--- a/include/haproxy/applet.h
+++ b/include/haproxy/applet.h
@@ -59,7 +59,7 @@
  * appctx_free(). <applet> is assigned as the applet, but it can be NULL. The
  * applet's task is always created on the current thread.
  */
-static inline struct appctx *appctx_new(struct applet *applet)
+static inline struct appctx *appctx_new(struct applet *applet, void *owner)
 {
 	struct appctx *appctx;
 
@@ -67,6 +67,7 @@
 	if (likely(appctx != NULL)) {
 		appctx->obj_type = OBJ_TYPE_APPCTX;
 		appctx->applet = applet;
+		appctx->owner = owner;
 		appctx_init(appctx);
 		appctx->t = task_new_here();
 		if (unlikely(appctx->t == NULL)) {
diff --git a/src/dns.c b/src/dns.c
index 249db22..cd7780c 100644
--- a/src/dns.c
+++ b/src/dns.c
@@ -891,10 +891,15 @@
 	struct stream *s;
 	struct applet *applet = &dns_session_applet;
 
-	appctx = appctx_new(applet);
-	if (!appctx)
+	cs = cs_new();
+	if (!cs) {
+		ha_alert("out of memory in dns_session_create().\n");
 		goto out_close;
+	}
 
+	appctx = appctx_new(applet, cs);
+	if (!appctx)
+		goto out_free_cs;
 	appctx->ctx.sft.ptr = (void *)ds;
 
 	sess = session_new(ds->dss->srv->proxy, NULL, &appctx->obj_type);
@@ -903,22 +908,16 @@
 		goto out_free_appctx;
 	}
 
-	cs = cs_new();
-	if (!cs) {
-		ha_alert("out of memory in dns_session_create().\n");
-		goto out_free_sess;
-	}
-	cs_attach_endp(cs, &appctx->obj_type, appctx);
-
 	if ((s = stream_new(sess, cs, &BUF_NULL)) == NULL) {
 		ha_alert("Failed to initialize stream in dns_session_create().\n");
-		goto out_free_cs;
+		goto out_free_sess;
 	}
 
-
 	s->target = &ds->dss->srv->obj_type;
 	if (!sockaddr_alloc(&cs_si(s->csb)->dst, &ds->dss->srv->addr, sizeof(ds->dss->srv->addr)))
 		goto out_free_strm;
+
+	cs_attach_endp(cs, &appctx->obj_type, appctx);
 	s->flags = SF_ASSIGNED|SF_ADDR_SET;
 	cs_si(s->csb)->flags |= SI_FL_NOLINGER;
 
@@ -938,12 +937,12 @@
  out_free_strm:
 	LIST_DELETE(&s->list);
 	pool_free(pool_head_stream, s);
- out_free_cs:
-	cs_free(cs);
  out_free_sess:
 	session_free(sess);
  out_free_appctx:
 	appctx_free(appctx);
+ out_free_cs:
+	cs_free(cs);
  out_close:
 	return NULL;
 }
diff --git a/src/flt_spoe.c b/src/flt_spoe.c
index 5d0a535..36b1f9a 100644
--- a/src/flt_spoe.c
+++ b/src/flt_spoe.c
@@ -1991,9 +1991,13 @@
 	struct conn_stream *cs;
 	struct stream      *strm;
 
-	if ((appctx = appctx_new(&spoe_applet)) == NULL)
+	cs = cs_new();
+	if (!cs)
 		goto out_error;
 
+	if ((appctx = appctx_new(&spoe_applet, cs)) == NULL)
+		goto out_free_cs;
+
 	appctx->ctx.spoe.ptr = pool_zalloc(pool_head_spoe_appctx);
 	if (SPOE_APPCTX(appctx) == NULL)
 		goto out_free_appctx;
@@ -2024,14 +2028,10 @@
 	if (!sess)
 		goto out_free_spoe;
 
-	cs = cs_new();
-	if (!cs)
-		goto out_free_sess;
-	cs_attach_endp(cs, &appctx->obj_type, appctx);
-
 	if ((strm = stream_new(sess, cs, &BUF_NULL)) == NULL)
-		goto out_free_cs;
+		goto out_free_sess;
 
+	cs_attach_endp(cs, &appctx->obj_type, appctx);
 	stream_set_backend(strm, conf->agent->b.be);
 
 	/* applet is waiting for data */
@@ -2050,8 +2050,6 @@
 	return appctx;
 
 	/* Error unrolling */
- out_free_cs:
-	cs_free(cs);
  out_free_sess:
 	session_free(sess);
  out_free_spoe:
@@ -2060,6 +2058,8 @@
 	pool_free(pool_head_spoe_appctx, SPOE_APPCTX(appctx));
  out_free_appctx:
 	appctx_free(appctx);
+ out_free_cs:
+	cs_free(cs);
  out_error:
 	return NULL;
 }
diff --git a/src/hlua.c b/src/hlua.c
index ecc0762..270e3f6 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -2944,11 +2944,17 @@
 	lua_rawgeti(L, LUA_REGISTRYINDEX, class_socket_ref);
 	lua_setmetatable(L, -2);
 
+	cs = cs_new();
+	if (!cs) {
+		hlua_pusherror(L, "socket: out of memory");
+		goto out_fail_conf;
+	}
+
 	/* Create the applet context */
-	appctx = appctx_new(&update_applet);
+	appctx = appctx_new(&update_applet, cs);
 	if (!appctx) {
 		hlua_pusherror(L, "socket: out of memory");
-		goto out_fail_conf;
+		goto out_fail_cs;
 	}
 
 	appctx->ctx.hlua_cosocket.connected = 0;
@@ -2963,19 +2969,14 @@
 		goto out_fail_appctx;
 	}
 
-	cs = cs_new();
-	if (!cs) {
-		hlua_pusherror(L, "socket: out of memory");
-		goto out_fail_sess;
-	}
-	cs_attach_endp(cs, &appctx->obj_type, appctx);
-
 	strm = stream_new(sess, cs, &BUF_NULL);
 	if (!strm) {
 		hlua_pusherror(L, "socket: out of memory");
-		goto out_fail_cs;
+		goto out_fail_sess;
 	}
 
+	cs_attach_endp(cs, &appctx->obj_type, appctx);
+
 	/* Initialise cross reference between stream and Lua socket object. */
 	xref_create(&socket->xref, &appctx->ctx.hlua_cosocket.xref);
 
@@ -2991,12 +2992,12 @@
 
 	return 1;
 
- out_fail_cs:
-	cs_free(cs);
  out_fail_sess:
 	session_free(sess);
  out_fail_appctx:
 	appctx_free(appctx);
+ out_fail_cs:
+	cs_free(cs);
  out_fail_conf:
 	WILL_LJMP(lua_error(L));
 	return 0;
diff --git a/src/http_client.c b/src/http_client.c
index 33213a8..cf1165b 100644
--- a/src/http_client.c
+++ b/src/http_client.c
@@ -476,26 +476,27 @@
 		goto out;
 	}
 
+	cs = cs_new();
+	if (!cs) {
+		ha_alert("httpclient: out of memory in %s:%d.\n", __FUNCTION__, __LINE__);
+		goto out;
+	}
+
 	/* The HTTP client will be created in the same thread as the caller,
 	 * avoiding threading issues */
-	appctx = appctx_new(applet);
+	appctx = appctx_new(applet, cs);
 	if (!appctx)
-		goto out;
+		goto out_free_cs;
 
 	sess = session_new(httpclient_proxy, NULL, &appctx->obj_type);
 	if (!sess) {
 		ha_alert("httpclient: out of memory in %s:%d.\n", __FUNCTION__, __LINE__);
 		goto out_free_appctx;
 	}
-	cs = cs_new();
-	if (!cs) {
-		ha_alert("httpclient: out of memory in %s:%d.\n", __FUNCTION__, __LINE__);
-		goto out_free_sess;
-	}
-	cs_attach_endp(cs, &appctx->obj_type, appctx);
+
 	if ((s = stream_new(sess, cs, &hc->req.buf)) == NULL) {
 		ha_alert("httpclient: Failed to initialize stream %s:%d.\n", __FUNCTION__, __LINE__);
-		goto out_free_cs;
+		goto out_free_sess;
 	}
 
 	/* set the "timeout server" */
@@ -528,6 +529,7 @@
 			break;
 	}
 
+	cs_attach_endp(cs, &appctx->obj_type, appctx);
 	s->flags |= SF_ASSIGNED|SF_ADDR_SET;
 	cs_si(s->csb)->flags |= SI_FL_NOLINGER;
 	s->res.flags |= CF_READ_DONTWAIT;
@@ -550,12 +552,12 @@
 out_free_stream:
 	LIST_DELETE(&s->list);
 	pool_free(pool_head_stream, s);
-out_free_cs:
-	cs_free(cs);
 out_free_sess:
 	session_free(sess);
 out_free_appctx:
 	appctx_free(appctx);
+out_free_cs:
+	cs_free(cs);
 out:
 
 	return NULL;
diff --git a/src/peers.c b/src/peers.c
index 413f594..e2bcee7 100644
--- a/src/peers.c
+++ b/src/peers.c
@@ -3191,9 +3191,15 @@
 	peer->last_hdshk = now_ms;
 	s = NULL;
 
-	appctx = appctx_new(&peer_applet);
-	if (!appctx)
+	cs = cs_new();
+	if (!cs) {
+		ha_alert("out of memory in peer_session_create().\n");
 		goto out_close;
+	}
+
+	appctx = appctx_new(&peer_applet, cs);
+	if (!appctx)
+		goto out_free_cs;
 
 	appctx->st0 = PEER_SESS_ST_CONNECT;
 	appctx->ctx.peers.ptr = (void *)peer;
@@ -3204,16 +3210,9 @@
 		goto out_free_appctx;
 	}
 
-	cs = cs_new();
-	if (!cs) {
-		ha_alert("out of memory in peer_session_create().\n");
-		goto out_free_sess;
-	}
-	cs_attach_endp(cs, &appctx->obj_type, appctx);
-
 	if ((s = stream_new(sess, cs, &BUF_NULL)) == NULL) {
 		ha_alert("Failed to initialize stream in peer_session_create().\n");
-		goto out_free_cs;
+		goto out_free_sess;
 	}
 
 	/* applet is waiting for data */
@@ -3224,6 +3223,8 @@
 	s->target = peer_session_target(peer, s);
 	if (!sockaddr_alloc(&(cs_si(s->csb)->dst), &peer->addr, sizeof(peer->addr)))
 		goto out_free_strm;
+
+	cs_attach_endp(cs, &appctx->obj_type, appctx);
 	s->flags = SF_ASSIGNED|SF_ADDR_SET;
 	cs_si(s->csb)->flags |= SI_FL_NOLINGER;
 
@@ -3240,12 +3241,12 @@
  out_free_strm:
 	LIST_DELETE(&s->list);
 	pool_free(pool_head_stream, s);
- out_free_cs:
-	cs_free(cs);
  out_free_sess:
 	session_free(sess);
  out_free_appctx:
 	appctx_free(appctx);
+ out_free_cs:
+	cs_free(cs);
  out_close:
 	return NULL;
 }
diff --git a/src/sink.c b/src/sink.c
index eec8570..16d3533 100644
--- a/src/sink.c
+++ b/src/sink.c
@@ -643,9 +643,15 @@
 	if (sft->srv->log_proto == SRV_LOG_PROTO_OCTET_COUNTING)
 		applet = &sink_forward_oc_applet;
 
-	appctx = appctx_new(applet);
-	if (!appctx)
+	cs = cs_new();
+	if (!cs) {
+		ha_alert("out of memory in sink_forward_session_create");
 		goto out_close;
+	}
+
+	appctx = appctx_new(applet, cs);
+	if (!appctx)
+		goto out_free_cs;
 
 	appctx->ctx.sft.ptr = (void *)sft;
 
@@ -655,22 +661,17 @@
 		goto out_free_appctx;
 	}
 
-	cs = cs_new();
-	if (!cs) {
-		ha_alert("out of memory in sink_forward_session_create");
-		goto out_free_sess;
-	}
-	cs_attach_endp(cs, &appctx->obj_type, appctx);
-
 	if ((s = stream_new(sess, cs, &BUF_NULL)) == NULL) {
 		ha_alert("Failed to initialize stream in sink_forward_session_create().\n");
-		goto out_free_cs;
+		goto out_free_sess;
 	}
 
 
 	s->target = &sft->srv->obj_type;
 	if (!sockaddr_alloc(&cs_si(s->csb)->dst, &sft->srv->addr, sizeof(sft->srv->addr)))
 		goto out_free_strm;
+
+	cs_attach_endp(cs, &appctx->obj_type, appctx);
 	s->flags = SF_ASSIGNED|SF_ADDR_SET;
 	cs_si(s->csb)->flags |= SI_FL_NOLINGER;
 
@@ -690,12 +691,12 @@
  out_free_strm:
 	LIST_DELETE(&s->list);
 	pool_free(pool_head_stream, s);
-  out_free_cs:
-	cs_free(cs);
  out_free_sess:
 	session_free(sess);
  out_free_appctx:
 	appctx_free(appctx);
+ out_free_cs:
+	cs_free(cs);
  out_close:
 	return NULL;
 }
diff --git a/src/stream_interface.c b/src/stream_interface.c
index 703fd37..f8f7794 100644
--- a/src/stream_interface.c
+++ b/src/stream_interface.c
@@ -339,7 +339,7 @@
 
 	DPRINTF(stderr, "registering handler %p for si %p (was %p)\n", app, si, si_task(si));
 
-	appctx = appctx_new(app);
+	appctx = appctx_new(app, si->cs);
 	if (!appctx)
 		return NULL;
 	cs_attach_endp(si->cs, &appctx->obj_type, appctx);