Cannot bind to local UDP socket - address already in use

I have some code that used to work but is failing to bind to a local UDP port saying it is already in use. lsof does not show that the port is being used.

Below is my receive function that fails. bindResult is "-1" when calling bind, and the error printed out contains "Address already in use (48)". I am trying to bind to 127.0.0.1:6000.

This has been working for a very long time, but I've not used it for one or two months, so not sure if a macOS upgrade or something else broke it.

func receive(handleRxData: @escaping (UdpSocket, IpAddress, ArraySlice<UInt8>) -> Void,
               withError error: (_ msg: String) -> Void) {
    
    self.handleRxData = handleRxData
    
    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 udpSocket = Unmanaged<UdpSocket>.fromOpaque(info!).takeUnretainedValue()
                              udpSocket.receiveCallback()
    },
                            UnsafeMutablePointer<CFSocketContext>(&cfSocketContext))
    let sock = CFSocketGetNative(cfSock)
    
    // Create ipv4 addr struct:
    var sin = sockaddr_in()
    if (local.type == .ipv4) {
      sin.sin_len = __uint8_t(MemoryLayout.size(ofValue: sin))
      sin.sin_family = sa_family_t(AF_INET)
      sin.sin_addr.s_addr = local.ipv4.bigEndian
      sin.sin_port = local.port.bigEndian
    }
    
    let bindResult = withUnsafeMutablePointer(to: &sin) {
      $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
        bind(sock, UnsafeMutablePointer<sockaddr>($0), socklen_t(MemoryLayout<sockaddr_in>.size))
      }
    }

    if bindResult < 0 {
      error("Could not bind to socket \(sin) ( \(String(cString: strerror(errno)!)) (\(errno)).")
      return
    }
    
    // Change socket to non-blocking:
    let flags = fcntl(sock, F_GETFL);
    let fcntlResult = fcntl(sock, F_SETFL, flags | O_NONBLOCK);

    if (fcntlResult < 0) {
      print("Could not change socket to non-blocking ( \(String(cString: strerror(errno)!)) (\(errno)).")
    }

    // Add to run loop:
    let rls = CFSocketCreateRunLoopSource(nil, cfSock, 0);
    if (rls == nil) {
      error("Could not get run loop source.")
      return
    }

    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, CFRunLoopMode.commonModes)// CFRunLoopMode.defaultMode);
  }
Answered by oreman in 705080022

Thanks.

I am not sure what to do with this tread since the problem was not a code problem but a port being reserved by XQuartz.

Thanks for the advice on netstat. I will use it in the future but it seems it would not have picked up the problem either since the port was not open, it was just being reserved. I cannot confirm since I've uninstalled XQuartz to resolve my issue (did not have the option to move other port).

I am marking this as the answer purely to close the thread, and in case anyone ever gets to it. Let me know if you disagree.

I am trying to bind to 127.0.0.1:6000.

On what platform?

Also, how are you using UDP? For broadcast? Or multicast? Or for point to point communications?

Share and Enjoy

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

Should I have used a tool other than lsof?

My go-to tool for this is netstat. For TCP listeners I use this:

% netstat -an | grep LISTEN

For UDP, just change the argument to grep.

Share and Enjoy

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

Accepted Answer

Thanks.

I am not sure what to do with this tread since the problem was not a code problem but a port being reserved by XQuartz.

Thanks for the advice on netstat. I will use it in the future but it seems it would not have picked up the problem either since the port was not open, it was just being reserved. I cannot confirm since I've uninstalled XQuartz to resolve my issue (did not have the option to move other port).

I am marking this as the answer purely to close the thread, and in case anyone ever gets to it. Let me know if you disagree.

Cannot bind to local UDP socket - address already in use
 
 
Q