MAJOR: buffers: replace buf->w with buf->p - buf->o

This change introduces the buffer's base pointer, which is the limit between
incoming and outgoing data. It's the point where the parsing should start
from. A number of computations have already been greatly simplified, but
more simplifications are expected to come from the removal of buf->r.

The changes appear good and have revealed occasional improper use of some
pointers. It is possible that this patch has introduced bugs or revealed
some, although preliminary testings tend to indicate that everything still
works as it should.
This commit is contained in:
Willy Tarreau 2012-03-02 16:13:16 +01:00
parent 3f7ff1406c
commit 89fa706d39
8 changed files with 71 additions and 93 deletions

View File

@ -62,7 +62,7 @@ static inline void buffer_init(struct buffer *buf)
buf->analysers = 0;
buf->cons = NULL;
buf->flags = BF_OUT_EMPTY;
buf->r = buf->lr = buf->w = buf->data;
buf->r = buf->lr = buf->p = buf->data;
}
/*****************************************************************/
@ -186,7 +186,7 @@ static inline int buffer_contig_space_res(const struct buffer *buf)
if (buffer_len(buf) >= spare)
spare = 0;
else if (buffer_len(buf)) {
spare = buf->w - res - buf->r;
spare = buffer_wrap_sub(buf, buf->p - buf->o) - res - buf->r;
if (spare <= 0)
spare += buf->size;
spare = buffer_contig_area(buf, buf->r, spare);
@ -209,7 +209,7 @@ static inline int buffer_contig_space_with_res(const struct buffer *buf, int res
if (buffer_len(buf) >= spare)
spare = 0;
else if (buffer_len(buf)) {
spare = buf->w - res - buf->r;
spare = buffer_wrap_sub(buf, buf->p - buf->o) - res - buf->r;
if (spare <= 0)
spare += buf->size;
spare = buffer_contig_area(buf, buf->r, spare);
@ -254,15 +254,15 @@ static inline int buffer_pending(const struct buffer *buf)
/* Returns the size of the working area which the caller knows ends at <end>.
* If <end> equals buf->r (modulo size), then it means that the free area which
* follows is part of the working area. Otherwise, the working area stops at
* <end>. It always starts at buf->w+o. The work area includes the
* <end>. It always starts at buf->p. The work area includes the
* reserved area.
*/
static inline int buffer_work_area(const struct buffer *buf, const char *end)
{
end = buffer_pointer(buf, end);
if (end == buf->r) /* pointer exactly at end, lets push forwards */
end = buf->w;
return buffer_count(buf, buffer_pointer(buf, buf->w + buf->o), end);
end = buffer_wrap_sub(buf, buf->p - buf->o);
return buffer_count(buf, buf->p, end);
}
/* Return 1 if the buffer has less than 1/4 of its capacity free, otherwise 0 */
@ -312,6 +312,7 @@ static inline void buffer_check_timeouts(struct buffer *b)
*/
static inline void buffer_flush(struct buffer *buf)
{
buf->p = buf->r;
buf->o += buf->i;
buf->i = 0;
if (buf->o)
@ -327,7 +328,7 @@ static inline void buffer_erase(struct buffer *buf)
buf->o = 0;
buf->i = 0;
buf->to_forward = 0;
buf->r = buf->lr = buf->w = buf->data;
buf->r = buf->lr = buf->p = buf->data;
buf->flags &= ~(BF_FULL | BF_OUT_EMPTY);
if (!buf->pipe)
buf->flags |= BF_OUT_EMPTY;
@ -348,7 +349,7 @@ static inline void buffer_cut_tail(struct buffer *buf)
return;
buf->i = 0;
buf->r = buf->w + buf->o;
buf->r = buf->p;
if (buf->r >= buf->data + buf->size)
buf->r -= buf->size;
buf->lr = buf->r;
@ -364,9 +365,7 @@ static inline void buffer_cut_tail(struct buffer *buf)
static inline void buffer_ignore(struct buffer *buf, int n)
{
buf->i -= n;
buf->w += n;
if (buf->w >= buf->data + buf->size)
buf->w -= buf->size;
buf->p = buffer_wrap_add(buf, buf->p + n);
buf->flags &= ~BF_FULL;
if (buffer_len(buf) >= buffer_max_len(buf))
buf->flags |= BF_FULL;
@ -457,7 +456,7 @@ static inline int buffer_realign(struct buffer *buf)
{
if (!(buf->i | buf->o)) {
/* let's realign the buffer to optimize I/O */
buf->r = buf->w = buf->lr = buf->data;
buf->r = buf->p = buf->lr = buf->data;
}
return buffer_contig_space(buf);
}
@ -470,13 +469,9 @@ static inline int buffer_realign(struct buffer *buf)
*/
static inline void buffer_skip(struct buffer *buf, int len)
{
buf->w += len;
if (buf->w >= buf->data + buf->size)
buf->w -= buf->size; /* wrap around the buffer */
buf->o -= len;
if (buffer_len(buf) == 0)
buf->r = buf->w = buf->lr = buf->data;
buf->r = buf->p = buf->lr = buf->data;
if (buffer_len(buf) < buffer_max_len(buf))
buf->flags &= ~BF_FULL;
@ -549,7 +544,7 @@ static inline int buffer_get_char(struct buffer *buf)
return -2;
return -1;
}
return *buf->w;
return *buffer_wrap_sub(buf, buf->p - buf->o);
}

View File

@ -180,7 +180,8 @@ struct buffer {
int wex; /* expiration date for a write or connect, in ticks */
int rto; /* read timeout, in ticks */
int wto; /* write timeout, in ticks */
char *r, *w, *lr; /* read ptr, write ptr, last read */
char *r, *lr; /* read ptr, last read */
char *p; /* buffer's start pointer, separates in and out data */
unsigned int size; /* buffer size in bytes */
unsigned int i; /* number of input bytes pending for analysis in the buffer */
unsigned int o; /* number of out bytes the sender can consume from this buffer */

View File

@ -123,7 +123,7 @@ acl_fetch_ssl_hello_type(struct proxy *px, struct session *l4, void *l7, int dir
b = ((dir & ACL_DIR_MASK) == ACL_DIR_RTR) ? l4->rep : l4->req;
bleft = b->i;
data = (const unsigned char *)b->w;
data = (const unsigned char *)b->p;
if (!bleft)
goto too_short;
@ -191,7 +191,7 @@ acl_fetch_req_ssl_ver(struct proxy *px, struct session *l4, void *l7, int dir,
if (!bleft)
goto too_short;
data = (const unsigned char *)l4->req->w;
data = (const unsigned char *)l4->req->p;
if ((*data >= 0x14 && *data <= 0x17) || (*data == 0xFF)) {
/* SSLv3 header format */
if (bleft < 5)
@ -259,8 +259,8 @@ acl_fetch_req_ssl_ver(struct proxy *px, struct session *l4, void *l7, int dir,
* all the part of the request which fits in a buffer is already
* there.
*/
if (msg_len > buffer_max_len(l4->req) + l4->req->data - l4->req->w)
msg_len = buffer_max_len(l4->req) + l4->req->data - l4->req->w;
if (msg_len > buffer_max_len(l4->req) + l4->req->data - l4->req->p)
msg_len = buffer_max_len(l4->req) + l4->req->data - l4->req->p;
if (bleft < msg_len)
goto too_short;
@ -325,7 +325,7 @@ acl_fetch_ssl_hello_sni(struct proxy *px, struct session *l4, void *l7, int dir,
b = ((dir & ACL_DIR_MASK) == ACL_DIR_RTR) ? l4->rep : l4->req;
bleft = b->i;
data = (unsigned char *)b->w;
data = (unsigned char *)b->p;
/* Check for SSL/TLS Handshake */
if (!bleft)
@ -463,7 +463,7 @@ acl_fetch_rdp_cookie(struct proxy *px, struct session *l4, void *l7, int dir,
if (bleft <= 11)
goto too_short;
data = (const unsigned char *)l4->req->w + 11;
data = (const unsigned char *)l4->req->p + 11;
bleft -= 11;
if (bleft <= 7)

View File

@ -46,6 +46,7 @@ unsigned long long buffer_forward(struct buffer *buf, unsigned long long bytes)
if (!bytes)
return 0;
if (bytes <= (unsigned long long)buf->i) {
buf->p = buffer_wrap_add(buf, buf->p + bytes);
buf->o += bytes;
buf->i -= bytes;
buf->flags &= ~BF_OUT_EMPTY;
@ -53,6 +54,7 @@ unsigned long long buffer_forward(struct buffer *buf, unsigned long long bytes)
}
forwarded = buf->i;
buf->p = buffer_wrap_add(buf, buf->p + forwarded);
buf->o += forwarded;
buf->i = 0;
@ -118,10 +120,9 @@ int buffer_write(struct buffer *buf, const char *msg, int len)
memcpy(buf->r, msg, len);
buf->o += len;
buf->r += len;
buf->p = buffer_wrap_add(buf, buf->p + len);
buf->r = buffer_wrap_add(buf, buf->r + len);
buf->total += len;
if (buf->r == buf->data + buf->size)
buf->r = buf->data;
buf->flags &= ~(BF_OUT_EMPTY|BF_FULL);
if (buffer_len(buf) >= buffer_max_len(buf))
@ -216,6 +217,7 @@ int buffer_put_block(struct buffer *buf, const char *blk, int len)
}
buf->o += fwd;
buf->i -= fwd;
buf->p = buffer_wrap_add(buf, buf->p + fwd);
buf->flags &= ~BF_OUT_EMPTY;
}
@ -256,7 +258,7 @@ int buffer_get_line(struct buffer *buf, char *str, int len)
goto out;
}
p = buf->w;
p = buffer_wrap_sub(buf, buf->p - buf->o);
if (max > buf->o) {
max = buf->o;
@ -269,9 +271,7 @@ int buffer_get_line(struct buffer *buf, char *str, int len)
if (*p == '\n')
break;
p++;
if (p == buf->data + buf->size)
p = buf->data;
p = buffer_wrap_add(buf, p + 1);
}
if (ret > 0 && ret < len && ret < buf->o &&
*(str-1) != '\n' &&
@ -304,14 +304,14 @@ int buffer_get_block(struct buffer *buf, char *blk, int len, int offset)
return 0;
}
firstblock = buf->data + buf->size - buf->w;
firstblock = buf->data + buf->size - buffer_wrap_sub(buf, buf->p - buf->o);
if (firstblock > offset) {
if (firstblock >= len + offset) {
memcpy(blk, buf->w + offset, len);
memcpy(blk, buffer_wrap_sub(buf, buf->p - buf->o) + offset, len);
return len;
}
memcpy(blk, buf->w + offset, firstblock - offset);
memcpy(blk, buffer_wrap_sub(buf, buf->p - buf->o) + offset, firstblock - offset);
memcpy(blk + firstblock - offset, buf->data, len - firstblock + offset);
return len;
}
@ -338,7 +338,8 @@ int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int
if (delta + b->r >= b->data + b->size)
return 0; /* no space left */
if (delta + b->r > b->w && b->w >= b->r && buffer_not_empty(b))
if (delta + b->r > buffer_wrap_sub(b, b->p - b->o) &&
buffer_wrap_sub(b, b->p - b->o) >= b->r && buffer_not_empty(b))
return 0; /* no space left before wrapping data */
/* first, protect the end of the buffer */
@ -355,7 +356,7 @@ int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int
b->flags &= ~BF_FULL;
if (buffer_len(b) == 0)
b->r = b->w = b->lr = b->data;
b->r = b->p = b->lr = b->data;
if (buffer_len(b) >= buffer_max_len(b))
b->flags |= BF_FULL;
@ -414,11 +415,11 @@ void buffer_bounce_realign(struct buffer *buf)
int advance, to_move;
char *from, *to;
advance = buf->data + buf->size - buf->w;
from = buffer_wrap_sub(buf, buf->p - buf->o);
advance = buf->data + buf->size - from;
if (!advance)
return;
from = buf->w;
to_move = buffer_len(buf);
while (to_move) {
char last, save;
@ -576,8 +577,8 @@ int chunk_asciiencode(struct chunk *dst, struct chunk *src, char qc) {
void buffer_dump(FILE *o, struct buffer *b, int from, int to)
{
fprintf(o, "Dumping buffer %p\n", b);
fprintf(o, " data=%p o=%d i=%d r=%p w=%p lr=%p\n",
b->data, b->o, b->i, b->r, b->w, b->lr);
fprintf(o, " data=%p o=%d i=%d r=%p p=%p lr=%p\n",
b->data, b->o, b->i, b->r, b->p, b->lr);
if (!to || to > buffer_len(b))
to = buffer_len(b);

View File

@ -3389,13 +3389,13 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si)
chunk_printf(&msg,
" wex=%s\n"
" data=%p r=%d w=%d lr=%d total=%lld\n",
" data=%p r=%d p=%d lr=%d total=%lld\n",
sess->req->wex ?
human_time(TICKS_TO_MS(sess->req->wex - now_ms),
TICKS_TO_MS(1000)) : "<NEVER>",
sess->req->data,
(int)(sess->req->r - sess->req->data),
(int)(sess->req->w - sess->req->data),
(int)(sess->req->p - sess->req->data),
(int)(sess->req->lr - sess->req->data),
sess->req->total);
@ -3419,13 +3419,13 @@ static int stats_dump_full_sess_to_buffer(struct stream_interface *si)
chunk_printf(&msg,
" wex=%s\n"
" data=%p r=%d w=%d lr=%d total=%lld\n",
" data=%p r=%d p=%d lr=%d total=%lld\n",
sess->rep->wex ?
human_time(TICKS_TO_MS(sess->rep->wex - now_ms),
TICKS_TO_MS(1000)) : "<NEVER>",
sess->rep->data,
(int)(sess->rep->r - sess->rep->data),
(int)(sess->rep->w - sess->rep->data),
(int)(sess->rep->p - sess->rep->data),
(int)(sess->rep->lr - sess->rep->data),
sess->rep->total);

View File

@ -1297,9 +1297,8 @@ void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx
* first if we need to remove some CRLF. We can only
* do this when o=0.
*/
char *beg = buf->w + buf->o;
if (beg >= buf->data + buf->size)
beg -= buf->size;
char *beg = buf->p;
if (unlikely(ptr != beg)) {
if (buf->o)
goto http_msg_ood;
@ -1366,9 +1365,8 @@ void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx
* first if we need to remove some CRLF. We can only
* do this when o=0.
*/
char *beg = buf->w + buf->o;
if (beg >= buf->data + buf->size)
beg -= buf->size;
char *beg = buf->p;
if (likely(ptr != beg)) {
if (buf->o)
goto http_msg_ood;
@ -1963,10 +1961,11 @@ int http_skip_chunk_crlf(struct buffer *buf, struct http_msg *msg)
return 1;
}
/* This function may only be used when the buffer's o is empty */
void http_buffer_heavy_realign(struct buffer *buf, struct http_msg *msg)
{
char *end = buf->data + buf->size;
int off = buf->data + buf->size - buf->w;
int off = buf->data + buf->size - buf->p;
/* two possible cases :
* - the buffer is in one contiguous block, we move it in-place
@ -1975,20 +1974,20 @@ void http_buffer_heavy_realign(struct buffer *buf, struct http_msg *msg)
if (buf->i) {
int block1 = buf->i;
int block2 = 0;
if (buf->r <= buf->w) {
if (buf->r <= buf->p) {
/* non-contiguous block */
block1 = buf->data + buf->size - buf->w;
block1 = buf->data + buf->size - buf->p;
block2 = buf->r - buf->data;
}
if (block2)
memcpy(swap_buffer, buf->data, block2);
memmove(buf->data, buf->w, block1);
memmove(buf->data, buf->p, block1);
if (block2)
memcpy(buf->data + block1, swap_buffer, block2);
}
/* adjust all known pointers */
buf->w = buf->data;
buf->p = buf->data;
buf->lr += off; if (buf->lr >= end) buf->lr -= buf->size;
buf->r += off; if (buf->r >= end) buf->r -= buf->size;
msg->sol += off; if (msg->sol >= end) msg->sol -= buf->size;
@ -3835,13 +3834,8 @@ void http_end_txn_clean_session(struct session *s)
buffer_auto_close(s->rep);
/* make ->lr point to the first non-forwarded byte */
s->req->lr = s->req->w + s->req->o;
if (s->req->lr >= s->req->data + s->req->size)
s->req->lr -= s->req->size;
s->rep->lr = s->rep->w + s->rep->o;
if (s->rep->lr >= s->rep->data + s->rep->size)
s->rep->lr -= s->req->size;
s->req->lr = s->req->p;
s->rep->lr = s->rep->p;
s->req->analysers = s->listener->analysers;
s->req->analysers &= ~AN_REQ_DECODE_PROXY;
s->rep->analysers = 0;
@ -4267,10 +4261,7 @@ int http_request_forward_body(struct session *s, struct buffer *req, int an_bit)
/* we want the CRLF after the data */
int ret;
req->lr = req->w + req->o;
if (req->lr >= req->data + req->size)
req->lr -= req->size;
req->lr = req->p;
ret = http_skip_chunk_crlf(req, msg);
if (ret == 0)
@ -5331,10 +5322,7 @@ int http_response_forward_body(struct session *s, struct buffer *res, int an_bit
/* we want the CRLF after the data */
int ret;
res->lr = res->w + res->o;
if (res->lr >= res->data + res->size)
res->lr -= res->size;
res->lr = res->p;
ret = http_skip_chunk_crlf(res, msg);
if (!ret)
@ -7458,9 +7446,7 @@ void http_reset_txn(struct session *s)
*/
if (unlikely(s->rep->i)) {
s->rep->i = 0;
s->rep->r = s->rep->w + s->rep->o;
if (s->rep->r >= s->rep->data + s->rep->size)
s->rep->r -= s->rep->size;
s->rep->r = s->rep->p;
}
s->req->rto = s->fe->timeout.client;

View File

@ -1484,7 +1484,7 @@ pattern_fetch_payloadlv(struct proxy *px, struct session *l4, void *l7, int dir,
return 0;
for (i = 0; i < len_size; i++) {
buf_size = (buf_size << 8) + ((unsigned char *)b->w)[i + len_offset];
buf_size = (buf_size << 8) + ((unsigned char *)b->p)[i + len_offset];
}
if (!buf_size)
@ -1494,7 +1494,7 @@ pattern_fetch_payloadlv(struct proxy *px, struct session *l4, void *l7, int dir,
return 0;
/* init chunk as read only */
chunk_initlen(&data->str, b->w + buf_offset, 0, buf_size);
chunk_initlen(&data->str, b->p + buf_offset, 0, buf_size);
return 1;
}
@ -1557,7 +1557,7 @@ pattern_fetch_payload(struct proxy *px, struct session *l4, void *l7, int dir,
return 0;
/* init chunk as read only */
chunk_initlen(&data->str, b->w + buf_offset, 0, buf_size);
chunk_initlen(&data->str, b->p + buf_offset, 0, buf_size);
return 1;
}

View File

@ -282,9 +282,10 @@ int stream_sock_read(int fd) {
*/
if (buffer_empty(b)) {
/* let's realign the buffer to optimize I/O */
b->r = b->w = b->lr = b->data;
b->r = b->p = b->lr = b->data;
}
else if (b->r > b->w) {
else if (b->data + b->o < b->p &&
b->p + b->i < b->data + b->size) {
/* remaining space wraps at the end, with a moving limit */
if (max > b->data + b->size - b->r)
max = b->data + b->size - b->r;
@ -311,6 +312,7 @@ int stream_sock_read(int fd) {
}
b->o += fwd;
b->i -= fwd;
b->p = buffer_wrap_add(b, b->p + fwd);
b->flags &= ~BF_OUT_EMPTY;
}
@ -598,14 +600,11 @@ static int stream_sock_write_loop(struct stream_interface *si, struct buffer *b)
* data left, and that there are sendable buffered data.
*/
while (1) {
if (b->r > b->w)
max = b->r - b->w;
else
max = b->data + b->size - b->w;
max = b->o;
/* limit the amount of outgoing data if required */
if (max > b->o)
max = b->o;
/* outgoing data may wrap at the end */
if (b->data + max > b->p)
max = b->data + max - b->p;
/* check if we want to inform the kernel that we're interested in
* sending more data after this call. We want this if :
@ -633,7 +632,7 @@ static int stream_sock_write_loop(struct stream_interface *si, struct buffer *b)
if (b->flags & BF_SEND_DONTWAIT)
send_flag &= ~MSG_MORE;
ret = send(si->fd, b->w, max, send_flag);
ret = send(si->fd, buffer_wrap_sub(b, b->p - b->o), max, send_flag);
} else {
int skerr;
socklen_t lskerr = sizeof(skerr);
@ -642,7 +641,7 @@ static int stream_sock_write_loop(struct stream_interface *si, struct buffer *b)
if (ret == -1 || skerr)
ret = -1;
else
ret = send(si->fd, b->w, max, MSG_DONTWAIT);
ret = send(si->fd, buffer_wrap_sub(b, b->p - b->o), max, MSG_DONTWAIT);
}
if (ret > 0) {
@ -651,14 +650,10 @@ static int stream_sock_write_loop(struct stream_interface *si, struct buffer *b)
b->flags |= BF_WRITE_PARTIAL;
b->w += ret;
if (b->w == b->data + b->size)
b->w = b->data; /* wrap around the buffer */
b->o -= ret;
if (likely(!buffer_len(b)))
/* optimize data alignment in the buffer */
b->r = b->w = b->lr = b->data;
b->r = b->p = b->lr = b->data;
if (likely(buffer_len(b) < buffer_max_len(b)))
b->flags &= ~BF_FULL;