首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我需要在iOS 9上工作的IPv6多播C代码

我需要在iOS 9上工作的IPv6多播C代码
EN

Stack Overflow用户
提问于 2015-10-03 00:50:00
回答 1查看 1.9K关注 0票数 10

苹果现在要求iOS 9应用程序与IPv6兼容。我们基本上没问题,除了发送UDP广播的一小段代码--这在iOS 9中失败了。

我读到的所有内容都告诉我,UDP多播是在IPv6中实现这一点的正确方法。我找到了一些示例代码,但它在我尝试过的任何版本的iOS或Mac上都不起作用。

这段代码是从我们程序中的C/C++库中调用的-很难回调到Swift、Obj-C、Java等。这些代码将被我们的应用程序的Mac OS X和Android版本共享。有人会认为在任何POSIX环境中用C语言进行IPv6多播都是可能的!

在下面的示例中,执行成功直到最后的sendto()调用,该调用实际发送UDP消息。sendto()失败,失败后errno设置为EBROKENPIPE (22)。

我最好的猜测是我错过了一些必需的setsockopt()调用,或者使用了错误的组播地址。现在,我被难住了。

下面是我正在进行的函数调用(为了多播“有人在那里吗?”在UDP端口4031上):

代码语言:javascript
复制
char *msg = "Is anybody out there?";
err = multicast_udp_msg ( "FF01::1111", 4031, msg, strlen(msg) );

下面是被调用的代码:

代码语言:javascript
复制
// Multicasts a message on a specific UDP port.
// myhost - IPv6 address on which to multicast the message (i.e., ourself)
// port - UDP port on which to broadcast the mssage
// msg - message contents to broadcast
// msgsize - length of message in bytes
// Return value is zero if successful, or nonzero on error.

int multicast_udp_msg ( char *myhost, short port, char *msg, size_t msgsize )
{
    int        sockfd, n;
    char    service[16] = { 0 };
    int        err = 0;
    struct addrinfo hints = { 0 }, *res, *ressave;
    struct sockaddr_storage addr = { 0 };

    hints.ai_family = AF_INET6;
    hints.ai_socktype = SOCK_DGRAM;

    sprintf ( service, "%hd", port );
    n = getaddrinfo ( myhost, service, &hints, &res );
    if ( n < 0 )
    {
        fprintf(stderr, "getaddrinfo error:: [%s]\n", gai_strerror(n));
        return -1;
    }

    ressave = res;

    sockfd = socket ( res->ai_family, res->ai_socktype, res->ai_protocol );
    if ( sockfd >= 0 )
    {
        memcpy ( &addr, res->ai_addr, sizeof ( addr ) );
        if ( joinGroup ( sockfd, 0, 8, &addr ) == 0 )
            if ( bind ( sockfd, res->ai_addr, res->ai_addrlen ) == 0 )
                if ( sendto ( sockfd, msg, msgsize, 0, (struct sockaddr *) &addr, sizeof ( addr ) ) < 0 )
                    err = errno;

        close ( sockfd );

        res = res->ai_next;
    }

    freeaddrinfo ( ressave );
    return err;
}

int
joinGroup(int sockfd, int loopBack, int mcastTTL,
         struct sockaddr_storage *addr)
{
    int r1, r2, r3, retval;

    retval=-1;

    switch (addr->ss_family) {
        case AF_INET: {
            struct ip_mreq      mreq;

            mreq.imr_multiaddr.s_addr=
            ((struct sockaddr_in *)addr)->sin_addr.s_addr;
            mreq.imr_interface.s_addr= INADDR_ANY;

            r1= setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
                           &loopBack, sizeof(loopBack));
            if (r1<0)
                perror("joinGroup:: IP_MULTICAST_LOOP:: ");

            r2= setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
                           &mcastTTL, sizeof(mcastTTL));
            if (r2<0)
                perror("joinGroup:: IP_MULTICAST_TTL:: ");

            r3= setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                           (const void *)&mreq, sizeof(mreq));
            if (r3<0)
                perror("joinGroup:: IP_ADD_MEMBERSHIP:: ");

        } break;

        case AF_INET6: {
            struct ipv6_mreq    mreq6;

            memcpy(&mreq6.ipv6mr_multiaddr,
                   &(((struct sockaddr_in6 *)addr)->sin6_addr),
                   sizeof(struct in6_addr));

            mreq6.ipv6mr_interface= 0; // cualquier interfaz

            r1= setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
                           &loopBack, sizeof(loopBack));
            if (r1<0)
                perror("joinGroup:: IPV6_MULTICAST_LOOP:: ");

            r2= setsockopt(sockfd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
                           &mcastTTL, sizeof(mcastTTL));
            if (r2<0)
                perror("joinGroup:: IPV6_MULTICAST_HOPS::  ");

            r3= setsockopt(sockfd, IPPROTO_IPV6,
                           IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6));
            if (r3<0)
                perror("joinGroup:: IPV6_ADD_MEMBERSHIP:: ");

        } break;

        default:
            r1=r2=r3=-1;
    }

    if ((r1>=0) && (r2>=0) && (r3>=0))
        retval=0;

    return retval;
}

欢迎大家的想法!

-Tim

EN

回答 1

Stack Overflow用户

发布于 2015-10-14 00:36:26

经过与苹果公司的反复讨论,以及一些额外的背景,我们有了一个答案。但这不是我最初问题的答案。首先,这里是上下文的Apple线程:

https://forums.developer.apple.com/message/71107

事实证明,我们实际上并不需要IPv6多播来解决手头的实际问题-即在本地Wi-Fi网络上查找遗留嵌入式设备。我们真的不得不使用IPv4 UDP广播来做到这一点。我们的嵌入式设备会忽略IPv6多播包,就像地球会忽略飞过它的中微子一样。

苹果公司给了我们一个setsockopt()调用,使IPv4 UDP广播能够在基础设施Wi-Fi网络上的iOS 9中工作。这就是此功能的预期用例。苹果还给了我们一个可能的失败原因,当广播在Ad Hoc Wi-Fi网络上无法工作时(这似乎是一个已知的iOS 9问题)。

因此,虽然我最初的问题没有在这里得到回答,但潜在的问题已经解决了。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32912042

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档