2015-10-02 21 views
10

Apple ora richiede che le app iOS 9 siano conformi a IPv6. Siamo per lo più OK, tranne che per un bit di codice che invia una trasmissione UDP, che ora non funziona in iOS 9.È necessario il codice multicast C IPv6 che funziona su iOS 9

Tutto ciò che ho letto mi dice che UDP multicast è il modo giusto per farlo in IPv6. Ho trovato codice di esempio, ma non funziona su alcuna versione di iOS o Mac OS X che ho provato.

Questo codice viene chiamato da una libreria C/C++ all'interno del nostro programma - difficile effettuare una richiamata in Swift, Obj-C, Java, ecc. E questo codice verrà condiviso da una versione Mac OS X e Android di la nostra app. Si potrebbe pensare che sia possibile eseguire il multicast IPv6 in C in qualsiasi ambiente POSIX!

Nell'esempio seguente, l'esecuzione ha esito positivo fino alla chiamata sendto() finale, che in realtà invia il messaggio UDP. Quel sendto() fallisce, con errno impostato su EBROKENPIPE (22) dopo l'errore.

La mia ipotesi migliore è che mi manca qualche chiamata setsockopt() o sto usando l'indirizzo multicast sbagliato. In questo momento, sono perplesso.

Ecco la chiamata di funzione che sto facendo (per multicast "C'è qualcuno là fuori?" Sulla porta UDP 4031):

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

Ecco il codice che viene chiamato:

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

Pensieri benvenuti!

-Tim

+2

Una cosa da considerare è che il multicast IPv6 utilizza flag, ambiti e intervalli che è davvero necessario ottenere correttamente. Ad esempio, l'intervallo 'FF01 ::/112' è un ambito locale del nodo, ma suppongo che tu stia cercando un ambito locale di collegamento come' FF02 ::/112'. –

+0

Ho provato FF02 :: 1 e FF02: 1111. Stesso risultato: sendto() restituisce -1, errno impostato su 22 (EBROKENPIPE). Stiamo entrambi indovinando qui. Qualcun altro ha implementato il multicast su iOS 9? –

+0

Tutto quello che stavo dicendo è che devi fare attenzione sull'indirizzo multicast che scegli. Non so che l'ambito locale del link sia corretto per quello che stai cercando di fare (quell'ambito non lascerà il link, come il nodo-scope locale non lascerà il nodo). Se si guarda, FF02 :: 1 è l'indirizzo Tutti i nodi. È necessario che IPv6 sia configurato sugli host e sulla rete in cui si sta tentando di testarlo (essere in grado di eseguire il ping tramite gli indirizzi unicast IPv6).Quindi è necessario studiare le RFC multicast IPv6 per fare una selezione di gruppo intelligente piuttosto che un hit-or-miss che sembra provate. –

risposta

6

Dopo un po 'avanti e indietro con Apple, e alcuni contesto aggiuntivo, abbiamo una risposta. Ma non è la risposta alla mia domanda originale. In primo luogo, ecco il filo di Apple per il contesto:

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

Si scopre che IPv6 multicast in realtà non era quello che ci serviva per risolvere il vero problema a portata di mano - vale a dire, trovando dispositivo embedded un'eredità su una Wi-locale Rete Fi Abbiamo davvero dovuto usare la trasmissione UDP IPv4 per farlo. Il nostro dispositivo incorporato ignora i pacchetti multicast IPv6 come la Terra ignora i neutrini che lo attraversano.

Apple ci ha fornito una chiamata setsockopt() che abilita la trasmissione UDP IPv4 a funzionare su iOS 9 su una rete Wi-Fi di infrastruttura. Questo è il caso d'uso previsto per questa funzione. E Apple ci ha anche fornito una probabile causa di errore quando quella trasmissione non funzionava in una rete Wi-Fi Ad Hoc (che sembra essere un problema noto di iOS 9).

Quindi, anche se la mia domanda originale non ha trovato risposta qui, il problema sottostante è stato risolto.