tags:

views:

350

answers:

2

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?
};
+3  A: 

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.

Dale Hagglund
@Dale, only field in the sockaddr_storage, that the user is supposed to access is __ss_family. So, even if the rest of the fields are aligned to 64 bit boundary, how that is going to help? Also, i was wrong that it is sockaddr_in6 rather than sockaddr_storage supposed to be aligned to 64 bit boundary.
chappar
If a struct or union contains any member requiring 64-bit alignment (e.g. `uint64_t`), then the structure itself will be placed on a 64-bit boundary. Otherwise there would be no way to guarantee that that member would stay aligned. Of course if the structure itself is 64-bit aligned then the first field (`__ss_family`) will also be 64-bit aligned.
mark4o
A: 

So from what you guys say, it seems that

a.

int64_t   __ss_align;

causes structure to be aligned to a 64-bit boundary.

b. __ss_pad1 ensures that ss_family is on the 64-bit boundary just before __ss_align

c. __ss_pad2 ensures the required total size.

I had read the above code at http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/socket.h.html#tag_13_61. From what is written there, it seems that the value of _SS_MAXSIZE is to be decided by the implementer.

In the code mentioned by Dale, the division in

uint64_t u_pad[_SS_MAXSIZE / sizeof(uint64_t)]

will cause an float, which will then be truncated, which then results in the structure being smaller that the required size (_SS_MAXSIZE).

:)

Ashim Ghosh