From 31971e536a7e6397cd58fffe0f4f52886fa879f0 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 20 Sep 2009 12:07:52 +0200 Subject: [PATCH] [MEDIUM] add support for infinite forwarding 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 | 12 +----------- include/proto/buffers.h | 16 +++++++++++----- include/types/buffers.h | 8 ++++++-- src/buffers.c | 12 ++++++++---- src/session.c | 33 +++++++++++++-------------------- src/stream_sock.c | 21 +++++++++++++-------- 6 files changed, 52 insertions(+), 50 deletions(-) diff --git a/include/common/defaults.h b/include/common/defaults.h index 966ef4fbd..c09f5a455 100644 --- a/include/common/defaults.h +++ b/include/common/defaults.h @@ -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 @@ -40,16 +40,6 @@ #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 diff --git a/include/proto/buffers.h b/include/proto/buffers.h index 6878cfe73..abaf5eeb5 100644 --- a/include/proto/buffers.h +++ b/include/proto/buffers.h @@ -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; } diff --git a/include/types/buffers.h b/include/types/buffers.h index 969c10342..14cb966da 100644 --- a/include/types/buffers.h +++ b/include/types/buffers.h @@ -143,6 +143,9 @@ #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. diff --git a/src/buffers.c b/src/buffers.c index 6b551ab2c..a21eb4f33 100644 --- a/src/buffers.c +++ b/src/buffers.c @@ -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; } diff --git a/src/session.c b/src/session.c index 9a8be6a45..38c14538e 100644 --- a/src/session.c +++ b/src/session.c @@ -941,12 +941,12 @@ struct task *process_session(struct task *t) /* 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 @@ struct task *process_session(struct task *t) 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 @@ struct task *process_session(struct task *t) /* 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 */ diff --git a/src/stream_sock.c b/src/stream_sock.c index ed2db2f2f..72c860772 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -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; }