Greetings Dev Forums,
I'm working on an iOS application written in Swift that includes UDP communications. I am using the IBM BlueSocket library. The code in my application sends out a UDP message on the broadcast address of the Wifi and (if connected) Ethernet network. This is used to allow various instances of the app to discover each other. The code has been in place and working for several months.
Two or three weeks ago I purchased a new 11" iPad Pro. When I connected it to my test network it was not discovered by the other systems running my application. The log for the app is filled with messages like this:
15:31:52.502 - unable to send sendUDPBroadcast: Error code: -9980(0x-26FC), Operation not permitted
The code that results in those messages looks like this:
private func sendUDPBroadcast(address: String, message: String) { guard let addr = Socket.createAddress(for: address, on: 64068) else { return } let data = encodeOutput(message: message) do { let socket = try Socket.create(family: .inet, type: .datagram, proto: .udp) try socket.udpBroadcast(enable: true) try socket.write(from: data, to: addr) socket.close() } catch let error { guard let socketError = error as? Socket.Error else { print("Unexpected error in sendUDPBroadcast") return } print("unable to send sendUDPBroadcast: \(socketError.description)") } }
I checked and this code is working fine on all of my other clients - all iPads running iOS 12.1 (16B92), which is the same version as is running on the new iPad Pro.
In attempting to figure out what is going on with the Pro, I noticed that the addr value created by the call on line 3 was incorrectly flagged as an ipv6 address. Digging in, the BlueSocket library uses the following code to convert a string address in dotted-quad format into an address object:
/// /// Creates an Address for a given host and port. /// /// - Parameters: /// - hostname: Hostname for this signature. /// - port: Port for this signature. /// /// - Returns: An Address instance, or nil if the hostname and port are not valid. /// public class func createAddress(for host: String, on port: Int32) -> Address? { var info: UnsafeMutablePointer? // Retrieve the info on our target... var status: Int32 = getaddrinfo(host, String(port), nil, &info) if status != 0 { return nil } // Defer cleanup of our target info... defer { if info != nil { freeaddrinfo(info) } } var address: Address if info!.pointee.ai_family == Int32(AF_INET) { var addr = sockaddr_in() memcpy(&addr, info!.pointee.ai_addr, Int(MemoryLayout<sockaddr_in>.size)) address = .ipv4(addr) } else if info!.pointee.ai_family == Int32(AF_INET6) { var addr = sockaddr_in6() memcpy(&addr, info!.pointee.ai_addr, Int(MemoryLayout<sockaddr_in6>.size)) address = .ipv6(addr) } else { return nil } return address }
For reasons unknown, the call to getaddrinfo() with the string value "192.168.10.255" and the port value of 64068 results in the pointee.ai_family being set to AF_INET6, but only on this one iPad. The call works as expected on all the other test clients.
I've filed a bug with the BlueSocket project on Github, but it looks more like this is something in the networking layer than in IBM's code.
Anyone have any ideas?
FWIW - I'm based in Cupertino and would be happy to let somebody from the core networking team take a look at this if it would help.