MEDIUM: spoe: Refactor SPOE appctx creation

A .init callback function is defined for the spoe_applet applet. This
function finishes the spoe_appctx initialization. It also finishes the
appctx startup by calling appctx_finalize_startup() and its handles the
stream customization.
diff --git a/src/flt_spoe.c b/src/flt_spoe.c
index c176a9b..99ef7d6 100644
--- a/src/flt_spoe.c
+++ b/src/flt_spoe.c
@@ -1214,6 +1214,52 @@
 	return task;
 }
 
+static int
+spoe_init_appctx(struct appctx *appctx)
+{
+	struct spoe_appctx *spoe_appctx = SPOE_APPCTX(appctx);
+	struct spoe_agent *agent = spoe_appctx->agent;
+	struct task *task;
+	struct stream *s;
+
+	if ((task = task_new_here()) == NULL)
+		goto out_free_task;
+	task->process = spoe_process_appctx;
+	task->context = appctx;
+
+	if (appctx_finalize_startup(appctx, &agent->spoe_conf->agent_fe, &BUF_NULL) == -1)
+		goto out_error;
+
+	spoe_appctx->owner = appctx;
+	spoe_appctx->task  = task;
+
+	LIST_INIT(&spoe_appctx->buffer_wait.list);
+	spoe_appctx->buffer_wait.target = appctx;
+	spoe_appctx->buffer_wait.wakeup_cb = (int (*)(void *))spoe_wakeup_appctx;
+
+	s = appctx_strm(appctx);
+	stream_set_backend(s, agent->b.be);
+
+	/* applet is waiting for data */
+	cs_cant_get(s->csf);
+
+	s->do_log = NULL;
+	s->res.flags |= CF_READ_DONTWAIT;
+
+	HA_SPIN_LOCK(SPOE_APPLET_LOCK, &agent->rt[tid].lock);
+	LIST_APPEND(&agent->rt[tid].applets, &spoe_appctx->list);
+	HA_SPIN_UNLOCK(SPOE_APPLET_LOCK, &agent->rt[tid].lock);
+	_HA_ATOMIC_INC(&agent->counters.applets);
+
+	appctx->st0 = SPOE_APPCTX_ST_CONNECT;
+	task_wakeup(spoe_appctx->task, TASK_WOKEN_INIT);
+	return 0;
+  out_free_task:
+	task_destroy(task);
+  out_error:
+	return -1;
+}
+
 /* Callback function that releases a SPOE applet. This happens when the
  * connection with the agent is closed. */
 static void
@@ -1980,6 +2026,7 @@
 	.obj_type = OBJ_TYPE_APPLET,
 	.name = "<SPOE>", /* used for logging */
 	.fct = spoe_handle_appctx,
+	.init = spoe_init_appctx,
 	.release = spoe_release_appctx,
 };
 
@@ -1988,74 +2035,39 @@
 static struct appctx *
 spoe_create_appctx(struct spoe_config *conf)
 {
-	struct appctx      *appctx;
-	struct session     *sess;
-	struct conn_stream *cs;
-	struct stream      *strm;
+	struct spoe_appctx *spoe_appctx;
+	struct appctx *appctx;
 
-	if ((appctx = appctx_new(&spoe_applet, NULL)) == NULL)
+	spoe_appctx = pool_zalloc(pool_head_spoe_appctx);
+	if (spoe_appctx == NULL)
 		goto out_error;
 
-	appctx->svcctx = pool_zalloc(pool_head_spoe_appctx);
-	if (SPOE_APPCTX(appctx) == NULL)
-		goto out_free_appctx;
-
-	appctx->st0 = SPOE_APPCTX_ST_CONNECT;
-	if ((SPOE_APPCTX(appctx)->task = task_new_here()) == NULL)
-		goto out_free_spoe_appctx;
-
-	SPOE_APPCTX(appctx)->owner           = appctx;
-	SPOE_APPCTX(appctx)->task->process   = spoe_process_appctx;
-	SPOE_APPCTX(appctx)->task->context   = appctx;
-	SPOE_APPCTX(appctx)->agent           = conf->agent;
-	SPOE_APPCTX(appctx)->version         = 0;
-	SPOE_APPCTX(appctx)->max_frame_size  = conf->agent->max_frame_size;
-	SPOE_APPCTX(appctx)->flags           = 0;
-	SPOE_APPCTX(appctx)->status_code     = SPOE_FRM_ERR_NONE;
-	SPOE_APPCTX(appctx)->buffer          = BUF_NULL;
-	SPOE_APPCTX(appctx)->cur_fpa         = 0;
-
-	LIST_INIT(&SPOE_APPCTX(appctx)->buffer_wait.list);
-	SPOE_APPCTX(appctx)->buffer_wait.target = appctx;
-	SPOE_APPCTX(appctx)->buffer_wait.wakeup_cb = (int (*)(void *))spoe_wakeup_appctx;
+	spoe_appctx->agent           = conf->agent;
+	spoe_appctx->version         = 0;
+	spoe_appctx->max_frame_size  = conf->agent->max_frame_size;
+	spoe_appctx->flags           = 0;
+	spoe_appctx->status_code     = SPOE_FRM_ERR_NONE;
+	spoe_appctx->buffer          = BUF_NULL;
+	spoe_appctx->cur_fpa         = 0;
+	LIST_INIT(&spoe_appctx->list);
+	LIST_INIT(&spoe_appctx->waiting_queue);
 
-	LIST_INIT(&SPOE_APPCTX(appctx)->list);
-	LIST_INIT(&SPOE_APPCTX(appctx)->waiting_queue);
 
-	sess = session_new(&conf->agent_fe, NULL, &appctx->obj_type);
-	if (!sess)
-		goto out_free_spoe;
-
-	appctx->sess = sess;
-	cs = cs_new_from_endp(appctx->endp, sess, &BUF_NULL);
-	if (!cs)
-		goto out_free_spoe;
+	if ((appctx = appctx_new(&spoe_applet, NULL)) == NULL)
+		goto out_free_spoe_appctx;
 
-	strm = DISGUISE(cs_strm(cs));
-	stream_set_backend(strm, conf->agent->b.be);
+	appctx->svcctx = spoe_appctx;
+	if (appctx_init(appctx) == -1)
+		goto out_free_appctx;
 
-	/* applet is waiting for data */
-	cs_cant_get(strm->csf);
 	appctx_wakeup(appctx);
-
-	strm->do_log = NULL;
-	strm->res.flags |= CF_READ_DONTWAIT;
-
-	HA_SPIN_LOCK(SPOE_APPLET_LOCK, &conf->agent->rt[tid].lock);
-	LIST_APPEND(&conf->agent->rt[tid].applets, &SPOE_APPCTX(appctx)->list);
-	HA_SPIN_UNLOCK(SPOE_APPLET_LOCK, &conf->agent->rt[tid].lock);
-	_HA_ATOMIC_INC(&conf->agent->counters.applets);
-
-	task_wakeup(SPOE_APPCTX(appctx)->task, TASK_WOKEN_INIT);
 	return appctx;
 
 	/* Error unrolling */
- out_free_spoe:
-	task_destroy(SPOE_APPCTX(appctx)->task);
- out_free_spoe_appctx:
-	pool_free(pool_head_spoe_appctx, SPOE_APPCTX(appctx));
  out_free_appctx:
-	appctx_free(appctx);
+	appctx_free_on_early_error(appctx);
+ out_free_spoe_appctx:
+	pool_free(pool_head_spoe_appctx, spoe_appctx);
  out_error:
 	return NULL;
 }