Transmisión de networking / multidifusión no enviada por iPhone en modo de punto de acceso personal

Con base en los hallazgos empíricos recientes y basados ​​en varias publicaciones en la web, parece que una aplicación que se ejecuta en un iPhone con un punto de acceso personal habilitado no puede enviar transmisiones y / o múltiples canales a la networking del punto de acceso personal. ¿Alguien puede arrojar luz sobre la causa de este problema?

La aplicación

Tengo una aplicación IOS, construida con código C ++ multiplataforma, que difunde y multiplica su presencia en la networking en la que se ejecuta. La aplicación funciona impecablemente cuando el iPhone está conectado a una networking Wi-Fi. En este caso, otros dispositivos en la networking reciben las transmisiones / multidifusiones, y todo funciona correctamente. Esto se puede verificar fácilmente conectando una computadora que ejecuta WireShark a la networking: los packages de transmisión / multidifusión se pueden ver en la traza de packages.

Huelga decir que la aplicación funciona bien en un iPhone conectado a un Wi-Fi local.

El problema

Cuando ejecuto la aplicación en un iPhone que tiene habilitado su punto de acceso personal, no se emiten transmisiones / multidifusiones en la networking de punto de acceso. Esto se puede verificar con WireShark, que no muestra dichos packages en su traza.

¿Hay alguna restricción con respecto al uso de un punto de acceso personal como un enrutador de networking capaz de manejar transmisiones y multidifusiones?

Cuando solicité una página web en mi dispositivo "WireSharking" usando un browser, el punto de acceso personal responde correctamente a todos los packages, devolviendo los contenidos web.

Información queueteral

Me he encontrado con otros pasados ​​de desbordamiento de stack que informan sobre problemas similares o similares:

  1. La connection TCP no funciona correctamente al usar iPhone como punto de connection.
  2. No se puede enviar la transmisión de ssdp por punto de acceso personal.

Un buen tutorial para escribir una aplicación de transmisión / multidifusión de este tipo en iPhone es " The Making of Talkie: Multifunction broadcasting and multicast " de Michael Tyson. Baste con decir que mi aplicación cumple con todos los requisitos (p. Ej., Configurar las opciones de socket SO_BROADCAST, SO_DONTROUTE e IP_MULTICAST_IF cuando corresponda).

Una respuesta a la reference (1) anterior escribe " ¿Podría ser porque el punto de acceso personal introduce la Traducción de direcciones de networking? ". Filtré las huellas de WireShark para mostrar solo los packages conectados a la IP del punto de acceso, y no hay evidencia de que el punto de acceso personal envíe nada a una dirección NAT.

En resumen

¿Alguien puede explicar por qué un iPhone con un punto de acceso personal no emite packages de multidifusión, y cómo resolver el problema?

Muchas gracias de antemano.

Tengo trabajo de transmisión (en iOS 10)

Estoy publicando una segunda respuesta, porque encontré una manera de transmitir el trabajo en iOS 10 en el modo de acceso personal. la solución es un poco compleja, pero así es como lo conseguí funcionar:

  1. use getifaddrs(if) para recorrer todas las interfaces ( do {} while (if = if->ifa_next) )
  2. rechazar interfaces de bucle invertido ( if->ifa_flags & IFF_LOOPBACK )
  3. solo filtrar las interfaces que admiten la difusión ( if->ifa_flags & IFF_BROADCAST )
  4. crear un socket con int sock = socket()
  5. Habilitar difusión: int yes = 1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes) int yes = 1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes)
  6. conéctese a la dirección de transmisión: connect(sock, if->ifa_dstaddr, if->ifa_dstaddr->sa_len)
  7. ahora use send() para enviar su post!

He confirmado que esto funciona tanto cuando el iPhone está conectado a una networking Wi-Fi, como cuando está en modo punto de acceso personal.

