diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index 16a261fb5..27a2f977c 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 1f45e3ff1..845aca08c 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);