Network Framework Broadcast Support

Hi all,

I am overhauling code of an iPadOS app that discovers devices on a network using a custom UDP broadcast based discovery protocol.

This is how the discovery mechanism should work: The iPad sends an IPv4 broadcast message to the network's broadcast address using a fixed destination port, but a random source port (determined at bind time). The device responds with a unicast message to the source IP address and port of the discovery message.

Until now the code is based on BSD sockets using GCDAsyncUdpSocket and has been working well for around ten years with a single socket that was used to both send and receive the discovery messages and replies.

We would like to make the move to the Network Framework now and I tried to recreate this discovery mechanism with the Network Framework in Objective-C.

I am able to create an nw_connection_t with the broadcast address as hostname and the specific destination port as port. I am able to send discovery messages to the device and the device sends a reply (verified with Wireshark). But calling nw_connection_receive_message(...) never fires. Also in Wireshark the iPad replies with Destination unreachable (Port unreachable).

When I create the connection with the unicast address of the device, the reply is received.

It seems to me, that the connection doesn't accept replies from addresses / ports that don't match, what was set when the connection was created. Is there a way to also accept messages from other sources? E.g. there is nw_multicast_group_descriptor_set_disable_unicast_traffic when doing multicast. This seems to solve this problems when doing mutlicast.

This is a code excerpt of what I tried:

// Create default UDP parameters without DTLS
nw_parameters_t params = nw_parameters_create_secure_udp(NW_PARAMETERS_DISABLE_PROTOCOL, NW_PARAMETERS_DEFAULT_CONFIGURATION);
// Enable P2P (should enable broadcast and multicast)
nw_parameters_set_include_peer_to_peer(params, true);
// Require the active interface
// The active interface comes from a path monitor callback
nw_parameters_require_interface(params, self.networkUtils.activeInterface.interface);
          
// Setup the remote endpoint with the "ping" (discovery) broadcast IP address and port
const char *endpointAddress = [pingAddress.ipAddress cStringUsingEncoding:NSUTF8StringEncoding];
NSString *portString = @(pingAddress.port).stringValue;
const char *endpointPort = [portString cStringUsingEncoding:NSUTF8StringEncoding];
nw_endpoint_t broadcastEndpoint = nw_endpoint_create_host(endpointAddress, endpointPort);
            
nw_connection_t tmpConnection = nw_connection_create(broadcastEndpoint, params);
__weak __typeof(self) weakSelf = self;
nw_connection_set_state_changed_handler(tmpConnection, ^(nw_connection_state_t state, nw_error_t  _Nullable error) {
    __strong __typeof(weakSelf) strongSelf = weakSelf;
    MSLogVerbose("State changed: %d; error: %@", state, error);
    strongSelf.connectionState = state;
    if (state == nw_connection_state_ready) {
        [strongSelf receiveMessageForConnection:tmpConnection];
     }
});
nw_connection_set_queue(tmpConnection, AGGalileoBrowser.browserQueue);
nw_connection_start(tmpConnection);

Thanks for your help! Arno

Answered by DTS Engineer in 805637022
a custom UDP broadcast based discovery protocol.

Will you just adopt Bonjour already!?!

Just kiddin’ (-: I know that your hands are likely tied by the accessory firmware. However, if you have any sway with the firmware developers, please do some nagging. Writing your own service discovery code is not fun.

Anyway, two things…


First, you wrote:

This is how the discovery mechanism should work: The iPad sends an IPv4 broadcast message to the network's broadcast address using a fixed destination port, but a random source port (determined at bind time). The device responds with a unicast message to the source IP address and port of the discovery message.

Thanks for that description; it’s super helpful.

Sadly, you won’t be able to use Network framework for this )-: Quoting TN3151 Choosing the right networking API:

However, not all UDP communication is that straightforward. UDP also supports multicast, broadcast, and other asymmetric designs. Network framework supports UDP multicast using the NWConnectionGroup class, but that support has limits and, specifically, it does not support UDP broadcast. If you need something that’s not supported by Network framework, use BSD Sockets.

Your on-the-wire design is one of those less straightforward cases that isn’t currently possible with Network framework.


Second, see the Service Discovery section of Don’t Try to Get the Device’s IP Address, linked to from Extra-ordinary Networking, for some general advice here.

Share and Enjoy

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

Accepted Answer
a custom UDP broadcast based discovery protocol.

Will you just adopt Bonjour already!?!

Just kiddin’ (-: I know that your hands are likely tied by the accessory firmware. However, if you have any sway with the firmware developers, please do some nagging. Writing your own service discovery code is not fun.

Anyway, two things…


First, you wrote:

This is how the discovery mechanism should work: The iPad sends an IPv4 broadcast message to the network's broadcast address using a fixed destination port, but a random source port (determined at bind time). The device responds with a unicast message to the source IP address and port of the discovery message.

Thanks for that description; it’s super helpful.

Sadly, you won’t be able to use Network framework for this )-: Quoting TN3151 Choosing the right networking API:

However, not all UDP communication is that straightforward. UDP also supports multicast, broadcast, and other asymmetric designs. Network framework supports UDP multicast using the NWConnectionGroup class, but that support has limits and, specifically, it does not support UDP broadcast. If you need something that’s not supported by Network framework, use BSD Sockets.

Your on-the-wire design is one of those less straightforward cases that isn’t currently possible with Network framework.


Second, see the Service Discovery section of Don’t Try to Get the Device’s IP Address, linked to from Extra-ordinary Networking, for some general advice here.

Share and Enjoy

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

Hi Quinn,

yeah, I know... :-)

These devices are still in use by our customers, but have been out of support for quite some time. The last firmware update was 7 years ago. So, it is, what it is. :-)

But thanks for the clarification anyways.

Do you think, that there will be changes in the Network Framework to support this kind of traffic? Or is this out of scope?

Thanks Arno

Do you think, that there will be changes in the Network Framework to support this kind of traffic? Or is this out of scope?

It’s definitely not out of scope.

I can’t make predictions about the future. My advice is that you file an enhancement request for the specific features you need. Make sure to clearly outline the on-the-wire protocol you’re trying to implement, like you did at the top of this thread. UDP has many different modes of operation, and some of them are actually supported by Network framework today [1].

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"

[1] Specifically:

  • UDP flows, where the local IP / local port / remote IP / remote port tuple is the same for all packets

  • UDP broadcast listeners, where you write a server that listens for broadcasts and then vends connections for each flow

Network Framework Broadcast Support
 
 
Q