Below is the definition of sockaddr_storage structure (rfc2553). According rfc2553, the sockaddr_storage should be aligned with 64 bit boundary and it should be able to hold both sockaddr_in and sockaddr_in6. Also, it must have atlest __ss_family member. Rest of the fields are implementation defined.
#define _SS_MAXSIZE 128 /* Implementation specific max size */
#define _SS_ALIGNSIZE (sizeof (int64_t))
/* Implementation specific desired alignment */
/*
* Definitions used for sockaddr_storage structure paddings design.
*/
#define _SS_PAD1SIZE (_SS_ALIGNSIZE - sizeof (sa_family_t))
#define _SS_PAD2SIZE (_SS_MAXSIZE - (sizeof (sa_family_t)+
_SS_PAD1SIZE + _SS_ALIGNSIZE))
struct sockaddr_storage {
sa_family_t __ss_family; /* address family */
/* Following fields are implementation specific */
char __ss_pad1[_SS_PAD1SIZE];
/* 6 byte pad, this is to make implementation
/* specific pad up to alignment field that */
/* follows explicit in the data structure */
int64_t __ss_align; /* field to force desired structure */
/* storage alignment */
char __ss_pad2[_SS_PAD2SIZE];
/* 112 byte pad to achieve desired size, */
/* _SS_MAXSIZE value minus size of ss_family */
/* __ss_pad1, __ss_align fields is 112 */
};
My question is why sockaddr_storage is defined as the way above? Why couldn't it defined as below?
struct sockaddr_storage {
sa_family_t __ss_family; /* address family */
char __ss_pad[_SS_MAXSIZE - sizeof(sa_family_t) ]; //will there be any alignment issue here?
};
Your proposed alternative wouldn't force the entire structure to be aligned on an 8-byte (64-bit) boundary, which you mention as a requirement from RFC2553.
In general, a structure takes on the strictest alignment required by any of its members. Since sa_family_t
is probably a u16_t
, which requires only 2-byte alignment, and an array of char requires at most 1-byte alignment, the alternative you propose would require only 2-byte alignment. (It's likely that the compiler would give it at least 4- and maybe 8-byte alignment anyway, but you can't be sure.)
The style of the actual definition is an attempt to make sure that every byte in the structure is part of some named field, ie, that the the compiler does not insert any padding between fields. This is needed (sort of) so that _SS_PAD2SIZE
has a value that can be computed in terms of the sizes of all other members.
However, I find this definition rather complicated. I'm pretty sure the following works just as well, and is quite a bit easier to understand:
struct sockaddr_storage {
union {
sa_family_t u_family;
uint64_t u_pad[_SS_MAXSIZE / sizeof(uint64_t)];
} __ss_u;
# define __ss_family __ss_u.u_family
};
Here, the union acquires the alignment requirements of its most strictly aligned member, which then propagates to the enclosing struct. Note that in this version I only have the one required field (although buried in a union) and a single padding array that is the exact size I want the entire struct to be. The only slightly tricky part is the macro definition of __ss_family
. It's possible that the macro trick is not strictly compliant with the requirements in the RFC, but there will be few (if any) ways to notice the difference.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With