blob: df4181c15892048233501a5cecb0aee39b9a4191 [file] [log] [blame]
Christopher Faulet1329f2a2021-12-16 17:32:56 +01001/*
2 * Conn-stream management functions
3 *
4 * Copyright 2021 Christopher Faulet <cfaulet@haproxy.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <haproxy/api.h>
14#include <haproxy/connection.h>
15#include <haproxy/conn_stream.h>
16#include <haproxy/pool.h>
Christopher Fauletcda94ac2021-12-23 17:28:17 +010017#include <haproxy/stream_interface.h>
Christopher Faulet1329f2a2021-12-16 17:32:56 +010018
19DECLARE_POOL(pool_head_connstream, "conn_stream", sizeof(struct conn_stream));
20
21
Christopher Fauletdd2d0d82021-12-20 09:34:32 +010022/* Tries to allocate a new conn_stream and initialize its main fields. On
23 * failure, nothing is allocated and NULL is returned.
Christopher Faulet1329f2a2021-12-16 17:32:56 +010024 */
Christopher Fauletcda94ac2021-12-23 17:28:17 +010025struct conn_stream *cs_new()
Christopher Faulet1329f2a2021-12-16 17:32:56 +010026{
27 struct conn_stream *cs;
28
29 cs = pool_alloc(pool_head_connstream);
30 if (unlikely(!cs))
31 return NULL;
Christopher Fauletf835dea2021-12-21 14:35:17 +010032 cs_init(cs);
Christopher Faulet1329f2a2021-12-16 17:32:56 +010033 return cs;
34}
35
36/* Releases a conn_stream previously allocated by cs_new(), as well as any
37 * buffer it would still hold.
38 */
39void cs_free(struct conn_stream *cs)
40{
Christopher Fauletcda94ac2021-12-23 17:28:17 +010041 si_free(cs->si);
Christopher Faulet1329f2a2021-12-16 17:32:56 +010042 pool_free(pool_head_connstream, cs);
43}
Christopher Fauletcda94ac2021-12-23 17:28:17 +010044
45
46/* Attaches a conn_stream to an endpoint and sets the endpoint ctx */
47void cs_attach_endp(struct conn_stream *cs, enum obj_type *endp, void *ctx)
48{
49 struct connection *conn;
50 struct appctx *appctx;
51
52 cs->end = endp;
53 cs->ctx = ctx;
54 if ((conn = objt_conn(endp)) != NULL) {
55 if (!conn->ctx)
56 conn->ctx = cs;
57 if (cs_strm(cs)) {
58 cs->si->ops = &si_conn_ops;
59 cs->data_cb = &si_conn_cb;
60 }
61 else if (cs_check(cs))
62 cs->data_cb = &check_conn_cb;
63 }
64 else if ((appctx = objt_appctx(endp)) != NULL) {
65 appctx->owner = cs;
66 if (cs->si) {
67 cs->si->ops = &si_applet_ops;
68 cs->data_cb = NULL;
69 }
70 }
71}
72
73/* Attaches a conn_stream to a app layer and sets the relevant callbacks */
74int cs_attach_app(struct conn_stream *cs, enum obj_type *app)
75{
76 cs->app = app;
77
78 if (objt_stream(app)) {
79 if (!cs->si)
80 cs->si = si_new(cs);
81 if (unlikely(!cs->si))
82 return -1;
83
84 if (cs_conn(cs)) {
85 cs->si->ops = &si_conn_ops;
86 cs->data_cb = &si_conn_cb;
87 }
88 else if (cs_appctx(cs)) {
89 cs->si->ops = &si_applet_ops;
90 cs->data_cb = NULL;
91 }
92 else {
93 cs->si->ops = &si_embedded_ops;
94 cs->data_cb = NULL;
95 }
96 }
97 else if (objt_check(app))
98 cs->data_cb = &check_conn_cb;
99 return 0;
100}
101
102/* Detach the conn_stream from the endpoint, if any. For a connecrion, if a mux
103 * owns the connection ->detach() callback is called. Otherwise, it means the
104 * conn-stream owns the connection. In this case the connection is closed and
105 * released. For an applet, the appctx is released. At the end, the conn-stream
106 * is not released but some fields a reset.
107 */
108void cs_detach_endp(struct conn_stream *cs)
109{
110 struct connection *conn;
111 struct appctx *appctx;
112
113 if ((conn = cs_conn(cs))) {
114 if (conn->mux) {
Christopher Faulet54e85cb2022-01-06 08:46:56 +0100115 /* TODO: handle unsubscribe for healthchecks too */
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100116 if (cs->si && cs->si->wait_event.events != 0)
117 conn->mux->unsubscribe(cs, cs->si->wait_event.events, &cs->si->wait_event);
118 conn->mux->detach(cs);
119 }
120 else {
121 /* It's too early to have a mux, let's just destroy
122 * the connection
123 */
124 conn_stop_tracking(conn);
125 conn_full_close(conn);
126 if (conn->destroy_cb)
127 conn->destroy_cb(conn);
128 conn_free(conn);
129 }
130 }
131 else if ((appctx = cs_appctx(cs))) {
132 if (appctx->applet->release)
133 appctx->applet->release(appctx);
134 appctx_free(appctx);
135 }
136
Christopher Fauletc36de9d2022-01-06 08:44:58 +0100137 /* FIXME: Rest CS for now but must be reviewed. CS flags are only
138 * connection related for now but this will evolved
139 */
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100140 cs->flags = CS_FL_NONE;
141 cs->end = NULL;
142 cs->ctx = NULL;
143 if (cs->si)
144 cs->si->ops = &si_embedded_ops;
145 cs->data_cb = NULL;
Christopher Fauletc36de9d2022-01-06 08:44:58 +0100146
147 if (cs->app == NULL)
148 cs_free(cs);
149}
150
151void cs_detach_app(struct conn_stream *cs)
152{
153 si_free(cs->si);
154 cs->app = NULL;
155 cs->si = NULL;
156 cs->data_cb = NULL;
157
158 if (cs->end == NULL)
159 cs_free(cs);
Christopher Fauletcda94ac2021-12-23 17:28:17 +0100160}