I am trying to search for UPnP devices in my network by sending an SSDP discovery packet. I can send them but I do not receive responses from devices and I do not know what I am missing. Maybe someone here can help me out. Goal is not to use any external libaries (pods, spm, ...).
Here is what I have:
import UIKit
import Network
extension NWEndpoint.Port {
static let ssdp: NWEndpoint.Port = 1_900
}
extension NWEndpoint.Host {
static let ssdp: NWEndpoint.Host = "239.255.255.250"
}
class ViewController: UIViewController {
private let parameters: NWParameters = {
let parameters: NWParameters = .udp
parameters.allowLocalEndpointReuse = true
parameters.allowFastOpen = true
return parameters
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
do {
try setupConnection()
} catch {
print(error.localizedDescription)
}
}
private func setupConnection() throws {
let endpoints: [NWEndpoint] = [
.hostPort(host: .ssdp, port: .ssdp)
]
let multicast = try NWMulticastGroup(for: endpoints)
let group = NWConnectionGroup(with: multicast, using: parameters)
group.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: true) { (message, content, isComplete) in
print("Received message from \(String(describing: message.remoteEndpoint))")
}
group.stateUpdateHandler = { [weak viewController = self] (state) in
guard let viewController = viewController else {
return
}
switch state {
case .setup:
print("Setup")
case .waiting(let error):
let message = String(format: "Waiting: %@", error.localizedDescription)
print(message)
case .ready:
print("Ready")
viewController.send(to: group)
case .failed(let error):
let message = String(format: "Failed: %@", error.localizedDescription)
print(message)
case .cancelled:
print("Cancelled")
@unknown default:
print("Unknown group state")
}
}
group.start(queue: .main)
}
private func send(to group: NWConnectionGroup) {
let message = "M-SEARCH * HTTP/1.1\r\nST: ssdp:all\r\nHOST: 239.255.255.250:1900\r\nMAN: \"ssdp:discover\"\r\nMX: 1\r\n\r\n"
let payload = message.data(using: .utf8)
group.send(content: payload) { error in
let message: String
if let error = error {
message = String(format: "Send completed with error %@", error.localizedDescription)
} else {
message = String(format: "Send completed")
}
print(message)
}
}
}
any help is appreciated! thank you in the meantime.
Edit: This does not work either
import UIKit
import Network
extension NWEndpoint.Port {
static let ssdp: NWEndpoint.Port = 1_900
}
extension NWEndpoint.Host {
static let ssdp: NWEndpoint.Host = "239.255.255.250"
}
class ViewController: UIViewController {
private let connectionQueue = DispatchQueue(label: "Connection")
private let listenerQueue = DispatchQueue(label: "Listener")
private let parameters: NWParameters = {
let parameters: NWParameters = .udp
parameters.allowLocalEndpointReuse = true
return parameters
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
do {
try setupConnection()
} catch {
print(error.localizedDescription)
}
}
private func setupConnection() throws {
let listener = try NWListener(using: parameters)
listener.stateUpdateHandler = { state in
print("l-state", state)
}
listener.newConnectionHandler = { (connection) in
print("connection", connection)
}
listener.start(queue: listenerQueue)
let connection = NWConnection(host: .ssdp, port: .ssdp, using: parameters)
connection.stateUpdateHandler = { [weak viewController = self] state in
print("c-state", state)
guard let viewController = viewController else {
return
}
switch state {
case .ready:
viewController.send(to: connection)
default: return
}
}
connection.start(queue: connectionQueue)
}
private func send(to connection: NWConnection) {
let message = "M-SEARCH * HTTP/1.1\r\nSt: ssdp:all\r\nHost: 239.255.255.250:1900\r\nMan: \"ssdp:discover\"\r\nMX: 1\r\n\r\n"
let payload = message.data(using: .utf8)
connection.send(content: payload, completion: .contentProcessed { error in
if let error = error {
print(error.localizedDescription)
} else {
print("ok")
}
})
connection.receive(minimumIncompleteLength: 1, maximumLength: 65536) { data, context, isComplete, error in
print("data", data ?? "")
}
}
}