/* * This function performs a shutdown-read on a stream interface attached to * a connection in a connected or init state (it does nothing for other * states). It either shuts the read side or marks itself as closed. The buffer * flags are updated to reflect the new state. If the stream interface has * SI_FL_NOHALF, we also forward the close to the write side. If a control * layer is defined, then it is supposed to be a socket layer and file * descriptors are then shutdown or closed accordingly. The function * automatically disables polling if needed. */ static void stream_int_shutr_conn(struct stream_interface *si) { struct connection *conn = __objt_conn(si->end); si->ib->flags &= ~CF_SHUTR_NOW; if (si->ib->flags & CF_SHUTR) return; si->ib->flags |= CF_SHUTR; si->ib->rex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_ROOM; if (si->state != SI_ST_EST && si->state != SI_ST_CON) return; if (si->ob->flags & CF_SHUTW) { conn_full_close(conn); si->state = SI_ST_DIS; si->exp = TICK_ETERNITY; } else if (si->flags & SI_FL_NOHALF) { /* we want to immediately forward this close to the write side */ return stream_int_shutw_conn(si); } else if (conn->ctrl) { /* we want the caller to disable polling on this FD */ conn_data_stop_recv(conn); } }
/* * This function propagates a null read received on a socket-based connection. * It updates the stream interface. If the stream interface has SI_FL_NOHALF, * the close is also forwarded to the write side as an abort. This function is * still socket-specific as it handles a setsockopt() call to set the SO_LINGER * state on the socket. */ void stream_sock_read0(struct stream_interface *si) { si->ib->flags &= ~CF_SHUTR_NOW; if (si->ib->flags & CF_SHUTR) return; si->ib->flags |= CF_SHUTR; si->ib->rex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_ROOM; if (si->state != SI_ST_EST && si->state != SI_ST_CON) return; if (si->ob->flags & CF_SHUTW) goto do_close; if (si->flags & SI_FL_NOHALF) { /* we want to immediately forward this close to the write side */ if (si->flags & SI_FL_NOLINGER) { si->flags &= ~SI_FL_NOLINGER; setsockopt(si->conn->t.sock.fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger)); } /* force flag on ssl to keep session in cache */ if (si->conn->xprt->shutw) si->conn->xprt->shutw(si->conn, 0); goto do_close; } /* otherwise that's just a normal read shutdown */ __conn_data_stop_recv(si->conn); return; do_close: /* OK we completely close the socket here just as if we went through si_shut[rw]() */ conn_full_close(si->conn); si->ib->flags &= ~CF_SHUTR_NOW; si->ib->flags |= CF_SHUTR; si->ib->rex = TICK_ETERNITY; si->ob->flags &= ~CF_SHUTW_NOW; si->ob->flags |= CF_SHUTW; si->ob->wex = TICK_ETERNITY; si->flags &= ~(SI_FL_WAIT_DATA | SI_FL_WAIT_ROOM); si->state = SI_ST_DIS; si->exp = TICK_ETERNITY; if (si->release) si->release(si); return; }
/* * This function propagates a null read received on a socket-based connection. * It updates the stream interface. If the stream interface has SI_FL_NOHALF, * the close is also forwarded to the write side as an abort. This function is * still socket-specific as it handles a setsockopt() call to set the SO_LINGER * state on the socket. */ void stream_sock_read0(struct stream_interface *si) { struct connection *conn = __objt_conn(si->end); si->ib->flags &= ~CF_SHUTR_NOW; if (si->ib->flags & CF_SHUTR) return; si->ib->flags |= CF_SHUTR; si->ib->rex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_ROOM; if (si->state != SI_ST_EST && si->state != SI_ST_CON) return; if (si->ob->flags & CF_SHUTW) goto do_close; if (si->flags & SI_FL_NOHALF) { /* we want to immediately forward this close to the write side */ /* force flag on ssl to keep session in cache */ if (conn->xprt->shutw) conn->xprt->shutw(conn, 0); goto do_close; } /* otherwise that's just a normal read shutdown */ if (conn_ctrl_ready(conn)) fdtab[conn->t.sock.fd].linger_risk = 0; __conn_data_stop_recv(conn); return; do_close: /* OK we completely close the socket here just as if we went through si_shut[rw]() */ conn_full_close(conn); si->ib->flags &= ~CF_SHUTR_NOW; si->ib->flags |= CF_SHUTR; si->ib->rex = TICK_ETERNITY; si->ob->flags &= ~CF_SHUTW_NOW; si->ob->flags |= CF_SHUTW; si->ob->wex = TICK_ETERNITY; si->flags &= ~(SI_FL_WAIT_DATA | SI_FL_WAIT_ROOM); si->state = SI_ST_DIS; si->exp = TICK_ETERNITY; return; }
/* * This function propagates a null read received on a socket-based connection. * It updates the stream interface. If the stream interface has SI_FL_NOHALF, * the close is also forwarded to the write side as an abort. */ void stream_sock_read0(struct stream_interface *si) { struct connection *conn = __objt_conn(si->end); struct channel *ic = si_ic(si); struct channel *oc = si_oc(si); HA_DBG("stream_sock_read0\n"); ic->flags &= ~CF_SHUTR_NOW; if (ic->flags & CF_SHUTR) return; ic->flags |= CF_SHUTR; ic->rex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_ROOM; if (si->state != SI_ST_EST && si->state != SI_ST_CON) return; if (oc->flags & CF_SHUTW) goto do_close; if (si->flags & SI_FL_NOHALF) { /* we want to immediately forward this close to the write side */ /* force flag on ssl to keep stream in cache */ conn_data_shutw_hard(conn); goto do_close; } /* otherwise that's just a normal read shutdown */ __conn_data_stop_recv(conn); return; do_close: /* OK we completely close the socket here just as if we went through si_shut[rw]() */ conn_full_close(conn); ic->flags &= ~CF_SHUTR_NOW; ic->flags |= CF_SHUTR; ic->rex = TICK_ETERNITY; oc->flags &= ~CF_SHUTW_NOW; oc->flags |= CF_SHUTW; oc->wex = TICK_ETERNITY; si->flags &= ~(SI_FL_WAIT_DATA | SI_FL_WAIT_ROOM); si->state = SI_ST_DIS; si->exp = TICK_ETERNITY; return; }
/* This function kills an existing embryonic session. It stops the connection's * transport layer, releases assigned resources, resumes the listener if it was * disabled and finally kills the file descriptor. This function requires that * sess->origin points to the incoming connection. */ static void session_kill_embryonic(struct session *sess) { int level = LOG_INFO; struct connection *conn = __objt_conn(sess->origin); struct task *task = sess->task; unsigned int log = sess->fe->to_log; const char *err_msg; if (sess->fe->options2 & PR_O2_LOGERRORS) level = LOG_ERR; if (log && (sess->fe->options & PR_O_NULLNOLOG)) { /* with "option dontlognull", we don't log connections with no transfer */ if (!conn->err_code || conn->err_code == CO_ER_PRX_EMPTY || conn->err_code == CO_ER_PRX_ABORT || conn->err_code == CO_ER_CIP_EMPTY || conn->err_code == CO_ER_CIP_ABORT || conn->err_code == CO_ER_SSL_EMPTY || conn->err_code == CO_ER_SSL_ABORT) log = 0; } if (log) { if (!conn->err_code && (task->state & TASK_WOKEN_TIMER)) { if (conn->flags & CO_FL_ACCEPT_PROXY) conn->err_code = CO_ER_PRX_TIMEOUT; else if (conn->flags & CO_FL_ACCEPT_CIP) conn->err_code = CO_ER_CIP_TIMEOUT; else if (conn->flags & CO_FL_SSL_WAIT_HS) conn->err_code = CO_ER_SSL_TIMEOUT; } session_prepare_log_prefix(sess); err_msg = conn_err_code_str(conn); if (err_msg) send_log(sess->fe, level, "%s: %s\n", trash.str, err_msg); else send_log(sess->fe, level, "%s: unknown connection error (code=%d flags=%08x)\n", trash.str, conn->err_code, conn->flags); } /* kill the connection now */ conn_stop_tracking(conn); conn_full_close(conn); conn_free(conn); task_delete(task); task_free(task); session_free(sess); }
/* * 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 marks itself as closed. The buffer flags are updated to reflect the * new state. If the stream interface has SI_FL_NOHALF, we also forward the * close to the write side. If a control layer is defined, then it is supposed * to be a socket layer and file descriptors are then shutdown or closed * accordingly. If no control layer is defined, then the SI is supposed to be * an embedded one and the owner task is woken up if it exists. The function * does not disable polling on the FD by itself, it returns non-zero instead * if the caller needs to do so (except when the FD is deleted where this is * implicit). */ int stream_int_shutr(struct stream_interface *si) { struct connection *conn = si->conn; si->ib->flags &= ~CF_SHUTR_NOW; if (si->ib->flags & CF_SHUTR) return 0; si->ib->flags |= CF_SHUTR; si->ib->rex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_ROOM; if (si->state != SI_ST_EST && si->state != SI_ST_CON) return 0; if (si->ob->flags & CF_SHUTW) { conn_full_close(si->conn); si->state = SI_ST_DIS; si->exp = TICK_ETERNITY; if (si->release) si->release(si); } else if (si->flags & SI_FL_NOHALF) { /* we want to immediately forward this close to the write side */ return stream_int_shutw(si); } else if (conn->ctrl) { /* we want the caller to disable polling on this FD */ return 1; } /* note that if the task exists, it must unregister itself once it runs */ if (!conn->ctrl && !(si->flags & SI_FL_DONT_WAKE) && si->owner) task_wakeup(si->owner, TASK_WOKEN_IO); return 0; }
/* * This function performs a shutdown-write on a stream interface attached to * a connection in a connected or init state (it does nothing for other * states). It either shuts the write side or marks itself as closed. The * buffer flags are updated to reflect the new state. It does also close * everything if the SI was marked as being in error state. If there is a * data-layer shutdown, it is called. If a control layer is defined, then it is * supposed to be a socket layer and file descriptors are then shutdown or * closed accordingly. The function automatically disables polling if needed. * Note: at the moment, we continue to check conn->ctrl eventhough we *know* it * is valid. This will help selecting the proper shutdown() and setsockopt() * calls if/when we implement remote sockets later. */ static void stream_int_shutw_conn(struct stream_interface *si) { struct connection *conn = __objt_conn(si->end); si->ob->flags &= ~CF_SHUTW_NOW; if (si->ob->flags & CF_SHUTW) return; si->ob->flags |= CF_SHUTW; si->ob->wex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_DATA; switch (si->state) { case SI_ST_EST: /* we have to shut before closing, otherwise some short messages * may never leave the system, especially when there are remaining * unread data in the socket input buffer, or when nolinger is set. * However, if SI_FL_NOLINGER is explicitly set, we know there is * no risk so we close both sides immediately. */ if (si->flags & SI_FL_ERR) { /* quick close, the socket is alredy shut anyway */ } else if (si->flags & SI_FL_NOLINGER) { /* unclean data-layer shutdown */ if (conn->xprt && conn->xprt->shutw) conn->xprt->shutw(conn, 0); } else { /* clean data-layer shutdown */ if (conn->xprt && conn->xprt->shutw) conn->xprt->shutw(conn, 1); /* If the stream interface is configured to disable half-open * connections, we'll skip the shutdown(), but only if the * read size is already closed. Otherwise we can't support * closed write with pending read (eg: abortonclose while * waiting for the server). */ if (!(si->flags & SI_FL_NOHALF) || !(si->ib->flags & (CF_SHUTR|CF_DONT_READ))) { /* We shutdown transport layer */ if (conn_ctrl_ready(conn)) shutdown(conn->t.sock.fd, SHUT_WR); if (!(si->ib->flags & (CF_SHUTR|CF_DONT_READ))) { /* OK just a shutw, but we want the caller * to disable polling on this FD if exists. */ if (conn->ctrl) conn_data_stop_send(conn); return; } } } /* fall through */ case SI_ST_CON: /* we may have to close a pending connection, and mark the * response buffer as shutr */ conn_full_close(conn); /* fall through */ case SI_ST_CER: case SI_ST_QUE: case SI_ST_TAR: si->state = SI_ST_DIS; /* fall through */ default: si->flags &= ~(SI_FL_WAIT_ROOM | SI_FL_NOLINGER); si->ib->flags &= ~CF_SHUTR_NOW; si->ib->flags |= CF_SHUTR; si->ib->rex = TICK_ETERNITY; si->exp = TICK_ETERNITY; } }
/* * This function performs a shutdown-write on a stream interface in a connected or * init state (it does nothing for other states). It either shuts the write side * or marks itself as closed. The buffer flags are updated to reflect the new state. * It does also close everything if the SI was marked as being in error state. If * there is a data-layer shutdown, it is called. If a control layer is defined, then * it is supposed to be a socket layer and file descriptors are then shutdown or * closed accordingly. If no control layer is defined, then the SI is supposed to * be an embedded one and the owner task is woken up if it exists. The function * does not disable polling on the FD by itself, it returns non-zero instead if * the caller needs to do so (except when the FD is deleted where this is implicit). */ int stream_int_shutw(struct stream_interface *si) { struct connection *conn = si->conn; si->ob->flags &= ~CF_SHUTW_NOW; if (si->ob->flags & CF_SHUTW) return 0; si->ob->flags |= CF_SHUTW; si->ob->wex = TICK_ETERNITY; si->flags &= ~SI_FL_WAIT_DATA; switch (si->state) { case SI_ST_EST: /* we have to shut before closing, otherwise some short messages * may never leave the system, especially when there are remaining * unread data in the socket input buffer, or when nolinger is set. * However, if SI_FL_NOLINGER is explicitly set, we know there is * no risk so we close both sides immediately. */ 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) { si->flags &= ~SI_FL_NOLINGER; if (conn->ctrl) { setsockopt(si->conn->t.sock.fd, SOL_SOCKET, SO_LINGER, (struct linger *) &nolinger, sizeof(struct linger)); } /* unclean data-layer shutdown */ if (conn->xprt && conn->xprt->shutw) conn->xprt->shutw(conn, 0); } else { /* clean data-layer shutdown */ if (conn->xprt && conn->xprt->shutw) conn->xprt->shutw(conn, 1); if (!(si->flags & SI_FL_NOHALF)) { /* We shutdown transport layer */ if (conn->ctrl) shutdown(si->conn->t.sock.fd, SHUT_WR); if (!(si->ib->flags & (CF_SHUTR|CF_DONT_READ))) { /* OK just a shutw, but we want the caller * to disable polling on this FD if exists. */ return !!conn->ctrl; } } } /* fall through */ case SI_ST_CON: /* we may have to close a pending connection, and mark the * response buffer as shutr */ conn_full_close(si->conn); /* fall through */ case SI_ST_CER: case SI_ST_QUE: case SI_ST_TAR: si->state = SI_ST_DIS; if (si->release) si->release(si); default: si->flags &= ~SI_FL_WAIT_ROOM; si->ib->flags |= CF_SHUTR; si->ib->rex = TICK_ETERNITY; si->exp = TICK_ETERNITY; } /* note that if the task exists, it must unregister itself once it runs */ if (!conn->ctrl && !(si->flags & SI_FL_DONT_WAKE) && si->owner) task_wakeup(si->owner, TASK_WOKEN_IO); return 0; }