diff --git a/include/proto/connection.h b/include/proto/connection.h index 1aa0ed909..0b4a0d845 100644 --- a/include/proto/connection.h +++ b/include/proto/connection.h @@ -632,6 +632,22 @@ static inline struct conn_stream *cs_new(struct connection *conn) return cs; } +/* Retrieves any valid conn_stream from this connection, preferably the first + * valid one. The purpose is to be able to figure one other end of a private + * connection for purposes like source binding or proxy protocol header + * emission. In such cases, any conn_stream is expected to be valid so the + * mux is encouraged to return the first one it finds. If the connection has + * no mux or the mux has no get_first_cs() method or the mux has no valid + * conn_stream, NULL is returned. The output pointer is purposely marked + * const to discourage the caller from modifying anything there. + */ +static inline const struct conn_stream *cs_get_first(const struct connection *conn) +{ + if (!conn || !conn->mux || !conn->mux->get_first_cs) + return NULL; + return conn->mux->get_first_cs(conn); +} + static inline void conn_force_unsubscribe(struct connection *conn) { if (conn->recv_wait) { diff --git a/include/types/connection.h b/include/types/connection.h index 889decb6c..ebc60e460 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -321,6 +321,7 @@ struct mux_ops { void (*shutw)(struct conn_stream *cs, enum cs_shw_mode); /* shutw function */ struct conn_stream *(*attach)(struct connection *); /* Create and attach a conn_stream to an outgoing connection */ + const struct conn_stream *(*get_first_cs)(const struct connection *); /* retrieves any valid conn_stream from this connection */ void (*detach)(struct conn_stream *); /* Detach a conn_stream from an outgoing connection, when the request is done */ void (*show_fd)(struct buffer *, struct connection *); /* append some data about connection into chunk for "show fd" */ int (*subscribe)(struct conn_stream *cs, int event_type, void *param); /* Subscribe to events, such as "being able to send" */ diff --git a/src/mux_h2.c b/src/mux_h2.c index de635127e..a643759f9 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -2539,6 +2539,27 @@ static struct conn_stream *h2_attach(struct connection *conn) return NULL; } +/* Retrieves the first valid conn_stream from this connection, or returns NULL. + * We have to scan because we may have some orphan streams. It might be + * beneficial to scan backwards from the end to reduce the likeliness to find + * orphans. + */ +static const struct conn_stream *h2_get_first_cs(const struct connection *conn) +{ + struct h2c *h2c = conn->mux_ctx; + struct h2s *h2s; + struct eb32_node *node; + + node = eb32_first(&h2c->streams_by_id); + while (node) { + h2s = container_of(node, struct h2s, by_id); + if (h2s->cs) + return h2s->cs; + node = eb32_next(node); + } + return NULL; +} + /* * Detach the stream from the connection and possibly release the connection. */ @@ -3770,6 +3791,7 @@ const struct mux_ops h2_ops = { .subscribe = h2_subscribe, .unsubscribe = h2_unsubscribe, .attach = h2_attach, + .get_first_cs = h2_get_first_cs, .detach = h2_detach, .shutr = h2_shutr, .shutw = h2_shutw, diff --git a/src/mux_pt.c b/src/mux_pt.c index 4195ec250..dd052c5fd 100644 --- a/src/mux_pt.c +++ b/src/mux_pt.c @@ -72,6 +72,16 @@ static struct conn_stream *mux_pt_attach(struct connection *conn) return NULL; } +/* Retrieves a valid conn_stream from this connection, or returns NULL. For + * this mux, it's easy as we can only store a single conn_stream. + */ +static const struct conn_stream *mux_pt_get_first_cs(const struct connection *conn) +{ + struct conn_stream *cs = conn->mux_ctx; + + return cs; +} + /* * Detach the stream from the connection and possibly release the connection. */ @@ -183,6 +193,7 @@ const struct mux_ops mux_pt_ops = { .snd_pipe = mux_pt_snd_pipe, #endif .attach = mux_pt_attach, + .get_first_cs = mux_pt_get_first_cs, .detach = mux_pt_detach, .shutr = mux_pt_shutr, .shutw = mux_pt_shutw,