struct sockaddr_un vs. sockaddr
"struct sockaddr" is a generic definition. It's used by any socket function that requires an address.
"struct sockaddr_un" (a "Unix sockets" address) is a specific kind of address family.
The more commonly seen "struct sockaddr_in" (an "Internet socket" address) is another specific kind of address family.
The cast is what allows the sockets APIs to accept a common parameter type that will actually be any one of several different actual types.
Here's a good link that shows several different address family definitions:
http://www.cas.mcmaster.ca/~qiao/courses/cs3mh3/tutorials/socket.html
A struct sockaddr
should generally only be used as the base type for a pointer. It is a structure intended to cover the common initial sequence of the members in the address family specific socket address types (struct sockaddr_un
, struct sockaddr_in
, struct sockaddr_in6
etc.)
The only member that you can rely on struct sockaddr
having is a single sa_family_t
, indicating the socket address family. The idea is that to obtain a sort of polymorphism - you can have a function that can operate on several different socket address types:
void foo(struct sockaddr *sa){ switch(sa->sa_family) { case AF_INET: { struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; /* AF_INET processing */ } case AF_UNIX: { struct sockaddr_un *sa_un = (struct sockaddr_un *)sa; /* AF_UNIX processing */ }/* ... */
Note though that code like the above is generally considered to break the "strict aliasing" rule in C - if you want to do that in your own code, you are supposed to use a union type:
union sockaddr { struct sockaddr sa; struct sockaddr_in sin; struct sockaddr_un sun; /* ... */};void foo(union sockaddr *sa_union){ struct sockaddr *sa = (struct sockaddr *)sa_union; switch(sa->sa_family) { case AF_INET: { struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; /* AF_INET processing */ } case AF_UNIX: { struct sockaddr_un *sa_un = (struct sockaddr_un *)sa; /* AF_UNIX processing */ }/* ... */