From 307cce570cac4cfefe97ab9309ddd2f388c6c075 Mon Sep 17 00:00:00 2001 From: Robert Sesek Date: Fri, 24 Dec 2010 13:53:56 -0500 Subject: [PATCH] Split out the C++ class into its own file. Also move NetworkConnection's private interface out. --- MacGDBp.xcodeproj/project.pbxproj | 8 ++ Source/NetworkCallbackController.h | 64 +++++++++ Source/NetworkCallbackController.mm | 179 +++++++++++++++++++++++++ Source/NetworkConnection.h | 2 +- Source/NetworkConnection.mm | 198 +--------------------------- Source/NetworkConnectionPrivate.h | 50 +++++++ 6 files changed, 304 insertions(+), 197 deletions(-) create mode 100644 Source/NetworkCallbackController.h create mode 100644 Source/NetworkCallbackController.mm create mode 100644 Source/NetworkConnectionPrivate.h diff --git a/MacGDBp.xcodeproj/project.pbxproj b/MacGDBp.xcodeproj/project.pbxproj index 539e6ad..3b8509d 100644 --- a/MacGDBp.xcodeproj/project.pbxproj +++ b/MacGDBp.xcodeproj/project.pbxproj @@ -43,6 +43,7 @@ 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 */; }; + 1EFBE66B12C51E3900F96D6E /* NetworkCallbackController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1EFBE66A12C51E3900F96D6E /* NetworkCallbackController.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 = (); }; }; @@ -120,6 +121,9 @@ 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 = ""; }; + 1EFBE66912C51E3900F96D6E /* NetworkCallbackController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkCallbackController.h; path = Source/NetworkCallbackController.h; sourceTree = ""; }; + 1EFBE66A12C51E3900F96D6E /* NetworkCallbackController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NetworkCallbackController.mm; path = Source/NetworkCallbackController.mm; sourceTree = ""; }; + 1EFBE66C12C51EFA00F96D6E /* NetworkConnectionPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NetworkConnectionPrivate.h; path = Source/NetworkConnectionPrivate.h; 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 +217,10 @@ isa = PBXGroup; children = ( 1E0724E111B47BCC0017AD3C /* NetworkConnection.h */, + 1EFBE66C12C51EFA00F96D6E /* NetworkConnectionPrivate.h */, 1EFBE62F12C515C200F96D6E /* NetworkConnection.mm */, + 1EFBE66912C51E3900F96D6E /* NetworkCallbackController.h */, + 1EFBE66A12C51E3900F96D6E /* NetworkCallbackController.mm */, 1E02C56F0C610158006F1752 /* DebuggerBackEnd.h */, 1E02C5700C610158006F1752 /* DebuggerBackEnd.m */, 1E35FFB00C65A74C0030F527 /* NSXMLElementAdditions.h */, @@ -450,6 +457,7 @@ 1EC1337E127DBB00007946FC /* VariableNode.m in Sources */, 1EC6965812BBC6A700A8D984 /* modp_b64.cc in Sources */, 1EFBE63012C515C200F96D6E /* NetworkConnection.mm in Sources */, + 1EFBE66B12C51E3900F96D6E /* NetworkCallbackController.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Source/NetworkCallbackController.h b/Source/NetworkCallbackController.h new file mode 100644 index 0000000..4e9e78b --- /dev/null +++ b/Source/NetworkCallbackController.h @@ -0,0 +1,64 @@ +/* + * MacGDBp + * Copyright (c) 2007 - 2010, Blue Static + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if not, + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#import + +@class NetworkConnection; + +// This class is used for the CFNetwork callbacks. It is a private class and +// the instance is owned by the NewtorkConnection instance. This class can be +// considered an extension of NetworkConnection. +class NetworkCallbackController +{ + public: + // This object should be constructed on the thread which the streams are + // to be scheduled on. It will hold a weak reference to the run loop on that + // thread. + NetworkCallbackController(NetworkConnection* connection); + + // These static methods forward an invocation to the instance methods. The + // last void pointer, named |self|, is the instance of this class. + static void SocketAcceptCallback(CFSocketRef socket, + CFSocketCallBackType callbackType, + CFDataRef address, + const void* data, + void* self); + static void ReadStreamCallback(CFReadStreamRef stream, + CFStreamEventType eventType, + void* self); + static void WriteStreamCallback(CFWriteStreamRef stream, + CFStreamEventType eventType, + void* self); + + private: + void OnSocketAccept(CFSocketRef socket, + CFDataRef address, + const void* data); + void OnReadStreamEvent(CFReadStreamRef stream, CFStreamEventType eventType); + void OnWriteStreamEvent(CFWriteStreamRef stream, CFStreamEventType eventType); + + // Removes the read or write stream from the run loop, closes the stream, + // releases the reference. + void UnscheduleReadStream(); + void UnscheduleWriteStream(); + + // Messages the NetworkConnection's delegate and takes ownership of |error|. + void ReportError(CFErrorRef error); + + NetworkConnection* connection_; // Weak, owns this. + CFRunLoopRef runLoop_; // Weak. +}; + diff --git a/Source/NetworkCallbackController.mm b/Source/NetworkCallbackController.mm new file mode 100644 index 0000000..7356912 --- /dev/null +++ b/Source/NetworkCallbackController.mm @@ -0,0 +1,179 @@ +/* + * MacGDBp + * Copyright (c) 2007 - 2010, Blue Static + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if not, + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#import "NetworkCallbackController.h" + +#import "NetworkConnection.h" +#import "NetworkConnectionPrivate.h" + +NetworkCallbackController::NetworkCallbackController(NetworkConnection* connection) + : connection_(connection), + runLoop_(CFRunLoopGetCurrent()) +{ +} + +// Static Methods ////////////////////////////////////////////////////////////// + +void NetworkCallbackController::SocketAcceptCallback(CFSocketRef socket, + CFSocketCallBackType callbackType, + CFDataRef address, + const void* data, + void* self) +{ + assert(callbackType == kCFSocketAcceptCallBack); + static_cast(self)->OnSocketAccept(socket, address, data); +} + +void NetworkCallbackController::ReadStreamCallback(CFReadStreamRef stream, + CFStreamEventType eventType, + void* self) +{ + static_cast(self)->OnReadStreamEvent(stream, eventType); +} + +void NetworkCallbackController::WriteStreamCallback(CFWriteStreamRef stream, + CFStreamEventType eventType, + void* self) +{ + static_cast(self)->OnWriteStreamEvent(stream, eventType); +} + + +// Private Instance Methods //////////////////////////////////////////////////// + +void NetworkCallbackController::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; + } + + // 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 NetworkCallbackController::OnReadStreamEvent(CFReadStreamRef stream, + CFStreamEventType eventType) +{ + switch (eventType) + { + case kCFStreamEventHasBytesAvailable: + [connection_ readStreamHasData]; + break; + + case kCFStreamEventErrorOccurred: + { + ReportError(CFReadStreamCopyError(stream)); + UnscheduleReadStream(); + break; + } + + case kCFStreamEventEndEncountered: + UnscheduleReadStream(); + [connection_ socketDisconnected]; + break; + }; +} + +void NetworkCallbackController::OnWriteStreamEvent(CFWriteStreamRef stream, + CFStreamEventType eventType) +{ + switch (eventType) + { + case kCFStreamEventCanAcceptBytes: + [connection_ sendQueuedWrites]; + break; + + case kCFStreamEventErrorOccurred: + { + ReportError(CFWriteStreamCopyError(stream)); + UnscheduleWriteStream(); + break; + } + + case kCFStreamEventEndEncountered: + UnscheduleReadStream(); + [connection_ socketDisconnected]; + break; + } +} + +void NetworkCallbackController::UnscheduleReadStream() +{ + CFReadStreamUnscheduleFromRunLoop(connection_.readStream, runLoop_, kCFRunLoopCommonModes); + CFReadStreamClose(connection_.readStream); + CFRelease(connection_.readStream); + connection_.readStream = NULL; +} + +void NetworkCallbackController::UnscheduleWriteStream() +{ + CFWriteStreamUnscheduleFromRunLoop(connection_.writeStream, runLoop_, kCFRunLoopCommonModes); + CFWriteStreamClose(connection_.writeStream); + CFRelease(connection_.writeStream); + connection_.writeStream = NULL; +} + +void NetworkCallbackController::ReportError(CFErrorRef error) +{ + [connection_ errorEncountered:[(NSError*)error description]]; + CFRelease(error); +} diff --git a/Source/NetworkConnection.h b/Source/NetworkConnection.h index 0b27ebe..234e797 100644 --- a/Source/NetworkConnection.h +++ b/Source/NetworkConnection.h @@ -55,7 +55,7 @@ class NetworkCallbackController; // The write stream. Weak. CFWriteStreamRef writeStream_; - // Run loop source used to quit the thread. + // Run loop source used to quit the thread. Strong. CFRunLoopSourceRef quitSource_; // An ever-increasing integer that gives each transaction a unique ID for the diff --git a/Source/NetworkConnection.mm b/Source/NetworkConnection.mm index c5728c0..08c3d60 100644 --- a/Source/NetworkConnection.mm +++ b/Source/NetworkConnection.mm @@ -15,208 +15,14 @@ */ #import "NetworkConnection.h" +#import "NetworkConnectionPrivate.h" #import #import #import "AppDelegate.h" #import "LoggingController.h" - -// NetworkConnection (Private) ///////////////////////////////////////////////// - -@interface NetworkConnection () - -@property (assign) CFSocketRef socket; -@property (assign) CFReadStreamRef readStream; -@property NSUInteger lastReadTransaction; -@property (retain) NSMutableString* currentPacket; -@property (assign) CFWriteStreamRef writeStream; -@property NSUInteger lastWrittenTransaction; -@property (retain) NSMutableArray* queuedWrites; - -- (void)runNetworkThread; - -- (void)socketDidAccept; -- (void)socketDisconnected; -- (void)readStreamHasData; - -// These methods MUST be called on the network thread as they are not threadsafe. -- (void)send:(NSString*)command; -- (void)performSend:(NSString*)command; -- (void)sendQueuedWrites; - -- (void)performQuitSignal; - -- (void)handleResponse:(NSXMLDocument*)response; -- (void)handlePacket:(NSString*)packet; - -// Threadsafe wrappers for the delegate's methods. -- (void)errorEncountered:(NSString*)error; -- (LogEntry*)recordSend:(NSString*)command; -- (LogEntry*)recordReceive:(NSString*)command; - -@end - -// CFNetwork Callbacks ///////////////////////////////////////////////////////// - -class NetworkCallbackController -{ - public: - NetworkCallbackController(NetworkConnection* connection) - : connection_(connection), - runLoop_(CFRunLoopGetCurrent()) - { - } - - 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; - } - - // 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]; - } - - static void ReadStreamCallback(CFReadStreamRef stream, - CFStreamEventType eventType, - void* self) - { - static_cast(self)->OnReadStreamEvent(stream, eventType); - } - - void OnReadStreamEvent(CFReadStreamRef stream, CFStreamEventType eventType) - { - switch (eventType) - { - case kCFStreamEventHasBytesAvailable: - [connection_ readStreamHasData]; - break; - - case kCFStreamEventErrorOccurred: - { - ReportError(CFReadStreamCopyError(stream)); - UnscheduleReadStream(); - break; - } - - case kCFStreamEventEndEncountered: - UnscheduleReadStream(); - [connection_ socketDisconnected]; - break; - }; - } - - void UnscheduleReadStream() - { - CFReadStreamUnscheduleFromRunLoop(connection_.readStream, runLoop_, kCFRunLoopCommonModes); - CFReadStreamClose(connection_.readStream); - CFRelease(connection_.readStream); - connection_.readStream = NULL; - } - - static void WriteStreamCallback(CFWriteStreamRef stream, - CFStreamEventType eventType, - void* self) - { - static_cast(self)->OnWriteStreamEvent(stream, eventType); - } - - void OnWriteStreamEvent(CFWriteStreamRef stream, CFStreamEventType eventType) - { - switch (eventType) - { - case kCFStreamEventCanAcceptBytes: - [connection_ sendQueuedWrites]; - break; - - case kCFStreamEventErrorOccurred: - { - ReportError(CFWriteStreamCopyError(stream)); - UnscheduleWriteStream(); - break; - } - - case kCFStreamEventEndEncountered: - UnscheduleReadStream(); - [connection_ socketDisconnected]; - break; - } - } - 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. -}; +#include "NetworkCallbackController.h" // Other Run Loop Callbacks //////////////////////////////////////////////////// diff --git a/Source/NetworkConnectionPrivate.h b/Source/NetworkConnectionPrivate.h new file mode 100644 index 0000000..9ce998a --- /dev/null +++ b/Source/NetworkConnectionPrivate.h @@ -0,0 +1,50 @@ +/* + * MacGDBp + * Copyright (c) 2007 - 2010, Blue Static + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if not, + * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + */ + +@class LogEntry; + +@interface NetworkConnection () + +@property (assign) CFSocketRef socket; +@property (assign) CFReadStreamRef readStream; +@property NSUInteger lastReadTransaction; +@property (retain) NSMutableString* currentPacket; +@property (assign) CFWriteStreamRef writeStream; +@property NSUInteger lastWrittenTransaction; +@property (retain) NSMutableArray* queuedWrites; + +- (void)runNetworkThread; + +- (void)socketDidAccept; +- (void)socketDisconnected; +- (void)readStreamHasData; + +// These methods MUST be called on the network thread as they are not threadsafe. +- (void)send:(NSString*)command; +- (void)performSend:(NSString*)command; +- (void)sendQueuedWrites; + +- (void)performQuitSignal; + +- (void)handleResponse:(NSXMLDocument*)response; +- (void)handlePacket:(NSString*)packet; + +// Threadsafe wrappers for the delegate's methods. +- (void)errorEncountered:(NSString*)error; +- (LogEntry*)recordSend:(NSString*)command; +- (LogEntry*)recordReceive:(NSString*)command; + +@end -- 2.22.5