CFSocketSetAddress returns success but prints failure in console

I am trying to get a UDP socket working in swift.


When I try to bind to the socket, by calling CFSocketSetAddress, then it returns success but prints out "CFSocketSetAddress listen failure: 102".


My callback, set with CFSocketCreate is never called when I send data.


Why would it return success but print failure in the debugger? Do I have an error in my code, shown below?


Thanks,


Pieter


  var socket: CFSocket? = nil
  init() {
    socket = CFSocketCreate(kCFAllocatorDefault,
                   PF_INET,
                   SOCK_DGRAM,
                   IPPROTO_UDP,
                   CFSocketCallBackType.readCallBack.rawValue,
                   { (socket: CFSocket?, callBackType: CFSocketCallBackType, address: CFData?, data: UnsafeRawPointer?, info: UnsafeMutableRawPointer?) -> Void in
                    print("callback test")
                   },
                   nil)
   
    if socket == nil {
      print("Could not create socket.")
      return
    }
   
    var sin = sockaddr_in()
    sin.sin_len = __uint8_t(MemoryLayout.size(ofValue: sin))
    sin.sin_family = sa_family_t(AF_INET)
    sin.sin_port = UInt16(6000).bigEndian
    sin.sin_addr.s_addr = INADDR_ANY.bigEndian
   
    let addressDataCF = NSData(bytes: &sin, length: MemoryLayout.size(ofValue: sin)) as CFData
    let socketErr = CFSocketSetAddress(socket, addressDataCF)
    switch socketErr {
    case .success:
      print("Success.")
    case .error:
      print("Error.")
    case .timeout:
      print("Timeout.")
    }
  }

Accepted Reply

I recommend against using

CFSocket
for… well… pretty much anything (-:

The problem with

CFSocket
is that it has a bunch of costs (most notably a cryptic API) without giving you any value in return (you still have to deal with all the fiddly low-level details of UDP). Historically it had one big benefit, namely run loop integration, but these days you can get most of that benefit by way of a dispatch event source. Critically, in modern Swift code, dispatch event sources are much easier to deal with than
CFSocket
callbacks.

If you do use

CFSocket
my recommendation is that you do all of the interesting work using BSD Sockets and then use
CFSocket
solely for run loop integration, that is, start with
CFSocketCreateWithNative
. This is what I did in the UDPEcho sample code.

With regards your specific question:

When I try to bind to the socket, by calling

CFSocketSetAddress
, then it returns success but prints out "CFSocketSetAddress listen failure: 102".

Because

CFSocket
runs the same code for TCP and UDP sockets, which means it tries to call
listen
even though that’s meaningless in a UDP socket. That
listen
call fals, which is why it prints an error, but that error is non-fatal, which is why it returns success.

This is a classic example of why, long ago, I decided that it’s best to use BSD Sockets for this and, if you use

CFSocket
at all, just use it for run loop integration.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Replies

I recommend against using

CFSocket
for… well… pretty much anything (-:

The problem with

CFSocket
is that it has a bunch of costs (most notably a cryptic API) without giving you any value in return (you still have to deal with all the fiddly low-level details of UDP). Historically it had one big benefit, namely run loop integration, but these days you can get most of that benefit by way of a dispatch event source. Critically, in modern Swift code, dispatch event sources are much easier to deal with than
CFSocket
callbacks.

If you do use

CFSocket
my recommendation is that you do all of the interesting work using BSD Sockets and then use
CFSocket
solely for run loop integration, that is, start with
CFSocketCreateWithNative
. This is what I did in the UDPEcho sample code.

With regards your specific question:

When I try to bind to the socket, by calling

CFSocketSetAddress
, then it returns success but prints out "CFSocketSetAddress listen failure: 102".

Because

CFSocket
runs the same code for TCP and UDP sockets, which means it tries to call
listen
even though that’s meaningless in a UDP socket. That
listen
call fals, which is why it prints an error, but that error is non-fatal, which is why it returns success.

This is a classic example of why, long ago, I decided that it’s best to use BSD Sockets for this and, if you use

CFSocket
at all, just use it for run loop integration.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

If you recomend against CFSocket, then is it not time for a new clean Socket abstraction lib?


Thanks, your reply helped me and I got a lot further. This is probably not the correct place to ask it, but I've been struggling a lot with the Swift scemantics in passing self through the CFSocketContext so that I can get back to my own class when the callback is called. I've asked a specific question about it here and although my answer was solved, my problem was not.


This is what I am doing:


Creating my socket. Note my use of pointerToSelf() to populate the info member.

    var cfSocketContext = CFSocketContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
    cfSocketContext.info = pointerToSelf()
  
    cfSock = CFSocketCreate(kCFAllocatorDefault,
                            PF_INET,
                            SOCK_DGRAM,
                            IPPROTO_UDP,
                            CFSocketCallBackType.readCallBack.rawValue,
                            { (socket: CFSocket?, callBackType: CFSocketCallBackType, address: CFData?, data: UnsafeRawPointer?, info: UnsafeMutableRawPointer?) -> Void in
                              let ptr = info!
                              let ptrTraceClient = ptr.bindMemory(to: TraceClient.self, capacity: 1)
                              ptrTraceClient.pointee.doSomething()
                            },
                            UnsafeMutablePointer<CFSocketContext>(&cfSocketContext))


pointerToSelf looks like this:

  static func fromPointer(_ ptr: UnsafeMutableRawPointer) -> TraceClient {
    let ptrTraceClient = ptr.bindMemory(to: TraceClient.self, capacity: 1)
    return ptrTraceClient.pointee
  }


When ptrTraceClient is dereferenced in the callback, then I get an exception.


How should I pass the reference to self so that I can get it back correctly in my callback?

Hi Quinn,


Thanks, got it going with your help. If anybody ever gets here in the futrure, then this is what I did:

    var cfSocketContext = CFSocketContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
    cfSocketContext.info = Unmanaged.passRetained(self).toOpaque()
   
    cfSock = CFSocketCreate(kCFAllocatorDefault,
                            PF_INET,
                            SOCK_DGRAM,
                            IPPROTO_UDP,
                            CFSocketCallBackType.readCallBack.rawValue,
                            { (socket: CFSocket?, callBackType: CFSocketCallBackType, address: CFData?, data: UnsafeRawPointer?, info: UnsafeMutableRawPointer?) -> Void in
                              let traceClient = Unmanaged<TraceClient>.fromOpaque(info!).takeRetainedValue()
                              traceClient.doSomething()
                            },
                            UnsafeMutablePointer<CFSocketContext>(&cfSocketContext))

got it going

Yay!

… then is it not time for a new clean Socket abstraction lib?

It’s hard to argue with that. Ideally such an API would be aligned with the ‘post Sockets’ work going on at the IETF but, right now, we have to work with the APIs that are currently shipping.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"