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);
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.
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 {
*/
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;
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)
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)
/*
- * 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
* 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");
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;
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;
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;
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;
si->applet.handler = NULL;
si->release = NULL;
si->owner = NULL;
+ si->target.type = TARG_TYPE_NONE;
+ si->target.ptr.v = NULL;
}
/*