Почему структура sockaddr_storage определяется так, как она определена? - PullRequest
7 голосов
/ 28 августа 2009

Ниже приведено определение структуры sockaddr_storage ( rfc2553 ). Согласно rfc2553, sockaddr_storage должен быть выровнен с 64-битной границей, и он должен содержать как sockaddr_in, так и sockaddr_in6. Кроме того, он должен иметь как минимум члена __ss_family. Остальные поля определены реализацией.

#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 */
};

Мой вопрос: почему sockaddr_storage определено выше? Почему это не может быть определено как ниже?

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?
};

Ответы [ 2 ]

6 голосов
/ 28 августа 2009

Предлагаемый вами вариант не приведет к выравниванию всей структуры на 8-байтовой (64-битной) границе, которую вы упоминаете в качестве требования из RFC2553.

В общем, структура принимает строжайшее выравнивание, требуемое любым из ее членов. Поскольку sa_family_t - это, вероятно, u16_t, для которого требуется только 2-байтовое выравнивание, а для массива char требуется не более 1-байтового выравнивания, предлагаемый вами вариант потребует только 2-байтового выравнивания. (Вполне вероятно, что компилятор в любом случае даст ему как минимум 4- и, возможно, 8-байтовое выравнивание, но вы не можете быть уверены.)

Стиль фактического определения - это попытка убедиться, что каждый байт в структуре является частью некоторого именованного поля, т. Е. Что компилятор не вставляет какие-либо отступы между полями. Это необходимо (в некотором роде), чтобы _SS_PAD2SIZE имел значение, которое можно вычислить с точки зрения размеров всех других членов.

Однако я нахожу это определение довольно сложным. Я уверен, что следующее работает так же хорошо, и его немного легче понять:

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
};

Здесь объединение получает требования к выравниванию своего наиболее строго выровненного элемента, который затем распространяется на включающую структуру. Обратите внимание, что в этой версии у меня есть только одно обязательное поле (хотя оно и похоронено в объединении) и один массив заполнения, который является точным размером, который я хочу, чтобы была вся структура. Единственная немного сложная часть - это макроопределение __ss_family. Возможно, что макро-трюк не полностью соответствует требованиям в RFC, но будет немного (если таковые имеются) способов заметить разницу.

0 голосов
/ 12 февраля 2010

Так что из того, что вы, ребята, говорите, кажется, что

а.

int64_t   __ss_align;

приводит к выравниванию структуры по 64-битной границе.

б. __ss_pad1 гарантирует, что ss_family находится на 64-битной границе непосредственно перед __ss_align

с. __ss_pad2 обеспечивает требуемый общий размер.

Я прочитал приведенный выше код на http://www.opengroup.org/onlinepubs/000095399/basedefs/sys/socket.h.html#tag_13_61. Из того, что там написано, кажется, что значение _SS_MAXSIZE должно быть решено исполнителем.

В коде, упомянутом Дейлом, деление на

uint64_t u_pad[_SS_MAXSIZE / sizeof(uint64_t)]

вызовет число с плавающей точкой, которое затем будет усечено, что приведет к тому, что структура будет меньше требуемого размера (_SS_MAXSIZE).

:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...