5 Replies
      Latest reply on Sep 15, 2019 7:51 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 (12,715 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 (12,715 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.

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

                      Ok, thank you for the explanation

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

                          Earlier I wrote:

                          AFAIK Network framework does not have an API that does the Bonjour resolve operation without also connecting.

                          I had a quick chat with the Network framework team and they confirmed this.  Exposing a ‘NWResolver’ API is feasible, but handling all the edge cases is tricky.  For example, earlier I wrote:

                          make sure to take the resulting DNS name and pass that to your third-party library.

                          It turns out that, in the general case, you might get multiple DNS names back for a service.  This is why Network framework has such an emphasis on resolving as part of connecting.  Handling all the edge cases otherwise is challenging.

                          Still, if you’d like to see this sort of thing added in the future, I encourage you to file an enhancement request describing your requirements.  Be as specific as possible here, for example, explaining why it’s not feasible to resolve while connecting, details of the connection process used by the underlying library you’re using, and so on.

                          Please post your bug number, just for the record.

                          Share and Enjoy

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