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