Unfortunately, these structures don't work like that... What you'll find is that the struct sockaddr
is a "base" definition that really only includes the socket family field, and some minimum space reservation - and then by typecasting, you're able to access the fields of another structure. As you're using IPv6, this means that you'll have a much longer address, and will need to allocate storage accordingly.
As the various addressing schemes use different information (e.g: address length), you need to make sure you allocate enough storage for what you're trying to use.
In your situation, the following would work:
struct sockaddr_in6 a;
memset(&(a->sin6_addr.s6_addr), 0, sizeof(a->sin6_addr.s6_addr));
printf("SIZEOF: %lu\n", sizeof(a->sin6_addr.s6_addr));
/* don't be afraid to clear the whole structure before filling it in too! */
memset(&a, 0, sizeof(a));
When you subsequently use it to connect / bind, then you'd typecast it there. When passing the structure to the kernel, you can almost think of it as passing a type-less pointer... the kernel knows you're using IPv6 (because you said so when calling socket()
, and in the address family field), and therefore which type to use. The typecast here just keeps the compiler happy - you're still sharing the full IPv6 info, and the size of that structure.
int fd, ret;
fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
ret = connect(fd, (struct sockaddr *)&a, sizeof(a));
Think of structures as a template you can lay over memory - it's just an indicator of how to read the data that is held in memory... by casting a region of memory to another type doesn't cause the underlying "thing" to change shape at all.
If you're allocating the address on the heap (not stack), then when you call *alloc()
, you need to give the correct size for the addressing you're using.
struct sockaddr_in6 *a;
a = malloc(sizeof *a);
a = malloc(sizeof (struct sockaddr_in6)); /* this works too... */
a = malloc(sizeof (struct sockaddr)); /* this is BROKEN */