static int sock_raw_read(struct connection *conn);
static int sock_raw_write(struct connection *conn);
static void sock_raw_data_finish(struct stream_interface *si);
-static void sock_raw_shutr(struct stream_interface *si);
-static void sock_raw_shutw(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);
return 1;
}
-/*
- * 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 closes the file descriptor and marks itself as closed. The buffer flags are
- * updated to reflect the new state. It does also close everything is the SI was
- * marked as being in error state.
- */
-static void sock_raw_shutw(struct stream_interface *si)
-{
- si->ob->flags &= ~BF_SHUTW_NOW;
- if (si->ob->flags & BF_SHUTW)
- return;
- si->ob->flags |= BF_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;
- setsockopt(si_fd(si), SOL_SOCKET, SO_LINGER,
- (struct linger *) &nolinger, sizeof(struct linger));
- }
- else if (!(si->flags & SI_FL_NOHALF)) {
- EV_FD_CLR(si_fd(si), DIR_WR);
- shutdown(si_fd(si), SHUT_WR);
-
- if (!(si->ib->flags & (BF_SHUTR|BF_DONT_READ)))
- return;
- }
-
- /* fall through */
- case SI_ST_CON:
- /* we may have to close a pending connection, and mark the
- * response buffer as shutr
- */
- conn_data_close(&si->conn);
- fd_delete(si_fd(si));
- /* 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 |= BF_SHUTR;
- si->ib->rex = TICK_ETERNITY;
- si->exp = TICK_ETERNITY;
- }
-}
-
-/*
- * 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 closes the file descriptor and 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.
- */
-static void sock_raw_shutr(struct stream_interface *si)
-{
- si->ib->flags &= ~BF_SHUTR_NOW;
- if (si->ib->flags & BF_SHUTR)
- return;
- si->ib->flags |= BF_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 & BF_SHUTW) {
- conn_data_close(&si->conn);
- fd_delete(si_fd(si));
- si->state = SI_ST_DIS;
- si->exp = TICK_ETERNITY;
-
- if (si->release)
- si->release(si);
- return;
- }
- else if (si->flags & SI_FL_NOHALF) {
- /* we want to immediately forward this close to the write side */
- return sock_raw_shutw(si);
- }
- EV_FD_CLR(si_fd(si), DIR_RD);
- return;
-}
-
/*
* This function propagates a null read received on a connection. It updates
* the stream interface. If the stream interface has SI_FL_NOHALF, we also
if (((ob->flags & (BF_SHUTW|BF_HIJACK|BF_AUTO_CLOSE|BF_SHUTW_NOW)) ==
(BF_AUTO_CLOSE|BF_SHUTW_NOW)) &&
(si->state == SI_ST_EST)) {
- sock_raw_shutw(si);
+ si_shutw(si);
goto out_wakeup;
}
/* stream sock operations */
struct sock_ops sock_raw = {
.update = sock_raw_data_finish,
- .shutr = sock_raw_shutr,
- .shutw = sock_raw_shutw,
+ .shutr = NULL,
+ .shutw = NULL,
.chk_rcv = sock_raw_chk_rcv,
.chk_snd = sock_raw_chk_snd,
.read = sock_raw_read,
/* socket functions used when running a stream interface as a task */
static void stream_int_update(struct stream_interface *si);
static void stream_int_update_embedded(struct stream_interface *si);
-static void stream_int_shutr(struct stream_interface *si);
-static void stream_int_shutw(struct stream_interface *si);
static void stream_int_chk_rcv(struct stream_interface *si);
static void stream_int_chk_snd(struct stream_interface *si);
/* socket operations for embedded tasks */
struct sock_ops stream_int_embedded = {
.update = stream_int_update_embedded,
- .shutr = stream_int_shutr,
- .shutw = stream_int_shutw,
+ .shutr = NULL,
+ .shutw = NULL,
.chk_rcv = stream_int_chk_rcv,
.chk_snd = stream_int_chk_snd,
.read = NULL,
/* socket operations for external tasks */
struct sock_ops stream_int_task = {
.update = stream_int_update,
- .shutr = stream_int_shutr,
- .shutw = stream_int_shutw,
+ .shutr = NULL,
+ .shutw = NULL,
.chk_rcv = stream_int_chk_rcv,
.chk_snd = stream_int_chk_snd,
.read = NULL,
si->ib->flags &= ~BF_READ_DONTWAIT;
}
-/* default shutr function for scheduled tasks */
-static void stream_int_shutr(struct stream_interface *si)
+/*
+ * 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)
{
- DPRINTF(stderr, "%s: si=%p, si->state=%d ib->flags=%08x ob->flags=%08x\n",
- __FUNCTION__,
- si, si->state, si->ib->flags, si->ob->flags);
+ struct connection *conn = &si->conn;
si->ib->flags &= ~BF_SHUTR_NOW;
if (si->ib->flags & BF_SHUTR)
- return;
+ return 0;
si->ib->flags |= BF_SHUTR;
si->ib->rex = TICK_ETERNITY;
si->flags &= ~SI_FL_WAIT_ROOM;
if (si->state != SI_ST_EST && si->state != SI_ST_CON)
- return;
+ return 0;
if (si->ob->flags & BF_SHUTW) {
+ conn_data_close(&si->conn);
+ if (conn->ctrl)
+ fd_delete(si_fd(si));
si->state = SI_ST_DIS;
si->exp = TICK_ETERNITY;
- conn_data_close(&si->conn);
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 exist, it must unregister itself once it runs */
- if (!(si->flags & SI_FL_DONT_WAKE) && si->owner)
+ /* 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;
}
-/* default shutw function for scheduled tasks */
-static void stream_int_shutw(struct stream_interface *si)
+/*
+ * 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)
{
- DPRINTF(stderr, "%s: si=%p, si->state=%d ib->flags=%08x ob->flags=%08x\n",
- __FUNCTION__,
- si, si->state, si->ib->flags, si->ob->flags);
+ struct connection *conn = &si->conn;
si->ob->flags &= ~BF_SHUTW_NOW;
if (si->ob->flags & BF_SHUTW)
- return;
+ return 0;
si->ob->flags |= BF_SHUTW;
si->ob->wex = TICK_ETERNITY;
si->flags &= ~SI_FL_WAIT_DATA;
switch (si->state) {
case SI_ST_EST:
- if (!(si->ib->flags & (BF_SHUTR|BF_DONT_READ)))
- break;
+ /* 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_fd(si), SOL_SOCKET, SO_LINGER,
+ (struct linger *) &nolinger, sizeof(struct linger));
+ }
+ /* unclean data-layer shutdown */
+ if (conn->data && conn->data->shutw)
+ conn->data->shutw(conn, 0);
+ } else {
+ /* clean data-layer shutdown */
+ if (conn->data && conn->data->shutw)
+ conn->data->shutw(conn, 1);
+
+ if (!(si->flags & SI_FL_NOHALF)) {
+ /* We shutdown transport layer */
+ if (conn->ctrl)
+ shutdown(si_fd(si), SHUT_WR);
+
+ if (!(si->ib->flags & (BF_SHUTR|BF_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_data_close(&si->conn);
+ if (conn->ctrl)
+ fd_delete(si_fd(si));
+ /* fall through */
case SI_ST_CER:
case SI_ST_QUE:
case SI_ST_TAR:
si->state = SI_ST_DIS;
- /* fall through */
- conn_data_close(&si->conn);
if (si->release)
si->release(si);
default:
si->exp = TICK_ETERNITY;
}
- /* note that if the task exist, it must unregister itself once it runs */
- if (!(si->flags & SI_FL_DONT_WAKE) && si->owner)
+ /* 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;
}
/* default chk_rcv function for scheduled tasks */
if (si->ob->flags & BF_OUT_EMPTY) {
if (((si->ob->flags & (BF_SHUTW|BF_HIJACK|BF_SHUTW_NOW)) == BF_SHUTW_NOW) &&
(si->state == SI_ST_EST))
- si_shutw(si);
+ stream_int_shutw(si);
EV_FD_CLR(fd, DIR_WR);
si->ob->wex = TICK_ETERNITY;
}