Post

Replies

Boosts

Views

Activity

Advanced UDP with Network.framework
I finally found a time to experiment with Network.framework and I find the experience very pleasant. The API looks well thought out and is a pleasure to work with. My app (on the App Store for around 13 years) uses UDP networking to create a mesh between multiple devices where each device acts as a server and client at the same time. It does that by creating one UDP socket on each device bound to a *:<port> and then uses that socket to sendmsg to other peers. That way all peers can communicate with each other using their well known <port>. This all works great and fine. To test the performance and verify the functionality I have multiple XCTestCase scenarios where I create multiple peers and simulate various communications and verify their correctness. Within the XCTestCase process that means creating multiple underlying sockets and then bind them to multiple local random <port>s. Works great. Now I'm trying to port this functionality to Network.framework. Let's assume two peers for now. Code simplified. Prepare NWParameter instances for both peers, plain UDP for now. // NOTE: params for peer 1 let p1 = NWParameters(dtls: nil, udp: .init()) p1.requiredLocalEndpoint = .hostPort(host: "0.0.0.0", port: 2222) p1.allowLocalEndpointReuse = true // NOTE: params for peer 2 let p2 = NWParameters(dtls: nil, udp: .init()) p2.requiredLocalEndpoint = .hostPort(host: "0.0.0.0", port: 3333) p2.allowLocalEndpointReuse = true Create NWListeners for each peer. // NOTE: listener for peer 1 - callbacks omitted for brevity let s1 = try NWListener(using: parameters) s1.start(queue: DispatchQueue.main) // NOTE: listener for peer 2 - callbacks omitted for brevity let s2 = try NWListener(using: parameters) s2.start(queue: DispatchQueue.main) The listeners start correctly and I can verify that I have two UDP ports open on my machine and bound to port 2222 and 3333. I can use netcat -u to send UDP packets to them and correctly see the appropriate NWConnection objects being created and all callbacks invoked. So far so good. Now in that XCTestCase, I want to exchange a packets between peer1 and peer2. So I will create appropriate NWConnection and send data. // NOTE: connection to port 3333 from port 2222 let c1 = NWConnection(host: "127.0.0.1", port: 3333, using: p1) c2.start(queue: DispatchQueue.main) // NOTE: wait for the c1 state .ready c2.send(content: ..., completion: ...) And now comes the problem. The connection transitions to .preparing state, with correct parameters, and then to .waiting state with Error 48. [L1 ready, local endpoint: <NULL>, parameters: udp, local: 0.0.0.0:2222, definite, attribution: developer, server, port: 3333, path satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, service: <NULL>] [L2 ready, local endpoint: <NULL>, parameters: udp, local: 0.0.0.0:3333, definite, attribution: developer, server, port: 2222, path satisfied (Path is satisfied), interface: en0[802.11], ipv4, dns, uses wifi, service: <NULL>] nw_socket_connect [C1:1] connectx(6 (guarded), [srcif=0, srcaddr=0.0.0.0:2222, dstaddr=127.0.0.1:3333], SAE_ASSOCID_ANY, 0, NULL, 0, NULL, SAE_CONNID_ANY) failed: [48: Address already in use] nw_socket_connect [C1:1] connectx failed (fd 6) [48: Address already in use] nw_socket_connect connectx failed [48: Address already in use] state: preparing connection: [C1 127.0.0.1:2222 udp, local: 0.0.0.0:2222, attribution: developer, path satisfied (Path is satisfied), interface: lo0] state: waiting(POSIXErrorCode(rawValue: 48): Address already in use) connection: [C1 127.0.0.1:3333 udp, local: 0.0.0.0:2222, attribution: developer, path satisfied (Path is satisfied), interface: lo0] I believe this happens because the connection c1 essentially tries to create under the hood a new socket or something instead of reusing the one prepared for s1. I can make the c1 work if I create the NWConnection without binding to the same localEndpoint as the listener s1. But in that case the packets sent via c1 use random outgoing port. What am I missing to make this scenario work in Network.framework ? P.S. I was able to make it work using the following trick: bind the s1 NWListener local endpoint to ::2222 (IPv6) connect the c1 NWConnection to 127.0.0.1:3333 (IPv4) That way packets on the wire are sent/received correctly. I would believe that this is a bug in the Network.framework. I can open a DTS if more information is needed.
8
0
1.3k
Mar ’24
os_signpost not working on macOS device, works on iOS device
I have an iOS app that uses os_signpost API for instrumentation. When I profile it from Xcode on real iOS device, it works as expected. When I profile its macCatalyst variant (using the identical code) on the same Mac where Xcode is running, the os_signpost Instrument does not show anything, not even the Apple provided signposts that are otherwise visible on the iOS. How do I make it work?
5
0
1.3k
Mar ’24
NWConnection vs. nw_connection_t
I have ported my code from BSD sockets over to Network.framework, and while blocking issues remain (https://forums.developer.apple.com/forums/thread/747815) and while I can not yet properly instrument my code because os_signpost does not seem to work on XCTestCases profiled directly from Xcode (https://forums.developer.apple.com/forums/thread/748059) I do already have some initial observations. Perf test case of sending full (~1280 bytes) UDP datagrams back and forth over lo0 indicates that BSD sockets code can achieve 20% higher throughput (in packets per second) than Network.framework based code. That is not what I expected, and I will continue investigating but for the moment I have one question I did not find answer to. Will using C based Network.framework API instead of Swift based one bring performance gains? For example, nw_connection_t provides an interface to send non-contiguous segments of dispatch_data_t without copying, whereas NWConnection only deals with contiguous Data. Thanks for any insights.
2
0
634
Mar ’24
_CMTimebaseCreateWithMasterClock - ITMS-90338: Non-public API usage
Hi guys, I am getting the following error when trying to upload for macOS. The same code works fine for iOS. Dear Developer, We identified one or more issues with a recent delivery for your app. Please correct the following issues, then upload again. ITMS-90338: Non-public API usage - The app references non-public symbols in Contents/MacOS/***: _CMTimebaseCreateWithMasterClock. If method names in your source code match the private Apple APIs listed above, altering your method names will help prevent this app from being flagged in future submissions. In addition, note that one or more of the above APIs may be located in a static library that was included with your app. If so, they must be removed. For further information, visit the Technical Support Information at http://developer.apple.com/support/technical/ Best regards, The App Store Team Just FYI: I am not using CMTimebaseCreateWithMasterClock at all, but rather the preferred variant CMTimebaseCreateWithSourceClock. Neither of these are private API. Both are available. Looks like a bug in AppStore Connect? Filed FB9752311 if anybody at Apple is listening.
6
2
2.3k
Nov ’21
Custom AppEntity struct Parameter for AppIntent not working for App Store (appintentsmetadataprocessor bug)
Hello, I have successfully implemented AppIntents with custom parameters based on AppEntity as described in the WWDC video https://developer.apple.com/videos/play/wwdc2022/10032/. When running the app in the iOS Simulator, everything works great. When trying to archive manually for upload to TestFlight, or using Xcode Cloud the Extract App Intents Metadata archive step fails with the following error: appintentsmetadataprocessor[89770:29069096] Starting appintentsmetadataprocessor export appintentsmetadataprocessor[89770:29069096] Writing Metadata.appintents appintentsmetadataprocessor[89770:29069096] Metadata root: /Users/***/Library/Developer/Xcode/DerivedData/YYY/Build/Intermediates.noindex/ArchiveIntermediates/ZZZ/InstallationBuildProductsLocation/Applications/GGG.app/Metadata.appintents appintentsmetadataprocessor[89770:29069096] Writing ExtractedAppShortcutsMetadata.stringsdata file appintentsmetadataprocessor[89770:29069096] Writing ExtractedParameterSummaryMetadata.stringsdata file appintentsmetadataprocessor[89770:29069096] Warning: error: could not determine type for property: MyApp.MyIntent.parameter from binary Command ExtractAppIntentsMetadata emitted errors but did not return a nonzero exit code to indicate failure The resulting build can actually be uploaded to TestFlight, but the AppIntent does not work properly when used in Shortcuts. The custom typed parameter is shown as in the Shortcuts app as "generic" parameter and can not be properly populated, queried.
3
0
1.6k
Oct ’22
Swift 5.x custom Hashable/Equatable conformance on iOS 9
Hi guys, I am using custom implementation of Hashable protocol on my classes/enums using fairly primitive logic using Hasher.combine() on several String/Int based fields. Everything seems to be working really well on Linux, macOS, and iOS 10, 11, 12, 13, 14. On iOS 9 with the app compiled using Xcode 11.5 and Xcode 11.6 however I started receiving lot of random crashes where my custom object/enum used as a key in a Set or Dictionary is not there, swift crashes with Set or Dictionary containing duplicate keys, etc. It all points toward some kind of issue where for my custom objects used as keys during the app run Hasher.combine() is called multiple times for the same object with different random seed, thus generating different hashValue for the same object during the same app run. To indicate, here is the precondition on line 5 that fails: let key = SomeKey() let dict = [:] precondition(dict[key] == nil, "SomeKey must not be present") dict[key] = SomeObject() precondition(dict[key] != nil, "SomeKey must be present") I'm trying to figure out whether this rings a bell for somebody since it is 100% iOS 9 specific. thanks for any pointers, Martin
6
0
2.5k
Aug ’20
False Alert of non-public symbols from Security.framework
Just pushed a build to AppStore Connect and received the reply below about referenced non-public symbols. Since all of these are as far as I know public and from Security.framework, the message appears to be a false alarm. Correct?ITMS-90338: Non-public API usage - The app references non-public symbols in Contents/Frameworks/Mixpanel.framework/Versions/A/Mixpanel: _SSLSetEnabledCiphers, _SecCertificateCopyData, _SecCertificateCreateWithData, _SecPolicyCreateBasicX509, _SecPolicyCreateSSL, _SecRandomCopyBytes, _SecTrustCopyPublicKey, _SecTrustCreateWithCertificates, _SecTrustEvaluate, _SecTrustGetCertificateAtIndex, _SecTrustGetCertificateCount, _SecTrustSetAnchorCertificates, _SecTrustSetPolicies, _kSecRandomDefault,The app references non-public symbols in Contents/MacOS/Baby Monitor: _SecCertificateCreateWithData, _SecItemAdd, _SecItemCopyMatching, _SecItemDelete, _SecItemUpdate, _SecKeyGeneratePair, _SecPolicyCreateSSL, _SecTrustCreateWithCertificates, _SecTrustEvaluate, _kSecAttrAccessible, _kSecAttrAccessibleAfterFirstUnlock, _kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, _kSecAttrAccount, _kSecAttrApplicationTag, _kSecAttrCreationDate, _kSecAttrIsPermanent, _kSecAttrKeySizeInBits, _kSecAttrKeyType, _kSecAttrKeyTypeRSA, _kSecAttrLabel, _kSecAttrModificationDate, _kSecAttrService, _kSecClass, _kSecClassKey, _kSecMatchLimit, _kSecMatchLimitAll, _kSecMatchLimitOne, _kSecReturnAttributes, _kSecReturnData, _kSecReturnRef, _kSecValueData, _kSecValueRef. If method names in your source code match the private Apple APIs listed above, altering your method names will help prevent this app from being flagged in future submissions. In addition, note that one or more of the above APIs may be located in a static library that was included with your app. If so, they must be removed. For further information, visit the Technical Support Information at http://developer.apple.com/support/technical/Best regards,The App Store Team
7
0
3.6k
Feb ’20