Hi,
I wanted to try using the new NWBrowser available in iOS 13 to replace my old Bonjour browsing code(NetServiceBrowser), problem is I'm unabe to get all IPv6 Addresses(except link local address) of the service I'm looking for.
In my environment, when I checked with ifconfig command, there are three IPv6 addresses.
fe80::c092:a0ff:fe51:3c8
fd1c:efcd:7e66:0:c092:a0ff:fe51:3c8
fd1c:efcd:7e66:0:68d:6b27:81e2:7511
Using NWBrowser and NWConnection, I ended up getting #1 address but I couldn't get #2, #3 addresses.
Here is my code.
let bonjour = NWBrowser.Descriptor.bonjourWithTXTRecord(type: serviceType, domain: searchDomain)
let params = NWParameters.init()
self.nwBrowser = NWBrowser(for: bonjour, using: params)
self.nwBrowser?.browseResultsChangedHandler = { [weak self] results, changes in
guard let self = self else { return }
for change in changes {
if case .added(let result) = change {
let connection = NWConnection(to: result.endpoint, using: .udp)
connection.stateUpdateHandler = { [weak self] state in
switch state {
case .ready:
if let remoteEndpoint= connection.currentPath?.remoteEndpoint,
case .hostPort(let host, let port) = innerEndpoint {
// here I can get #1 address from host
// but, I couldn't get #2, #3 addresses
}
}
}
connection.start(queue: .main)
}
}
}
self.nwBrowser?.start(queue: .main)
Using NetServiceBrowser and netServiceDidResolveAddress(), I can get All IP addresses(#1, #2, #3)
Here is my code.
let netServiceBrowser = NetServiceBrowser()
netServiceBrowser.delegate = self
netServiceBrowser.searchForServices(ofType: serviceType, inDomain: searchDomain)
func netServiceBrowser(_ browser: NetServiceBrowser, didFind service: NetService, moreComing: Bool) {
service.delegate = self
service.resolve(withTimeout: resolutionTimeoutSeconds)
}
func netServiceDidResolveAddress(_ service: NetService) {
// service.addresses is [Data], I can get all addresses I want.
}
I wonder if getting only Link Local Address through NWConnection is the intended behavior.
Or is there a way to get all address using NWBrowser and NWConnection?
Hi,
We are running into problem as there is no API to set SNI on TLS Parameters of NWConnection. In CFStream API this can be done easily by setting "kCFStreamSSLPeerName". When this is set, in Client Hello this parameter is used as SNI.
Is there any way/alternative to set SNI on NWConnection?
Thanks and regards.
phillips-hue-cert.txt
Accidentally close: https://developer.apple.com/forums/thread/707263
I want to connect to a Phillips Hue Api (something like that: https://<ip_address>/clip/v2/ressource/device).
The issue is that on the software Postman (to test), Phillips Hue says to disable "SSL Certificate Verification".
When I try to call with URLRequest in my app the same url, using URLSessions, I get this error:
Domain=kCFErrorDomainCFNetwork Code=-1202 NSLocalizedDescription=The certificate for this server is invalid. You might be connecting to a server that is pretending to be “<ip_address_of_Hue_bridge>” which could put your confidential information at risk.
I read those articles:
https://developer.apple.com/forums/thread/67493
https://developer.apple.com/forums/thread/67493
I don't want to disable all HTTPS server trust evaluation, it’s super insecure. I want to customise the trust evaluation to let the connection through to be as secure as possible.
But I don't really know how to do this with URLSession or another thing if needed.
Phillips Hue is giving what looks like a pem certificate (see in attachements).
I don't know how to implement this in my URLSession request.
Thank you for your help
Post not yet marked as solved
General:
Networking Overview document — Despite the fact that this is in the archive, this is still really useful.
TLS for App Developers DevForums post
Choosing a Network Debugging Tool documentation
Low-Level Networking on watchOS DevForums post
Foundation networking:
DevForums tags: Foundation, CFNetwork
URL Loading System documentation — NSURLSession, or URLSession in Swift, is the recommended API for HTTP[S] on Apple platforms.
Network framework:
DevForums tag: Network
Network framework documentation — Network framework is the recommended API for TCP, UDP, and QUIC on Apple platforms.
Network Extension (including Wi-Fi on iOS):
See Network Extension Resources
Wi-Fi on macOS:
DevForums tag: Core WLAN
Core WLAN framework documentation
Secure networking:
DevForums tags: Security
Apple Platform Security support document
Preventing Insecure Network Connections documentation — This is all about App Transport Security.
Available trusted root certificates for Apple operating systems support article
Requirements for trusted certificates in iOS 13 and macOS 10.15 support article
About upcoming limits on trusted certificates support article
Technote 2232 HTTPS Server Trust Evaluation
Technote 2326 Creating Certificates for TLS Testing
QA1948 HTTPS and Test Servers
Miscellaneous:
More network-related DevForums tags: 5G, QUIC, Bonjour
On FTP DevForums post
Using the Multicast Networking Additional Capability DevForums post
Investigating Network Latency Problems DevForums post
Local Network Privacy FAQ DevForums post
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Post not yet marked as solved
We've been hitting a problem with sending frames over UDP that over 50k bytes despite writing a NWProtocolFramer based on the code in this thread
The error is coming from the stack with:
nw_protocol_ipv6_frame_output_finalizer [C1.1.1:3] Not enough bytes to fragment 55616
I was under the impression that NWProtocolFramer is the way to fragment the frame for the specific use case but I'm confused at this 50k limit that we seem to be hitting.
Any ideas?
Thanks!
Post not yet marked as solved
According to Section 2.6.2 of RFC 3927, 169.254.255.255 is the broadcast address for the Link-Local prefix.
This does not seem to work in macOS; what I see in WireShark are ARP messages "Who has 169.254.255.255?". Which obviously doesn't work.
I'm on macOS 12.4 / Xcode 13.4. Same code works fine in Linux (Ubuntu 20.04).
Anybody have any ideas?
Post not yet marked as solved
I want my app to react when it sees that a certain port is being listened to, and likewise when it stops being listened to.
Specifically, another app will start a gdb server (at 127.0.0.1 on 9003) and I want mine to detect that. I don't really even care that it's a gdb server, just when the port is in use or not. I can do it right now using polling using a variation of this but that's not great for CPU wakes.
I'm wondering if I can use an NWConnection (with no timeout) to monitor for these events (port in use, port no longer in use). If so, any pointers would be very gratefully received :) Even if just to say I'm barking up the wrong tree!
I have a data that should be transmitted using UDP with NWConnection.
Size of data is larger than maximum datagram size provided by UDP, so I need to split data to send it.
I tried to find solution with searching about UDP data split, but couldn't find appropriate solution to my problem.
Which keyword should I search about to start from?
Post not yet marked as solved
I have a wireless stateless-switch within my private network (LAN) which transmits HTTP posts to a configured URL (e.g. an always-on MacMini) about the switch's state. Upon receipt of a post, my MacOS app will then take appropriate action. No response to the sender is required. The frequency of posts will be minimal ( a few per day), but require immediate attention when received. The LAN is protected from external misuse by a secure gateway.
I'd appreciate any suggestions for a lightweight solution (i.e. not a full-blown web-server), either as an overview of methods or sample source (e.g. on GitHub).
Regards, Michaela
Post not yet marked as solved
Hi Quinn,
I am developing an app that connects to a local device via Wifi or Ethernet.
I am using tcp over Network.framework for the communication.
My network connector is configured as such for iOS:
let tcp_params = NWParameters.tcp
tcp_params.preferNoProxies = true
tcp_params.acceptLocalOnly = true
tcp_params.prohibitedInterfaceTypes = [.cellular]
So what happens is that everything is fine as long as both the iPhone and the device are connected to an AccesPoint. But there is another option where the device acts as AccessPoint and you can join that network straight. The device, since it has no connection to the internet, does not offer a default route - so that any client devices can still use cellular network to access the internet.
What happens though is that I cannot get a connection to that device in case cellular data is on.
The state handler shows the following error message:
lC3 MINI-20001._cap._tcp.local. tcp, no cellular, prefer no proxy, attribution: developer, path unsatisfied (Denied over cellular interface), interface: pdp_ip0[lte], ipv4, ipv6, expensive]
As soon as I disable cellular data, everything works fine.
Is there any way to get around this? There must be cause Safari can actually connect to the device even with cellular data on.
I have played with various ways to configure the NWParameters, but no luck.
Maybe you got the magic?
Cheers,
Michael
Post not yet marked as solved
Hi, I'm trying to send audio data via UDP.
I am using Network.framework with networking, so to use send method in NWConnection sending data must be Data type or confirm to DataProtocol.
To satisfy those conditions, I have implemented a method to convert from AVAudioPCMBuffer type to Data type.
func makeDataFromPCMBuffer(buffer: AVAudioPCMBuffer, time: AVAudioTime) -> Data {
let audioBuffer = buffer.audioBufferList.pointee.mBuffers
let data: Data!
data = .init(bytes: audioBuffer.mData!, count: Int(audioBuffer.mDataByteSize))
return data
}
Implementation above is referenced from this post
The problem is that the size of converted data is too big to fit in UDP datagram and error below occurs when I try to send data.
I have found out that initial size of buffer is too big to fit in maximumDatagramSize.
Below is code regarding to buffer.
let tapNode: AVAudioNode = mixerNode
let format = tapNode.outputFormat(forBus: 0)
tapNode.installTap(onBus: 0, bufferSize: 4096, format: format, block: { (buffer, time) in
// size of buffer: AVAudioPCMBuffer is 19200 already.
let bufferData = self.makeDataFromPCMBuffer(buffer: buffer, time: time)
sharedConnection?.sendRecordedBuffer(buffer: bufferData)
})
I need to reduce size of AVAudioPCMBuffer to fit in UDP datagram, But I can't find right way to do it.
What would be best way to make data fit in datagram?
I thought of dividing data in half, but this is UDP so I'm not sure how to handle those datas when one data has lost.
So I'm trying to make AVAudioPCMBuffer fit in datagram.
Any help would be very appreciated!
I have written a WebSocket client using Apple Network Framework in C++. I use a sec_protocol_options_set_verify_block to customize the server SSL certificate trust evaluation. This includes logic to append a revocation policy to the trust object like this:
Code snippet
If CRL checks are set to HARD i.e kSecRevocationRequirePositiveResponse bit is set. Then the evaluation always fails with Trust evaluation result - kSecTrustResultRecoverableTrustFailure and the revocation result is FALSE. The error code is -67635 corresponding to errSecIncompleteCertRevocationCheck. But weirdly the error message printed is '"leafCert","CACert" certificates do not meet pinning requirements'. This does not match up to the error code seen.
These are placeholder names for my self signed server
certificates. The root is added to the Keychain and marked trusted in the keychain. If I put CRL checks to SOFT, no CRL check takes place but the trust evaluation succeeds.
Putting the error message anomaly aside. If I run WireShark traces on the server machine where the CRL distribution point is also located, I do not see any HTTP requests coming in for the CRL list. I have checked the CRL DP URL in a browser and it is reachable.
Is there something wrong with the policy creation process? Why is it not at least trying to access the CRL DP?
Post not yet marked as solved
A number of years ago I wrote code that uses dns_open(...) and dns_lookup(...) to call a remote name server for dns resolution.
Testing in Monterey, Big Sur and Catalina I get a NULL reply from dns_lookup. The code produces an expected result with Mojave and High Sierra.
If I pass NULL as the argument to dns_open() then resolution is successful, but that is not using the desired name server.
I have submitted feedback request FB10027085 with a small project that demonstrates the failure.
I have a downchannel half-connection to the Amazon Alexa cloud
https://developer.amazon.com/en-US/docs/alexa/alexa-voice-service/manage-http2-connection.html#create
Now, if the APP enters the background, my connection will be broken. Even if I put it in the backgroundTask, I cannot maintain the connection through ping,
How do I maintain this HTTP persistent connection when the APP is in the background, plz。
Post marked as Apple Recommended
I want to create an app that only scans the nearby wifi network and checks whether the user's wifi network is present in the scanned list or not. NO connection requires. How to achieve it. I tried almost all the options. I am getting the current connected WIFI SSID and BSSID with help of CaptiveNetwork.
Post not yet marked as solved
Hello,
I'm working on an Apple Watch/ iPhone/PC/Mac OS sport applications with different types of connectivity and i'm a bit stuck with the bellow issue.
I'm trying to Resolve a Bonjour that is using NWBrowser on WatchOS 8.6 on Apple Watch SE with LTE and i encounter strange issues:
First i'm setup a NWBrowser :
NWBrowser(for: .bonjourWithTXTRecord(type: "_angry._tcp", domain: nil), using: parameters)
Then, using :
browser?.browseResultsChangedHandler = { [weak self] results, changes in
Everything works well until here
I'm gathering info form name and txt of the service found and ask the client if i want's a connection to service found .
Using NWConnection to connecting to the found enpoint:
NWConnection(to: endpoint, using: params)
Here starts the issue
In the stateUpdateHandler :
connection?.stateUpdateHandler = { state in
switch state {
case .ready:
if let innerEndpoint = connection?.currentPath?.remoteEndpoint,
case .hostPort(let host, let port) = innerEndpoint {
i'm checking the port and host where i'm getting the wrong informations, an IPV6 and a port that don't exists on the target server and a log in the console :
2022-05-22 15:54:33.146148+0300 WatchKit Extension[956:609596] [] nw_endpoint_proxy_copy_synthesized_url Endpoint type is not an address or host, cannot synthesize URL
2022-05-22 15:54:33.319537+0300
WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.319604+0300
WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.319621+0300
WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.319636+0300
WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.319651+0300 WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.501821+0300 WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.501875+0300 WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.501892+0300 WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.501908+0300 WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
2022-05-22 15:54:33.501923+0300 WatchKit Extension[956:609596] [] nw_endpoint_proxy_match_exception_to_endpoint Invalid proxy endpoint type 3 for matching
I tried this on an apple watch simulator and a couple of real iPhone devices and everything works well, i'm getting the good port and host and no console errors/warnings.
PS: All this are done during a running HKWorkoutSession to ensure that the app is kept active during different networking operations.
What i'm doing wrong since is working fine on iPhone and WatchOS Simulator?
Thanks ,
Angry Software
This thread
rvictl not working on big sur and … | Apple Developer Forums
was locked with very optimistic:
"There have been significant improvements to RVI in recent releases"
No idea how because I simply cannot get it working:
After enabling kernel extension in Recovery and Allow in Security (with two reboots), SIP back ON (but also tried off) I cannot get anything from rvictl
Xcode 13.4
Build version 13F17a
manager@localmagersMini ~ % which -a rvictl
/Library/Apple/usr/bin/rvictl
manager@localmagersMini ~ % /Library/Apple/usr/libexec/rpmuxd
rpmuxd_transaction_begin:109 Transactions moved from 0->1
rpmuxd_transaction_end:121 Transactions moved from 1->0, starting idle timer
rpmuxd_transaction_end_block_invoke_2:132 Idle timer fired, exiting.
manager@localmagersMini ~ % sudo launchctl list com.apple.rpmux
Could not find service "com.apple.rpmux" in domain for system
manager@localmagersMini ~ % sudo launchctl load -w /Library/Apple/System/Library/LaunchDaemons/com.apple.rpmuxd.plist
/Library/Apple/System/Library/LaunchDaemons/com.apple.rpmuxd.plist: service already loaded
Load failed: 37: Operation already in progress
manager@localmagersMini ~ % sudo kextload /Library/Apple/System/Library/Extensions/RemoteVirtualInterface.kext
Executing: /usr/bin/kmutil load -p /Library/Apple/System/Library/Extensions/RemoteVirtualInterface.kext
Error Domain=KMErrorDomain Code=71 "Kernel request failed: (libkern/kext) kext (kmod) start/stop routine failed (-603946985)" UserInfo={NSLocalizedDescription=Kernel request failed: (libkern/kext) kext (kmod) start/stop routine failed (-603946985)}
manager@localmagersMini ~ % rvictl -s 00008101-000979680a04001e
manager@localmagersMini ~ % ifconfig -l
lo0 gif0 stf0 XHC0 XHC1 anpi1 anpi0 XHC2 en0 en4 en5 en2 en3 en6 en7 ap1 en1 bridge0 awdl0 llw0 utun0 utun1 utun2
manager@localmagersMini ~ % rvictl -l
Could not get list of devices
Anybody has any ideas?
sebus
I am trying to send and receive an audio data(saved by .caf extension device) using Network.framework.
This is my plan.
convert file into Data type using below code:
guard let data = try? Data(contentsOf: recordedDocumentURL) else {
print("recorded file to data conversion failed in touchUpCallButton Method")
return
}
send Data type data using NWConnection.send, UDP.
receive Data type data using NWConnection.receiveMessage
convert received Data type data into AVAudioFile type data and play it using AVAudioEngine
Right now my problem is that size of data converted from audio file is too big to fit in maximumDatagramSize to send.
So in my understanding, I need to split Data type into many small bytes of data and send it one by one.
But in this case, I need to collect received data to make complete audio file again, so received device can play complete audio file.
And.. I'm stuck at this step.
I can't find right solution to divide Data type into small pieces to send by datagram using UDP.
What I have in my mind is to use 'subdata(in: Range<Data.Index>) -> Data' function and 'append(Data)' function to divide and sum up data.
Is this right approach to solve my problem?
Little advice would be very appreciated!
Hi, I'm trying to build a Walki-talkie app using Swift.
My Idea is...
record user's voice by AVAudioEngine in device1
convert recorded file into Data type data
send data from device1 to device2 using NWConnection.send
receive data using NWConnection.receiveMessage
play received data in device2
I am implementing this app using P2P option in Network.framework, so each device has both browser and listener.
And I have to make each device to keep receiving incoming data, and to send recorded voices.
At first I thought that if receiveMessage method was executed, it would wait for other device's send method to send data and receive it.
But while debugging, program didn't stopped at receiveMessage method, it just went through and executed next line.
I must be missing something, but I'm not sure what it is.
Below is send and receive part of code I tried.
func sendRecordedAudio(data: Data) {
guard let connection = connection else {
print("connection optional unwrap failed: sendRecordedAudio")
return
}
connection.send(content: data, completion: .contentProcessed({ (error) in
if let error = error {
print("Send error: \(error)")
}
}))
}
func receiveRecordedAudio() {
guard let connection = connection else {
print("connection optional unwrap failed: receiveRecordedAudio")
return
}
connection.receiveMessage{ (data, context, isComplete, error) in
if let error = error {
print("\(error) occurred in receiveRecordedAudio")
}
if let data = data {
self.delegate?.receivedAudio(data: data)
}
}
}
App is calling sendRecordAudio when recording audio is ended, and calling receiveRecordeAudio when user pressed receive button.
Any help would be greatly appreciated!
Post not yet marked as solved
Consider the following situation: user uploads a large file via a share extension (extension writes upload details into shared DB and initiates background transfer), then quickly realizes that's a wrong file, so he switches to containing app, opens up a list of uploads and hits "Cancel".
Question is, how containing app is supposed to reliably cancel such transfer, given that only one process can access same NSURLSession at the time, a session is not disconnected until all tasks are complete (or connected process is terminated) and extension may not be terminated yet?