Bonjour, also known as zero-configuration networking, enables automatic discovery of devices and services on a local network using industry standard.

Posts under Bonjour tag

47 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

mDNSResponder failing Bonjour Conformance Test
I'm using the following: mDNSResponder 1790.80.10 Bonjour Conformance Test (BCT) 1.5.2 Linux 6.1.y kernel I'm testing an Airplay 2 speaker as part of our self certification. When BCT gets into the mDNS tests mDNSResponder fails the subsequent conflict test with this message: ERROR 2023-06-12 10:37:29.398711-0500 _sub_conflict 03570: Device did not complete its probing sequence for a new name after a subsequent conflict arose for its previously acquired name. BCT then retries three times with each retry failing with the same message. Am I missing something from my software that interacts with the mdns daemon? Is this a known issue with the posix build for mDNSResponder? What can I do to get this test to pass? Any help would be appreciated. Ethan
5
0
1.5k
Oct ’23
Cannot connect with another computer over avahi
I installed Gentoo in virtual machine using Apple Virtualization framework. In linux then I installed avahi, configured the network in Bridge mode. Now I want to connect from this virtual machine to other computer in local network. I can see other computers on the local network, and connect with them using local IP address. But for some reason these are not detected using .local domain. I run avahi-browse -at|grep PS3 and it detected 4 entries for this computer: IPV4 _ssh._tcp local IPV6 _ssh._tcp local IPV4 _sftp-ssh._tcp local IPV6 _sftp-ssh._tcp local Also avahi-resolve -n PS3.local correctly detects IPv6 address of this machine. So why cannot I connect with the computer using PS3.local name?
1
0
718
Oct ’23
NWConnection performance on iOS is wildly inconsistent
I have an system that is designed around a collection of devices (iPhones or iPads) discovered via bonjour and connected with a NWConnection over TCP. Commands issued from one of the devices are sent to each of the peers and should be executed as soon as they are received. The problem I am encountering is a high variability in transit time device to device that I am having a hard time accounting for. By 'high' I am noting anywhere from 20-80ms of latency device to device. CPU utilization on each iPhone is essentially 0. Keepalives are enabled and firing off every 2 seconds. Additionally, the physical devices all have bluetooth off (as recommended in other posts) The interesting part is when I add into the connection mix an iPhone simulator (running on either a M1 MacBook Air, or my M1U Studio). When a command is issued from the simulator instance, all connected devices report back anywhere within ~0-3ms of deviation from the initiator, which is more what I expect from the network. Thinking that it's perhaps the M1 series of chips being far and away more competent than the A15's in the iPhone 13's and 14 that are in my testbed, I added my M1 iPad to the mix. Invoking a command from the iPad has similar variability as invoking it from one of the iPhones. The code is stupid simple and I'm posting here prior to opening up a DTS case in the hope that there's a magic "shouldUseSpeedholes=true" flag I can set. I have gone through several variations: using UDP instead of TCP (worse variations), changing from a listener/browser on each device to a single browser, multiple listener (no difference), changing from keeping things on the main queue (as in the docs) to a separate concurrent high priority dispatch queue (no difference). There is no TLS in the mix. I have tried both allowing peer-to-peer as well as not (no difference). I'm even using a single purpose project instead of my main codebase to isolate everything else that could be messing with scheduling with communications. I've tried each band of my WIFI (2.4 and 2x5ghz SSIDs) - no change. Sending func send(option: AppFramingOptions, withData data: Data?) { let message = NWProtocolFramer.Message(appFramingOption: option) let context = NWConnection.ContentContext(identifier: "\(option.rawValue)", metadata: [message]) for (uniqueKey, connection) in connections { if uniqueKey.contains(serviceName) { connection.send(content: data, contentContext: context, isComplete: true, completion: .idempotent) } } } In the above function, I am looking for the serviceName because I want to use connections connected via the browser as opposed to the listener (which isn't tagged with service name info in the endpoint). The check avoids a device receiving the command twice. Receiving connection.receiveMessage { content, contentContext, isComplete, error in guard error == nil else { connection.cancel() return } if let msg = contentContext?.protocolMetadata(definition: AppFraming.definition) as? NWProtocolFramer.Message { switch msg.appFramingOption { default: self.messageReceivedHandler?(content, msg.appFramingOption, Date().timeIntervalSince1970, withUniqueKey) } } receiveMessage() } } It's very much patterned off the TicTacToe example code (with a mechanism for multiple connections). My next step is embedding a web server in each device and making REST calls rather than commands over a TCP stream (which is CRAZY INSANE I KNOW). I also do not want to have to have a Macintosh dependency for this system because I cannot get predictable(ish) transit times. Any help is appreciated!
3
0
823
Sep ’23
Xcode Error : Building a custom peer-to-peer protocol
Unable to launch this sample project. Xcode says it cannot open the file. Building a custom peer-to-peer protocol I'm trying to build iPhone as a mouse. I am not planning on releasing it but more like a practice for myself. I have one other question, how to use a mac app to receive mouse data while it's in background as it's required by my app. Is Background Tasks the right way ? I am planning to use Network framework for networking but there is not much documentation available. Pardon me if it's a basic question.
1
0
821
Aug ’23
Getting Started with Bonjour
Every now and then I talk to someone who’s trying to use Bonjour and just can’t get over the first hurdle. That happened today, and so I decided to share my write-up for the benefit of others. Questions or comments? Put them in a new thread here on DevForums, tagging it with Bonjour so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" Getting Started with Bonjour Bonjour is an Apple term for a variety of Internet standards [1]. Bonjour allows your app to browse for and connect to services on the network without infrastructure support. For example, Bonjour lets you find and connect to a printer even if the network has no DHCP server to hand out IP addresses. If you’re new to Bonjour, a good place to start is the Bonjour Overview. It’s in the documentation archive, so it hasn’t been updated in a while, but the fundamentals haven’t changed. There are, however, two things that have changed: Network framework has new Bonjour APIs, and the old ones are now deprecated. iOS 14 introduced local network privacy. This post shows how to get started with Bonjour, taking into account these new developments. [1] Specifically: RFC 3927 Dynamic Configuration of IPv4 Link-Local Addresses RFC 6762 Multicast DNS RFC 6763 DNS-Based Service Discovery Start Browsing Let’s start by implementing a service browser. To simplify things, this browses for SSH services. That way you can get started with the browser without first having to implement a server to register your service. If you don’t already have an SSH service registered on your network, start one by enabling System Settings > General > Sharing > Remote Login on your Mac. The SSH service type is, unsurprisingly, _ssh._tcp. First, on your Mac, run the dns-sd tool to confirm that you have an SSH service visible on your network: % dns-sd -B "_ssh._tcp" "local." % dns-sd -B "_ssh._tcp" "local." … Timestamp A-R Flags if Domain Service Type Instance Name … 11:54:43.315 Add 2 6 local. _ssh._tcp. Fluffy … 11:54:43.725 Add 2 6 local. _ssh._tcp. SAM the Robot 12 ^C This shows that I have two services, one called Fluffy and the other called SAM the Robot 12. Let’s write some iOS code to browse for those. To start, create an app from the iOS > App template and connect a button to the startStop() method of a class like this: import Foundation import Network class AppModel { var browserQ: NWBrowser? = nil func start() -> NWBrowser { print("browser will start") let descriptor = NWBrowser.Descriptor.bonjour(type: "_ssh._tcp", domain: "local.") let browser = NWBrowser(for: descriptor, using: .tcp) browser.stateUpdateHandler = { newState in print("browser did change state, new: \(newState)") } browser.browseResultsChangedHandler = { updated, changes in print("browser results did change:") for change in changes { switch change { case .added(let result): print("+ \(result.endpoint)") case .removed(let result): print("- \(result.endpoint)") case .changed(old: let old, new: let new, flags: _): print("± \(old.endpoint) \(new.endpoint)") case .identical: fallthrough @unknown default: print("?") } } } browser.start(queue: .main) return browser } func stop(browser: NWBrowser) { print("browser will stop") browser.stateUpdateHandler = nil browser.cancel() } func startStop() { if let browser = self.browserQ { self.browserQ = nil self.stop(browser: browser) } else { self.browserQ = self.start() } } } Note I’m using SwiftUI, but if you chose to use UIKit you could add this code directly to your view controller. Of course, whether you want to add networking code to your view controller is another question. The answer is, natch, “No”, except when creating a tiny test project like this one (-: Now build and run in the simulator and click your buton. It’ll print something like this: browser will start browser did change state, new: ready browser results did change: + SAM the Robot 12._ssh._tcp.local. + Fluffy._ssh._tcp.local. As you can see, it’s found our two SSH services. Yay! Run on the Device Now stop the app and run it on a real device. This time the Test button results in: browser will start … browser did change state, new: failed(-65555: NoAuth) This is local network privacy kicking in. There are two things you need to do: Add a NSBonjourServices property to your Info.plist to declare what service types you’re using. Add a NSLocalNetworkUsageDescription property to your Info.plist to explain what you’re doing with the local network. Do that and run your app again. On tapping the Test button you’ll see an alert asking you to grant your app access to the local network. Tap Allow and the browser will start generating results as before. Respond to Updates When working with Bonjour it’s important to keep your browser running to update your app’s state. To test this, start a Remote Login on a different machine and look for a new result being printed: browser results did change: + Slimey._ssh._tcplocal. And then turn it off: browser results did change: - Slimey._ssh._tcplocal. If you don’t have another Mac to test this with, start a dummy service using dns-sd: % dns-sd -R "Guy Smiley" "_ssh._tcp" "local." 12345 Registering Service Test._ssh._tcp.local. port 12345 … Press control-C to stop the dns-sd tool, which unregisters the service. Connect When the user choose a service, it’s time to connect. There are two ways to do this, depending on the networking API you use to run your connection. NWConnection can connect directly to a Bonjour service endpoint. For example, you might have code that connects to a DNS name and port: func makeConnection(host: String, port: UInt16) -> NWConnection { let host = NWEndpoint.Host(host) let port = NWEndpoint.Port(rawValue: port)! let endpoint = NWEndpoint.hostPort(host: host, port: port) return NWConnection(to: endpoint, using: .tcp) } Replace that with code that takes the endpoint you get back from the browser: func makeConnection(endpoint: NWEndpoint) -> NWConnection { return NWConnection(to: endpoint, using: .tcp) } If you’re using a legacy API, like BSD Sockets, you’ll need to resolve the Bonjour service endpoint to a DNS name and then pass that DNS name into your connection code. Network framework does not support resolving Bonjour service endpoints out of the box, so you’ll have to do that yourself. For an example of how you might do this, see this post. IMPORTANT For this to work reliably, your BSD Sockets code must support Happy Eyeballs. See TN3151 Choosing the right networking API for specific advice on that front. Register a Service Now let’s look at the server side. To listen for connections with Network framework, you might write code like this: import Foundation import Network class AppModel { var listenerQ: NWListener? = nil func start() -> NWListener? { print("listener will start") guard let listener = try? NWListener(using: .tcp) else { return nil } listener.stateUpdateHandler = { newState in print("listener did change state, new: \(newState)") } listener.newConnectionHandler = { connection in connection.cancel() } listener.start(queue: .main) return listener } func stop(listener: NWListener) { print("listener will stop") listener.stateUpdateHandler = nil listener.cancel() } func startStop() { if let listener = self.listenerQ { self.listenerQ = nil self.stop(listener: listener) } else { self.listenerQ = self.start() } } } To register your service with Bonjour, add these lines before the call to start(queue:): listener.service = .init(type: "_ssh._tcp") listener.serviceRegistrationUpdateHandler = { change in print(change) } The listener calls your service registration update handler to tell you the name of the service. Typically you display this value somewhere in your UI. For more about this, see Showing Connection Information in an iOS Server. To confirm that your service is running, open Terminal and choose Shell > New Remote Command. Your service should show up in the Secure Shell (ssh) list. Alternatively, browse for SSH services using the dns-sd tool, as illustrated in the Start Browsing section above.
0
0
2.3k
Aug ’23