I've got an iPhone app that makes UPnP queries over Wi-Fi to locate a Wi-Fi-connected camera, using GCDAsyncSocket. All the communications use IPv4 addresses over an ad-hoc network created by the cameras themselves, and the app is working properly with over 2500 field deployments.
However I have one customer for whom it fails on his iPhone, unless Airplane Mode is on, or cellular data is turned off. The same camera works fine with his iPad mini, so it's not the camera's fault as best we can determine.
The app sets up a listening socket:
_listenSocket = [[GCDAsyncSocket alloc] initWithDelegate:self
delegateQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)];
_listenSocket.IPv6Enabled = NO;
accepted = [_listenSocket acceptOnInterface:getWirelessInterface()
port:_upnpPort error:&error];
It then sets up a sending socket, also with IPV6 disabled; connects to the host (at a known or suspected IP address) over the wireless interface; and sends a UPnP SUBSCRIBE message:
_sendSocket = [[GCDAsyncSocket alloc] initWithDelegate:self
delegateQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)];
if (!_sendSocket) {
NSLog(@"sendMsg: unable to allocate sendSocket");
return;
}
_sendSocket.IPv6Enabled = NO;
NSError *err = nil;
if (![_sendSocket connectToHost:hostParts[0]
onPort:[hostParts[1] intValue]
viaInterface:getWirelessInterface()
withTimeout:TIMEOUT
error:&err]) // Asynchronous!
{
// If there was an error, it's likely something like
// "already connected" or "no delegate set"
NSLog(@"socket connectToHost error: %@", err);
return;
}
[_sendSocket writeData:[msg dataUsingEncoding:NSUTF8StringEncoding] withTimeout:TIMEOUT tag:1];
Normally, this works as expected. However, in this one case, the send fails; the delegate method socketDidDisconnect:withError: gets called:
sendSocket disconnected with error: Error Domain=GCDAsyncSocketErrorDomain
Code=8 "IPv6 has been disabled and DNS lookup found no IPv4 address."
If I delete the "xxxSocket.IPv6Enabled = NO;" lines, I get this instead:
listenSocket disconnected with error: Error Domain=NSPOSIXErrorDomain
Code=65 "No route to host"
Various Googlings indicate that "no route to host" indicates an IPv4 address can't be resolved in an IPv6 environment, and the "IPv6 has been disabled and DNS lookup found no IPv4 address" message is self-explanatory.
Why is this happening on this one iPhone, and not on all the others out there (including my own test instruments)? How might I fix it, aside from saying "turn cellular data off"? Why is DNS even involved, if I'm using the IPv4 address of the very router (ad-hoc access point) I've already connected to to get the network running in the first place?
(One other stackoverflow post (GCDAsyncUdpSocket immediately closes when sending to an IPv6 address) suggested retrying until things worked, but I haven't had any success with that.)