bouke / netservice Goto Github PK
View Code? Open in Web Editor NEWSwift NetService (Bonjour / Zeroconf / mDNS) implementation for Linux
License: MIT License
Swift NetService (Bonjour / Zeroconf / mDNS) implementation for Linux
License: MIT License
I'm having a bit trouble running my service on Ubuntu 16.05 in a VM and Ubuntu Mate on Raspberry. It was working a couple of weeks ago. It runs okay on MacOS and iOS. No changes on the Linux side of the equation, and minimal changes (but some) to the subsystem in my framework, so that's probably the cause. These Apple NetService error codes are very opaque.
The didNotPublish delegate call is called and gives the following error code:
["NSNetServicesErrorCode": -65540, "NSNetServicesErrorDomain": 10]
Are you familiar with that one? As a reminder, I'm using the dns_sd branch.
This library originally did all the networking itself, but Swift support for calling POSIX and POSIX networking in itself was quite difficult to get right. Since 0.5 we're using avahi to provide a dns-sd implementation. Once Swift has great async/await support, a rewrite might be investigated.
After leaving my project alone for a year, upgraded to Xcode 12 and suddenly couldn't find my available service when browsing, which I confirmed was published and available. Received error -72800 missingRequiredConfigurationError and tracked down that there is a new requirement where you need to list all services you want to provide your user with access to under the key NSBonjourServices
in info.plist
. What a pain. The format for defining the services for that key are _myservice._tcp
and _myservice._udp
, depending on transport respectively.
Documention for NSBonjourServices key
If you know a way around this (I doubt that's possible) that would be great. I haven't tested this issue from the Linux side of the equation yet, and will update this issue when I do.
Currently we use SwiftPM's Utility
library to parse CLI arguments. This is "unstable, unsupported API". We should move away from using this API.
I'm unable to get the "dns_sd" branch to build. Here's the error message. Thanks!
#include "shim.h"
^
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/Cdns_sd.git--4743522453419668987/shim.h:1:10: error: 'dns_sd.h' file not found
#include <dns_sd.h>
^
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/NetService.git--7099908149735996145/Sources/NetService/NetService.swift:13:8: error: could not build C module 'Cdns_sd'
import Cdns_sd
^
<module-includes>:1:10: note: in file included from <module-includes>:1:
#include "shim.h"
^
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/Cdns_sd.git--4743522453419668987/shim.h:1:10: error: 'dns_sd.h' file not found
#include <dns_sd.h>
^
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/NetService.git--7099908149735996145/Sources/NetService/NetService.swift:13:8: error: could not build C module 'Cdns_sd'
import Cdns_sd
This seems to be a method available on Apple's NetService:
https://developer.apple.com/documentation/foundation/netservice/1418325-getinputstream
I post the service like this:
var serverDelegate: NetServiceDelegate?
DispatchQueue.global(qos: .background).async {
let service = NetService(domain: "local.", type: "_remote._tcp.", name: "MacRemote", port: 0)
service.publish(options: [.listenForConnections])
service.schedule(in: .main, forMode: .defaultRunLoopMode)
service.delegate = self.serverDelegate
withExtendedLifetime((service, self.serverDelegate)) {
RunLoop.main.run()
}
}
Browsing with Bonjour Browser mac app displays two services under "MacRemote"- one with my Mac's ip and another with an APIPA adress (169.254....). Is this normal ?
This is causing my client to find the APIPA ip instead of the normal IP.
Any advice is much appreciated.
Hi Bouke, fellow Dutchie here. Came across your library and integrated it into my project to support Bonjour discovery on Linux. Fine piece of work!
While it works on OSX (well, with some glitches where the local mDNSResponder gets confused doesn't seem to be hearing the advertisements by NetService.. meanwhile I am seeing traffic with the dns-sd
utility so I think your library works fine) and compiles on Linux, I get the following error:
precondition failed: host name 43ff16893f97. should have suffix .local: file /root/.build/checkouts/NetService.git--4183857386241951162/Sources/NetService/Responder.swift, line 6
This is where the error is thrown:
let hostname = try gethostname() + "."
precondition(hostname.hasSuffix(".local."), "host name \(hostname) should have suffix .local")
self.hostname = hostname
The cause being that gethostname() returns a host without any domain. Now this happens inside a Docker container (which doesn't appear to have a domain name associated). If this is not fixable, perhaps you should throw an exception here instead (as the error is really dependent on runtime configuration).
func stop()
Halts a currently running search or resolution.
When I publish a service on Ubuntu 16.04, I get the following warning message:
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see <http://0pointer.de/avahi-compat?s=libdns_sd&e=Linux>
Is that anything to be concerned about?
My client seems to be resolving successfully but the calls to my delegate are not made (they work on iOS and macOS). Any ideas? Thanks!
Super-excited to find your project - it is exactly what I need. I'm adding support for Linux to an existing iOS project that already utilizes Apple's NetService framework. I was wondering if your framework utilizes the same interface as Apple's so that I could just drop it into my project. It looks very similar but it would be really helpful to know any divergence in advance.
I have the module importing to my Raspberry Pi project no problem! But for some reason it is not recognizing references to NetServiceDelegate, NetServiceBrowser and NetServiceBrowserDelegate.
In perhaps a related issue, it does not see "stop()" on NetServiceBrowser, but I can see that method implemented in your source (even though I also see an issue from last year saying it requires implementation).
Importing "NetService" is the only module required, correct? Thanks!
I've run into a strange problem where if NetService and BlueSocket are both included as dependencies the build process hangs on the following line and brings down the whole OS:
'Cdns_sd' avahi-compat-libdns_sd.pc: warning: prohibited flag(s): -D_REENTRANT
If I modify the package to build with either of the two dependencies on their own, it builds just fine for each. It only crashes when building with both dependencies.
I've created a simple project to demonstrate the failur. You can comment/uncomment the individual dependencies to build with each dependency solo, and combine them to get the crash:
https://github.com/robreuss/CopyPackage.git
I'm running this on a Raspberry Pi 3b, Ubuntu 20.04.3, and Swift 5.5.
It builds just fine when running in a VM using VMWare under macOS ARM.
This problem is a major blocker for me so any help would be most appreciated! Thanks Bouke.
See the mDNSResponder source code, available under Apache License: https://opensource.apple.com/tarballs/mDNSResponder/.
Does it work on iOS 14 devices?
I'm attempting to browse for a Bonjour service from a Linux client running on Raspbian Buster on a Raspberry Pi Zero W that is published by an iOS server . Although it finds the service, it does not resolve.
This delegate method is called:
public func netService(_ sender: NetService, didNotResolve errorDict: [String: NSNumber])
The error provided is:
["NSNetServicesErrorCode": -1, "NSNetServicesErrorDomain": 10]
I thought I had this Linux-based client browsing/resolution working under Linux about a year or two ago, although that was with Ubuntu Mate, and perhaps I made a configuration change to that install.
I used avahi-browse to look for the service and it is published:
`Server version: avahi 0.7; Host name: goose.local
E Ifce Prot Name Type Domain
That same Linux host is itself running a service and iOS devices are able to connect to that no problem.
Thanks.
It seems that RunLoop is not working on the armv7 build. Investigate other solutions.
Hello,
I'm attempting to use the package but am finding that it crashes when one tries to resolve the address of a discovered service.
This is with libavahi-compat-libdnssd-dev
. Version 0.8-5+deb11u2
on Raspberry Pi OS (Bullseye) and Swift v5.8 or v.5.9
See sample project here:
https://github.com/Diggory/NetServiceLinuxTest
Thread 0 “NetServiceLinux” crashed:
0 NetService.didResolveAddress(host:port:textRecord:) + 252 in NetServiceLinuxTest at /home/pi/Swift/NetServiceLinuxTest/.build/checkouts/NetService/Sources/NetService/NetService.swift:489:23
487│
488│ fileprivate func didResolveAddress(host: String, port: UInt16, textRecord: Data?) {
489│ self.hostName = host
│ ▲
490│ self.port = Int(port)
491│ self.textRecord = textRecord
1 closure #1 in variable initialization expression of _resolveReply + 983 in NetServiceLinuxTest at /home/pi/Swift/NetServiceLinuxTest/.build/checkouts/NetService/Sources/NetService/NetService.swift:45:13
43│ let port = UInt16(bigEndian: port)
44│ let textRecord = txtRecord.map { Data(bytes: $0, count: Int(txtLen)) }
45│ service.didResolveAddress(
│ ▲
46│ host: hosttarget,
47│ port: port,
2 0x0000007fb4825af8 <unknown> in libdns_sd.so.1.0.0
3 0x0000007fb3375a78 <unknown> in libavahi-client.so.3.2.9
4 0x0000007fb33713d4 <unknown> in libavahi-client.so.3.2.9
5 0x0000007fb2bc9e74 <unknown> in libdbus-1.so.3.19.17
6 0x0000007fb3377c50 <unknown> in libavahi-client.so.3.2.9
7 0x0000007fb3394ebc <unknown> in libavahi-common.so.3.5.4
8 0x0000007fb4825fa8 <unknown> in libdns_sd.so.1.0.0
9 NetService.processResult() + 75 in NetServiceLinuxTest at /home/pi/Swift/NetServiceLinuxTest/.build/checkouts/NetService/Sources/NetService/NetService.swift:512:9
510│
511│ fileprivate func processResult() {
512│ DNSServiceProcessResult(serviceRef)
│ ▲
513│ }
514│ }
10 closure #1 in variable initialization expression of _processResult + 375 in NetServiceLinuxTest at /home/pi/Swift/NetServiceLinuxTest/.build/checkouts/NetService/Sources/NetService/NetService.swift:53:13
51│ private let _processResult: CFSocketCallBack = { (_, _, _, _, info) in
52│ let service: NetService = Unmanaged.fromOpaque(info!).takeUnretainedValue()
53│ service.processResult()
│ ▲
54│ }
55│
11 0x0000007fb3ba545c __CFSocketPerformV0 + 1539 in libFoundation.so
12 0x0000007fb3ba27a8 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 23 in libFoundation.so
13 0x0000007fb3ba2404 __CFRunLoopDoSources0 + 359 in libFoundation.so
14 0x0000007fb3b9e1f8 __CFRunLoopRun + 671 in libFoundation.so
15 0x0000007fb3b9dcd8 CFRunLoopRunSpecific + 475 in libFoundation.so
16 0x0000007fb3afc2b0 RunLoop.run(mode:before:) + 243 in libFoundation.so
17 NetServiceLinuxTest_main + 323 in NetServiceLinuxTest at /home/pi/Swift/NetServiceLinuxTest/Sources/main.swift:16:33
14│ let shouldKeepRunning = true
15│ // Run forever
16│ while shouldKeepRunning == true &&
│ ▲
17│ runLoop.run(mode:.default, before: distantFuture) {}
18│
18 0x0000007fb33cce18 __libc_start_main + 231 in libc-2.31.so
Segmentation fault
Hello,
I'm using HAP in a project which depends on NetService. When I compile my project on Linux,
I'm getting errors like:
/home/travis/build/MiCasa-HomeKit/MiCasaPlugin/.build/checkouts/NetService/Sources/NetService/NetServiceBrowser.swift:181:66: error: cannot find 'kCFSocketReadCallBack' in scope
372 socket = CFSocketCreateWithNative(nil, fd, CFOptionFlags(kCFSocketReadCallBack), _processResult, &context)
These errors occur in several files. You can find the full log at:
https://travis-ci.org/github/MiCasa-HomeKit/MiCasaPlugin/jobs/740481068
This is my .travis.yml file:
https://github.com/MiCasa-HomeKit/MiCasaPlugin/blob/feat-%231-setup-ci-cd-pipeline/.travis.yml
Best regards
Thomas
I use references to NetService services as keys in a dictionary, so if it's possible to make it hashable that would be wonderful! Thank you!
I'm getting a seg fault and it's occurring in difficult-to-track ways, suggestive a background process getting into trouble.
Sometimes I get all the way through my browsing and connection process, and exchange data over TCP, but then the seg fault occurs. Other times it seems to occur around the time I call stopBrowsing
. Another time, it occurred right after the browser found the same service twice and started to resolve.
My guess is that the last case where the same service was found twice may be the best clue.
This is not directly related to your NetService framework but Apple's. Do you have a recipe for extracting the port number from the sender.addresses
property returned by netServiceDidResolveAddress? This code is working to extract the address but I'm unable to modify it to get the port. Insofar as it doesn't account for address types, it's probably insufficient even for the IP address?
` func netServiceDidResolveAddress(_ sender: NetService) {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
guard let data = sender.addresses?.first else { return }
do {
try data.withUnsafeBytes { (pointer:UnsafePointer<sockaddr>) -> Void in
guard getnameinfo(pointer, socklen_t(data.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else {
throw NSError(domain: "domain", code: 0, userInfo: ["error":"unable to get ip address"])
}
}
} catch {
logError("Could not get service IP address: \(error)")
print(error)
return
}
let address = String(cString:hostname)
logDebug("\(sender.name) IP:\(address)")
}`
I was able to get my library running as an executable on Ubuntu 16.04 referencing the "dns_sd" branch as a dependency. However, when I switched to packaging as a library for another executable to use my library as a dependency, the Package Manager complained about using a branch dependency within a library. It doesn't like using revision id numbers either.
I tried forking your NetService and merging "dns_sd" into master, but although things build, there's no service activity when running. Do you have any suggestions on how I might utilize the"dns_sd" branch in a library, because that is working great?
I realize this question is a bit off the track of NetService itself but I was hoping you might be able to help.
Ran into the following after swift run. First, here's my Package.swift:
let package = Package(
name: "Linux",
products: [
.library(
name: "Linux",
targets: ["Linux"]),
],
dependencies: [
.package(url: "https://github.com/IBM-Swift/BlueSocket.git",.upToNextMajor(from: "1.0.0")),
.package(url: "https://github.com/Bouke/NetService.git",.upToNextMajor(from: "0.4.1"))
],
targets: [
.target(
name: "Linux",
dependencies: ["Socket", "NetService"]),
.testTarget(
name: "LinuxTests",
dependencies: ["Linux"]),
]
)
Here's the error:
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/NetService.git-469506449312911919/Sources/NetService/NetServiceBrowser.swift:100:35: error: value of type '[ResourceRecord]' has no member 'compactMap'
let newPointers = message.answers
~~~~~~~~^~~~~~~
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/NetService.git-469506449312911919/Sources/NetService/Responder.swift:66:21: error: value of type '[Socket.Address]' has no member 'compactMap'
hostRecords = addresses.compactMap { (address) -> HostRecord<IPv4>? in
^~~~~~~~~ ~~~~~~~~~~
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/NetService.git-469506449312911919/Sources/NetService/Responder.swift:74:22: error: value of type '[Socket.Address]' has no member 'compactMap'
host6Records = addresses.compactMap { (address) -> HostRecord<IPv6>? in
^~~~~~~~~ ~~~~~~~~~~
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/NetService.git-469506449312911919/Sources/NetService/NetService.swift:291:18: error: value of type '[ResourceRecord]' has no member 'compactMap'
if message.answers.compactMap({ $0 as? ServiceRecord }).contains(where: { $0.name == fqdn }) {
~~~~~~~~^~~~~~~ ~~~~~~~~~~
/home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/checkouts/NetService.git-469506449312911919/Sources/NetService/Utils.swift:185:10: error: value of type '[UnsafeMutablePointer<ifaddrs>]' has no member 'compactMap'
.filter { Int($0.pointee.ifa_flags) & Int(IFF_LOOPBACK) == 0 }
~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
error: terminated(1): /home/robreuss/swift-4.0-RELEASE-ubuntu16.04/usr/bin/swift-build-tool -f /home/robreuss/Development/VirtualMobileController/VirtualMobileController_Linux/.build/debug.yaml Linux.exe
Is includesPeerToPeer (from Apple's version) not implemented in NetServiceBrowser? I provide access to this property to developers using my framework, but I could easily compiler switch it out on Linux if it's a hassle for you to implement, or stub!
https://developer.apple.com/documentation/foundation/netservice/1414086-includespeertopeer
Common suffixes in the DNS messages can be referenced from within the message. On unpacking this is already performed. On packing this should be done as well.
Hi, now we have Swift working on Windows. I am curious of any experiments for adding Bouke NetService to Windows.
I see two possibilities:
1- Try with the legacy Apple Bonjour SDK for Windows. The SDK is old (2004) but provides the DLL and the dns_sd.h header.
Do you think this Apple dns_sd.h for Windows can simply replace the one you are using for Linux ?
https://developer.apple.com/download/all/?q=Bonjour%20SDK%20for%20Windows
2- Since now Microsoft support Bonjour native on Windows 10/11 with there own Win32 DNS API, we can design a Swift layer over the Microsoft API (windns.h). Longer way but native Win32 support. Any advantages over Apple legacy dns_sd for Windows ? Is anybody have tried this way ?
https://docs.microsoft.com/en-us/windows/win32/api/_dns/
Thanks to Bouke for helping us having a Swift NetService solution for macOS and Linux.
Looking forward for Windows support too.
Looks like the delegate "didAcceptConnectionWith" has been disabled in the "dns_sd" branch. Is that a temporary or permanent change?
Using precondition
should not be used for user errors, only for incorrect API usage. So we should probably report this error using the delegate's didNotPublish(error:...)
.
Publishing service on Linux successfully, and iOS client is seeing the service and attempting to resolve, but nothing happens. Any way I can do some logging with your NetService to help diagnose? This occurs on both "dns_sd" and "master"
When trying NetService with NetService-example on the swift Docker Official Image, I am getting the following warning messages and NetService is not working (not publishing, nor browsing services):
root@docker-desktop:/singular/NetService-Example-master# .build/debug/NetService-Example
*** WARNING *** The program 'NetService-Example' uses the Apple Bonjour compatibility layer of Avahi.
*** WARNING *** Please fix your application to use the native API of Avahi!
*** WARNING *** For more information see http://0pointer.de/blog/projects/avahi-compat.html
Building and running NetService-example in Xcode, seems to be working fine.
Any idea on how to get NetService to work on the swift Docker Official Image?
Is browsing functionality ready for use yet? I'm happy to test when you're ready!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.