コード例 #1
0
/*
 * 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);
	}
}
コード例 #2
0
ファイル: stream_interface.c プロジェクト: btorch/haproxy
/*
 * 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;
}
コード例 #3
0
/*
 * 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;
}
コード例 #4
0
/*
 * 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;
}
コード例 #5
0
ファイル: session.c プロジェクト: spinpunch/haproxy-1.8
/* 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);
}
コード例 #6
0
ファイル: stream_interface.c プロジェクト: btorch/haproxy
/*
 * 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;
}
コード例 #7
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;
	}
}
コード例 #8
0
ファイル: stream_interface.c プロジェクト: btorch/haproxy
/*
 * 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;
}