From 0a7b2ae2c426733cc3f299bc83a2162bff09f5e2 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Fri, 24 Dec 2010 13:29:35 -0500 Subject: [PATCH] Use a C++ class to handle the CFNetwork events, rather than plain C functions. --- MacGDBp.xcodeproj/project.pbxproj | 8 +- Source/NetworkConnection.h | 9 + ...tworkConnection.m => NetworkConnection.mm} | 272 ++++++++++-------- 3 files changed, 164 insertions(+), 125 deletions(-) rename Source/{NetworkConnection.m => NetworkConnection.mm} (78%) diff --git a/MacGDBp.xcodeproj/project.pbxproj b/MacGDBp.xcodeproj/project.pbxproj index b815f24..539e6ad 100644 --- a/MacGDBp.xcodeproj/project.pbxproj +++ b/MacGDBp.xcodeproj/project.pbxproj @@ -12,7 +12,6 @@ 1E02C3D50C60EC2C006F1752 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E02C3D40C60EC2C006F1752 /* AppDelegate.m */; }; 1E02C5710C610158006F1752 /* DebuggerBackEnd.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E02C5700C610158006F1752 /* DebuggerBackEnd.m */; }; 1E02C5F60C610724006F1752 /* DebuggerController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E02C5F50C610724006F1752 /* DebuggerController.m */; }; - 1E0724E311B47BCC0017AD3C /* NetworkConnection.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E0724E211B47BCC0017AD3C /* NetworkConnection.m */; }; 1E0AFBB90FC2518700C67031 /* HUDIcon.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E0AFBB80FC2518700C67031 /* HUDIcon.png */; }; 1E1E53030DF9B89800D334F9 /* Breakpoints.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1E1E53010DF9B89800D334F9 /* Breakpoints.xib */; }; 1E35FC760C6579CA0030F527 /* NSXMLElementAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E35FC750C6579CA0030F527 /* NSXMLElementAdditions.m */; }; @@ -43,6 +42,7 @@ 1EEBFD090D3599E8008F835B /* BSSplitView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EEBFD070D3599E8008F835B /* BSSplitView.m */; }; 1EEBFD120D359A9F008F835B /* dimple.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EEBFD110D359A9F008F835B /* dimple.png */; }; 1EEE875D0D9DE4B4009CBA7C /* MacGDBp.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1EEE875C0D9DE4B4009CBA7C /* MacGDBp.icns */; }; + 1EFBE63012C515C200F96D6E /* NetworkConnection.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1EFBE62F12C515C200F96D6E /* NetworkConnection.mm */; }; 1EFF70C30DFDC018006B9D33 /* BreakpointController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EFF70C20DFDC018006B9D33 /* BreakpointController.m */; }; 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; @@ -75,7 +75,6 @@ 1E02C5F40C610724006F1752 /* DebuggerController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DebuggerController.h; path = Source/DebuggerController.h; sourceTree = ""; }; 1E02C5F50C610724006F1752 /* DebuggerController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DebuggerController.m; path = Source/DebuggerController.m; sourceTree = ""; }; 1E0724E111B47BCC0017AD3C /* NetworkConnection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkConnection.h; path = Source/NetworkConnection.h; sourceTree = ""; }; - 1E0724E211B47BCC0017AD3C /* NetworkConnection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NetworkConnection.m; path = Source/NetworkConnection.m; sourceTree = ""; }; 1E0AFBB80FC2518700C67031 /* HUDIcon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = HUDIcon.png; path = Icons/HUDIcon.png; sourceTree = ""; }; 1E1E53020DF9B89800D334F9 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/Breakpoints.xib; sourceTree = ""; }; 1E35FC750C6579CA0030F527 /* NSXMLElementAdditions.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = NSXMLElementAdditions.m; path = Source/NSXMLElementAdditions.m; sourceTree = ""; }; @@ -120,6 +119,7 @@ 1EEBFD080D3599E8008F835B /* BSSplitView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BSSplitView.h; path = Source/BSSplitView.h; sourceTree = ""; }; 1EEBFD110D359A9F008F835B /* dimple.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dimple.png; sourceTree = ""; }; 1EEE875C0D9DE4B4009CBA7C /* MacGDBp.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = MacGDBp.icns; path = Icons/MacGDBp.icns; sourceTree = ""; }; + 1EFBE62F12C515C200F96D6E /* NetworkConnection.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NetworkConnection.mm; path = Source/NetworkConnection.mm; sourceTree = ""; }; 1EFF70C10DFDC018006B9D33 /* BreakpointController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpointController.h; path = Source/BreakpointController.h; sourceTree = ""; }; 1EFF70C20DFDC018006B9D33 /* BreakpointController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BreakpointController.m; path = Source/BreakpointController.m; sourceTree = ""; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -213,7 +213,7 @@ isa = PBXGroup; children = ( 1E0724E111B47BCC0017AD3C /* NetworkConnection.h */, - 1E0724E211B47BCC0017AD3C /* NetworkConnection.m */, + 1EFBE62F12C515C200F96D6E /* NetworkConnection.mm */, 1E02C56F0C610158006F1752 /* DebuggerBackEnd.h */, 1E02C5700C610158006F1752 /* DebuggerBackEnd.m */, 1E35FFB00C65A74C0030F527 /* NSXMLElementAdditions.h */, @@ -447,9 +447,9 @@ 1EBF4D5D0EE35F0700B62769 /* StackController.m in Sources */, 1E67E6FD0F3C052000E68F1B /* PreferencesPathsArrayController.m in Sources */, 1E6B5947116106FE001189D2 /* LoggingController.m in Sources */, - 1E0724E311B47BCC0017AD3C /* NetworkConnection.m in Sources */, 1EC1337E127DBB00007946FC /* VariableNode.m in Sources */, 1EC6965812BBC6A700A8D984 /* modp_b64.cc in Sources */, + 1EFBE63012C515C200F96D6E /* NetworkConnection.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/NetworkConnection.h b/Source/NetworkConnection.h index c357866..0b27ebe 100644 --- a/Source/NetworkConnection.h +++ b/Source/NetworkConnection.h @@ -16,6 +16,12 @@ #import +#ifdef __cplusplus +class NetworkCallbackController; +#else +@class NetworkCallbackController; +#endif + @protocol NetworkConnectionDelegate; @class LoggingController; @@ -37,6 +43,9 @@ // Reference to the message loop that the socket runs on. Weak. NSRunLoop* runLoop_; + // Internal class that manages CFNetwork callbacks. Strong. + NetworkCallbackController* callbackController_; + // The raw CFSocket on which the two streams are based. Strong. CFSocketRef socket_; diff --git a/Source/NetworkConnection.m b/Source/NetworkConnection.mm similarity index 78% rename from Source/NetworkConnection.m rename to Source/NetworkConnection.mm index adb2191..c5728c0 100644 --- a/Source/NetworkConnection.m +++ b/Source/NetworkConnection.mm @@ -59,132 +59,164 @@ // CFNetwork Callbacks ///////////////////////////////////////////////////////// -void ReadStreamCallback(CFReadStreamRef stream, CFStreamEventType eventType, void* connectionRaw) +class NetworkCallbackController { - NetworkConnection* connection = (NetworkConnection*)connectionRaw; - switch (eventType) + public: + NetworkCallbackController(NetworkConnection* connection) + : connection_(connection), + runLoop_(CFRunLoopGetCurrent()) { - case kCFStreamEventHasBytesAvailable: - [connection readStreamHasData]; - break; - - case kCFStreamEventErrorOccurred: - { - CFErrorRef error = CFReadStreamCopyError(stream); - CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - CFReadStreamClose(stream); - CFRelease(stream); - [connection errorEncountered:[[(NSError*)error autorelease] description]]; - break; + } + + static void SocketAcceptCallback(CFSocketRef socket, + CFSocketCallBackType callbackType, + CFDataRef address, + const void* data, + void* self) + { + assert(callbackType == kCFSocketAcceptCallBack); + static_cast(self)->OnSocketAccept(socket, address, data); + } + + void OnSocketAccept(CFSocketRef socket, + CFDataRef address, + const void* data) + { + CFReadStreamRef readStream; + CFWriteStreamRef writeStream; + + // Create the streams on the socket. + CFStreamCreatePairWithSocket(kCFAllocatorDefault, + *(CFSocketNativeHandle*)data, // Socket handle. + &readStream, // Read stream in-pointer. + &writeStream); // Write stream in-pointer. + + // Create struct to register callbacks for the stream. + CFStreamClientContext context = { 0 }; + context.info = this; + + // Set the client of the read stream. + CFOptionFlags readFlags = kCFStreamEventOpenCompleted | + kCFStreamEventHasBytesAvailable | + kCFStreamEventErrorOccurred | + kCFStreamEventEndEncountered; + if (CFReadStreamSetClient(readStream, readFlags, &NetworkCallbackController::ReadStreamCallback, &context)) + // Schedule in run loop to do asynchronous communication with the engine. + CFReadStreamScheduleWithRunLoop(readStream, runLoop_, kCFRunLoopCommonModes); + else + return; + + // Open the stream now that it's scheduled on the run loop. + if (!CFReadStreamOpen(readStream)) { + ReportError(CFReadStreamCopyError(readStream)); + return; } - - case kCFStreamEventEndEncountered: - CFReadStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - CFReadStreamClose(stream); - CFRelease(stream); - [connection socketDisconnected]; - break; - }; -} + + // Set the client of the write stream. + CFOptionFlags writeFlags = kCFStreamEventOpenCompleted | + kCFStreamEventCanAcceptBytes | + kCFStreamEventErrorOccurred | + kCFStreamEventEndEncountered; + if (CFWriteStreamSetClient(writeStream, writeFlags, &NetworkCallbackController::WriteStreamCallback, &context)) + // Schedule it in the run loop to receive error information. + CFWriteStreamScheduleWithRunLoop(writeStream, runLoop_, kCFRunLoopCommonModes); + else + return; + + // Open the write stream. + if (!CFWriteStreamOpen(writeStream)) { + ReportError(CFWriteStreamCopyError(writeStream)); + return; + } + + connection_.readStream = readStream; + connection_.writeStream = writeStream; + [connection_ socketDidAccept]; + } -void WriteStreamCallback(CFWriteStreamRef stream, CFStreamEventType eventType, void* connectionRaw) -{ - NetworkConnection* connection = (NetworkConnection*)connectionRaw; - switch (eventType) + static void ReadStreamCallback(CFReadStreamRef stream, + CFStreamEventType eventType, + void* self) { - case kCFStreamEventCanAcceptBytes: - [connection sendQueuedWrites]; - break; - - case kCFStreamEventErrorOccurred: + static_cast(self)->OnReadStreamEvent(stream, eventType); + } + + void OnReadStreamEvent(CFReadStreamRef stream, CFStreamEventType eventType) + { + switch (eventType) { - CFErrorRef error = CFWriteStreamCopyError(stream); - CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - CFWriteStreamClose(stream); - CFRelease(stream); - [connection errorEncountered:[[(NSError*)error autorelease] description]]; - break; - } - - case kCFStreamEventEndEncountered: - CFWriteStreamUnscheduleFromRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - CFWriteStreamClose(stream); - CFRelease(stream); - [connection socketDisconnected]; - break; + case kCFStreamEventHasBytesAvailable: + [connection_ readStreamHasData]; + break; + + case kCFStreamEventErrorOccurred: + { + ReportError(CFReadStreamCopyError(stream)); + UnscheduleReadStream(); + break; + } + + case kCFStreamEventEndEncountered: + UnscheduleReadStream(); + [connection_ socketDisconnected]; + break; + }; } -} -void SocketAcceptCallback(CFSocketRef socket, - CFSocketCallBackType callbackType, - CFDataRef address, - const void* data, - void* connectionRaw) -{ - assert(callbackType == kCFSocketAcceptCallBack); - NetworkConnection* connection = (NetworkConnection*)connectionRaw; + void UnscheduleReadStream() + { + CFReadStreamUnscheduleFromRunLoop(connection_.readStream, runLoop_, kCFRunLoopCommonModes); + CFReadStreamClose(connection_.readStream); + CFRelease(connection_.readStream); + connection_.readStream = NULL; + } - CFReadStreamRef readStream; - CFWriteStreamRef writeStream; - - // Create the streams on the socket. - CFStreamCreatePairWithSocket(kCFAllocatorDefault, - *(CFSocketNativeHandle*)data, // Socket handle. - &readStream, // Read stream in-pointer. - &writeStream); // Write stream in-pointer. - - // Create struct to register callbacks for the stream. - CFStreamClientContext context; - context.version = 0; - context.info = connection; - context.retain = NULL; - context.release = NULL; - context.copyDescription = NULL; - - // Set the client of the read stream. - CFOptionFlags readFlags = - kCFStreamEventOpenCompleted | - kCFStreamEventHasBytesAvailable | - kCFStreamEventErrorOccurred | - kCFStreamEventEndEncountered; - if (CFReadStreamSetClient(readStream, readFlags, ReadStreamCallback, &context)) - // Schedule in run loop to do asynchronous communication with the engine. - CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - else - return; - - // Open the stream now that it's scheduled on the run loop. - if (!CFReadStreamOpen(readStream)) + static void WriteStreamCallback(CFWriteStreamRef stream, + CFStreamEventType eventType, + void* self) { - CFStreamError error = CFReadStreamGetError(readStream); - NSLog(@"error! %@", error); - return; + static_cast(self)->OnWriteStreamEvent(stream, eventType); } - - // Set the client of the write stream. - CFOptionFlags writeFlags = - kCFStreamEventOpenCompleted | - kCFStreamEventCanAcceptBytes | - kCFStreamEventErrorOccurred | - kCFStreamEventEndEncountered; - if (CFWriteStreamSetClient(writeStream, writeFlags, WriteStreamCallback, &context)) - // Schedule it in the run loop to receive error information. - CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes); - else - return; - - // Open the write stream. - if (!CFWriteStreamOpen(writeStream)) + + void OnWriteStreamEvent(CFWriteStreamRef stream, CFStreamEventType eventType) { - CFStreamError error = CFWriteStreamGetError(writeStream); - NSLog(@"error! %@", error); - return; + switch (eventType) + { + case kCFStreamEventCanAcceptBytes: + [connection_ sendQueuedWrites]; + break; + + case kCFStreamEventErrorOccurred: + { + ReportError(CFWriteStreamCopyError(stream)); + UnscheduleWriteStream(); + break; + } + + case kCFStreamEventEndEncountered: + UnscheduleReadStream(); + [connection_ socketDisconnected]; + break; + } } - - connection.readStream = readStream; - connection.writeStream = writeStream; - [connection socketDidAccept]; -} + void UnscheduleWriteStream() + { + CFWriteStreamUnscheduleFromRunLoop(connection_.writeStream, runLoop_, kCFRunLoopCommonModes); + CFWriteStreamClose(connection_.writeStream); + CFRelease(connection_.writeStream); + connection_.writeStream = NULL; + } + + private: + void ReportError(CFErrorRef error) + { + [connection_ errorEncountered:[(NSError*)error description]]; + CFRelease(error); + } + + NetworkConnection* connection_; // Weak, owns this. + CFRunLoopRef runLoop_; // Weak. +}; // Other Run Loop Callbacks //////////////////////////////////////////////////// @@ -248,14 +280,11 @@ void PerformQuitSignal(void* info) thread_ = [NSThread currentThread]; runLoop_ = [NSRunLoop currentRunLoop]; + callbackController_ = new NetworkCallbackController(self); // Pass ourselves to the callback so we don't have to use ugly globals. - CFSocketContext context; - context.version = 0; - context.info = self; - context.retain = NULL; - context.release = NULL; - context.copyDescription = NULL; + CFSocketContext context = { 0 }; + context.info = callbackController_; // Create the address structure. struct sockaddr_in address; @@ -276,7 +305,7 @@ void PerformQuitSignal(void* info) socket_ = CFSocketCreateWithSocketSignature(kCFAllocatorDefault, &signature, // Socket signature. kCFSocketAcceptCallBack, // Callback types. - SocketAcceptCallback, // Callout function pointer. + &NetworkCallbackController::SocketAcceptCallback, // Callout function pointer. &context); // Context to pass to callout. if (!socket_) { [self errorEncountered:@"Could not open socket."]; @@ -296,7 +325,6 @@ void PerformQuitSignal(void* info) // Create a source that is used to quit. CFRunLoopSourceContext quitContext = { 0 }; - quitContext.version = 0; quitContext.info = self; quitContext.perform = PerformQuitSignal; quitSource_ = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &quitContext); @@ -306,6 +334,8 @@ void PerformQuitSignal(void* info) thread_ = nil; runLoop_ = nil; + delete callbackController_; + callbackController_ = NULL; CFRunLoopSourceInvalidate(quitSource_); CFRelease(quitSource_); -- 2.22.5