From b22e55bc8f06b6679aa5e71c3a73c0f61256f960 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Sun, 20 Mar 2011 10:16:46 +0100 Subject: [PATCH] [MEDIUM] stream_sock: add support for sending the proxy protocol header line Upon connection establishment, stream_sock is now able to send a PROXY line before sending any data. Since it's possible that the buffer is already full, and we don't want to allocate a block for that line, we compute it on-the-fly when we need it. We just store the offset from which to (re-)send from the end of the line, since it's assumed that multiple outputs of the same proxy line will be strictly equivalent. In practice, one call is enough. We just make sure to handle the case where the first send() would indicate an incomplete output, eventhough it's very unlikely to ever happen. --- include/types/stream_interface.h | 1 + src/stream_sock.c | 42 +++++++++++++++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index 16a261fb5e..27a2f977cb 100644 --- a/include/types/stream_interface.h +++ b/include/types/stream_interface.h @@ -134,6 +134,7 @@ struct stream_interface { /* struct members below are the "remote" part, as seen from the buffer side */ struct target target; /* the target to connect to (server, proxy, applet, ...) */ int conn_retries; /* number of connect retries left */ + int send_proxy_ofs; /* <0 = offset to (re)send from the end, >0 = send all */ int fd; /* file descriptor for a stream driver when known */ struct { int state; /* applet state, initialized to zero */ diff --git a/src/stream_sock.c b/src/stream_sock.c index 1f45e3ff14..845aca08cc 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -1,7 +1,7 @@ /* * Functions operating on SOCK_STREAM and buffers. * - * Copyright 2000-2010 Willy Tarreau + * Copyright 2000-2011 Willy Tarreau * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -544,6 +545,41 @@ static int stream_sock_write_loop(struct stream_interface *si, struct buffer *b) int retval = 1; int ret, max; + if (unlikely(si->send_proxy_ofs)) { + /* The target server expects a PROXY line to be sent first. + * If the send_proxy_ofs is negative, it corresponds to the + * offset to start sending from then end of the proxy string + * (which is recomputed every time since it's constant). If + * it is positive, it means we have to send from the start. + */ + ret = make_proxy_line(trash, sizeof(trash), + &b->prod->addr.c.from, &b->prod->addr.c.to); + if (!ret) + return -1; + + if (si->send_proxy_ofs > 0) + si->send_proxy_ofs = -ret; /* first call */ + + /* we have to send trash from (ret+sp for -sp bytes) */ + ret = send(si->fd, trash + ret + si->send_proxy_ofs, -si->send_proxy_ofs, + (b->flags & BF_OUT_EMPTY) ? 0 : MSG_MORE); + if (ret > 0) { + if (fdtab[si->fd].state == FD_STCONN) + fdtab[si->fd].state = FD_STREADY; + + si->send_proxy_ofs += ret; /* becomes zero once complete */ + b->flags |= BF_WRITE_NULL; /* connect() succeeded */ + } + else if (ret == 0 || errno == EAGAIN) { + /* nothing written, we need to poll for write first */ + return 0; + } + else { + /* bad, we got an error */ + return -1; + } + } + #if defined(CONFIG_HAP_LINUX_SPLICE) while (b->pipe) { ret = splice(b->pipe->cons, NULL, si->fd, NULL, b->pipe->data, @@ -710,7 +746,7 @@ int stream_sock_write(int fd) if (b->flags & BF_SHUTW) goto out_wakeup; - if (likely(!(b->flags & BF_OUT_EMPTY))) { + if (likely(!(b->flags & BF_OUT_EMPTY) || si->send_proxy_ofs)) { /* OK there are data waiting to be sent */ retval = stream_sock_write_loop(si, b); if (retval < 0) @@ -1057,7 +1093,7 @@ void stream_sock_chk_snd(struct stream_interface *si) if (!(si->flags & SI_FL_WAIT_DATA) || /* not waiting for data */ (fdtab[si->fd].ev & FD_POLL_OUT) || /* we'll be called anyway */ - (ob->flags & BF_OUT_EMPTY)) /* called with nothing to send ! */ + ((ob->flags & BF_OUT_EMPTY) && !(si->send_proxy_ofs))) /* called with nothing to send ! */ return; retval = stream_sock_write_loop(si, ob); -- 2.39.5