Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift 3 how to resolve NetService IP?

Just trying Bonjour in swift 3

Here is my code , I can receive the 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 service name Webber's Mac mini of type _myapp._tcp.,port 5678, addresses Optional([<1002162e c0a80205 00000000 00000000>, <1c1e162e 00000000 fe800000 00000000 00bce7ad 24b4b7e8 08000000>])

c0a80205 is the IP I looking for => 192.168.2.5

And the address is [Data] , Apple says

The addresses of the service. This is an NSArray of NSData instances, each of which contains a single struct sockaddr suitable for use with connect(2). In the event that no addresses are resolved for the service or the service has not yet been resolved, an empty NSArray is returned.

I still confuse why Data can't use .btyes ? As Apple says "This is an NSArray of NSData instances" But I can't use it like NSData

And how to resolve the address as readable IP string ?

I try this before , but do not get the result as I except ...

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 be help , Thanks

like image 447
Webber Lai Avatar asked Jul 05 '16 07:07

Webber Lai


3 Answers

Edited Phil Coles answer for Swift 5.0 warning free 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)
    }
like image 107
Nick Hingston Avatar answered Nov 17 '22 16:11

Nick Hingston


Here's 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)
}

Swift 5

var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
data.withUnsafeBytes { (pointer: UnsafeRawBufferPointer) -> Void in
        let sockaddrPtr = pointer.bindMemory(to: sockaddr.self)
        guard let unsafePtr = sockaddrPtr.baseAddress else { return }
        guard getnameinfo(unsafePtr, socklen_t(data.count), &hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 else {
            return
        }
    }
let ipAddress = String(cString:hostname)
print(ipAddress)
like image 28
Phil Cole Avatar answered Nov 17 '22 15:11

Phil Cole


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

Just use this func to get 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;
    }
like image 4
Webber Lai Avatar answered Nov 17 '22 15:11

Webber Lai