NWConnection failing due to wrong port when using endpoint from NWBrowser.Result

Hi,

I'm starting a project that needs to detect some hardware on the network using Bonjour and then connect and send messages.

I started using the TicTacToe example from WWDC as my basis and i'm able to start a browser and detect my devices on the network.

In my browseResultsChangedHandler i can see new service endpoints being added using the following code block.

Code Block swift
case .added(let browseResult):
switch browseResult.endpoint {
case .hostPort(let host, let port):
print("added hostPort \(host) \(port)")
case .service(let name, let type, let domain, _):
print("added service: \(name)\n with type: \(type)\n on domain: \(domain)")
default:
print("fail")
  }

I'm using the array of NWBrowser.Result to populate a tableview and then segue to a new view when they select a row. As part of this I pass the browser result corresponding to the selected row to the new view.

When I reach the new view I try to start a connection:

Code Block swift
var browserResult: NWBrowser.Result?
override func viewDidLoad() {
    super.viewDidLoad()
/* Do any additional setup after loading the view. */
    if (browserResult != nil) {
        let endpoint = browserResult!.endpoint
        if case let NWEndpoint.service(name: name, type: _, domain: _, interface: _) = endpoint {
            connectedDeviceLabel.text = name
        }
    }
    ConnectToDevice()
}
func ConnectToDevice() {
        if (browserResult != nil) {
            connection = NetworkConnection(endpoint: browserResult!.endpoint, interface: browserResult!.interfaces.first)
            connection?.delegate = self
        }
}
/* NetworkConnection */
init(endpoint: NWEndpoint, interface: NWInterface?) {
        /* Create parameters, and allow browsing over peer-to-peer link. */
        let tcpOptions = NWProtocolTCP.Options()
        tcpOptions.enableKeepalive = true
        tcpOptions.keepaliveIdle = 2
        let parameters = NWParameters(tls: nil, tcp: tcpOptions)
        parameters.includePeerToPeer = true
        parameters.allowLocalEndpointReuse = true
        let connection = NWConnection(to: endpoint, using: parameters)
        self.connection = connection
        startConnection_B()
    }
func startConnection_B() {
    guard let connection = connection else {
        return
    }
    connection.stateUpdateHandler = { newState in
        switch newState {
            case .ready:
                print("\(connection) established")
                /* When the connection is ready, start receiving messages. */
                self.receiveNextMessage()
                /* Notify delegate that the connection is ready. */
                if let delegate = self.delegate {
                    delegate.connectionReady()
                }
            case .failed(let error):
                print("\(connection) failed with \(error)")
                /* Cancel the connection upon a failure. */
                connection.cancel()
            default:
                break
        }
    }
    /* Start the connection establishment. */
    connection.start(queue: .main)
}

However when attempting to start the connection it fails with a socket error:
nw_socket_handle_socket_event [C1.1.1:1] Socket SO_ERROR [61: Connection refused]
After some detective work using Xcode's network activity report, i discovered that this is because it is attempting to connect on port 80 rather than the correct port of 3134. It does however get the IP address correct.

If I manually start an NWConnection using hardcoded values in place of the detected endpoint the connection works and I can send/receive data:
Code Block swift
let connection = NWConnection(host: "192.168.1.93", port: 3134, using: .tcp)

I'm new to both networking and swift so fully expect i've done something wrong. Any advice would be greatly appreciated.
Accepted Answer
So, to be clear, the endpoint you’re using to create NetworkConnection is a Bonjour service, that is, it has a .service(_:_:_:_:) value?

If so, it’s hard to see how Network framework could be getting this wrong. My best theory is that the accessory is advertising the wrong port. You can test this using dns-sd on your Mac, for example:

Code Block
% dns-sd -L "Darth Inker" _http._tcp local.
Lookup Darth Inker._http._tcp.local.
DATE: ---Fri 12 Mar 2021---
10:06:31.145 ...STARTING...
10:06:31.145 Darth\032Inker._http._tcp.local. can be reached at darth-inker.local.:80 (interface 6)
^C


where NNN is the name from the endpoint, TTT is the type, and DDD is the domain. You can see that it prints DNS name (darth-inker.local.) and port (80). In my case the HTTP service was advertised on port 80, but it sounds like your accessory is running the service on 3134.

Share and Enjoy

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

Thanks for the quick response.
Yes, your statement in the first line of your response is correct

I think you are right about the device advertising the wrong port.
I backtracked a bit and tried with the older NetService library which allows me to resolve the address and port

Code Block swift
    func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
        bonjourService = service
        service.delegate = self
        service.resolve(withTimeout: 5.0)
        print("Found service: \(service.name) with type: \(service.type)")
    }
    func netServiceDidResolveAddress(_ sender: NetService) {
        print(sender.port)
    }

Sure enough, the output from this also thinks the port is 80.

So I downloaded the Discovery app from the app store and it looks like the port is discoverable as port 80, but then the correct port is contained in the extra parameters (these are what's known as the TXT record?)

I will get in contact with the hardware developer and see if this is in fact the case and can be resolved



I will get in contact with the hardware developer

Yeah, that seems like the best option. You can work around this on the client if necessary, but it’s a bit tricky and thus fixing it at the source would be nicer.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
NWConnection failing due to wrong port when using endpoint from NWBrowser.Result
 
 
Q