[MEDIUM] stream_sock: don't close prematurely when nolinger is set

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.
diff --git a/include/types/fd.h b/include/types/fd.h
index 2bc258f..0c631b1 100644
--- a/include/types/fd.h
+++ b/include/types/fd.h
@@ -65,6 +65,7 @@
 #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 {
diff --git a/src/client.c b/src/client.c
index 346adc6..45c576d 100644
--- a/src/client.c
+++ b/src/client.c
@@ -418,6 +418,9 @@
 		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;
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index adf4e23..4a84186 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -289,6 +289,9 @@
 	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:
diff --git a/src/stream_sock.c b/src/stream_sock.c
index a3ef269..52305c5 100644
--- a/src/stream_sock.c
+++ b/src/stream_sock.c
@@ -579,7 +579,7 @@
 		 * 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 @@
 			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