From bc933930a709e9bf96450b98805df1f6b57bfa1f Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 9 Oct 2017 16:21:43 +0200 Subject: [PATCH] MEDIUM: h2: start to implement the frames processing loop The rcv_buf() callback now calls h2_process_demux() after an recv() call leaving some data in the buffer, and the snd_buf() callback calls h2_process_mux() to try to process pending data from streams. --- src/mux_h2.c | 77 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 22 deletions(-) diff --git a/src/mux_h2.c b/src/mux_h2.c index 9776deaa3..08b665709 100644 --- a/src/mux_h2.c +++ b/src/mux_h2.c @@ -576,6 +576,19 @@ static struct h2s *h2c_stream_new(struct h2c *h2c, int id) return h2s; } +/* process Rx frames to be demultiplexed */ +static void h2_process_demux(struct h2c *h2c) +{ +} + +/* process Tx frames from streams to be multiplexed. Returns > 0 if it reached + * the end. + */ +static int h2_process_mux(struct h2c *h2c) +{ + return 1; +} + /*********************************************************/ /* functions below are I/O callbacks from the connection */ @@ -619,7 +632,7 @@ static void h2_recv(struct connection *conn) if (buf->i == buf->size) h2c->flags |= H2_CF_DEM_DFULL; - /* FIXME: should we try to process streams here instead of doing it in ->wake ? */ + h2_process_demux(h2c); /* after streams have been processed, we should have made some room */ if (buf->i != buf->size) @@ -631,8 +644,7 @@ static void h2_recv(struct connection *conn) 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 ? */ + int done; if (conn->flags & CO_FL_ERROR) return; @@ -642,29 +654,50 @@ static void h2_send(struct connection *conn) return; } + /* This loop is quite simple : it tries to fill as much as it can from + * pending streams into the existing buffer until it's reportedly full + * or the end of send requests is reached. Then it tries to send this + * buffer's contents out, marks it not full if at least one byte could + * be sent, and tries again. + * + * The snd_buf() function normally 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 can 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. An + * alternative would be to set it as long as there's an active stream + * but that would be problematic for ACKs until we have an absolute + * guarantee that all waiters have at least one byte to send. The + * latter should possibly not be set for now. + */ + + done = 0; + while (!done) { + unsigned int flags = 0; + + /* fill as much as we can into the current buffer */ + while (((h2c->flags & (H2_CF_MUX_MFULL|H2_CF_MUX_MALLOC)) == 0) && !done) + done = h2_process_mux(h2c); + + if (conn->flags & CO_FL_ERROR) + break; + + if (h2c->flags & (H2_CF_MUX_MFULL | H2_CF_DEM_MBUSY | H2_CF_DEM_MROOM)) + flags |= CO_SFL_MSG_MORE; + + if (conn->xprt->snd_buf(conn, h2c->mbuf, flags) <= 0) + break; + + /* wrote at least one byte, the buffer is not full anymore */ + h2c->flags &= ~(H2_CF_MUX_MFULL | H2_CF_DEM_MROOM); + } + if (conn->flags & CO_FL_SOCK_WR_SH) { /* output closed, nothing to send, clear the buffer to release it */ h2c->mbuf->o = 0; } - - /* 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. - */ - if (conn->xprt->snd_buf(conn, h2c->mbuf, 0) > 0) - h2c->flags &= ~(H2_CF_MUX_MFULL | H2_CF_DEM_MROOM); - - if (conn->flags & CO_FL_ERROR) - return; } /* call the wake up function of all streams attached to the connection */