swiftsocketssockaddr-in

Getting an IP address and port number from a sockaddr_in struct in Swift?


After much trial and error, and without any success, it seems I might need a bit of help on this one:

How can I get IP address and port number from a sockaddr_in in the latest version of Swift?

I saw some related questions but can't seem to find a proper example anywhere. Also, I don't really seem to grasp how C type structs and pointers need to be handled in Swift, which doesn't really help.

Can anyone please supply me with an example or link to useful resources?

Many thanks in advance!


Solution

  • If you need the IP address and port as numbers then you can access the corresponding fields of a sockaddr_in directly, but remember to convert the values from network byte (big endian) to host byte order:

    let saddr: sockAddr = ...
    
    let port = in_port_t(bigEndian: sockAddr.sin_port)
    let addr = in_addr_t(bigEndian: sockAddr.sin_addr.s_addr)
    

    getnameinfo() can be used to extract the IP address as a string (in dotted-decimal notation), and optionally the port as well. Casting a struct sockaddr_in pointer to a struct sockaddr pointer is called "rebinding" in Swift, and done with withMemoryRebound():

    var sockAddr: sockaddr_in = ...
    
    var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
    var service = [CChar](repeating: 0, count: Int(NI_MAXSERV))
    
    withUnsafePointer(to: &sockAddr) {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 0) {
            _ = getnameinfo($0, socklen_t($0.pointee.sa_len),
                            &hostname, socklen_t(hostname.count),
                            &service, socklen_t(service.count),
                            NI_NUMERICHOST | NI_NUMERICSERV)
        }
    }
    print("addr:", hostname)
    print("port:", service)
    

    This works for both IPv4 and IPv6 socket address structures (sockaddr_in and sockaddr_in6).

    For more information about "unsafe pointer conversions", see SE-0107 UnsafeRawPointer API and UnsafeRawPointer Migration. The latter page contains example code how to handle socket addresses in Swift 3.