The image view width is a multiply of 6 and should be able to represent all pixels as they are without any trick, so it doesn't seem like it should do that.
Post
Replies
Boosts
Views
Activity
@FrankSchlegel wow thank you, I added the ROI callback (simply returning the images full extent) and the top image doesn't look corrupted anymore. I'm so confused as to why the default behavior is any different when an ROI callback is not specified, wow. Still not the end of the story though, when drawing large with interpolation disabled (NSImageInterpolationNone and kCAFilterNearest), the top image is doing something odd, new video here -> http://tclementdev.com/coreimage_metal_test2.mov
@FrankSchlegel here's a screen recording, top view is drawing the image in drawRect(), bottom view is assigning the image to the layer contents. The bottom view display what I expect. http://tclementdev.com/coreimage_metal_test.mov
For anyone at Apple seeing this, I filed FB12608056 with sample code and screen recording.
I've done some further experiments: if I set the CGImage (obtained from the CIImage) directly onto the contents property of the layer of my view, then it works and display fine. But if I implement drawRect() and draw the CGImage into the CGContext using CGContextDrawImage() then it appears corrupted. How weird is that?
@eskimo here it is: FB12059413
Would there be a way to tell whether an instance of SecCertificateRef is trusted as part of the immutable store vs. the system/user keychain?
iOS and macOS. Trying to block real attacks/snooping, not the device owner inspecting traffic.
I'm having this problem too. Is there any solution?
Thank you Quinn. It is at least good to have confirmation and know where I can stand. Good to hear you plan to fix it soon as well, even though I have to work with it for now.
I have had other issues with custom framers as well (FB9405024, FB9430130). Hopefully the tech will eventually mature and I can use it again.
The framing protocol very much seems to be playing a role, this is what I think I have established with the help of Quinn. The code posted by Quinn works: the writer stops enqueuing quickly. I took Quinn's code and only added the protocol framer (that merely passes the data along) and now the writer enqueues into memory explosion.
Using a method like this to handle input is roughly the same as calling connection.receive(minimumIncompleteLength: 1, maximumLength: 1000), is there a reason you are not parsing out the length of your frame from the packet header?
Hi Matt, in my app I do parse the length from the packet header. This is a reduced sample code, the simplest possible that demonstrates the problem. I added a protocol framer that basically does nothing (just passing the data along), and it changed the behavior of the writer, which seems wrong to me.
About your code, you need to remove these three lines:
if error == nil {
startReceive(on: connection)
}
Because the whole point is to see what happens when the other side does not read (or rather does not read fast enough). If you remove these three lines, you will see that the sender keeps enqueuing indefinitely into memory explosion.
Sure. Thank you Quinn!
Ok Quinn. I made further testing and the problem seems related to me using a protocol framer. Give it a try and let me know what you think.
import Foundation
import Network
class MyProtocol: NWProtocolFramerImplementation {
// Create a global definition of your game protocol to add to connections.
static let definition = NWProtocolFramer.Definition(implementation: MyProtocol.self)
// Set a name for your protocol for use in debugging.
static var label: String { return "MyProtocol" }
// Set the default behavior for most framing protocol functions.
required init(framer: NWProtocolFramer.Instance) { }
func start(framer: NWProtocolFramer.Instance) -> NWProtocolFramer.StartResult {
return .ready
}
func wakeup(framer: NWProtocolFramer.Instance) { }
func stop(framer: NWProtocolFramer.Instance) -> Bool { return true }
func cleanup(framer: NWProtocolFramer.Instance) { }
// Whenever the application sends a message, add your protocol header and forward the bytes.
func handleOutput(framer: NWProtocolFramer.Instance, message: NWProtocolFramer.Message, messageLength: Int, isComplete: Bool) {
try? framer.writeOutputNoCopy(length: messageLength)
}
// Whenever new bytes are available to read, try to parse out your message format.
func handleInput(framer: NWProtocolFramer.Instance) -> Int {
let message = NWProtocolFramer.Message(definition: MyProtocol.definition)
_ = framer.deliverInputNoCopy(length: 1000, message: message, isComplete: true)
return 0
}
}
var listenerRef: NWListener? = nil
var receiveConnectionRef: NWConnection? = nil
func startListener() {
let options = NWProtocolFramer.Options(definition: MyProtocol.definition)
let parameters = NWParameters.tcp
parameters.defaultProtocolStack.applicationProtocols.insert(options, at: 0)
let listener = try! NWListener(using: parameters, on: 12345)
listenerRef = listener
listener.stateUpdateHandler = { state in
print("listener: state did change, new: \(state)")
}
listener.newConnectionHandler = { conn in
if let old = receiveConnectionRef {
print("listener: will cancel old connection")
old.cancel()
receiveConnectionRef = nil
}
receiveConnectionRef = conn
startReceive(on: conn)
conn.start(queue: .main)
}
listener.start(queue: .main)
}
func startReceive(on connection: NWConnection) {
connection.receiveMessage { dataQ, _, isComplete, errorQ in
if let data = dataQ {
print("receiver: did received, count: \(data.count)")
}
if let error = errorQ {
print("receiver: did fail, error: \(error)")
return
}
// if isComplete {
// print("receiver: is complete")
// return
// }
print("receiver: will not start new receive to force back pressure")
}
}
var sendConnectionRef: NWConnection? = nil
var totalSent = 0
func sendRandomData(to connection: NWConnection) {
var bytes = [UInt8](repeating: 0, count: 1000)
let err = SecRandomCopyBytes(kSecRandomDefault, bytes.count, &bytes)
assert(err == errSecSuccess)
let message = NWProtocolFramer.Message(definition: MyProtocol.definition)
let context = NWConnection.ContentContext(identifier: "Data", metadata: [message])
connection.send(content: Data(bytes), contentContext: context, completion: .contentProcessed({ errorQ in
if let error = errorQ {
print("sender: send failed, error: \(error)")
return
}
totalSent += bytes.count
print("sender: did send, total: \(totalSent)")
sendRandomData(to: connection)
}))
}
func startSender() {
let options = NWProtocolFramer.Options(definition: MyProtocol.definition)
let parameters = NWParameters.tcp
parameters.defaultProtocolStack.applicationProtocols.insert(options, at: 0)
let connection = NWConnection(host: "localhost", port: 12345, using: parameters)
sendConnectionRef = connection // Guarantees a long-lived referenced.
connection.stateUpdateHandler = { state in
print("sender: state did change, new: \(state)")
}
sendRandomData(to: connection)
connection.start(queue: .main)
}
func main() {
startListener()
startSender()
dispatchMain()
}
main()
exit(EXIT_SUCCESS)
Thank you Quinn. I did not test your sample code yet, the only difference I can think of for now is that in my case I never stopped receiving data like you're doing here. Could it be that the connection keeps calling the completion handler as long as some data is being sent (and received) and regardless of how fast the data is being received?