Hey guys!
It seems I just stumbled upon the exact same issue whilst developing a multiplatform (iOS and macOS) app that would use SSDP (and potentially other multicast-based protocols) to discover devices on the user's network. To ensure I'd follow Apple's guidelines as best as possible, I decided to go for the Network framework instead of another one (didn't see this post before I started).
Unfortunately, this still seems to be an issue. Please see my playground code below for testing. I never get to see any response from clients, but Wireshark and TCPDump clearly show the outgoing and incoming packets.
The code is ready to be dumped into Playground:
import Foundation
import Network
final class SSDPBrowser {
private var queue = DispatchQueue.global(qos: .userInitiated)
private var listener: NWListener?
private var listeningPort: NWEndpoint.Port = 0
private var connection: NWConnection?
private var ssdpIP: NWEndpoint.Host = "239.255.255.250"
private var ssdpPort: NWEndpoint.Port = 1_900
public func connect() {
self.connection = NWConnection(host: self.ssdpIP, port: self.ssdpPort, using: .udp)
connection!.stateUpdateHandler = { (newState) in
switch (newState) {
case .preparing:
print("Entered state: preparing")
case .ready:
print("Entered state: ready")
case .setup:
print("Entered state: setup")
case .cancelled:
print("Entered state: cancelled")
case .waiting:
print("Entered state: waiting")
case .failed:
print("Entered state: failed")
default:
print("Entered an unknown state")
}
}
connection!.viabilityUpdateHandler = { (isViable) in
if (isViable) {
print("Connection is viable")
} else {
print("Connection is not viable")
}
}
connection!.betterPathUpdateHandler = { (betterPathAvailable) in
if (betterPathAvailable) {
print("A better path is availble")
} else {
print("No better path is available")
}
}
connection!.start(queue: .global())
}
public func sendSSDPDiscoveryPacket() {
let message = "M-SEARCH * HTTP/1.1\r\n" +
"MAN: \"ssdp:discover\"\r\n" +
"HOST: \(self.ssdpIP):\(self.ssdpPort)\r\n" +
"ST: \"ssdp:all\"\r\n" +
"MX: 10\r\n\r\n"
let payload = message.data(using: .utf8)
self.connection!.send(content: payload, completion: .contentProcessed({ sendError in
if let error = sendError {
print("Unable to process and send data: \(error)")
} else {
print("SSDP discovery packet has been sent:\r---\r\(message)")
self.connection!.receiveMessage { (data, context, isComplete, error) in
if let unwrappedError = error {
print("Error: NWError received in \(#function) - \(unwrappedError)")
return
}
guard isComplete, let data = data else {
print("Error: Received nil Data with context - \(String(describing: context))")
return
}
print("Received message: " + String(decoding: data, as: UTF8.self))
}
}
}))
}
}
let ssdpBrowser = SSDPBrowser()
ssdpBrowser.connect()
ssdpBrowser.sendSSDPDiscoveryPacket()
As a workaround, I went ahead and tried to test another framework based on Bluesockets called SSDPClient (https://github.com/resourcepool/ssdp-client), but that didn't work either. It seems the receive fails for some unknown reason (error 9982). Not even the basic example they propose on Github seems to work under Xcode 13 anymore.
Do you have any update for us if and how things evolved with Bug 9120983, or maybe any other hint on what I can do to overcome this?
Many thanks for your support in advance,
Nicolas
Topic:
App & System Services
SubTopic:
Networking
Tags: