[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.
This commit is contained in:
Willy Tarreau 2009-09-20 12:07:52 +02:00
parent 59454bfaa4
commit 31971e536a
6 changed files with 52 additions and 50 deletions

View File

@ -2,7 +2,7 @@
include/common/defaults.h include/common/defaults.h
Miscellaneous default values. 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 This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@ -40,16 +40,6 @@
#define MAXREWRITE (BUFSIZE / 2) #define MAXREWRITE (BUFSIZE / 2)
#endif #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 REQURI_LEN 1024
#define CAPTURE_LEN 64 #define CAPTURE_LEN 64

View 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 * cause lockups when send_max goes down to zero if nobody is ready to push the
* remaining data. * 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) if (!bytes)
return; return;
@ -98,8 +98,13 @@ static inline void buffer_forward(struct buffer *buf, unsigned int bytes)
return; return;
} }
buf->to_forward += bytes - data_left;
buf->send_max += 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 /* 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) if (buf->r - buf->data == buf->size)
buf->r -= buf->size; buf->r -= buf->size;
if ((signed)(buf->to_forward - 1) >= 0) { if (buf->to_forward >= 1) {
buf->to_forward--; if (buf->to_forward != BUF_INFINITE_FORWARD)
buf->to_forward--;
buf->send_max++; buf->send_max++;
buf->flags &= ~BF_OUT_EMPTY; buf->flags &= ~BF_OUT_EMPTY;
} }

View File

@ -143,6 +143,9 @@
#define AN_RTR_HTTP_HDR 0x00000200 /* inspect HTTP response headers */ #define AN_RTR_HTTP_HDR 0x00000200 /* inspect HTTP response headers */
#define AN_REQ_PRST_RDP_COOKIE 0x00000400 /* persistence on rdp cookie */ #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 */ /* describes a chunk of string */
struct chunk { struct chunk {
char *str; /* beginning of the string itself. Might not be 0-terminated */ 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 size; /* buffer size in bytes */
unsigned int max_len; /* read limit, used to keep room for header rewriting */ 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 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 */ unsigned int analysers; /* bit field indicating what to do on the buffer */
int analyse_exp; /* expiration date for current analysers (if set) */ int analyse_exp; /* expiration date for current analysers (if set) */
void (*hijacker)(struct session *, struct buffer *); /* alternative content producer */ 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 The producer is responsible for decreasing ->to_forward and increasing
->send_max. The ->to_forward parameter indicates how many bytes may be fed ->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 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 may never exceed ->l. This parameter is updated by any buffer_write() as
well as any data forwarded through the visible buffer. well as any data forwarded through the visible buffer.

View File

@ -101,10 +101,14 @@ int buffer_feed(struct buffer *buf, const char *str, int len)
buf->l += len; buf->l += len;
buf->r += len; buf->r += len;
buf->total += len; buf->total += len;
if (buf->to_forward > 0) { if (buf->to_forward) {
int fwd = MIN(buf->to_forward, len); unsigned long fwd = len;
buf->send_max += fwd; if (buf->to_forward != BUF_INFINITE_FORWARD) {
buf->to_forward -= fwd; if (fwd > buf->to_forward)
fwd = buf->to_forward;
buf->to_forward -= fwd;
}
buf->send_max += fwd;
buf->flags &= ~BF_OUT_EMPTY; buf->flags &= ~BF_OUT_EMPTY;
} }

View File

@ -941,12 +941,12 @@ resync_stream_interface:
/* If noone is interested in analysing data, it's time to forward /* 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 * everything. We configure the buffer to forward indefinitely.
* or to_forward are reached.
*/ */
if (!s->req->analysers && if (!s->req->analysers &&
!(s->req->flags & (BF_HIJACK|BF_SHUTW)) && !(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 /* This buffer is freewheeling, there's no analyser nor hijacker
* attached to it. If any data are left in, we'll permit them to * attached to it. If any data are left in, we'll permit them to
* move. * move.
@ -955,13 +955,12 @@ resync_stream_interface:
buffer_auto_close(s->req); buffer_auto_close(s->req);
buffer_flush(s->req); buffer_flush(s->req);
/* If the producer is still connected, we'll schedule large blocks /* If the producer is still connected, we'll enable data to flow
* of data to be forwarded from the producer to the consumer (which * from the producer to the consumer (which might possibly not be
* might possibly not be connected yet). * connected yet).
*/ */
if (!(s->req->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)) && if (!(s->req->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)))
s->req->to_forward < FORWARD_DEFAULT_SIZE) buffer_forward(s->req, BUF_INFINITE_FORWARD);
buffer_forward(s->req, FORWARD_DEFAULT_SIZE);
} }
/* check if it is wise to enable kernel splicing to forward request data */ /* 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 */ /* perform output updates to the response buffer */
/* If noone is interested in analysing data, it's time to forward /* 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 * everything. We configure the buffer to forward indefinitely.
* or to_forward are reached.
*/ */
if (!s->rep->analysers && if (!s->rep->analysers &&
!(s->rep->flags & (BF_HIJACK|BF_SHUTW)) && !(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 /* This buffer is freewheeling, there's no analyser nor hijacker
* attached to it. If any data are left in, we'll permit them to * attached to it. If any data are left in, we'll permit them to
* move. * move.
*/ */
buffer_auto_close(s->rep); buffer_auto_close(s->rep);
buffer_flush(s->rep); buffer_flush(s->rep);
if (!(s->rep->flags & (BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)))
/* If the producer is still connected, we'll schedule large blocks buffer_forward(s->rep, BUF_INFINITE_FORWARD);
* 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);
} }
/* check if it is wise to enable kernel splicing to forward response data */ /* check if it is wise to enable kernel splicing to forward response data */

View 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) static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
{ {
int fd = si->fd; int fd = si->fd;
int ret, max, total = 0; int ret;
unsigned long max;
int retval = 1; int retval = 1;
if (!b->to_forward) if (!b->to_forward)
@ -138,7 +139,7 @@ static int stream_sock_splice_in(struct buffer *b, struct stream_interface *si)
while (1) { while (1) {
max = b->to_forward; max = b->to_forward;
if (max <= 0) { if (!max) {
/* It looks like the buffer + the pipe already contain /* It looks like the buffer + the pipe already contain
* the maximum amount of data to be transferred. Try to * the maximum amount of data to be transferred. Try to
* send those data immediately on the other side if it * 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; break;
} /* ret <= 0 */ } /* ret <= 0 */
b->to_forward -= ret; if (b->to_forward != BUF_INFINITE_FORWARD)
total += ret; b->to_forward -= ret;
b->total += ret; b->total += ret;
b->pipe->data += ret; b->pipe->data += ret;
b->flags |= BF_READ_PARTIAL; b->flags |= BF_READ_PARTIAL;
@ -332,10 +333,14 @@ int stream_sock_read(int fd) {
cur_read += ret; cur_read += ret;
/* if we're allowed to directly forward data, we must update send_max */ /* 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))) { if (b->to_forward && !(b->flags & (BF_SHUTW|BF_SHUTW_NOW))) {
int fwd = MIN(b->to_forward, ret); unsigned long fwd = ret;
b->send_max += fwd; if (b->to_forward != BUF_INFINITE_FORWARD) {
b->to_forward -= fwd; if (fwd > b->to_forward)
fwd = b->to_forward;
b->to_forward -= fwd;
}
b->send_max += fwd;
b->flags &= ~BF_OUT_EMPTY; b->flags &= ~BF_OUT_EMPTY;
} }