MINOR: protocol: add a new proto_fam structure for protocol families

We need to specially handle protocol families which regroup common
functions used for a given address family. These functions include
bind(), addrcmp(), get_src() and get_dst() for now. Some fields are
also added about the address family, socket domain (protocol family
passed to the socket() syscall), and address length.

These protocol families are referenced from the protocols but not yet
used.
diff --git a/include/haproxy/proto_sockpair.h b/include/haproxy/proto_sockpair.h
index b04ebea..6807169 100644
--- a/include/haproxy/proto_sockpair.h
+++ b/include/haproxy/proto_sockpair.h
@@ -21,6 +21,8 @@
 #ifndef _HAPROXY_PROTO_SOCKPAIR_H
 #define _HAPROXY_PROTO_SOCKPAIR_H
 
+extern struct proto_fam proto_fam_sockpair;
+
 int recv_fd_uxst(int sock);
 int send_fd_uxst(int fd, int send_fd);
 int sockpair_bind_receiver(struct receiver *rx, void (*handler)(int fd), char **errmsg);
diff --git a/include/haproxy/protocol-t.h b/include/haproxy/protocol-t.h
index f29c944..fe0c981 100644
--- a/include/haproxy/protocol-t.h
+++ b/include/haproxy/protocol-t.h
@@ -58,6 +58,21 @@
 #define CONNECT_DELACK_ALWAYS                   0x00000004 /* Use a delayed ACK */
 #define CONNECT_CAN_USE_TFO                     0x00000008 /* We can use TFO for this connection */
 
+/* protocol families define standard functions acting on a given address family
+ * for a socket implementation, such as AF_INET/PF_INET for example.
+ */
+struct proto_fam {
+	char name[PROTO_NAME_LEN];                      /* family name, zero-terminated */
+	int sock_domain;				/* socket domain, as passed to socket()   */
+	sa_family_t sock_family;			/* socket family, for sockaddr */
+	socklen_t sock_addrlen;				/* socket address length, used by bind() */
+	int l3_addrlen;					/* layer3 address length, used by hashes */
+	int (*addrcmp)(const struct sockaddr_storage *, const struct sockaddr_storage *); /* compare addresses (like memcmp) */
+	int (*bind)(struct receiver *rx, void (*handler)(int fd), char **errmsg); /* bind a receiver */
+	int (*get_src)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve src addr */
+	int (*get_dst)(int fd, struct sockaddr *, socklen_t, int dir); /* syscall used to retrieve dst addr */
+};
+
 /* This structure contains all information needed to easily handle a protocol.
  * Its primary goal is to ease listeners maintenance. Specifically, the
  * bind() primitive must be used before any fork(), and the enable_all()
@@ -65,6 +80,7 @@
  */
 struct protocol {
 	char name[PROTO_NAME_LEN];			/* protocol name, zero-terminated */
+	struct proto_fam *fam;                          /* protocol family */
 	int sock_domain;				/* socket domain, as passed to socket()   */
 	int sock_type;					/* socket type, as passed to socket()     */
 	int sock_prot;					/* socket protocol, as passed to socket() */
diff --git a/include/haproxy/sock_inet.h b/include/haproxy/sock_inet.h
index 9f95679..7ecdc7b 100644
--- a/include/haproxy/sock_inet.h
+++ b/include/haproxy/sock_inet.h
@@ -31,6 +31,9 @@
 extern int sock_inet_tcp_maxseg_default;
 extern int sock_inet6_tcp_maxseg_default;
 
+extern struct proto_fam proto_fam_inet4;
+extern struct proto_fam proto_fam_inet6;
+
 int sock_inet4_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b);
 int sock_inet6_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b);
 int sock_inet_get_dst(int fd, struct sockaddr *sa, socklen_t salen, int dir);
diff --git a/include/haproxy/sock_unix.h b/include/haproxy/sock_unix.h
index 38ededa..3b46b48 100644
--- a/include/haproxy/sock_unix.h
+++ b/include/haproxy/sock_unix.h
@@ -28,6 +28,8 @@
 #include <haproxy/api.h>
 #include <haproxy/receiver-t.h>
 
+extern struct proto_fam proto_fam_unix;
+
 int sock_unix_addrcmp(const struct sockaddr_storage *a, const struct sockaddr_storage *b);
 int sock_unix_bind_receiver(struct receiver *rx, void (*handler)(int fd), char **errmsg);
 
diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c
index a920f4e..a2a9607 100644
--- a/src/proto_sockpair.c
+++ b/src/proto_sockpair.c
@@ -45,9 +45,22 @@
 static int sockpair_bind_listener(struct listener *listener, char *errmsg, int errlen);
 static int sockpair_connect_server(struct connection *conn, int flags);
 
