diff --git a/include/types/connection.h b/include/types/connection.h index 748af8de6..ce43b734e 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -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, ...) */ diff --git a/include/types/session.h b/include/types/session.h index 35a17e191..0757c70c8 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -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 */ diff --git a/src/session.c b/src/session.c index ea4e020a6..69ca2cbd0 100644 --- a/src/session.c +++ b/src/session.c @@ -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; }