MEDIUM: session: add a pointer to a struct task in the session
The session may need to enforce a timeout when waiting for a handshake. Till now we used a trick to avoid allocating a pointer, we used to set the connection's owner to the task and set the task's context to the session, so that it was possible to circle between all of them. The problem is that we'll really need to pass the pointer to the session to the upper layers during initialization and that the only place to store it is conn->owner, which is squatted for this trick. So this patch moves the struct task* into the session where it should always have been and ensures conn->owner points to the session until the data layer is properly initialized.
This commit is contained in:
parent
ca3610251b
commit
0b74eae1f1
|
@ -299,7 +299,7 @@ struct connection {
|
|||
const struct xprt_ops *xprt; /* operations at the transport layer */
|
||||
const struct data_cb *data; /* data layer callbacks. Must be set before xprt->init() */
|
||||
void *xprt_ctx; /* general purpose pointer, initialized to NULL */
|
||||
void *owner; /* pointer to upper layer's entity (eg: stream interface) */
|
||||
void *owner; /* pointer to upper layer's entity (eg: session, stream interface) */
|
||||
int xprt_st; /* transport layer state, initialized to zero */
|
||||
union conn_handle handle; /* connection handle at the socket layer */
|
||||
enum obj_type *target; /* the target to connect to (server, proxy, applet, ...) */
|
||||
|
|
|
@ -46,6 +46,7 @@ struct session {
|
|||
struct timeval tv_accept; /* date of the session's accept() in internal date (monotonic) */
|
||||
struct stkctr stkctr[MAX_SESS_STKCTR]; /* stick counters for tcp-connection */
|
||||
struct vars vars; /* list of variables for the session scope. */
|
||||
struct task *task; /* handshake timeout processing */
|
||||
};
|
||||
|
||||
#endif /* _TYPES_SESSION_H */
|
||||
|
|
|
@ -52,6 +52,7 @@ struct session *session_new(struct proxy *fe, struct listener *li, enum obj_type
|
|||
sess->tv_accept = now; /* corrected date for internal use */
|
||||
memset(sess->stkctr, 0, sizeof(sess->stkctr));
|
||||
vars_init(&sess->vars, SCOPE_SESS);
|
||||
sess->task = NULL;
|
||||
}
|
||||
return sess;
|
||||
}
|
||||
|
@ -102,7 +103,8 @@ static void session_count_new(struct session *sess)
|
|||
* returns a positive value upon success, 0 if the connection can be ignored,
|
||||
* or a negative value upon critical failure. The accepted file descriptor is
|
||||
* closed if we return <= 0. If no handshake is needed, it immediately tries
|
||||
* to instanciate a new stream.
|
||||
* to instanciate a new stream. The created connection's owner points to the
|
||||
* new session until the upper layers are created.
|
||||
*/
|
||||
int session_accept_fd(struct listener *l, int cfd, struct sockaddr_storage *addr)
|
||||
{
|
||||
|
@ -148,6 +150,8 @@ int session_accept_fd(struct listener *l, int cfd, struct sockaddr_storage *addr
|
|||
if (!sess)
|
||||
goto out_free_conn;
|
||||
|
||||
conn_set_owner(cli_conn, sess);
|
||||
|
||||
p->feconn++;
|
||||
/* This session was accepted, count it now */
|
||||
if (p->feconn > p->fe_counters.conn_max)
|
||||
|
@ -222,32 +226,33 @@ int session_accept_fd(struct listener *l, int cfd, struct sockaddr_storage *addr
|
|||
if (global.tune.client_rcvbuf)
|
||||
setsockopt(cfd, SOL_SOCKET, SO_RCVBUF, &global.tune.client_rcvbuf, sizeof(global.tune.client_rcvbuf));
|
||||
|
||||
/* OK, now either we have a pending handshake to execute with and
|
||||
* then we must return to the I/O layer, or we can proceed with the
|
||||
* end of the stream initialization. In case of handshake, we also
|
||||
* set the I/O timeout to the frontend's client timeout.
|
||||
/* OK, now either we have a pending handshake to execute with and then
|
||||
* we must return to the I/O layer, or we can proceed with the end of
|
||||
* the stream initialization. In case of handshake, we also set the I/O
|
||||
* timeout to the frontend's client timeout and register a task in the
|
||||
* session for this purpose. The connection's owner is left to the
|
||||
* session during this period.
|
||||
*
|
||||
* At this point we set the relation between sess/task/conn this way :
|
||||
*
|
||||
* orig -- sess <-- context
|
||||
* | |
|
||||
* v |
|
||||
* conn -- owner ---> task
|
||||
* +----------------- task
|
||||
* | |
|
||||
* orig -- sess <-- context |
|
||||
* | ^ | |
|
||||
* v | | |
|
||||
* conn -- owner ---> task <-----+
|
||||
*/
|
||||
if (cli_conn->flags & CO_FL_HANDSHAKE) {
|
||||
struct task *t;
|
||||
|
||||
if (unlikely((t = task_new()) == NULL))
|
||||
if (unlikely((sess->task = task_new()) == NULL))
|
||||
goto out_free_sess;
|
||||
|
||||
conn_set_owner(cli_conn, t);
|
||||
conn_set_xprt_done_cb(cli_conn, conn_complete_session);
|
||||
|
||||
t->context = sess;
|
||||
t->nice = l->nice;
|
||||
t->process = session_expire_embryonic;
|
||||
t->expire = tick_add_ifset(now_ms, p->timeout.client);
|
||||
task_queue(t);
|
||||
sess->task->context = sess;
|
||||
sess->task->nice = l->nice;
|
||||
sess->task->process = session_expire_embryonic;
|
||||
sess->task->expire = tick_add_ifset(now_ms, p->timeout.client);
|
||||
task_queue(sess->task);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -327,10 +332,11 @@ static void session_prepare_log_prefix(struct session *sess)
|
|||
* 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, struct task *task)
|
||||
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;
|
||||
|
||||
|
@ -401,7 +407,7 @@ static struct task *session_expire_embryonic(struct task *t)
|
|||
if (!(t->state & TASK_WOKEN_TIMER))
|
||||
return t;
|
||||
|
||||
session_kill_embryonic(sess, t);
|
||||
session_kill_embryonic(sess);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -410,8 +416,7 @@ static struct task *session_expire_embryonic(struct task *t)
|
|||
*/
|
||||
static int conn_complete_session(struct connection *conn)
|
||||
{
|
||||
struct task *task = conn->owner;
|
||||
struct session *sess = task->context;
|
||||
struct session *sess = conn->owner;
|
||||
struct stream *strm;
|
||||
|
||||
conn_clear_xprt_done_cb(conn);
|
||||
|
@ -437,12 +442,13 @@ static int conn_complete_session(struct connection *conn)
|
|||
task_wakeup(strm->task, TASK_WOKEN_INIT);
|
||||
|
||||
/* the embryonic session's task is not needed anymore */
|
||||
task_delete(task);
|
||||
task_free(task);
|
||||
task_delete(sess->task);
|
||||
task_free(sess->task);
|
||||
sess->task = NULL;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
session_kill_embryonic(sess, task);
|
||||
session_kill_embryonic(sess);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue