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.
diff --git a/include/proto/buffers.h b/include/proto/buffers.h
index 18495b5..0aa1ff3 100644
--- a/include/proto/buffers.h
+++ b/include/proto/buffers.h
@@ -62,7 +62,7 @@
 	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 @@
 	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 @@
 	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 @@
 /* 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_flush(struct buffer *buf)
 {
+	buf->p = buf->r;
 	buf->o += buf->i;
 	buf->i = 0;
 	if (buf->o)
@@ -327,7 +328,7 @@
 	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 @@
 		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_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 @@
 {
 	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 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 @@
 			return -2;
 		return -1;
 	}
-	return *buf->w;
+	return *buffer_wrap_sub(buf, buf->p - buf->o);
 }
 
 
diff --git a/include/types/buffers.h b/include/types/buffers.h
index cc394b2..f250532 100644
--- a/include/types/buffers.h
+++ b/include/types/buffers.h
@@ -180,7 +180,8 @@
 	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 */
diff --git a/src/acl.c b/src/acl.c
index 430f985..507516f 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -123,7 +123,7 @@
 	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 @@
 	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 @@
 	 * 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 @@
 	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 @@
 	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)
diff --git a/src/buffers.c b/src/buffers.c
index 74e3a10..41d3624 100644
--- a/src/buffers.c
+++ b/src/buffers.c
@@ -46,6 +46,7 @@
 	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 @@
 	}
 
 	forwarded = buf->i;
+	buf->p = buffer_wrap_add(buf, buf->p + forwarded);
 	buf->o += forwarded;
 	buf->i = 0;
 
@@ -118,10 +120,9 @@
 
 	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 @@
 		}
 		buf->o += fwd;
 		buf->i -= fwd;
+		buf->p = buffer_wrap_add(buf, buf->p + fwd);
 		buf->flags &= ~BF_OUT_EMPTY;
 	}
 
@@ -256,7 +258,7 @@
 		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 @@
 
 		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 @@
 		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 @@
 	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 @@
 
 	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 @@
 	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 @@
 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);
diff --git a/src/dumpstats.c b/src/dumpstats.c
index 26cbdd6..e9f9171 100644
--- a/src/dumpstats.c
+++ b/src/dumpstats.c
@@ -3389,13 +3389,13 @@
 
 		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 @@
 
 		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);
 
diff --git a/src/proto_http.c b/src/proto_http.c
index f1167c1..06f658e 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -1297,9 +1297,8 @@
 			 * 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 @@
 			 * 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 @@
 	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 @@
 	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 @@
 	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 @@
 			/* 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 @@
 			/* 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 @@
 	 */
 	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;
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 7a3d714..1714416 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -1484,7 +1484,7 @@
 		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 @@
 		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 @@
 		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;
 }
diff --git a/src/stream_sock.c b/src/stream_sock.c
index 74fe0b2..0d039eb 100644
--- a/src/stream_sock.c
+++ b/src/stream_sock.c
@@ -282,9 +282,10 @@
 		 */
 		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 @@
 				}
 				b->o += fwd;
 				b->i -= fwd;
+				b->p = buffer_wrap_add(b, b->p + fwd);
 				b->flags &= ~BF_OUT_EMPTY;
 			}
 
@@ -598,14 +600,11 @@
 	 * 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 @@
 			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 @@
 			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 @@
 
 			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;