From: Willy Tarreau Date: Mon, 7 May 2012 16:12:14 +0000 (+0200) Subject: REORG/MEDIUM: replace stream interface protocol functions by a proto pointer X-Git-Tag: v1.5-dev9~14 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=26d8c59f0b32942cfb3391c40336305612d4eae6;p=thirdparty%2Fhaproxy.git REORG/MEDIUM: replace stream interface protocol functions by a proto pointer The stream interface now makes use of the socket protocol pointer instead of the direct functions. --- diff --git a/include/proto/protocols.h b/include/proto/protocols.h index 05567ea689..cebe560913 100644 --- a/include/proto/protocols.h +++ b/include/proto/protocols.h @@ -125,6 +125,8 @@ int protocol_unbind_all(void); */ int protocol_enable_all(void); +/* returns the protocol associated to family or NULL if not found */ +struct protocol *protocol_by_family(int family); #endif /* _PROTO_PROTOCOLS_H */ diff --git a/include/proto/stream_sock.h b/include/proto/stream_sock.h index f66d32192a..577dad8540 100644 --- a/include/proto/stream_sock.h +++ b/include/proto/stream_sock.h @@ -78,8 +78,8 @@ static inline void stream_sock_get_to_addr(struct stream_interface *si) 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; } @@ -95,8 +95,8 @@ static inline void stream_sock_get_from_addr(struct stream_interface *si) 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; } diff --git a/include/types/peers.h b/include/types/peers.h index 24ab804b19..50e4ea3840 100644 --- a/include/types/peers.h +++ b/include/types/peers.h @@ -73,6 +73,7 @@ struct peer { } 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 */ }; diff --git a/include/types/protocols.h b/include/types/protocols.h index 104cee56ff..4112b08c88 100644 --- a/include/types/protocols.h +++ b/include/types/protocols.h @@ -134,6 +134,8 @@ struct listener { } 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() @@ -154,6 +156,10 @@ struct protocol { 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 */ diff --git a/include/types/server.h b/include/types/server.h index c0729fc544..31f036d836 100644 --- a/include/types/server.h +++ b/include/types/server.h @@ -148,6 +148,7 @@ struct server { 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 */ diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index 1dc5052caa..fb2b258e58 100644 --- a/include/types/stream_interface.h +++ b/include/types/stream_interface.h @@ -137,10 +137,7 @@ struct stream_interface { 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() */ diff --git a/src/backend.c b/src/backend.c index f125931818..4652fba047 100644 --- a/src/backend.c +++ b/src/backend.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -974,9 +975,7 @@ int connect_server(struct session *s) * 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); @@ -987,13 +986,22 @@ int connect_server(struct session *s) 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; diff --git a/src/cfgparse.c b/src/cfgparse.c index 8bfa4b2c97..e4ee9a0522 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -1266,6 +1266,15 @@ int cfg_parse_peers(const char *file, int linenum, char **args, int kwm) 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) { @@ -4080,6 +4089,14 @@ stats_error_parsing: 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; diff --git a/src/peers.c b/src/peers.c index 31fb8d9537..ba57e1868f 100644 --- a/src/peers.c +++ b/src/peers.c @@ -1154,9 +1154,8 @@ static struct session *peer_session_create(struct peer *peer, struct peer_sessio 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; @@ -1173,9 +1172,8 @@ static struct session *peer_session_create(struct peer *peer, struct peer_sessio 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; @@ -1183,7 +1181,6 @@ static struct session *peer_session_create(struct peer *peer, struct peer_sessio 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); diff --git a/src/proto_tcp.c b/src/proto_tcp.c index f709e73655..478bff5729 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -70,6 +70,7 @@ static struct protocol proto_tcpv4 = { .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, @@ -88,6 +89,7 @@ static struct protocol proto_tcpv6 = { .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, diff --git a/src/protocols.c b/src/protocols.c index 5b3e081cfa..155636f4fd 100644 --- a/src/protocols.c +++ b/src/protocols.c @@ -319,6 +319,18 @@ int protocol_disable_all(void) return err; } +/* Returns the protocol handler for socket 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. */ /************************************************************************/ diff --git a/src/session.c b/src/session.c index 5cddabdf85..af3a464420 100644 --- a/src/session.c +++ b/src/session.c @@ -169,10 +169,8 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) 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; @@ -195,10 +193,8 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) 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; @@ -685,7 +681,7 @@ static int sess_update_st_cer(struct session *s, struct stream_interface *si) /* * 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) { @@ -713,7 +709,7 @@ 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; @@ -1920,7 +1916,8 @@ struct task *process_session(struct task *t) */ 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; diff --git a/src/stream_interface.c b/src/stream_interface.c index 35ebc30596..543cfeea60 100644 --- a/src/stream_interface.c +++ b/src/stream_interface.c @@ -331,7 +331,7 @@ struct task *stream_int_register_handler(struct stream_interface *si, struct si_ 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; @@ -354,7 +354,7 @@ struct task *stream_int_register_handler_task(struct stream_interface *si, 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;