diff --git a/launchers/macosx/obj-cpp/AppDelegate.h b/launchers/macosx/obj-cpp/AppDelegate.h
index ad20e10c3639b4b92ee2eea62e3a85eedef2e601..d5592a336820dc910eb7f210703dfac5c9f1b6c8 100644
--- a/launchers/macosx/obj-cpp/AppDelegate.h
+++ b/launchers/macosx/obj-cpp/AppDelegate.h
@@ -7,9 +7,9 @@
 
 #include <Cocoa/Cocoa.h>
 
+#include "RouterTask.h"
 #include "StatusItemButton.h"
 #include "JavaHelper.h"
-#include "RouterTask.h"
 #include "neither/maybe.hpp"
 #include "optional.hpp"
 #include "subprocess.hpp"
@@ -26,24 +26,33 @@
 
 using namespace neither;
 
-using maybeAnRouterRunner = std::experimental::optional<RouterTask*>;
+@class ExtractMetaInfo;
+using maybeAnRouterRunner = std::experimental::optional<I2PRouterTask*>;
 
+std::vector<std::string> buildClassPath(std::string basePath);
 
 extern JvmListSharedPtr gRawJvmList;
 
 // DO NOT ACCESS THIS GLOBAL VARIABLE DIRECTLY.
 static std::mutex globalRouterStatusMutex;
 static maybeAnRouterRunner globalRouterStatus = maybeAnRouterRunner{};
+static bool isRuterRunning = false;
 
 maybeAnRouterRunner getGlobalRouterObject();
-void setGlobalRouterObject(RouterTask* newRouter);
+void setGlobalRouterObject(I2PRouterTask* newRouter);
+bool getGlobalRouterIsRunning();
+void setGlobalRouterIsRunning(bool running);
 
-@class ExtractMetaInfo;
 @interface ExtractMetaInfo : NSObject
