[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
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

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
* 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;
}

View File

@ -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.

View 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;
}

View File

@ -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 */

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)
{
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;
}