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; } /*