-@property (strong) NSString* i2pBase;
-@property (strong) NSString* javaBinary;
-@property (strong) NSString* zipFile;
-@property (strong) NSString* jarFile;
+@property (copy) NSString* i2pBase;
+@property (copy) NSString* javaBinary;
+@property (copy) NSString* zipFile;
+@property (copy) NSString* jarFile;
+@end
+
+@class I2PStatusMenu;
+@interface I2PStatusMenu : NSMenu
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem;
 @end
 
 inline void sendUserNotification(NSString* title, NSString* informativeText, NSImage* contentImage = NULL, bool makeSound = false) {
@@ -68,10 +77,21 @@ inline std::vector<std::string> globVector(const std::string& pattern){
     return files;
 }
 
+inline std::string getDefaultBaseDir()
+{
+  // Figure out base directory
+  const char* pathFromHome = "/Users/%s/Library/I2P";
+  auto username = getenv("USER");
+  char buffer[strlen(pathFromHome)+strlen(username)];
+  sprintf(buffer, pathFromHome, username);
+  std::string i2pBaseDir(buffer);
+  return i2pBaseDir;
+}
+
 @interface MenuBarCtrl : NSObject <StatusItemButtonDelegate, NSMenuDelegate>
 @property BOOL enableLogging;
 @property BOOL enableVerboseLogging;
-@property (strong) NSMenu *menu;
+@property (strong) I2PStatusMenu *menu;
 @property (strong) StatusItemButton* statusBarButton;
 @property (strong) NSUserDefaults *userPreferences;
 @property (strong, nonatomic) NSImage * image;
@@ -81,7 +101,7 @@ inline std::vector<std::string> globVector(const std::string& pattern){
 - (void) statusItemButtonRightClick: (StatusItemButton *) button;
 - (void) statusBarImageBtnClicked;
 - (void) btnPressedAction:(id)sender;
-- (void) menuWillOpen:(NSMenu *)menu;
+- (void) menuWillOpen:(I2PStatusMenu *)menu;
 
 - (void) openRouterConsoleBtnHandler: (NSMenuItem *) menuItem;
 - (void) startJavaRouterBtnHandler: (NSMenuItem *) menuItem;
@@ -91,7 +111,7 @@ inline std::vector<std::string> globVector(const std::string& pattern){
 // Methods
 - (MenuBarCtrl *) init;
 - (void) dealloc;
-- (NSMenu *) createStatusBarMenu;
+- (I2PStatusMenu *) createStatusBarMenu;
 @end
 
 @protocol MenuBarCtrlDelegate
@@ -106,9 +126,10 @@ inline std::vector<std::string> globVector(const std::string& pattern){
 @property (strong) NSUserDefaults *userPreferences;
 @property BOOL enableLogging;
 @property BOOL enableVerboseLogging;
+@property ExtractMetaInfo *metaInfo;
 @property (copy) NSImage *contentImage NS_AVAILABLE(10_9, NA);
-- (void)extractI2PBaseDir:(ExtractMetaInfo *)metaInfo completion:(void(^)(BOOL success, NSError *error))completion;
-- (void)startupI2PRouter:(ExtractMetaInfo *)metaInfo;
+- (void)extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion;
+- (void)startupI2PRouter;
 - (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
 - (void)applicationWillTerminate:(NSNotification *)aNotification;
 - (void)setApplicationDefaultPreferences;
@@ -120,57 +141,4 @@ inline std::vector<std::string> globVector(const std::string& pattern){
 @end
 
 
-/*
-
-
-@implementation CNSStatusBarCtrl
--(id)initWithSysTray:(I2PCtrlSysIcon *)sys
-{
-  self = [super init];
-  if (self) {
-    item = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain];
-    menu = 0;
-    systray = sys;
-    imageCell = [[NSImageView alloc] initWithParent:self];
-    [item setView: imageCell];
-    [item setHidden: NO];
-    CFShow(CFSTR("CNSStatusBarCtrl::initWithSysTray executed"));
-  }
-  return self;
-}
--(NSStatusItem*)item {
-    return item;
-}
--(void)dealloc {
-  [[NSStatusBar systemStatusBar] removeStatusItem:item];
-  [[NSNotificationCenter defaultCenter] removeObserver:imageCell];
-  [imageCell release];
-  [item release];
-  [super dealloc];
-}
-@end
-
-
-class CSystemTrayIcon
-{
-public:
-  CSystemTrayIcon(I2PCtrlSysIcon *sys)
-  {
-    item = [[CNSStatusBarCtrl alloc] initWithSysTray:sys];
-    [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item];
-    const int menuHeight = [[NSStatusBar systemStatusBar] thickness];
-    printf("menuHeight: %d\n", menuHeight);
-    [[[item item] view] setHidden: NO];
-  }
-  ~CSystemTrayIcon()
-  {
-    [[[item item] view] setHidden: YES];
-    [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
-    [item release];
-  }
-  CNSStatusBarCtrl *item;
-};
-*/
-
-
 #endif
diff --git a/launchers/macosx/obj-cpp/Info.plist b/launchers/macosx/obj-cpp/Info.plist
index 79a7a00dad28307e312ce71d4582064a6dc146e4..1e0372a288fb991f6730d6db16250405029dbbed 100644
--- a/launchers/macosx/obj-cpp/Info.plist
+++ b/launchers/macosx/obj-cpp/Info.plist
@@ -11,7 +11,7 @@
 	<key>CFBundleGetInfoString</key>
 	<string>0.9.35-experimental</string>
 	<key>CFBundleIconFile</key>
-	<string>i2p</string>
+	<string>images/AppIcon.icns</string>
 	<key>CFBundleIdentifier</key>
 	<string>net.i2p.launcher</string>
 	<key>CFBundleInfoDictionaryVersion</key>
diff --git a/launchers/macosx/obj-cpp/PidWatcher.h b/launchers/macosx/obj-cpp/PidWatcher.h
index acb79673ccc59f5bedc2438e81752bedc65cb303..7cac1c858c42fe9c88600069f8b99e62c0124bc9 100644
--- a/launchers/macosx/obj-cpp/PidWatcher.h
+++ b/launchers/macosx/obj-cpp/PidWatcher.h
@@ -3,33 +3,12 @@
 #include <CoreFoundation/CoreFoundation.h>
 #include <unistd.h>
 #include <sys/event.h>
-#include <functional>
 
 #include "neither/either.hpp"
 #include "AppDelegate.h"
 
 using callbackType = void (CFFileDescriptorRef, CFOptionFlags, void *);
 using HandleFunction = std::function<void(int)>;
-/*
-class CallbackWrapper
-{
-    CallbackWrapper(HandleFunction func) : mCallback(func);
-    void operator(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) {
-        struct kevent kev;
-        int fd = CFFileDescriptorGetNativeDescriptor(fdref);
-        kevent(fd, NULL, 0, &kev, 1, NULL);
-        // take action on death of process here
-        NSLog(@"process with pid '%u' died\n", (unsigned int)kev.ident);
-
-        mCallback(0);
-        CFFileDescriptorInvalidate(fdref);
-        CFRelease(fdref);
-    }
-
-private:
-    HandleFunction mCallback;
-};
-*/
 
 static void noteProcDeath(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) {
     struct kevent kev;
diff --git a/launchers/macosx/obj-cpp/RouterTask.h b/launchers/macosx/obj-cpp/RouterTask.h
index 9c29a1d521fda4dc13757a1f15f699662381ba2f..2f5436e38f3cd8aff53910f284341395596838da 100644
--- a/launchers/macosx/obj-cpp/RouterTask.h
+++ b/launchers/macosx/obj-cpp/RouterTask.h
@@ -14,22 +14,21 @@
 
 
 @class RTaskOptions;
-
 @interface RTaskOptions : NSObject
 @property (strong) NSString* binPath;
 @property (strong) NSArray<NSString *>* arguments;
 @property (strong) NSString* i2pBaseDir;
 @end
 
-@class RouterTask;
-
-@interface RouterTask : NSObject
+@class I2PRouterTask;
+@interface I2PRouterTask : NSObject
 @property (strong) NSTask* routerTask;
 @property (strong) NSUserDefaults *userPreferences;
 @property (strong) NSFileHandle *readLogHandle;
 @property (strong) NSMutableData *totalLogData;
 @property (strong) NSPipe *processPipe;
 @property (strong) NSFileHandle *input;
+@property (atomic) BOOL isRouterRunning;
 @property (atomic) BOOL userRequestedRestart;
 - (instancetype) initWithOptions : (RTaskOptions*) options;
 - (int) execute;
@@ -37,6 +36,7 @@
 - (void) requestRestart;
 - (BOOL) isRunning;
 - (int) getPID;
+- (void)routerStdoutData:(NSNotification *)notification;
 @end
 
 
@@ -48,6 +48,8 @@ class JavaRunner;
 typedef std::function<void(void)> fp_t;
 typedef std::function<void(JavaRunner *ptr)> fp_proc_t;
 
+
+
 /**
  *
  * class JavaRunner
diff --git a/launchers/macosx/obj-cpp/RouterTask.mm b/launchers/macosx/obj-cpp/RouterTask.mm
index fb54ead119f6ce873348c03c5d8c88730bfa9b00..f12be635da77dbbe7f82c7f547d3b6f13e93307f 100644
--- a/launchers/macosx/obj-cpp/RouterTask.mm
+++ b/launchers/macosx/obj-cpp/RouterTask.mm
@@ -13,12 +13,19 @@
 @implementation RTaskOptions
 @end
 
-@implementation RouterTask
+@implementation I2PRouterTask
 
 
+- (void)routerStdoutData:(NSNotification *)notification
+{
+    NSLog(@"%@", [[NSString alloc] initWithData:[notification.object availableData] encoding:NSUTF8StringEncoding]);
+    [notification.object waitForDataInBackgroundAndNotify];
+}
+
 - (instancetype) initWithOptions : (RTaskOptions*) options
 {
-    self.userRequestedRestart = FALSE;
+    self.userRequestedRestart = NO;
+    self.isRouterRunning = NO;
     self.input = [NSFileHandle fileHandleWithStandardInput];
     self.routerTask = [NSTask new];
     self.processPipe = [NSPipe new];
@@ -30,8 +37,22 @@
     [self.routerTask setEnvironment: envDict];
     [self.routerTask setStandardOutput:self.processPipe];
 	[self.routerTask setStandardError:self.processPipe];
+
+    NSFileHandle *stdoutFileHandle = [self.processPipe fileHandleForReading];
+    [[NSNotificationCenter defaultCenter] addObserver:self
+        selector:@selector(routerStdoutData:)
+        name:NSFileHandleDataAvailableNotification
+        object:stdoutFileHandle];
+
+    [stdoutFileHandle waitForDataInBackgroundAndNotify];
+
     [self.routerTask setTerminationHandler:^(NSTask* task) {
         NSLog(@"termHandler triggered!");
+        NSBundle *launcherBundle = [NSBundle mainBundle];
+        auto iconImage = [launcherBundle pathForResource:@"ItoopieTransparent" ofType:@"png"];
+        sendUserNotification(APP_IDSTR, @"I2P Router has stopped", [NSImage imageNamed:iconImage]);
+        // Cleanup
+        self.isRouterRunning = NO;
     }];
 /*
     self.readLogHandle = [self.processPipe fileHandleForReading];
@@ -53,7 +74,8 @@
 
 - (void) requestRestart
 {
-    self.userRequestedRestart = TRUE;
+    self.userRequestedRestart = YES;
+    kill([self.routerTask processIdentifier], SIGHUP);
 }
 
 - (BOOL) isRunning
@@ -63,35 +85,17 @@
 
 - (int) execute
 {
-    //@try {
+    @try {
         [self.routerTask launch];
         watchPid([self.routerTask processIdentifier]);
-        [self.input waitForDataInBackgroundAndNotify];
-        [[self.processPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
-        [[NSNotificationCenter defaultCenter] addObserverForName:NSFileHandleDataAvailableNotification
-                                                          object:[self.processPipe fileHandleForReading] queue:nil
-                                                      usingBlock:^(NSNotification *note)
-         {
-             // Read from shell output
-             NSData *outData = [[self.processPipe fileHandleForReading] availableData];
-             NSString *outStr = [[NSString alloc] initWithData:outData encoding:NSUTF8StringEncoding];
-             if ([outStr length] > 1) {
-                 NSLog(@"output: %@", outStr);
-             }
-
-             // Continue waiting for shell output.
-             [[self.processPipe fileHandleForReading] waitForDataInBackgroundAndNotify];
-         }];
-         //[self.routerTask waitUntilExit];
-        //NSThread *thr = [[NSThread alloc] initWithTarget:self.routerTask selector:@selector(launch) object:nil];
-        //[self.routerTask waitUntilExit];
+        self.isRouterRunning = YES;
         return 1;
-    /*}
+    }
     @catch (NSException *e)
 	{
 		NSLog(@"Expection occurred %@", [e reason]);
         return 0;
-	}*/
+	}
 }
 
 - (int) getPID
diff --git a/launchers/macosx/obj-cpp/StatusItemButton.h b/launchers/macosx/obj-cpp/StatusItemButton.h
index e38ca53038a7a2e436885c81a53d5e0e630bc132..93086f5e4fb0870658fa7a6ef1870d40d032d30e 100644
--- a/launchers/macosx/obj-cpp/StatusItemButton.h
+++ b/launchers/macosx/obj-cpp/StatusItemButton.h
@@ -2,6 +2,12 @@
 
 #import <Cocoa/Cocoa.h>
 
+/**
+ *
+ * This is a class representing the "image" in the systray.
+ *
+ *
+ * **/
 @class StatusItemButton;
 
 @protocol StatusItemButtonDelegate <NSObject>
diff --git a/launchers/macosx/obj-cpp/main.mm b/launchers/macosx/obj-cpp/main.mm
index e5f6583227f70f47471fe88941b5f642d307f040..9a64c4796e2034ab54062f6f01380720e7f6691f 100644
--- a/launchers/macosx/obj-cpp/main.mm
+++ b/launchers/macosx/obj-cpp/main.mm
@@ -30,6 +30,7 @@
 #include "JavaHelper.h"
 #include "fn.h"
 #include "optional.hpp"
+#include "portcheck.h"
 
 #define debug(format, ...) CFShow([NSString stringWithFormat:format, ## __VA_ARGS__]);
 
@@ -42,6 +43,10 @@ JvmListSharedPtr gRawJvmList = nullptr;
 @interface AppDelegate () <NSUserNotificationCenterDelegate, NSApplicationDelegate>
 @end
 
+std::vector<std::string> buildClassPath(std::string basePath)
+{
+    return globVector(basePath+std::string("/lib/*.jar"));
+}
 
 maybeAnRouterRunner getGlobalRouterObject()
 {
@@ -49,44 +54,36 @@ maybeAnRouterRunner getGlobalRouterObject()
     return globalRouterStatus;
 }
 
-void setGlobalRouterObject(RouterTask* newRouter)
+void setGlobalRouterObject(I2PRouterTask* newRouter)
 {
     std::lock_guard<std::mutex> lock(globalRouterStatusMutex);
     globalRouterStatus.emplace(newRouter);
 }
 
-std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir) {
-/*
-  NSLog(@"Arguments: %@", [NSString stringWithUTF8String:arguments.c_str()]);
-  auto launchLambda = [](JavaRunner *javaRun) {
-    javaRun->javaProcess->start_process();
-    auto pid = javaRun->javaProcess->pid();
-    std::cout << "I2P Router process id = " << pid << std::endl;
-
-    // Blocking
-    javaRun->javaProcess->wait();
-  };
-  auto callbackAfterExit = [](){
-    printf("Callback after exit\n");
-  };
-  NSLog(@"Still fine!");
 
-  setGlobalRouterObject(new JavaRunner{ javaBin, arguments, i2pBaseDir, std::move(launchLambda), std::move(callbackAfterExit) });
+pthread_mutex_t mutex;
 
-  NSLog(@"Still fine!");
-  return std::async(std::launch::async, [&]{
-      getGlobalRouterObject().value()->execute();
-      return 0;
-    });
-*/
-    //CFShow(arguments);
+bool getGlobalRouterIsRunning()
+{
+    pthread_mutex_lock(&mutex);
+    bool current = isRuterRunning;
+    pthread_mutex_unlock(&mutex);
+    return current;
+}
+void setGlobalRouterIsRunning(bool running)
+{
+    pthread_mutex_lock(&mutex);
+    isRuterRunning = running;
+    pthread_mutex_unlock(&mutex);
+}
 
+std::future<int> startupRouter(NSString* javaBin, NSArray<NSString*>* arguments, NSString* i2pBaseDir) {
     @try {
         RTaskOptions* options = [RTaskOptions alloc];
         options.binPath = javaBin;
         options.arguments = arguments;
         options.i2pBaseDir = i2pBaseDir;
-        auto instance = [[[RouterTask alloc] initWithOptions: options] autorelease];
+        auto instance = [[[I2PRouterTask alloc] initWithOptions: options] autorelease];
         setGlobalRouterObject(instance);
         //NSThread *thr = [[NSThread alloc] initWithTarget:instance selector:@selector(execute) object:nil];
         [instance execute];
@@ -112,6 +109,15 @@ void openUrl(NSString* url)
     [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString: url]];
 }
 
+@implementation I2PStatusMenu
+
+- (BOOL)validateMenuItem:(NSMenuItem *)item
+{
+  NSLog(@"item is: %@",item);
+  return YES;
+}
+
+@end
 
 @implementation MenuBarCtrl
 
@@ -148,6 +154,8 @@ void openUrl(NSString* url)
 - (void) startJavaRouterBtnHandler: (NSMenuItem *) menuItem
 {
   NSLog(@"Clicked startJavaRouterBtnHandler");
+  AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
+  [appDelegate startupI2PRouter];
 }
 
 - (void) restartJavaRouterBtnHandler: (NSMenuItem *) menuItem
@@ -210,9 +218,9 @@ void openUrl(NSString* url)
   [self.menu release];
 }
 
-- (NSMenu *)createStatusBarMenu
+- (I2PStatusMenu *)createStatusBarMenu
 {
-  NSMenu *menu = [[NSMenu alloc] init];
+  I2PStatusMenu *menu = [[I2PStatusMenu alloc] init];
   [menu setAutoenablesItems:NO];
 
   NSMenuItem *openConsoleI2Pbtn =
@@ -271,10 +279,10 @@ void openUrl(NSString* url)
 
 @implementation AppDelegate
 
-- (void)extractI2PBaseDir:(ExtractMetaInfo *)metaInfo completion:(void(^)(BOOL success, NSError *error))completion
+- (void)extractI2PBaseDir:(void(^)(BOOL success, NSError *error))completion
 {
-  std::string basePath([metaInfo.i2pBase UTF8String]);
-  NSParameterAssert(metaInfo.i2pBase);
+  std::string basePath([self.metaInfo.i2pBase UTF8String]);
+  NSParameterAssert(self.metaInfo.i2pBase);
   NSError *error = NULL;
   BOOL success;
   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@@ -286,10 +294,10 @@ void openUrl(NSString* url)
     basearg += basePath;
 
     std::string zippath("-Di2p.base.zip=");
-    zippath += [metaInfo.zipFile UTF8String];
+    zippath += [self.metaInfo.zipFile UTF8String];
 
     std::string jarfile("-cp ");
-    jarfile += [metaInfo.jarFile UTF8String];
+    jarfile += [self.metaInfo.jarFile UTF8String];
 
     // Create directory
     mkdir(basePath.c_str(), S_IRUSR | S_IWUSR | S_IXUSR);
@@ -305,7 +313,7 @@ void openUrl(NSString* url)
     cli.push_back("net.i2p.launchers.BaseExtractor");
 
     //auto charCli = map(cli, [](std::string str){ return str.c_str(); });
-    std::string execStr = [metaInfo.javaBinary UTF8String];
+    std::string execStr = [self.metaInfo.javaBinary UTF8String];
     for_each(cli, [&execStr](std::string str){ execStr += std::string(" ") + str; });
 
     NSLog(@"Trying cmd: %@", [NSString stringWithUTF8String:execStr.c_str()]);
@@ -337,16 +345,12 @@ void openUrl(NSString* url)
   });
 }
 
-- (void)startupI2PRouter:(ExtractMetaInfo *)metaInfo
+- (void)startupI2PRouter
 {
-  std::string basePath([metaInfo.i2pBase UTF8String]);
-  auto buildClassPath = [](std::string basePath) -> std::vector<std::string> {
-      return globVector(basePath+std::string("/lib/*.jar"));
-  };
-    // Expect base to be extracted by now.
+  std::string basePath([self.metaInfo.i2pBase UTF8String]);
 
-    // Get paths
-    NSBundle *launcherBundle = [NSBundle mainBundle];
+  // Get paths
+  NSBundle *launcherBundle = [NSBundle mainBundle];
   auto jarList = buildClassPath(basePath);
   std::string classpathStrHead = "-classpath";
   std::string classpathStr = "";
@@ -371,12 +375,12 @@ void openUrl(NSString* url)
     argList.push_back([NSString stringWithUTF8String:classpathStrHead.c_str()]);
     argList.push_back([NSString stringWithUTF8String:classpathStr.c_str()]);
     argList.push_back(@"net.i2p.router.Router");
-    auto javaBin = std::string([metaInfo.javaBinary UTF8String]);
+    auto javaBin = std::string([self.metaInfo.javaBinary UTF8String]);
 
 
     sendUserNotification(APP_IDSTR, @"I2P Router is starting up!", self.contentImage);
-    auto nsJavaBin = metaInfo.javaBinary;
-    auto nsBasePath = metaInfo.i2pBase;
+    auto nsJavaBin = self.metaInfo.javaBinary;
+    auto nsBasePath = self.metaInfo.i2pBase;
     NSArray* arrArguments = [NSArray arrayWithObjects:&argList[0] count:argList.size()];
     startupRouter(nsJavaBin, arrArguments, nsBasePath);
     //if (self.enableVerboseLogging) NSLog(@"Defaults: %@", [pref dictionaryRepresentation]);
@@ -434,7 +438,8 @@ void openUrl(NSString* url)
     @"lastI2PVersion" : (NSString *)CFSTR(DEF_I2P_VERSION),
     @"enableLogging": @true,
     @"enableVerboseLogging": @true,
-    @"autoStartRouter": @true
+    @"autoStartRouter": @true,
+    @"i2pBaseDirectory": (NSString *)CFStringCreateWithCString(NULL, const_cast<const char *>(getDefaultBaseDir().c_str()), kCFStringEncodingUTF8)
   }];
   if (self.enableVerboseLogging) NSLog(@"Default JVM home preference set to: %@", (NSString *)cfDefaultHome);
 
@@ -468,12 +473,9 @@ void openUrl(NSString* url)
   // In case we are unbundled, make us a proper UI application
   [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];
   [NSApp activateIgnoringOtherApps:YES];
-  //auto prefArray = CFPreferencesCopyKeyList(CFAPPDOMAIN, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost);
-  //CFShow(prefArray);
   auto javaHomePref = [self.userPreferences stringForKey:@"javaHome"];
   if (self.enableVerboseLogging) NSLog(@"Java home from preferences: %@", javaHomePref);
 
-
   // This is the only GUI the user experience on a regular basis.
   self.menuBarCtrl = [[MenuBarCtrl alloc] init];
 
@@ -482,13 +484,8 @@ void openUrl(NSString* url)
 
   NSLog(@"We should have started the statusbar object by now...");
 
-  // Figure out base directory
-  const char* pathFromHome = "/Users/%s/Library/I2P";
-  auto username = getenv("USER");
-  char buffer[strlen(pathFromHome)+strlen(username)];
-  sprintf(buffer, pathFromHome, username);
-  std::string i2pBaseDir(buffer);
-  if (self.enableVerboseLogging) printf("Home directory is: %s\n", buffer);
+  std::string i2pBaseDir(getDefaultBaseDir());
+  //if (self.enableVerboseLogging) printf("Home directory is: %s\n", buffer);
 
 
   //[statusBarButton setAction:@selector(itemClicked:)];
@@ -499,57 +496,57 @@ void openUrl(NSString* url)
   self.menuBarCtrl.enableLogging = self.enableLogging;
   self.menuBarCtrl.enableVerboseLogging = self.enableVerboseLogging;
 
-  if (self.enableVerboseLogging) NSLog(@"processinfo %@", [[NSProcessInfo processInfo] arguments]);
 
-  auto getJavaHomeLambda = [&pref,&self]() -> std::string {
-      NSString* val = @"";
-      val = [pref stringForKey:@"javaHome"];
-      if (val == NULL) val = @"";
-      if (self.enableVerboseLogging) NSLog(@"Javahome: %@", val);
-      return std::string([val UTF8String]);;
-  };
 
-  auto getJavaBin = [&getJavaHomeLambda]() -> std::string {
-      // Get Java home
-    auto javaHome = getJavaHomeLambda();
+  if (port_check() != 0)
+  {
+    NSLog(@"Seems i2p is already running - I will not start the router (port 7657 is in use..)");
+    return;
+  }
+
+  if (self.enableVerboseLogging) NSLog(@"processinfo %@", [[NSProcessInfo processInfo] arguments]);
+
+  auto getJavaBin = [&pref,&self]() -> std::string {
+    // Get Java home
+    NSString* val = @"";
+    val = [pref stringForKey:@"javaHome"];
+    if (val == NULL) val = @"";
+    if (self.enableVerboseLogging) NSLog(@"Javahome: %@", val);
+    auto javaHome = std::string([val UTF8String]);
     trim(javaHome); // Trim to remove endline
     auto javaBin = std::string(javaHome);
     javaBin += "/bin/java"; // Append java binary to path.
     return javaBin;
   };
 
-  auto buildClassPath = [](std::string basePath) -> std::vector<std::string> {
-      return globVector(basePath+std::string("/lib/*.jar"));
-  };
-
 
-  auto metaInfo = [ExtractMetaInfo alloc];
-  metaInfo.i2pBase = [NSString stringWithUTF8String:buffer];
-  metaInfo.javaBinary = [NSString stringWithUTF8String:getJavaBin().c_str()];
-  metaInfo.jarFile = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
-  metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
+  self.metaInfo = [[ExtractMetaInfo alloc] init];
+  self.metaInfo.i2pBase = [NSString stringWithUTF8String:i2pBaseDir.c_str()];
+  self.metaInfo.javaBinary = [NSString stringWithUTF8String:getJavaBin().c_str()];
+  self.metaInfo.jarFile = [launcherBundle pathForResource:@"launcher" ofType:@"jar"];
+  self.metaInfo.zipFile = [launcherBundle pathForResource:@"base" ofType:@"zip"];
 
   std::string basearg("-Di2p.dir.base=");
   basearg += i2pBaseDir;
 
   std::string jarfile("-cp ");
-  jarfile += [metaInfo.zipFile UTF8String];
+  jarfile += [self.metaInfo.zipFile UTF8String];
 
   struct stat sb;
-  if ( !(stat(buffer, &sb) == 0 && S_ISDIR(sb.st_mode)) )
+  if ( !(stat(i2pBaseDir.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode)) )
   {
     // I2P is not extracted.
     if (self.enableVerboseLogging) NSLog(@"I2P Directory don't exists!");
 
-    [self extractI2PBaseDir: metaInfo completion:^(BOOL success, NSError *error) {
+    [self extractI2PBaseDir:^(BOOL success, NSError *error) {
         //__typeof__(self) strongSelf = weakSelf;
         //if (strongSelf == nil) return;
-        [self startupI2PRouter:metaInfo];
+        [self startupI2PRouter];
     }];
 
   } else {
       if (self.enableVerboseLogging) NSLog(@"I2P directory found!");
-      [self startupI2PRouter:metaInfo];
+      [self startupI2PRouter];
   }
 
 }
diff --git a/launchers/macosx/obj-cpp/portcheck.h b/launchers/macosx/obj-cpp/portcheck.h
new file mode 100644
index 0000000000000000000000000000000000000000..fd7838c952a80a3d3ee944aecf51352862bf178d
--- /dev/null
+++ b/launchers/macosx/obj-cpp/portcheck.h
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <errno.h>
+
+typedef struct sockaddr *sad; /* A necesary dummy typedef */
+
+
+int port_check(int portNum=7657)
+{
+int sock; /* Socket that will be bind */
+struct sockaddr_in sin; /* Address Structure */
+
+/* Create the socket */
+/* PF_INET is the option for make a TCP socket.
+        You can try "man socket" for more info */
+sock = socket( PF_INET, SOCK_STREAM, 0 );
+
+/* The socket creation failed */
+if ( 0 > sock ) {
+  perror( "socket" );
+  return ( -1 );
+}
+
+/* Address */
+sin.sin_family = AF_INET;
+sin.sin_port = htons( portNum ); /* htons() convert the number
+                                                      to big endian */
+sin.sin_addr.s_addr = INADDR_ANY;
+
+/* We bind the socket to the port PORT to check if
+          the port is in use */
+if ( 0 > bind( sock, (sad)&sin, sizeof( sin ) ) ) {
+  /* Bind failed, now we can check if the address is
+                in use */
+
+  if ( EADDRINUSE == errno ) {
+  /* We put the code necesary to manage this case */
+  printf( "The TCP port %d is in use.\n", portNum );
+  }
+
+  else
+  /* If the error were other than EADDRINUSE, we print it */
+  perror( "bind" );
+
+  return 1;
+}
+
+/* If we arrive to this point, the port weren't in use and
+          we have it attached to our program. We can close
+          the socket or use it */
+close( sock ); /* Close the socket */
+
+return 0;
+}