From: Willy Tarreau Date: Tue, 2 Oct 2012 23:39:48 +0000 (+0200) Subject: MEDIUM: connection: use a generic data-layer init() callback X-Git-Tag: v1.5-dev13~215 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=071e137ec23402b0c4c3cb1a5967c483f34a9270;p=thirdparty%2Fhaproxy.git MEDIUM: connection: use a generic data-layer init() callback The generic data-layer init callback is now used after the transport layer is complete and before calling the data layer recv/send callbacks. This allows the session to switch from the embryonic session data layer to the complete stream interface data layer, by making conn_session_complete() the data layer's init callback. It sill looks awkwards that the init() callback must be used opon error, but except by adding yet another one, it does not seem to be mergeable into another function (eg: it should probably not be merged with ->wake to avoid unneeded calls during the handshake, though semantically that would make sense). --- diff --git a/include/proto/session.h b/include/proto/session.h index b9eb447717..049fc931c6 100644 --- a/include/proto/session.h +++ b/include/proto/session.h @@ -47,7 +47,6 @@ int parse_track_counters(char **args, int *arg, int section_type, struct proxy *curpx, struct track_ctr_prm *prm, struct proxy *defpx, char **err); -int conn_session_complete(struct connection *conn, int flag); /* Remove the refcount from the session to the tracked counters, and clear the * pointer to ensure this is only performed once. The caller is responsible for diff --git a/include/types/connection.h b/include/types/connection.h index ddc610e2b2..60caa4dc8c 100644 --- a/include/types/connection.h +++ b/include/types/connection.h @@ -86,7 +86,7 @@ enum { /* below we have all handshake flags grouped into one */ CO_FL_HANDSHAKE = CO_FL_SI_SEND_PROXY | CO_FL_SSL_WAIT_HS | CO_FL_ACCEPT_PROXY, - CO_FL_INIT_SESS = 0x00000800, /* initialize a session before using data */ + CO_FL_INIT_DATA = 0x00000800, /* initialize the data layer before using it */ /* when any of these flags is set, polling is defined by socket-layer * operations, as opposed to data-layer. Transport is explicitly not diff --git a/src/connection.c b/src/connection.c index 007d3b1bed..d1813f9675 100644 --- a/src/connection.c +++ b/src/connection.c @@ -67,12 +67,12 @@ int conn_fd_handler(int fd) if (!(conn->flags & CO_FL_POLL_SOCK)) __conn_sock_stop_both(conn); - /* Maybe we need to finish initializing an incoming session. The - * function may fail and cause the connection to be destroyed, thus + /* The data layer might not be ready yet (eg: when using embryonic + * sessions). If we're about to move data, we must initialize it first. + * The function may fail and cause the connection to be destroyed, thus * we must not use it anymore and should immediately leave instead. */ - if ((conn->flags & CO_FL_INIT_SESS) && - conn_session_complete(conn, CO_FL_INIT_SESS) < 0) + if ((conn->flags & CO_FL_INIT_DATA) && conn->data->init(conn) < 0) return 0; /* The data transfer starts here and stops on error and handshakes */ @@ -103,10 +103,12 @@ int conn_fd_handler(int fd) } leave: - /* we may need to release the connection which is an embryonic session */ - if ((conn->flags & (CO_FL_ERROR|CO_FL_INIT_SESS)) == (CO_FL_ERROR|CO_FL_INIT_SESS)) { - conn->flags |= CO_FL_ERROR; - conn_session_complete(conn, CO_FL_INIT_SESS); + /* we may need to release the connection which is an embryonic session + * in case of failure. For this we use the init callback which will + * detect the error and clean everything up. + */ + if ((conn->flags & (CO_FL_ERROR|CO_FL_INIT_DATA)) == (CO_FL_ERROR|CO_FL_INIT_DATA)) { + conn->data->init(conn); return 0; } diff --git a/src/session.c b/src/session.c index 62099213df..a32ec6b09d 100644 --- a/src/session.c +++ b/src/session.c @@ -50,6 +50,7 @@ struct pool_head *pool2_session; struct list sessions; +static int conn_session_complete(struct connection *conn); static struct task *expire_mini_session(struct task *t); int session_complete(struct session *s); @@ -58,7 +59,7 @@ struct data_cb sess_conn_cb = { .recv = NULL, .send = NULL, .wake = NULL, - .init = NULL, + .init = conn_session_complete, }; /* This function is called from the protocol layer accept() in order to @@ -193,7 +194,7 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) t->process = expire_mini_session; t->expire = tick_add_ifset(now_ms, p->timeout.client); task_queue(t); - s->si[0].conn.flags |= CO_FL_INIT_SESS; + s->si[0].conn.flags |= CO_FL_INIT_DATA; return 1; } @@ -266,12 +267,12 @@ static void kill_mini_session(struct session *s) /* Finish initializing a session from a connection, or kills it if the * connection shows and error. Returns <0 if the connection was killed. */ -int conn_session_complete(struct connection *conn, int flag) +static int conn_session_complete(struct connection *conn) { struct session *s = conn->owner; if (!(conn->flags & CO_FL_ERROR) && (session_complete(s) > 0)) { - conn->flags &= ~flag; + conn->flags &= ~CO_FL_INIT_DATA; return 0; }