From: Willy Tarreau Date: Mon, 9 Oct 2017 09:56:46 +0000 (+0200) Subject: MEDIUM: h2: implement basic recv/send/wake functions X-Git-Tag: v1.8-rc1~60 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a2af51291f5ee297bc4eb04f4c6efa440b2d4a36;p=thirdparty%2Fhaproxy.git MEDIUM: h2: implement basic recv/send/wake functions For now they don't do much since the buffers are not yet allocated, but the squeletton is here. --- diff --git a/src/mux_h2.c b/src/mux_h2.c index fa8f24a04e..aeea4ecf6e 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -226,11 +226,104 @@ static void h2_release(struct connection *conn) /* callback called on recv event by the connection handler */ static void h2_recv(struct connection *conn) { + struct h2c *h2c = conn->mux_ctx; + struct buffer *buf = h2c->dbuf; + int max; + + if (conn->flags & CO_FL_ERROR) + goto error; + + /* note: buf->o == 0 */ + max = buf->size - buf->i; + if (!max) { + /* FIXME: buffer full, add a flag, stop polling and wait */ + __conn_xprt_stop_recv(conn); + return; + } + + conn->xprt->rcv_buf(conn, buf, max); + if (conn->flags & CO_FL_ERROR) + goto error; + + if (buf->i == buf->size) { + /* buffer now full */ + __conn_xprt_stop_recv(conn); + return; + } + + /* FIXME: should we try to process streams here instead of doing it in ->wake ? */ + + if (conn_xprt_read0_pending(conn)) + __conn_xprt_stop_recv(conn); + return; + + error: + __conn_xprt_stop_recv(conn); } /* callback called on send event by the connection handler */ static void h2_send(struct connection *conn) { + struct h2c *h2c = conn->mux_ctx; + + /* FIXME: should we try to process pending streams here instead of doing it in ->wake ? */ + + if (conn->flags & CO_FL_ERROR) + goto error; + + if (conn->flags & (CO_FL_HANDSHAKE|CO_FL_WAIT_L4_CONN|CO_FL_WAIT_L6_CONN)) { + /* a handshake was requested */ + return; + } + + if (!h2c->mbuf->o) { + /* nothing to send */ + goto done; + } + + if (conn->flags & CO_FL_SOCK_WR_SH) { + /* output closed, nothing to send, clear the buffer to release it */ + h2c->mbuf->o = 0; + goto done; + } + + /* pending response data, we need to try to send or subscribe to + * writes. The snd_buf() function takes a "flags" argument which + * may be made of a combination of CO_SFL_MSG_MORE to indicate + * that more data immediately comes and CO_SFL_STREAMER to + * indicate that the connection is streaming lots of data (used + * to increase TLS record size at the expense of latency). The + * former could be sent any time there's a buffer full flag, as + * it indicates at least one stream attempted to send and failed + * so there are pending data. And alternative would be to set it + * as long as there's an active stream but that would be + * problematic for ACKs. The latter should possibly not be set + * for now. + */ + conn->xprt->snd_buf(conn, h2c->mbuf, 0); + + if (conn->flags & CO_FL_ERROR) + goto error; + + if (h2c->mbuf->o) { + /* incomplete send, the snd_buf callback has already updated + * the connection flags. + * + * FIXME: we should arm a send timeout here + */ + __conn_xprt_want_send(conn); + return; + } + + done: + /* FIXME: release the output buffer when empty or do it in ->wake() ? */ + __conn_xprt_stop_send(conn); + return; + + error: + /* FIXME: report an error somewhere in the mux */ + __conn_xprt_stop_send(conn); + return; } /* callback called on any event by the connection handler. @@ -239,6 +332,13 @@ static void h2_send(struct connection *conn) */ static int h2_wake(struct connection *conn) { + struct h2c *h2c = conn->mux_ctx; + + if ((conn->flags & CO_FL_ERROR) && eb_is_empty(&h2c->streams_by_id)) { + h2_release(conn); + return -1; + } + return 0; }