Swift 3 how to resolve NetService IP address?

Just try Bonjour in fast 3

Here is my code, I can get a delegate

func netServiceDidResolveAddress(_ sender: NetService) { print("netServiceDidResolveAddress service name \(sender.name) of type \(sender.type)," + "port \(sender.port), addresses \(sender.addresses)") } 

And here is my result

netServiceDidResolveAddress Webber service name Mac mini type _myapp._tcp., port 5678, addresses Optional ([<<1002162e c0a80205 00000000 00000000>, <1c1e162e 00000000 fe800000 00000000 00bce7ad 24b4b7e8 08000000>])

c0a80205 is the IP address I'm looking for => 192.168.2.5

And the address is [Data], Apple says

Service Addresses These are NSArray instances of NSData, each of which contains one structural sockaddr, suitable for use with connection (2). If the addresses are not allowed for the service or the service is not yet resolved, an empty NSArray is returned.

I'm still confused why data cannot use .btyes? As Apple says: "This is an NSArray of NSData instances" But I can't use it like NSData p>

And how to resolve the address as a readable IP string?

I have tried this before, but am not getting the result as I rule out ...

 let thedata = NSData(bytes: sender.addresses, length: (sender.addresses?.count)!) var storage = sockaddr_storage() thedata.getBytes(&storage, length: sizeof(sockaddr_storage)) if Int32(storage.ss_family) == AF_INET { let addr4 = withUnsafePointer(&storage) {UnsafePointer<sockaddr_in>($0).pointee } print(inet_ntoa(addr4.sin_addr)); } 

Any suggestion will help, thanks

+5
source share
4 answers

This is how I did it in Swift 3.

 func netServiceDidResolveAddress(_ sender: NetService) { var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST)) guard let data = sender.addresses?.first else { return } data.withUnsafeBytes { (pointer:UnsafePointer<sockaddr>) -> Void in guard getnameinfo(pointer, socklen_t(data.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else { return } } let ipAddress = String(cString:hostname) print(ipAddress) } 
+13
source

OK ... this is not a reasonable answer, at least I can get a readable IP

Just use this function to get the IP string

 let bonjourDevices = [NetService]() let bonjourDevice = bonjourDevices[0] let host = self.getIPV4StringfromAddress(address:bonjourDevice.addresses!) func getIPV4StringfromAddress(address: [Data] , port : Int ) -> String{ let data = address.first! as NSData; var ip1 = UInt8(0) data.getBytes(&ip1, range: NSMakeRange(4, 1)) var ip2 = UInt8(0) data.getBytes(&ip2, range: NSMakeRange(5, 1)) var ip3 = UInt8(0) data.getBytes(&ip3, range: NSMakeRange(6, 1)) var ip4 = UInt8(0) data.getBytes(&ip4, range: NSMakeRange(7, 1)) let ipStr = String(format: "%d.%d.%d.%d:%d",ip1,ip2,ip3,ip4,port); return ipStr; } 
+3
source

I can't get it to work with Data , but using NSData , I would use this:

 extension NSData { func castToCPointer<T>() -> T { let mem = UnsafeMutablePointer<T>.allocate(capacity: MemoryLayout<T.Type>.size) self.getBytes(mem, length: MemoryLayout<T.Type>.size) return mem.move() } } 

So we have netServiceDidResolveAddress :

 func netServiceDidResolveAddress(_ sender: NetService) { if let addresses = sender.addresses, addresses.count > 0 { for address in addresses { let data = address as NSData let inetAddress: sockaddr_in = data.castToCPointer() if inetAddress.sin_family == __uint8_t(AF_INET) { if let ip = String(cString: inet_ntoa(inetAddress.sin_addr), encoding: .ascii) { // IPv4 print(ip) } } else if inetAddress.sin_family == __uint8_t(AF_INET6) { let inetAddress6: sockaddr_in6 = data.castToCPointer() let ipStringBuffer = UnsafeMutablePointer<Int8>.allocate(capacity: Int(INET6_ADDRSTRLEN)) var addr = inetAddress6.sin6_addr if let ipString = inet_ntop(Int32(inetAddress6.sin6_family), &addr, ipStringBuffer, __uint32_t(INET6_ADDRSTRLEN)) { if let ip = String(cString: ipString, encoding: .ascii) { // IPv6 print(ip) } } ipStringBuffer.deallocate(capacity: Int(INET6_ADDRSTRLEN)) } } } } 

I have the following result (saving ips in an array before displaying):

 ["172.16.10.120", "172.16.8.251", "::", "::82c9:d9a5:2eed:1c87"] 

Code inspired by https://gist.github.com/agrippa1994/d8c66a2ded74fb2dd801 written in Swift 2.3 and adapted for Swift 3.0

+3
source

Phil Coles' edited answer to the free Swift 5.0 solution:

 func netServiceDidResolveAddress(_ sender: NetService) { var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST)) guard let data = sender.addresses?.first else { return } data.withUnsafeBytes { ptr in guard let sockaddr_ptr = ptr.baseAddress?.assumingMemoryBound(to: sockaddr.self) else { // handle error return } var sockaddr = sockaddr_ptr.pointee guard getnameinfo(sockaddr_ptr, socklen_t(sockaddr.sa_len), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else { return } } let ipAddress = String(cString:hostname) print(ipAddress) } 
0
source

All Articles