[no] option httpclose X X X X
option httplog X X X X
[no] option http_proxy X X X X
+[no] option independant-
+ streams X X X X
[no] option log-health- X - X X
checks
[no] option log-separate-
See also : "option httpclose"
+option independant-streams
+no option independant-streams
+ Enable or disable independant timeout processing for both directions
+ May be used in sections : defaults | frontend | listen | backend
+ yes | yes | yes | yes
+ Arguments : none
+
+ By default, when data is sent over a socket, both the write timeout and the
+ read timeout for that socket are refreshed, because we consider that there is
+ activity on that socket, and we have no other means of guessing if we should
+ receive data or not.
+
+ While this default behaviour is desirable for almost all applications, there
+ exists a situation where it is desirable to disable it, and only refresh the
+ read timeout if there are incoming data. This happens on sessions with large
+ timeouts and low amounts of exchanged data such as telnet session. If the
+ server suddenly disappears, the output data accumulates in the system's
+ socket buffers, both timeouts are correctly refreshed, and there is no way
+ to know the server does not receive them, so we don't timeout. However, when
+ the underlying protocol always echoes sent data, it would be enough by itself
+ to detect the issue using the read timeout. Note that this problem does not
+ happen with more verbose protocols because data won't accumulate long in the
+ socket buffers.
+
+ When this option is set on the frontend, it will disable read timeout updates
+ on data sent to the client. There probably is little use of this case. When
+ the option is set on the backend, it will disable read timeout updates on
+ data sent to the server. Doing so will typically break large HTTP posts from
+ slow lines, so use it with caution.
+
+ See also : "timeout client" and "timeout server"
+
+
option log-health-checks
no option log-health-checks
Enable or disable logging of health checks
#define PR_O2_RDPC_PRST 0x00000200 /* Actvate rdp cookie analyser */
#define PR_O2_CLFLOG 0x00000400 /* log into clf format */
#define PR_O2_LOGHCHKS 0x00000800 /* log health checks */
+#define PR_O2_INDEPSTR 0x00001000 /* independant streams, don't update rex on write */
struct error_snapshot {
struct timeval when; /* date of this event, (tv_sec == 0) means "never" */
SI_FL_WAIT_DATA = 0x0008, /* waiting for more data to send */
SI_FL_CAP_SPLTCP = 0x0010, /* splicing possible from/to TCP */
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 */
};
#define SI_FL_CAP_SPLICE (SI_FL_CAP_SPLTCP)
{ "log-health-checks", PR_O2_LOGHCHKS, PR_CAP_BE, 0 },
{ "tcp-smart-accept", PR_O2_SMARTACC, PR_CAP_FE, 0 },
{ "tcp-smart-connect", PR_O2_SMARTCON, PR_CAP_BE, 0 },
+ { "independant-streams", PR_O2_INDEPSTR, PR_CAP_FE|PR_CAP_BE, 0 },
{ NULL, 0, 0, 0 }
};
s->si[0].iohandler = NULL;
s->si[0].fd = cfd;
s->si[0].flags = SI_FL_NONE | SI_FL_CAP_SPLTCP; /* TCP splicing capable */
+ if (s->fe->options2 & PR_O2_INDEPSTR)
+ s->si[0].flags |= SI_FL_INDEP_STR;
s->si[0].exp = TICK_ETERNITY;
s->si[1].state = s->si[1].prev_state = SI_ST_INI;
s->si[1].exp = TICK_ETERNITY;
s->si[1].fd = -1; /* just to help with debugging */
s->si[1].flags = SI_FL_NONE;
+ if (s->be->options2 & PR_O2_INDEPSTR)
+ s->si[1].flags |= SI_FL_INDEP_STR;
s->srv = s->prev_srv = s->srv_conn = NULL;
s->pend_pos = NULL;
s->si[0].iohandler = NULL;
s->si[0].fd = cfd;
s->si[0].flags = SI_FL_NONE;
+ if (s->fe->options2 & PR_O2_INDEPSTR)
+ s->si[0].flags |= SI_FL_INDEP_STR;
s->si[0].exp = TICK_ETERNITY;
s->si[1].state = s->si[1].prev_state = SI_ST_INI;
s->si[1].exp = TICK_ETERNITY;
s->si[1].fd = -1; /* just to help with debugging */
s->si[1].flags = SI_FL_NONE;
+ if (s->be->options2 & PR_O2_INDEPSTR)
+ s->si[1].flags |= SI_FL_INDEP_STR;
+
stream_int_register_handler(&s->si[1], stats_io_handler);
s->si[1].private = s;
s->si[1].st0 = s->si[1].st1 = 0;
s->rep->rto = s->req->wto = be->timeout.server;
s->req->cto = be->timeout.connect;
s->conn_retries = be->conn_retries;
+ s->si[1].flags &= ~SI_FL_INDEP_STR;
+ if (be->options2 & PR_O2_INDEPSTR)
+ s->si[1].flags |= SI_FL_INDEP_STR;
+
if (be->options2 & PR_O2_RSPBUG_OK)
s->txn.rsp.err_pos = -1; /* let buggy responses pass */
s->flags |= SN_BE_ASSIGNED;
if ((si->ib->flags & (BF_FULL|BF_SHUTR)) == BF_FULL)
si->flags |= SI_FL_WAIT_ROOM;
- if (si->ob->flags & BF_WRITE_ACTIVITY || si->ib->flags & BF_READ_ACTIVITY) {
- if (tick_isset(si->ib->rex))
- si->ib->rex = tick_add_ifset(now_ms, si->ib->rto);
+ if (si->ob->flags & BF_WRITE_ACTIVITY) {
if (tick_isset(si->ob->wex))
si->ob->wex = tick_add_ifset(now_ms, si->ob->wto);
}
+ if (si->ib->flags & BF_READ_ACTIVITY ||
+ (si->ob->flags & BF_WRITE_ACTIVITY && !(si->flags & SI_FL_INDEP_STR))) {
+ if (tick_isset(si->ib->rex))
+ si->ib->rex = tick_add_ifset(now_ms, si->ib->rto);
+ }
+
if (si->ob->flags & BF_WRITE_PARTIAL)
si->ob->prod->chk_rcv(si->ob->prod);
b->wex = tick_add_ifset(now_ms, b->wto);
out_wakeup:
- if (tick_isset(si->ib->rex)) {
+ if (tick_isset(si->ib->rex) && !(si->flags & SI_FL_INDEP_STR)) {
/* Note: to prevent the client from expiring read timeouts
- * during writes, we refresh it. A better solution would be
- * to merge read+write timeouts into a unique one, although
- * that needs some study particularly on full-duplex TCP
- * connections.
+ * during writes, we refresh it. We only do this if the
+ * interface is not configured for "independant streams",
+ * because for some applications it's better not to do this,
+ * for instance when continuously exchanging small amounts
+ * of data which can full the socket buffers long before a
+ * write timeout is detected.
*/
si->ib->rex = tick_add_ifset(now_ms, si->ib->rto);
}
EV_FD_COND_S(fd, DIR_WR);
if (!tick_isset(ob->wex) || ob->flags & BF_WRITE_ACTIVITY) {
ob->wex = tick_add_ifset(now_ms, ob->wto);
- if (tick_isset(ib->rex)) {
+ if (tick_isset(ib->rex) && !(si->flags & SI_FL_INDEP_STR)) {
/* Note: depending on the protocol, we don't know if we're waiting
* for incoming data or not. So in order to prevent the socket from
* expiring read timeouts during writes, we refresh the read timeout,
- * except if it was already infinite.
+ * except if it was already infinite or if we have explicitly setup
+ * independant streams.
*/
ib->rex = tick_add_ifset(now_ms, ib->rto);
}
if ((ob->flags & (BF_OUT_EMPTY|BF_SHUTW|BF_WRITE_PARTIAL)) == BF_WRITE_PARTIAL)
ob->wex = tick_add_ifset(now_ms, ob->wto);
- if (tick_isset(si->ib->rex)) {
+ if (tick_isset(si->ib->rex) && !(si->flags & SI_FL_INDEP_STR)) {
/* Note: to prevent the client from expiring read timeouts
- * during writes, we refresh it. A better solution would be
- * to merge read+write timeouts into a unique one, although
- * that needs some study particularly on full-duplex TCP
- * connections.
+ * during writes, we refresh it. We only do this if the
+ * interface is not configured for "independant streams",
+ * because for some applications it's better not to do this,
+ * for instance when continuously exchanging small amounts
+ * of data which can full the socket buffers long before a
+ * write timeout is detected.
*/
si->ib->rex = tick_add_ifset(now_ms, si->ib->rto);
}