6

I'm trying to create a Bonjour service in my iOS application, but can't get it to publish. Only the netServiceWillPublish delegate method is ever called and the service isn't showing up using dns-sd.

Here's my code:

var service: NetService? = nil

func start() {
    createSockets()

    service = NetService(domain: "test", type: "_test._tcp.", name: "Test", port: Int32(port))
    service?.delegate = self
    service?.startMonitoring()
    service?.publish()
    service?.setTXTRecord(NetService.data(fromTXTRecord: [
        "model": "AppleTV3,2,1".data(using: .utf8)!,
        "srcvers": "160.10".data(using: .utf8)!,
        "features": "0x100009FF".data(using: .utf8)!,
        "deviceId": "b8:53:ac:43:f3:15".data(using: .utf8)!,
        "pw": "0".data(using: .utf8)!,
        "rmodel": "MacBookPro10,2".data(using: .utf8)!
        ]))

}

private func createSockets() {
    ipv4Socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAutomaticallyReenableAcceptCallBack, socketCallback, nil)

    var sin = sockaddr_in()

    memset(&sin, 0, MemoryLayout<sockaddr_in>.size)
    sin.sin_len = __uint8_t(MemoryLayout<sockaddr_in>.size)
    sin.sin_family = sa_family_t(AF_INET); /* Address family */
    sin.sin_port = in_port_t(port) /* Or a specific port */
    sin.sin_addr.s_addr = INADDR_ANY

    let sincfd = withUnsafePointer(to: &sin) {
        $0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout<sockaddr_in>.size) {
            return CFDataCreate(kCFAllocatorDefault, $0, MemoryLayout<sockaddr_in>.size)
        }
    }

    CFSocketSetAddress(ipv4Socket, sincfd)

    let socketsource = CFSocketCreateRunLoopSource(
        kCFAllocatorDefault,
        ipv4Socket,
        0);

    CFRunLoopAddSource(
        CFRunLoopGetCurrent(),
        socketsource,
        CFRunLoopMode.defaultMode);
}

I'm new to this type of networking in iOS, what am I doing wrong here?

Jake
  • 13,097
  • 9
  • 44
  • 73
  • 2
    Maybe you can try keeping a reference of your NetService? Maybe it got deallocated. – koropok Dec 12 '16 at 08:09
  • 1
    The NetService has a reference at the class level in the code that isn't working. I just changed it in the post to ofuscate what we're doing since it's proprietary. I'll update the code snippet so reflect that. Thanks. – Jake Dec 12 '16 at 15:01
  • I'm using a obj-c third party for bonjour connections and it's working fine. Not sure if it might help. https://github.com/jdiehl/async-network – koropok Dec 14 '16 at 01:53

1 Answers1

5

Using service?.publish(options: NetService.Options.listenForConnections) and not creating the socket myself fixed the issue.

It ends up let publishing this way will automatically create a TCP listener for both IPv4 and IPv6 for the NetService.

Apple Documentation:

/* When passed to -publishWithOptions:, in addition to publishing the service, a
 * TCP listener is started for both IPv4 and IPv6 on the port specified by the
 * NSNetService. If the listening port can't be opened, an error is reported using
 * -netService:didNotPublish:. Specify a port number of zero to use a random port.
 * When -netServiceDidPublish: is called, -port will return the actual listening
 * port number. Since the listener only supports TCP, the publish will fail with
 * NSNetServicesBadArgumentError if the NSNetService type does not end with "_tcp".
 * New incoming connections will be delivered in the form of NSStreams via the
 * -netService:didAcceptConnectionWithInputStream:outputStream: delegate method.
 */
 @available(iOS 7.0, *)
 public static var listenForConnections: NetService.Options { get }
Jake
  • 13,097
  • 9
  • 44
  • 73