Código de muestra completa

 #include <ifaddrs.h> #include <arpa/inet.h> #include <net/if.h> -(IBAction)sayHello:(id)sender { // fetch a linked list of all network interfaces struct ifaddrs *interfaces; if (getifaddrs(&interfaces) == -1) { NSLog(@"getifaddrs() failed: %s", strerror(errno)); return; } // loop through the linked list for(struct ifaddrs *interface=interfaces; interface; interface=interface->ifa_next) { // ignore loopback interfaces if (interface->ifa_flags & IFF_LOOPBACK) continue; // ignore interfaces that don't have a broadcast address if (!(interface->ifa_flags & IFF_BROADCAST) || interface->ifa_dstaddr == NULL) continue; // check the type of the address (IPv4, IPv6) int protocol_family; struct sockaddr_in ipv4_addr = {0}; struct sockaddr_in6 ipv6_addr = {0}; struct sockaddr *addr; if (interface->ifa_dstaddr->sa_family == AF_INET) { if (interface->ifa_dstaddr->sa_len > sizeof ipv4_addr) { NSLog(@"Address too big"); continue; } protocol_family = PF_INET; memcpy(&ipv4_addr, interface->ifa_dstaddr, interface->ifa_dstaddr->sa_len); ipv4_addr.sin_port = htons(16000); addr = (struct sockaddr *)&ipv4_addr; char text_addr[255] = {0}; inet_ntop(AF_INET, &ipv4_addr.sin_addr, text_addr, sizeof text_addr); NSLog(@"Sending message to %s:%d", text_addr, ntohs(ipv4_addr.sin_port)); } else if (interface->ifa_dstaddr->sa_family == AF_INET6) { if (interface->ifa_dstaddr->sa_len > sizeof ipv6_addr) { NSLog(@"Address too big"); continue; } protocol_family = PF_INET6; memcpy(&ipv6_addr, interface->ifa_dstaddr, interface->ifa_dstaddr->sa_len); ipv6_addr.sin6_port = htons(16000); addr = (struct sockaddr *)&ipv6_addr; char text_addr[255] = {0}; inet_ntop(AF_INET6, &ipv6_addr.sin6_addr, text_addr, sizeof text_addr); NSLog(@"Sending message to %s:%d", text_addr, ntohs(ipv6_addr.sin6_port)); } else { NSLog(@"Unsupported protocol: %d", interface->ifa_dstaddr->sa_family); continue; } // create a socket int sock = socket(protocol_family, SOCK_DGRAM, IPPROTO_UDP); if (sock == -1) { NSLog(@"socket() failed: %s", strerror(errno)); continue; } // configure the socket for broadcast mode int yes = 1; if (-1 == setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes)) { NSLog(@"setsockopt() failed: %s", strerror(errno)); } // create some bytes to send NSString *message = @"Hello world!\n"; NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding]; if (-1 == connect(sock, addr, addr->sa_len)) { NSLog(@"connect() failed: %s", strerror(errno)); } // send the message ssize_t sent_bytes = send(sock, data.bytes, data.length, 0); if (sent_bytes == -1) { NSLog(@"send() failed: %s", strerror(errno)); } else if (sent_bytes<data.length) { NSLog(@"send() sent only %d of %d bytes", (int)sent_bytes, (int)data.length); } // close the socket! important! there is only a finite number of file descriptors available! if (-1 == close(sock)) { NSLog(@"close() failed: %s", strerror(errno)); } } freeifaddrs(interfaces); } 

Este método de muestra emite un post UDP en el puerto 16000.

Para la debugging, puede usar la herramienta socat . Simplemente ejecute el siguiente command en su computadora (que debe estar en la misma networking que el teléfono):

 socat UDP-RECV:16000 STDOUT 

Solución rápida y sucia

También encontré el mismo problema al desarrollar una aplicación de iPhone que utiliza un post de multidifusión UDP para descubrir dispositivos en la networking. Al parecer, el iPhone bloquea los posts de multidifusión en el modo de punto de acceso personal.

Sin embargo, el iPhone parece usar la subnetworking 172.20.10.0/28 para dispositivos en la networking de puntos de acceso personal. Esto significa que solo hay 16 direcciones posibles. De estos, 172.20.10.0 aparentemente no se utiliza, 172.20.10.1 es el iPhone en sí, y el envío de posts a 172.20.10.15 falla con un error "no permitido". Esto significa que solo los siguientes clientes pueden utilizar las siguientes 13 direcciones: 172.20.10.2 , 172.20.10.3 , …, 172.20.10.14 .

Así que mi trabajo es bastante simple: en lugar de enviar posts de difusión solo a 224.0.0.0 , también los envío a todas las otras direcciones posibles en la subnetworking ( 172.20.10.2172.20.10.14 ).

Por supuesto, para estar a testing del futuro en una aplicación de producción probablemente deberías revisar la list de interfaces de networking, verificar la IP y la subnetworking, etc., pero para mi uso personal este método es suficiente.