- (void)stepIn;
- (void)stepOut;
- (void)stepOver;
+- (void)stop;
- (void)detach;
// Breakpoint management.
[self recordCallback:@selector(debuggerStep:) forTransaction:tx];
}
+/**
+ * Halts execution of the script.
+ */
+- (void)stop
+{
+ [connection_ close];
+ active_ = NO;
+ self.status = @"Stopped";
+ if ([delegate respondsToSelector:@selector(debuggerDisconnected)])
+ [delegate debuggerDisconnected];
+}
+
/**
* Ends the current debugging session.
*/
*/
- (IBAction)stop:(id)sender
{
- [connection detach];
+ [connection stop];
}
- (void)fetchChildProperties:(VariableNode*)node
*/
#import <CoreFoundation/CoreFoundation.h>
+#import <Foundation/Foundation.h>
@class NetworkConnection;
// thread.
NetworkCallbackController(NetworkConnection* connection);
+ // Creates a socket and schedules it on the current run loop.
+ void OpenConnection(NSUInteger port);
+
+ // Closes down the read/write streams.
+ void CloseConnection();
+
+ private:
// 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,
CFStreamEventType eventType,
void* self);
- private:
void OnSocketAccept(CFSocketRef socket,
CFDataRef address,
const void* data);
// Messages the NetworkConnection's delegate and takes ownership of |error|.
void ReportError(CFErrorRef error);
-
+
+ // The actual socket.
+ CFSocketRef socket_; // Strong.
+
NetworkConnection* connection_; // Weak, owns this.
CFRunLoopRef runLoop_; // Weak.
};
#import "NetworkCallbackController.h"
+#import <sys/socket.h>
+#import <netinet/in.h>
+
#import "NetworkConnection.h"
#import "NetworkConnectionPrivate.h"
{
}
+void NetworkCallbackController::OpenConnection(NSUInteger port)
+{
+ // Pass ourselves to the callback so we don't have to use ugly globals.
+ CFSocketContext context = { 0 };
+ context.info = this;
+
+ // Create the address structure.
+ struct sockaddr_in address;
+ memset(&address, 0, sizeof(address));
+ address.sin_len = sizeof(address);
+ address.sin_family = AF_INET;
+ address.sin_port = htons(port);
+ address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ // Create the socket signature.
+ CFSocketSignature signature;
+ signature.protocolFamily = PF_INET;
+ signature.socketType = SOCK_STREAM;
+ signature.protocol = IPPROTO_TCP;
+ signature.address = (CFDataRef)[NSData dataWithBytes:&address length:sizeof(address)];
+
+ do {
+ socket_ = CFSocketCreateWithSocketSignature(kCFAllocatorDefault,
+ &signature, // Socket signature.
+ kCFSocketAcceptCallBack, // Callback types.
+ &NetworkCallbackController::SocketAcceptCallback, // Callout function pointer.
+ &context); // Context to pass to callout.
+ if (!socket_) {
+ [connection_ errorEncountered:@"Could not open socket."];
+ sleep(1);
+ }
+ } while (!socket_);
+
+ // Allow old, yet-to-be recycled sockets to be reused.
+ BOOL yes = YES;
+ setsockopt(CFSocketGetNative(socket_), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(BOOL));
+ setsockopt(CFSocketGetNative(socket_), SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(BOOL));
+
+ // Schedule the socket on the run loop.
+ CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 0);
+ CFRunLoopAddSource(runLoop_, source, kCFRunLoopCommonModes);
+ CFRelease(source);
+}
+
+void NetworkCallbackController::CloseConnection()
+{
+ if (socket_) {
+ NSLog(@"invalidating socket %d", close(CFSocketGetNative(socket_)));
+ CFSocketInvalidate(socket_);
+ NSLog(@"socket is valid %d", CFSocketIsValid(socket_));
+ CFRelease(socket_);
+ socket_ = NULL;
+ }
+ UnscheduleReadStream();
+ UnscheduleWriteStream();
+}
+
// Static Methods //////////////////////////////////////////////////////////////
void NetworkCallbackController::SocketAcceptCallback(CFSocketRef socket,
switch (eventType)
{
case kCFStreamEventHasBytesAvailable:
- [connection_ readStreamHasData];
+ if (connection_.readStream)
+ [connection_ readStreamHasData];
break;
case kCFStreamEventErrorOccurred:
+ NSLog(@"%s error", __PRETTY_FUNCTION__);
ReportError(CFReadStreamCopyError(stream));
UnscheduleReadStream();
break;
case kCFStreamEventEndEncountered:
+ NSLog(@"%s end", __PRETTY_FUNCTION__);
UnscheduleReadStream();
[connection_ socketDisconnected];
break;
// Internal class that manages CFNetwork callbacks. Strong.
NetworkCallbackController* callbackController_;
- // The raw CFSocket on which the two streams are based. Strong.
- CFSocketRef socket_;
-
// The read stream that is scheduled on the main run loop. Weak.
CFReadStreamRef readStream_;
#import "NetworkConnection.h"
#import "NetworkConnectionPrivate.h"
-#import <sys/socket.h>
-#import <netinet/in.h>
-
#import "AppDelegate.h"
#import "LoggingController.h"
#include "NetworkCallbackController.h"
@synthesize connected = connected_;
@synthesize delegate = delegate_;
-@synthesize socket = socket_;
@synthesize readStream = readStream_;
@synthesize lastReadTransaction = lastReadTransaction_;
@synthesize currentPacket = currentPacket_;
runLoop_ = [NSRunLoop currentRunLoop];
callbackController_ = new NetworkCallbackController(self);
- // Pass ourselves to the callback so we don't have to use ugly globals.
- CFSocketContext context = { 0 };
- context.info = callbackController_;
-
- // Create the address structure.
- struct sockaddr_in address;
- memset(&address, 0, sizeof(address));
- address.sin_len = sizeof(address);
- address.sin_family = AF_INET;
- address.sin_port = htons(port_);
- address.sin_addr.s_addr = htonl(INADDR_ANY);
-
- // Create the socket signature.
- CFSocketSignature signature;
- signature.protocolFamily = PF_INET;
- signature.socketType = SOCK_STREAM;
- signature.protocol = IPPROTO_TCP;
- signature.address = (CFDataRef)[NSData dataWithBytes:&address length:sizeof(address)];
-
- do {
- socket_ = CFSocketCreateWithSocketSignature(kCFAllocatorDefault,
- &signature, // Socket signature.
- kCFSocketAcceptCallBack, // Callback types.
- &NetworkCallbackController::SocketAcceptCallback, // Callout function pointer.
- &context); // Context to pass to callout.
- if (!socket_) {
- [self errorEncountered:@"Could not open socket."];
- sleep(1);
- }
- } while (!socket_);
-
- // Allow old, yet-to-be recycled sockets to be reused.
- BOOL yes = YES;
- setsockopt(CFSocketGetNative(socket_), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(BOOL));
- setsockopt(CFSocketGetNative(socket_), SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(BOOL));
-
- // Schedule the socket on the run loop.
- CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket_, 0);
- CFRunLoopAddSource([runLoop_ getCFRunLoop], source, kCFRunLoopCommonModes);
- CFRelease(source);
-
// Create a source that is used to quit.
CFRunLoopSourceContext quitContext = { 0 };
quitContext.info = self;
quitSource_ = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &quitContext);
CFRunLoopAddSource([runLoop_ getCFRunLoop], quitSource_, kCFRunLoopCommonModes);
+ callbackController_->OpenConnection(port_);
+
CFRunLoopRun();
thread_ = nil;
if (runLoop_) {
CFRunLoopStop([runLoop_ getCFRunLoop]);
}
-
- // The socket goes down, so do the streams, which clean themselves up.
- if (socket_) {
- NSLog(@"invalidating socket");
- CFSocketInvalidate(socket_);
- CFRelease(socket_);
- socket_ = NULL;
- }
+
+ callbackController_->CloseConnection();
}
/**
// by the C++ NetworkCallbackController to communicate.
@interface NetworkConnection ()
-@property (assign) CFSocketRef socket;
@property (assign) CFReadStreamRef readStream;
@property NSUInteger lastReadTransaction;
@property (retain) NSMutableString* currentPacket;