tvOS 14.6 fails trying to bind UDP/1900 (succeeds on tvOS Simulator)

I'm working on a tvOS app/library which uses SSDP. The code binds a UDP socket to port 1900 and joins a multicast group using BSD Socket library. I believe this used to work on a previous tvOS version, but specifically as of tvOS 14.6 there is a divergence between the tvOS Simulator and actual devices. Actual devices fail at the call to bind, with an Address Already in Use error. The tvOS simulator binds just fine after throwing up a macOS firewall 'allow incoming connections' dialog.

Any ideas what the official situation is here? The com.apple.developer.networking.multicast entitlement seems to be iOS only at this time, is that correct? Also there seems to be no 'local networking' permission dialog in tvOS - is that also correct?

The com.apple.developer.networking.multicast entitlement seems to be iOS only at this time, is that correct?

That’s correct.

I’m not sure what’s going on with your code. My experience is that the multicast APIs are very easy to use incorrectly, in a way that works in some environments and then fails in others. However, there’s no guarantee that’s what’s going on here.

First things first, lets rule out a port number issue: If you temporarily change the code to use some other port, does that work?

Share and Enjoy

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

@eskimo thanks for the reply - yes I confirmed that after changing the port number to 19000 instead of 1900 (on both my Client iOS App and tvOS server app) it does indeed work correctly. And it works correctly on the tvOS simulator using the correct SSDP port (1900), and I can see the port bound in lsof when it's running:

MyTVApp      76639 ikura    5u  IPv4 0x5f8914619e22755b      0t0  UDP *:ssdp

Here's my code block where the bind fails, it's using GCDAsyncSockets:

// MARK: Socket Setup

        let multicastSocket = GCDAsyncUdpSocket(delegate: self, delegateQueue: DispatchQueue.main)
        multicastSocket.setIPv6Enabled(false)

        do {
            try multicastSocket.enableReusePort(true)
            try multicastSocket.bind(toPort: 1900) // On AppleTV 4K tvOS14.6 this throws with 'Address in Use' error
            try multicastSocket.joinMulticastGroup("239.255.255.250")
            try multicastSocket.enableBroadcast(true)
            try multicastSocket.beginReceiving()
        } catch {
            multicastSocket.close()
            DispatchQueue.main.async {
                for observer in self.observers {
                    observer.multicastSocketInitialisationFailed(error: error)
                }
            }
        }

        self.multicastSocket = multicastSocket

First up, when working with gnarly networking problems you should always test on a real device. The simulator is a great tool for day-to-day debugging but it not relevant for problems like this.

Second, the fact that changing the port fixes things confirms my understanding that tvOS does not require the multicast entitlement.

It also suggests, along with the EADDRINUSE error, that the real issue here is that something else on the Apple TV is using that port. It sounds like that’s a major source of grief for your app, in which case you should definitely file a bug about it.

Please post your bug number, just for the record.

Share and Enjoy

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

tvOS 14.6 fails trying to bind UDP/1900 (succeeds on tvOS Simulator)
 
 
Q