Networking

RSS for tag

Explore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.

Networking Documentation

Posts under Networking subtopic

Post

Replies

Boosts

Views

Activity

Stumped by URLSession behaviour I don't understand...
I have an app that has been using the following code to down load audio files: if let url = URL(string: episode.fetchPath()) { var request = URLRequest(url: url) request.httpMethod = "get" let task = session.downloadTask(with: request) And then the following completionHandler code: func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { try FileManager.default.moveItem(at: location, to: localUrl) In the spirit of modernization, I'm trying to update this code to use async await: var request = URLRequest(url: url) request.httpMethod = "get" let (data, response) = try await URLSession.shared.data(for: request) try data.write(to: localUrl, options: [.atomicWrite, .completeFileProtection]) Both these code paths use the same url value. Both return the same Data blobs (they return the same hash value) Unfortunately the second code path (using await) introduces a problem. When the audio is playing and the iPhone goes to sleep, after 15 seconds, the audio stops. This problem does not occur when running the first code (using the didFinish completion handler) Same data, stored in the same URL, but using different URLSession calls. I would like to use async/await and not have to experience the audio ending after just 15 seconds of the device screen being asleep. any guidance greatly appreciated.
7
0
526
Jan ’26
Once started, NWPathMonitor appears to be kept alive until cancelled, but is this documented?
NWPathMonitor appears to retain itself (or is retained by some internal infrastructure) once it has been started until cancelled. This seems like it can lead to memory leaks if the references to to the monitor are dropped. Is this behavior documented anywhere? func nwpm_self_retain() { weak var weakRef: NWPathMonitor? autoreleasepool { let monitor: NWPathMonitor = NWPathMonitor() weakRef = monitor monitor.start(queue: .main) // monitor.cancel() // assertion fails unless this is called } assert(weakRef == nil) } nwpm_self_retain()
3
0
136
Jan ’26
MultiPeer Connectivity: Device discovery succeeds but handshake fails when off-network
Hi, I am building an app that depends on multiple iOS devices connecting to a designated "coordinator" iOS device. I am using MPC, and it works great when the devices are connected to the same WiFi AP, with virtually 100% connection success. My definition of success is a near instant detection of available devices, >95% connection success rate, and a stable ongoing connection with no unexpected disconnects. The issue arises when the devices are not connected to the same WiFi network (or connected to no network with WiFi and bluetooth still on). Devices detect each other immediately, but when initiating a connection, both devices initiate a handshake, but the connection is not successful. In the few times where the connection succeeds, the connection quality is high, stable, and doesn't drop. Is this a known limitation of the framework? Could I be doing something wrong in my implementation?
1
0
215
Dec ’25
Why nslookup dns queries not routed to NETransparentProxyProvider
I’m using an NETransparentProxyProvider where I add UDP-53 rules to intercept DNS queries from a private application. These queries are resolved locally on the endpoint by returning a custom DNS response. Example Rules look like this: NENetworkRule(destinationHost: NWHostEndpoint(hostname: "mypaapp.com", port: 53),protocol:.UDP) This works as expected through browser and ping. handleNewUDPFlow/handleNewFlow with NEAppProxyUDPFlow gets called where custom dns response get written. Using nslookup mypaapp.com doesn't works. Why does this behaves differently for nslookup?
1
0
106
Dec ’25
NetworkConnection throws EINVAL when receiving ping/pong control frames
Summary NetworkConnection<WebSocket> in iOS 26 Network framework throws POSIXErrorCode(rawValue: 22): Invalid argument when receiving WebSocket ping (opcode 9) or pong (opcode 10) control frames. This prevents proper WebSocket keep-alive functionality. Environment iOS 26.0 (Simulator) macOS 26.1 Xcode 26.0 Note: This issue was initially discovered on iOS 26 Simulator. The same behavior was confirmed on macOS 26, suggesting a shared bug in the Network framework. The attached sample code is for macOS for easier reproduction. Description When using the new NetworkConnection<WebSocket> API introduced in iOS 26 or macOS 26, the receive() method throws EINVAL error whenever a ping or pong control frame is received from the server. This is a critical issue because: WebSocket servers commonly send ping frames to keep connections alive Clients send ping frames to verify connection health The receive callback never receives the ping/pong frame - the error occurs before the frame reaches user code Steps to Reproduce Create a WebSocket connection to any server that supports ping/pong (e.g., wss://echo.websocket.org): import Foundation import Network // MARK: - WebSocket Ping/Pong EINVAL Bug Reproduction // This sample demonstrates that NetworkConnection<WebSocket> throws EINVAL // when receiving ping or pong control frames. @main struct WebSocketPingPongBug { static func main() async { print("=== WebSocket Ping/Pong EINVAL Bug Reproduction ===\n") do { try await testPingPong() } catch { print("Test failed with error: \(error)") } } static func testPingPong() async throws { let host = "echo.websocket.org" let port: UInt16 = 443 print("Connecting to wss://\(host)...") let endpoint = NWEndpoint.hostPort( host: NWEndpoint.Host(host), port: NWEndpoint.Port(rawValue: port)! ) try await withNetworkConnection(to: endpoint, using: { WebSocket { TLS { TCP() } } }) { connection in print("Connected!\n") // Start receive loop in background let receiveTask = Task { var messageCount = 0 while !Task.isCancelled { do { let (data, metadata) = try await connection.receive() messageCount += 1 print("[\(messageCount)] Received frame - opcode: \(metadata.opcode)") if let text = String(data: data, encoding: .utf8) { print("[\(messageCount)] Content: \(text)") } else { print("[\(messageCount)] Binary data: \(data.count) bytes") } } catch let error as NWError { if case .posix(let code) = error, code == .EINVAL { print("❌ EINVAL error occurred! (POSIXErrorCode 22: Invalid argument)") print(" This is the bug - ping/pong frame caused EINVAL") // Continue to demonstrate workaround continue } print("Receive error: \(error)") break } catch { print("Receive error: \(error)") break } } } // Wait for initial message from server try await Task.sleep(for: .seconds(2)) // Test 1: Send text message (should work) print("\n--- Test 1: Sending text message ---") try await connection.send("Hello, WebSocket!") print("✅ Text message sent") try await Task.sleep(for: .seconds(1)) // Test 2: Send ping (pong response will cause EINVAL) print("\n--- Test 2: Sending ping frame ---") print("Expecting EINVAL when pong is received...") let pingMetadata = NWProtocolWebSocket.Metadata(opcode: .ping) try await connection.ping(Data()) { pingMetadata } print("✅ Ping sent, waiting for pong...") // Wait for pong response try await Task.sleep(for: .seconds(2)) // Cleanup receiveTask.cancel() print("\n=== Test Complete ===") print("If you saw 'EINVAL error occurred!' above, the bug is reproduced.") } } } The receive() call fails with error when pong arrives: ❌ EINVAL error occurred! (POSIXErrorCode 22: Invalid argument) Test Results Scenario Result Send/receive text (opcode 1) ✅ OK Client sends ping, receives pong ❌ EINVAL on pong receive Expected Behavior The receive() method should successfully return ping and pong frames, or at minimum, handle them internally without throwing an error. The autoReplyPing option should allow automatic pong responses without disrupting the receive loop. Actual Behavior When a ping or pong control frame is received: The receive() method throws NWError.posix(.EINVAL) The frame never reaches user code (no opcode check is possible) The connection remains valid, but the receive loop is interrupted Workaround Catch the EINVAL error and restart the receive loop: while !Task.isCancelled { do { let received = try await connection.receive() // Process message } catch let error as NWError { if case .posix(let code) = error, code == .EINVAL { // Control frame caused EINVAL, continue receiving continue } throw error } } This workaround allows continued operation but: Cannot distinguish between ping-related EINVAL and other EINVAL errors Cannot access the ping/pong frame content Cannot implement custom ping/pong handling Impact WebSocket connections to servers that send periodic pings will experience repeated EINVAL errors Applications must implement workarounds that may mask other legitimate errors Additional Information Packet capture confirms ping/pong frames are correctly transmitted at the network level The error occurs in the Network framework's internal processing, before reaching user code
5
0
266
Dec ’25
NETransparentProxyProvider – Support for Port Ranges in NENetworkRule
Hello, We are implementing a Transparent Proxy using NETransparentProxyProvider and configuring NETransparentProxyNetworkSettings with NENetworkRule. Currently, NENetworkRule requires: NENetworkRule( destinationHost: NWHostEndpoint(hostname: String, port: String), protocol: .TCP / .UDP / .any ) NWHostEndpoint.port accepts only a single port value (as a String) or an empty string for all ports. At present, we are creating a separate NENetworkRule for each port in the range (ex for range 49152–65535 approximately 16,384 rules). After deploying this configuration, we observe the following behavior: nesessionmanager starts consuming very high CPU (near 100%) The system becomes unresponsive The device eventually hangs and restarts automatically The behavior resembles a kernel panic scenario This strongly suggests that creating thousands of NENetworkRule entries may not be a supported or scalable approach. Questions: Is there any officially supported way to specify a port range in NENetworkRule? Is creating thousands of rules (one per port) considered acceptable or supported? Is the recommended design to intercept broadly (e.g., port = "") and filter port ranges inside handleNewTCPFlow / handleNewUDPFlow instead? Are there documented system limits for the number of NENetworkRule entries allowed in NETransparentProxyNetworkSettings?
2
0
127
2w
Local Network permission on macOS 15 macOS 26: multicast behaves inconsistently and regularly drops
Problem description Since macOS Sequoia, our users have experienced issues with multicast traffic in our macOS app. Regularly, the app starts but cannot receive multicast, or multicast eventually stops mid-execution. The app sometimes asks again for Local Network permission, while it was already allowed so. Several versions of our app on a single machine are sometimes (but not always) shown as different instances in the System Settings > Privacy & Security > Local Network list. And when several instances are shown in that list, disabling one disables all of them, but it does not actually forbids the app from receiving multicast traffic. All of those issues are experienced by an increasing number of users after they update their system from macOS 14 to macOS 15 or 26, and many of them have reported networking issues during production-critical moments. We haven't been able to find the root cause of those issues, so we built a simple test app, called "FM Mac App Test", that can reproduce multicast issues. This app creates a GCDAsyncUdpSocket socket to receive multicast packets from a piece of hardware we also develop, and displays a simple UI showing if such packets are received. The app is entitled with "Custom Network Protocol", is built against x86_64 and arm64, and is archived (signed and notarized). We can share the source code if requested. Out of the many issues our main app exhibits, the test app showcases some: The app asks several times for Local Network permission, even after being allowed so previously. After allowing the app's Local Network and rebooting the machine, the System Settings > Privacy & Security > Local Network does not show the app, and the app asks again for Local Network access. The app shows a different Local Network Usage Description than in the project's plist. Several versions of the app appear as different instances in the Privacy list, and behave strangely. Toggling on or off one instance toggles the others. Only one version of the app seems affected by the setting, the other versions always seem to have access to Local Network even when the toggle is set to off. We even did see messages from different app versions in different user accounts. This seems to contradicts Apple's documentation that states user accounts have independent Privacy settings. Can you help us understand what we are missing (in terms of build settings, entitlements, proper archiving...) so our app conforms to what macOS expects for proper Local Network behavior? Related material Local Network Privacy breaks Application: this issue seemed related to ours, but the fix was to ensure different versions of the app have different UUIDs. We ensured that ourselves, to no improvement. Local Network FAQ Technote TN3179 Steps to Reproduce Test App is developed on Xcode 15.4 (15F31d) on macOS 14.5 (23F79), and runs on macOS 26.0.1 (25A362). We can share the source code if requested. On a clean install of macOS Tahoe (our test setup used macOS 26.0.1 on a Mac mini M2 8GB), we upload the app (version 5.1). We run the app, make sure the selected NIC is the proper one, and open the multicast socket. The app asks us to allow Local Network, we allow it. The alert shows a different Local Network Usage Description than the one we set in our project's plist. The app properly shows packets are received from the console on our LAN. We check the list in System Settings > Privacy & Security > Local Network, it includes our app properly allowed. We then reboot the machine. After reboot, the same list does not show the app anymore. We run the app, it asks again about Local Network access (still with incorrect Usage Description). We allow it again, but no console packet is received yet. Only after closing and reopening the socket are the console packets received. After a 2nd reboot, the System Settings > Privacy & Security > Local Network list shows correctly the app. The app seems to now run fine. We then upload an updated version of the same app (5.2), also built and notarized. The 2nd version is simulating when we send different versions of our main app to our users. The updated version has a different UUID than the 1st version. The updated version also asks for Local Network access, this time with proper Usage Description. A 3rd updated version of the app (5.3, also with unique UUID) behaves the same. The System Settings > Privacy & Security > Local Network list shows three instances of the app. We toggle off one of the app, all of them toggle off. The 1st version of the app (5.1) does not have local network access anymore, but both 2nd and 3rd versions do, while their toggle button seems off. We toggle on one of the app, all of them toggle on. All 3 versions have local network access.
15
1
621
2d
Local network access is blocked when two almost identical apps are installed
We are developing an enterprise app that connects to a local server. It uses simple URLSessions. There is a view in the app where you enter the server url (IP address) and a connection check is made. iOS asks for permission to access the local network. Everything works. If the server is reachable, the connection info is saved. Recently we encountered a very strange issue: We also have a beta version of this app. If we first install the normal version on a device, enter the server IP, save, and then install the beta version and do the same there: It does not get a connection (it waits for the timeout). The strange part is: If I try to configure the connection in the normal version again, it also does not work, it just waits for the timeout. The really strange part: When I delete the beta version, while the normal version is waiting for its connection, the connection succeeds immediately. Both versions have a different display name, bundle id. I also tried using a device that is not in our MDM: same problem. Even the iOS version seems to have no impact: I tried on iOS 15, 18 and 26. Is there an explanation and hopefully also a solution to this problem?
2
0
65
Dec ’25
macOS Sequoia No Route to Host on first request. Retries work.
My app has local network permission on macOS Sequoia and works in most cases. I've noticed that after unlocking my MacBook Pro, the very first request will regularly fail with a No Route to Host. A simple retry resolves the issue, but I would have expected the very first request to succeed. Is this is a known issue on macOS Sequoia or by design? I'd prefer not to add a retry for this particular request as the app is a network utility.
6
1
2.1k
Apr ’25
URLRequest(url:cachePolicy:timeoutInterval:) started to crash in iOS 26
For a long time our app had this creation of a URLRequest: var urlRequest = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: timeout) But since iOS 26 was released we started to get crashes in this call. It is created on a background thread. Thread 10 Crashed: 0 libsystem_malloc.dylib 0x00000001920e309c _xzm_xzone_malloc_freelist_outlined + 864 (xzone_malloc.c:1869) 1 libswiftCore.dylib 0x0000000184030360 swift::swift_slowAllocTyped(unsigned long, unsigned long, unsigned long long) + 56 (Heap.cpp:110) 2 libswiftCore.dylib 0x0000000184030754 swift_allocObject + 136 (HeapObject.cpp:245) 3 Foundation 0x00000001845dab9c specialized _ArrayBuffer._consumeAndCreateNew(bufferIsUnique:minimumCapacity:growForAppend:) + 120 4 Foundation 0x00000001845daa58 specialized static _SwiftURL._makeCFURL(from:baseURL:) + 2288 (URL_Swift.swift:1192) 5 Foundation 0x00000001845da118 closure #1 in _SwiftURL._nsurl.getter + 112 (URL_Swift.swift:64) 6 Foundation 0x00000001845da160 partial apply for closure #1 in _SwiftURL._nsurl.getter + 20 (<compiler-generated>:0) 7 Foundation 0x00000001845da0a0 closure #1 in _SwiftURL._nsurl.getterpartial apply + 16 8 Foundation 0x00000001845d9a6c protocol witness for _URLProtocol.bridgeToNSURL() in conformance _SwiftURL + 196 (<compiler-generated>:974) 9 Foundation 0x000000018470f31c URLRequest.init(url:cachePolicy:timeoutInterval:) + 92 (URLRequest.swift:44)# Live For Studio Any idea if this crash is caused by our code or if it is a known problem in iOS 26? I have attached one of the crash reports from Xcode: 2025-10-08_10-13-45.1128_+0200-8acf1536892bf0576f963e1534419cd29e6e10b8.crash
14
0
639
Jan ’26
NEURLFilterManager Error 2 in macOS - How to Validate Configuration Parameters for setConfiguration or saveToPreferences
I'm currently testing URLFilter for use in a macOS product. After calling loadFromPreferences, I set the following configuration parameters: pirServerURL = URL(string: "http://localhost:8080")! pirAuthenticationToken = "AAAA" controlProviderBundleIdentifier = "{extension app bundle identifier}" However, when I call saveToPreferences, I get an Invalid Configuration error. Is there a way to determine which parameter is invalid or incorrectly set? Also, I would appreciate any macOS-specific examples of using NEURLFilterManager, as most of the documentation I’ve found seems to focus on iOS. Thank you.
1
0
86
Nov ’25
joinAccessoryHotspot does not fail if wrong passphrase is provided
I am trying to connect to an accessory's WiFi network using the below code and I always see the message "connection succeded" even if I provide an incorrect passphrase. I tried with different accessories and see the same behavior. hotspotConfigurationManager.joinAccessoryHotspot(accessory, passphrase: passphrase) { error in if let error = error { print("connection failed: \(error.localizedDescription)") } else { print("connection succeeded") } }
2
1
130
Apr ’25
Replacing Packet Filter (pf) with Content Filter for VPN Firewall Use Case
Hi, We're in the process of following Apple’s guidance on transitioning away from Packet Filter (pf) and migrating to a Network Extension-based solution that functions as a firewall. During this transition, we've encountered several limitations with the current Content Filter API and wanted to share our findings. Our VPN client relies on firewall functionality to enforce strict adherence to split tunneling rules defined via the routing table. This ensures that no traffic leaks outside the VPN tunnel, which is critical for our users for a variety of reasons. To enforce this, our product currently uses interface-scoped rules to block all non-VPN traffic outside the tunnel. Replicating this behavior with the Content Filter API (NEFilterDataProvider) appears to be infeasible today. The key limitation we've encountered is that the current Content Filter API does not expose information about the network interface associated with a flow. As a workaround, we considered using the flow’s local endpoint IP to infer the interface, but this data is not available until after returning a verdict to peek into the flow’s data—at which point the connection has already been established. This can result in connection metadata leaking outside the tunnel, which may contain sensitive information depending on the connection. What is the recommended approach for this use case? NEFilterPacketProvider? This may work, but it has a negative impact on network performance. Using a Packet Tunnel Provider and purely relying on enforceRoutes? Would this indeed ensure that no traffic can leak by targeting a specific interface or by using a second VPN extension? And more broadly—especially if no such approach is currently feasible with the existing APIs—we're interpreting TN3165 as a signal that pf should be considered deprecated and may not be available in the next major macOS release. Is that a reasonable interpretation?
5
0
245
May ’25
Can an e-commerce iOS app running in the Xcode Simulator disrupt NETransparentProxyProvider and NEFilterDataProvider, causing DNS failures on macOS
Description: We are investigating an issue where running a specific e-commerce iOS app inside the Xcode Simulator intermittently disrupts the Mac’s network connectivity. When the app is launched in the Simulator, our NETransparentProxyProvider and NEFilterDataProvider extensions occasionally stop receiving traffic correctly, and shortly afterward the entire macOS DNS resolution fails. Once this happens, all apps on the Mac lose internet access until mac is restarted. Disabling extensions also fixing the issue. This issue only appears when the app runs in the Xcode Simulator. I would like to confirm: Is it possible for traffic patterns or network behavior inside the Simulator to interfere with system-level Network Extension providers on macOS? Are there known limitations or conflicts between the Simulator’s virtual networking interfaces and Network Extensions? Any recommended debugging steps or best practices to isolate this behavior? Any guidance, known issues, or suggestions would be appreciated.
3
0
332
Dec ’25
Wi-Fi Raw Socket Disconnection Issue on iPhone 17 Series
On my iPhone 16 Pro and iPhone 16 Pro Max devices, running iOS 26.0, 26.0.1, and 26.1, Wi-Fi raw socket communication works flawlessly. Even after keeping the connection active for over 40 minutes, there are no disconnections during data transmission. However, on the iPhone 17 and iPhone 17 Pro, the raw socket connection drops within 20 seconds. Once it disconnects, the socket cannot reconnect unless the Wi-Fi module itself is reset. I believe this issue is caused by a bug in the iPhone 17 series’ communication module. I have looked into many cases, and it appears to be related to a bug in the N1 chipset. Are there any possible solutions or workarounds for this issue?
6
1
317
Dec ’25
URL filter app with multiple configurations
Hello, We've been working on an app that uses the new NEUrlFilter API and we've got a question. Currently, the system is designed with the assumption that a single app == usecase == single remote database. But what if we would like to give the user the ability to use different blocklists? For example, the user may want to: Block scam domains Block tracking domains Block adult domains Or any composition of these 3 What should we do to give the user this option? It seems that we could differentiate different databases by using different PIR service hostnames, but that would also mean that we'll have to send several requests for the same usecase but with different PIR service hostnames (and they'll all share the same app bundle ID). Will these requests be accepted then? If not, is there an alternative? PS: By sending a request I mean submitting this form
1
1
149
Oct ’25
DeviceDiscoveryUI and Bonjour for iOS
I have some confusion around the usage of DeviceDiscoveryUI. The documentation suggests that it is available only on TVOS. But with the recent announcement of WifiAware, it has been used in iOS devices as well. Within DeviceDiscoveryUI, the DevicePicker or the DevicePairingView documentation seems to be available with iOS. Is this just a documentation mistake? Followup - Can I use DeviceDiscoveryUI's DevicePicker/ DevicePairingView to discover devices through Bonjour and then establish a connection through Network framework?
2
1
164
Oct ’25
Network Framework peer to peer limitations
Hi all, We've been exploring the capabilities of the Network.framework for peer-to-peer communication and have run into some behavior that we haven't been able to fully explain with the existing documentation. In our tests, we’re working with 12 iOS devices, all disconnected from Wi-Fi to force communication over Apple Wireless Direct Link (AWDL). While using the Network.framework to create peer-to-peer connections, we observed that the number of connected peers never exceeded 8, despite all 12 devices being active and configured identically. Some questions we’re hoping to get clarification or discussion on: Is there a known upper limit to the number of peer-to-peer connections supported via AWDL? Are there conditions under which the framework or system limits or throttles visible peers? Does AWDL behavior vary by hardware model, iOS version, or backgrounding state of the app? Is there any official documentation or guidance around peer discovery or connection limits when using NWBrowser and NWConnection in a peer-to-peer context? We’d appreciate any insights from the Apple engineering team or other developers who have worked with larger peer groups using Network.framework in peer-to-peer mode.
4
8
229
May ’25
Completion handler blocks are not supported in background sessions
When I try to implement the new Background Task options in the same way as they show in the WWDC video (on watchOS) likes this: let config = URLSessionConfiguration.background(withIdentifier: "SESSION_ID") config.sessionSendsLaunchEvents = true let session = URLSession(configuration: config) let response = await withTaskCancellationHandler {       try? await session.data(for: request) } onCancel: {       let task = session.downloadTask(with: request))       task.resume() } I'm receiving the following error: Terminating app due to uncaught exception 'NSGenericException', reason: 'Completion handler blocks are not supported in background sessions. Use a delegate instead.' Did I forget something?
7
2
2.7k
Apr ’25