]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] add support for infinite forwarding
authorWilly Tarreau <w@1wt.eu>
Sun, 20 Sep 2009 10:07:52 +0000 (12:07 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 20 Sep 2009 10:07:52 +0000 (12:07 +0200)
In TCP, we don't want to forward chunks of data, we want to forward
indefinitely. This patch introduces a special value for the amount
of data to be forwarded. When buffer_forward() is called with
BUF_INFINITE_FORWARD, it configures the buffer to never stop
forwarding until the end.

include/common/defaults.h
include/proto/buffers.h
include/types/buffers.h
src/buffers.c
src/session.c
src/stream_sock.c

index 966ef4fbd9aece606f0bbf8ed239ce5166dc14b4..c09f5a455fe46c14bad9673309315a38ee4e6bdf 100644 (file)
@@ -2,7 +2,7 @@
   include/common/defaults.h
   Miscellaneous default values.
 
-  Copyright (C) 2000-2008 Willy Tarreau - w@1wt.eu
+  Copyright (C) 2000-2009 Willy Tarreau - w@1wt.eu
 
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
 #define MAXREWRITE      (BUFSIZE / 2)
 #endif
 
-/* FORWARD_DEFAULT_SIZE
- * Indicates how many bytes may be forwarded at once in low-level stream-socks
- * without waking the owner task up. This should be much larger than the buffer
- * size. A few megabytes seem appropriate.
- */
-#ifndef FORWARD_DEFAULT_SIZE
-#define FORWARD_DEFAULT_SIZE (16*1024*1024)
-#endif
-
-
 #define REQURI_LEN      1024
 #define CAPTURE_LEN     64
 
index 6878cfe7314c0a3c17fc2da5172ca6d4b8001f46..abaf5eeb58ccccb332ea3e818cbb21b879bd0bf1 100644 (file)
@@ -85,9 +85,9 @@ static inline void buffer_check_timeouts(struct buffer *b)
  * cause lockups when send_max goes down to zero if nobody is ready to push the
  * remaining data.
  */
-static inline void buffer_forward(struct buffer *buf, unsigned int bytes)
+static inline void buffer_forward(struct buffer *buf, unsigned long bytes)
 {
-       unsigned int data_left;
+       unsigned long data_left;
 
        if (!bytes)
                return;
@@ -98,8 +98,13 @@ static inline void buffer_forward(struct buffer *buf, unsigned int bytes)
                return;
        }
 
-       buf->to_forward += bytes - data_left;
        buf->send_max += data_left;
+       if (buf->to_forward == BUF_INFINITE_FORWARD)
+               return;
+
+       buf->to_forward += bytes - data_left;
+       if (bytes == BUF_INFINITE_FORWARD)
+               buf->to_forward = bytes;
 }
 
 /* Schedule all remaining buffer data to be sent. send_max is not touched if it
@@ -380,8 +385,9 @@ static inline int buffer_si_putchar(struct buffer *buf, char c)
        if (buf->r - buf->data == buf->size)
                buf->r -= buf->size;
 
-       if ((signed)(buf->to_forward - 1) >= 0) {
-               buf->to_forward--;
+       if (buf->to_forward >= 1) {
+               if (buf->to_forward != BUF_INFINITE_FORWARD)
+                       buf->to_forward--;
                buf->send_max++;
                buf->flags &= ~BF_OUT_EMPTY;
        }
index 969c10342715565b9dd2f4742c1c0a7a50988658..14cb966dad5355174eaa97c8fe644d58c43037d4 100644 (file)
 #define AN_RTR_HTTP_HDR         0x00000200  /* inspect HTTP response headers */
 #define AN_REQ_PRST_RDP_COOKIE  0x00000400  /* persistence on rdp cookie */
 
