[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().
This commit is contained in:
Willy Tarreau 2011-03-04 22:04:29 +01:00
parent f153686a71
commit ac82540c35
7 changed files with 68 additions and 9 deletions

View 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);

View 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 {

View 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;

View 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)

View 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");

View 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;

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