2015-10-02 21 views
10

Apple wymaga teraz, aby aplikacje iOS 9 były zgodne z IPv6. W większości jesteśmy w porządku, z wyjątkiem fragmentu kodu, który wysyła transmisję UDP - teraz kończy się niepowodzeniem w iOS 9.Potrzebujesz IPv6 Multicast C kod, który działa na iOS 9

Wszystko, co czytam, mówi mi, że multicast UDP jest właściwą drogą do wykonania tego w IPv6. Znalazłem przykładowy kod, ale nie działa on na żadnej wersji systemu iOS lub Mac OS X, której próbowałem.

Ten kod jest wywoływany z biblioteki C/C++ wewnątrz naszego programu - trudne do wywołania zwrotnego w Swift, Obj-C, Java itp. Kod ten będzie udostępniany przez system Mac OS X i wersję Androida nasza aplikacja. Można by pomyśleć, że można przeprowadzić multicast IPv6 w C w dowolnym środowisku POSIX!

W poniższym przykładzie wykonanie kończy się sukcesem aż do ostatecznego wywołania sendto(), które faktycznie wysyła komunikat UDP. Ta funkcja sendto() kończy się niepowodzeniem, z errno ustawionym na EBROKENPIPE (22) po awarii.

Moim najlepszym przypuszczeniem jest to, że brakuje mi jakiegoś wymaganego wywołania setsockopt() lub używam niewłaściwego adresu multiemisji. W tej chwili jestem zaskoczony.

Oto wywołanie funkcji Robię (do multicast "Czy ktoś tam jest?" Na port UDP 4031):

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

Oto kod, który jest nazywany:

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

Myśli mile widziane!

-Tim

+2

Jedną z rzeczy, o której trzeba pomyśleć, jest to, że multiemisja IPv6 używa flag, zakresów i zakresów, które naprawdę muszą być poprawne. Na przykład zakres 'FF01 ::/112' jest zasięgiem lokalnym węzła, ale domyślam się, że naprawdę szukasz zasięgu lokalnego, takiego jak' FF02 ::/112'. –

+0

Próbowałem FF02 :: 1 i FF02: 1111. Ten sam wynik: sendto() zwraca -1, errno jest ustawione na 22 (EBROKENPIPE). Oboje tylko zgadujemy. Czy ktoś jeszcze zaimplementował multicast na iOS 9? –

+0

Wszystko, co mówiłem, to to, że musisz uważać na wybrany adres multiemisji. Nie wiem, czy zasięg łącza lokalnego jest poprawny dla tego, co próbujesz zrobić (zakres ten nie opuści łącza, tak jak zasięg lokalny węzła nie opuści węzła). Jeśli spojrzeć, FF02 :: 1 jest adresem wszystkich węzłów. Musisz mieć skonfigurowany IPv6 na hostach i w sieci, w której próbujesz to sprawdzić (możesz pingować przez adresy emisji pojedynczej IPv6).Następnie należy przestudiować specyfikacje RFC multiemisji IPv6, aby dokonać inteligentnego wyboru grupy, a nie trafienia, które wydaje się próbować. –

Odpowiedz

6

Po pewnym back-i-dalej z Apple, a niektóre dodatkowego kontekstu, mamy odpowiedź. Ale to nie jest odpowiedź na moje oryginalne pytanie. Po pierwsze, tutaj jest wątek Jabłko dla kontekstu:

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

Okazuje się, że multicast IPv6 nie był rzeczywiście to, co potrzebne, aby rozwiązać poważny problem pod ręką - a mianowicie znalezienie starszego wbudowanego urządzenia na lokalnym Wi- Sieć Fi. Aby to zrobić, musieliśmy użyć broadcast IPv4 UDP. Nasze urządzenie wbudowane ignoruje pakiety multiemisji IPv6, tak jak Ziemia ignoruje przelatujące przez nie neutriny.

Apple dało nam wywołanie setsockopt(), które umożliwiło emisje IPv4 UDP do pracy w systemie iOS 9 w infrastrukturze sieci Wi-Fi. To jest zamierzony przypadek użycia dla tej funkcji. A Apple również dał nam prawdopodobną przyczynę niepowodzenia, gdy transmisja nie zadziałała w sieci Wi-Fi Ad Hoc (wydaje się, że jest to znany problem z iOS 9).

Tak więc, chociaż moje oryginalne pytanie nie zostało tu udzielone, podstawowa kwestia została rozwiązana.