Create network connections to send and receive data using the QUIC protocol.

Posts under QUIC tag

26 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Usage of QUIC APIs inside HTTP/3 implementation (URLSession/Request)
Hello, I have a very basic quic client implementation. When you run this code with some basic quic server, you will see that we can't get a handle to stream identifier 0, but behavior is actually different when we use URLSession/URLRequest, and I can see that some information can be sent over the wire for stream identifier 0 with that implementation. You can find both code below I'm using to test this. I'd like to get more info about how I can use stream identifier 0 with NWMultiplexGroup, if I can't use it with NWMultiplexGroup, I need a workaround to use stream with id 0 and use multiple streams over the same connection. import Foundation import Network let dispatchQueue = DispatchQueue(label: "quicConnectionQueue") let incomingStreamQueue = DispatchQueue(label: "quicIncStreamsQueue") let outgoingStreamQueue = DispatchQueue(label: "quicOutStreamsQueue") let quicOptions = NWProtocolQUIC.Options() quicOptions.alpn = ["test"] sec_protocol_options_set_verify_block(quicOptions.securityProtocolOptions, { (sec_prot_metadata, sec_trust, complete_callback) in complete_callback(true) }, dispatchQueue) let parameters = NWParameters(quic: quicOptions); let multiplexGroup = NWMultiplexGroup(to: NWEndpoint.hostPort(host: "127.0.0.1", port: 5000)) let connectionGroup = NWConnectionGroup(with: multiplexGroup, using: parameters) connectionGroup.stateUpdateHandler = { newState in switch newState { case .ready: print("Connected using QUIC!") let _ = createNewStream(connGroup: connectionGroup, content: "First Stream") let _ = createNewStream(connGroup: connectionGroup, content: "Second Stream") break default: print("Default hit: newState: \(newState)") } } connectionGroup.newConnectionHandler = { newConnection in // Set state update handler on incoming stream newConnection.stateUpdateHandler = { newState in // Handle stream states } // Start the incoming stream newConnection.start(queue: incomingStreamQueue) } connectionGroup.start(queue: dispatchQueue) sleep(50) func createNewStream(connGroup: NWConnectionGroup, content: String) -> NWConnection? { let stream = NWConnection(from: connectionGroup) stream?.stateUpdateHandler = { streamState in switch streamState { case .ready: stream?.send(content: content.data(using: .ascii), completion: .contentProcessed({ error in print("Send completed! Error: \(String(describing: error))") })) print("Sent data!") printStreamId(stream: stream) break default: print("Default hit: streamState: \(streamState)") } } stream?.start(queue: outgoingStreamQueue) return stream } func printStreamId(stream: NWConnection?) { let streamMetadata = stream?.metadata(definition: NWProtocolQUIC.definition) as? NWProtocolQUIC.Metadata print("stream Identifier: \(String(describing: streamMetadata?.streamIdentifier))") } URLSession/URLRequest code: import Foundation var networkManager = NetworkManager() networkManager.testHTTP3Request() sleep(5) class NetworkManager: NSObject, URLSessionDataDelegate { private var session: URLSession! private var operationQueue = OperationQueue() func testHTTP3Request() { if self.session == nil { let config = URLSessionConfiguration.default config.requestCachePolicy = .reloadIgnoringLocalCacheData self.session = URLSession(configuration: config, delegate: self, delegateQueue: operationQueue) } let urlStr = "https://localhost:5000" let url = URL(string: urlStr)! var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0) request.assumesHTTP3Capable = true self.session.dataTask(with: request) { (data, response, error) in if let error = error as NSError? { print("task transport error \(error.domain) / \(error.code)") return } guard let data = data, let response = response as? HTTPURLResponse else { print("task response is invalid") return } guard 200 ..< 300 ~= response.statusCode else { print("task response status code is invalid; received \(response.statusCode), but expected 2xx") return } print("task finished with status \(response.statusCode), bytes \(data.count)") }.resume() } } extension NetworkManager { func urlSession(_ session: URLSession, task: URLSessionTask, didFinishCollecting metrics: URLSessionTaskMetrics) { let protocols = metrics.transactionMetrics.map { $0.networkProtocolName ?? "-" } print("protocols: \(protocols)") } func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.serverTrust == nil { completionHandler(.useCredential, nil) } else { let trust: SecTrust = challenge.protectionSpace.serverTrust! let credential = URLCredential(trust: trust) completionHandler(.useCredential, credential) } } }
0
0
116
1w
Using Network Framework + Bonjour + QUIC + TLS
Hello, I was able to use the TicTackToe code base and modify it such that I have a toggle at the top of the screen that allows me to start / stop the NWBrowser and NWListener. I have it setup so when the browser finds another device it attempts to connect to it. I support N devices / connections. I am able to use the NWParameters extension that is in the TickTackToe game that uses a passcode and TLS. I am able to send messages between devices just fine. Here is what I used extension NWParameters { // Create parameters for use in PeerConnection and PeerListener. convenience init(passcode: String) { // Customize TCP options to enable keepalives. let tcpOptions = NWProtocolTCP.Options() tcpOptions.enableKeepalive = true tcpOptions.keepaliveIdle = 2 // Create parameters with custom TLS and TCP options. self.init(tls: NWParameters.tlsOptions(passcode: passcode), tcp: tcpOptions) // Enable using a peer-to-peer link. self.includePeerToPeer = true } // Create TLS options using a passcode to derive a preshared key. private static func tlsOptions(passcode: String) -> NWProtocolTLS.Options { let tlsOptions = NWProtocolTLS.Options() let authenticationKey = SymmetricKey(data: passcode.data(using: .utf8)!) let authenticationCode = HMAC<SHA256>.authenticationCode(for: "HI".data(using: .utf8)!, using: authenticationKey) let authenticationDispatchData = authenticationCode.withUnsafeBytes { DispatchData(bytes: $0) } sec_protocol_options_add_pre_shared_key(tlsOptions.securityProtocolOptions, authenticationDispatchData as __DispatchData, stringToDispatchData("HI")! as __DispatchData) sec_protocol_options_append_tls_ciphersuite(tlsOptions.securityProtocolOptions, tls_ciphersuite_t(rawValue: TLS_PSK_WITH_AES_128_GCM_SHA256)!) return tlsOptions } // Create a utility function to encode strings as preshared key data. private static func stringToDispatchData(_ string: String) -> DispatchData? { guard let stringData = string.data(using: .utf8) else { return nil } let dispatchData = stringData.withUnsafeBytes { DispatchData(bytes: $0) } return dispatchData } } When I try to modify it to use QUIC and TLS 1.3 like so extension NWParameters { // Create parameters for use in PeerConnection and PeerListener. convenience init(psk: String) { self.init(quic: NWParameters.quicOptions(psk: psk)) self.includePeerToPeer = true } private static func quicOptions(psk: String) -> NWProtocolQUIC.Options { let quicOptions = NWProtocolQUIC.Options(alpn: ["h3"]) let authenticationKey = SymmetricKey(data: psk.data(using: .utf8)!) let authenticationCode = HMAC<SHA256>.authenticationCode(for: "hello".data(using: .utf8)!, using: authenticationKey) let authenticationDispatchData = authenticationCode.withUnsafeBytes { DispatchData(bytes: $0) } sec_protocol_options_set_min_tls_protocol_version(quicOptions.securityProtocolOptions, .TLSv13) sec_protocol_options_set_max_tls_protocol_version(quicOptions.securityProtocolOptions, .TLSv13) sec_protocol_options_add_pre_shared_key(quicOptions.securityProtocolOptions, authenticationDispatchData as __DispatchData, stringToDispatchData("hello")! as __DispatchData) sec_protocol_options_append_tls_ciphersuite(quicOptions.securityProtocolOptions, tls_ciphersuite_t(rawValue: TLS_AES_128_GCM_SHA256)!) sec_protocol_options_set_verify_block(quicOptions.securityProtocolOptions, { _, _, sec_protocol_verify_complete in sec_protocol_verify_complete(true) }, .main) return quicOptions } // Create a utility function to encode strings as preshared key data. private static func stringToDispatchData(_ string: String) -> DispatchData? { guard let stringData = string.data(using: .utf8) else { return nil } let dispatchData = stringData.withUnsafeBytes { DispatchData(bytes: $0) } return dispatchData } } I get the following errors in the console boringssl_session_handshake_incomplete(241) [C3:1][0x109d0c600] SSL library error boringssl_session_handshake_error_print(44) [C3:1][0x109d0c600] Error: 4459057536:error:100000ae:SSL routines:OPENSSL_internal:NO_CERTIFICATE_SET:/Library/Caches/com.apple.xbs/Sources/boringssl/ssl/tls13_server.cc:882: boringssl_session_handshake_incomplete(241) [C4:1][0x109d0d200] SSL library error boringssl_session_handshake_error_print(44) [C4:1][0x109d0d200] Error: 4459057536:error:100000ae:SSL routines:OPENSSL_internal:NO_CERTIFICATE_SET:/Library/Caches/com.apple.xbs/Sources/boringssl/ssl/tls13_server.cc:882: nw_endpoint_flow_failed_with_error [C3 fe80::1884:2662:90ca:b011%en0.65328 in_progress channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], scoped, ipv4, dns, uses wifi)] already failing, returning nw_endpoint_flow_failed_with_error [C4 192.168.0.98:65396 in_progress channel-flow (satisfied (Path is satisfied), viable, interface: en0[802.11], scoped, ipv4, dns, uses wifi)] already failing, returning quic_crypto_connection_state_handler [C1:1] [2ae0263d7dc186c7-] TLS error -9858 (state failed) nw_connection_copy_connected_local_endpoint_block_invoke [C3] Client called nw_connection_copy_connected_local_endpoint on unconnected nw_connection nw_connection_copy_connected_remote_endpoint_block_invoke [C3] Client called nw_connection_copy_connected_remote_endpoint on unconnected nw_connection nw_connection_copy_protocol_metadata_internal_block_invoke [C3] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection quic_crypto_connection_state_handler [C2:1] [84fdc1e910f59f0a-] TLS error -9858 (state failed) nw_connection_copy_connected_local_endpoint_block_invoke [C4] Client called nw_connection_copy_connected_local_endpoint on unconnected nw_connection nw_connection_copy_connected_remote_endpoint_block_invoke [C4] Client called nw_connection_copy_connected_remote_endpoint on unconnected nw_connection nw_connection_copy_protocol_metadata_internal_block_invoke [C4] Client called nw_connection_copy_protocol_metadata_internal on unconnected nw_connection Am I missing some configuration? I noticed with the working code that uses TCP and TLS that there is an NWParameters initializer that accepts tls options and tcp option but there isnt one that accepts tls and quic. Thank you for any help :)
19
0
634
4d
Combining Bonjour and QUIC multiplex group using Network.framework
In my iOS app I am currently using Bonjour (via Network.framework) to have two local devices find each other and then establish a single bidirectional QUIC connection between them. I am now trying to transition from a single QUIC connection to a QUIC multiplex group (NWMultiplexGroup) with multiple QUIC streams sharing a single tunnel. However I am hitting an error when trying to establish the NWConnectionGroup tunnel to the endpoint discovered via Bonjour. I am using the same "_aircam._udp" Bonjour service name I used before (for the single connection) and am getting the following error: nw_group_descriptor_allows_endpoint Endpoint iPhone15Pro._aircam._udp.local. is of invalid type for multiplex group Does NWConnectionGroup not support connecting to Bonjour endpoints? Or do I need a different service name string? Or is there something else I could be doing wrong? If connecting to Bonjour endpoints isn't supported, I assume I'll have to work around this by first resolving the discovered endpoint using Quinn's code from this thread? And I guess I would then have to have two NWListeners, one just for Bonjour discovery and one listening on a port of my choice for the multiplex tunnel connection?
12
0
276
4w
Prioritizing QUIC streams?
When creating multiple QUIC streams (NWConnections) sharing one QUIC tunnel (using NWMultiplexGroup), is it possible to assign different priorities to the streams? And if yes, how? The only prioritization option I found so far is NWConnection.ContentContext.relativePriority, but I assume that is for prioritizing messages within a single NWConnection?
5
0
265
Oct ’24
Error during continuous transmission in QUIC DATAGRAM communication
Hello, I have a question about sending data in QUIC DATAGRAM. Regarding sending data in QUIC DATAGRAM, when I create a NWConnectionGroup and then use the send method of that group to send data in sequence, quite often I get an Optional(POSIXErrorCode(rawValue: 89): Operation canceled) error. A little Thread.sleep between sends improves the situation somewhat, but the above error still occurs. Also, since I want to send the frame data of the video in this communication process, adding a wait will drastically reduce performance and make the speed impractical. However, if send is executed continuously without adding weights, the above error will occur 80% of the time or more. Is it necessary to send while monitoring some status when sending? In communication using QUIC Stream, when connecting to the server with NWConnection and sending with its send method, the above error does not occur even if send is executed without wait, and data can be transferred with good performance. I am trying to use DATAGRAM communication to further increase throughput, but I am not having much success, and there is not much information on DATAGRAM communication. Thank you in advance for your help.
3
3
255
Oct ’24
Inquiry Regarding Data Migration Using Quick Start
I am currently developing an iOS app with a new feature that utilizes Quick Start for data migration between devices. We are testing this in a test environment using an app distributed via TestFlight. However, we are encountering an issue where the app installed on the pre-migration device (distributed via TestFlight) does not transfer to the post-migration device. Could this issue be related to the fact that the app was distributed via TestFlight? Is there any restriction where only apps released via the App Store can be migrated using Quick Start? We would appreciate it if you could provide some insights into the cause of this issue and any alternative testing methods.
1
0
248
Oct ’24
Missing buffers on client side
Hi, We are working with a small QUIC POC, in which the macbook pro is the server and the vision pro the client (we use it to test QUIC's functionality). We have below logic to send small buffers (128k) using only one stream because we want the data to arrive in order and reliably as QUIC guarantees: private func createDummyData() { dummyData.append(Data(bytes: &frameNumber, count: MemoryLayout<UInt64>.size)) frameNumber += 1 } private func sendDataToClient() { createDummyData() let start = Date() Thread.sleep(forTimeInterval: 0.015) outgoingConnection?.sendBuffer(dummyData) { [weak self] in let interval = Date().timeIntervalSince(start) print("--> frame #: \(String(describing: self?.frameNumber)), send took: \(interval) seconds") self?.dummyData.removeLast(8) self?.sendDataToClient() } } As you can see we are waiting for the completion handler to call the next send operation. We needed to add a delay (0.015) because even when the data is arriving in order, we are not receiving a considerable amount of buffer on the client side. If we remove the delay, this is the way we are receiving our data. By the way, we are including a frame number (1,2,3,4....) on each buffer so we know which one arrived at the client : Connected to QUIC bi-di tunnel id: 0... Timestamp: 00:42:40.413, Buffer received... Frame number: 0, received... Timestamp: 00:42:40.414, Buffer received... Frame number: 1, received... Timestamp: 00:42:40.416, Buffer received... Frame number: 29, received... Timestamp: 00:42:40.416, Buffer received... Frame number: 30, received... Timestamp: 00:42:40.418, Buffer received... Frame number: 43, received... Timestamp: 00:42:40.418, Buffer received... Frame number: 52, received... Timestamp: 00:42:40.422, Buffer received... Frame number: 65, received... Timestamp: 00:42:40.424, Buffer received... Frame number: 80, received... Timestamp: 00:42:40.426, Buffer received... Frame number: 90, received... As you can see, we have received frames number 0 and 1 but after that we received # 29 and then jumps from 30 to 43 and 52 and 65. Again, if we introduce the delay this is not the case, is not fixing it but at least there are not that many losses. We thought QUIC had an internal sending queue in which every frame is waiting to be sent and it will be delivered reliably. Kindly let us know what are we missing.
0
0
365
Aug ’24
QUIC & http3
Hi, This is basically a fundamental question on the QUIC's implementation via the Network framework. We are using the NWMultiplexGroup object to deal with multiples streams over the wire, but we would like to understand if this object is using http3 under the hood, because our understanding is the actual connection multiplexing is happening under that protocol. If this is not the case, can you please elaborate a little bit more on this. Btw, in this implementation we are not using URLSession at all, is just pure QUIC via Network framework. Thanks in advance.
1
0
418
Aug ’24
QUIC streams/connections terminated when taking off the AVP
Hi, We have this situation in which we are sending buffers from a server to the Vision Pro in a local network and for some reason when we take the headset off of the user's head, the QUIC stream we are using are getting closed/terminated/disconnected. What our options are in order to remove this behavior, probably resume or make sure the AVP is ready again to receive the buffers from the server in a graceful manner?
1
0
467
Aug ’24
macOS Server App on background state
Hi, let us explain the situation we have: We have a macOS server app which happens to be/act as a QUIC server (this setup is for a live demo). Once the server receives a streaming request from the client, server starts to send a bunch of QUIC streams to the client. The server needs to run on a macbook pro for the live demo and everything works fine, now when we click on a different app (the server app looses focus) the server app goes to background state and the network activity just stops going from 90MB/s to almost zero, but when we click on the server app again, the network activity goes back to 90MB/s and it continues normally. We understand this is the OS taking some decisions by managing resources efficiently. Question: Kindly let us know which options do we have to keep the server app QUIC networking tasks continuously running, even if it is not on the foreground (basically for it to behave like an actual server/service)? Thanks in advance
4
0
504
Aug ’24
QUIC Network framework interoperability
We would like to understand/double check if it is possible to use QUIC in Swift via Network framework as the client along with some other QUIC solution on the server (ex. s2n-quic, quiche, msquic, etc..) which won't be a macOS server. If that interoperability is indeed possible, the NWConnectionGroup won't be an approach we could use IMO, since probably we will need to develop that from scratch on both sides. Thanks in advance.
3
0
584
Jul ’24
assumesHTTP3Capable not working only on some iPhones
Hi, We are using HTTP3 only and hence using assumesHTTP3Capable for every request. It worked so far but now encountered one iPhone that never honor this flag and always tries to create a connection using TCP: [tcp] tcp_input [C1:3] flags=[R.] seq=0, ack=2023568485, win=0 state=SYN_SENT rcv_nxt=0, snd_una=2023568484 The request is created like this: let url = URL(string: urlString)! var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 60.0) request.assumesHTTP3Capable = true return try await urlSession.data(for: request) iOS: 16 XCode: 15.3 In what cases iOS CFNetwork would not honor "assumesHTTP3Capable" ? (or how can I find out why?)
4
0
545
Jul ’24
How to find out network connection error details
Hi, When running my iOS app in Xcode, I got the following message in the console multiple times: [connection] nw_read_request_report [C1] Receive failed with error "Operation timed out" It seems not critical as my app still works, but how can I find out more details of the connection that printed this message? For example, the network request the caused this, or the URL? Xcode: 15.3 iOS 17 SwiftUI app
5
0
685
Jun ’24
QUIC Connection Group Server Sending Pace
We have an implementation in which we use QUIC via a connection group, server are client are on Swift using the Network framework. Our use case is, the server should send data buffers to the client as fast and as much as possible, now the pace to call the send method from the server should be carefully done, because if we send too much data of course the client is not gonna be able to receive it. The question would be, is there a way to query the congestion window so we know on the server side, how much data we should be able to send at some point? Asking because we are not getting all the data we are sending from the server on our client side... We are using these settings: let options = NWProtocolQUIC.Options(alpn: ["h3"]) options.direction = .bidirectional // options.idleTimeout = 86_400_000 options.maxUDPPayloadSize = Int.max options.initialMaxData = Int.max options.initialMaxStreamDataBidirectionalLocal = Int.max options.initialMaxStreamDataBidirectionalRemote = Int.max options.initialMaxStreamDataUnidirectional = Int.max options.initialMaxStreamsBidirectional = 400 options.initialMaxStreamsUnidirectional = 400 Questions: 1.- Can we get a little more detail in above options, specifically on their impact to the actual connection? 2.- IsinitialMaxData the actual congestion window value 3.- Are we missing something or making incorrect assumptions? Thanks in advance.
10
0
878
Jul ’24
NWConnectionGroup w/QUIC Best Practices
Hello. Wanted to ask about the right way, or the intended way to leverage NWConnectionGroup for a QUIC based streaming solution. The use case is, we are making a request from the client in order to play a movie, and we want to send as much video frames as possible (and as fast as possible) from the streaming server, which also uses the Network framework. Our understanding is, NWConnectionGroup will open a QUIC tunnel between both parties so we can multiplex different streams to the client and we are already doing that. We see a throughput of approx. 20-35MB/s (client device is an iPad and server is an M2 macbook pro running a server app) and we would like to understand if we can improve these results way more. For example: 1.- Is it a good practice to create a second tunnel (NWConnectionGroup), or is not needed here?. We tried that, but the second one is also coming with id 0 on the metadata object, just as the first group we instantiated, not sure why this is the case. 2.- We are using a pool of several NWConnection (initialized with the group object) already instantiated, that way we send a video buffer in chunks as a stream on each connection. We use one connection for a buffer and when we need to send another buffer we use a different NWConnection pulled from the pool. We maybe just want a confirmation/validation of what we are doing, or to see if we are missing something on our implementation... Thanks in advance.
2
0
640
Oct ’24
Crash in Network framework nw_queue_context_async + 76 (queue.m:87)
Hi, We recently released a version of our app where we use 'NWParameters.PrivacyContext'. On iOS 17.4 and iOS 17.4.1 the app crashes with a following crash: Distributor ID: com.apple.AppStore Hardware Model: iPhone12,1 Process: <app> Path: <path to app> Identifier: <bundle id> Version: <version> AppStoreTools: 15E204 AppVariant: 1:iPhone12,1:15 Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: <our bundle id> [4899] Date/Time: 2024-04-29 01:50:13.4113 +0300 Launch Time: 2024-04-29 01:13:47.6252 +0300 OS Version: iPhone OS 17.4.1 (21E236) Release Type: User Baseband Version: 5.00.00 Report Version: 104 Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000054 Exception Codes: 0x0000000000000001, 0x0000000000000054 VM Region Info: 0x54 is not in any region. Bytes before following region: 4334124972 REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL UNUSED SPACE AT START ---> __TEXT 102558000-1063e4000 [ 62.5M] r-x/r-x SM=COW <path to app> Termination Reason: SIGNAL 11 Segmentation fault: 11 Terminating Process: exc handler [24308] Triggered by Thread: 18 Kernel Triage: VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter Thread 18 name: Thread 18 Crashed: 0 libdispatch.dylib 0x00000001a573b7d8 dispatch_async + 192 (queue.c:940) 1 Network 0x000000019ddbdb38 nw_queue_context_async + 76 (queue.m:87) 2 Network 0x000000019e512748 invocation function for block in nw_socket_init_socket_event_source(nw_socket*, unsigned int) + 1488 (protocol_socket.cpp:4351) 3 libdispatch.dylib 0x00000001a5736dd4 _dispatch_client_callout + 20 (object.m:576) 4 libdispatch.dylib 0x00000001a573a2d8 _dispatch_continuation_pop + 600 (queue.c:321) 5 libdispatch.dylib 0x00000001a574e1c8 _dispatch_source_latch_and_call + 420 (source.c:596) 6 libdispatch.dylib 0x00000001a574cd8c _dispatch_source_invoke + 832 (source.c:961) 7 libdispatch.dylib 0x00000001a5740284 _dispatch_workloop_invoke + 1756 (queue.c:4570) 8 libdispatch.dylib 0x00000001a5749cb4 _dispatch_root_queue_drain_deferred_wlh + 288 (queue.c:6998) 9 libdispatch.dylib 0x00000001a5749528 _dispatch_workloop_worker_thread + 404 (queue.c:6592) 10 libsystem_pthread.dylib 0x00000001f981cf20 _pthread_wqthread + 288 (pthread.c:2665) 11 libsystem_pthread.dylib 0x00000001f981cfc0 start_wqthread + 8 (:-1) Thread 18 crashed with ARM Thread State (64-bit): x0: 0x0000000301a922e0 x1: 0x000000032471a720 x2: 0x0000000000000000 x3: 0x00000003015e2300 x4: 0x0000000000000003 x5: 0x00000000000022e0 x6: 0x0000000172462ef0 x7: 0x000000000000008b x8: 0x00000000000008ff x9: 0x0000000000000000 x10: 0x0000000000010000 x11: 0x0000000000000020 x12: 0x00000003016f3854 x13: 0x00000000001ff800 x14: 0x00000000000007fb x15: 0x0000000089800118 x16: 0x00000001a573511c x17: 0x000000019e514740 x18: 0x0000000000000000 x19: 0x0000000000000000 x20: 0x0000000308eae8c0 x21: 0x000000032471a730 x22: 0x000000032471b0e0 x23: 0x000000000000e023 x24: 0x0000000172463085 x25: 0x000000002b1d034c x26: 0x0000000000000800 x27: 0x0000000000000000 x28: 0x0000000000000000 fp: 0x000000032471a6b0 lr: 0xad5ba301a573b750 sp: 0x000000032471a690 pc: 0x00000001a573b7d8 cpsr: 0x80000000 esr: 0x92000006 (Data Abort) byte read Translation fault What could be the reason for it?
2
0
566
Apr ’24
NWConnectionGroup no way to send/receive on QUIC stream with identifier `0`
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?
2
0
730
Apr ’24
Troubleshooting Peer-to-Peer Connection Failure between iOS Apps Using NWListener, NWConnection, and STUN
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?
1
0
689
Mar ’24
QUIC connection error
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.
1
0
1.5k
Mar ’24