3 Replies
      Latest reply on Sep 13, 2019 2:58 AM by eskimo
      benjaminfrombeauvallon Level 1 Level 1 (0 points)

        Hi,

         

        I wanted to try using the new NWBrowser available in iOS 13 to replace my old Bonjour browsing code, problem is I'm unabe to get the IP and Port of the service I'm looking for.

         

        My code :

         

        let params = NWParameters()
        params.includePeerToPeer = true
        _bonjourBrowser = NWBrowser(for: .bonjour(type: "_mpd._tcp.", domain: nil), using: params)
        
        _bonjourBrowser.browseResultsChangedHandler = { results, changes in
          for change in changes {
            switch change {
            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, let interface):
                print("added service \(name) \(type) \(domain) \(String(describing: interface))")
              default:
                print("fail")
              }
            case .removed(let browseResult):
              print("removed \(browseResult.endpoint)")
            case .changed(_, let browseResult, let flags):
              if flags.contains(.interfaceAdded) {
                print("\(browseResult.endpoint) added interfaces")
              }
              if flags.contains(.interfaceRemoved) {
                print("\(browseResult.endpoint) removed interfaces")
              }
            default:
              print("no change")
            }
          }
        }
        
        _bonjourBrowser.start(queue: DispatchQueue.global())
        

         

        What I get is :

        added service MPD.PI _mpd._tcp local. nil

        added service MPD.MBP _mpd._tcp local. nil

         

        How can I get an IP and Port out of this ?

        • Re: Get IP & Port from NWBrowser
          eskimo Apple Staff Apple Staff (11,795 points)

          In Bonjour parlance, a browser does not return address information (local DNS name, IP address list, port).  Rather, it returns a list of services (name, type, domain).  To get the former from the latter, you have to resolve the service.

          Most high-level networking APIs let you pass in a service and the networking API will resolve it for you.  Thus, it’s relatively unusual to want to manually resolve it.  Why are you doing that in this case?

          Share and Enjoy

          Quinn “The Eskimo!”
          Apple Developer Relations, Developer Technical Support, Core OS/Hardware
          let myEmail = "eskimo" + "1" + "@apple.com"

            • Re: Get IP & Port from NWBrowser
              benjaminfrombeauvallon Level 1 Level 1 (0 points)

              Hi,

               

              I'm working on an iOS app to control a MPD server (http://musicpd.org), the server advertise itself via Bonjour/Zeroconf.

              To connect to it, the api (plain C) expect a couple Hostname/IP & port.

               

              Until now I was using the old NetServiceBrowser but it's not very swifty and kinda ugly.

                • Re: Get IP & Port from NWBrowser
                  eskimo Apple Staff Apple Staff (11,795 points)

                  AFAIK Network framework does not have an API that does the Bonjour resolve operation without also connecting.  To solve this, you’ll have to go either up or down the stack:

                  • Construct an NSNetService and then call -resolveWithTimeout: on it.

                  • Use DNSServiceResolve.

                  Both of these have their challenges.  Specifically, in the NSNetService case, you have to deal with run loops.

                  In both cases, make sure to take the resulting DNS name and pass that to your third-party library.  That allows it to connect by name, which should improve the chances of it connecting successfully [1].


                  Oh, before I go, I want to stress that the fact that NWBrowser does not resolve is a feature, not a bug.  Resolving every service you encounter when browsing is a major Bonjour faux pas.  The goal is to only resolve the service you’re connecting to, and then only at the point when you do the connection.  Network framework does that as part of NWConnection, so the issue here is about whether there’s a way to do that without actually connecting.

                  Share and Enjoy

                  Quinn “The Eskimo!”
                  Apple Developer Relations, Developer Technical Support, Core OS/Hardware
                  let myEmail = "eskimo" + "1" + "@apple.com"

                  [1] This assumes that it uses a system connect-by-name API, or contains all the necessary smarts to connect in a wide variety of environments.  If this is a cross-platform code base it may not, in which case you may encounter connectivity problems in oddball network environments.  If so, you might want to do a dummy connection yourself (using NWConnection), get the IP address it used, and pass that to your library.