Skip to content

Commit

Permalink
fix(debugging): Don't close inspector socket after 30 sec. timeout
Browse files Browse the repository at this point in the history
We had to close it in order to have the hardcoded port number 18181
available for other apps after finishing (or never starting) a
debugging session. Without this timeout the first app that opened
the port would take it as long as it's running and would prevent
any subsequent debugging attempts of another app on the same iOS device;
or even the same app on another iOS Simulator on the same Mac machine.

From now on, if the 18181 port is unavailable, a random free port \
will be used and its number will be output in the application log.
When starting a debug session, {N} CLI will monitor the logs
in order to receive the allocated port number for the current
session.
  • Loading branch information
mbektchiev committed Apr 10, 2018
1 parent b56eead commit b6e4540
Showing 1 changed file with 31 additions and 37 deletions.
68 changes: 31 additions & 37 deletions src/debugging/TNSDebugging.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
#include <sys/socket.h>
#include <sys/types.h>

// Synchronization object for serializing access to inspector variable and data
// socket
// {N} CLI is relying on this message in order to receive the inspector port number. Please do not change it!
#define LOG_DEBUGGER_PORT NSLog(@"NativeScript debugger has opened inspector socket on port %d.", currentInspectorPort)

// Synchronization object for serializing access to inspector variable and data socket

id inspectorLock() {
static dispatch_once_t once;
Expand All @@ -32,7 +34,7 @@ id inspectorLock() {
}
static TNSRuntimeInspector* inspector = nil;
static BOOL isWaitingForDebugger = NO;
static int32_t cleanupRequestsCount = 0;
static int currentInspectorPort = 0;

typedef void (^TNSInspectorProtocolHandler)(NSString* message, NSError* error);

Expand Down Expand Up @@ -77,16 +79,32 @@ TNSCreateInspectorServer(TNSInspectorFrontendConnectedHandler connectedHandler,
struct sockaddr_in addr = {
sizeof(addr), AF_INET, htons(18181), { INADDR_ANY }, { 0 }
};
if (!CheckError(
bind(listenSocket, (const struct sockaddr*)&addr, sizeof(addr)),
connectedHandler)) {
return nil;

if (bind(listenSocket, (const struct sockaddr*)&addr, sizeof(addr)) != 0) {

// Try getting a random port if the default one is unavailable
addr.sin_port = htons(0);

if (!CheckError(
bind(listenSocket, (const struct sockaddr*)&addr, sizeof(addr)),
connectedHandler)) {

return nil;
}
}

if (!CheckError(listen(listenSocket, 0), connectedHandler)) {
return nil;
}

// read actually allocated listening port
socklen_t len = sizeof(addr);
if (!CheckError(getsockname(listenSocket, (struct sockaddr*)&addr, &len), connectedHandler)) {
return nil;
}

currentInspectorPort = ntohs(addr.sin_port);

__block dispatch_source_t listenSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, listenSocket, 0, queue);

dispatch_source_set_event_handler(listenSource, ^{
Expand Down Expand Up @@ -242,8 +260,6 @@ static void TNSEnableRemoteInspector(int argc, char** argv,
TNSRuntime* runtime) {
__block dispatch_source_t listenSource = nil;

__block dispatch_block_t scheduleInspectorServerCleanup = nil;

dispatch_block_t clearInspector = ^{
// Keep a working copy for calling into the VM after releasing inspectorLock
TNSRuntimeInspector* tempInspector = nil;
Expand All @@ -252,7 +268,6 @@ static void TNSEnableRemoteInspector(int argc, char** argv,
tempInspector = inspector;
inspector = nil;
NSSetUncaughtExceptionHandler(NULL);
scheduleInspectorServerCleanup();
}
}
// Release and dealloc old inspector; must be outside of the inspectorLock
Expand All @@ -270,23 +285,6 @@ static void TNSEnableRemoteInspector(int argc, char** argv,
clearInspector();
};

scheduleInspectorServerCleanup = ^{
dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 30);
OSAtomicIncrement32Barrier(&cleanupRequestsCount);
dispatch_after(delay, dispatch_get_main_queue(), ^{
if (OSAtomicDecrement32Barrier(&cleanupRequestsCount) == 0) {
bool stopListening = false;
@synchronized(inspectorLock()) {
stopListening = inspector == nil;
}

if (stopListening) {
clear();
}
}
});
};

[[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationWillResignActiveNotification
object:nil
Expand Down Expand Up @@ -368,16 +366,14 @@ static void TNSEnableRemoteInspector(int argc, char** argv,
CFRunLoopRef runloop = CFRunLoopGetMain();
CFRunLoopPerformBlock(
runloop, (__bridge CFTypeRef)(inspectorRunloopModes), ^{
// Keep a working copy for calling into the VM after releasing
// inspectorLock
// Keep a working copy for calling into the VM after releasing inspectorLock
TNSRuntimeInspector* tempInspector = nil;
@synchronized(inspectorLock()) {
tempInspector = inspector;
}

if (tempInspector) {
// NSLog(@"NativeScript Debugger
// receiving: %@", message);
// NSLog(@"NativeScript Debugger receiving: %@", message);
[tempInspector dispatchMessage:message];
}
});
Expand Down Expand Up @@ -412,8 +408,7 @@ static void TNSEnableRemoteInspector(int argc, char** argv,
dispatch_after(delay, dispatch_get_main_queue(), ^{
if (isWaitingForDebugger) {
isWaitingForDebugger = NO;
NSLog(@"NativeScript waiting for debugger timeout elapsed. "
@"Continuing execution.");
NSLog(@"NativeScript waiting for debugger timeout elapsed. Continuing execution.");
}
});

Expand All @@ -434,15 +429,12 @@ static void TNSEnableRemoteInspector(int argc, char** argv,
// Remove any existing frontend connections
clearInspector();

// Keep current listening source if existing, schedule cleanup before
// check will guard it from previous timer (if such has been started)
scheduleInspectorServerCleanup();

if (!listenSource) {
listenSource = TNSCreateInspectorServer(
connectionHandler, ioErrorHandler, clearInspector);
}

LOG_DEBUGGER_PORT;
notify_post(NOTIFICATION("ReadyForAttach"));
});

Expand All @@ -451,8 +443,10 @@ static void TNSEnableRemoteInspector(int argc, char** argv,
&attachAvailabilityQuerySubscription,
dispatch_get_main_queue(), ^(int token) {
if (inspector) {
LOG_DEBUGGER_PORT;
notify_post(NOTIFICATION("AlreadyConnected"));
} else if (listenSource) {
LOG_DEBUGGER_PORT;
notify_post(NOTIFICATION("ReadyForAttach"));
} else {
notify_post(NOTIFICATION("AttachAvailable"));
Expand Down

0 comments on commit b6e4540

Please sign in to comment.