From 100c46712068f550145f250f597d25daf3c588cd Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 20 Aug 2012 12:06:26 +0200 Subject: [PATCH] MEDIUM: stream_interface: offer a generic function for connection updates We need to have a generic function to be called by upper layers when buffer flags have been updated (the si->update function). At the moment, both sock_raw and sock_ssl had their own which basically was a copy-paste. Since these functions are only used to update stream interface flags, it is logical to have them handled by the stream interface code. This allowed us to remove the stream_interface-specific update function from sock_raw and sock_ssl which now use the generic code. The stream_sock_update_conn callback has also been more appropriately renamed conn_notify_si() since it's meant to be called by lower layers to notify the SI and possibly upper layers about incoming changes. --- include/proto/stream_interface.h | 3 +- src/connection.c | 2 +- src/sock_raw.c | 83 +----------------------------- src/stream_interface.c | 87 +++++++++++++++++++++++++++++++- 4 files changed, 89 insertions(+), 86 deletions(-) diff --git a/include/proto/stream_interface.h b/include/proto/stream_interface.h index 224ce8499..5e2d74f6b 100644 --- a/include/proto/stream_interface.h +++ b/include/proto/stream_interface.h @@ -35,7 +35,8 @@ int stream_int_check_timeouts(struct stream_interface *si); void stream_int_report_error(struct stream_interface *si); void stream_int_retnclose(struct stream_interface *si, const struct chunk *msg); int conn_si_send_proxy(struct connection *conn, unsigned int flag); -void stream_sock_update_conn(struct connection *conn); +void conn_notify_si(struct connection *conn); +void stream_int_update_conn(struct stream_interface *si); int stream_int_shutr(struct stream_interface *si); int stream_int_shutw(struct stream_interface *si); diff --git a/src/connection.c b/src/connection.c index 1f0d8a98c..1eada2d67 100644 --- a/src/connection.c +++ b/src/connection.c @@ -82,7 +82,7 @@ int conn_fd_handler(int fd) leave: if (conn->flags & CO_FL_NOTIFY_SI) - stream_sock_update_conn(conn); + conn_notify_si(conn); /* Last check, verify if the connection just established */ if (unlikely(!(conn->flags & (CO_FL_WAIT_L4_CONN | CO_FL_WAIT_L6_CONN | CO_FL_CONNECTED)))) diff --git a/src/sock_raw.c b/src/sock_raw.c index 6ce4c9118..6a3a2565c 100644 --- a/src/sock_raw.c +++ b/src/sock_raw.c @@ -45,7 +45,6 @@ /* main event functions used to move data between sockets and buffers */ static void sock_raw_read(struct connection *conn); static void sock_raw_write(struct connection *conn); -static void sock_raw_data_finish(struct stream_interface *si); static void sock_raw_read0(struct stream_interface *si); static void sock_raw_chk_rcv(struct stream_interface *si); static void sock_raw_chk_snd(struct stream_interface *si); @@ -674,86 +673,6 @@ static void sock_raw_read0(struct stream_interface *si) return; } -/* - * Updates a connected sock_raw file descriptor status and timeouts - * according to the buffers' flags. It should only be called once after the - * buffer flags have settled down, and before they are cleared. It doesn't - * harm to call it as often as desired (it just slightly hurts performance). - */ -static void sock_raw_data_finish(struct stream_interface *si) -{ - struct buffer *ib = si->ib; - struct buffer *ob = si->ob; - - DPRINTF(stderr,"[%u] %s: fd=%d owner=%p ib=%p, ob=%p, exp(r,w)=%u,%u ibf=%08x obf=%08x ibh=%d ibt=%d obh=%d obd=%d si=%d\n", - now_ms, __FUNCTION__, - si_fd(si), fdtab[si_fd(fd)].owner, - ib, ob, - ib->rex, ob->wex, - ib->flags, ob->flags, - ib->i, ib->o, ob->i, ob->o, si->state); - - /* Check if we need to close the read side */ - if (!(ib->flags & BF_SHUTR)) { - /* Read not closed, update FD status and timeout for reads */ - if (ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) { - /* stop reading */ - if (!(si->flags & SI_FL_WAIT_ROOM)) { - if ((ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) == BF_FULL) - si->flags |= SI_FL_WAIT_ROOM; - conn_data_stop_recv(&si->conn); - 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. The stream socket handler will already - * have updated it if there has been a completed I/O. - */ - si->flags &= ~SI_FL_WAIT_ROOM; - conn_data_want_recv(&si->conn); - if (!(ib->flags & (BF_READ_NOEXP|BF_DONT_READ)) && !tick_isset(ib->rex)) - ib->rex = tick_add_ifset(now_ms, ib->rto); - } - } - - /* Check if we need to close the write side */ - if (!(ob->flags & BF_SHUTW)) { - /* Write not closed, update FD status and timeout for writes */ - if (ob->flags & BF_OUT_EMPTY) { - /* stop writing */ - if (!(si->flags & SI_FL_WAIT_DATA)) { - if ((ob->flags & (BF_FULL|BF_HIJACK|BF_SHUTW_NOW)) == 0) - si->flags |= SI_FL_WAIT_DATA; - conn_data_stop_send(&si->conn); - 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. The stream socket handler will already - * have updated it if there has been a completed I/O. - */ - si->flags &= ~SI_FL_WAIT_DATA; - conn_data_want_send(&si->conn); - if (!tick_isset(ob->wex)) { - ob->wex = tick_add_ifset(now_ms, ob->wto); - 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 or if we have explicitly setup - * independent streams. - */ - ib->rex = tick_add_ifset(now_ms, ib->rto); - } - } - } - } -} - /* This function is used for inter-stream-interface calls. It is called by the * consumer to inform the producer side that it may be interested in checking * for free space in the buffer. Note that it intentionally does not update @@ -889,7 +808,7 @@ static void sock_raw_chk_snd(struct stream_interface *si) /* stream sock operations */ struct sock_ops sock_raw = { - .update = sock_raw_data_finish, + .update = stream_int_update_conn, .shutr = NULL, .shutw = NULL, .chk_rcv = sock_raw_chk_rcv, diff --git a/src/stream_interface.c b/src/stream_interface.c index 5f32933f8..e3816e414 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -552,8 +552,12 @@ int conn_si_send_proxy(struct connection *conn, unsigned int flag) return 0; } -/* function to be called on stream sockets after all I/O handlers */ -void stream_sock_update_conn(struct connection *conn) +/* Callback to be used by connection I/O handlers upon completion. It differs from + * the function below in that it is designed to be called by lower layers after I/O + * events have been completed. It will also try to wake the associated task up if + * an important event requires special handling. + */ +void conn_notify_si(struct connection *conn) { int fd = conn->t.sock.fd; struct stream_interface *si = container_of(conn, struct stream_interface, conn); @@ -651,6 +655,85 @@ void stream_sock_update_conn(struct connection *conn) si->ib->flags &= ~BF_READ_DONTWAIT; } +/* Updates the timers and flags of a stream interface attached to a connection, + * depending on the buffers' flags. It should only be called once after the + * buffer flags have settled down, and before they are cleared. It doesn't + * harm to call it as often as desired (it just slightly hurts performance). + * It is only meant to be called by upper layers after buffer flags have been + * manipulated by analysers. + */ +void stream_int_update_conn(struct stream_interface *si) +{ + struct buffer *ib = si->ib; + struct buffer *ob = si->ob; + + if (si->conn.flags & CO_FL_HANDSHAKE) { + /* a handshake is in progress */ + si->flags &= ~SI_FL_WAIT_DATA; + return; + } + + /* Check if we need to close the read side */ + if (!(ib->flags & BF_SHUTR)) { + /* Read not closed, update FD status and timeout for reads */ + if (ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) { + /* stop reading */ + if (!(si->flags & SI_FL_WAIT_ROOM)) { + if ((ib->flags & (BF_FULL|BF_HIJACK|BF_DONT_READ)) == BF_FULL) + si->flags |= SI_FL_WAIT_ROOM; + conn_data_stop_recv(&si->conn); + 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. The stream socket handler will already + * have updated it if there has been a completed I/O. + */ + si->flags &= ~SI_FL_WAIT_ROOM; + conn_data_want_recv(&si->conn); + if (!(ib->flags & (BF_READ_NOEXP|BF_DONT_READ)) && !tick_isset(ib->rex)) + ib->rex = tick_add_ifset(now_ms, ib->rto); + } + } + + /* Check if we need to close the write side */ + if (!(ob->flags & BF_SHUTW)) { + /* Write not closed, update FD status and timeout for writes */ + if (ob->flags & BF_OUT_EMPTY) { + /* stop writing */ + if (!(si->flags & SI_FL_WAIT_DATA)) { + if ((ob->flags & (BF_FULL|BF_HIJACK|BF_SHUTW_NOW)) == 0) + si->flags |= SI_FL_WAIT_DATA; + conn_data_stop_send(&si->conn); + 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. The stream socket handler will already + * have updated it if there has been a completed I/O. + */ + si->flags &= ~SI_FL_WAIT_DATA; + conn_data_want_send(&si->conn); + if (!tick_isset(ob->wex)) { + ob->wex = tick_add_ifset(now_ms, ob->wto); + 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 or if we have explicitly setup + * independent streams. + */ + ib->rex = tick_add_ifset(now_ms, ib->rto); + } + } + } + } +} + /* * Local variables: * c-indent-level: 8