All documentation and examples say that if a socket's CFSocketCallBack
callout is given a .dataCallback
as its second parameter (callbackType
), that implies that the fourth one (data
) can be cast to a CFData
object containing all the data pre-read from the socket.
However, when I try to do this, it fails:
private func myCallout(socket: CFSocket?,
callBackType: CFSocketCallBackType,
address: CFData?,
callBackTypeMetaData: UnsafeRawPointer?,
info: UnsafeMutableRawPointer?) -> Void {
// Behavior inferred from Developer
// https://developer.apple.com/documentation/corefoundation/cfsocketcallback
guard
let info = info,
let socket = socket
else {
return assertionFailure("Socket may have gone out of scope before response")
}
// <REDACTED>
if callBackType == .dataCallBack {
guard let data = callBackTypeMetaData?.load(as: CFData.self) else {
return assertionFailure("Data Callback's metadata was not a CFData object")
}
foo(data as Data) // Crashes here
}
// <REDACTED>
}
The crash I get is this:
Thread 1: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0).
In the debugger, when I type this:
(lldb) po callBackTypeMetaData!.load(as: CFData.self)
it just prints a pointer address (rather high, also; only two significant 0
s). However, when I type this:
(lldb) po callBackTypeMetaData!.load(as: CFData.self) as Data
It prints this:
error: Execution was interrupted, reason: EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0).
The process has been returned to the state before expression evaluation.
So it seems what I got is not really a CFData
, but it's close enough to seem similar to it on the surface, until something actually tries to read it as such.
So what's going on here, where is my data, and how do I fix this?
data = callBackTypeMetaData!.load(as: CFData.self)
reads a CFData
pointer from the memory location that callBackTypeMetaData!
points to. What you want is to "reinterpret"
the raw pointer as a CFData
(or NSData
) pointer:
if callBackType == .dataCallBack {
if let rawPointer = callBackTypeMetaData {
let data = Unmanaged<NSData>.fromOpaque(rawPointer).takeUnretainedValue() as Data
// ...
}
}