[MEDIUM] stream_sock_process_data moved to stream_sock.c
The old temporary process_srv_data function moved to stream_sock.c.
diff --git a/include/proto/stream_sock.h b/include/proto/stream_sock.h
index d57ddf5..dc2b763 100644
--- a/include/proto/stream_sock.h
+++ b/include/proto/stream_sock.h
@@ -33,6 +33,7 @@
/* main event functions used to move data between sockets and buffers */
int stream_sock_read(int fd);
int stream_sock_write(int fd);
+int stream_sock_process_data(int fd);
/* This either returns the sockname or the original destination address. Code
diff --git a/src/proto_http.c b/src/proto_http.c
index b53bb6c..4581813 100644
--- a/src/proto_http.c
+++ b/src/proto_http.c
@@ -50,6 +50,7 @@
#include <proto/queue.h>
#include <proto/senddata.h>
#include <proto/session.h>
+#include <proto/stream_sock.h>
#include <proto/task.h>
#ifdef CONFIG_HAP_TCPSPLICE
@@ -756,7 +757,7 @@
buffer_shutw_now(s->req);
}
- if (process_srv_data(s))
+ if (stream_sock_process_data(s->req->cons->fd))
resync |= PROCESS_SRV;
/* Count server-side errors (but not timeouts). */
@@ -3863,916 +3864,6 @@
return 0;
}
-/*
- * Manages the server FSM and its socket during the DATA phase. It must not be
- * called when a file descriptor is not attached to the buffer. It must only be
- * called during SI_ST_EST. It normally returns zero, but may return 1 if it
- * absolutely wants to be called again.
- */
-int process_srv_data(struct session *t)
-{
- struct buffer *req = t->req;
- struct buffer *rep = t->rep;
- int fd = req->cons->fd;
-
- DPRINTF(stderr,"[%u] %s: c=%s exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
- now_ms, __FUNCTION__,
- cli_stnames[t->cli_state],
- rep->rex, req->wex,
- req->flags, rep->flags,
- req->l, rep->l);
-
- /* Read or write error on the file descriptor */
- if (fdtab[fd].state == FD_STERROR) {
- trace_term(t, TT_HTTP_SRV_6);
- if (!req->cons->err_type) {
- req->cons->err_loc = t->srv;
- req->cons->err_type = SI_ET_DATA_ERR;
- }
- buffer_shutw(req);
- req->flags |= BF_WRITE_ERROR;
- buffer_shutr(rep);
- rep->flags |= BF_READ_ERROR;
-
- do_close_and_return:
- fd_delete(fd);
- req->cons->state = SI_ST_CLO;
- return 0;
- }
-
- /* Check if we need to close the read side */
- if (!(rep->flags & BF_SHUTR)) {
- /* Last read, forced read-shutdown, or other end closed */
- if (rep->flags & (BF_READ_NULL|BF_SHUTR_NOW|BF_SHUTW)) {
- trace_term(t, TT_HTTP_SRV_10);
- do_close_read:
- buffer_shutr(rep);
- if (req->flags & BF_SHUTW)
- goto do_close_and_return;
-
- EV_FD_CLR(fd, DIR_RD);
- }
- /* Read timeout */
- else if (unlikely(!(rep->flags & BF_READ_TIMEOUT) && tick_is_expired(rep->rex, now_ms))) {
- trace_term(t, TT_HTTP_SRV_12);
- rep->flags |= BF_READ_TIMEOUT;
- if (!req->cons->err_type) {
- req->cons->err_loc = t->srv;
- req->cons->err_type = SI_ET_DATA_TO;
- }
- goto do_close_read;
- }
- /* Read not closed, update FD status and timeout for reads */
- else if (rep->flags & (BF_FULL|BF_HIJACK)) {
- /* stop reading */
- EV_FD_COND_C(fd, DIR_RD);
- rep->rex = TICK_ETERNITY;
- }
- else {
- /* (re)start reading and update timeout. Note: we don't recompute the timeout
- * everytime we get here, otherwise it would risk never to expire. We only
- * update it if is was not yet set, or if we already got some read status.
- */
- EV_FD_COND_S(fd, DIR_RD);
- if (!tick_isset(rep->rex) || rep->flags & BF_READ_STATUS)
- rep->rex = tick_add_ifset(now_ms, rep->rto);
- }
- }
-
- /* Check if we need to close the write side */
- if (!(req->flags & BF_SHUTW)) {
- /* Forced write-shutdown or other end closed with empty buffer. */
- if ((req->flags & BF_SHUTW_NOW) ||
- (req->flags & (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) == (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) {
- trace_term(t, TT_HTTP_SRV_11);
- do_close_write:
- buffer_shutw(req);
- if (rep->flags & BF_SHUTR)
- goto do_close_and_return;
-
- EV_FD_CLR(fd, DIR_WR);
- shutdown(fd, SHUT_WR);
- }
- /* Write timeout */
- else if (unlikely(!(req->flags & BF_WRITE_TIMEOUT) && tick_is_expired(req->wex, now_ms))) {
- trace_term(t, TT_HTTP_SRV_13);
- req->flags |= BF_WRITE_TIMEOUT;
- if (!req->cons->err_type) {
- req->cons->err_loc = t->srv;
- req->cons->err_type = SI_ET_DATA_TO;
- }
- goto do_close_write;
- }
- /* Write not closed, update FD status and timeout for writes */
- else if ((req->flags & (BF_EMPTY|BF_MAY_FORWARD)) != BF_MAY_FORWARD) {
- /* stop writing */
- EV_FD_COND_C(fd, DIR_WR);
- req->wex = TICK_ETERNITY;
- }
- else {
- /* (re)start writing and update timeout. Note: we don't recompute the timeout
- * everytime we get here, otherwise it would risk never to expire. We only
- * update it if is was not yet set, or if we already got some write status.
- */
- EV_FD_COND_S(fd, DIR_WR);
- if (!tick_isset(req->wex) || req->flags & BF_WRITE_STATUS) {
- req->wex = tick_add_ifset(now_ms, req->wto);
- if (tick_isset(req->wex) && !(rep->flags & BF_SHUTR) && tick_isset(rep->rex)) {
- /* 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.
- */
- rep->rex = req->wex;
- }
- }
- }
- }
- return 0; /* other cases change nothing */
-}
-
-
-///*
-// * Manages the client FSM and its socket. It normally returns zero, but may
-// * return 1 if it absolutely wants to be called again.
-// *
-// * Note: process_cli is the ONLY function allowed to set cli_state to anything
-// * but CL_STCLOSE.
-// */
-//int process_cli(struct session *t)
-//{
-// struct buffer *req = t->req;
-// struct buffer *rep = t->rep;
-//
-// DPRINTF(stderr,"[%u] %s: c=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
-// now_ms, __FUNCTION__,
-// cli_stnames[t->cli_state],
-// t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_RD) : 0,
-// t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_WR) : 0,
-// req->rex, rep->wex,
-// req->flags, rep->flags,
-// req->l, rep->l);
-//
-// update_state:
-// /* FIXME: we still have to check for CL_STSHUTR because client_retnclose
-// * still set this state (and will do until unix sockets are converted).
-// */
-// if (t->cli_state == CL_STDATA || t->cli_state == CL_STSHUTR) {
-// /* we can skip most of the tests at once if some conditions are not met */
-// if (!((req->flags & (BF_READ_TIMEOUT|BF_READ_ERROR)) ||
-// (rep->flags & (BF_WRITE_TIMEOUT|BF_WRITE_ERROR)) ||
-// (!(req->flags & BF_SHUTR) && req->flags & (BF_READ_NULL|BF_SHUTW)) ||
-// (!(rep->flags & BF_SHUTW) &&
-// (rep->flags & (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) == (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR))))
-// goto update_timeouts;
-//
-// /* read or write error */
-// if (rep->flags & BF_WRITE_ERROR || req->flags & BF_READ_ERROR) {
-// buffer_shutr(req);
-// buffer_shutw(rep);
-// fd_delete(t->cli_fd);
-// t->cli_state = CL_STCLOSE;
-// trace_term(t, TT_HTTP_CLI_1);
-// if (!req->analysers) {
-// if (!(t->flags & SN_ERR_MASK))
-// t->flags |= SN_ERR_CLICL;
-// if (!(t->flags & SN_FINST_MASK)) {
-// if (t->pend_pos)
-// t->flags |= SN_FINST_Q;
-// else if (!(req->flags & BF_CONNECTED))
-// t->flags |= SN_FINST_C;
-// else
-// t->flags |= SN_FINST_D;
-// }
-// }
-// goto update_state;
-// }
-// /* last read, or end of server write */
-// else if (!(req->flags & BF_SHUTR) && /* not already done */
-// req->flags & (BF_READ_NULL | BF_SHUTW)) {
-// buffer_shutr(req);
-// if (!(rep->flags & BF_SHUTW)) {
-// EV_FD_CLR(t->cli_fd, DIR_RD);
-// trace_term(t, TT_HTTP_CLI_2);
-// } else {
-// /* output was already closed */
-// fd_delete(t->cli_fd);
-// t->cli_state = CL_STCLOSE;
-// trace_term(t, TT_HTTP_CLI_3);
-// }
-// goto update_state;
-// }
-// /* last server read and buffer empty : we only check them when we're
-// * allowed to forward the data.
-// */
-// else if (!(rep->flags & BF_SHUTW) && /* not already done */
-// rep->flags & BF_EMPTY && rep->flags & BF_MAY_FORWARD &&
-// rep->flags & BF_SHUTR && !(t->flags & SN_SELF_GEN)) {
-// buffer_shutw(rep);
-// if (!(req->flags & BF_SHUTR)) {
-// EV_FD_CLR(t->cli_fd, DIR_WR);
-// shutdown(t->cli_fd, SHUT_WR);
-// /* We must ensure that the read part is still alive when switching to shutw */
-// /* FIXME: is this still true ? */
-// EV_FD_SET(t->cli_fd, DIR_RD);
-// req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
-// trace_term(t, TT_HTTP_CLI_4);
-// } else {
-// fd_delete(t->cli_fd);
-// t->cli_state = CL_STCLOSE;
-// trace_term(t, TT_HTTP_CLI_5);
-// }
-// goto update_state;
-// }
-// /* read timeout */
-// else if ((req->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT) {
-// buffer_shutr(req);
-// if (!(rep->flags & BF_SHUTW)) {
-// EV_FD_CLR(t->cli_fd, DIR_RD);
-// trace_term(t, TT_HTTP_CLI_6);
-// } else {
-// /* output was already closed */
-// fd_delete(t->cli_fd);
-// t->cli_state = CL_STCLOSE;
-// trace_term(t, TT_HTTP_CLI_7);
-// }
-// if (!req->analysers) {
-// if (!(t->flags & SN_ERR_MASK))
-// t->flags |= SN_ERR_CLITO;
-// if (!(t->flags & SN_FINST_MASK)) {
-// if (t->pend_pos)
-// t->flags |= SN_FINST_Q;
-// else if (!(req->flags & BF_CONNECTED))
-// t->flags |= SN_FINST_C;
-// else
-// t->flags |= SN_FINST_D;
-// }
-// }
-// goto update_state;
-// }
-// /* write timeout */
-// else if ((rep->flags & (BF_SHUTW|BF_WRITE_TIMEOUT)) == BF_WRITE_TIMEOUT) {
-// buffer_shutw(rep);
-// if (!(req->flags & BF_SHUTR)) {
-// EV_FD_CLR(t->cli_fd, DIR_WR);
-// shutdown(t->cli_fd, SHUT_WR);
-// /* We must ensure that the read part is still alive when switching to shutw */
-// /* FIXME: is this still true ? */
-// EV_FD_SET(t->cli_fd, DIR_RD);
-// req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
-// trace_term(t, TT_HTTP_CLI_8);
-// } else {
-// fd_delete(t->cli_fd);
-// t->cli_state = CL_STCLOSE;
-// trace_term(t, TT_HTTP_CLI_9);
-// }
-// if (!req->analysers) {
-// if (!(t->flags & SN_ERR_MASK))
-// t->flags |= SN_ERR_CLITO;
-// if (!(t->flags & SN_FINST_MASK)) {
-// if (t->pend_pos)
-// t->flags |= SN_FINST_Q;
-// else if (!(req->flags & BF_CONNECTED))
-// t->flags |= SN_FINST_C;
-// else
-// t->flags |= SN_FINST_D;
-// }
-// }
-// goto update_state;
-// }
-//
-// update_timeouts:
-// /* manage read timeout */
-// if (!(req->flags & BF_SHUTR)) {
-// if (req->flags & BF_FULL) {
-// /* no room to read more data */
-// if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
-// /* stop reading until we get some space */
-// req->rex = TICK_ETERNITY;
-// }
-// } else {
-// EV_FD_COND_S(t->cli_fd, DIR_RD);
-// req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
-// }
-// }
-//
-// /* manage write timeout */
-// if (!(rep->flags & BF_SHUTW)) {
-// /* first, we may have to produce data (eg: stats).
-// * right now, this is limited to the SHUTR state.
-// */
-// if (req->flags & BF_SHUTR && t->flags & SN_SELF_GEN) {
-// produce_content(t);
-// if (rep->flags & BF_EMPTY) {
-// buffer_shutw(rep);
-// fd_delete(t->cli_fd);
-// t->cli_state = CL_STCLOSE;
-// trace_term(t, TT_HTTP_CLI_10);
-// goto update_state;
-// }
-// }
-//
-// /* we don't enable client write if the buffer is empty, nor if the server has to analyze it */
-// if ((rep->flags & BF_EMPTY) || !(rep->flags & BF_MAY_FORWARD)) {
-// if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
-// /* stop writing */
-// rep->wex = TICK_ETERNITY;
-// }
-// } else {
-// /* buffer not empty */
-// EV_FD_COND_S(t->cli_fd, DIR_WR);
-// if (!tick_isset(rep->wex)) {
-// /* restart writing */
-// rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
-// if (!(req->flags & BF_SHUTR) && tick_isset(rep->wex) && tick_isset(req->rex)) {
-// /* FIXME: to prevent the client from expiring read timeouts during writes,
-// * we refresh it, except if it was already infinite. */
-// req->rex = rep->wex;
-// }
-// }
-// }
-// }
-// return 0; /* other cases change nothing */
-// }
-// else if (t->cli_state == CL_STCLOSE) { /* CL_STCLOSE: nothing to do */
-// if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
-// int len;
-// len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)req->cons->fd);
-// write(1, trash, len);
-// }
-// return 0;
-// }
-//#ifdef DEBUG_DEV
-// fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, t->cli_state);
-// ABORT_NOW();
-//#endif
-// return 0;
-//}
-//
-//
-///* Return 1 if we could get a new connection for session t, otherwise zero */
-//int tcp_get_connection(struct session *t)
-//{
-// struct http_txn *txn = &t->txn;
-// struct buffer *req = t->req;
-// struct buffer *rep = t->rep;
-//
-// DPRINTF(stderr,"[%u] %s: c=%s exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
-// now_ms, __FUNCTION__,
-// cli_stnames[t->cli_state],
-// rep->rex, req->wex,
-// req->flags, rep->flags,
-// req->l, rep->l);
-//
-//
-// if ((rep->flags & BF_SHUTW) ||
-// ((req->flags & BF_SHUTR) &&
-// (req->flags & BF_EMPTY || t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
-// req->wex = TICK_ETERNITY;
-// if (t->pend_pos)
-// t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
-// /* note that this must not return any error because it would be able to
-// * overwrite the client_retnclose() output.
-// */
-// if (txn->flags & TX_CLTARPIT)
-// srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_T, 0, NULL);
-// else
-// srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, NULL);
-//
-// trace_term(t, TT_HTTP_SRV_1);
-// return 0;
-// }
-//
-// /* stop here if we're not allowed to connect */
-// if (!(req->flags & BF_MAY_FORWARD))
-// return 0;
-//
-// /* the client allows the server to connect */
-// if (txn->flags & TX_CLTARPIT) {
-// /* This connection is being tarpitted. The CLIENT side has
-// * already set the connect expiration date to the right
-// * timeout. We just have to check that it has not expired.
-// */
-// if (!(req->flags & BF_WRITE_TIMEOUT))
-// return 0;
-//
-// /* We will set the queue timer to the time spent, just for
-// * logging purposes. We fake a 500 server error, so that the
-// * attacker will not suspect his connection has been tarpitted.
-// * It will not cause trouble to the logs because we can exclude
-// * the tarpitted connections by filtering on the 'PT' status flags.
-// */
-// req->wex = TICK_ETERNITY;
-// t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
-// srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
-// 500, error_message(t, HTTP_ERR_500));
-// trace_term(t, TT_HTTP_SRV_2);
-// return 0;
-// }
-//
-// /* Right now, we will need to create a connection to the server.
-// * We might already have tried, and got a connection pending, in
-// * which case we will not do anything till it's pending. It's up
-// * to any other session to release it and wake us up again.
-// */
-// if (t->pend_pos) {
-// if (!(req->flags & BF_WRITE_TIMEOUT)) {
-// return 0;
-// } else {
-// /* we've been waiting too long here */
-// req->wex = TICK_ETERNITY;
-// t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
-// srv_close_with_err(t, SN_ERR_SRVTO, SN_FINST_Q,
-// 503, error_message(t, HTTP_ERR_503));
-// trace_term(t, TT_HTTP_SRV_3);
-// if (t->srv)
-// t->srv->failed_conns++;
-// t->be->failed_conns++;
-// return 0;
-// }
-// }
-//
-// do {
-// if (srv_redispatch_connect(t) != 0)
-// return 0;
-//
-// if (t->srv && t->srv->rdr_len && t->flags & SN_REDIRECTABLE) {
-// /* Server supporting redirection and it is possible.
-// * Invalid requests are reported as such. It concerns all
-// * the largest ones.
-// */
-// struct chunk rdr;
-// char *path;
-// int len;
-//
-// /* 1: create the response header */
-// rdr.len = strlen(HTTP_302);
-// rdr.str = trash;
-// memcpy(rdr.str, HTTP_302, rdr.len);
-//
-// /* 2: add the server's prefix */
-// if (rdr.len + t->srv->rdr_len > sizeof(trash))
-// goto cancel_redir;
-//
-// memcpy(rdr.str + rdr.len, t->srv->rdr_pfx, t->srv->rdr_len);
-// rdr.len += t->srv->rdr_len;
-//
-// /* 3: add the request URI */
-// path = http_get_path(txn);
-// if (!path)
-// goto cancel_redir;
-// len = txn->req.sl.rq.u_l + (txn->req.sol+txn->req.sl.rq.u) - path;
-// if (rdr.len + len > sizeof(trash) - 4) /* 4 for CRLF-CRLF */
-// goto cancel_redir;
-//
-// memcpy(rdr.str + rdr.len, path, len);
-// rdr.len += len;
-// memcpy(rdr.str + rdr.len, "\r\n\r\n", 4);
-// rdr.len += 4;
-//
-// srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, 302, &rdr);
-// trace_term(t, TT_HTTP_SRV_3);
-//
-// /* FIXME: we should increase a counter of redirects per server and per backend. */
-// if (t->srv)
-// t->srv->cum_sess++;
-// return 0;
-// cancel_redir:
-// txn->status = 400;
-// t->fe->failed_req++;
-// srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
-// 400, error_message(t, HTTP_ERR_400));
-// trace_term(t, TT_HTTP_SRV_4);
-// return 0;
-// }
-//
-// /* try to (re-)connect to the server, and fail if we expire the
-// * number of retries.
-// */
-// if (srv_retryable_connect(t)) {
-// t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
-// if (!(req->cons.flags & BC_KNOWN))
-// return 0;
-// /* We got an FD */
-// return 1;
-// }
-// } while (1);
-//}
-//
-//
-///* Return 1 if the pending connection has failed and should be retried,
-// * otherwise zero.
-// */
-//int tcp_connection_failed(struct session *t)
-//{
-// struct buffer *req = t->req;
-// struct buffer *rep = t->rep;
-// int conn_err;
-//
-// DPRINTF(stderr,"[%u] %s: c=%s exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
-// now_ms, __FUNCTION__,
-// cli_stnames[t->cli_state],
-// rep->rex, req->wex,
-// req->flags, rep->flags,
-// req->l, rep->l);
-//
-// if ((rep->flags & BF_SHUTW) ||
-// ((req->flags & BF_SHUTR) &&
-// ((req->flags & BF_EMPTY && !(req->flags & BF_WRITE_STATUS)) ||
-// t->be->options & PR_O_ABRT_CLOSE))) { /* give up */
-// req->wex = TICK_ETERNITY;
-// if (!(t->flags & SN_CONN_TAR)) {
-// /* if we are in turn-around, we have already closed the FD */
-// fd_delete(req->cons->fd);
-// req->cons->state = SI_ST_CLO;
-// if (t->srv) {
-// t->srv->cur_sess--;
-// sess_change_server(t, NULL);
-// }
-// }
-//
-// /* note that this must not return any error because it would be able to
-// * overwrite the client_retnclose() output.
-// */
-// srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
-// trace_term(t, TT_HTTP_SRV_5);
-// return 0;
-// }
-//
-// if (!(req->flags & (BF_WRITE_STATUS | BF_WRITE_TIMEOUT)))
-// return 0; /* nothing changed */
-//
-// if (!(req->flags & BF_WRITE_STATUS) || (req->flags & BF_WRITE_ERROR)) {
-// /* timeout, asynchronous connect error or first write error */
-// if (t->flags & SN_CONN_TAR) {
-// /* We are doing a turn-around waiting for a new connection attempt. */
-// if (!(req->flags & BF_WRITE_TIMEOUT))
-// return 0;
-// t->flags &= ~SN_CONN_TAR;
-// }
-// else {
-// fd_delete(req->cons->fd);
-// req->cons->state = SI_ST_CLO;
-// if (t->srv) {
-// t->srv->cur_sess--;
-// sess_change_server(t, NULL);
-// }
-//
-// if (!(req->flags & BF_WRITE_STATUS))
-// conn_err = SN_ERR_SRVTO; // it was a connect timeout.
-// else
-// conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
-//
-// /* ensure that we have enough retries left */
-// if (srv_count_retry_down(t, conn_err))
-// return 0;
-//
-// if (req->flags & BF_WRITE_ERROR) {
-// /* we encountered an immediate connection error, and we
-// * will have to retry connecting to the same server, most
-// * likely leading to the same result. To avoid this, we
-// * fake a connection timeout to retry after a turn-around
-// * time of 1 second. We will wait in the previous if block.
-// */
-// t->flags |= SN_CONN_TAR;
-// req->wex = tick_add(now_ms, MS_TO_TICKS(1000));
-// return 0;
-// }
-// }
-//
-// if (t->srv && t->conn_retries == 0 && t->be->options & PR_O_REDISP) {
-// /* We're on our last chance, and the REDISP option was specified.
-// * We will ignore cookie and force to balance or use the dispatcher.
-// */
-// /* let's try to offer this slot to anybody */
-// if (may_dequeue_tasks(t->srv, t->be))
-// process_srv_queue(t->srv);
-//
-// /* it's left to the dispatcher to choose a server */
-// t->flags &= ~(SN_DIRECT | SN_ASSIGNED | SN_ADDR_SET);
-// t->prev_srv = t->srv;
-//
-// /* first, get a connection */
-// if (srv_redispatch_connect(t)) {
-// if (req->cons.flags & BC_KNOWN)
-// return 0;
-// /* we need to get a connection */
-// return 1;
-// }
-// } else {
-// if (t->srv)
-// t->srv->retries++;
-// t->be->retries++;
-// }
-//
-// do {
-// /* Now we will try to either reconnect to the same server or
-// * connect to another server. If the connection gets queued
-// * because all servers are saturated, then we will go back to
-// * the idle state where the buffer's consumer is marked as
-// * unknown.
-// */
-// if (srv_retryable_connect(t)) {
-// t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
-// if (req->cons.flags & BC_KNOWN)
-// return 0;
-// /* we did not get a connection */
-// return 1;
-// }
-//
-// /* we need to redispatch the connection to another server */
-// if (srv_redispatch_connect(t)) {
-// if (req->cons.flags & BC_KNOWN)
-// return 0;
-// /* we need to get a connection */
-// return 1;
-// }
-// } while (1);
-// }
-// else { /* no error and write OK */
-// t->logs.t_connect = tv_ms_elapsed(&t->logs.tv_accept, &now);
-//
-// if (req->flags & BF_EMPTY) {
-// EV_FD_CLR(req->cons->fd, DIR_WR);
-// req->wex = TICK_ETERNITY;
-// } else {
-// EV_FD_SET(req->cons->fd, DIR_WR);
-// req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
-// if (tick_isset(req->wex)) {
-// /* FIXME: to prevent the server from expiring read timeouts during writes,
-// * we refresh it. */
-// rep->rex = req->wex;
-// }
-// }
-//
-// if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
-// EV_FD_SET(req->cons->fd, DIR_RD);
-// rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
-// buffer_set_rlim(rep, BUFSIZE); /* no rewrite needed */
-//
-// /* if the user wants to log as soon as possible, without counting
-// bytes from the server, then this is the right moment. */
-// if (t->fe->to_log && !(t->logs.logwait & LW_BYTES)) {
-// t->logs.t_close = t->logs.t_connect; /* to get a valid end date */
-// tcp_sess_log(t);
-// }
-//#ifdef CONFIG_HAP_TCPSPLICE
-// if ((t->fe->options & t->be->options) & PR_O_TCPSPLICE) {
-// /* TCP splicing supported by both FE and BE */
-// tcp_splice_splicefd(t->cli_fd, req->cons->fd, 0);
-// }
-//#endif
-// }
-// else {
-// rep->analysers |= AN_RTR_HTTP_HDR;
-// buffer_set_rlim(rep, BUFSIZE - MAXREWRITE); /* rewrite needed */
-// t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
-// /* reset hdr_idx which was already initialized by the request.
-// * right now, the http parser does it.
-// * hdr_idx_init(&t->txn.hdr_idx);
-// */
-// }
-//
-// req->flags |= BF_CONNECTED;
-// if (!rep->analysers)
-// t->rep->flags |= BF_MAY_FORWARD;
-// req->wex = TICK_ETERNITY;
-// return 0;
-// }
-//}
-//
-//
-///*
-// * Tries to establish a connection to the server and associate it to the
-// * request buffer's consumer side. It normally returns zero, but may return 1
-// * if it absolutely wants to be called again.
-// */
-//int process_srv_conn(struct session *t)
-//{
-// DPRINTF(stderr,"[%u] %s: c=%s exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
-// now_ms, __FUNCTION__,
-// cli_stnames[t->cli_state],
-// t->rep->rex, t->req->wex,
-// t->req->flags, t->rep->flags,
-// t->req->l, t->rep->l);
-//
-// while (!(t->req->flags & BF_CONNECTED)) {
-// if (!(t->req->cons.flags & BC_KNOWN)) {
-// /* no connection in progress, get a new one */
-// if (!tcp_get_connection(t))
-// break;
-// } else {
-// /* connection in progress or just completed */
-// if (!tcp_connection_failed(t))
-// break;
-// }
-// }
-// return 0;
-//}
-//
-//
-///*
-// * Manages the server FSM and its socket during the DATA phase. It must not
-// * be called when a file descriptor is not attached to the buffer. It normally
-// * returns zero, but may return 1 if it absolutely wants to be called again.
-// */
-//int process_srv_data(struct session *t)
-//{
-// struct buffer *req = t->req;
-// struct buffer *rep = t->rep;
-//
-// DPRINTF(stderr,"[%u] %s: c=%s exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
-// now_ms, __FUNCTION__,
-// cli_stnames[t->cli_state],
-// rep->rex, req->wex,
-// req->flags, rep->flags,
-// req->l, rep->l);
-//
-// /* we can skip most of the tests at once if some conditions are not met */
-// if (!((req->flags & (BF_WRITE_TIMEOUT|BF_WRITE_ERROR)) ||
-// (!(req->flags & BF_SHUTW) &&
-// (req->flags & (BF_EMPTY|BF_MAY_FORWARD)) == (BF_EMPTY|BF_MAY_FORWARD)) ||
-// (rep->flags & (BF_READ_TIMEOUT|BF_READ_ERROR)) ||
-// (!(rep->flags & BF_SHUTR) && rep->flags & (BF_READ_NULL|BF_SHUTW))))
-// goto update_timeouts;
-//
-// /* read or write error */
-// /* FIXME: what happens when we have to deal with HTTP ??? */
-// if (req->flags & BF_WRITE_ERROR || rep->flags & BF_READ_ERROR) {
-// buffer_shutr(rep);
-// buffer_shutw(req);
-// fd_delete(req->cons->fd);
-// req->cons->state = SI_ST_CLO;
-// if (t->srv) {
-// t->srv->cur_sess--;
-// t->srv->failed_resp++;
-// sess_change_server(t, NULL);
-// }
-// t->be->failed_resp++;
-// trace_term(t, TT_HTTP_SRV_6);
-// if (!rep->analysers) {
-// if (!(t->flags & SN_ERR_MASK))
-// t->flags |= SN_ERR_SRVCL;
-// if (!(t->flags & SN_FINST_MASK))
-// t->flags |= SN_FINST_D;
-// }
-// if (may_dequeue_tasks(t->srv, t->be))
-// process_srv_queue(t->srv);
-//
-// return 0;
-// }
-//
-// /* last read, or end of client write */
-// if (!(rep->flags & BF_SHUTR) && /* not already done */
-// rep->flags & (BF_READ_NULL | BF_SHUTW)) {
-// buffer_shutr(rep);
-// if (!(req->flags & BF_SHUTW)) {
-// EV_FD_CLR(req->cons->fd, DIR_RD);
-// trace_term(t, TT_HTTP_SRV_7);
-// } else {
-// /* output was already closed */
-// fd_delete(req->cons->fd);
-// req->cons->state = SI_ST_CLO;
-// if (t->srv) {
-// t->srv->cur_sess--;
-// sess_change_server(t, NULL);
-// }
-// trace_term(t, TT_HTTP_SRV_8);
-//
-// if (may_dequeue_tasks(t->srv, t->be))
-// process_srv_queue(t->srv);
-// return 0;
-// }
-// }
-// /* end of client read and no more data to send. We can forward
-// * the close when we're allowed to forward data (anytime right
-// * now). If we're using option forceclose, then we may also
-// * shutdown the outgoing write channel once the response starts
-// * coming from the server.
-// */
-// if (!(req->flags & BF_SHUTW) && /* not already done */
-// req->flags & BF_EMPTY && req->flags & BF_MAY_FORWARD &&
-// (req->flags & BF_SHUTR ||
-// (t->be->options & PR_O_FORCE_CLO && rep->flags & BF_READ_STATUS))) {
-// buffer_shutw(req);
-// if (!(rep->flags & BF_SHUTR)) {
-// EV_FD_CLR(req->cons->fd, DIR_WR);
-// shutdown(req->cons->fd, SHUT_WR);
-// trace_term(t, TT_HTTP_SRV_9);
-// /* We must ensure that the read part is still alive when switching to shutw */
-// /* FIXME: is this still true ? */
-// EV_FD_SET(req->cons->fd, DIR_RD);
-// rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
-// } else {
-// fd_delete(req->cons->fd);
-// req->cons->state = SI_ST_CLO;
-// if (t->srv) {
-// t->srv->cur_sess--;
-// sess_change_server(t, NULL);
-// }
-// trace_term(t, TT_HTTP_SRV_10);
-//
-// if (may_dequeue_tasks(t->srv, t->be))
-// process_srv_queue(t->srv);
-// return 0;
-// }
-// }
-//
-// /* read timeout */
-// if ((rep->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT) {
-// if (!rep->analysers) {
-// if (!(t->flags & SN_ERR_MASK))
-// t->flags |= SN_ERR_SRVTO;
-// if (!(t->flags & SN_FINST_MASK))
-// t->flags |= SN_FINST_D;
-// }
-// buffer_shutr(rep);
-// if (!(req->flags & BF_SHUTW)) {
-// EV_FD_CLR(req->cons->fd, DIR_RD);
-// trace_term(t, TT_HTTP_SRV_11);
-// } else {
-// fd_delete(req->cons->fd);
-// req->cons->state = SI_ST_CLO;
-// if (t->srv) {
-// t->srv->cur_sess--;
-// sess_change_server(t, NULL);
-// }
-// trace_term(t, TT_HTTP_SRV_12);
-//
-// if (may_dequeue_tasks(t->srv, t->be))
-// process_srv_queue(t->srv);
-// return 0;
-// }
-// }
-//
-// /* write timeout */
-// if ((req->flags & (BF_SHUTW|BF_WRITE_TIMEOUT)) == BF_WRITE_TIMEOUT) {
-// if (!rep->analysers) {
-// if (!(t->flags & SN_ERR_MASK))
-// t->flags |= SN_ERR_SRVTO;
-// if (!(t->flags & SN_FINST_MASK))
-// t->flags |= SN_FINST_D;
-// }
-// buffer_shutw(req);
-// if (!(rep->flags & BF_SHUTR)) {
-// EV_FD_CLR(req->cons->fd, DIR_WR);
-// shutdown(req->cons->fd, SHUT_WR);
-// /* We must ensure that the read part is still alive when switching to shutw */
-// /* FIXME: is this still needed ? */
-// EV_FD_SET(req->cons->fd, DIR_RD);
-// rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
-// trace_term(t, TT_HTTP_SRV_13);
-// } else {
-// fd_delete(req->cons->fd);
-// req->cons->state = SI_ST_CLO;
-// if (t->srv) {
-// t->srv->cur_sess--;
-// sess_change_server(t, NULL);
-// }
-// trace_term(t, TT_HTTP_SRV_14);
-//
-// if (may_dequeue_tasks(t->srv, t->be))
-// process_srv_queue(t->srv);
-// return 0;
-// }
-// }
-//
-// update_timeouts:
-// /* manage read timeout */
-// if (!(rep->flags & BF_SHUTR)) {
-// if (rep->flags & BF_FULL) {
-// if (EV_FD_COND_C(req->cons->fd, DIR_RD))
-// rep->rex = TICK_ETERNITY;
-// } else {
-// EV_FD_COND_S(req->cons->fd, DIR_RD);
-// rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
-// }
-// }
-//
-// /* manage write timeout */
-// if (!(req->flags & BF_SHUTW)) {
-// if (req->flags & BF_EMPTY || !(req->flags & BF_MAY_FORWARD)) {
-// /* stop writing */
-// if (EV_FD_COND_C(req->cons->fd, DIR_WR))
-// req->wex = TICK_ETERNITY;
-// } else {
-// /* buffer not empty, there are still data to be transferred */
-// EV_FD_COND_S(req->cons->fd, DIR_WR);
-// if (!tick_isset(req->wex)) {
-// /* restart writing */
-// req->wex = tick_add_ifset(now_ms, t->be->timeout.server);
-// if (!(rep->flags & BF_SHUTR) && tick_isset(req->wex) && tick_isset(rep->rex)) {
-// /* FIXME: to prevent the server from expiring read timeouts during writes,
-// * we refresh it, except if it was already infinite.
-// */
-// rep->rex = req->wex;
-// }
-// }
-// }
-// }
-// return 0; /* other cases change nothing */
-//}
-//
/*
* Produces data for the session <s> depending on its source. Expects to be
diff --git a/src/stream_sock.c b/src/stream_sock.c
index cc33b81..a08bf9b 100644
--- a/src/stream_sock.c
+++ b/src/stream_sock.c
@@ -26,6 +26,7 @@
#include <common/ticks.h>
#include <common/time.h>
+#include <proto/buffers.h>
#include <proto/client.h>
#include <proto/fd.h>
#include <proto/stream_sock.h>
@@ -415,6 +416,134 @@
}
+/*
+ * Manages a stream_sock connection during its data phase. The file descriptor
+ * status is checked, and the read and write timeouts are controlled. The
+ * buffers are examined for special shutdown cases and finally the timeouts,
+ * file descriptor and buffers' flags are updated accordingly.
+ */
+int stream_sock_process_data(int fd)
+{
+ struct buffer *ib = fdtab[fd].cb[DIR_RD].b;
+ struct buffer *ob = fdtab[fd].cb[DIR_WR].b;
+
+ DPRINTF(stderr,"[%u] %s: fd=%d owner=%p ib=%p, ob=%p, exp(r,w)=%u,%u ibf=%08x obf=%08x ibl=%d obl=%d\n",
+ now_ms, __FUNCTION__,
+ fd, fdtab[fd].owner,
+ ib, ob,
+ ib->rex, ob->wex,
+ ib->flags, ob->flags,
+ ib->l, ob->l);
+
+ /* Read or write error on the file descriptor */
+ if (fdtab[fd].state == FD_STERROR) {
+ //trace_term(t, TT_HTTP_SRV_6);
+ if (!ob->cons->err_type) {
+ //ob->cons->err_loc = t->srv;
+ ob->cons->err_type = SI_ET_DATA_ERR;
+ }
+ buffer_shutw(ob);
+ ob->flags |= BF_WRITE_ERROR;
+ buffer_shutr(ib);
+ ib->flags |= BF_READ_ERROR;
+
+ do_close_and_return:
+ fd_delete(fd);
+ ob->cons->state = SI_ST_CLO;
+ return 0;
+ }
+
+ /* Check if we need to close the read side */
+ if (!(ib->flags & BF_SHUTR)) {
+ /* Last read, forced read-shutdown, or other end closed */
+ if (ib->flags & (BF_READ_NULL|BF_SHUTR_NOW|BF_SHUTW)) {
+ //trace_term(t, TT_HTTP_SRV_10);
+ do_close_read:
+ buffer_shutr(ib);
+ if (ob->flags & BF_SHUTW)
+ goto do_close_and_return;
+
+ EV_FD_CLR(fd, DIR_RD);
+ }
+ /* Read timeout */
+ else if (unlikely(!(ib->flags & BF_READ_TIMEOUT) && tick_is_expired(ib->rex, now_ms))) {
+ //trace_term(t, TT_HTTP_SRV_12);
+ ib->flags |= BF_READ_TIMEOUT;
+ if (!ob->cons->err_type) {
+ //ob->cons->err_loc = t->srv;
+ ob->cons->err_type = SI_ET_DATA_TO;
+ }
+ goto do_close_read;
+ }
+ /* Read not closed, update FD status and timeout for reads */
+ else if (ib->flags & (BF_FULL|BF_HIJACK)) {
+ /* stop reading */
+ EV_FD_COND_C(fd, DIR_RD);
+ ib->rex = TICK_ETERNITY;
+ }
+ else {
+ /* (re)start reading and update timeout. Note: we don't recompute the timeout
+ * everytime we get here, otherwise it would risk never to expire. We only
+ * update it if is was not yet set, or if we already got some read status.
+ */
+ EV_FD_COND_S(fd, DIR_RD);
+ if (!tick_isset(ib->rex) || ib->flags & BF_READ_STATUS)
+ ib->rex = tick_add_ifset(now_ms, ib->rto);
+ }
+ }
+
+ /* Check if we need to close the write side */
+ if (!(ob->flags & BF_SHUTW)) {
+ /* Forced write-shutdown or other end closed with empty buffer. */
+ if ((ob->flags & BF_SHUTW_NOW) ||
+ (ob->flags & (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) == (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) {
+ //trace_term(t, TT_HTTP_SRV_11);
+ do_close_write:
+ buffer_shutw(ob);
+ if (ib->flags & BF_SHUTR)
+ goto do_close_and_return;
+
+ EV_FD_CLR(fd, DIR_WR);
+ shutdown(fd, SHUT_WR);
+ }
+ /* Write timeout */
+ else if (unlikely(!(ob->flags & BF_WRITE_TIMEOUT) && tick_is_expired(ob->wex, now_ms))) {
+ //trace_term(t, TT_HTTP_SRV_13);
+ ob->flags |= BF_WRITE_TIMEOUT;
+ if (!ob->cons->err_type) {
+ //ob->cons->err_loc = t->srv;
+ ob->cons->err_type = SI_ET_DATA_TO;
+ }
+ goto do_close_write;
+ }
+ /* Write not closed, update FD status and timeout for writes */
+ else if ((ob->flags & (BF_EMPTY|BF_MAY_FORWARD)) != BF_MAY_FORWARD) {
+ /* stop writing */
+ EV_FD_COND_C(fd, DIR_WR);
+ ob->wex = TICK_ETERNITY;
+ }
+ else {
+ /* (re)start writing and update timeout. Note: we don't recompute the timeout
+ * everytime we get here, otherwise it would risk never to expire. We only
+ * update it if is was not yet set, or if we already got some write status.
+ */
+ EV_FD_COND_S(fd, DIR_WR);
+ if (!tick_isset(ob->wex) || ob->flags & BF_WRITE_STATUS) {
+ ob->wex = tick_add_ifset(now_ms, ob->wto);
+ if (tick_isset(ob->wex) && !(ib->flags & BF_SHUTR) && tick_isset(ib->rex)) {
+ /* 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.
+ */
+ ib->rex = ob->wex;
+ }
+ }
+ }
+ }
+ return 0; /* other cases change nothing */
+}
+
/*
* Local variables: