From e393fe224bd90640dbc967f28c2872441f1e3f48 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sat, 16 Aug 2008 22:18:07 +0200 Subject: [PATCH] [MEDIUM] buffers: add BF_EMPTY and BF_FULL to remove dependency on req/rep->l It is not always convenient to run checks on req->l in functions to check if a buffer is empty or full. Now the stream_sock functions set flags BF_EMPTY and BF_FULL according to the buffer contents. Of course, functions which touch the buffer contents adjust the flags too. --- include/proto/buffers.h | 27 +++++++++++++++++++---- include/types/buffers.h | 7 +++++- src/buffers.c | 32 ++++++++++++++++++++++++++- src/client.c | 1 - src/proto_http.c | 49 ++++++++++++++++++++--------------------- src/proto_uxst.c | 36 ++++++++++++++---------------- src/senddata.c | 4 ++-- src/stream_sock.c | 9 +++++++- 8 files changed, 111 insertions(+), 54 deletions(-) diff --git a/include/proto/buffers.h b/include/proto/buffers.h index 4090eade9..27bf2ea89 100644 --- a/include/proto/buffers.h +++ b/include/proto/buffers.h @@ -40,12 +40,15 @@ int init_buffer(); /* Initializes all fields in the buffer. The ->rlim field is initialized last * so that the compiler can optimize it away if changed immediately after the - * call to this function. + * call to this function. By default, it is set to the full size of the buffer. + * The BF_EMPTY flags is set. */ static inline void buffer_init(struct buffer *buf) { - buf->l = buf->total = buf->flags = 0; - buf->rlim = buf->r = buf->lr = buf->w = buf->data; + buf->l = buf->total = 0; + buf->r = buf->lr = buf->w = buf->data; + buf->flags = BF_EMPTY; + buf->rlim = buf->data + BUFSIZE; } /* returns 1 if the buffer is empty, 0 otherwise */ @@ -59,11 +62,16 @@ static inline int buffer_isfull(const struct buffer *buf) { return buf->l == BUFSIZE; } -/* flushes any content from buffer */ +/* flushes any content from buffer and adjusts flags + * accordingly. + */ static inline void buffer_flush(struct buffer *buf) { buf->r = buf->lr = buf->w = buf->data; buf->l = 0; + buf->flags |= BF_EMPTY | BF_FULL; + if (buf->rlim) + buf->flags &= ~BF_FULL; } /* marks the buffer as "shutdown" for reads and cancels the timeout */ @@ -91,6 +99,17 @@ static inline int buffer_max(const struct buffer *buf) return buf->w - buf->r; } +/* sets the buffer read limit to bytes, and adjusts the FULL + * flag accordingly. + */ +static inline void buffer_set_rlim(struct buffer *buf, int size) +{ + buf->rlim = buf->data + size; + if (buf->l < size) + buf->flags &= ~BF_FULL; + else + buf->flags |= BF_FULL; +} /* * Tries to realign the given buffer, and returns how many bytes can be written diff --git a/include/types/buffers.h b/include/types/buffers.h index be9369358..0c3bb3726 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -26,8 +26,13 @@ #include /* The BF_* macros designate Buffer Flags, which may be ORed in the bit field - * member 'flags' in struct buffer. + * member 'flags' in struct buffer. Some of them are persistent (BF_SHUT*), + * some of them (BF_EMPTY,BF_FULL) may only be set by the low-level read/write + * functions as well as those who change the buffer's read limit. */ +#define BF_EMPTY 1 /* buffer is empty */ +#define BF_FULL 2 /* buffer cannot accept any more data (l >= rlim-data) */ + #define BF_SHUTR 4 /* producer has already shut down */ #define BF_SHUTW 8 /* consumer has already shut down */ diff --git a/src/buffers.c b/src/buffers.c index fa6b8a906..f7e672d07 100644 --- a/src/buffers.c +++ b/src/buffers.c @@ -49,6 +49,12 @@ int buffer_write(struct buffer *buf, const char *msg, int len) if (buf->r == buf->data + BUFSIZE) buf->r = buf->data; + buf->flags &= ~(BF_EMPTY|BF_FULL); + if (buf->l == 0) + buf->flags |= BF_EMPTY; + if (buf->l >= buf->rlim - buf->data) + buf->flags |= BF_FULL; + return -1; } @@ -74,8 +80,14 @@ int buffer_write_chunk(struct buffer *buf, struct chunk *chunk) buf->total += chunk->len; if (buf->r == buf->data + BUFSIZE) buf->r = buf->data; - chunk->len = 0; + buf->flags &= ~(BF_EMPTY|BF_FULL); + if (buf->l == 0) + buf->flags |= BF_EMPTY; + if (buf->l >= buf->rlim - buf->data) + buf->flags |= BF_FULL; + + chunk->len = 0; return -1; } @@ -110,6 +122,12 @@ int buffer_replace(struct buffer *b, char *pos, char *end, const char *str) if (b->lr > pos) b->lr += delta; b->l += delta; + b->flags &= ~(BF_EMPTY|BF_FULL); + if (b->l == 0) + b->flags |= BF_EMPTY; + if (b->l >= b->rlim - b->data) + b->flags |= BF_FULL; + return delta; } @@ -145,6 +163,12 @@ int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int if (b->lr > pos) b->lr += delta; b->l += delta; + b->flags &= ~(BF_EMPTY|BF_FULL); + if (b->l == 0) + b->flags |= BF_EMPTY; + if (b->l >= b->rlim - b->data) + b->flags |= BF_FULL; + return delta; } @@ -183,6 +207,12 @@ int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len) if (b->lr > pos) b->lr += delta; b->l += delta; + b->flags &= ~(BF_EMPTY|BF_FULL); + if (b->l == 0) + b->flags |= BF_EMPTY; + if (b->l >= b->rlim - b->data) + b->flags |= BF_FULL; + return delta; } diff --git a/src/client.c b/src/client.c index 7135d7177..67c6dc795 100644 --- a/src/client.c +++ b/src/client.c @@ -333,7 +333,6 @@ int event_accept(int fd) { goto out_fail_req; /* no memory */ buffer_init(s->req); - s->req->rlim += BUFSIZE; if (p->mode == PR_MODE_HTTP) /* reserve some space for header rewriting */ s->req->rlim -= MAXREWRITE; diff --git a/src/proto_http.c b/src/proto_http.c index acbe5ddca..294ab3745 100644 --- a/src/proto_http.c +++ b/src/proto_http.c @@ -1743,7 +1743,7 @@ int process_request(struct session *t) * later, so the session will never terminate. We * must terminate it now. */ - if (unlikely(req->l >= req->rlim - req->data)) { + if (unlikely(req->flags & BF_FULL)) { /* FIXME: check if URI is set and return Status * 414 Request URI too long instead. */ @@ -2331,7 +2331,7 @@ int process_request(struct session *t) */ if (!(t->flags & (SN_ASSIGNED|SN_DIRECT)) && t->txn.meth == HTTP_METH_POST && t->be->url_param_name != NULL && - t->be->url_param_post_limit != 0 && req->l < BUFSIZE && + t->be->url_param_post_limit != 0 && !(req->flags & BF_FULL) && memchr(msg->sol + msg->sl.rq.u, '?', msg->sl.rq.u_l) == NULL) { /* are there enough bytes here? total == l || r || rlim ? * len is unsigned, but eoh is int, @@ -2408,7 +2408,7 @@ int process_request(struct session *t) * could. Let's switch to the DATA state. * ************************************************************/ - req->rlim = req->data + BUFSIZE; /* no more rewrite needed */ + buffer_set_rlim(req, BUFSIZE); /* no more rewrite needed */ t->logs.tv_request = now; /* When a connection is tarpitted, we use the tarpit timeout, @@ -2418,7 +2418,7 @@ int process_request(struct session *t) * FIXME: this part should be moved elsewhere (eg: on the server side) */ if (txn->flags & TX_CLTARPIT) { - t->req->l = 0; + buffer_flush(t->req); /* flush the request so that we can drop the connection early * if the client closes first. */ @@ -2502,8 +2502,7 @@ int process_request(struct session *t) * buffer closed). */ if (req->l - body >= limit || /* enough bytes! */ - req->l >= req->rlim - req->data || /* full */ - req->flags & (BF_READ_ERROR | BF_READ_NULL | BF_READ_TIMEOUT)) { + req->flags & (BF_FULL | BF_READ_ERROR | BF_READ_NULL | BF_READ_TIMEOUT)) { /* The situation will not evolve, so let's give up on the analysis. */ t->logs.tv_request = now; /* update the request timer to reflect full request */ t->analysis &= ~AN_REQ_HTTP_BODY; @@ -2542,9 +2541,9 @@ int process_response(struct session *t) * For the parsing, we use a 28 states FSM. * * Here is the information we currently have : - * rep->data + req->som = beginning of response - * rep->data + req->eoh = end of processed headers / start of current one - * rep->data + req->eol = end of current header or line (LF or CRLF) + * rep->data + rep->som = beginning of response + * rep->data + rep->eoh = end of processed headers / start of current one + * rep->data + rep->eol = end of current header or line (LF or CRLF) * rep->lr = first non-visited byte * rep->r = end of data */ @@ -2644,7 +2643,7 @@ int process_response(struct session *t) return 1; } /* too large response does not fit in buffer. */ - else if (rep->l >= rep->rlim - rep->data) { + else if (rep->flags & BF_FULL) { goto hdr_response_bad; } /* read timeout : return a 504 to the client. */ @@ -2948,7 +2947,7 @@ int process_response(struct session *t) * could. Let's switch to the DATA state. * ************************************************************/ - rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */ + buffer_set_rlim(rep, BUFSIZE); /* no more rewrite needed */ t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now); #ifdef CONFIG_HAP_TCPSPLICE @@ -3049,7 +3048,7 @@ int process_cli(struct session *t) * allowed to forward the data. */ else if (!(rep->flags & BF_SHUTW) && /* already done */ - rep->l == 0 && rep->flags & BF_MAY_FORWARD && + rep->flags & BF_EMPTY && rep->flags & BF_MAY_FORWARD && rep->flags & BF_SHUTR && !(t->flags & SN_SELF_GEN)) { buffer_shutw(rep); if (!(req->flags & BF_SHUTR)) { @@ -3129,7 +3128,7 @@ int process_cli(struct session *t) /* manage read timeout */ if (!(req->flags & BF_SHUTR)) { - if (req->l >= req->rlim - req->data) { + if (req->flags & BF_FULL) { /* no room to read more data */ if (EV_FD_COND_C(t->cli_fd, DIR_RD)) { /* stop reading until we get some space */ @@ -3148,7 +3147,7 @@ int process_cli(struct session *t) */ if (req->flags & BF_SHUTR && t->flags & SN_SELF_GEN) { produce_content(t); - if (rep->l == 0) { + if (rep->flags & BF_EMPTY) { buffer_shutw(rep); fd_delete(t->cli_fd); t->cli_state = CL_STCLOSE; @@ -3158,7 +3157,7 @@ int process_cli(struct session *t) } /* we don't enable client write if the buffer is empty, nor if the server has to analyze it */ - if ((rep->l == 0) || !(rep->flags & BF_MAY_FORWARD)) { + if ((rep->flags & BF_EMPTY) || !(rep->flags & BF_MAY_FORWARD)) { if (EV_FD_COND_C(t->cli_fd, DIR_WR)) { /* stop writing */ rep->wex = TICK_ETERNITY; @@ -3227,7 +3226,7 @@ int process_srv(struct session *t) if (t->srv_state == SV_STIDLE) { if ((rep->flags & BF_SHUTW) || ((req->flags & BF_SHUTR) && - (req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */ + (req->flags & BF_EMPTY || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */ req->cex = TICK_ETERNITY; if (t->pend_pos) t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now); @@ -3359,7 +3358,7 @@ int process_srv(struct session *t) else if (t->srv_state == SV_STCONN) { /* connection in progress */ if ((rep->flags & BF_SHUTW) || ((req->flags & BF_SHUTR) && - ((req->l == 0 && !(req->flags & BF_WRITE_STATUS)) || + ((req->flags & BF_EMPTY && !(req->flags & BF_WRITE_STATUS)) || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */ req->cex = TICK_ETERNITY; if (!(t->flags & SN_CONN_TAR)) { @@ -3458,10 +3457,10 @@ int process_srv(struct session *t) else { /* no error or write 0 */ t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now); - if (req->l == 0) /* nothing to write */ { + if (req->flags & BF_EMPTY) { EV_FD_CLR(t->srv_fd, DIR_WR); req->wex = TICK_ETERNITY; - } else /* need the right to write */ { + } else { EV_FD_SET(t->srv_fd, DIR_WR); req->wex = tick_add_ifset(now_ms, t->be->timeout.server); if (tick_isset(req->wex)) { @@ -3475,7 +3474,7 @@ int process_srv(struct session *t) EV_FD_SET(t->srv_fd, DIR_RD); rep->rex = tick_add_ifset(now_ms, t->be->timeout.server); t->srv_state = SV_STDATA; - rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */ + buffer_set_rlim(rep, BUFSIZE); /* no rewrite needed */ /* if the user wants to log as soon as possible, without counting bytes from the server, then this is the right moment. */ @@ -3493,7 +3492,7 @@ int process_srv(struct session *t) else { t->srv_state = SV_STDATA; t->analysis |= AN_RTR_HTTP_HDR; - rep->rlim = rep->data + BUFSIZE - MAXREWRITE; /* rewrite needed */ + buffer_set_rlim(rep, BUFSIZE - MAXREWRITE); /* rewrite needed */ t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE; /* reset hdr_idx which was already initialized by the request. * right now, the http parser does it. @@ -3558,7 +3557,7 @@ int process_srv(struct session *t) * coming from the server. */ else if (!(req->flags & BF_SHUTW) && /* not already done */ - req->l == 0 && req->flags & BF_MAY_FORWARD && + req->flags & BF_EMPTY && req->flags & BF_MAY_FORWARD && (req->flags & BF_SHUTR || (t->be->options & PR_O_FORCE_CLO && rep->flags & BF_READ_STATUS))) { buffer_shutw(req); @@ -3642,7 +3641,7 @@ int process_srv(struct session *t) /* manage read timeout */ if (!(rep->flags & BF_SHUTR)) { - if (rep->l >= rep->rlim - rep->data) { + if (rep->flags & BF_FULL) { if (EV_FD_COND_C(t->srv_fd, DIR_RD)) rep->rex = TICK_ETERNITY; } else { @@ -3653,7 +3652,7 @@ int process_srv(struct session *t) /* manage write timeout */ if (!(req->flags & BF_SHUTW)) { - if (req->l == 0 || !(req->flags & BF_MAY_FORWARD)) { + if (req->flags & BF_EMPTY || !(req->flags & BF_MAY_FORWARD)) { /* stop writing */ if (EV_FD_COND_C(t->srv_fd, DIR_WR)) req->wex = TICK_ETERNITY; @@ -5101,7 +5100,7 @@ int stats_check_uri_auth(struct session *t, struct proxy *backend) EV_FD_CLR(t->cli_fd, DIR_RD); buffer_shutr(t->req); buffer_shutr(t->rep); - t->req->rlim = t->req->data + BUFSIZE; /* no more rewrite needed */ + buffer_set_rlim(t->req, BUFSIZE); /* no more rewrite needed */ t->logs.tv_request = now; t->data_source = DATA_SRC_STATS; t->data_state = DATA_ST_INIT; diff --git a/src/proto_uxst.c b/src/proto_uxst.c index d74bcb4c9..443586f2a 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -483,8 +483,6 @@ int uxst_event_accept(int fd) { buffer_init(s->req); buffer_init(s->rep); - s->req->rlim += BUFSIZE; - s->rep->rlim += BUFSIZE; fd_insert(cfd); fdtab[cfd].owner = t; @@ -582,7 +580,7 @@ static int process_uxst_cli(struct session *t) return 1; } /* last server read and buffer empty */ - else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) { + else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->flags & BF_EMPTY)) { EV_FD_CLR(t->cli_fd, DIR_WR); buffer_shutw(rep); shutdown(t->cli_fd, SHUT_WR); @@ -635,7 +633,7 @@ static int process_uxst_cli(struct session *t) return 1; } - if (req->l >= req->rlim - req->data) { + if (req->flags & BF_FULL) { /* no room to read more data */ if (EV_FD_COND_C(t->cli_fd, DIR_RD)) { /* stop reading until we get some space */ @@ -657,7 +655,7 @@ static int process_uxst_cli(struct session *t) } } - if ((rep->l == 0) || + if ((rep->flags & BF_EMPTY) || ((s < SV_STDATA) /* FIXME: this may be optimized && (rep->w == rep->h)*/)) { if (EV_FD_COND_C(t->cli_fd, DIR_WR)) { /* stop writing */ @@ -694,7 +692,7 @@ static int process_uxst_cli(struct session *t) } return 1; } - else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->l == 0)) { + else if ((s == SV_STSHUTR || s == SV_STCLOSE) && (rep->flags & BF_EMPTY)) { buffer_shutw(rep); fd_delete(t->cli_fd); t->cli_state = CL_STCLOSE; @@ -717,7 +715,7 @@ static int process_uxst_cli(struct session *t) return 1; } - if (rep->l == 0) { + if (rep->flags & BF_EMPTY) { if (EV_FD_COND_C(t->cli_fd, DIR_WR)) { /* stop writing */ rep->wex = TICK_ETERNITY; @@ -770,7 +768,7 @@ static int process_uxst_cli(struct session *t) } return 1; } - else if (req->l >= req->rlim - req->data) { + else if (req->flags & BF_FULL) { /* no room to read more data */ /* FIXME-20050705: is it possible for a client to maintain a session @@ -821,7 +819,7 @@ static int process_uxst_srv(struct session *t) if (s == SV_STIDLE) { if (c == CL_STCLOSE || c == CL_STSHUTW || (c == CL_STSHUTR && - (t->req->l == 0 || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */ + (t->req->flags & BF_EMPTY || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */ tv_eternity(&req->cex); if (t->pend_pos) t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now); @@ -870,7 +868,7 @@ static int process_uxst_srv(struct session *t) else if (s == SV_STCONN) { /* connection in progress */ if (c == CL_STCLOSE || c == CL_STSHUTW || (c == CL_STSHUTR && - ((t->req->l == 0 && !(req->flags & BF_WRITE_STATUS)) || + ((t->req->flags & BF_EMPTY && !(req->flags & BF_WRITE_STATUS)) || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */ tv_eternity(&req->cex); fd_delete(t->srv_fd); @@ -941,7 +939,7 @@ static int process_uxst_srv(struct session *t) t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now); //fprintf(stderr,"3: c=%d, s=%d\n", c, s); - if (req->l == 0) /* nothing to write */ { + if (req->flags & BF_EMPTY) /* nothing to write */ { EV_FD_CLR(t->srv_fd, DIR_WR); tv_eternity(&req->wex); } else /* need the right to write */ { @@ -962,7 +960,7 @@ static int process_uxst_srv(struct session *t) t->srv_state = SV_STDATA; if (t->srv) t->srv->cum_sess++; - rep->rlim = rep->data + BUFSIZE; /* no rewrite needed */ + buffer_set_rlim(rep, BUFSIZE); /* no rewrite needed */ /* if the user wants to log as soon as possible, without counting bytes from the server, then this is the right moment. */ @@ -1007,7 +1005,7 @@ static int process_uxst_srv(struct session *t) return 1; } /* end of client read and no more data to send */ - else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) { + else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->flags & BF_EMPTY)) { EV_FD_CLR(t->srv_fd, DIR_WR); buffer_shutw(req); shutdown(t->srv_fd, SHUT_WR); @@ -1048,7 +1046,7 @@ static int process_uxst_srv(struct session *t) } /* recompute request time-outs */ - if (req->l == 0) { + if (req->flags & BF_EMPTY) { if (EV_FD_COND_C(t->srv_fd, DIR_WR)) { /* stop writing */ tv_eternity(&req->wex); @@ -1106,7 +1104,7 @@ static int process_uxst_srv(struct session *t) return 1; } - else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->l == 0)) { + else if ((c == CL_STSHUTR || c == CL_STCLOSE) && (req->flags & BF_EMPTY)) { //EV_FD_CLR(t->srv_fd, DIR_WR); buffer_shutw(req); fd_delete(t->srv_fd); @@ -1142,7 +1140,7 @@ static int process_uxst_srv(struct session *t) return 1; } - else if (req->l == 0) { + else if (req->flags & BF_EMPTY) { if (EV_FD_COND_C(t->srv_fd, DIR_WR)) { /* stop writing */ tv_eternity(&req->wex); @@ -1263,8 +1261,8 @@ void process_uxst_session(struct task *t, int *next) continue; } if (s->cli_state == CL_STSHUTR || - (s->req->l >= s->req->rlim - s->req->data)) { - if (s->req->l == 0) { + (s->req->flags & BF_FULL)) { + if (s->req->flags & BF_EMPTY) { s->srv_state = SV_STCLOSE; fsm_resync |= 1; continue; @@ -1275,7 +1273,7 @@ void process_uxst_session(struct task *t, int *next) */ memcpy(s->rep->data, s->req->data, sizeof(s->rep->data)); s->rep->l = s->req->l; - s->rep->rlim = s->rep->data + BUFSIZE; + buffer_set_rlim(s->rep, BUFSIZE); s->rep->w = s->rep->data; s->rep->lr = s->rep->r = s->rep->data + s->rep->l; diff --git a/src/senddata.c b/src/senddata.c index 33fe54819..6bc5915b4 100644 --- a/src/senddata.c +++ b/src/senddata.c @@ -51,13 +51,13 @@ void client_retnclose(struct session *s, const struct chunk *msg) EV_FD_CLR(s->cli_fd, DIR_RD); EV_FD_SET(s->cli_fd, DIR_WR); buffer_shutr(s->req); + buffer_flush(s->req); s->rep->wex = tick_add_ifset(now_ms, s->rep->wto); s->rep->flags |= BF_MAY_FORWARD; s->cli_state = CL_STSHUTR; // FIXME: still used by unix sockets buffer_flush(s->rep); if (msg && msg->len) buffer_write(s->rep, msg->str, msg->len); - s->req->l = 0; } @@ -69,10 +69,10 @@ void client_retnclose(struct session *s, const struct chunk *msg) */ void client_return(struct session *s, const struct chunk *msg) { + buffer_flush(s->req); buffer_flush(s->rep); if (msg && msg->len) buffer_write(s->rep, msg->str, msg->len); - s->req->l = 0; } /* diff --git a/src/stream_sock.c b/src/stream_sock.c index 3e3e0b9d8..b35b9fe76 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -84,6 +84,7 @@ int stream_sock_read(int fd) { /* Not anymore room to store data. This should theorically * never happen, but better safe than sorry ! */ + b->flags |= BF_FULL; EV_FD_CLR(fd, DIR_RD); b->rex = TICK_ETERNITY; goto out_wakeup; @@ -111,6 +112,7 @@ int stream_sock_read(int fd) { b->l += ret; cur_read += ret; b->flags |= BF_PARTIAL_READ; + b->flags &= ~BF_EMPTY; if (b->r == b->data + BUFSIZE) { b->r = b->data; /* wrap around the buffer */ @@ -118,7 +120,7 @@ int stream_sock_read(int fd) { b->total += ret; - if (b->l == b->rlim - b->data) { + if (b->l >= b->rlim - b->data) { /* The buffer is now full, there's no point in going through * the loop again. */ @@ -151,6 +153,7 @@ int stream_sock_read(int fd) { b->xfer_large = 0; } + b->flags |= BF_FULL; EV_FD_CLR(fd, DIR_RD); b->rex = TICK_ETERNITY; goto out_wakeup; @@ -335,12 +338,16 @@ int stream_sock_write(int fd) { b->w += ret; b->flags |= BF_PARTIAL_WRITE; + + if (b->l < b->rlim - b->data) + b->flags &= ~BF_FULL; if (b->w == b->data + BUFSIZE) { b->w = b->data; /* wrap around the buffer */ } if (!b->l) { + b->flags |= BF_EMPTY; EV_FD_CLR(fd, DIR_WR); b->wex = TICK_ETERNITY; goto out_wakeup;