Skip to content

Instantly share code, notes, and snippets.

@MatiMax
Last active November 14, 2016 05:48

Revisions

  1. MatiMax revised this gist Sep 30, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion DNSResolve.swift
    Original file line number Diff line number Diff line change
    @@ -54,7 +54,7 @@ class DNSResolve {
    //: Create a boolean pointer `DarwinBoolean` for use with the function `CFHostGetNames`.
    var resolved: DarwinBoolean = DarwinBoolean(false)
    //: Now get the results of the info resolution.
    let cfNames: CFArrayRef = CFHostGetNames(host!, &resolved)!.takeRetainedValue()
    let cfNames: CFArrayRef = CFHostGetNames(host!, &resolved)!.takeUnretainedValue()
    print("namesResolved: Names resolved: \(resolved) with error \(error.error)")
    //: We can use cascading casts from `[AnyObject]` to a force-unwrapped `[String]`. Thank you, Swift.
    self.names = cfNames as [AnyObject] as! [String]
  2. MatiMax revised this gist Sep 28, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion DNSResolve.swift
    Original file line number Diff line number Diff line change
    @@ -25,7 +25,7 @@ class DNSResolve {
    }
    //: Create the `CFHostRef` with the `CFData` object and store the retained value for later use.
    let hostref = CFHostCreateWithAddress(kCFAllocatorDefault, data)
    self.host = hostref.takeRetainedValue()
    self.host = hostref.takeUnretainedValue()
    //: For the callback to work we have to create a client context.
    var ctx = CFHostClientContext(
    version: 0,
  3. MatiMax revised this gist Sep 28, 2016. No changes.
  4. MatiMax created this gist Sep 7, 2015.
    80 changes: 80 additions & 0 deletions DNSResolve.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,80 @@
    //: # How to retrieve a host name and associated aliases from an IP address using Core Fondation's `CFHost`
    import Cocoa
    import XCPlayground
    //: In order to get the callback working we use a simple class to implement the showcase.
    class DNSResolve {
    //: The IP address may be a Swift `String` thanks to the toll-free bridging to C strings.
    let ip: String = "17.172.224.47"
    //: We use an optional `CFHost` variable because CFHost neither comes with an initializer nor is conforming to the Nullable protocol.
    var host: CFHost?
    //: We use this array of `String`s to store the resolved host names.
    var names: [String] = []

    func resolve() {
    //: Let's set up the `sockaddr_in` C structure using the initializer.
    var sin = sockaddr_in(
    sin_len: UInt8(sizeof(sockaddr_in)),
    sin_family: sa_family_t(AF_INET),
    sin_port: in_port_t(0),
    sin_addr: in_addr(s_addr: inet_addr(ip)),
    sin_zero: (0,0,0,0,0,0,0,0)
    )
    //: Now convert the structure into a `CFData` object.
    let data = withUnsafePointer(&sin) { ptr in
    CFDataCreate(kCFAllocatorDefault, UnsafePointer(ptr), sizeof(sockaddr_in))
    }
    //: Create the `CFHostRef` with the `CFData` object and store the retained value for later use.
    let hostref = CFHostCreateWithAddress(kCFAllocatorDefault, data)
    self.host = hostref.takeRetainedValue()
    //: For the callback to work we have to create a client context.
    var ctx = CFHostClientContext(
    version: 0,
    info: unsafeBitCast(self, UnsafeMutablePointer<Void>.self),
    retain: nil,
    release: nil,
    copyDescription: unsafeBitCast(0, CFAllocatorCopyDescriptionCallBack.self)
    )
    //: We can now set up the client for the callback using the `CFHostClientCallBack` signature for the closure.
    CFHostSetClient(host!, { (host, infoType, error, info) in
    let obj = unsafeBitCast(info, DNSResolve.self)
    print("Resolving …")
    obj.namesResolved(withError: error.memory)
    }, &ctx)
    //: Now schedule the runloop for the host.
    CFHostScheduleWithRunLoop(host!, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
    //: Create a `CFStreamError` object for use with the info resolution using `CFHostStartInfoResolution`.
    var error = CFStreamError()
    //: Start the info resolution.
    let started: Bool = CFHostStartInfoResolution(host!, .Names, &error)
    print("Name resolution started: \(started)")
    }
    //: This function is attachted as `CFHostClientCallBack` in `CFHostSetClient` which should get called during the info resolution.
    func namesResolved(withError error: CFStreamError) {
    print("namesResolved: Resolving …")
    //: Create a boolean pointer `DarwinBoolean` for use with the function `CFHostGetNames`.
    var resolved: DarwinBoolean = DarwinBoolean(false)
    //: Now get the results of the info resolution.
    let cfNames: CFArrayRef = CFHostGetNames(host!, &resolved)!.takeRetainedValue()
    print("namesResolved: Names resolved: \(resolved) with error \(error.error)")
    //: We can use cascading casts from `[AnyObject]` to a force-unwrapped `[String]`. Thank you, Swift.
    self.names = cfNames as [AnyObject] as! [String]

    //: **Oh dear—we see only one host name here and no aliases. Stuck again … :-(**
    print("CFArray reports \(CFArrayGetCount(cfNames)) elements, [String] reports \(self.names.count) elements.")
    self.listNames()
    //: After the info resolution clean up either way.
    CFHostSetClient(host!, nil, nil);
    CFHostCancelInfoResolution(host!, .Names)
    CFHostUnscheduleFromRunLoop(host!, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)

    }

    func listNames() {
    print(self.names)
    }
    }
    //: OK, let's create an instance of our `DNSResolve` class and run the `resolve()` method.
    let dnsRes = DNSResolve()
    dnsRes.resolve()
    //: In order to see the callback working we have to set Playground's execution to take on forever.
    XCPSetExecutionShouldContinueIndefinitely()