/* 0x00000080 - 0x00000800 unused */
/* Flags indicating the connection state */
-#define H1C_F_CS_ERROR 0x00001000 /* connection must be closed ASAP because an error occurred */
-#define H1C_F_CS_SHUTW_NOW 0x00002000 /* connection must be shut down for writes ASAP */
-#define H1C_F_CS_SHUTDOWN 0x00004000 /* connection is shut down */
+#define H1C_F_CS_ERROR 0x00001000 /* connection must be closed ASAP because an error occurred (conn-stream may still be attached) */
+#define H1C_F_CS_SHUTDOWN 0x00002000 /* connection must be shut down ASAP flushing output first (conn-stream may still be attached) */
+/* 0x00000040 unused */
#define H1C_F_CS_IDLE 0x00008000 /* connection is idle and may be reused
* (exclusive to all H1C_F_CS flags and never set when an h1s is attached) */
static int h1_send(struct h1c *h1c);
static int h1_process(struct h1c *h1c);
static struct task *h1_io_cb(struct task *t, void *ctx, unsigned short state);
-static void h1_shutw_conn(struct connection *conn, enum cs_shw_mode mode);
static struct task *h1_timeout_task(struct task *t, void *context, unsigned short state);
+static void h1_shutw_conn(struct connection *conn, enum cs_shw_mode mode);
static void h1_wake_stream_for_recv(struct h1s *h1s);
static void h1_wake_stream_for_send(struct h1s *h1s);
if (h1c->task) {
h1c->task->expire = TICK_ETERNITY;
if (h1c->flags & H1C_F_CS_SHUTDOWN) {
- /* half-closed connections switch to clientfin/serverfin
- * timeouts so that we don't hang too long on clients
- * that have gone away (especially in tunnel mode).
+ /* half-closed or dead connections : switch to clientfin/serverfin
+ * timeouts so that we don't hang too long on clients that have
+ * gone away (especially in tunnel mode).
*/
h1c->task->expire = tick_add(now_ms, h1c->shut_timeout);
task_queue(h1c->task);
- TRACE_DEVEL("refreshing connection's timeout (half-closed)", H1_EV_H1C_SEND, h1c->conn);
+ TRACE_DEVEL("refreshing connection's timeout (dead or half-closed)", H1_EV_H1C_SEND, h1c->conn);
} else if (b_data(&h1c->obuf)) {
/* any connection with pending data, need a timeout (server or client).
*/
- h1c->task->expire = tick_add(now_ms, ((h1c->flags & H1C_F_CS_SHUTW_NOW)
- ? h1c->shut_timeout
- : h1c->timeout));
+ h1c->task->expire = tick_add(now_ms, h1c->timeout);
task_queue(h1c->task);
TRACE_DEVEL("refreshing connection's timeout", H1_EV_H1C_SEND, h1c->conn);
} else if ((h1c->flags & (H1C_F_CS_IDLE|H1C_F_WAIT_NEXT_REQ)) && !(h1c->flags & H1C_F_IS_BACK)) {
if (h1c->flags & H1C_F_WAIT_NEXT_REQ)
timeout = tick_first(timeout, h1c->px->timeout.httpka);
- h1c->task->expire = tick_add(now_ms, ((h1c->flags & H1C_F_CS_SHUTW_NOW)
- ? h1c->shut_timeout
- : timeout));
+ h1c->task->expire = tick_add(now_ms, timeout);
task_queue(h1c->task);
TRACE_DEVEL("refreshing connection's timeout", H1_EV_H1C_SEND, h1c->conn);
}
TRACE_STATE("h1s on error, set error on h1c", H1_EV_H1C_ERR, h1c->conn, h1s);
}
- if (!(h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTW_NOW|H1C_F_CS_SHUTDOWN)) && /* No error/shutdown on h1c */
+ if (!(h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN)) && /* No error/shutdown on h1c */
!(h1c->conn->flags & (CO_FL_ERROR|CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH)) && /* No error/shutdown on conn */
(h1s->flags & (H1S_F_WANT_KAL|H1S_F_PARSING_DONE)) == (H1S_F_WANT_KAL|H1S_F_PARSING_DONE) && /* K/A possible */
h1s->req.state == H1_MSG_DONE && h1s->res.state == H1_MSG_DONE) { /* req/res in DONE state */
h1c->flags |= (H1C_F_CS_IDLE|H1C_F_WAIT_NEXT_REQ);
TRACE_STATE("set idle mode on h1c, waiting for the next request", H1_EV_H1C_ERR, h1c->conn, h1s);
}
+ else {
+ TRACE_STATE("set shudown on h1c", H1_EV_H1C_ERR, h1c->conn, h1s);
+ h1c->flags |= H1C_F_CS_SHUTDOWN;
+ }
pool_free(pool_head_h1s, h1s);
}
}
if (!b_data(&h1c->obuf)) {
TRACE_DEVEL("leaving with everything sent", H1_EV_H1C_SEND, h1c->conn);
h1_release_buf(h1c, &h1c->obuf);
- if (h1c->flags & H1C_F_CS_SHUTW_NOW) {
+ if (h1c->flags & H1C_F_CS_SHUTDOWN) {
TRACE_STATE("process pending shutdown for writes", H1_EV_H1C_SEND, h1c->conn);
h1_shutw_conn(conn, CS_SHW_NORMAL);
}
return -1;
if (!h1s) {
- if (h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN) ||
+ if ((h1c->flags & H1C_F_CS_ERROR) ||
+ ((h1c->flags & H1C_F_CS_SHUTDOWN) && !b_data(&h1c->obuf)) ||
conn->flags & (CO_FL_ERROR|CO_FL_SOCK_RD_SH|CO_FL_SOCK_WR_SH))
goto release;
if (!(h1c->flags & H1C_F_IS_BACK) && (h1c->flags & H1C_F_CS_IDLE)) {
*/
if (b_data(&h1c->ibuf)) {
h1_release_buf(h1c, &h1c->ibuf);
- h1c->flags = (h1c->flags & ~H1C_F_CS_IDLE) | H1C_F_CS_SHUTW_NOW;
+ h1c->flags = (h1c->flags & ~H1C_F_CS_IDLE) | H1C_F_CS_SHUTDOWN;
TRACE_DEVEL("remaining data on detach, kill connection", H1_EV_STRM_END|H1_EV_H1C_END);
goto release;
}
release:
/* We don't want to close right now unless the connection is in error or shut down for writes */
- if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_CS_SHUTDOWN|H1C_F_UPG_H2C)) ||
+ if ((h1c->flags & (H1C_F_CS_ERROR|H1C_F_UPG_H2C)) ||
(h1c->conn->flags & (CO_FL_ERROR|CO_FL_SOCK_WR_SH)) ||
- ((h1c->flags & H1C_F_CS_SHUTW_NOW) && !b_data(&h1c->obuf)) ||
+ ((h1c->flags & H1C_F_CS_SHUTDOWN) && !b_data(&h1c->obuf)) ||
!h1c->conn->owner) {
TRACE_DEVEL("killing dead connection", H1_EV_STRM_END, h1c->conn);
h1_release(h1c);
TRACE_ENTER(H1_EV_STRM_SHUT, h1c->conn, h1s);
+ if (cs->flags & CS_FL_SHR)
+ goto end;
if (cs->flags & CS_FL_KILL_CONN) {
TRACE_STATE("stream wants to kill the connection", H1_EV_STRM_SHUT, h1c->conn, h1s);
goto do_shutr;
TRACE_ENTER(H1_EV_STRM_SHUT, h1c->conn, h1s);
+ if (cs->flags & CS_FL_SHW)
+ goto end;
if (cs->flags & CS_FL_KILL_CONN) {
TRACE_STATE("stream wants to kill the connection", H1_EV_STRM_SHUT, h1c->conn, h1s);
goto do_shutw;
}
do_shutw:
- h1c->flags |= H1C_F_CS_SHUTW_NOW;
- if ((cs->flags & CS_FL_SHW) || b_data(&h1c->obuf))
- goto end;
- h1_shutw_conn(cs->conn, mode);
+ h1c->flags |= H1C_F_CS_SHUTDOWN;
+ if (!b_data(&h1c->obuf))
+ h1_shutw_conn(cs->conn, mode);
end:
TRACE_LEAVE(H1_EV_STRM_SHUT, h1c->conn, h1s);
}
TRACE_ENTER(H1_EV_STRM_SHUT, conn, h1c->h1s);
conn_xprt_shutw(conn);
conn_sock_shutw(conn, (mode == CS_SHW_NORMAL));
- h1c->flags = (h1c->flags & ~H1C_F_CS_SHUTW_NOW) | H1C_F_CS_SHUTDOWN;
TRACE_LEAVE(H1_EV_STRM_SHUT, conn, h1c->h1s);
}