+/* Magic value to forward infinite size (TCP, ...), used with ->to_forward */
+#define BUF_INFINITE_FORWARD    (~0UL)
+
 /* describes a chunk of string */
 struct chunk {
        char *str;      /* beginning of the string itself. Might not be 0-terminated */
@@ -164,7 +167,7 @@ struct buffer {
        unsigned int size;              /* buffer size in bytes */
        unsigned int max_len;           /* read limit, used to keep room for header rewriting */
        unsigned int send_max;          /* number of bytes the sender can consume om this buffer, <= l */
-       unsigned int to_forward;        /* number of bytes to forward after send_max without a wake-up */
+       unsigned long to_forward;       /* number of bytes to forward after send_max without a wake-up */
        unsigned int analysers;         /* bit field indicating what to do on the buffer */
        int analyse_exp;                /* expiration date for current analysers (if set) */
        void (*hijacker)(struct session *, struct buffer *); /* alternative content producer */
@@ -205,7 +208,8 @@ struct buffer {
 
    The producer is responsible for decreasing ->to_forward and increasing
    ->send_max. The ->to_forward parameter indicates how many bytes may be fed
-   into either data buffer without waking the parent up. The ->send_max
+   into either data buffer without waking the parent up. The special value
+   BUF_INFINITE_FORWARD is never decreased nor increased. The ->send_max
    parameter says how many bytes may be read from the visible buffer. Thus it
    may never exceed ->l. This parameter is updated by any buffer_write() as
    well as any data forwarded through the visible buffer.
index 6b551ab2c2683d5fb2e3766280f2f55cfbdb0643..a21eb4f33eaacb6d0dc28fb152e7ba3e63c566f7 100644 (file)
@@ -101,10 +101,14 @@ int buffer_feed(struct buffer *buf, const char *str, int len)
        buf->l += len;
        buf->r += len;
        buf->total += len;
-       if (buf->to_forward > 0) {
-               int fwd = MIN(buf->to_forward, len);
-               buf->send_max   += fwd;
-               buf->to_forward -= fwd;
+       if (buf->to_forward) {
+               unsigned long fwd = len;
+               if (buf->to_forward != BUF_INFINITE_FORWARD) {
+                       if (fwd > buf->to_forward)
+                               fwd = buf->to_forward;
+                       buf->to_forward -= fwd;
+               }
+               buf->send_max += fwd;
                buf->flags &= ~BF_OUT_EMPTY;
        }
 
index 9a8be6a4568b3533da25fee302179ff01cf58a08..38c14538e5917965b61ff8d1626d78ced0d7086e 100644 (file)
@@ -941,12 +941,12 @@ resync_stream_interface:
 
 
        /* If noone is interested in analysing data, it's time to forward
-        * everything. We will wake up from time to time when either send_max
-        * or to_forward are reached.
+        * everything. We configure the buffer to forward indefinitely.
         */
        if (!s->req->analysers &&
            !(s->req->flags & (BF_HIJACK|BF_SHUTW)) &&
-           (s->req->prod->state >= SI_ST_EST)) {
+           (s->req->prod->state >= SI_ST_EST) &&
+           (s->req->to_forward != BUF_INFINITE_FORWARD)) {
                /* This buffer is freewheeling, there's no analyser nor hijacker
                 * attached to it. If any data are left in, we'll permit them to
                 * move.
@@ -955,13 +955,12 @@ resync_stream_interface:
                buffer_auto_close(s->req);
                buffer_flush(s->req);
 
-               /* If the producer is still connected, we'll schedule large blocks
-                * of data to be forwarded from the producer to the consumer (which
-                * might possibly not be connected yet).
+               /* If the producer is still connected, we'll enable data to flow
+                * from the producer to the consumer (which might possibly not be
+                * connected yet).
                 */
-               if (!(s->req->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)) &&
-                   s->req->to_forward < FORWARD_DEFAULT_SIZE)
-                       buffer_forward(s->req, FORWARD_DEFAULT_SIZE);
+               if (!(s->req->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)))
+                       buffer_forward(s->req, BUF_INFINITE_FORWARD);
        }
 
        /* check if it is wise to enable kernel splicing to forward request data */
@@ -1063,26 +1062,20 @@ resync_stream_interface:
        /* perform output updates to the response buffer */
 
        /* If noone is interested in analysing data, it's time to forward
-        * everything. We will wake up from time to time when either send_max
-        * or to_forward are reached.
+        * everything. We configure the buffer to forward indefinitely.
         */
        if (!s->rep->analysers &&
            !(s->rep->flags & (BF_HIJACK|BF_SHUTW)) &&
-           (s->rep->prod->state >= SI_ST_EST)) {
+           (s->rep->prod->state >= SI_ST_EST) &&
+           (s->rep->to_forward != BUF_INFINITE_FORWARD)) {
                /* This buffer is freewheeling, there's no analyser nor hijacker
                 * attached to it. If any data are left in, we'll permit them to
                 * move.
                 */
                buffer_auto_close(s->rep);
                buffer_flush(s->rep);
-
-               /* If the producer is still connected, we'll schedule large blocks
-                * of data to be forwarded from the producer to the consumer (which
-                * might possibly not be connected yet).
-                */
-               if (!(s->rep->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)) &&
-                   s->rep->to_forward < FORWARD_DEFAULT_SIZE)
-                       buffer_forward(s->rep, FORWARD_DEFAULT_SIZE);
+               if (!(s->rep->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)))
+                       buffer_forward(s->rep, BUF_INFINITE_FORWARD);
        }
 
        /* check if it is wise to enable kernel splicing to forward response data */
index ed2db2f2ffbead5694ca49093e015dabb454c083..72c860772947a823a2893660171b6f284adac999 100644 (file)
@@ -105,7 +105,8 @@ _syscall6(int, splice, int, fdin, loff_t *, off_in, int, fdout, loff_t *, off_ou
 static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
 {
        int fd = si->fd;
-       int ret, max, total = 0;
+       int ret;
+       unsigned long max;
        int retval = 1;
 
        if (!b->to_forward)
@@ -138,7 +139,7 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
 
        while (1) {
                max = b->to_forward;
-               if (max <= 0) {
+               if (!max) {
                        /* It looks like the buffer + the pipe already contain
                         * the maximum amount of data to be transferred. Try to
                         * send those data immediately on the other side if it
@@ -202,8 +203,8 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
                        break;
                } /* ret <= 0 */
 
-               b->to_forward -= ret;
-               total += ret;
+               if (b->to_forward != BUF_INFINITE_FORWARD)
+                       b->to_forward -= ret;
                b->total += ret;
                b->pipe->data += ret;
                b->flags |= BF_READ_PARTIAL;
@@ -332,10 +333,14 @@ int stream_sock_read(int fd) {
                        cur_read += ret;
 
                        /* if we're allowed to directly forward data, we must update send_max */
-                       if (b->to_forward > 0 && !(b->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
-                               int fwd = MIN(b->to_forward, ret);
-                               b->send_max   += fwd;
-                               b->to_forward -= fwd;
+                       if (b->to_forward && !(b->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
+                               unsigned long fwd = ret;
+                               if (b->to_forward != BUF_INFINITE_FORWARD) {
+                                       if (fwd > b->to_forward)
+                                               fwd = b->to_forward;
+                                       b->to_forward -= fwd;
+                               }
+                               b->send_max += fwd;
                                b->flags &= ~BF_OUT_EMPTY;
                        }