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
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'. –
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? –
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. –