2015-10-02 6 views
10

Appleは現在、iOS 9アプリをIPv6に準拠させる必要があります。 UDPブロードキャストを送信するコードを除いてほとんどOKですが、これはiOS 9で失敗します。iOS 9で動作するIPv6マルチキャストCコードが必要です

IPv6でこれを行うには、UDPマルチキャストが正しい方法です。私はいくつかのサンプルコードを見つけましたが、私が試したiOSまたはMac OS Xのどのバージョンでも動作しません。

このコードはSwift、Obj-C、Javaなどのコールバックを作成するのが難しいプログラム内のC/C++ライブラリから呼び出されています。このコードはMac OS XおよびAndroidバージョンの私たちのアプリ。 POSIX環境でCでIPv6マルチキャストを行うことは可能でしょうか?

以下のサンプルでは、​​実際にUDPメッセージを送信する最後のsendto()呼び出しまで実行が成功します。そのsendto()は失敗し、失敗後にerrnoはEBROKENPIPE(22)に設定されます。

私はいくつかの必要なsetsockopt()コールが不足しているか、間違ったマルチキャストアドレスを使用していると思います。今、私は困惑しています。ここで

は、関数呼び出し、私が作ってるんだ(マルチキャストには、「そこに誰か」UDPポート4031上で)です:

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

char *msg = "Is anybody out there?"; 
err = multicast_udp_msg ("FF01::1111", 4031, msg, strlen(msg)); 

ここで呼び出されているコードです思考は歓迎! Appleといくつかの前後、およびいくつかの追加のコンテキストの後

+2

IPv6マルチキャストは、本当に必要なフラグ、スコープ、範囲を使用するということを考えてください。例えば、 'FF01 ::/112'はノードローカルスコープですが、' FF02 ::/112'のようなリンクローカルスコープを本当に探していると思います。 –

+0

私はFF02 :: 1とFF02:1111を試しました。同じ結果:sendto()は-1を返し、errnoは22(EBROKENPIPE)に設定します。私たちはどちらもここで推測しています。他の誰かがiOS 9でマルチキャストを実装していますか? –

+0

私が言っていたのは、あなたが選んだマルチキャストアドレスに注意する必要があるということでした。私は、リンクローカルスコープがあなたがやっていることが正しいことを知らない(そのスコープはリンクを離れず、ノードローカルスコープがノードを離れることはない)。あなたが見た場合、FF02 :: 1はAll Nodesアドレスです。これをテストしようとしているホストやネットワーク上でIPv6を設定する必要があります(IPv6ユニキャストアドレス経由でpingできるようにする必要があります)。次に、IPv6マルチキャストRFCを研究して、あなたが試みているようなヒットミスではなくインテリジェントなグループ選択を行う必要があります。 –

答えて

6

-Tim

、我々は答えを持っています。しかし、それは私の元の質問に対する答えではありません。まず、ここでのコンテキストのためのアップルのスレッドがあります: - ローカルWi-にレガシー組み込みデバイスを見つけること、すなわち

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

これは、IPv6マルチキャストは、私たちが手元に実際の問題を解決するために必要なものを実際にはなかったことが判明しますFiネットワーク。私たちは実際にIPv4 UDPブロードキャストを使用しなければなりませんでした。私たちの組み込み機器は、地球がそれを飛んでいるニュートリノを無視するようなIPv6マルチキャストパケットを無視します。

アップルは、インフラストラクチャWi-Fiネットワーク上でIPv4 UDPブロードキャストをiOS 9で動作させるsetsockopt()コールを提供しました。それがこの機能の意図されたユースケースです。また、AppleがアドホックWi-Fiネットワーク(iOS 9の既知の問題と思われる)でそのブロードキャストが動作しなくなった場合、失敗の原因として考えていた。

私の元の質問には答えられていませんが、根本的な問題は解決されています。

関連する問題