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

Sequoia 'local network' permission failure from launch agent
I'm trying to invoke a 3rd party command line tool from a launch agent to connect to a server on my LAN. It seems impossible. I have a little shell script that does what I need, and it works fine invoked in Terminal.app. The first time I run it that way I get permission prompts and I agree to them all. Subsequent invocations work. Now I put a launch agent in ~/Library/Launch Agents. It does nothing more than invoke my shell script at some specific time daily. launchd launches it, but it fails to access the LAN, with a 'no route to host' error message. The command line tool I'm trying to use is not a macOS-provided one, but one from MacPorts/HomeBrew (I tried both). It doesn't even matter which tool I'm using, I tried a very simple case of just using nc/netcat. If I use the macOS-provided nc, then I can access my LAN. If I install nc from MacPorts /HomeBrew, that nc cannot access my LAN. This I've reproed on a literally brand new Mac, then updated to newest Sequoia (15.3.2), then done all I've described above. I've ruled out DNS by working with raw IP addresses. I've disabled gatekeeper with sudo spctl --master-disable. I've tried using cron instead of launch agents, same results. I've tried codesigning with codesign -dvvv /opt/homebrew/bin/nc, no help. I've read TN3179 Understanding local network privacy. In summary: Terminal.app -> script -> macOS/brew nc -> internet/LAN = works launchagent -> script -> macOS nc -> internet = works launchagent -> script -> macOS nc -> LAN = works launchagent -> script -> brew nc -> internet = works launchagent -> script -> brew nc -> LAN = fails How can I make that last case work?
17
0
968
3w
libquic.dylib crash during QUIC path migration on iOS 26 (quic_migration_probe_path / nw_protocol_data_access_buffer)
libquic.dylib crashes with a null/invalid buffer access in nw_protocol_data_access_buffer during QUIC connection path migration on iOS 26. App code is not in the stack — this is entirely within Apple system libraries. We are seeing a consistent crash on iOS 26 that does not reproduce on iOS 17 or iOS 18. The crash occurs on a background thread ("com.apple.network.connections") with no application code in the crashed thread's stack. The crash trace begins in quic_migration_probe_path and terminates in nw_protocol_data_access_buffer + 180, suggesting a use-after-free or buffer lifetime violation during QUIC connection path migration (e.g., Wi-Fi ↔ Cellular handoff). This crash does not appear to be reproducible on demand — it correlates with network path transitions while QUIC connections are active. Our app uses standard URLSession with default/ephemeral session configurations and does not explicitly enable HTTP/3; iOS 26 is automatically upgrading eligible connections. Crash thread (abbreviated): 0 libquic.dylib quic_conn_send_packet + 144 1 libquic.dylib quic_conn_continue_sending + 424 2 libquic.dylib __quic_conn_send_frames_for_key_state_block_invoke_2 + 1244 3 Network nw_protocol_data_access_buffer + 180 ← crash 4 Network nw_protocol_data_copy_buffer 5 Network nw_endpoint_flow_output_frames 6 libquic.dylib quic_conn_send_frames_for_key_state 7 libquic.dylib quic_conn_send_frames 8 libquic.dylib quic_migration_probe_path + 1464 9 libquic.dylib quic_migration_path_established + 2608 10 libquic.dylib __quic_migration_path_event_block_invoke.21 11 libquic.dylib quic_migration_path_event 12 Network nw_protocol_implementation_connected There is no app code in the crashed thread. This is a regression introduced in iOS 26, where libquic.dylib was separated into its own dynamic library and new path migration probe logic was introduced.
9
0
1.5k
3w
iCloud Private Relay: network blocking set up exactly as documented (NXDOMAIN for mask.icloud.com / mask-h2.icloud.com), but iOS shows no alert
We run a Wi-Fi network with our own captive portal and want iOS clients to be told that Private Relay is not available here, as described in Prepare your network or web server for iCloud Private Relay and WWDC21 session 10096. Our setup: Resolver: Unbound, handed out via DHCP, with local-zone: "mask.icloud.com" always_nxdomain and local-zone: "mask-h2.icloud.com" always_nxdomain. The network is IPv4-only. The captive portal intercepts all UDP port 53 traffic and drops everything else (e.g. port 853). TCP port 53 is not served. We also tried NXDOMAIN for mask-api.icloud.com, apple-native-relay.apple.com, mask.apple-dns.net, mask-api.fe.apple-dns.net and mask-t.apple-dns.net, with no change. [Result of our resolver log: do queries for the mask hosts arrive from the test iPhone, and what do we answer? Before and after captive-portal login?] What the documentation promises: “users will be alerted that they need to either disable Private Relay for that network, or choose another network.” What happens: On [iPhone model], iOS [exact version/build], with Private Relay enabled in iCloud settings and “Limit IP Address Tracking” [on/off] for this Wi-Fi, joining our network shows no message at all. [What the user sees instead: Safari loads normally / pages fail / nothing changes.] Counter-observation: On a hotel guest network (Marriott) the same kind of device did show a notice, so the feature seems to still work on current iOS. We do not know how that network blocks Private Relay. Related reports: thread 687684 and thread 722315 describe a similar gap (network-level NXDOMAIN gives no alert, on-device DNS filtering does). Our own report: FB[number], no response so far. Questions: Which conditions must be met for iOS to show the message? Is NXDOMAIN for the two documented names enough, or does the alert also depend on other hostnames, the DNS response type (NXDOMAIN vs. NODATA), or the state of the network (e.g. before/after captive login)? Is the alert suppressed when “Limit IP Address Tracking” was turned off for that Wi-Fi earlier, or when Private Relay has already connected successfully on another network? Is the documentation still accurate for current iOS releases? If not, could it be updated?
3
0
285
3w
Network Extension URL Filter registration pending review for more than a month
Hello, I am writing about a Network Extension URL Filter configuration submitted through the Identity & Trust section of the CloudKit Console on 5 September 2026 Status shown: In Review / Waiting for Approval Last Modified: 5 September 2026 (unchanged since submission) It has now been 37 days with no response — no approval, no rejection, and no request for changes. The PIR server , Privacy Pass issuer and HTTP/2 OHTTP gateway have been live and serving since the day of submission, configured per the Onboarding.md guidance in Apple's PIR service example, including the apple-url-filter DNS TXT record on the service URL and the url-filter-test validation entry. Could anyone please let me know: Whether this configuration is actually in a review queue, and the expected timeframe; Whether anything further is required from our side — if so, we will act on it the same day. The URL filter is a core protection feature of our app, which is currently in App Store review; the feature stays disabled for users until this registration is approved, so the delay is holding up what we can ship. Thank you for your help.
4
0
263
3w
Personal Hotspot SSID Stops Advertising After a Period of Time on iPhone
We are observing an issue on iOS 26.6.x where the Personal Hotspot SSID stops being advertised after a period of time, making it unavailable for discovery by nearby devices. This behavior impacts our device onboarding workflow, which relies on connecting to the iPhone's Personal Hotspot. Once the SSID is no longer advertised, nearby devices are unable to discover and connect to the hotspot. Based on our testing, the behavior appears to be independent of our application and seems to be controlled by the operating system. The same behavior is observed even when our application is not running. Observed Behavior Personal Hotspot is enabled and initially discoverable. After a few minutes, the hotspot SSID is no longer visible to nearby devices. Devices can no longer discover or connect to the hotspot. Simply opening the Settings app again causes the hotspot SSID to start advertising immediately and become discoverable once more. The behavior is reproducible on iOS 26.6.x. Expected Behavior While Personal Hotspot remains enabled, the hotspot SSID should continue to be advertised and discoverable by nearby devices without requiring the user to reopen the Settings app. Alternatively, if this behavior is intentional, clarification on the expected hotspot advertisement lifecycle and any related system policies would be appreciated. Impact This issue affects workflows that depend on persistent hotspot availability for accessory provisioning and device onboarding. Users may be required to repeatedly open the Settings app to make the hotspot discoverable again, which negatively impacts the provisioning experience. Questions Is this a known change in Personal Hotspot behavior in iOS 26.6.x? Is it expected for the hotspot SSID to stop advertising after a period of inactivity? Is reopening the Settings app expected to restart hotspot advertising? Are there any new power management or system-level restrictions affecting hotspot discoverability? Is there a recommended approach for applications that depend on consistent Personal Hotspot availability during device setup?
1
1
132
3w
Background URLSession uploads stalled by scheduler budget policies
Our app supports large-file uploads (20 GB+) and uploads of many files. We use a background URLSession so transfers can continue if the user backgrounds the app. In separate affected-device captures, Console logs and a sysdiagnose show dasd declining upload activities under Energy Budget Policy or Data Budget Policy. Upload tasks are created and resumed, but no bytes are transferred. Subsequent uploads can also remain queued, including after earlier uploads are cancelled and the app is relaunched. The issue is intermittent but can persist: one device recovered after approximately 24 hours; another remained affected for several days. We have not established what causes recovery or how the relevant budget eligibility is computed or replenished. Foreground and power observations For the energy-budget reproduction, the user kept the app foregrounded. Application lifecycle logs and RunningBoard running-active-Visible notifications corroborate foreground/active state around the affected task creation and resume operations. The rejection repeatedly reports: Energy Budget Policy [energyBudget]: Required:1.00, Observed:0.00 Decision: MNP Battery samples were approximately 68%, with Low Power Mode off. New uploads using the same session succeeded while the device was connected to external power and were rejected again after disconnection. Discretionary configuration versus daemon classification Our upload-session factory does not set isDiscretionary to true. In a separate, successful reproduction, instrumentation read isDiscretionary from the actual owning URLSession.configuration at task creation: 10:35:04.234749-0500 Frame.io: Upload task 1 created in session com.frameio.backgroundSession.diagnostics, configured isDiscretionary: false The corresponding daemon entry was: 10:35:04.245137-0500 nsurlsessiond: NDSession <8BA476D9-E790-46B6-B1DA-0246E14BBDAF> Task <1B16494D-BBE8-448F-9297-9DB8772ADD92>.<1> current discretionary status for com.frame.FrameIO is discretionary (opt-in: 0) All five tasks in that successful upload showed this combination. We do not yet have the instrumented configuration readout from the failed energy-budget reproduction. Implementation notes Large files are split into smaller files to support resumable uploads through our backend API. Each part is submitted as a file-backed upload task through the same background session, using a stable session identifier across launches. Goal User-initiated uploads make progress while the app is foregrounded and the network is available, and continue when possible after backgrounding. We understand background execution is system-controlled, but need to avoid uploads remaining stalled for days with no actionable recovery. We are considering switching between foreground and background URLsessions when the app moves between the foreground and background, but have concerns about that the bookkeeping on that path could be a brittle pattern. We have also considered using a BGContinuedProcessingTaskRequest for the entire upload, but have concerns about running into new scheduling issues there. Questions What session configuration and task-submission pattern does Apple recommend for this requirement? Is a background URLSession appropriate for both foreground and background uploading, or should we use a different architecture? Is it expected that tasks created and resumed while the app is foreground/active, with the owning session reporting isDiscretionary = false, can be blocked by Energy Budget or Data Budget Policy? If so, what supported approach allows these user-initiated uploads to progress while the app remains foregrounded? When this restriction persists across cancellation, new uploads, and app relaunch, what supported recovery mechanism should we implement? Can the app detect the restriction and take an effective action, rather than requiring external power or waiting an unknown amount of time? For 20 GB+ files and large upload batches split into file-backed tasks, are there recommended chunk sizes, outstanding-task limits, or session-management practices that prevent this failure mode? If the captured foreground behavior is unexpected, is this a known OS issue with an available fix or supported workaround? What additional evidence is needed to obtain a concrete remediation?
3
2
405
3w
Official iOS API or entitlement for real-time LTE/5G RF measurements (PCI, RSRP, SINR, Cell ID)?
Hello Apple Developer Team, I am developing an iPhone application called RF Field Test for professional DAS (Distributed Antenna System) and macro cellular network technicians. The application already supports GPS location tracking, network connection detection, and cellular speed testing. To make it useful for professional RF field testing, I need access to real-time cellular measurements, including: PCI (Physical Cell Identity) Cell ID / ECI / NCI RSRP, RSRQ, and SINR LTE and NR frequency bands EARFCN and NR-ARFCN LTE / 5G NSA / 5G SA identification Channel bandwidth Serving and neighboring cell information I understand that standard public Core Telephony APIs do not expose most of these measurements. My questions are: Is there an officially supported API, entitlement, or carrier-specific development program that provides access to these measurements? Can an independent developer apply for this access, or must the application be developed through an authorized cellular carrier? Would Apple's interoperability request process be appropriate for requesting these capabilities? If these measurements are unavailable to third-party applications, is there an official recommended approach for developing professional cellular RF testing tools on iPhone? I am looking for a legitimate, App Store-compliant solution without private APIs or unsupported methods. Thank you for any guidance.
1
0
392
3w
NetworkConnection: DATAGRAM offer 1400 but usableDatagramFrameSize returns 0 (FB25125957)
I am looking for guidance on the new Swift NetworkConnection<QUIC> DATAGRAM API. A Network.framework defect has not been established. I filed FB25125957, which includes a minimal reproducible source package and numeric evidence. Environment Apple Silicon M2, macOS 27.0.1 (26A434), Xcode 27.0 (27A266a), macOS SDK 27.0 (26A425), Swift 6.4. Builds use an explicit DEVELOPER_DIR, Swift 6 strict concurrency, and warnings as errors. Apple-to-Apple localhost case Both endpoints offer maxDatagramFrameSize(1400), explicitly start their parent connections, and wait for ready. Fresh certificate mutual TLS uses a private test root, role-specific SAN validation, and preknown exact leaf pins. No system trust or keychain modification. After ready, the client awaits parent.datagrams, then reads usableDatagramFrameSize on that same parent. The accessor returns and the getter returns 0. Both endpoints passed their current TLS 1.3 / ALPN / certificate gates, with no early data. The server getter remained unobserved when our local guard stopped this case. No DATAGRAM payload was sent. Our capability error 1005 is a local guard, not NWError. Independent-peer case One Apple listener and an aioquic 1.3.0 client, both advertising 1400, with the same current root/SAN/exact-pin authentication requirements. Both passed mutual authentication, TLS 1.3 / 0x1301 / exact ALPN, with no resumption or early data. The peer decoded Apple's remote max_datagram_frame_size=1400 (present) and recorded its own serialized offer=1400. On the same accepted Apple parent, await datagrams returned and usableDatagramFrameSize completed with 0. The peer's local serialization does not prove that Apple parsed its offer. No application DATAGRAM or media payload was sent. Questions Does ready guarantee that the peer DATAGRAM transport parameter has been processed? Does completing await parent.datagrams provide a stronger guarantee? If a zero usable capacity is transient, what supported event or API should be awaited rather than arbitrary sleeps/retries? What is the supported start/ready/datagrams ordering and parent lifetime for outgoing versus accepted connections? Is opening a reliable stream first a prerequisite? Is there a minimal certificate-TLS DATAGRAM example? Which public diagnostic can distinguish an absent/zero peer advertisement from usable-size calculation, interoperability, or lifecycle issues? Is there a known limitation in this exact OS/SDK, a fixed version, or an authentication-preserving workaround? The source and evidence are attached to FB25125957. They contain no private keys, passwords, pairing credentials, user footage, app bundles, or full qlog. I am asking about basic DATAGRAM availability, not claiming any Wi-Fi or video performance result.
0
0
110
4w
SOCKS5 proxies (from PAC or ProxyConfiguration) are never applied to QUIC, and NWConnection silently connects directly
On macOS 27.0.1 (26A434), a SOCKS5 proxy is applied to TCP connections but never to QUIC. This happens whether the proxy comes from a PAC file in the system proxy settings or from an explicit ProxyConfiguration. The system SOCKS5 client only ever sends CONNECT; it never sends UDP ASSOCIATE (RFC 1928, CMD 0x03), so it has no way to carry UDP. URLSession handles this by staying on TCP through the proxy. A QUIC NWConnection instead connects directly to the origin, as if no proxy were configured. Setup. The system proxy settings use a PAC URL (ProxyAutoConfigURLString in scutil --proxy; in my test it was installed through NEProxySettings.proxyAutoConfigurationURL). For the test host, a public site that serves HTTP/3, the PAC returns SOCKS5 127.0.0.1:<port>. For the explicit cases I used a local SOCKS5 server that logs every command it receives. With the system PAC, default parameters, no explicit proxy: URLSession, assumesHTTP3Capable = true: goes through the proxy over TCP (transaction metrics: h2, isProxyConnection == true, remote address 127.0.0.1:<port>). HTTP/3 isn't used, which is consistent: the proxy can't carry it. NWConnection, TLS: currentPath.remoteEndpoint is 127.0.0.1:<port>. The PAC is honored. NWConnection, QUIC (ALPN h3): .ready in about 170 ms, and currentPath.remoteEndpoint is the origin's own address. The PAC is ignored. With an explicit proxy, set via NWParameters.PrivacyContext.proxyConfigurations: QUIC with a working SOCKS5 server: .ready, and the server receives nothing — no CONNECT, no UDP ASSOCIATE. QUIC with the proxy pointing at a port nothing listens on: still .ready, still connected to the origin's own address. TLS with that same dead proxy: stays in .waiting with ECONNREFUSED. The proxy is honored for TCP. At no point did the SOCKS5 server receive a UDP ASSOCIATE request. Cases 3–5 are the concerning part. An app that configures a proxy, or a user or administrator who installs a PAC, reasonably expects traffic to go through the proxy or fail. Instead, QUIC traffic goes straight to the origin, which then sees the device's own address, and nothing in the API signals that the proxy was skipped. Minimal snippet: import Network let host: NWEndpoint.Host = "YOUR_HTTP3_HOST" // any public host that serves HTTP/3 let parameters = NWParameters(quic: NWProtocolQUIC.Options(alpn: ["h3"])) // Remove these four lines to test with the system PAC instead. let privacy = NWParameters.PrivacyContext(description: "socks5-quic") privacy.proxyConfigurations = [ ProxyConfiguration(socksv5Proxy: .hostPort(host: "127.0.0.1", port: 1099)) // nothing listens on 1099 ] parameters.setPrivacyContext(privacy) let connection = NWConnection(host: host, port: 443, using: parameters) connection.stateUpdateHandler = { state in if case .ready = state { // Prints the origin's own address. With NWParameters.tls instead of QUIC, // the same proxy configuration leaves the connection in .waiting (ECONNREFUSED). print(connection.currentPath?.remoteEndpoint as Any) } } connection.start(queue: .main) I filed this as FB24760235 on 09/13/2026 and haven't had a response, so I'd like to ask here: Is it intended that a QUIC NWConnection ignores both the system PAC and proxyConfigurations? If so, how can an app find out that a connection went direct? And shouldn't a connection that can't honor the configured proxy fail rather than bypass it? Is UDP ASSOCIATE support planned for the system SOCKS5 client, so that QUIC and other UDP traffic can follow a SOCKS5 proxy the way TCP does? Thanks!
3
0
833
4w
Keeping a Local Wi-Fi TCP Transfer Alive in the Background Using Bluetooth Notifications — Is This Viable?
Requirement Description The app operates as a central device. It connects to a Bluetooth peripheral via Core Bluetooth. Once connected, the peripheral enables a Wi-Fi hotspot. The app joins this hotspot and transfers data over a TCP connection. The app needs to remain active in the background until this TCP data transfer is complete.  Question Regarding the Proposed Solution One proposed approach is to have the peripheral send periodic BLE notifications (reporting transfer progress) to the app, using each notification to briefly wake the app and extend its background execution time. Would this method successfully keep the TCP connection alive in the background until the transfer finishes? Does it comply with App Store review guidelines?  Request for Alternative Solutions If this approach is not viable, could you advise on any supported mechanisms or recommended architectures that would allow a local Wi-Fi TCP data transfer to complete reliably after the app moves to the background?
1
0
252
4w
Can't the input loop of a NWProtocolFramerImplementation be like...
Recently, I've been asking here about creating a NWProtocolFramerImplementation that splits across line breaks. Examples and questions usually involve some glob in a "while true" loop. From reading around, couldn't that function be implemented as: func handleInput(framer: NWProtocolFramer.Instance) -> Int { // Pull out objects until an incomplete object is discovered. var domainData: Data? while framer.parseInput( minimumIncompleteLength: 1, maximumLength: .max, parse: { buffer, isComplete in guard let buffer else { return 0 } // Why is `buffer` an Optional? // Other checks and computations // Mutate domainData with the result of this iteration. // Return how many bytes from the buffer are an irrevocable part of domainData. } ) { defer { domainData = nil } guard let domainData else { break } let domainMessage = //... let framerMessage = NWProtocolFramer.Message(myMessage: domainMessage) // The return value is whether or not the delivery was immediate. _ = framer.deliverInputNoCopy(length: domainData.count, message: framerMessage, isComplete: true) } return 0 } A clear separation of concerns, and makes figuring out what's going on easier.
1
0
371
Oct ’26
Unexplained behavioural changes in BSD sockets on macos 26.6.x and 27
We have started seeing some unexplained behavioural differences in the BSD socket APIs on macos 26.6.x and macos 27. On a different front, there also seems to be some changes in the ptrace area for PT_DETACH. Historically, the release notes of macos don't include any mention of such changes. And unfortunately, prior experience of filing feedback assistant issues too hasn't been very motivating due to lack of any response on those tickets. These forums have been very helpful in trying to understand some of these changes, and I plan to raise separate topics for the issues shortly. In the past, the other useful option I have used is reading up the kernel sources published at https://opensource.apple.com/releases/. But there hasn't been any updates for macos 26.6 or macos 27. It will be very useful if macos 26.6 and 27 releases are published there. That will help expedite investigating some of these failures. BSD socket APIs in the recent releases of macos have seen several issues (feedback assistant issues have been filed). The implications of these failures is that we (in OpenJDK) have had to disable several tests on recent versions of macos which has reduced the test coverage and reliability of these very primitive networking APIs on this platform.
5
0
420
Oct ’26
WCSession.sendMessage is crashing when a reply or error handler is attached, why?
The following code should send a message from the watch to the iPhone. Unfortunately, it is crashing. I have no clue why. if WCSession.isSupported() { let session = WCSession.default if ((session.activationState == .activated) && session.isReachable) { session.sendMessage(["SimpleMessages":["start"]], replyHandler:{reply in _ = 0 }, errorHandler:nil) } } If the reply handler is set to nil, the code does not crash. Anyway, in both cases the message is correctly sent from the watch to the phone. The code itself is run on the main thread (verified). I am running watchOS 26.6 and iOS 27. Here is the crash : Stack trace
3
0
340
Oct ’26
Dual-stack UDP socket bound to port 0 can get a port already in use on 127.0.0.1 (FB25058707)
I filed FB25058707 and wanted to make sure it reaches the right people, because it causes silent datagram loss that's hard to trace. On macOS, when a dual-stack UDP socket (AF_INET6 with IPV6_V6ONLY=0) binds [::]:0, the kernel sometimes gives it a port that an AF_INET socket already has bound to 127.0.0.1. Datagrams sent to 127.0.0.1 on that port then go to the AF_INET socket, so the dual-stack socket never receives them. An explicit bind of the same socket to that port fails with EADDRINUSE; only port-0 assignment hands it out. This program binds 1000 AF_INET sockets to 127.0.0.1:0, then binds dual-stack sockets to [::]:0 and checks where a datagram to 127.0.0.1:port lands whenever the port is already held. It's loopback only and runs in a few seconds: /* * A dual-stack UDP socket (AF_INET6, IPV6_V6ONLY=0) bound to [::]:0 can be * assigned a port already bound by an AF_INET socket on 127.0.0.1. Datagrams * to 127.0.0.1:port then reach the AF_INET socket, not the dual-stack one. * Loopback only. Build: cc -O2 -o dualstack_port0 dualstack_port0.c */ #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/time.h> #include <unistd.h> #define HELD 1000 #define TRIALS 2000 static int held[65536]; static void die(const char *what) { perror(what); exit(1); } static int port_of(int s) { struct sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(s, (struct sockaddr *)&ss, &len) != 0) die("getsockname"); if (ss.ss_family == AF_INET) return ntohs(((struct sockaddr_in *)&ss)->sin_port); return ntohs(((struct sockaddr_in6 *)&ss)->sin6_port); } static int bind_v4(in_addr_t addr) { int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) die("socket AF_INET"); struct sockaddr_in sin = { .sin_len = sizeof(sin), .sin_family = AF_INET, .sin_addr.s_addr = addr }; if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) != 0) die("bind AF_INET"); return s; } static int bind_dual(void) { int s = socket(AF_INET6, SOCK_DGRAM, 0), off = 0; if (s < 0) die("socket AF_INET6"); if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) != 0) die("IPV6_V6ONLY"); struct sockaddr_in6 sin6 = { .sin6_len = sizeof(sin6), .sin6_family = AF_INET6, .sin6_addr = in6addr_any }; if (bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) != 0) die("bind AF_INET6"); return s; } /* Returns 1 if s receives token within 100ms, skipping other datagrams. */ static int got(int s, const char *token) { struct timeval tv = { .tv_sec = 0, .tv_usec = 100000 }; if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) die("SO_RCVTIMEO"); char buf[64]; for (;;) { ssize_t n = recv(s, buf, sizeof(buf) - 1, 0); if (n < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; die("recv"); } buf[n] = 0; if (strcmp(buf, token) == 0) return 1; } } int main(void) { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) != 0) die("getrlimit"); rl.rlim_cur = rl.rlim_max < 4096 ? rl.rlim_max : 4096; if (setrlimit(RLIMIT_NOFILE, &rl) != 0) die("setrlimit"); memset(held, -1, sizeof(held)); for (int i = 0; i < HELD;) { int s = bind_v4(htonl(INADDR_LOOPBACK)), p = port_of(s); if (held[p] >= 0) { close(s); continue; } held[p] = s; i++; } int sender = bind_v4(htonl(INADDR_LOOPBACK)); for (int dual = 1; dual >= 0; dual--) { int collisions = 0, to_held = 0, to_wild = 0; for (int i = 0; i < TRIALS; i++) { int w = dual ? bind_dual() : bind_v4(htonl(INADDR_ANY)), p = port_of(w); if (held[p] >= 0) { collisions++; char token[32]; snprintf(token, sizeof(token), "%d-%d", dual, i); struct sockaddr_in to = { .sin_len = sizeof(to), .sin_family = AF_INET, .sin_port = htons(p), .sin_addr.s_addr = htonl(INADDR_LOOPBACK) }; if (sendto(sender, token, strlen(token), 0, (struct sockaddr *)&to, sizeof(to)) < 0) die("sendto"); to_held += got(held[p], token); to_wild += got(w, token); } close(w); } printf("%s: %d/%d wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket %d times, the wildcard socket %d times\n", dual ? "AF_INET6 V6ONLY=0 [::]:0" : "AF_INET 0.0.0.0:0 ", collisions, TRIALS, to_held, to_wild); } return 0; } On macOS 27.0 (26A428): AF_INET6 V6ONLY=0 [::]:0: 122/2000 wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket 122 times, the wildcard socket 0 times AF_INET 0.0.0.0:0 : 0/2000 wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket 0 times, the wildcard socket 0 times macOS 15.8.1 x86_64 gives the same pattern, and a Go version of the test reproduces on 15.7.9 and 26.6.2 as well. FreeBSD 15.1 gives 0/2000 with a dual-stack socket. From the public XNU source (xnu-12377.121.6), in6_pcbsetport checks candidate ports with in6_pcblookup_local, which skips PCBs without INP_IPV6, while in6_pcbbind does an IPv4 PCB lookup for dual-stack wildcard binds. That would explain why an explicit bind is refused but port 0 isn't. This is the cause of the long-standing Go issue golang/go#67226, since Go's net.ListenUDP("udp", 0.0.0.0:0) creates exactly this socket, and of intermittent failures in QUIC client tests. Using an AF_INET socket for IPv4-only traffic avoids it, but there's no workaround for a socket that needs both families on one port.
2
0
342
Oct ’26
macos 27 - EDOM error from setsockopt() for SO_LINGER socket option for values greater than 32767
On macos 27, there appears to be a change in the setsockopt() implementation for the SO_LINGER option. It looks like the implementation now imposes a different maximum limit on the value that is accepted for linger. Consider the trivial attached C program. Rename it from main.c.txt to main.c. Compiling it (using clang main.c) and running it (using ./a.out), on older versions of macos (like 26.x), it returns: ----------------------- MacOS version: 26.7.1 Kernel version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000 ----------------------- SUCCESS - set SO_LINGER to value 10 SUCCESS - set SO_LINGER to value 42 SUCCESS - set SO_LINGER to value 1024 SUCCESS - set SO_LINGER to value 32767 SUCCESS - set SO_LINGER to value 32768 SUCCESS - set SO_LINGER to value 65535 SUCCESS - set SO_LINGER to value 65536 SUCCESS - set SO_LINGER to value 65578 However, on macos 27, this now fails with EDOM error ("Numerical argument out of domain") for values greater than 32767: ----------------------- MacOS version: 27.0.1 Kernel version: Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:16 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8112 ----------------------- SUCCESS - set SO_LINGER to value 10 SUCCESS - set SO_LINGER to value 42 SUCCESS - set SO_LINGER to value 1024 SUCCESS - set SO_LINGER to value 32767 FAILURE - failed to set SO_LINGER to value 32768, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65535, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65536, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65578, reason: Numerical argument out of domain I'm guessing this is an intentional change, but I wanted to confirm nonetheless. Should the documentation of SO_LINGER and SO_LINGER_SEC socket options, in man setsockopt, mention the acceptable value range for them? main.c.txt
2
0
318
Oct ’26
macos 27 - unexpected/new errno from BSD socket connect() when pending connections exceed backlog
Please consider the trivial C program attached to this thread. The code creates a socket() and listen()s for connections, but (intentionally) doesn't accept() the connections. The listen() is done using a small backlog (of 1). This test then does several connect() attempts and expects that the connect() attempts will accumulate in the pending queue and once the queue exceeds the backlog limit, then as specified in man listen: The backlog parameter defines the maximum length for the queue of pending connections. If a connection request arrives with the queue full, the client may receive an error with an indication of ECONNREFUSED. then the connect() attempt will receive a ECONNREFUSED. However, in macos 27, such a connect() attempt leads to ECONNRESET (Connection reset by peer) instead of ECONNREFUSED. Is this expected? Experiments show that prior versions of macos were returning a ETIMEDOUT for such connect() attempts. If this new error is expected from connect() when the backlog limit has exceeded, should it be specified in the man listen documentation? Rename the attached main.c.txt to main.c. Compiling the attached program on macos 27, using clang main.c and then running ./a.out results in: ----------------------- MacOS version: 27.0.1 Kernel version: Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:16 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8112 ----------------------- started server at at 127.0.0.1:52753 with a backlog of 1 connect() attempt 1 - connected connect() attempt 2 - connected connect() attempt 3 - connected connect() attempt 4 - connected connect() attempt 5 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 6 - connected connect() attempt 7 - connected connect() attempt 8 - connected connect() attempt 9 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 10 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 11 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 On a related note, it's unclear why several of the connect() attempts succeeded instead of just 1 of them succeeding. On prior versions of macos, the output of the same program is: ----------------------- MacOS version: 26.7.1 Kernel version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000 ----------------------- started server at at 127.0.0.1:52451 with a backlog of 1 connect() attempt 1 - connected connect() attempt 2 - failed to connect() - Operation timed out connect() attempt 3 - failed to connect() - Operation timed out connect() attempt 4 - failed to connect() - Operation timed out connect() attempt 5 - failed to connect() - Operation timed out connect() attempt 6 - failed to connect() - Operation timed out connect() attempt 7 - failed to connect() - Operation timed out connect() attempt 8 - failed to connect() - Operation timed out connect() attempt 9 - failed to connect() - Operation timed out connect() attempt 10 - failed to connect() - Operation timed out connect() attempt 11 - failed to connect() - Operation timed out and this output is much more understandable and deterministic. main.c.txt
2
0
335
Oct ’26
TCP connection in with Wi-Fi aware framework never reaches ".ready" state
While developing our wifi-aware implementation we ran into a specific issue where TCP connections seem to never reach a "ready" state (ready to transfer data). It stays in “”preparing” state trying to connect for forever. We tried to recreate a new TCP connection every time after the connection stays in "preparing" for longer than 10 seconds. This helps to "recover" eventually, but it only happens after 1.5 - 2 minutes. Creating a completely new NetworkBrowser and NetworkListener doesn’t speed up this process. The issue occurs when the browser and listener are setting up the NAN/TCP connection, at that time if the user opens the DevicePairingView it seems that it disrupts or interferes with the connection, entering an invalid state. From what we can see it takes around 2 minutes for it to recover, presumably this is when NAN drops the connection (timeout) and creates a new one.

 STEPS TO REPRODUCE Reproduction steps:

 Open the app on 2 wifi-aware devices.
 Device 1 presses “Pair with device”. Device 2 navigates to “Receive” and presses the “”Pair with sender”.
 Complete the pairing process.

 Device 1 (Send) presses the start button.
 Device 2 (receive) presses start button, Directly after the button press, device 1 presses the “”Pair with sender” button
 Observe TCP connection never fully establishes (1.5 - 2 mins) PLATFORM AND VERSION iOS Development environment: Xcode 26.3, macOS 26.4.1 Run-time configuration: iOS 26.5 test project with a recording showing the issue: https://github.com/DeveloperNiels/WAIssue
7
0
790
Oct ’26
Out-of-band data returned by recv() and read() on socket bound to non-loopback address even when SO_OOBINLINE is disabled
I've been investigating an issue with the SO_OOBINLINE socket option. When that option is disabled, the expectation is that out-of-band data that is sent on the socket will not be available through the use of read() or recv() calls on that socket. What we have been noticing is that when the socket is bound to a non-loopback address (and the communication is happening over that non-loopback address), then even when SO_OOBINLINE is disabled for the socket, the read()/recv() calls both return the out-of-band data. The issue however isn't reproducible with loopback address, and read()/recv() both correctly exclude the out-of-band data. This issue is only noticed on macos. I have been able to reproduce on macos M1, following version, but the original report which prompted me to look into this was reported on macos x64. My M1 OS version is: sw_vers ProductName: macOS ProductVersion: 14.3.1 BuildVersion: 23D60 Attached is a reproducer (main.c.txt - rename it to main.c after downloading) that I have been able to develop which reproduces this issue on macos. When you compile and run that: ./a.out it binds to a non-loopback address by default and you should see the failure log, resembling: ... ERROR: expected: 1234512345 but received: 12345U12345 To run the same reproducer against loopback address, run it as: ./a.out loopback and that should succeed (i.e. no out-of-band data) with logs resembling: ... SUCCESS: completed successfully, expected: 1234512345, received: 1234512345 Is this a bug in the OS? I would have reported this directly through feedback assistant, but my past few open issues (since more than a year) have not even seen an acknowledgement or a reply, so I decided to check here first. main.c.txt
8
0
1.3k
Oct ’26
NEURLFilterManager.localizedDescription is ignored by System Settings -> Network -> Filters
macOS 26.6, 26.7, 27.0 and 27.2 beta 1/2. Reproduced with Apple's SimpleURLFilter sample ("Filtering traffic by URL", WWDC25 session 234), built and run as a macOS app. The sample never sets localizedDescription, so I added one line to ConfigurationModel.save(configuration:) before saveToPreferences(): sharedFilterManager.localizedDescription = "Sentinel Filter Name" The property holds the value in memory: after loadFromPreferences(), the logged LocalizedStringResource still has key: "Sentinel Filter Name". But the effective configuration the system starts the session with has no localizedDescription — the session is named after the app: name = SimpleURLFilter applicationName = SimpleURLFilter application = com.example.apple-samplecode.SimpleURLFilterTC3Q7MAJXF (the rest of the nesessionmanager dump is the urlFilter dictionary, and it has no localizedDescription key). System Settings > Network > Filters shows the filter as URLFilter, not "Sentinel Filter Name". The stored configuration (/Library/Preferences/com.apple.networkextension.plist) has no localizedDescription key either, and injecting one by hand does not survive a nesessionmanager restart. Re-saving, removing and re-creating the configuration, and rebooting the Mac do not change the displayed name. Expected: the docs describe localizedDescription as "A string containing a description of the URL filter", and WWDC25 session 234's code sample ("Configure and manage URL Filter") sets it this way (manager.localizedDescription = "Alice's URL Filter"). For comparison, a NETransparentProxyManager configuration on the same Mac persists localizedDescription as the configuration's Name in the same plist, while the URL filter configuration has no such field. Filed as FB24987420.
1
0
313
Sep ’26
Sequoia 'local network' permission failure from launch agent
I'm trying to invoke a 3rd party command line tool from a launch agent to connect to a server on my LAN. It seems impossible. I have a little shell script that does what I need, and it works fine invoked in Terminal.app. The first time I run it that way I get permission prompts and I agree to them all. Subsequent invocations work. Now I put a launch agent in ~/Library/Launch Agents. It does nothing more than invoke my shell script at some specific time daily. launchd launches it, but it fails to access the LAN, with a 'no route to host' error message. The command line tool I'm trying to use is not a macOS-provided one, but one from MacPorts/HomeBrew (I tried both). It doesn't even matter which tool I'm using, I tried a very simple case of just using nc/netcat. If I use the macOS-provided nc, then I can access my LAN. If I install nc from MacPorts /HomeBrew, that nc cannot access my LAN. This I've reproed on a literally brand new Mac, then updated to newest Sequoia (15.3.2), then done all I've described above. I've ruled out DNS by working with raw IP addresses. I've disabled gatekeeper with sudo spctl --master-disable. I've tried using cron instead of launch agents, same results. I've tried codesigning with codesign -dvvv /opt/homebrew/bin/nc, no help. I've read TN3179 Understanding local network privacy. In summary: Terminal.app -> script -> macOS/brew nc -> internet/LAN = works launchagent -> script -> macOS nc -> internet = works launchagent -> script -> macOS nc -> LAN = works launchagent -> script -> brew nc -> internet = works launchagent -> script -> brew nc -> LAN = fails How can I make that last case work?
Replies
17
Boosts
0
Views
968
Activity
3w
libquic.dylib crash during QUIC path migration on iOS 26 (quic_migration_probe_path / nw_protocol_data_access_buffer)
libquic.dylib crashes with a null/invalid buffer access in nw_protocol_data_access_buffer during QUIC connection path migration on iOS 26. App code is not in the stack — this is entirely within Apple system libraries. We are seeing a consistent crash on iOS 26 that does not reproduce on iOS 17 or iOS 18. The crash occurs on a background thread ("com.apple.network.connections") with no application code in the crashed thread's stack. The crash trace begins in quic_migration_probe_path and terminates in nw_protocol_data_access_buffer + 180, suggesting a use-after-free or buffer lifetime violation during QUIC connection path migration (e.g., Wi-Fi ↔ Cellular handoff). This crash does not appear to be reproducible on demand — it correlates with network path transitions while QUIC connections are active. Our app uses standard URLSession with default/ephemeral session configurations and does not explicitly enable HTTP/3; iOS 26 is automatically upgrading eligible connections. Crash thread (abbreviated): 0 libquic.dylib quic_conn_send_packet + 144 1 libquic.dylib quic_conn_continue_sending + 424 2 libquic.dylib __quic_conn_send_frames_for_key_state_block_invoke_2 + 1244 3 Network nw_protocol_data_access_buffer + 180 ← crash 4 Network nw_protocol_data_copy_buffer 5 Network nw_endpoint_flow_output_frames 6 libquic.dylib quic_conn_send_frames_for_key_state 7 libquic.dylib quic_conn_send_frames 8 libquic.dylib quic_migration_probe_path + 1464 9 libquic.dylib quic_migration_path_established + 2608 10 libquic.dylib __quic_migration_path_event_block_invoke.21 11 libquic.dylib quic_migration_path_event 12 Network nw_protocol_implementation_connected There is no app code in the crashed thread. This is a regression introduced in iOS 26, where libquic.dylib was separated into its own dynamic library and new path migration probe logic was introduced.
Replies
9
Boosts
0
Views
1.5k
Activity
3w
iCloud Private Relay: network blocking set up exactly as documented (NXDOMAIN for mask.icloud.com / mask-h2.icloud.com), but iOS shows no alert
We run a Wi-Fi network with our own captive portal and want iOS clients to be told that Private Relay is not available here, as described in Prepare your network or web server for iCloud Private Relay and WWDC21 session 10096. Our setup: Resolver: Unbound, handed out via DHCP, with local-zone: "mask.icloud.com" always_nxdomain and local-zone: "mask-h2.icloud.com" always_nxdomain. The network is IPv4-only. The captive portal intercepts all UDP port 53 traffic and drops everything else (e.g. port 853). TCP port 53 is not served. We also tried NXDOMAIN for mask-api.icloud.com, apple-native-relay.apple.com, mask.apple-dns.net, mask-api.fe.apple-dns.net and mask-t.apple-dns.net, with no change. [Result of our resolver log: do queries for the mask hosts arrive from the test iPhone, and what do we answer? Before and after captive-portal login?] What the documentation promises: “users will be alerted that they need to either disable Private Relay for that network, or choose another network.” What happens: On [iPhone model], iOS [exact version/build], with Private Relay enabled in iCloud settings and “Limit IP Address Tracking” [on/off] for this Wi-Fi, joining our network shows no message at all. [What the user sees instead: Safari loads normally / pages fail / nothing changes.] Counter-observation: On a hotel guest network (Marriott) the same kind of device did show a notice, so the feature seems to still work on current iOS. We do not know how that network blocks Private Relay. Related reports: thread 687684 and thread 722315 describe a similar gap (network-level NXDOMAIN gives no alert, on-device DNS filtering does). Our own report: FB[number], no response so far. Questions: Which conditions must be met for iOS to show the message? Is NXDOMAIN for the two documented names enough, or does the alert also depend on other hostnames, the DNS response type (NXDOMAIN vs. NODATA), or the state of the network (e.g. before/after captive login)? Is the alert suppressed when “Limit IP Address Tracking” was turned off for that Wi-Fi earlier, or when Private Relay has already connected successfully on another network? Is the documentation still accurate for current iOS releases? If not, could it be updated?
Replies
3
Boosts
0
Views
285
Activity
3w
Network Extension URL Filter registration pending review for more than a month
Hello, I am writing about a Network Extension URL Filter configuration submitted through the Identity & Trust section of the CloudKit Console on 5 September 2026 Status shown: In Review / Waiting for Approval Last Modified: 5 September 2026 (unchanged since submission) It has now been 37 days with no response — no approval, no rejection, and no request for changes. The PIR server , Privacy Pass issuer and HTTP/2 OHTTP gateway have been live and serving since the day of submission, configured per the Onboarding.md guidance in Apple's PIR service example, including the apple-url-filter DNS TXT record on the service URL and the url-filter-test validation entry. Could anyone please let me know: Whether this configuration is actually in a review queue, and the expected timeframe; Whether anything further is required from our side — if so, we will act on it the same day. The URL filter is a core protection feature of our app, which is currently in App Store review; the feature stays disabled for users until this registration is approved, so the delay is holding up what we can ship. Thank you for your help.
Replies
4
Boosts
0
Views
263
Activity
3w
Personal Hotspot SSID Stops Advertising After a Period of Time on iPhone
We are observing an issue on iOS 26.6.x where the Personal Hotspot SSID stops being advertised after a period of time, making it unavailable for discovery by nearby devices. This behavior impacts our device onboarding workflow, which relies on connecting to the iPhone's Personal Hotspot. Once the SSID is no longer advertised, nearby devices are unable to discover and connect to the hotspot. Based on our testing, the behavior appears to be independent of our application and seems to be controlled by the operating system. The same behavior is observed even when our application is not running. Observed Behavior Personal Hotspot is enabled and initially discoverable. After a few minutes, the hotspot SSID is no longer visible to nearby devices. Devices can no longer discover or connect to the hotspot. Simply opening the Settings app again causes the hotspot SSID to start advertising immediately and become discoverable once more. The behavior is reproducible on iOS 26.6.x. Expected Behavior While Personal Hotspot remains enabled, the hotspot SSID should continue to be advertised and discoverable by nearby devices without requiring the user to reopen the Settings app. Alternatively, if this behavior is intentional, clarification on the expected hotspot advertisement lifecycle and any related system policies would be appreciated. Impact This issue affects workflows that depend on persistent hotspot availability for accessory provisioning and device onboarding. Users may be required to repeatedly open the Settings app to make the hotspot discoverable again, which negatively impacts the provisioning experience. Questions Is this a known change in Personal Hotspot behavior in iOS 26.6.x? Is it expected for the hotspot SSID to stop advertising after a period of inactivity? Is reopening the Settings app expected to restart hotspot advertising? Are there any new power management or system-level restrictions affecting hotspot discoverability? Is there a recommended approach for applications that depend on consistent Personal Hotspot availability during device setup?
Replies
1
Boosts
1
Views
132
Activity
3w
Background URLSession uploads stalled by scheduler budget policies
Our app supports large-file uploads (20 GB+) and uploads of many files. We use a background URLSession so transfers can continue if the user backgrounds the app. In separate affected-device captures, Console logs and a sysdiagnose show dasd declining upload activities under Energy Budget Policy or Data Budget Policy. Upload tasks are created and resumed, but no bytes are transferred. Subsequent uploads can also remain queued, including after earlier uploads are cancelled and the app is relaunched. The issue is intermittent but can persist: one device recovered after approximately 24 hours; another remained affected for several days. We have not established what causes recovery or how the relevant budget eligibility is computed or replenished. Foreground and power observations For the energy-budget reproduction, the user kept the app foregrounded. Application lifecycle logs and RunningBoard running-active-Visible notifications corroborate foreground/active state around the affected task creation and resume operations. The rejection repeatedly reports: Energy Budget Policy [energyBudget]: Required:1.00, Observed:0.00 Decision: MNP Battery samples were approximately 68%, with Low Power Mode off. New uploads using the same session succeeded while the device was connected to external power and were rejected again after disconnection. Discretionary configuration versus daemon classification Our upload-session factory does not set isDiscretionary to true. In a separate, successful reproduction, instrumentation read isDiscretionary from the actual owning URLSession.configuration at task creation: 10:35:04.234749-0500 Frame.io: Upload task 1 created in session com.frameio.backgroundSession.diagnostics, configured isDiscretionary: false The corresponding daemon entry was: 10:35:04.245137-0500 nsurlsessiond: NDSession <8BA476D9-E790-46B6-B1DA-0246E14BBDAF> Task <1B16494D-BBE8-448F-9297-9DB8772ADD92>.<1> current discretionary status for com.frame.FrameIO is discretionary (opt-in: 0) All five tasks in that successful upload showed this combination. We do not yet have the instrumented configuration readout from the failed energy-budget reproduction. Implementation notes Large files are split into smaller files to support resumable uploads through our backend API. Each part is submitted as a file-backed upload task through the same background session, using a stable session identifier across launches. Goal User-initiated uploads make progress while the app is foregrounded and the network is available, and continue when possible after backgrounding. We understand background execution is system-controlled, but need to avoid uploads remaining stalled for days with no actionable recovery. We are considering switching between foreground and background URLsessions when the app moves between the foreground and background, but have concerns about that the bookkeeping on that path could be a brittle pattern. We have also considered using a BGContinuedProcessingTaskRequest for the entire upload, but have concerns about running into new scheduling issues there. Questions What session configuration and task-submission pattern does Apple recommend for this requirement? Is a background URLSession appropriate for both foreground and background uploading, or should we use a different architecture? Is it expected that tasks created and resumed while the app is foreground/active, with the owning session reporting isDiscretionary = false, can be blocked by Energy Budget or Data Budget Policy? If so, what supported approach allows these user-initiated uploads to progress while the app remains foregrounded? When this restriction persists across cancellation, new uploads, and app relaunch, what supported recovery mechanism should we implement? Can the app detect the restriction and take an effective action, rather than requiring external power or waiting an unknown amount of time? For 20 GB+ files and large upload batches split into file-backed tasks, are there recommended chunk sizes, outstanding-task limits, or session-management practices that prevent this failure mode? If the captured foreground behavior is unexpected, is this a known OS issue with an available fix or supported workaround? What additional evidence is needed to obtain a concrete remediation?
Replies
3
Boosts
2
Views
405
Activity
3w
Official iOS API or entitlement for real-time LTE/5G RF measurements (PCI, RSRP, SINR, Cell ID)?
Hello Apple Developer Team, I am developing an iPhone application called RF Field Test for professional DAS (Distributed Antenna System) and macro cellular network technicians. The application already supports GPS location tracking, network connection detection, and cellular speed testing. To make it useful for professional RF field testing, I need access to real-time cellular measurements, including: PCI (Physical Cell Identity) Cell ID / ECI / NCI RSRP, RSRQ, and SINR LTE and NR frequency bands EARFCN and NR-ARFCN LTE / 5G NSA / 5G SA identification Channel bandwidth Serving and neighboring cell information I understand that standard public Core Telephony APIs do not expose most of these measurements. My questions are: Is there an officially supported API, entitlement, or carrier-specific development program that provides access to these measurements? Can an independent developer apply for this access, or must the application be developed through an authorized cellular carrier? Would Apple's interoperability request process be appropriate for requesting these capabilities? If these measurements are unavailable to third-party applications, is there an official recommended approach for developing professional cellular RF testing tools on iPhone? I am looking for a legitimate, App Store-compliant solution without private APIs or unsupported methods. Thank you for any guidance.
Replies
1
Boosts
0
Views
392
Activity
3w
NetworkConnection: DATAGRAM offer 1400 but usableDatagramFrameSize returns 0 (FB25125957)
I am looking for guidance on the new Swift NetworkConnection<QUIC> DATAGRAM API. A Network.framework defect has not been established. I filed FB25125957, which includes a minimal reproducible source package and numeric evidence. Environment Apple Silicon M2, macOS 27.0.1 (26A434), Xcode 27.0 (27A266a), macOS SDK 27.0 (26A425), Swift 6.4. Builds use an explicit DEVELOPER_DIR, Swift 6 strict concurrency, and warnings as errors. Apple-to-Apple localhost case Both endpoints offer maxDatagramFrameSize(1400), explicitly start their parent connections, and wait for ready. Fresh certificate mutual TLS uses a private test root, role-specific SAN validation, and preknown exact leaf pins. No system trust or keychain modification. After ready, the client awaits parent.datagrams, then reads usableDatagramFrameSize on that same parent. The accessor returns and the getter returns 0. Both endpoints passed their current TLS 1.3 / ALPN / certificate gates, with no early data. The server getter remained unobserved when our local guard stopped this case. No DATAGRAM payload was sent. Our capability error 1005 is a local guard, not NWError. Independent-peer case One Apple listener and an aioquic 1.3.0 client, both advertising 1400, with the same current root/SAN/exact-pin authentication requirements. Both passed mutual authentication, TLS 1.3 / 0x1301 / exact ALPN, with no resumption or early data. The peer decoded Apple's remote max_datagram_frame_size=1400 (present) and recorded its own serialized offer=1400. On the same accepted Apple parent, await datagrams returned and usableDatagramFrameSize completed with 0. The peer's local serialization does not prove that Apple parsed its offer. No application DATAGRAM or media payload was sent. Questions Does ready guarantee that the peer DATAGRAM transport parameter has been processed? Does completing await parent.datagrams provide a stronger guarantee? If a zero usable capacity is transient, what supported event or API should be awaited rather than arbitrary sleeps/retries? What is the supported start/ready/datagrams ordering and parent lifetime for outgoing versus accepted connections? Is opening a reliable stream first a prerequisite? Is there a minimal certificate-TLS DATAGRAM example? Which public diagnostic can distinguish an absent/zero peer advertisement from usable-size calculation, interoperability, or lifecycle issues? Is there a known limitation in this exact OS/SDK, a fixed version, or an authentication-preserving workaround? The source and evidence are attached to FB25125957. They contain no private keys, passwords, pairing credentials, user footage, app bundles, or full qlog. I am asking about basic DATAGRAM availability, not claiming any Wi-Fi or video performance result.
Replies
0
Boosts
0
Views
110
Activity
4w
SOCKS5 proxies (from PAC or ProxyConfiguration) are never applied to QUIC, and NWConnection silently connects directly
On macOS 27.0.1 (26A434), a SOCKS5 proxy is applied to TCP connections but never to QUIC. This happens whether the proxy comes from a PAC file in the system proxy settings or from an explicit ProxyConfiguration. The system SOCKS5 client only ever sends CONNECT; it never sends UDP ASSOCIATE (RFC 1928, CMD 0x03), so it has no way to carry UDP. URLSession handles this by staying on TCP through the proxy. A QUIC NWConnection instead connects directly to the origin, as if no proxy were configured. Setup. The system proxy settings use a PAC URL (ProxyAutoConfigURLString in scutil --proxy; in my test it was installed through NEProxySettings.proxyAutoConfigurationURL). For the test host, a public site that serves HTTP/3, the PAC returns SOCKS5 127.0.0.1:<port>. For the explicit cases I used a local SOCKS5 server that logs every command it receives. With the system PAC, default parameters, no explicit proxy: URLSession, assumesHTTP3Capable = true: goes through the proxy over TCP (transaction metrics: h2, isProxyConnection == true, remote address 127.0.0.1:<port>). HTTP/3 isn't used, which is consistent: the proxy can't carry it. NWConnection, TLS: currentPath.remoteEndpoint is 127.0.0.1:<port>. The PAC is honored. NWConnection, QUIC (ALPN h3): .ready in about 170 ms, and currentPath.remoteEndpoint is the origin's own address. The PAC is ignored. With an explicit proxy, set via NWParameters.PrivacyContext.proxyConfigurations: QUIC with a working SOCKS5 server: .ready, and the server receives nothing — no CONNECT, no UDP ASSOCIATE. QUIC with the proxy pointing at a port nothing listens on: still .ready, still connected to the origin's own address. TLS with that same dead proxy: stays in .waiting with ECONNREFUSED. The proxy is honored for TCP. At no point did the SOCKS5 server receive a UDP ASSOCIATE request. Cases 3–5 are the concerning part. An app that configures a proxy, or a user or administrator who installs a PAC, reasonably expects traffic to go through the proxy or fail. Instead, QUIC traffic goes straight to the origin, which then sees the device's own address, and nothing in the API signals that the proxy was skipped. Minimal snippet: import Network let host: NWEndpoint.Host = "YOUR_HTTP3_HOST" // any public host that serves HTTP/3 let parameters = NWParameters(quic: NWProtocolQUIC.Options(alpn: ["h3"])) // Remove these four lines to test with the system PAC instead. let privacy = NWParameters.PrivacyContext(description: "socks5-quic") privacy.proxyConfigurations = [ ProxyConfiguration(socksv5Proxy: .hostPort(host: "127.0.0.1", port: 1099)) // nothing listens on 1099 ] parameters.setPrivacyContext(privacy) let connection = NWConnection(host: host, port: 443, using: parameters) connection.stateUpdateHandler = { state in if case .ready = state { // Prints the origin's own address. With NWParameters.tls instead of QUIC, // the same proxy configuration leaves the connection in .waiting (ECONNREFUSED). print(connection.currentPath?.remoteEndpoint as Any) } } connection.start(queue: .main) I filed this as FB24760235 on 09/13/2026 and haven't had a response, so I'd like to ask here: Is it intended that a QUIC NWConnection ignores both the system PAC and proxyConfigurations? If so, how can an app find out that a connection went direct? And shouldn't a connection that can't honor the configured proxy fail rather than bypass it? Is UDP ASSOCIATE support planned for the system SOCKS5 client, so that QUIC and other UDP traffic can follow a SOCKS5 proxy the way TCP does? Thanks!
Replies
3
Boosts
0
Views
833
Activity
4w
Keeping a Local Wi-Fi TCP Transfer Alive in the Background Using Bluetooth Notifications — Is This Viable?
Requirement Description The app operates as a central device. It connects to a Bluetooth peripheral via Core Bluetooth. Once connected, the peripheral enables a Wi-Fi hotspot. The app joins this hotspot and transfers data over a TCP connection. The app needs to remain active in the background until this TCP data transfer is complete.  Question Regarding the Proposed Solution One proposed approach is to have the peripheral send periodic BLE notifications (reporting transfer progress) to the app, using each notification to briefly wake the app and extend its background execution time. Would this method successfully keep the TCP connection alive in the background until the transfer finishes? Does it comply with App Store review guidelines?  Request for Alternative Solutions If this approach is not viable, could you advise on any supported mechanisms or recommended architectures that would allow a local Wi-Fi TCP data transfer to complete reliably after the app moves to the background?
Replies
1
Boosts
0
Views
252
Activity
4w
Can't the input loop of a NWProtocolFramerImplementation be like...
Recently, I've been asking here about creating a NWProtocolFramerImplementation that splits across line breaks. Examples and questions usually involve some glob in a "while true" loop. From reading around, couldn't that function be implemented as: func handleInput(framer: NWProtocolFramer.Instance) -> Int { // Pull out objects until an incomplete object is discovered. var domainData: Data? while framer.parseInput( minimumIncompleteLength: 1, maximumLength: .max, parse: { buffer, isComplete in guard let buffer else { return 0 } // Why is `buffer` an Optional? // Other checks and computations // Mutate domainData with the result of this iteration. // Return how many bytes from the buffer are an irrevocable part of domainData. } ) { defer { domainData = nil } guard let domainData else { break } let domainMessage = //... let framerMessage = NWProtocolFramer.Message(myMessage: domainMessage) // The return value is whether or not the delivery was immediate. _ = framer.deliverInputNoCopy(length: domainData.count, message: framerMessage, isComplete: true) } return 0 } A clear separation of concerns, and makes figuring out what's going on easier.
Replies
1
Boosts
0
Views
371
Activity
Oct ’26
Unexplained behavioural changes in BSD sockets on macos 26.6.x and 27
We have started seeing some unexplained behavioural differences in the BSD socket APIs on macos 26.6.x and macos 27. On a different front, there also seems to be some changes in the ptrace area for PT_DETACH. Historically, the release notes of macos don't include any mention of such changes. And unfortunately, prior experience of filing feedback assistant issues too hasn't been very motivating due to lack of any response on those tickets. These forums have been very helpful in trying to understand some of these changes, and I plan to raise separate topics for the issues shortly. In the past, the other useful option I have used is reading up the kernel sources published at https://opensource.apple.com/releases/. But there hasn't been any updates for macos 26.6 or macos 27. It will be very useful if macos 26.6 and 27 releases are published there. That will help expedite investigating some of these failures. BSD socket APIs in the recent releases of macos have seen several issues (feedback assistant issues have been filed). The implications of these failures is that we (in OpenJDK) have had to disable several tests on recent versions of macos which has reduced the test coverage and reliability of these very primitive networking APIs on this platform.
Replies
5
Boosts
0
Views
420
Activity
Oct ’26
WCSession.sendMessage is crashing when a reply or error handler is attached, why?
The following code should send a message from the watch to the iPhone. Unfortunately, it is crashing. I have no clue why. if WCSession.isSupported() { let session = WCSession.default if ((session.activationState == .activated) && session.isReachable) { session.sendMessage(["SimpleMessages":["start"]], replyHandler:{reply in _ = 0 }, errorHandler:nil) } } If the reply handler is set to nil, the code does not crash. Anyway, in both cases the message is correctly sent from the watch to the phone. The code itself is run on the main thread (verified). I am running watchOS 26.6 and iOS 27. Here is the crash : Stack trace
Replies
3
Boosts
0
Views
340
Activity
Oct ’26
Dual-stack UDP socket bound to port 0 can get a port already in use on 127.0.0.1 (FB25058707)
I filed FB25058707 and wanted to make sure it reaches the right people, because it causes silent datagram loss that's hard to trace. On macOS, when a dual-stack UDP socket (AF_INET6 with IPV6_V6ONLY=0) binds [::]:0, the kernel sometimes gives it a port that an AF_INET socket already has bound to 127.0.0.1. Datagrams sent to 127.0.0.1 on that port then go to the AF_INET socket, so the dual-stack socket never receives them. An explicit bind of the same socket to that port fails with EADDRINUSE; only port-0 assignment hands it out. This program binds 1000 AF_INET sockets to 127.0.0.1:0, then binds dual-stack sockets to [::]:0 and checks where a datagram to 127.0.0.1:port lands whenever the port is already held. It's loopback only and runs in a few seconds: /* * A dual-stack UDP socket (AF_INET6, IPV6_V6ONLY=0) bound to [::]:0 can be * assigned a port already bound by an AF_INET socket on 127.0.0.1. Datagrams * to 127.0.0.1:port then reach the AF_INET socket, not the dual-stack one. * Loopback only. Build: cc -O2 -o dualstack_port0 dualstack_port0.c */ #include <arpa/inet.h> #include <errno.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/time.h> #include <unistd.h> #define HELD 1000 #define TRIALS 2000 static int held[65536]; static void die(const char *what) { perror(what); exit(1); } static int port_of(int s) { struct sockaddr_storage ss; socklen_t len = sizeof(ss); if (getsockname(s, (struct sockaddr *)&ss, &len) != 0) die("getsockname"); if (ss.ss_family == AF_INET) return ntohs(((struct sockaddr_in *)&ss)->sin_port); return ntohs(((struct sockaddr_in6 *)&ss)->sin6_port); } static int bind_v4(in_addr_t addr) { int s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) die("socket AF_INET"); struct sockaddr_in sin = { .sin_len = sizeof(sin), .sin_family = AF_INET, .sin_addr.s_addr = addr }; if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) != 0) die("bind AF_INET"); return s; } static int bind_dual(void) { int s = socket(AF_INET6, SOCK_DGRAM, 0), off = 0; if (s < 0) die("socket AF_INET6"); if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)) != 0) die("IPV6_V6ONLY"); struct sockaddr_in6 sin6 = { .sin6_len = sizeof(sin6), .sin6_family = AF_INET6, .sin6_addr = in6addr_any }; if (bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) != 0) die("bind AF_INET6"); return s; } /* Returns 1 if s receives token within 100ms, skipping other datagrams. */ static int got(int s, const char *token) { struct timeval tv = { .tv_sec = 0, .tv_usec = 100000 }; if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) die("SO_RCVTIMEO"); char buf[64]; for (;;) { ssize_t n = recv(s, buf, sizeof(buf) - 1, 0); if (n < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) return 0; die("recv"); } buf[n] = 0; if (strcmp(buf, token) == 0) return 1; } } int main(void) { struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) != 0) die("getrlimit"); rl.rlim_cur = rl.rlim_max < 4096 ? rl.rlim_max : 4096; if (setrlimit(RLIMIT_NOFILE, &rl) != 0) die("setrlimit"); memset(held, -1, sizeof(held)); for (int i = 0; i < HELD;) { int s = bind_v4(htonl(INADDR_LOOPBACK)), p = port_of(s); if (held[p] >= 0) { close(s); continue; } held[p] = s; i++; } int sender = bind_v4(htonl(INADDR_LOOPBACK)); for (int dual = 1; dual >= 0; dual--) { int collisions = 0, to_held = 0, to_wild = 0; for (int i = 0; i < TRIALS; i++) { int w = dual ? bind_dual() : bind_v4(htonl(INADDR_ANY)), p = port_of(w); if (held[p] >= 0) { collisions++; char token[32]; snprintf(token, sizeof(token), "%d-%d", dual, i); struct sockaddr_in to = { .sin_len = sizeof(to), .sin_family = AF_INET, .sin_port = htons(p), .sin_addr.s_addr = htonl(INADDR_LOOPBACK) }; if (sendto(sender, token, strlen(token), 0, (struct sockaddr *)&to, sizeof(to)) < 0) die("sendto"); to_held += got(held[p], token); to_wild += got(w, token); } close(w); } printf("%s: %d/%d wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket %d times, the wildcard socket %d times\n", dual ? "AF_INET6 V6ONLY=0 [::]:0" : "AF_INET 0.0.0.0:0 ", collisions, TRIALS, to_held, to_wild); } return 0; } On macOS 27.0 (26A428): AF_INET6 V6ONLY=0 [::]:0: 122/2000 wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket 122 times, the wildcard socket 0 times AF_INET 0.0.0.0:0 : 0/2000 wildcard binds got a port held by a 127.0.0.1 socket; the probe reached that socket 0 times, the wildcard socket 0 times macOS 15.8.1 x86_64 gives the same pattern, and a Go version of the test reproduces on 15.7.9 and 26.6.2 as well. FreeBSD 15.1 gives 0/2000 with a dual-stack socket. From the public XNU source (xnu-12377.121.6), in6_pcbsetport checks candidate ports with in6_pcblookup_local, which skips PCBs without INP_IPV6, while in6_pcbbind does an IPv4 PCB lookup for dual-stack wildcard binds. That would explain why an explicit bind is refused but port 0 isn't. This is the cause of the long-standing Go issue golang/go#67226, since Go's net.ListenUDP("udp", 0.0.0.0:0) creates exactly this socket, and of intermittent failures in QUIC client tests. Using an AF_INET socket for IPv4-only traffic avoids it, but there's no workaround for a socket that needs both families on one port.
Replies
2
Boosts
0
Views
342
Activity
Oct ’26
macos 27 - EDOM error from setsockopt() for SO_LINGER socket option for values greater than 32767
On macos 27, there appears to be a change in the setsockopt() implementation for the SO_LINGER option. It looks like the implementation now imposes a different maximum limit on the value that is accepted for linger. Consider the trivial attached C program. Rename it from main.c.txt to main.c. Compiling it (using clang main.c) and running it (using ./a.out), on older versions of macos (like 26.x), it returns: ----------------------- MacOS version: 26.7.1 Kernel version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000 ----------------------- SUCCESS - set SO_LINGER to value 10 SUCCESS - set SO_LINGER to value 42 SUCCESS - set SO_LINGER to value 1024 SUCCESS - set SO_LINGER to value 32767 SUCCESS - set SO_LINGER to value 32768 SUCCESS - set SO_LINGER to value 65535 SUCCESS - set SO_LINGER to value 65536 SUCCESS - set SO_LINGER to value 65578 However, on macos 27, this now fails with EDOM error ("Numerical argument out of domain") for values greater than 32767: ----------------------- MacOS version: 27.0.1 Kernel version: Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:16 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8112 ----------------------- SUCCESS - set SO_LINGER to value 10 SUCCESS - set SO_LINGER to value 42 SUCCESS - set SO_LINGER to value 1024 SUCCESS - set SO_LINGER to value 32767 FAILURE - failed to set SO_LINGER to value 32768, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65535, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65536, reason: Numerical argument out of domain FAILURE - failed to set SO_LINGER to value 65578, reason: Numerical argument out of domain I'm guessing this is an intentional change, but I wanted to confirm nonetheless. Should the documentation of SO_LINGER and SO_LINGER_SEC socket options, in man setsockopt, mention the acceptable value range for them? main.c.txt
Replies
2
Boosts
0
Views
318
Activity
Oct ’26
macos 27 - unexpected/new errno from BSD socket connect() when pending connections exceed backlog
Please consider the trivial C program attached to this thread. The code creates a socket() and listen()s for connections, but (intentionally) doesn't accept() the connections. The listen() is done using a small backlog (of 1). This test then does several connect() attempts and expects that the connect() attempts will accumulate in the pending queue and once the queue exceeds the backlog limit, then as specified in man listen: The backlog parameter defines the maximum length for the queue of pending connections. If a connection request arrives with the queue full, the client may receive an error with an indication of ECONNREFUSED. then the connect() attempt will receive a ECONNREFUSED. However, in macos 27, such a connect() attempt leads to ECONNRESET (Connection reset by peer) instead of ECONNREFUSED. Is this expected? Experiments show that prior versions of macos were returning a ETIMEDOUT for such connect() attempts. If this new error is expected from connect() when the backlog limit has exceeded, should it be specified in the man listen documentation? Rename the attached main.c.txt to main.c. Compiling the attached program on macos 27, using clang main.c and then running ./a.out results in: ----------------------- MacOS version: 27.0.1 Kernel version: Darwin Kernel Version 27.0.0: Tue Aug 11 21:02:16 PDT 2026; root:xnu-13432.1.9~1/RELEASE_ARM64_T8112 ----------------------- started server at at 127.0.0.1:52753 with a backlog of 1 connect() attempt 1 - connected connect() attempt 2 - connected connect() attempt 3 - connected connect() attempt 4 - connected connect() attempt 5 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 6 - connected connect() attempt 7 - connected connect() attempt 8 - connected connect() attempt 9 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 10 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 connect() attempt 11 - failed to connect() - Connection reset by peer <-- FAILURE: Unexpected error code, expected either ETIMEDOUT or ECONNREFUSED but got 54 On a related note, it's unclear why several of the connect() attempts succeeded instead of just 1 of them succeeding. On prior versions of macos, the output of the same program is: ----------------------- MacOS version: 26.7.1 Kernel version: Darwin Kernel Version 25.6.0: Tue Aug 18 17:49:13 PDT 2026; root:xnu-12377.161.15.700.19~2/RELEASE_ARM64_T6000 ----------------------- started server at at 127.0.0.1:52451 with a backlog of 1 connect() attempt 1 - connected connect() attempt 2 - failed to connect() - Operation timed out connect() attempt 3 - failed to connect() - Operation timed out connect() attempt 4 - failed to connect() - Operation timed out connect() attempt 5 - failed to connect() - Operation timed out connect() attempt 6 - failed to connect() - Operation timed out connect() attempt 7 - failed to connect() - Operation timed out connect() attempt 8 - failed to connect() - Operation timed out connect() attempt 9 - failed to connect() - Operation timed out connect() attempt 10 - failed to connect() - Operation timed out connect() attempt 11 - failed to connect() - Operation timed out and this output is much more understandable and deterministic. main.c.txt
Replies
2
Boosts
0
Views
335
Activity
Oct ’26
TCP connection in with Wi-Fi aware framework never reaches ".ready" state
While developing our wifi-aware implementation we ran into a specific issue where TCP connections seem to never reach a "ready" state (ready to transfer data). It stays in “”preparing” state trying to connect for forever. We tried to recreate a new TCP connection every time after the connection stays in "preparing" for longer than 10 seconds. This helps to "recover" eventually, but it only happens after 1.5 - 2 minutes. Creating a completely new NetworkBrowser and NetworkListener doesn’t speed up this process. The issue occurs when the browser and listener are setting up the NAN/TCP connection, at that time if the user opens the DevicePairingView it seems that it disrupts or interferes with the connection, entering an invalid state. From what we can see it takes around 2 minutes for it to recover, presumably this is when NAN drops the connection (timeout) and creates a new one.

 STEPS TO REPRODUCE Reproduction steps:

 Open the app on 2 wifi-aware devices.
 Device 1 presses “Pair with device”. Device 2 navigates to “Receive” and presses the “”Pair with sender”.
 Complete the pairing process.

 Device 1 (Send) presses the start button.
 Device 2 (receive) presses start button, Directly after the button press, device 1 presses the “”Pair with sender” button
 Observe TCP connection never fully establishes (1.5 - 2 mins) PLATFORM AND VERSION iOS Development environment: Xcode 26.3, macOS 26.4.1 Run-time configuration: iOS 26.5 test project with a recording showing the issue: https://github.com/DeveloperNiels/WAIssue
Replies
7
Boosts
0
Views
790
Activity
Oct ’26
Out-of-band data returned by recv() and read() on socket bound to non-loopback address even when SO_OOBINLINE is disabled
I've been investigating an issue with the SO_OOBINLINE socket option. When that option is disabled, the expectation is that out-of-band data that is sent on the socket will not be available through the use of read() or recv() calls on that socket. What we have been noticing is that when the socket is bound to a non-loopback address (and the communication is happening over that non-loopback address), then even when SO_OOBINLINE is disabled for the socket, the read()/recv() calls both return the out-of-band data. The issue however isn't reproducible with loopback address, and read()/recv() both correctly exclude the out-of-band data. This issue is only noticed on macos. I have been able to reproduce on macos M1, following version, but the original report which prompted me to look into this was reported on macos x64. My M1 OS version is: sw_vers ProductName: macOS ProductVersion: 14.3.1 BuildVersion: 23D60 Attached is a reproducer (main.c.txt - rename it to main.c after downloading) that I have been able to develop which reproduces this issue on macos. When you compile and run that: ./a.out it binds to a non-loopback address by default and you should see the failure log, resembling: ... ERROR: expected: 1234512345 but received: 12345U12345 To run the same reproducer against loopback address, run it as: ./a.out loopback and that should succeed (i.e. no out-of-band data) with logs resembling: ... SUCCESS: completed successfully, expected: 1234512345, received: 1234512345 Is this a bug in the OS? I would have reported this directly through feedback assistant, but my past few open issues (since more than a year) have not even seen an acknowledgement or a reply, so I decided to check here first. main.c.txt
Replies
8
Boosts
0
Views
1.3k
Activity
Oct ’26
NEURLFilterManager.localizedDescription is ignored by System Settings -> Network -> Filters
macOS 26.6, 26.7, 27.0 and 27.2 beta 1/2. Reproduced with Apple's SimpleURLFilter sample ("Filtering traffic by URL", WWDC25 session 234), built and run as a macOS app. The sample never sets localizedDescription, so I added one line to ConfigurationModel.save(configuration:) before saveToPreferences(): sharedFilterManager.localizedDescription = "Sentinel Filter Name" The property holds the value in memory: after loadFromPreferences(), the logged LocalizedStringResource still has key: "Sentinel Filter Name". But the effective configuration the system starts the session with has no localizedDescription — the session is named after the app: name = SimpleURLFilter applicationName = SimpleURLFilter application = com.example.apple-samplecode.SimpleURLFilterTC3Q7MAJXF (the rest of the nesessionmanager dump is the urlFilter dictionary, and it has no localizedDescription key). System Settings > Network > Filters shows the filter as URLFilter, not "Sentinel Filter Name". The stored configuration (/Library/Preferences/com.apple.networkextension.plist) has no localizedDescription key either, and injecting one by hand does not survive a nesessionmanager restart. Re-saving, removing and re-creating the configuration, and rebooting the Mac do not change the displayed name. Expected: the docs describe localizedDescription as "A string containing a description of the URL filter", and WWDC25 session 234's code sample ("Configure and manage URL Filter") sets it this way (manager.localizedDescription = "Alice's URL Filter"). For comparison, a NETransparentProxyManager configuration on the same Mac persists localizedDescription as the configuration's Name in the same plist, while the URL filter configuration has no such field. Filed as FB24987420.
Replies
1
Boosts
0
Views
313
Activity
Sep ’26