*/
int protocol_enable_all(void);
+/* returns the protocol associated to family <family> or NULL if not found */
+struct protocol *protocol_by_family(int family);
#endif /* _PROTO_PROTOCOLS_H */
return;
}
#endif
- if (si->get_dst &&
- si->get_dst(si->fd, (struct sockaddr *)&si->addr.to, &namelen) != -1)
+ if (si->proto->get_dst &&
+ si->proto->get_dst(si->fd, (struct sockaddr *)&si->addr.to, &namelen) != -1)
si->flags |= SI_FL_TO_SET;
return;
}
return;
namelen = sizeof(si->addr.to);
- if (si->get_src &&
- si->get_src(si->fd, (struct sockaddr *)&si->addr.from, &namelen) != -1)
+ if (si->proto->get_src &&
+ si->proto->get_src(si->fd, (struct sockaddr *)&si->addr.from, &namelen) != -1)
si->flags |= SI_FL_FROM_SET;
return;
}
} conf; /* config information */
time_t last_change;
struct sockaddr_storage addr; /* peer address */
+ struct protocol *proto; /* peer address protocol */
struct peer *next; /* next peer in the list */
};
} conf; /* config information */
};
+struct stream_interface;
+
/* This structure contains all information needed to easily handle a protocol.
* Its primary goal is to ease listeners maintenance. Specifically, the
* bind_all() primitive must be used before any fork(), and the enable_all()
int (*unbind_all)(struct protocol *proto); /* unbind all bound listeners */
int (*enable_all)(struct protocol *proto); /* enable all bound listeners */
int (*disable_all)(struct protocol *proto); /* disable all bound listeners */
+ int (*connect)(struct stream_interface *); /* connect function if any */
+ int (*get_src)(int, struct sockaddr *, socklen_t *); /* syscall used to retrieve src addr */
+ int (*get_dst)(int, struct sockaddr *, socklen_t *); /* syscall used to retrieve dst addr */
+
struct list listeners; /* list of listeners using this protocol */
int nb_listeners; /* number of listeners */
struct list list; /* list of registered protocols */
int bind_hdr_len; /* length of the name of the header above */
int bind_hdr_occ; /* occurrence number of header above: >0 = from first, <0 = from end, 0=disabled */
#endif
+ struct protocol *proto; /* server address protocol */
unsigned down_time; /* total time the server was down */
time_t last_change; /* last time, when the state was changed */
struct timeval check_start; /* last health check start time */
void *err_loc; /* commonly the server, NULL when SI_ET_NONE */
struct sock_ops sock; /* socket level operations */
-
- int (*connect)(struct stream_interface *); /* connect function if any */
- int (*get_src)(int, struct sockaddr *, socklen_t *); /* syscall used to retrieve src addr */
- int (*get_dst)(int, struct sockaddr *, socklen_t *); /* syscall used to retrieve dst addr */
+ struct protocol *proto; /* socket protocol */
void (*release)(struct stream_interface *); /* handler to call after the last close() */
#include <proto/lb_fwlc.h>
#include <proto/lb_fwrr.h>
#include <proto/lb_map.h>
+#include <proto/protocols.h>
#include <proto/proto_http.h>
#include <proto/proto_tcp.h>
#include <proto/queue.h>
* session's freshly assigned target with the stream interface's.
*/
stream_interface_prepare(s->req->cons, &stream_sock);
- s->req->cons->connect = tcp_connect_server;
- s->req->cons->get_src = getsockname;
- s->req->cons->get_dst = getpeername;
+
/* the target was only on the session, assign it to the SI now */
copy_target(&s->req->cons->target, &s->target);
stream_sock_get_to_addr(s->req->prod);
}
+ /* set the correct protocol on the output stream interface */
+ if (s->target.type == TARG_TYPE_SERVER)
+ s->req->cons->proto = target_srv(&s->target)->proto;
+ else if (s->target.type == TARG_TYPE_PROXY) {
+ s->req->cons->proto = protocol_by_family(s->req->cons->addr.to.ss_family);
+ if (!s->req->cons->proto)
+ return SN_ERR_INTERNAL;
+ }
+
assign_tproxy_address(s);
/* flag for logging source ip/port */
if (s->fe->options2 & PR_O2_SRC_ADDR)
s->req->cons->flags |= SI_FL_SRC_ADDR;
- err = s->req->cons->connect(s->req->cons);
+ err = s->req->cons->proto->connect(s->req->cons);
if (err != SN_ERR_NONE)
return err;
goto out;
}
newpeer->addr = *sk;
+ newpeer->proto = protocol_by_family(newpeer->addr.ss_family);
+
+ if (!sk) {
+ Alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
+ file, linenum, newpeer->addr.ss_family, args[2]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+
set_host_port(&newpeer->addr, realport);
if (strcmp(newpeer->id, localpeer) == 0) {
goto out;
}
newsrv->addr = *sk;
+ newsrv->proto = protocol_by_family(newsrv->addr.ss_family);
+
+ if (!sk) {
+ Alert("parsing [%s:%d] : Unknown protocol family %d '%s'\n",
+ file, linenum, newsrv->addr.ss_family, args[2]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
set_host_port(&newsrv->addr, realport);
newsrv->check_port = curproxy->defsrv.check_port;
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].get_src = NULL;
- s->si[0].get_dst = NULL;
+ s->si[0].proto = NULL;
+ s->si[0].release = NULL;
clear_target(&s->si[0].target);
s->si[0].exp = TICK_ETERNITY;
s->si[0].flags = SI_FL_NONE;
s->si[1].conn_retries = p->conn_retries;
s->si[1].err_type = SI_ET_NONE;
s->si[1].err_loc = NULL;
- s->si[1].connect = tcp_connect_server;
- s->si[1].get_src = getsockname;
- s->si[1].get_dst = getpeername;
+ s->si[1].proto = peer->proto;
+ s->si[1].release = NULL;
set_target_proxy(&s->si[1].target, s->be);
s->si[1].exp = TICK_ETERNITY;
s->si[1].flags = SI_FL_NONE;
s->si[1].flags |= SI_FL_INDEP_STR;
stream_interface_prepare(&s->si[1], &stream_sock);
- s->si[1].release = NULL;
session_init_srv_conn(s);
set_target_proxy(&s->target, s->be);
.sock_addrlen = sizeof(struct sockaddr_in),
.l3_addrlen = 32/8,
.accept = &stream_sock_accept,
+ .connect = tcp_connect_server,
.bind = tcp_bind_listener,
.bind_all = tcp_bind_listeners,
.unbind_all = unbind_all_listeners,
.sock_addrlen = sizeof(struct sockaddr_in6),
.l3_addrlen = 128/8,
.accept = &stream_sock_accept,
+ .connect = tcp_connect_server,
.bind = tcp_bind_listener,
.bind_all = tcp_bind_listeners,
.unbind_all = unbind_all_listeners,
return err;
}
+/* Returns the protocol handler for socket family <family> or NULL if not found */
+struct protocol *protocol_by_family(int family)
+{
+ struct protocol *proto;
+
+ list_for_each_entry(proto, &protocols, list) {
+ if (proto->sock_domain == family)
+ return proto;
+ }
+ return NULL;
+}
+
/************************************************************************/
/* All supported ACL keywords must be declared here. */
/************************************************************************/
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].proto = l->proto;
s->si[0].release = NULL;
- s->si[0].get_src = getpeername;
- s->si[0].get_dst = getsockname;
clear_target(&s->si[0].target);
s->si[0].exp = TICK_ETERNITY;
s->si[0].flags = SI_FL_NONE;
s->si[1].err_type = SI_ET_NONE;
s->si[1].conn_retries = 0; /* used for logging too */
s->si[1].err_loc = NULL;
- s->si[1].connect = NULL;
+ s->si[1].proto = NULL;
s->si[1].release = NULL;
- s->si[1].get_src = NULL;
- s->si[1].get_dst = NULL;
clear_target(&s->si[1].target);
s->si[1].sock.shutr= stream_int_shutr;
s->si[1].sock.shutw= stream_int_shutw;
/*
* This function handles the transition between the SI_ST_CON state and the
* SI_ST_EST state. It must only be called after switching from SI_ST_CON (or
- * SI_ST_INI) to SI_ST_EST, but only when a ->connect function is defined.
+ * SI_ST_INI) to SI_ST_EST, but only when a ->proto is defined.
*/
static void sess_establish(struct session *s, struct stream_interface *si)
{
rep->analysers |= s->fe->fe_rsp_ana | s->be->be_rsp_ana;
rep->flags |= BF_READ_ATTACHED; /* producer is now attached */
- if (si->connect) {
+ if (si->proto) {
/* real connections have timeouts */
req->wto = s->be->timeout.server;
rep->rto = s->be->timeout.server;
*/
s->req->cons->state = SI_ST_REQ; /* new connection requested */
s->req->cons->conn_retries = s->be->conn_retries;
- if (unlikely(s->req->cons->target.type == TARG_TYPE_APPLET && !s->req->cons->connect)) {
+ if (unlikely(s->req->cons->target.type == TARG_TYPE_APPLET &&
+ !(s->req->cons->proto && s->req->cons->proto->connect))) {
s->req->cons->state = SI_ST_EST; /* connection established */
s->rep->flags |= BF_READ_ATTACHED; /* producer is now attached */
s->req->wex = TICK_ETERNITY;
DPRINTF(stderr, "registering handler %p for si %p (was %p)\n", app, si, si->owner);
stream_interface_prepare(si, &stream_int_embedded);
- si->connect = NULL;
+ si->proto = NULL;
set_target_applet(&si->target, app);
si->applet.state = 0;
si->release = app->release;
DPRINTF(stderr, "registering handler %p for si %p (was %p)\n", fct, si, si->owner);
stream_interface_prepare(si, &stream_int_task);
- si->connect = NULL;
+ si->proto = NULL;
clear_target(&si->target);
si->release = NULL;
si->flags |= SI_FL_WAIT_DATA;