From: Willy Tarreau Date: Fri, 4 Mar 2011 21:04:29 +0000 (+0100) Subject: [MEDIUM] stream_interface: store the target pointer and type X-Git-Tag: v1.5-dev8~295 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ac82540c3547624887e2901928f549c84c0c6892;p=thirdparty%2Fhaproxy.git [MEDIUM] stream_interface: store the target pointer and type When doing a connect() on a stream interface, some information is needed from the server and from the backend. In some situations, we don't have a server and only a backend (eg: peers). In other cases, we know we have an applet and we don't want to connect to anything, but we'd still like to have the info about the applet being used. For this, we now store a pointer to the "target" into the stream interface. The target describes what's on the other side before trying to connect. It can be a server, a proxy or an applet for now. Later we'll probably have descriptors for multiple-stage chains so that the final information may still be found. This will help removing many specific cases in the code. It already made it possible to remove the "srv" and "be" parameters to tcpv4_connect_server(). --- diff --git a/include/proto/proto_tcp.h b/include/proto/proto_tcp.h index 3baed1fdda..b871003a45 100644 --- a/include/proto/proto_tcp.h +++ b/include/proto/proto_tcp.h @@ -30,8 +30,7 @@ int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct sockaddr_in *remote); void tcpv4_add_listener(struct listener *listener); void tcpv6_add_listener(struct listener *listener); -int tcpv4_connect_server(struct stream_interface *si, - struct proxy *be, struct server *srv); +int tcpv4_connect_server(struct stream_interface *si); int tcp_inspect_request(struct session *s, struct buffer *req, int an_bit); int tcp_inspect_response(struct session *s, struct buffer *rep, int an_bit); int tcp_persist_rdp_cookie(struct session *s, struct buffer *req, int an_bit); diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index ea7b266a3f..aae25c6373 100644 --- a/include/types/stream_interface.h +++ b/include/types/stream_interface.h @@ -74,12 +74,30 @@ enum { SI_FL_NOLINGER = 0x0080, /* may close without lingering. One-shot. */ }; +/* target types */ +enum { + TARG_TYPE_NONE = 0, /* no target set, pointer is NULL by definition */ + TARG_TYPE_PROXY, /* target is a proxy ; use address with the proxy's settings */ + TARG_TYPE_SERVER, /* target is a server ; use address with server's and its proxy's settings */ + TARG_TYPE_APPLET, /* target is an applet ; use only the applet */ +}; + #define SI_FL_CAP_SPLICE (SI_FL_CAP_SPLTCP) struct server; struct proxy; struct si_applet; +struct target { + int type; + union { + void *v; /* pointer value, for any type */ + struct proxy *p; /* when type is TARG_TYPE_PROXY */ + struct server *s; /* when type is TARG_TYPE_SERVER */ + struct si_applet *a; /* when type is TARG_TYPE_APPLET */ + } ptr; +}; + /* A stream interface has 3 parts : * - the buffer side, which interfaces to the buffers. * - the remote side, which describes the state and address of the other side. @@ -108,10 +126,11 @@ struct stream_interface { void (*shutw)(struct stream_interface *); /* shutw function */ void (*chk_rcv)(struct stream_interface *);/* chk_rcv function */ void (*chk_snd)(struct stream_interface *);/* chk_snd function */ - int (*connect)(struct stream_interface *, struct proxy *, struct server *); /* connect function if any */ + int (*connect)(struct stream_interface *); /* connect function if any */ void (*release)(struct stream_interface *); /* handler to call after the last close() */ /* struct members below are the "remote" part, as seen from the buffer side */ + struct target target; /* the target to connect to (server, proxy, applet, ...) */ int conn_retries; /* number of connect retries left */ int fd; /* file descriptor for a stream driver when known */ struct { diff --git a/src/backend.c b/src/backend.c index 0e1f9255a7..0d5081a2f1 100644 --- a/src/backend.c +++ b/src/backend.c @@ -936,10 +936,17 @@ int connect_server(struct session *s) */ stream_sock_prepare_interface(s->req->cons); s->req->cons->connect = tcpv4_connect_server; + if (s->srv) { + s->req->cons->target.type = TARG_TYPE_SERVER; + s->req->cons->target.ptr.s = s->srv; + } else { + s->req->cons->target.type = TARG_TYPE_PROXY; + s->req->cons->target.ptr.p = s->be; + } assign_tproxy_address(s); - err = s->req->cons->connect(s->req->cons, s->be, s->srv); + err = s->req->cons->connect(s->req->cons); if (err != SN_ERR_NONE) return err; diff --git a/src/peers.c b/src/peers.c index 6c754652a2..5e3b353e35 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1155,6 +1155,10 @@ struct session *peer_session_create(struct peer *peer, struct peer_session *ps) s->si[0].state = s->si[0].prev_state = SI_ST_EST; s->si[0].err_type = SI_ET_NONE; s->si[0].err_loc = NULL; + s->si[0].connect = NULL; + s->si[0].applet.handler = NULL; + s->si[0].target.ptr.v = NULL; + s->si[0].target.type = TARG_TYPE_NONE; s->si[0].exp = TICK_ETERNITY; s->si[0].flags = SI_FL_NONE; if (s->fe->options2 & PR_O2_INDEPSTR) @@ -1172,6 +1176,9 @@ struct session *peer_session_create(struct peer *peer, struct peer_session *ps) s->si[1].err_type = SI_ET_NONE; s->si[1].err_loc = NULL; s->si[1].connect = tcpv4_connect_server; + s->si[1].applet.handler = NULL; + s->si[1].target.ptr.p = s->be; + s->si[1].target.type = TARG_TYPE_PROXY; s->si[1].exp = TICK_ETERNITY; s->si[1].flags = SI_FL_NONE; if (s->be->options2 & PR_O2_INDEPSTR) diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 174d661db8..2d79e22d26 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -181,10 +181,12 @@ int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct socka /* - * This function initiates a connection to the server assigned to this session - * (s->srv, si->addr.s.to). A source address may be pointed to by si->addr.s.from. - * Note that this is only used in case of transparent proxying. Normal source bind - * addresses are still determined locally (due to the possible need of a source port). + * This function initiates a connection to the target assigned to this session + * (si->{target,addr.s.to}). A source address may be pointed to by si->addr.s.from + * in case of transparent proxying. Normal source bind addresses are still + * determined locally (due to the possible need of a source port). + * si->target may point either to a valid server or to a backend, depending + * on si->target.type. Only TARG_TYPE_PROXY and TARG_TYPE_SERVER are supported. * * It can return one of : * - SN_ERR_NONE if everything's OK @@ -196,9 +198,24 @@ int tcpv4_bind_socket(int fd, int flags, struct sockaddr_in *local, struct socka * Additionnally, in the case of SN_ERR_RESOURCE, an emergency log will be emitted. */ -int tcpv4_connect_server(struct stream_interface *si, struct proxy *be, struct server *srv) +int tcpv4_connect_server(struct stream_interface *si) { int fd; + struct server *srv; + struct proxy *be; + + switch (si->target.type) { + case TARG_TYPE_PROXY: + be = si->target.ptr.p; + srv = NULL; + break; + case TARG_TYPE_SERVER: + srv = si->target.ptr.s; + be = srv->proxy; + break; + default: + return SN_ERR_INTERNAL; + } if ((fd = si->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { qfprintf(stderr, "Cannot get a server socket.\n"); diff --git a/src/session.c b/src/session.c index fdf8043ec3..87f74641c0 100644 --- a/src/session.c +++ b/src/session.c @@ -169,6 +169,8 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) s->si[0].connect = NULL; s->si[0].applet.handler = NULL; s->si[0].release = NULL; + s->si[0].target.type = TARG_TYPE_NONE; + s->si[0].target.ptr.v = NULL; s->si[0].exp = TICK_ETERNITY; s->si[0].flags = SI_FL_NONE; @@ -192,6 +194,8 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) s->si[1].connect = NULL; s->si[1].applet.handler = NULL; s->si[1].release = NULL; + s->si[1].target.type = TARG_TYPE_NONE; + s->si[1].target.ptr.v = NULL; s->si[1].shutr = stream_int_shutr; s->si[1].shutw = stream_int_shutw; s->si[1].exp = TICK_ETERNITY; diff --git a/src/stream_interface.c b/src/stream_interface.c index 71fc864a04..db13973929 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -313,6 +313,8 @@ struct task *stream_int_register_handler(struct stream_interface *si, struct si_ si->chk_rcv = stream_int_chk_rcv; si->chk_snd = stream_int_chk_snd; si->connect = NULL; + si->target.type = TARG_TYPE_APPLET; + si->target.ptr.a = app; si->applet.handler = app; si->release = NULL; si->flags |= SI_FL_WAIT_DATA; @@ -337,6 +339,8 @@ struct task *stream_int_register_handler_task(struct stream_interface *si, si->chk_rcv = stream_int_chk_rcv; si->chk_snd = stream_int_chk_snd; si->connect = NULL; + si->target.type = TARG_TYPE_NONE; + si->target.ptr.v = NULL; si->applet.handler = NULL; /* not used when running as an external task */ si->release = NULL; si->flags |= SI_FL_WAIT_DATA; @@ -366,6 +370,8 @@ void stream_int_unregister_handler(struct stream_interface *si) si->applet.handler = NULL; si->release = NULL; si->owner = NULL; + si->target.type = TARG_TYPE_NONE; + si->target.ptr.v = NULL; } /*