1

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.)

Adam Wilt
  • 553
  • 4
  • 10
  • UPnP says it can use DNS to resolve things: > If during the DHCP transaction, the device obtains a domain name, for example, through a DNS server or via DNS forwarding, the device should use that name in subsequent network operations; otherwise, the device should use its IP address. **https://en.wikipedia.org/wiki/Universal_Plug_and_Play#Protocol** – Kristopher Ives Dec 22 '17 at 03:23

1 Answers1

0

I haven't been able to figure out why this is happening: it affects at least two people on T-Mobile in Florida and California, but I can't replicate it using T-Mobile in Washington.

I did find a fix: replace connectToHost with connectToAddress, which connects to the IPv4 address directly without a DNS resolution step. While connectToHost allows either a hostname or an IP address, it runs a DNS lookup step even with an IP address, and that lookup was getting confounded by whatever was occurring when the affected iDevices were connected to T-Mobile.

Adam Wilt
  • 553
  • 4
  • 10