Issue Sending Multicast Packets Across Multiple Interfaces Using NWConnectionGroup

Hi everyone,

I'm currently working on a project where I need to send multicast packets across all available network interfaces using Apple Network Framework's NWConnectionGroup. Specifically, the MacBook (device I am using for sending multicast requests, MacOS: 15.1) is connected to two networks: Wi-Fi (Network 1) and Ethernet (Network 2), and I need to send multicast requests over both interfaces.

I tried using the .requiredInterface property as suggested by Eskimo in this post, but I’m running into issues.

It seems like I can't create an NWInterface object because it doesn't have any initializers.

Here is the code which I wrote:

var multicast_group_descriptor : NWMulticastGroup
var multicast_endpoint : NWEndpoint
multicast_endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host("234.0.0.1"), port: NWEndpoint.Port(rawValue: 49154)!)
var connection_group : NWConnectionGroup
var multicast_params : NWParameters
multicast_params = NWParameters.udp
 var interface = NWInterface(NWInterface.InterfaceType.wiredEthernet)

I get following error:

'NWInterface' cannot be constructed because it has no accessible initializers

I also experimented with the .requiredInterfaceType property. Even when I set it to .wiredEthernet and then change it to .wifi, I am still unable to send requests over the Wi-Fi network.

Here is the code I wrote:

var multicast_params : NWParameters
multicast_params = NWParameters.udp
multicast_params.allowLocalEndpointReuse = true
multicast_params.requiredInterfaceType = .wiredEthernet
    
var ip = multicast_params.defaultProtocolStack.internetProtocol! as! NWProtocolIP.Options
ip.disableMulticastLoopback = true

connection_group = NWConnectionGroup(with: multicast_group_descriptor, using: multicast_params)

connection_group.stateUpdateHandler = { state in
    print(state)
    
    if state == .ready {
        connection_group.send(content: "Hello from machine on 15".data(using: .utf8)) { error in
            print("Send to mg1 completed on wired Ethernet with error \(error?.errorCode)")
            
            var params = connection_group.parameters
            params.requiredInterfaceType = .wifi
            
            connection_group.send(content: "Hello from machine on 15 P2 on Wi-Fi".data(using: .utf8)) { error in
                print("Send to mg1 completed on Wi-Fi with error \(error?.errorCode)")
            }
        }
    }
}

Is this expected behavior when using NWConnectionGroup? Or is there a different approach I should take to ensure multicast requests are sent over both interfaces simultaneously?

Any insights or suggestions would be greatly appreciated!

Thanks in advance,

Harshal

Contrary to what Eskimo stated in the reply here

QUOTE

"Upon initializing NWConnectionGroup, it appears that packets are received on all interfaces without the ability to control this at the interface level. Is this correct?"

Eskimo: Correct.

UNQUOTE

I wrote below code:


import Network
import Foundation
  
var multicast_group_descriptor : NWMulticastGroup
var multicast_endpoint : NWEndpoint
multicast_endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host("234.0.0.1"), port: NWEndpoint.Port(rawValue: 49154)!)
  
do {
    multicast_group_descriptor = try NWMulticastGroup(for: [multicast_endpoint], disableUnicast: false)
  
  
var connection_group : NWConnectionGroup
var multicast_params : NWParameters
multicast_params = NWParameters.udp
multicast_params.allowLocalEndpointReuse = true
    
    var ip = multicast_params.defaultProtocolStack.internetProtocol! as! NWProtocolIP.Options
    
    ip.disableMulticastLoopback = true
    
    
connection_group = NWConnectionGroup (with: multicast_group_descriptor, using: multicast_params)
  
    connection_group.stateUpdateHandler = { state in
             
            print (state)
             
        if (state == .ready) {
             
                connection_group.send(content: "Hello from machine on 15".data(using: .utf8)) { error in
                    print ("send to mg1 completed with error \(error?.errorCode)")
 
            }
            
            
        }
         
    }
     
    connection_group.newConnectionHandler = { connection in
             
        print ("received new connection")
        print (connection.endpoint)
        connection.stateUpdateHandler = { state in
             
            print ("Received connection state: \(state)")
             
            if (state == .ready) {
                 
                connection.receive(minimumIncompleteLength: 1, maximumLength: 65000) { content, contentContext, isComplete, error in
                    print ("received message with error \(error?.errorCode) is: ")
                    print (String (data: content!, encoding: .utf8))
                }
            }
        }
        connection.start(queue: .global())
        }
     
    connection_group.setReceiveHandler { message, content, isComplete in
        print ("Recevied on Receive Handler: \(String (data: content!, encoding: .utf8))")
        print (message.remoteEndpoint)
         
           
            message.reply(content: "hello back from 15 P2".data(using: .utf8))
        
    }
     
    connection_group.start(queue: .global())
    RunLoop.main.run()
     
} catch (let err) {
     
    print (err)
}

When I send packets from a device connected via Ethernet (Network 2), they are delivered to the Receive Handler. However, packets sent from a device on Wi-Fi (Network 1) are not received by the handler, despite both packets being captured on my machine (confirmed via Wireshark).

Wireshark Trace:

10 130.653672 X.Y.Z.Q 234.0.0.1 UDP 60 64737 → 49154 Len=18
11 134.479501 A.B.C.D 234.0.0.1 UDP 60 56643 → 49154 Len=18

Output from Code:

Received on Receive Handler: Optional("\u{01}\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0X")
Optional(X.Y.Z.Q:60504)

Note:

  • X.Y.Z.Q is the IP for the machine connected to Ethernet (Network 2).

  • A.B.C.D is the IP for the machine connected to Wi-Fi (Network 1).

When I run the networksetup -listallnetworkservices command, I get the following output:

n asterisk (*) denotes that a network service is disabled.
AX88179A
Belkin USB-C LAN // my ethernet adaptor
Wi-Fi   // my wifi adaptor
Thunderbolt Bridge
GlobalProtect

This confirms that both the Wi-Fi and Ethernet services are active.

How can I ensure that I receive all the multicast packets from all available interfaces (Ethernet and Wi-Fi) on the Receive Handler?

Regards,

Harshal

Bah, I’m still dealing with a big backlog, so I don’t have time to respond fully, but I can at least answer this.

It seems like I can't create an NWInterface object because it doesn't have any initializers.

Indeed. You can use an Ethernet channel path monitor for this. For the details, see this thread.

Share and Enjoy

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

Issue Sending Multicast Packets Across Multiple Interfaces Using NWConnectionGroup
 
 
Q