+struct proto_fam proto_fam_sockpair = {
+	.name = "sockpair",
+	.sock_domain = AF_CUST_SOCKPAIR,
+	.sock_family = AF_UNIX,
+	.sock_addrlen = sizeof(struct sockaddr_un),
+	.l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),
+	.addrcmp = NULL,
+	.bind = sockpair_bind_receiver,
+	.get_src = NULL,
+	.get_dst = NULL,
+};
+
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_sockpair = {
 	.name = "sockpair",
+	.fam = &proto_fam_sockpair,
 	.sock_domain = AF_CUST_SOCKPAIR,
 	.sock_type = SOCK_STREAM,
 	.sock_prot = 0,
diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 4af22e5..cb4dc32 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -51,6 +51,7 @@
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_tcpv4 = {
 	.name = "tcpv4",
+	.fam = &proto_fam_inet4,
 	.sock_domain = AF_INET,
 	.sock_type = SOCK_STREAM,
 	.sock_prot = IPPROTO_TCP,
@@ -76,6 +77,7 @@
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_tcpv6 = {
 	.name = "tcpv6",
+	.fam = &proto_fam_inet6,
 	.sock_domain = AF_INET6,
 	.sock_type = SOCK_STREAM,
 	.sock_prot = IPPROTO_TCP,
diff --git a/src/proto_udp.c b/src/proto_udp.c
index 43eff39..d4d6b2a 100644
--- a/src/proto_udp.c
+++ b/src/proto_udp.c
@@ -47,6 +47,7 @@
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_udp4 = {
 	.name = "udp4",
+	.fam = &proto_fam_inet4,
 	.sock_domain = AF_CUST_UDP4,
 	.sock_type = SOCK_DGRAM,
 	.sock_prot = IPPROTO_UDP,
@@ -72,6 +73,7 @@
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_udp6 = {
 	.name = "udp6",
+	.fam = &proto_fam_inet6,
 	.sock_domain = AF_CUST_UDP6,
 	.sock_type = SOCK_DGRAM,
 	.sock_prot = IPPROTO_UDP,
diff --git a/src/proto_uxst.c b/src/proto_uxst.c
index 5ceb18f..0b8e176 100644
--- a/src/proto_uxst.c
+++ b/src/proto_uxst.c
@@ -48,6 +48,7 @@
 /* Note: must not be declared <const> as its list will be overwritten */
 static struct protocol proto_unix = {
 	.name = "unix_stream",
+	.fam = &proto_fam_unix,
 	.sock_domain = PF_UNIX,
 	.sock_type = SOCK_STREAM,
 	.sock_prot = 0,
diff --git a/src/sock_inet.c b/src/sock_inet.c
index 3bb4f34..09ff71e 100644
--- a/src/sock_inet.c
+++ b/src/sock_inet.c
@@ -31,6 +31,29 @@
 #include <haproxy/sock_inet.h>
 #include <haproxy/tools.h>
 
+struct proto_fam proto_fam_inet4 = {
+	.name = "inet4",
+	.sock_domain = PF_INET,
+	.sock_family = AF_INET,
+	.sock_addrlen = sizeof(struct sockaddr_in),
+	.l3_addrlen = 32/8,
+	.addrcmp = sock_inet4_addrcmp,
+	.bind = sock_inet_bind_receiver,
+	.get_src = sock_get_src,
+	.get_dst = sock_inet_get_dst,
+};
+
+struct proto_fam proto_fam_inet6 = {
+	.name = "inet6",
+	.sock_domain = PF_INET6,
+	.sock_family = AF_INET6,
+	.sock_addrlen = sizeof(struct sockaddr_in6),
+	.l3_addrlen = 128/8,
+	.addrcmp = sock_inet6_addrcmp,
+	.bind = sock_inet_bind_receiver,
+	.get_src = sock_get_src,
+	.get_dst = sock_get_dst,
+};
 
 /* PLEASE NOTE for function below:
  *   - sock_inet4_* is solely for AF_INET (IPv4)
diff --git a/src/sock_unix.c b/src/sock_unix.c
index 04accb4..4620b74 100644
--- a/src/sock_unix.c
+++ b/src/sock_unix.c
@@ -36,6 +36,18 @@
 #include <haproxy/tools.h>
 
 
+struct proto_fam proto_fam_unix = {
+	.name = "unix",
+	.sock_domain = PF_UNIX,
+	.sock_family = AF_UNIX,
+	.sock_addrlen = sizeof(struct sockaddr_un),
+	.l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),
+	.addrcmp = sock_unix_addrcmp,
+	.bind = sock_unix_bind_receiver,
+	.get_src = sock_get_src,
+	.get_dst = sock_get_dst,
+};
+
 /* PLEASE NOTE for functions below:
  *
  * The address family SHOULD always be checked. In some cases a function will