diff --git a/include/types/fd.h b/include/types/fd.h index 2bc258fa71..0c631b1d62 100644 --- a/include/types/fd.h +++ b/include/types/fd.h @@ -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 { diff --git a/src/client.c b/src/client.c index 346adc6734..45c576dd60 100644 --- a/src/client.c +++ b/src/client.c @@ -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; diff --git a/src/proto_tcp.c b/src/proto_tcp.c index adf4e230c0..4a841866f6 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -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: diff --git a/src/stream_sock.c b/src/stream_sock.c index a3ef269926..52305c5e34 100644 --- a/src/stream_sock.c +++ b/src/stream_sock.c @@ -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