iOS 14.0.1 UDP receive

We recently fixed an issue with not being able to receive udp with iOS 14 update. With iOS 14.0.1 this issue has started again.

We can receive udp within the Xcode debug however once published to TestFlight or store it no longer will receive data. We are using Cocoa Open Library GCDAsyncSocket. I will post code below.

We are very confused about the Local Network Privacy that has been added and the multicast entitlement. We are only receiving udp not broadcasting and also not multicasting. From my understanding the Local Network Privacy is not needed to just receive udp. The fact that it works in debug and not within TestFlight or Store makes me wonder if this is not the case and it's a permission issue. I added in the Local Privacy Network into the info.plist to verify and it still does not work. However I do not get a popup requesting permission nor do I see the app under the settings local privacy.

Is the local privacy network needed if you are only receiving udp not through bonjour services but through GCDAsyncSocket. Do I need to request the multicasting entitlement and how do I go about doing this?

This was working in 14.0.0 in the store version. It no longer works in 14.0.1

This is a small snipped of the code being used.

        udpSocket = [[GCDAsyncUdpSocket alloc]initWithDelegate:self delegateQueue:dispatchgetmain_queue()];

        NSError *error = nil;

        if (![udpSocket bindToPort:GPSRecievePort error:&error])
        {
            NSString *ErrorMessage = [NSString stringWithFormat:@"ViewDidLoad : udp BindtoPort - %@", error];

            ErrorMessage = [ErrorMessage stringByReplacingOccurrencesOfString:@"\"" withString:@""];

            [self ErrorGPS:ErrorMessage];

            NSLog(@"Error binding: %@", error);

            [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(Connect) userInfo:nil repeats:NO];

            NSLog(@"GPS Reconnect");
            GPSConnected = false;
            return;
        }

        else
        {
            if(![udpSocket beginReceiving:&error])

            {
                NSString *ErrorMessage = [NSString stringWithFormat:@"ViewDidLoad : udp BindtoPort - %@", error];

            }
        }
Answered by Bnjbel97 in 640833022
The issue was the Local Privacy Network dialog not showing. I was a bit unclear on this. I didn't believe this was needed to receive UDP but in our case it seems it is required. This is using the CocoaAsyncSocket library GCDAsyncUdpSocket. We discovered this when a gentleman was testing on a local host. The app uses both tcp/ip for some communication and udp for external gps. The tcp/ip communication on the local network triggered the dialog I believe since it does have outgoing messaging. When accepting the UDP receive started working. I did see there was a bug that is noted that only outgoing messaging on the local network will trigger the local privacy network dialog. To resolve we just access the local hostname which triggers the dialog.

I have not delved into the GCDAsyncUdpSocket library nor a network expert by any means. We are binding to a specific known port to listen. It is possible that this is maybe something underlining within the library we are using. This may not be a thing with NSConnection. I do agree with tts320 that maybe just binding to the port should trigger this dialog as well. It seems everything but the receive on unicast requires it. Also I didn't see a good way, similar to internal GPS, when the dialog appears handling a callback to know exactly if it was authorized or not. This may be different with NWConnection. I have not looked at that completely and is something we may move to in the future but currently just need it to work.

Thank you for your help and comments with this.
OK, let’s start with one clarification: If you’re just doing UDP unicast you do not need the multicast entitlement (com.apple.developer.networking.multicast).

As to what’s going on with your UDP receive code, let’s start with some factoids:
  • Using NWListener to listen for incoming TCP connections does not require local network access. If you start a listener and someone connects to it then the connection will go through without even triggering the local network privacy alert.

  • This is also true when you listen for incoming TCP connections using BSD Sockets.

  • And for when you use NWListener in UDP mode.

Just to be sure I retested these statements using a test device in my office.

As far as using BSD Sockets to listen for UDP ‘connections’, I believe that it behaves like NWListener. I’ve tested that in the past but I’m not able to retest it today.

As to what’s going on with your app, it’s hard to say without knowing more about the third-party library you’re working with. You have a couple of options here:
  • You can seek help from the library’s vendor to see if they can work out what’s going wrong between their code and Apple’s APIs.

  • Alternatively, you can do the same yourself by digging through the library code.

Once you have work out what’s going wrong at the BSD Sockets layer, post the details here and I’ll take another look.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Unlike the OP's, my app is receiving UDP multicast, but not transmitting anything either. To make it work in iPadOS 14.0.1 I requested the multicast special entitlement and performed the steps according to Quinn's excellent instructions. However, there was no prompt for the user to allow the Local network access, and the app did not receive the UDP multicast. Only after adding a call to open an UDP socket and send data from iPad there was the prompt asking for Local network access. After giving access, the app started receiving UDP multicast. If the permission is then switched off via Settings/Privacy/Local Network, the UDP multicast is no longer received.

Since granting access by the user seems to be a requirement, in my opinion iPadOS should prompt for local network access even when the user is just binding to an UDP port to receive data.

I am using GCDAsyncUdpSocket from CocoaAsyncSocket.
You can try to turn off the private address of WiFi

Accepted Answer
The issue was the Local Privacy Network dialog not showing. I was a bit unclear on this. I didn't believe this was needed to receive UDP but in our case it seems it is required. This is using the CocoaAsyncSocket library GCDAsyncUdpSocket. We discovered this when a gentleman was testing on a local host. The app uses both tcp/ip for some communication and udp for external gps. The tcp/ip communication on the local network triggered the dialog I believe since it does have outgoing messaging. When accepting the UDP receive started working. I did see there was a bug that is noted that only outgoing messaging on the local network will trigger the local privacy network dialog. To resolve we just access the local hostname which triggers the dialog.

I have not delved into the GCDAsyncUdpSocket library nor a network expert by any means. We are binding to a specific known port to listen. It is possible that this is maybe something underlining within the library we are using. This may not be a thing with NSConnection. I do agree with tts320 that maybe just binding to the port should trigger this dialog as well. It seems everything but the receive on unicast requires it. Also I didn't see a good way, similar to internal GPS, when the dialog appears handling a callback to know exactly if it was authorized or not. This may be different with NWConnection. I have not looked at that completely and is something we may move to in the future but currently just need it to work.

Thank you for your help and comments with this.
Bnjbel97
Could you provide example code of how to trigger the Local Network Privacy dialog using the CocoaAsyncSocket library?

Could you provide example code of how to trigger the Local Network
Privacy dialog using the CocoaAsyncSocket library?

You don’t need a third-party library for this. Rather, check out FAQ-8 in the Local Network Privacy FAQ.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"

You don’t need a third-party library for this. Rather, check out FAQ-8 in the Local Network Privacy FAQ.

I copied the code exactly as it appeared in Triggering the Local Network Privacy Alert and added a print statement for each address just to see it something was being sent. The triggerLocalNetworkPrivacyAlert() looped over 4 addresses and still no privacy dialog was produced.
iOS 14.0.1 UDP receive
 
 
Q