What is the purpose of the sa_data field in sockaddr?

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 

The actual structure passed to addr will depend on the address family. The sockaddr structure is defined as something like:

 struct sockaddr { sa_family_t sa_family; char sa_data[14]; } 

So, for the IPv4 address (AF_INET), the actual structure to be transmitted is this:

 /* Source http://linux.die.net/man/7/ip */ struct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ }; /* Internet address. */ struct in_addr { uint32_t s_addr; /* address in network byte order */ }; 

Does the binding code check the value of sockaddr.sa_family and depending on the value found, it then turns the sockaddr structure into an appropriate structure, such as sockaddr_in ?

Why is sa_data set to 14 characters? If I understand correctly, the sa_data field is just a field that will have a large enough space to store all types of address families? Presumably, the original designers expected 14 characters to be wide enough to fit all future types.

+5
source share
2 answers

According to the glibc manual :

The length of 14 sa_data is essentially arbitrary.

And the FreeBSD Developer's Guide mentions the following:

Pay attention to the uncertainty with which the sa_data field is declared, just like an array of 14 bytes, with a comment comment there can be more than 14 of them.

This uncertainty is quite deliberate. Sockets are very powerful interface. Although most people probably consider this nothing more than an Internet interface, and most applications probably use it for this, sockets can be used for almost any kind of inter-process communications, of which only the Internet (or, more precisely, IP) is one .

Yes, the sa_family field sa_family used to recognize how to handle the passed structure (which is passed to struct sockaddr* in the call for binding). You can learn more about how this works in the FreeBSD Developers Guide .

And actually there are "polymorphic" (sub) sockaddr types in which sa_data contains more than 16 bytes, for example:

 struct sockaddr_un { sa_family_t sun_family; /* AF_UNIX */ char sun_path[108]; /* pathname */ }; 
+5
source

The sockaddr structure is used as a tagged union. Reading the sa_family field, it can be attributed to the structure of the corresponding form.

14 bytes are arbitrary. It is large enough to store IPv4 addresses, but not large enough to store IPv6 addresses. There is also a sockaddr_storage structure that is large enough for both. Reading Microsoft documents on SOCKADDR_STORAGE , it has 128 bytes, which is much more than is necessary for IPv6. While checking some Linux headers, they are apparently at least as large.

For reference, the IPv6 structure:

 struct sockaddr_in6 { u_int16_t sin6_family; // address family, AF_INET6 u_int16_t sin6_port; // port number, Network Byte Order u_int32_t sin6_flowinfo; // IPv6 flow information struct in6_addr sin6_addr; // IPv6 address u_int32_t sin6_scope_id; // Scope ID }; struct in6_addr { unsigned char s6_addr[16]; // IPv6 address }; 

As you can see, the 16-byte s6_addr field is already larger than the 14-byte sa_data on it. The total size after the sa_family field is 26 bytes.

+3
source

All Articles