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);
}
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.