]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] stream_sock: don't close prematurely when nolinger is set
authorWilly Tarreau <w@1wt.eu>
Sun, 28 Jun 2009 09:09:07 +0000 (11:09 +0200)
committerWilly Tarreau <w@1wt.eu>
Sun, 28 Jun 2009 09:09:07 +0000 (11:09 +0200)
When the nolinger option is used, we must not close too fast because
some data might be left unsent. Instead we must proceed with a normal
shutdown first, then a close. Also, we want to avoid merging FIN with
the last segment if nolinger is set, because if that one gets lost,
there is no chance for it to be retransmitted.

include/types/fd.h
src/client.c
src/proto_tcp.c
src/stream_sock.c

index 2bc258fa7155fdcbbac264f9558f70b721f577d1..0c631b1d62cec775ccb4da16b117db7a318ae56d 100644 (file)
@@ -65,6 +65,7 @@ enum {
 #define FD_FL_TCP               0x0001       /* socket is TCP */
 #define FD_FL_TCP_NODELAY       0x0002
 #define FD_FL_TCP_CORK          0x0004
+#define FD_FL_TCP_NOLING        0x0008       /* lingering disabled */
 
 /* info about one given fd */
 struct fdtab {
index 346adc6734244d89ed65c88b1e7b329ad138c435..45c576dd60e64d9d6ec868ebb24dccf68322fbb4 100644 (file)
@@ -418,6 +418,9 @@ int event_accept(int fd) {
                fdtab[cfd].owner = &s->si[0];
                fdtab[cfd].state = FD_STREADY;
                fdtab[cfd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;
+               if (p->options & PR_O_TCP_NOLING)
+                       fdtab[cfd].flags |= FD_FL_TCP_NOLING;
+
                fdtab[cfd].cb[DIR_RD].f = l->proto->read;
                fdtab[cfd].cb[DIR_RD].b = s->req;
                fdtab[cfd].cb[DIR_WR].f = l->proto->write;
index adf4e230c0158f4cb870a8921396b5a1cfe6c5c2..4a841866f65420113066d7c380ec1f4029b185e9 100644 (file)
@@ -289,6 +289,9 @@ int tcp_bind_listener(struct listener *listener, char *errmsg, int errlen)
        fdtab[fd].owner = listener; /* reference the listener instead of a task */
        fdtab[fd].state = FD_STLISTEN;
        fdtab[fd].flags = FD_FL_TCP;
+       if (listener->options & LI_O_NOLINGER)
+               fdtab[fd].flags |= FD_FL_TCP_NOLING;
+
        fdtab[fd].peeraddr = NULL;
        fdtab[fd].peerlen = 0;
  tcp_return:
index a3ef26992617932788656c5a9c1b8446fb475fcd..52305c5e34ee7d4513cfb2a991d1e3f7bd272161 100644 (file)
@@ -579,7 +579,7 @@ static int stream_sock_write_loop(struct stream_interface *si, struct buffer *b)
                 * buffer but we know we will close, so we try to merge the ongoing FIN
                 * with the last data segment.
                 */
-               if ((fdtab[si->fd].flags & (FD_FL_TCP|FD_FL_TCP_CORK)) == FD_FL_TCP) {
+               if ((fdtab[si->fd].flags & (FD_FL_TCP|FD_FL_TCP_NOLING|FD_FL_TCP_CORK)) == FD_FL_TCP) {
                        if (unlikely((b->send_max == b->l && 
                                      (b->flags & (BF_SHUTW|BF_SHUTW_NOW|BF_HIJACK|BF_WRITE_ENA|BF_SHUTR)) ==
                                      (BF_WRITE_ENA|BF_SHUTR)))) {
@@ -829,6 +829,12 @@ void stream_sock_shutw(struct stream_interface *si)
                        shutdown(si->fd, SHUT_WR);
                        return;
                }
+
+               if (fdtab[si->fd].flags & FD_FL_TCP_NOLING) {
+                       /* we have to shut before closing if we disable lingering */
+                       EV_FD_CLR(si->fd, DIR_WR);
+                       shutdown(si->fd, SHUT_WR);
+               }
                /* fall through */
        case SI_ST_CON:
                /* we may have to close a pending connection, and mark the