SI_FL_DONT_WAKE = 0x0020, /* resync in progress, don't wake up */
SI_FL_INDEP_STR = 0x0040, /* independant streams = don't update rex on write */
SI_FL_NOLINGER = 0x0080, /* may close without lingering. One-shot. */
+ SI_FL_NOHALF = 0x0100, /* no half close, close both sides at once */
SI_FL_SRC_ADDR = 0x1000, /* get the source ip/port with getsockname */
SI_FL_TO_SET = 0x2000, /* addr.to is set */
SI_FL_FROM_SET = 0x4000, /* addr.from is set */
req->analyse_exp = TICK_ETERNITY;
req->analysers &= ~an_bit;
+ /* if the server closes the connection, we want to immediately react
+ * and close the socket to save packets and syscalls.
+ */
+ req->cons->flags |= SI_FL_NOHALF;
+
s->logs.tv_request = now;
/* OK let's go on with the BODY now */
return 1;
*/
http_silent_debug(__LINE__, s);
- s->req->cons->flags |= SI_FL_NOLINGER;
+ s->req->cons->flags |= SI_FL_NOLINGER | SI_FL_NOHALF;
s->req->cons->sock.shutr(s->req->cons);
s->req->cons->sock.shutw(s->req->cons);
s->req->cons->sock.shutw(s->req->cons);
}
- if (unlikely((s->req->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT))
+ if (unlikely((s->req->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT)) {
+ if (s->req->prod->flags & SI_FL_NOHALF)
+ s->req->prod->flags |= SI_FL_NOLINGER;
s->req->prod->sock.shutr(s->req->prod);
+ }
buffer_check_timeouts(s->rep);
s->rep->cons->sock.shutw(s->rep->cons);
}
- if (unlikely((s->rep->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT))
+ if (unlikely((s->rep->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT)) {
+ if (s->rep->prod->flags & SI_FL_NOHALF)
+ s->rep->prod->flags |= SI_FL_NOLINGER;
s->rep->prod->sock.shutr(s->rep->prod);
+ }
}
/* 1b: check for low-level errors reported at the stream interface.
buffer_shutr_now(s->req);
/* shutdown(read) pending */
- if (unlikely((s->req->flags & (BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTR_NOW))
+ if (unlikely((s->req->flags & (BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTR_NOW)) {
+ if (s->req->prod->flags & SI_FL_NOHALF)
+ s->req->prod->flags |= SI_FL_NOLINGER;
s->req->prod->sock.shutr(s->req->prod);
+ }
/* it's possible that an upper layer has requested a connection setup or abort.
* There are 2 situations where we decide to establish a new connection :
buffer_shutr_now(s->rep);
/* shutdown(read) pending */
- if (unlikely((s->rep->flags & (BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTR_NOW))
+ if (unlikely((s->rep->flags & (BF_SHUTR|BF_SHUTR_NOW)) == BF_SHUTR_NOW)) {
+ if (s->rep->prod->flags & SI_FL_NOHALF)
+ s->rep->prod->flags |= SI_FL_NOLINGER;
s->rep->prod->sock.shutr(s->rep->prod);
+ }
if (s->req->prod->state == SI_ST_DIS || s->req->cons->state == SI_ST_DIS)
goto resync_stream_interface;
if (si->flags & SI_FL_ERR) {
/* quick close, the socket is already shut. Remove pending flags. */
si->flags &= ~SI_FL_NOLINGER;
- } else if (si->flags & SI_FL_NOLINGER) {
+ }
+ else if (si->flags & SI_FL_NOLINGER) {
si->flags &= ~SI_FL_NOLINGER;
setsockopt(si->fd, SOL_SOCKET, SO_LINGER,
(struct linger *) &nolinger, sizeof(struct linger));
- } else {
+ }
+ else if (!(si->flags & SI_FL_NOHALF)) {
EV_FD_CLR(si->fd, DIR_WR);
shutdown(si->fd, SHUT_WR);
* This function performs a shutdown-read on a stream interface in a connected or
* init state (it does nothing for other states). It either shuts the read side
* or closes the file descriptor and marks itself as closed. The buffer flags are
- * updated to reflect the new state.
+ * updated to reflect the new state. If the stream interface has SI_FL_NOHALF,
+ * we also forward the close to the write side.
*/
static void sock_raw_shutr(struct stream_interface *si)
{
si->release(si);
return;
}
+ else if (si->flags & SI_FL_NOHALF) {
+ /* we want to immediately forward this close to the write side */
+ return sock_raw_shutw(si);
+ }
EV_FD_CLR(si->fd, DIR_RD);
return;
}