[quote='867952022, DTS Engineer, /thread/808917?answerId=867952022#867952022']
Did you opt in to peer-to-peer on both the listener and the browser?
[/quote]
I did do that. Please see my code snippets below.
private func startBrowser() async throws {
let parameters = NWParameters()
parameters.includePeerToPeer = true
// parameters.requiredInterfaceType = .wifi
// parameters.prohibitedInterfaceTypes = [.cellular]
try await NetworkBrowser(
for: .bonjour(serviceName, domain: nil, includeTxtRecord: false),
using: parameters
)
.onStateUpdate { _, state in
switch state {
case let .failed(error):
logger.error("[startBrowser]:browser failed: -> \(error)")
case .ready:
logger.info("[startBrowser]: browser is ready")
case .cancelled:
logger.error("[startBrowser]: browser cancelled")
case .setup:
logger.info("[startBrowser]: browser in setup")
case let .waiting(error):
logger.error("[startBrowser]: browser is waiting: \(error)")
@unknown default:
break
}
}
.run { endpoints in
self.handleBrowserEndpoints(endpoints)
}
}
private func startListener() async throws {
guard let identity = Utils.importIdentityFromPKCS12() else {
logger.error("could not get identity")
return
}
guard let certificateData = Utils.getCertificateData(from: identity) else {
logger.error("could not read certificate data")
return
}
let builder = try makeQUICParametersBuilder(identity: identity, certificateData: certificateData)
@SharedReader(.thisDeviceID) var thisDeviceID
let listener = try NetworkListener(for: .bonjour(name: nil, type: serviceName), using: builder)
listener.service = NWListener.Service(name: thisDeviceID, type: serviceName)
try await listener.onServiceRegistrationUpdate { _, change in
switch change {
case let .add(endpoint):
logger.info("onServiceRegistrationUpdate: added \(endpoint.debugDescription)")
case let .remove(endpoint):
logger.info("onServiceRegistrationUpdate: removed \(endpoint.debugDescription)")
@unknown default:
return
}
}
.onStateUpdate { lst, state in
logger.info("\(String(describing: lst)): \(String(describing: state))")
switch state {
case let .failed(error):
logger.error("Listener failed: \(error)")
case .ready:
logger.info("Listener ready")
case .cancelled:
logger.info("listener cancelled")
case let .waiting(error):
logger.error("listener is waiting: \(error)")
case .setup:
logger.info("listener setup")
@unknown default:
break
}
}
.run { connection in
logger.info("listener run callback received connection")
await self.handleInboundConnection(connection)
}
}
private func makeQUICParametersBuilder(identity: SecIdentity, certificateData: Data) throws -> NWParametersBuilder<QUIC> {
guard let nwIdentity = sec_identity_create(identity) else {
throw NetworkingError.failedToCreateIdentity
}
var quic = QUIC(alpn: ["captadoh"])
quic = quic.idleTimeout(0)
quic = quic.tls.localIdentity(nwIdentity)
quic = quic.tls.certificateValidator { _, secTrust async -> Bool in
let trust = sec_trust_copy_ref(secTrust).takeRetainedValue()
guard let certificates = SecTrustCopyCertificateChain(trust) as? [SecCertificate],
let peerCertificate = certificates.first
else {
logger.error("Failed to get peer certificate")
return false
}
let peerCertificateData = SecCertificateCopyData(peerCertificate) as Data
logger.info("Peer cert SHA256: \(SHA256.hash(data: peerCertificateData).map { String(format: "%02x", $0) }.joined())")
logger.info("Local cert SHA256: \(SHA256.hash(data: certificateData).map { String(format: "%02x", $0) }.joined())")
return peerCertificateData == certificateData
}
quic = quic.tls.peerAuthentication(.required)
var builder = NWParametersBuilder<QUIC>.parameters {
quic
}
builder = builder.peerToPeerIncluded(true)
// builder = builder.requiredInterfaceType(.wifi)
// builder = builder.prohibitedInterfaceTypes([.cellular])
return builder
}
Topic:
App & System Services
SubTopic:
Networking
Tags: