Here is a simple program that shows how we normally type cast struct sockaddr *
to struct sockaddr_in *
or struct sockaddr_in6 *
while writing socket programs.
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int main()
{
struct addrinfo *ai;
printf("sizeof (struct sockaddr): %zu\n", sizeof (struct sockaddr));
printf("sizeof (struct sockaddr_in): %zu\n", sizeof (struct sockaddr_in));
printf("sizeof (struct sockaddr_in6): %zu\n", sizeof (struct sockaddr_in6));
if (getaddrinfo("localhost", "http", NULL, &ai) != 0) {
printf("error\n");
return EXIT_FAILURE;
}
if (ai->ai_family == AF_INET) {
struct sockaddr_in *addr = (struct sockaddr_in *) ai->ai_addr;
printf("IPv4 port: %d\n", addr->sin_port);
} else if (ai->ai_family == AF_INET6) {
struct sockaddr_in6 *addr = (struct sockaddr_in6 *) ai->ai_addr;
printf("IPv6 port: %d\n", addr->sin6_port);
}
return 0;
}
Beej's Guide to Network Programming also recommends this in page 10.
To deal with struct sockaddr, programmers created a parallel structure: struct sockaddr_in (“in” for “Internet”) to be used with IPv4.
And this is the important bit: a pointer to a struct sockaddr_in can be cast to a pointer to a struct sockaddr and vice-versa. So even though connect() wants a struct sockaddr*, you can still use a struct sockaddr_in and cast it at the last minute!
But from the discussion at another question, it appears that this is just a hack, not valid C code as per the C standard.
In particular, see AnT's answer that mentions,
As for the popular technique with casts between struct sockaddr *, struct sockaddr_in * and struct sockaddr_in6 * - these are just hacks that have nothing to do with C language. They just work in practice, but as far as C language is concerned, the technique is invalid.
So if this technique we use to do socket programming (and what is also recommended by the books) is invalid, what is the valid way to rewrite the above code so that it is also a valid C code as per the C standard?