/* * Conn-stream management functions * * Copyright 2021 Christopher Faulet * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * */ #include #include #include #include #include DECLARE_POOL(pool_head_connstream, "conn_stream", sizeof(struct conn_stream)); /* Tries to allocate a new conn_stream and initialize its main fields. On * failure, nothing is allocated and NULL is returned. */ struct conn_stream *cs_new() { struct conn_stream *cs; cs = pool_alloc(pool_head_connstream); if (unlikely(!cs)) return NULL; cs_init(cs); return cs; } /* Releases a conn_stream previously allocated by cs_new(), as well as any * buffer it would still hold. */ void cs_free(struct conn_stream *cs) { si_free(cs->si); pool_free(pool_head_connstream, cs); } /* Attaches a conn_stream to an endpoint and sets the endpoint ctx */ void cs_attach_endp(struct conn_stream *cs, enum obj_type *endp, void *ctx) { struct connection *conn; struct appctx *appctx; cs->end = endp; cs->ctx = ctx; if ((conn = objt_conn(endp)) != NULL) { if (!conn->ctx) conn->ctx = cs; if (cs_strm(cs)) { cs->si->ops = &si_conn_ops; cs->data_cb = &si_conn_cb; } else if (cs_check(cs)) cs->data_cb = &check_conn_cb; } else if ((appctx = objt_appctx(endp)) != NULL) { appctx->owner = cs; if (cs->si) { cs->si->ops = &si_applet_ops; cs->data_cb = NULL; } } } /* Attaches a conn_stream to a app layer and sets the relevant callbacks */ int cs_attach_app(struct conn_stream *cs, enum obj_type *app) { cs->app = app; if (objt_stream(app)) { if (!cs->si) cs->si = si_new(cs); if (unlikely(!cs->si)) return -1; if (cs_conn(cs)) { cs->si->ops = &si_conn_ops; cs->data_cb = &si_conn_cb; } else if (cs_appctx(cs)) { cs->si->ops = &si_applet_ops; cs->data_cb = NULL; } else { cs->si->ops = &si_embedded_ops; cs->data_cb = NULL; } } else if (objt_check(app)) cs->data_cb = &check_conn_cb; return 0; } /* Detach the conn_stream from the endpoint, if any. For a connecrion, if a mux * owns the connection ->detach() callback is called. Otherwise, it means the * conn-stream owns the connection. In this case the connection is closed and * released. For an applet, the appctx is released. At the end, the conn-stream * is not released but some fields a reset. */ void cs_detach_endp(struct conn_stream *cs) { struct connection *conn; struct appctx *appctx; if ((conn = cs_conn(cs))) { if (conn->mux) { /* TODO: handle unsubscribe for healthchecks too */ if (cs->si && cs->si->wait_event.events != 0) conn->mux->unsubscribe(cs, cs->si->wait_event.events, &cs->si->wait_event); conn->mux->detach(cs); } else { /* It's too early to have a mux, let's just destroy * the connection */ conn_stop_tracking(conn); conn_full_close(conn); if (conn->destroy_cb) conn->destroy_cb(conn); conn_free(conn); } } else if ((appctx = cs_appctx(cs))) { if (cs->si) si_applet_release(cs->si); appctx_free(appctx); } /* FIXME: Rest CS for now but must be reviewed. CS flags are only * connection related for now but this will evolved */ cs->flags = CS_FL_NONE; cs->end = NULL; cs->ctx = NULL; if (cs->si) cs->si->ops = &si_embedded_ops; cs->data_cb = NULL; if (cs->app == NULL) cs_free(cs); } void cs_detach_app(struct conn_stream *cs) { si_free(cs->si); cs->app = NULL; cs->si = NULL; cs->data_cb = NULL; if (cs->end == NULL) cs_free(cs); }