[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.
This commit is contained in:
parent
5d01a63b78
commit
5d707e1aaa
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue