How to Resolve Hostnames of Devices on the Same Wi-Fi Network with NBNS Protocol

I am currently attempting to resolve the hostname of a device connected to the same Wi-Fi network as mine. However, I've been unable to find sufficient resources or documentation on utilising the NBNS (NetBIOS Name Service) protocol for this purpose. Can someone please provide guidance on how to achieve this?

Replies

I have tried with GCDAsyncUdpSocket ( https://github.com/robbiehanson/CocoaAsyncSocket ) haven't received any callbacks.

var ip: String = "192.168.0.19"

var port: UInt16 = 137

let broadcastData: Data = "Hi".data(using: .utf8)!

var udpSocket : GCDAsyncUdpSocket!

func broadCast(){

    udpSocket = GCDAsyncUdpSocket(delegate: self, delegateQueue: .main)  

    do {

        port = findFreePort()

        try udpSocket.bind(toPort: port)

        print("\nBind port \(port)")

        try udpSocket.enableReusePort(true)

        try udpSocket.enableBroadcast(true)

        print("Enable broadcast")

        try udpSocket.beginReceiving()

        print("Begin receiving")

        udpSocket.send(broadcastData, toHost: ip, port: port, withTimeout: -1, tag: 0)

        print("Send \(String(data: broadcastData, encoding: .utf8)!) to host \(ip) on port \(port)")

    } catch {

        print("udp broadcast error")

    }

}

func udpSocket(_ sock: GCDAsyncUdpSocket, didNotConnect error: Error?) {
        print("didNotConnect")
    }
    
    func udpSocketDidClose(_ sock: GCDAsyncUdpSocket, withError error: Error?) {
        print("udpSocketDidClose")
    }
    
    func udpSocket(_ sock: GCDAsyncUdpSocket, didConnectToAddress address: Data) {
        print("didConnectToAddress")
    }
    
    func udpSocket(_ sock: GCDAsyncUdpSocket, didSendDataWithTag tag: Int) {
        print("didSendDataWithTag")
    }
    
    func udpSocket(_ sock: GCDAsyncUdpSocket, didNotSendDataWithTag tag: Int, dueToError error: Error?) {
        print("didNotSendDataWithTag")
    }
    
    func udpSocket(_ sock: GCDAsyncUdpSocket, didReceive data: Data, fromAddress address: Data, withFilterContext filterContext: Any?) {
        print("didReceive data \(data)")
        print("fromAddress data \(address)")
        var host: NSString? = ""
        var port: UInt16 = 0
        GCDAsyncUdpSocket.getHost(&host, port: &port, fromAddress: address)
        print("host \(host ?? "---")")
        print("port \(port)")
        print("address \(address)")
    }
 func findFreePort() -> UInt16 {
        var port: UInt16 = 8000;

        let socketFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if socketFD == -1 {
          //print("Error creating socket: \(errno)")
          return port;
        }

        var hints = addrinfo(
          ai_flags: AI_PASSIVE,
          ai_family: AF_INET,
          ai_socktype: SOCK_STREAM,
          ai_protocol: 0,
          ai_addrlen: 0,
          ai_canonname: nil,
          ai_addr: nil,
          ai_next: nil
        );

        var addressInfo: UnsafeMutablePointer<addrinfo>? = nil;
        var result = getaddrinfo(nil, "0", &hints, &addressInfo);
        if result != 0 {
          //print("Error getting address info: \(errno)")
          close(socketFD);

          return port;
        }

        result = Darwin.bind(socketFD, addressInfo!.pointee.ai_addr, socklen_t(addressInfo!.pointee.ai_addrlen));
        if result == -1 {
          //print("Error binding socket to an address: \(errno)")
          close(socketFD);

          return port;
        }

        result = Darwin.listen(socketFD, 1);
        if result == -1 {
          //print("Error setting socket to listen: \(errno)")
          close(socketFD);

          return port;
        }

        var addr_in = sockaddr_in();
        addr_in.sin_len = UInt8(MemoryLayout.size(ofValue: addr_in));
        addr_in.sin_family = sa_family_t(AF_INET);

        var len = socklen_t(addr_in.sin_len);
        result = withUnsafeMutablePointer(to: &addr_in, {
          $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
            return Darwin.getsockname(socketFD, $0, &len);
          }
        });

        if result == 0 {
          port = addr_in.sin_port;
        }

        Darwin.shutdown(socketFD, SHUT_RDWR);
        close(socketFD);

        return port;
    }

NBNS is kinda horrible. Does your accessory support Bonjour [1]? It’s likely that it does, in which case this problem becomes much easier.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Bonjour is an Apple term for three industry-standard protocols:

Thanks @eskimo My application do support for bonjour , I got the special entitlement access for multicast usage.Can you please share the documentation or resources for how to achieve with bonjour.

If your accessory supports Bonjour then you don’t need the multicast entitlement. Our Bonjour APIs do their work out of process, so your app isn’t sending or receive multicasts directly.

To use Bonjour you’ll need some Info.plist properties:

  • NSLocalNetworkUsageDescription (docs)

  • NSBonjourServices (docs)

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"