Hi,
I've created a packet tunnel but my packetFlow object isn't get called with any packets. Do I need to do something else to configure the packetFlow? Maybe I have to link it to a NWUDPSession?
Thanks,
Dave
class PacketTunnelProvider: NEPacketTunnelProvider {
override func startTunnel(options: [String : NSObject]?, completionHandler: @escaping (Error?) -> Void) {
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: tunnelRemoteAddress)
settings.ipv4Settings = NEIPv4Settings(addresses: [tunnelRemoteAddress], subnetMasks: ["255.255.255.255"])
settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]
setTunnelNetworkSettings(settings) { error in
completionHandler(error)
self.readPacketObjects()
}
}
private func readPacketObjects() {
self.packetFlow.readPacketObjects() { packets in
// It never gets here.
self.logMessage("Got '\(packets.count)' packet(s)")
self.packetFlow.writePacketObjects(packets)
self.readPacketObjects()
}
}
}
Networking
RSS for tagExplore the networking protocols and technologies used by the device to connect to Wi-Fi networks, Bluetooth devices, and cellular data services.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Hi everyone,
I'm currently working on a project where I need to send multicast packets across all available network interfaces using Apple Network Framework's NWConnectionGroup. Specifically, the MacBook (device I am using for sending multicast requests, MacOS: 15.1) is connected to two networks: Wi-Fi (Network 1) and Ethernet (Network 2), and I need to send multicast requests over both interfaces.
I tried using the .requiredInterface property as suggested by Eskimo in this post, but I’m running into issues.
It seems like I can't create an NWInterface object because it doesn't have any initializers.
Here is the code which I wrote:
var multicast_group_descriptor : NWMulticastGroup
var multicast_endpoint : NWEndpoint
multicast_endpoint = NWEndpoint.hostPort(host: NWEndpoint.Host("234.0.0.1"), port: NWEndpoint.Port(rawValue: 49154)!)
var connection_group : NWConnectionGroup
var multicast_params : NWParameters
multicast_params = NWParameters.udp
var interface = NWInterface(NWInterface.InterfaceType.wiredEthernet)
I get following error:
'NWInterface' cannot be constructed because it has no accessible initializers
I also experimented with the .requiredInterfaceType property. Even when I set it to .wiredEthernet and then change it to .wifi, I am still unable to send requests over the Wi-Fi network.
Here is the code I wrote:
var multicast_params : NWParameters
multicast_params = NWParameters.udp
multicast_params.allowLocalEndpointReuse = true
multicast_params.requiredInterfaceType = .wiredEthernet
var ip = multicast_params.defaultProtocolStack.internetProtocol! as! NWProtocolIP.Options
ip.disableMulticastLoopback = true
connection_group = NWConnectionGroup(with: multicast_group_descriptor, using: multicast_params)
connection_group.stateUpdateHandler = { state in
print(state)
if state == .ready {
connection_group.send(content: "Hello from machine on 15".data(using: .utf8)) { error in
print("Send to mg1 completed on wired Ethernet with error \(error?.errorCode)")
var params = connection_group.parameters
params.requiredInterfaceType = .wifi
connection_group.send(content: "Hello from machine on 15 P2 on Wi-Fi".data(using: .utf8)) { error in
print("Send to mg1 completed on Wi-Fi with error \(error?.errorCode)")
}
}
}
}
Is this expected behavior when using NWConnectionGroup? Or is there a different approach I should take to ensure multicast requests are sent over both interfaces simultaneously?
Any insights or suggestions would be greatly appreciated!
Thanks in advance,
Harshal
For important background information, read Extra-ordinary Networking before reading this.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Broadcasts and Multicasts, Hints and Tips
I regularly see folks struggle with broadcasts and multicasts on Apple platforms. This post is my attempt to clear up some of the confusion.
This post covers both IPv4 and IPv6. There is, however, a key difference. In IPv4, broadcasts and multicasts are distinct concepts. In contrast, IPv6 doesn’t support broadcast as such; rather, it treats broadcasts as a special case of multicasts. IPv6 does have an all nodes multicast address, but it’s rarely used.
Before reading this post, I suggest you familiarise yourself with IP addresses in general. A good place to start is The Fount of All Knowledge™.
Service Discovery
A lot of broadcast and multicast questions come from folks implementing their own service discovery protocol. I generally recommend against doing that, for the reasons outlined in the Service Discovery section of Don’t Try to Get the Device’s IP Address.
There are, however, some good reasons to implement a custom service discovery protocol. For example, you might be working with an accessory that only supports this custom protocol [1]. If you must implement your own service discovery protocol, read this post and also read the advice in Don’t Try to Get the Device’s IP Address.
IMPORTANT Sometimes I see folks implementing their own version of mDNS. This is almost always a mistake:
If you’re using third-party tooling that includes its own mDNS implementation, it’s likely that this tooling allows you to disable that implementation and instead rely on the Bonjour support that’s built-in to all Apple platforms.
If you’re doing some weird low-level thing with mDNS or DNS-SD, it’s likely that you can do that with the low-level DNS-SD API.
[1] And whose firmware you can’t change! I talk more about this in Working with a Wi-Fi Accessory.
API Choice
Broadcasts and multicasts typically use UDP [1]. TN3151 Choosing the right networking API describes two recommended UDP APIs:
Network framework
BSD Sockets
Our general advice is to prefer Network framework over BSD Sockets, but UDP broadcasts and multicasts are an exception to that rule. Network framework has very limited UDP broadcast support. And while it’s support for UDP multicasts is less limited, it’s still not sufficient for all UDP applications. In cases where Network framework is not sufficient, BSD Sockets is your only option.
[1] It is possible to broadcast and multicast at the Ethernet level, but I almost never see questions about that.
UDP Broadcasts in Network Framework
Historically I’ve claimed that Network framework was useful for UDP broadcasts is very limited circumstances (for example, in the footnote on this post). I’ve since learnt that this isn’t the case. Or, more accurately, this support is so limited (r. 122924701) as to be useless in practice.
For the moment, if you want to work with UDP broadcasts, your only option is BSD Sockets.
UDP Multicasts in Network Framework
Network framework supports UDP multicast using the NWConnectionGroup class with the NWMulticastGroup group descriptor. This support has limits. The most significant limit is that it doesn’t support broadcasts; it’s for multicasts only.
Note This only relevant to IPv4. Remember that IPv6 doesn’t support broadcasts as a separate concept.
There are other limitations, but I don’t have a good feel for them. I’ll update this post as I encounter issues.
Local Network Privacy
Some Apple platforms support local network privacy. This impacts broadcasts and multicasts in two ways:
Broadcasts and multicasts require local network access, something that’s typically granted by the user.
Broadcasts and multicasts are limited by a managed entitlement (except on macOS).
TN3179 Understanding local network privacy has lots of additional info on this topic, including the list of platforms to which it applies.
Send, Receive, and Interfaces
When you broadcast or multicast, there’s a fundamental asymmetry between send and receive:
You can reasonable receive datagrams on all broadcast-capable interfaces.
But when you send a datagram, it has to target a specific interface.
The sending behaviour is the source of many weird problems. Consider the IPv4 case. If you send a directed broadcast, you can reasonably assume it’ll be routed to the correct interface based on the network prefix. But folks commonly send an all-hosts broadcast (255.255.255.255), and it’s not obvious what happens in that case.
Note If you’re unfamiliar with the terms directed broadcast and all-hosts broadcast, see IP address.
The exact rules for this are complex, vary by platform, and can change over time. For that reason, it’s best to write your broadcast code to be interface specific. That is:
Identify the interfaces on which you want to work.
Create a socket per interface.
Bind that socket to that interface.
Note Use the IP_BOUND_IF (IPv4) or IPV6_BOUND_IF (IPv6) socket options rather than binding to the interface address, because the interface address can change over time.
Extra-ordinary Networking has links to other posts which discuss these concepts and the specific APIs in more detail.
Miscellaneous Gotchas
A common cause of mysterious broadcast and multicast problems is folks who hard code BSD interface names, like en0. Doing that might work for the vast majority of users but then fail in some obscure scenarios.
BSD interface names are not considered API and you must not hard code them. Extra-ordinary Networking has links to posts that describe how to enumerate the interface list and identify interfaces of a specific type.
Don’t assume that there’ll be only one interface of a given type. This might seem obviously true, but it’s not. For example, our platforms support peer-to-peer Wi-Fi, so each device has multiple Wi-Fi interfaces.
When sending a broadcast, don’t forget to enable the SO_BROADCAST socket option.
If you’re building a sandboxed app on the Mac, working with UDP requires both the com.apple.security.network.client and com.apple.security.network.server entitlements.
Some folks reach for broadcasts or multicasts because they’re sending the same content to multiple devices and they believe that it’ll be faster than unicasts. That’s not true in many cases, especially on Wi-Fi. For more on this, see the Broadcasts section of Wi-Fi Fundamentals.
Snippets
To send a UDP broadcast:
func broadcast(message: Data, to interfaceName: String) throws {
let fd = try FileDescriptor.socket(AF_INET, SOCK_DGRAM, 0)
defer { try! fd.close() }
try fd.setSocketOption(SOL_SOCKET, SO_BROADCAST, 1 as CInt)
let interfaceIndex = if_nametoindex(interfaceName)
guard interfaceIndex > 0 else { throw … }
try fd.setSocketOption(IPPROTO_IP, IP_BOUND_IF, interfaceIndex)
try fd.send(data: message, to: ("255.255.255.255", 2222))
}
Note These snippet uses the helpers from Calling BSD Sockets from Swift.
To receive UDP broadcasts:
func receiveBroadcasts(from interfaceName: String) throws {
let fd = try FileDescriptor.socket(AF_INET, SOCK_DGRAM, 0)
defer { try! fd.close() }
let interfaceIndex = if_nametoindex(interfaceName)
guard interfaceIndex > 0 else { fatalError() }
try fd.setSocketOption(IPPROTO_IP, IP_BOUND_IF, interfaceIndex)
try fd.setSocketOption(SOL_SOCKET, SO_REUSEADDR, 1 as CInt)
try fd.setSocketOption(SOL_SOCKET, SO_REUSEPORT, 1 as CInt)
try fd.bind("0.0.0.0", 2222)
while true {
let (data, (sender, port)) = try fd.receiveFrom()
…
}
}
IMPORTANT This code runs synchronously, which is less than ideal. In a real app you’d run the receive asynchronously, for example, using a Dispatch read source. For an example of how to do that, see this post.
If you need similar snippets for multicast, lemme know. I’ve got them lurking on my hard disk somewhere (-:
Other Resources
Apple’s official documentation for BSD Sockets is in the man pages. See Reading UNIX Manual Pages. Of particular interest are:
setsockopt man page
ip man page
ip6 man page
If you’re not familiar with BSD Sockets, I strongly recommend that you consult third-party documentation for it. BSD Sockets is one of those APIs that looks simple but, in reality, is ridiculously complicated. That’s especially true if you’re trying to write code that works on BSD-based platforms, like all of Apple’s platforms, and non-BSD-based platforms, like Linux.
I specifically recommend UNIX Network Programming, by Stevens et al, but there are lots of good alternatives.
https://unpbook.com
Revision History
2025-09-01 Fixed a broken link.
2025-01-16 First posted.
Hi,
I've encountered a strange behavior in the DNS Proxy Provider extension. Our app implements both DNS Proxy Provider and Content Filter Providers extensions, configured via MDM.
When the app is uninstalled, the behavior of the providers differs:
For Content Filter Providers (both Filter Control and Filter Data Providers), the providers stop as expected with the stop reason:
/** @const NEProviderStopReasonProviderDisabled The provider was disabled. */
case providerDisabled = 5
However, for the DNS Proxy Provider, the provider remains in the "Running" state, even though there is no app available to match the provider's bundle ID in the uploaded configuration profile.
When the app is reinstalled:
The Content Filter Providers start as expected.
The DNS Proxy Provider stops with the stop reason:
/** @const NEProviderStopReasonAppUpdate The NEProvider is being updated */
@available(iOS 13.0, *)
case appUpdate = 16
At this point, the DNS Proxy Provider remains in an 'Invalid' state. Reinstalling the app a second time seems to resolve the issue, with both the DNS Proxy Provider and Content Filter Providers starting as expected.
This issue seems to occur only if some time has passed after the DNS Proxy Provider entered the 'Running' state. It appears as though the system retains a stale configuration for the DNS Proxy Provider, even after the app has been removed.
Steps to reproduce:
Install the app and configure both DNS Proxy Provider and Content Filter Providers using MDM.
Uninstall the app.
Content Filter Providers are stopped as expected (NEProviderStopReason.providerDisabled = 5).
DNS Proxy Provider remains in the 'Running' state.
Reinstall the app.
Content Filter Providers start as expected.
DNS Proxy Provider stops with NEProviderStopReason.appUpdate (16) and remains 'Invalid'.
Reinstall the app again.
DNS Proxy Provider now starts as expected.
This behavior raises concerns about how the system manages the lifecycle of DNS Proxy Provider, because DNS Proxy Provider is matched with provider bundle id in .mobileconfig file.
Has anyone else experienced this issue? Any suggestions on how to address or debug this behavior would be highly appreciated.
Thank you!
I’m working with the NEHotspotHelper API in my iOS app, and I noticed the following log message in Console:
"(BUNDLE ID ) is using NEHotspotHelper API and it's unresponsive to API's evaluate command. The API gives 45 seconds to 3rd party apps to respond, and then it launches WebSheet to allow user to interact with the portal."
I have two different apps that both register a NEHotspotHelper handler:
App A checks for .evaluate and calls createResponse(.unsupportedNetwork) if we don’t manage that particular network.
App B registers for hotspot events but does not handle .evaluate at all.
In App A, whenever I see that “unresponsive” or “45 seconds” log, the system eventually launches the standard captive portal WebSheet. In App B, I never see those logs.
I have a few questions:
Are these “unresponsive” logs indeed triggered by the .evaluate command specifically?
In other words, do we only see that 45-second timeout and the subsequent WebSheet message if our app is registered to handle Evaluate but doesn’t respond quickly (or responds with .unsupportedNetwork)?
Is it best practice (or required) to always respond to .evaluate—for example, sending .unsupportedNetwork if we don’t plan on managing the user’s login or captive portal? Does ignoring .evaluate lead to other unexpected behavior or logs?
Should we still explicitly respond to Evaluate with .unsupportedNetwork? Or is it okay to skip Evaluate handling entirely on every app or invocation?
I’d love to confirm whether .evaluate handling is the direct cause of these logs, and how best to avoid the “unresponsive”/“45 seconds” fallback if our app isn’t intended to manage the portal.
Thanks in advance for any insights!
Topic:
App & System Services
SubTopic:
Networking
We recently notified from Apple that our Hotspot helper is delaying device to switch Wifi Networks. To handle this issue better, we need to refactor our code a bit handle the scenario gracefully and while reading this documentation https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/Hotspot_Network_Subsystem_Guide/Contents/AuthStateMachine.html#//apple_ref/doc/uid/TP40016639-CH2-SW1
Some questions came up while responding back to evaluate and filterscanlist command. Here are our questions
What is the lifecycle of exclude_list? Does it get cleared every time Authentication State Machine goes into Inactive State?
What happens if we send commandNotRecognized/unsupportedNetwork/temporaryFailure after evaluate command? Does our app get an evaluate command next time when device joins the same network?
What is the actual time for the app to respond to network change evaluate command? Is 45 seconds the timeout limit for app to evaluate and respond?
After responding to the evaluate command, how quickly is it terminated from running in the background?
Topic:
App & System Services
SubTopic:
Networking
I've implemented a custom system extension VPN for macOS using Packet Tunnel Provider.
The VPN is configured with on-demand, and a rule to always connect whenever there's traffic:
onDemandRules = [NEOnDemandRuleConnect()]
As for the tunnel's settings (at the Packet Tunnel Provider), I've configured a split tunnel, so some routes are excluded from the tunnel.
Now I have the following scenario:
The VPN is connected
The Mac enters sleep
The sleep() function is called (at my Packet Tunnel Provider)
The Mac briefly awakes to check emails/push notifications/etc. This traffic is excluded from the tunnel.
What is the expected behavior here? Should the wake function be called because of the on-demand rule? Or should the VPN remain asleep because this traffic is excluded from the tunnel?
Context: We are using NWConnection for UDP and TCP Connections, and wanted to know the best way to keep the number of pending send completions in control to limit resource usage
Questions:
Is there a way to control the send rate, such that too many 'send pending completion' does not get queued. Say if I do a ‘extremely dense flurry of 10 million NWConnection.send’ will all go asynchronous without any complications? Or I would be informed once it reaches some threshold.
Or no? And is it the responsibility of the application using NWConnection.send to limit the outstanding completion , as if they were beyond a certain limit, it would have an impact on outstanding and subsequent requests?
If so – how would one know ‘what is supposed to be the limit’ at runtime? Is this a process level or system level limit.
Will errors like EAGAIN and ETIMEOUT ever will be reported. In the test I simulated, where the TCP Server was made to not do receive, causing the 'socket send buffer' to become full on the sender side. On the sender side my send stopped getting complete, and became pending. Millions of sends were pending for long duration, hence wanted to know if we will ever get EAGAIN or ETIMEOUT.
Hello, we have noticed a crash in BigSur 11.7.10, 20G1427 libdispatch:
Crashed Thread: 1 Dispatch queue: com.apple.network.connections
Exception Type: EXC_BAD_INSTRUCTION (SIGILL)
Exception Codes: 0x0000000000000001, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Termination Signal: Illegal instruction: 4
Termination Reason: Namespace SIGNAL, Code 0x4
Terminating Process: exc handler [94088]
Application Specific Information:
BUG IN CLIENT OF LIBDISPATCH: Release of a suspended object
Thread 0:
0 libsystem_kernel.dylib 0x00007fff20488aea __sigsuspend_nocancel + 10
1 libdispatch.dylib 0x00007fff2031f4e1 _dispatch_sigsuspend + 36
2 libdispatch.dylib 0x00007fff2031f4bd _dispatch_sig_thread + 53
Thread 1 Crashed:: Dispatch queue: com.apple.network.connections
0 libdispatch.dylib 0x00007fff2033cc35 _dispatch_queue_xref_dispose.cold.1 + 24
1 libdispatch.dylib 0x00007fff20313808 _dispatch_queue_xref_dispose + 50
2 libdispatch.dylib 0x00007fff2030e2eb -[OS_dispatch_source _xref_dispose] + 17
3 libnetwork.dylib 0x00007fff24255999 __nw_queue_context_create_source_block_invoke + 41
4 libdispatch.dylib 0x00007fff2030d623 _dispatch_call_block_and_release + 12
5 libdispatch.dylib 0x00007fff2030e806 _dispatch_client_callout + 8
6 libdispatch.dylib 0x00007fff203111b0 _dispatch_continuation_pop + 423
7 libdispatch.dylib 0x00007fff203211f4 _dispatch_source_invoke + 1181
8 libdispatch.dylib 0x00007fff20316318 _dispatch_workloop_invoke + 1784
9 libdispatch.dylib 0x00007fff2031ec0d _dispatch_workloop_worker_thread + 811
10 libsystem_pthread.dylib 0x00007fff204b545d _pthread_wqthread + 314
11 libsystem_pthread.dylib 0x00007fff204b442f start_wqthread + 15
I have seen similar crashes in the forum, but none from com.apple.network.connections queue.
Should we raise a ticket or is this something that was fixed in newer OS versions?
Thanks!
Jakub
I added a Content Filter to my app, and when running it in Xcode (Debug/Release), I get the expected permission prompt:
"Would like to filter network content (Allow / Don't Allow)".
However, when I install the app via TestFlight, this prompt doesn’t appear at all, and the feature doesn’t work.
Is there a special configuration required for TestFlight? Has anyone encountered this issue before?
Thanks!
I have an issue that causes multiple instances of the push provider to be initialized. And I'd like to ask you what could trigger the instantiation NEAppPushProvider subclass. It seems like it's being triggered excessively. If there's documentation that I have overlooked then just show it to me and I'll be on my way.
Here's the details. But really all I want to know is why is my subclass for NEAppPushProvider keeps getting initialized. If you can answer me that than maybe all these details don't really matter but here they are.
Here's why I believe there's multiple push provider. I see logs for my push provider initializing but I don't see it de-initializing. I also see redundant logs showing multiple instances trying to log into my server. Each time it initializes, an additional log is added for trying to log into my server.
In the app, the system saves it's configuration shortly after initialization, after saving and loading the push configuration, the app doesn't touch config.
Meanwhile in the extension, after 8 or so hours, the extension starts creating a new instance of the push provider. Then a few hours later it does it again. And again. Until the watch dog kills us for wasting too much CPU.
Normally on a fresh install, I'll observe turning off the wifi to call stop on the push provider and later have the push provider de-initialize.
The extension maintains a socket connection to the server, the server can send it messages to display push notifications. The software runs on hospital networks, which will not have access to the internet. It seems like the connection to the server is stable from the logs. I don't detect any disconnections. I'll check with the server to confirm.
In the app I call removeFromPreferences to clear out any extensions before logging in/saving push configurations. And I call saveToPreferences on the NEAppPushManager. I do this to make sure I don't have more than one push configuration saved at one time. I also have many logs looking out for this. I used the sample code from apple as the basis of the my own Push Manager. I can post code if you deem it necessary.
Hope to here from you soon. Thank you.
The Download is not Working in the background mode even if i entitled all the necessary permission for the application it only works when the app is connected to xcode due to xcode keep the session alive but if try after removing the connection from the xcode the app not able to keep the download after 45 sec what may be the reason
my code
var request = URLRequest(url: url)
request.httpMethod = "GET"
let bearerToken = SyncManager.accessToken
request.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
let uniqueIdentifier = "\(self.vdmsId)_\(UUID().uuidString)"
backgroundTaskID = UIApplication.shared.beginBackgroundTask { [weak self] in
if let taskID = self?.backgroundTaskID {
UIApplication.shared.endBackgroundTask(taskID)
self?.backgroundTaskID = .invalid
}
}
let CursessionConfig = URLSessionConfiguration.background(withIdentifier: uniqueIdentifier)
CursessionConfig.isDiscretionary = false
CursessionConfig.sessionSendsLaunchEvents = true
CursessionConfig.shouldUseExtendedBackgroundIdleMode = true
// Set timeout intervals
CursessionConfig.timeoutIntervalForResource = 24 * 60 * 60 // 24 hours
CursessionConfig.timeoutIntervalForRequest = 60 * 60 // 1 hour
let Cursession = URLSession(configuration: CursessionConfig, delegate: self, delegateQueue: nil)
self.CurInstanceSession = Cursession
self.session = Cursession
if SyncManager.activeSessions == nil {
SyncManager.activeSessions = [URLSession]()
}
SyncManager.activeSessions?.append(Cursession)
self.downloadCompletionHandler = completion
let CurdownloadTask = Cursession.downloadTask(with: request)
CurdownloadTask.resume()
is there any solutions and i have entitled all the neccessary permisssions like background fetch, process and i also tries with the UIApplication.shared.beginBackgroundTask but after 45 sec it gets terminated all of the suden what may be the issue
Topic:
App & System Services
SubTopic:
Networking
Hi,
We are working on an app that communicates over a UDP connection on the local network. In our testing, we have a Python UDP client running on the same network, which responds when we send a message to a broadcast IP (255.255.255.255). This setup works as expected on an iOS 15 device.
However, when we test the same scenario on an iOS 18 device, the UDP communication doesn't seem to reach the Python UDP client. We've verified that the UDP client and the iOS device are on the same network, and the Python client is responding correctly.
Has Apple introduced any restrictions or changes regarding UDP broadcast behavior in iOS 18? Is broadcasting to 255.255.255.255 still supported, or has this functionality been limited in recent iOS versions?
I am trying to connect an iPhone 16 (iOS 18.3) to a Wi-Fi device with the SSID "DIRECT-DR_6930_KP201128", but every time, without being able to enter the Wi-Fi password, the message "Unable to join the network 'DIRECT-DR_6930_KP201128'" is displayed. Below are the system logs from the connection failure. Could you please tell me the cause of the connection failure?
By the way, an iPhone SE 2nd (iOS 18.2.1) can connect to the same Wi-Fi device without any issues.
System Logs:
・Jan 31 19:18:14 900-iPhone-16-docomo Preferences(WiFiKit)[351] : {ASSOC-} association finished for DIRECT-DR_6930_KP201128 - success 0
・Jan 31 19:18:14 900-iPhone-16-docomo runningboardd(RunningBoard)[33] : Assertion 33-351-4412 (target:[app<com.apple.Preferences(DE1AB487-615D-473C-A8D6-EAEF07337B18)>:351]) will be created as inactive as start-time-defining assertions exist
・Jan 31 19:18:14 900-iPhone-16-docomo Preferences(WiFiKit)[351] : association failure: (error Error Domain=com.apple.wifikit.error Code=12 "Unknown Error" UserInfo={NSDebugDescription=Unknown Error, NSUnderlyingError=0x303307660 {Error Domain=com.apple.corewifi.error.wifid Code=-3938 "(null)"}})
・Jan 31 19:18:14 900-iPhone-16-docomo Preferences(WiFiKit)[351] : dismissing credentials view controller for DIRECT-DR_6930_KP201128
My code makes an iPhone use the CBCentralManager to talk to devices peripherals over core bluetooth.
After attempting a connect to a peripheral device, I get a didConnect callback on CBCentralManagerDelegate.
After this I initiate discovery of services using:
peripheral.discoverServices([CBUUID(nsuuid: serviceUUID)])
Since I am only interested in discovering my service of interest and not the others to speed up time to the actual sending of data.
This also gives me the didDiscoverServices callback without error prints in which I do the following:
guard let services = peripheral.services, !services.isEmpty else {
print("Empty services")
centralManager.cancelPeripheralConnection(peripheral)
return
}
And for next steps
if let serviceOfInterest = services.first(where: {$0.uuid == CBUUID(nsuuid: serviceUUID)}) { //double check for service we want
initiateDiscoverCharacteristics(peripheral: peripheral, service: serviceOfInterest)
}
Below is what initiateDiscoverCharacteristics() does. I basically only tries to discover certain characteristics of the selected service:
peripheral.discoverCharacteristics(
[CBUUID(nsuuid: readUUID),
CBUUID(nsuuid: writeUUID)],
for: serviceOfInterest)
For this also we get the didDiscoverCharacteristicsFor callback without error prints.
Here in this callback however we were not doing the serviceOfInterest check to see that we are getting the callback for the service we expect, since our understanding was that we will get didDiscoverCharacteristicsFor callback for the characteristics on the serviceOfInterest because that is what peripheral.discoverCharacteristics() was initiated for.
When we go ahead to write some data/subscribe for notify/read data we have 2 guard statements for services and characteristics of a particular service.
The first guard below passes:
if(peripheral.services == nil) {
print("services yet to be discovered \(peripheral.identifier.uuidString)")
return
}
However the second guard below fails:
let serviceOfInterest = peripheral.services?.first(where: {$0.uuid == CBUUID(nsuuid: serviceUUID})
if((serviceOfInterest?.characteristics == nil) || (serviceOfInterest?.characteristics == [])) {
print("characteristics yet to be discovered \(peripheral.identifier.uuidString)")
return
}
First of all, does the iPhone go ahead and discover other characteristics and services separately even when we explicitly mention the service and the characteristics it should discover?
Now if you say yes and that it maybe the reason of our bug because we didn't do a check for serviceOfInterest in didDiscoverCharacteristicsFor callback, then I have another question.
Why don't we get a second/third print in didDiscoverCharacteristicsFor callback signifying that more characteristics were discovered?
The peripheral device just disconnects after a set timeout (peripheral device used in our testing does this if we are not communicating with it for a certain amount of time).
This issue is extremely rare. We have seen it only twice in our customer base. Both the instances were on the same iPhone 15 Pro. Once a few months back and once recently. Currently, this iPhone is having iOS version 18.1.1 running on it.
Hi,
I am working on a use case where I want to read the wifi signal strength data in the terms of RSSI (Received Signal Strength Indicator) values (or) any other way of representation. when my iPhone is connected to the wifi and Move around the house.
Is this use case possible ? If yes, what are all the entitlements that I have to obtain?
I have some concerns related to shortening the lifetime of certificates, as per
https://support.apple.com/en-gb/102028
Does this apply to Private CA root certificates?
And if yes:
does it apply if I use ATS and higher level API like URLSession
does it apply it I carry my root CA cert in my app payload and use low level libraries without ATS support?
I recently encountered an issue with incorrect progress reporting and timeout behavior when using NSURLSession to upload small data buffers.
Background
In my app, I split a large video file into smaller 1MB chunk files for upload. This approach facilitates error retries and concurrent uploads. Additionally, I monitor the upload speed for each request, and if the speed is too slow, I switch CDNs to re-upload the chunk.
Issue Description
When using NSURLSessionUploadTask or NSURLSessionDataTask to upload a 1MB HTTP body, I noticed that the progress callbacks are not accurate. I rely on the following callback to track progress:
- (void)URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:
Even when using Network Link Conditioner to restrict bandwidth to a very low level, this callback reports identical values for totalBytesSent and totalBytesExpectedToSend right at the start of the request, indicating 100% upload progress. However, through network traffic inspection, I observed that the upload continues slowly and is far from complete.
Additionally, I noticed that even though the upload is still ongoing, the request times out after the duration specified in - NSURLSessionConfiguration.timeoutIntervalForRequest. According to the documentation:
"The request timeout interval controls how long (in seconds) a task should wait for additional data to arrive before giving up. The timer associated with this value is reset whenever new data arrives."
This behavior suggests that the timeout timer is not reset as the document says during slow uploads, likely because didSendBodyData is not updating as expected.
Consequently, the timer expires prematurely, causing 1MB chunks to frequently timeout under slow network conditions. This also prevents me from accurately calculating the real-time upload speed, making it impossible to implement my CDN switching strategy.
Some Investigation
I have found discussions on this forum regarding similar issues. Apple engineers mentioned that upload progress is reported based on the size of data written to the local buffer rather than the actual amount of data transmitted over the network. This can indeed explain the behaviour mentioned above:
https://developer.apple.com/forums/thread/63548
https://developer.apple.com/forums/thread/746523
Interestingly, I also noticed that progress reporting works correctly when uploading to some certain servers, which I suspect is related to the TCP receive window size configured on those servers. For example:
Accurate progress: https://www.w3schools.com
Inaccurate progress: Most servers, like https://developer.apple.com
I created a sample project to demostrate the progress & timeout issues and different behaviours when uploading to some servers:
https://github.com/Naituw/NSURLSessionUploadProgressTest
Questions
Is there any way to resolve or workaround this issue?
Like adjusting the size of the local send buffer?
or configuring NSURLSession to report progress based on acknowledged TCP packets instead of buffer writes?
Or are there any alternative solutions for implementing more accurate timeout mechanisms and monitoring real-time upload speed?
Topic:
App & System Services
SubTopic:
Networking
I am looking for a lightweight server that can run inside an app.
The key requirement is that it must support local IP communication over HTTPS.
I have searched Google and found several frameworks, but as far as I know, support for HTTPS in this environment has been discontinued or is no longer available.
If anyone knows a solution that meets these criteria, I would greatly appreciate your guidance.
Thank you in advance!😀
Topic:
App & System Services
SubTopic:
Networking
Hi, I am working on a case in our organisation where hundreds if not a thousand wireless network clients are affected by regular, usually 30 sometimes 60 minute sometime they are unnoticeable but often people having meetings notice that a lot.
We excluded wireless network configuration issue since disconnections happens to clients both connected to Cisco and Ubiquiti Access Points.
WLC logs mostly show EAP timeout errors - clients are getting disauthenticated and authenticated back - usually without any action needed - but the meeting is being interrupted.
What I found in Macbook logs with sudo log show [options] is the main reason of network disconnection:
2025-02-04 14:16:31.219192+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[DPSQuickRecoveryRecommendationEngine updateTimeSincePreviousTriggerForStudy:msgKey:dictKey:]::913:msgkey:WFAAWDWASDS_symptomsDnsTimeSincePreviousTriggerMinutes dictKey:dps_lastSymptomsDpsTrigger previous_TS:(null) current_TS:Tue Feb 4 14:16:31 2025 difference:0
2025-02-04 14:16:31.219704+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[DPSQuickRecoveryRecommendationEngine updateScreenState]::198:DPS Fast Reset Recommendation Engine: (screenON & foreGrnd traffic) is DETECTED
2025-02-04 14:16:31.219713+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[DPSQuickRecoveryRecommendationEngine recommendSymptomsDpsRecovery:symptomsDnsStats:awdlState:currentSymptomsCondition:isLANPingSuccessful:appUsage:averageCCA:]::966:PeerDiagnostics: Data not received from peerDiagnostics
2025-02-04 14:16:31.219714+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[DPSQuickRecoveryRecommendationEngine checkForPriorityNetwork]::256:Priority Network Check Disabled: NO IsPriorityNetwork: YES
2025-02-04 14:16:31.219732+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[DPSQuickRecoveryRecommendationEngine isResetAllowedForKey:forPrefSelector:]::330:key:symptomsDps_lastScreenOnRecoveryWD previousWD_TS:(null) currentWD_TS:Tue Feb 4 14:16:31 2025 recommendation:YES
2025-02-04 14:16:31.219735+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[DPSQuickRecoveryRecommendationEngine updateSymptomsDPSRecoveryWDStatsForKey:]::210:Added key: symptomsDps_numRecommendedScreenOnRecoveryWD value:1 dict:(null)
2025-02-04 14:16:31.219737+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[DPSQuickRecoveryRecommendationEngine recommendSymptomsDpsRecovery:symptomsDnsStats:awdlState:currentSymptomsCondition:isLANPingSuccessful:appUsage:averageCCA:]::1023:PeerDiagnostics: Recommendation for DNS Symptoms Recovery: Reassoc
Do you guys have any idea where can I see that DNS symptoms?
I can also see some reading like:
2025-02-04 14:16:31.219169+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[WAEngine gatherConsecutiveDatapathReadings:forProcessToken:andReply:]_block_invoke::4235:DNS Symptoms pre-decision check:: Associated:YES Primary:YES isCaptive:NO isValidDnsConfig:YES
2025-02-04 14:16:31.219169+0100 0xc01342 Default 0x0 86459 0 wifianalyticsd: [com.apple.wifi.analytics:Default] -[WAEngine gatherConsecutiveDatapathReadings:forProcessToken:andReply:]_block_invoke::4238:SDNS: WiFi Not Primary - setting suppressedReason kSymptomsDnsWiFiInterfaceNotPrimary
WiFi Not Primary - how if this is my only interface? - I removed all other
Killing and disabling wifianalyticsd does not help - the process is being spawned by launchd on airportd request:
2025-02-04 08:54:11.903825+0100 0xb85274 Default 0x0 627 0 airportd: (WiFiAnalytics) [com.apple.wifi.analytics:Default] -[WAClient _establishDaemonConnection]_block_invoke::1057:XPC: establishing connection to daemon with token ending in: <private>...
2025-02-04 08:54:11.907779+0100 0xb8504a Default 0x0 627 0 airportd: (IO80211) [com.apple.WiFiManager:] Info: <airport[627]> -[dpsManager submitDpsSymptom:isCriticalApp:]_block_invoke:
2025-02-04 08:54:11.907943+0100 0xb8504a Default 0x0 627 0 airportd: (IO80211) -[dpsManager submitDpsSymptom:isCriticalApp:]_block_invoke: Error preparing DPSNotification for submission: Error Domain=com.apple.wifi.analytics.errordomain Code=9014 "WAErrorCodeDaemonContactTimeout" UserInfo={NSLocalizedFailureReason=WAErrorCodeDaemonContactTimeout}, or null WAMessageAWD
2025-02-04 08:54:11.908055+0100 0xb8504a Default 0x0 627 0 airportd: (IO80211) [com.apple.WiFiManager:] <airport[627]> -[dpsManager submitDpsSymptom:isCriticalApp:]_block_invoke: Error preparing DPSNotification for submission: Error Domain=com.apple.wifi.analytics.errordomain Code=9014 "WAErrorCodeDaemonContactTimeout" UserInfo={NSLocalizedFailureReason=WAErrorCodeDaemonContactTimeout}, or null WAMessageAWD
2025-02-04 08:54:11.910453+0100 0xb85274 Default 0x0 627 0 airportd: (libxpc.dylib) [com.apple.xpc:connection] [0x80fe64640] activating connection: mach=true listener=false peer=false name=com.apple.wifianalyticsd
2025-02-04 08:54:11.911105+0100 0xb85382 Default 0x0 1 0 launchd: [system/com.apple.wifianalyticsd:] internal event: WILL_SPAWN, code = 0
2025-02-04 08:54:11.911229+0100 0xb85382 Default 0x0 1 0 launchd: [system/com.apple.wifianalyticsd:] service state: spawn scheduled
2025-02-04 08:54:11.911233+0100 0xb85382 Default 0x0 1 0 launchd: [system/com.apple.wifianalyticsd:] service state: spawning
2025-02-04 08:54:11.911384+0100 0xb85382 Default 0x0 1 0 launchd: [system/com.apple.wifianalyticsd:] launching: ipc (mach)
2025-02-04 08:54:11.920272+0100 0xb85382 Default 0x0 1 0 launchd: [system/com.apple.wifianalyticsd [86459]:] xpcproxy spawned with pid 86459
Do you guys have any idea what is the cause of this behaviour?
Or how to disable wifianalyticsd process for good?
Topic:
App & System Services
SubTopic:
Networking