【问题标题】:Why glibc2.23 change struct sockaddr_storage?为什么 glibc2.23 改变 struct sockaddr_storage?
【发布时间】:2017-08-28 07:10:00
【问题描述】:

我检查了 git 日志为 https://patchwork.sourceware.org/patch/12453/。此修改似乎解决了特定平台上的问题。 但我不明白为什么要在 struct sockaddr_storage 中交换 __ss_align 和 __ss_padding。 我现在正在开发的 Qualcomm 平台有很多类型转换,如下所示。

struct sockaddr_storage prefix_addr

(struct sockaddr_in6 *)&(prefix_addr)->sin6_addr.s6_addr 

在我们的 Cortex A7 平台上,结构对齐如下:

glibc2.23 之前:

struct sockaddr_in6
{
    sin6_family;   //0th byte
    sin6_port;     //2nd byte
    sin6_flowinfo; //4th byte
    sin6_addr;     //8th byte
};


struct sockaddr_storage
{
    ss_family;    //0th byte
    __ss_align;   //4th byte
    __ss_padding; //8th byte
};

glibc2.23之后:

struct sockaddr_storage
{
    ss_family;    //0th byte
    __ss_padding; //2nd byte
    __ss_align;   //124th byte
};

glibc 改变了 struct sockaddr_storage,但 struct sockaddr_in6 并没有改变,所以这个修改会在我们的平台上造成很多对齐问题,导致获取 IPV6 地址错误。

【问题讨论】:

    标签: c sockets ipv6 glibc


    【解决方案1】:

    请参考弗洛里安的回复:

    2017 年 9 月 1 日下午 12:07,李和南写道:

    定义 SASTORAGE_DATA(addr) (addr).__ss_padding

    typedef struct qcmap_cm_nl_prefix_info_s { 布尔前缀信息有效; 无符号字符前缀长度; 无符号整数 mtu; 结构 sockaddr_storage prefix_addr; 结构 ifa_cacheinfo 缓存信息; } qcmap_cm_nl_prefix_info_t;

    void QCMAP_Backhaul::GetIPV6PrefixInfo(char *devname, qcmap_cm_nl_prefix_info_t *ipv6_prefix_info) { 结构 sockaddr_in6 *sin6 = NULL;

    ...

    sin6 = (struct sockaddr_in6 *)&ipv6_prefix_info->prefix_addr; memcpy(SASTORAGE_DATA(ipv6_prefix_info->prefix_addr), RTA_DATA(rta), sizeof(sin6->sin6_addr)); ... }

    目前在此处公开:

    https://github.com/Bigcountry907/HTC_a13_vzw_Kernel/blob/master/vendor/qcom/proprietary/data/mobileap_v2/server/src/QCMAP_ConnectionManager.cpp#L3658

    我希望应用程序做这样的事情:

    struct sockaddr_in6 sin6; memset (&sin6, 0, sizeof (sin6));
    sin6.sin6_family = AF_INET6; memcpy (&sin6.sin6_addr, RTA_DATA (rta), sizeof (sin6.sin6_addr));内存 (&ipv6_prefix_info->prefix_addr, &sin6, sizeof (sin6));

    这避免了任何别名问题和对内部结构的依赖 struct sockaddr_storage (仅用作分配 足够大小和对齐的通用结构 sockaddr)。它也是 初始化套接字地址的其他组件(例如 端口号和流标签)。

    谢谢,弗洛里安

    另请参阅: https://books.google.com.hk/books?id=ptSC4LpwGA0C&pg=PA72&lpg=PA72&dq=alignment+sufficient&source=bl&ots=Kt0BQhjiMt&sig=HTUbm2bzVNSoMxNX98EMzORFc30&hl=zh-CN&sa=X&ved=0ahUKEwiP78iMoovWAhVLipQKHYFdCxcQ6AEIQzAF#v=onepage&q=alignment%20sufficient&f=false

    结论是高通对 sockaddr_storage 的使用不正确。

    【讨论】:

      【解决方案2】:

      我不确定这是 glibc 中产生对齐警告的更改:此更改对您显示的源代码没有影响。

      相反,我认为 Qualcomm 正在使用 clang,并且从 clang 4.x 开始,有一个新的对齐警告,我已经看到生成关于对齐的误报警告,具体取决于您编写代码的方式:-Waddress-of-packed-member

      您应该检查您使用的 clang 版本是否已更改,因为 glibc 已更改。如果是这种情况,这当然可以解释您的问题。

      使用临时变量会使这些警告消失。

      而不是像这样拨打电话:

      my_function(((struct sockaddr_in6 *)&prefix_addr)->sin6_addr.s6_addr)
      

      只写:

      struct sockaddr_in6 p = *(struct sockaddr_in6 *) &prefix_addr;
      my_function(p.sin6_addr.s6_addr);
      

      这可以避免对齐警告。

      【讨论】:

      • 嗨,Alexandre,对不起,我没有把自己说清楚。我现在遇到的不是编译警告。这是一个错误。由于 IPV6 地址始终保存在 sockaddr_storage.__ss_padding 中,当我们希望像以前一样获得像 1111:2222:3333:4444:5555:6666:7777:8888 这样的 IPV6 地址时,实际上在 glibc2.23 上我们得到了 2233:3344:4455 :5566:6677:7788:88xx:xxxx.
      • 好的,问题是使用sockaddr_storage.__ss_padding 访问地址是一个有效的技巧,但没有记录并且基于特定的实现。由于它不在规范中,人们进行了更改,最后,你得到了错误。避免错误的唯一方法是使用您在问题开头编写的类型转换,因为这是符合规范的唯一方法。如果您查看 Berkeley 的实现,您会看到在此结构中添加填充的另一种方法:github.com/freebsd/freebsd/blob/master/sys/sys/…
      猜你喜欢
      • 2016-10-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      相关资源
      最近更新 更多