MINOR: protocol: properly assign the sock_domain and sock_family

When we finally split sock_domain from sock_family in 2.3, something
was not cleanly finished. The family is what should be stored in the
address while the domain is what is supposed to be passed to socket().
But for the custom addresses, we did the opposite, just because the
protocol_lookup() function was acting on the domain, not the family
(both of which are equal for non-custom addresses).

This is an API bug but there's no point backporting it since it does
not have visible effects. It was visible in the code since a few places
were using PF_UNIX while others were comparing the domain against AF_MAX
instead of comparing the family.

This patch clarifies this in the comments on top of proto_fam, addresses
the indexing issue and properly reconfigures the two custom families.
This commit is contained in:
Willy Tarreau 2024-08-09 18:59:46 +02:00
parent 67bf1d6c9e
commit 732913f848
5 changed files with 19 additions and 9 deletions

View File

@ -70,7 +70,17 @@ enum proto_type {
#define PROTO_F_REUSEPORT_TESTED 0x00000002 /* SO_REUSEPORT support was tested */
/* protocol families define standard functions acting on a given address family
* for a socket implementation, such as AF_INET/PF_INET for example.
* for a socket implementation, such as AF_INET/PF_INET for example. There is
* permanent confusion between domain and family. Here's how it works:
* - the domain defines the format of addresses (e.g. sockaddr_in etc),
* it is passed as the first argument to socket()
* - the family is part of the address and is stored in receivers, servers
* and everywhere there is an address. It's also a proto_fam selector.
* Domains are often PF_xxx though man 2 socket on Linux quotes 4.x BSD's man
* that says AF_* can be used everywhere. At least it tends to keep the code
* clearer about the intent. In HAProxy we're defining new address families
* with AF_CUST_* which appear in addresses, and they cannot be used for the
* domain, the socket() call must use sock_domain instead.
*/
struct proto_fam {
char name[PROTO_NAME_LEN]; /* family name, zero-terminated */

View File

@ -22,8 +22,8 @@
struct proto_fam proto_fam_rhttp = {
.name = "rhttp",
.sock_domain = AF_CUST_RHTTP_SRV,
.sock_family = AF_INET,
.sock_domain = AF_INET,
.sock_family = AF_CUST_RHTTP_SRV,
.bind = rhttp_bind_receiver,
};

View File

@ -50,8 +50,8 @@ struct connection *sockpair_accept_conn(struct listener *l, int *status);
struct proto_fam proto_fam_sockpair = {
.name = "sockpair",
.sock_domain = AF_CUST_SOCKPAIR,
.sock_family = AF_UNIX,
.sock_domain = AF_UNIX,
.sock_family = AF_CUST_SOCKPAIR,
.sock_addrlen = sizeof(struct sockaddr_un),
.l3_addrlen = sizeof(((struct sockaddr_un*)0)->sun_path),
.addrcmp = NULL,

View File

@ -38,14 +38,14 @@ __decl_spinlock(proto_lock);
/* Registers the protocol <proto> */
void protocol_register(struct protocol *proto)
{
int sock_domain = proto->fam->sock_domain;
int sock_family = proto->fam->sock_family;
BUG_ON(sock_domain < 0 || sock_domain >= AF_CUST_MAX);
BUG_ON(sock_family < 0 || sock_family >= AF_CUST_MAX);
BUG_ON(proto->proto_type >= PROTO_NUM_TYPES);
HA_SPIN_LOCK(PROTO_LOCK, &proto_lock);
LIST_APPEND(&protocols, &proto->list);
__protocol_by_family[sock_domain]
__protocol_by_family[sock_family]
[proto->proto_type]
[proto->xprt_type == PROTO_TYPE_DGRAM] = proto;
HA_SPIN_UNLOCK(PROTO_LOCK, &proto_lock);

View File

@ -1147,7 +1147,7 @@ int _sock_supports_reuseport(const struct proto_fam *fam, int type, int protocol
fd1 = fd2 = -1;
/* ignore custom sockets */
if (!fam || fam->sock_domain >= AF_MAX)
if (!fam || fam->sock_family >= AF_MAX)
goto leave;
fd1 = socket(fam->sock_domain, type, protocol);