]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[MEDIUM] stream_interface: store the target pointer and type
authorWilly Tarreau <w@1wt.eu>
Fri, 4 Mar 2011 21:04:29 +0000 (22:04 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 10 Mar 2011 22:32:15 +0000 (23:32 +0100)
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().

include/proto/proto_tcp.h
include/types/stream_interface.h
src/backend.c
src/peers.c
src/proto_tcp.c
src/session.c
src/stream_interface.c

index 3baed1fdda0be79e156e47b1dc9934e0c6d25dff..b871003a45dd6ec2db33c47930255d6b2ff17319 100644 (file)
@@ -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);
index ea7b266a3fbc266efdf068e69b5d729091622c71..aae25c63732441b636fc740095eacc935b1b2741 100644 (file)
@@ -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 {
index 0e1f9255a78bb6a6856f580576f363febefaa15e..0d5081a2f11500e56d58a0f311bc9d2325c19612 100644 (file)
@@ -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;
index 6c754652a2b14745e0a91e82bb656f94299ad6d7..5e3b353e355c5983e5767f73a22c2b280b1ef9a8 100644 (file)
@@ -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)
index 174d661db8f5c08c6e00eb38bc90b6705e617e44..2d79e22d26135dc993e8af8db3a4216531151f6b 100644 (file)
@@ -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");
index fdf8043ec3ea046d0e843f35bb7c411036fb7393..87f74641c09ee74a5cc56f406393f89e18bc03b0 100644 (file)
@@ -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;
index 71fc864a047e1025fb3c98dd1e5f11f8b369da74..db13973929608eb8264e0702f40e29741965ab46 100644 (file)
@@ -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;
 }
 
 /*