Hello! I'm playing around with QUIC and Swift and using the Network framework. So far, the process has been really straightforward, but I noticed that I can't seem to get a handle on the stream with identifier 0.
If I use NWConnection directly, I only have access to the first stream, which has the stream ID 0. This not what I want since I wanna use multiple streams. Following the documentation, I started using NWMultiplexGroup and starting a NWConnectionGroup with it.
Everything works fine and I can get all streams that my backend service opens using NWMultiplexGroup's newConnectionHandler property. However, whenever backend sends a message on stream_id 0, none of my connections receive it. Looking around with
connection.metadata(definition: NWProtocolQUIC.definition) as? NWProtocolQUIC.Metadata
for each connection, I see that all streams are accounted for except stream 0. Then, using the NWConnectionGroup variant of the above
connectionGroup.metadata(definition: NWProtocolQUIC.definition) as? NWProtocolQUIC.Metadata
I see that the connection group itself has Stream ID 0. However, calling setReceiveHandler does nothing (it's never called, even when backend is sending messages) and when I attempt to send a message using NWConnectionGroup's -send method, a new stream is opened (instead of it being sent on stream ID 0).
How can one get a handle on NWConnection for stream ID 0?
QUIC
RSS for tagCreate network connections to send and receive data using the QUIC protocol.
Posts under QUIC tag
25 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi, wondering if IOS supports WebTransport (HTTP/3) yet?
If so, where can I find information on implementing it in my app?
I am currently developing two iOS applications that require peer-to-peer connectivity. To facilitate this, I've implemented NWListener and NWConnection in both apps for network communication. To determine each device's public IP address and port—necessary for establishing a connection over the internet through my mobile operator's Carrier-Grade NAT (CGNAT)—I'm using a STUN server.
Despite successfully retrieving the external IP addresses and ports for both devices, I am unable to establish a peer-to-peer connection between them. My current setup involves initiating a connection using the public addresses and ports discovered through the STUN server response. However, all attempts to connect the devices directly have been unsuccessful.
I am seeking guidance on whether there are additional considerations or specific configurations needed when using NWListener, NWConnection, and a STUN server to establish a direct connection between devices in a CGNAT environment. Is there a particular step or network configuration I might be missing to successfully connect both iOS devices to each other using their external network details?
Hi, we are currently implementing below method for a quick POC in iOS (Xcode 15.3/macOS Sonoma 14.0):
func startQUICConnection() async {
// Set the initial stream to bidirectional.
options.direction = .bidirectional
self.mainConn?.stateUpdateHandler = { [weak self] state in
print("Main Connection State: \(state)")
switch state {
case .ready:
print("Ready...")
default:
break
}
}
// Don't forget to start the connection.
self.mainConn?.start(queue: self.queue)
}
This is what we have in the initializer of the class:
parameters = NWParameters(quic: options)
mainConn = NWConnection(to: endpoint, using: parameters)
These are the class's properties:
let endpoint = NWEndpoint.hostPort(host: "0.0.0.0", port: .init(integerLiteral: 6667))
let options = NWProtocolQUIC.Options(alpn: ["echo"])
let queue = DispatchQueue(label: "quic", qos: .userInteractive)
var mainConn: NWConnection? = nil
let parameters: NWParameters!
As per the logs, we never get to the .ready state for the NWConnection.
Logs:
nw_path_evaluator_create_flow_inner failed NECP_CLIENT_ACTION_ADD_FLOW (null) evaluator parameters: quic, attach protocol listener, attribution: developer, context: Default Network Context (private), proc: 022B7C28-0271-3628-8E5E-26B590B50E5B
nw_path_evaluator_create_flow_inner NECP_CLIENT_ACTION_ADD_FLOW 8FEBF750-979D-437F-B4A8-FB71F4C5A882 [22: Invalid argument]
nw_endpoint_flow_setup_channel [C2 0.0.0.0:6667 in_progress channel-flow (satisfied (Path is satisfied), interface: en0[802.11], ipv4, ipv6, dns, uses wifi)] failed to request add nexus flow
Main Connection State: preparing
Main Connection State: waiting(POSIXErrorCode(rawValue: 22): Invalid argument)
We're running a local server using proxygen on port 6667. It connects with the proxygen client though...
Have tried several thing but results are the same.
My team are now testing http/3 support in our app and backend. It looks strange to me how the behaviour is different between iOS 15.7.3 and 16.x (now 16.6).
It is a default URLSession config and just a regular URLRequest, with no assumesHTTP3Capable flag set. I observe the protocol in use with both collecting URLSessionTaskMetrics and the Network instrument.
On 15.7.3 the 1st request is done using h2, the network subsystem caches the Alt-Svc header (per host I suppose). Several seconds pass and then when I issue the same 2nd request a new connection is established and the protocol is upgraded to h3. This is all fine and as described in the documentation or wwdc videos.
However, when I take the same steps with a device running e.g. iOS 16.5.1 I see that the protocol is never upgraded to h3. Neither a longer timeout nor an app relaunch make any difference.
Interestingly, on my Ventura desktop the same url is also handled differently: h3 by Chrome but always h2 by Safari. In the mobile Safari on iOS 16, I'm also always shown HTTP/2 on e.g. the cloudflare status page for QUIC.
What can be the reason for such behaviour on iOS 16 and Apple platforms in general?
PS. I've tried running the app with CFNETWORK_DIAGNOSTICS but found no useful log messages to clarify problems with QUIC. Is there still a way to better diagnose such a problem?