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.
This commit is contained in:
Willy Tarreau 2017-10-09 16:21:43 +02:00
parent 5160683fc7
commit bc933930a7

View File

@ -576,6 +576,19 @@ static struct h2s *h2c_stream_new(struct h2c *h2c, int id)
return h2s; 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 */ /* 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) if (buf->i == buf->size)
h2c->flags |= H2_CF_DEM_DFULL; 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 */ /* after streams have been processed, we should have made some room */
if (buf->i != buf->size) if (buf->i != buf->size)
@ -631,8 +644,7 @@ static void h2_recv(struct connection *conn)
static void h2_send(struct connection *conn) static void h2_send(struct connection *conn)
{ {
struct h2c *h2c = conn->mux_ctx; struct h2c *h2c = conn->mux_ctx;
int done;
/* FIXME: should we try to process pending streams here instead of doing it in ->wake ? */
if (conn->flags & CO_FL_ERROR) if (conn->flags & CO_FL_ERROR)
return; return;
@ -642,29 +654,50 @@ static void h2_send(struct connection *conn)
return; 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) { if (conn->flags & CO_FL_SOCK_WR_SH) {
/* output closed, nothing to send, clear the buffer to release it */ /* output closed, nothing to send, clear the buffer to release it */
h2c->mbuf->o = 0; 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 */ /* call the wake up function of all streams attached to the connection */