source: launchers/macosx/RouterTask.mm @ c3b8317

Last change on this file since c3b8317 was dfcc616, checked in by meeh <meeh@…>, 20 months ago

Mac OS X Launcher: Misc changes in ObjC, forwarding sendUserNotification to Swift.

  • Property mode set to 100644
File size: 5.5 KB
Line 
1#include "RouterTask.h"
2
3#include <dispatch/dispatch.h>
4#include <future>
5#include <stdlib.h>
6
7#ifdef __cplusplus
8#include "include/subprocess.hpp"
9#import "I2PLauncher-Swift.h"
10#include "AppDelegate.h"
11
12#include <assert.h>
13#include <errno.h>
14#include <stdbool.h>
15#include <sys/sysctl.h>
16#endif
17
18#include "include/PidWatcher.h"
19
20#import <AppKit/AppKit.h>
21#import <Foundation/Foundation.h>
22
23@implementation RTaskOptions
24@end
25
26@implementation I2PRouterTask
27
28- (void)routerStdoutData:(NSNotification *)notification
29{
30    NSLog(@"%@", [[NSString alloc] initWithData:[notification.object availableData] encoding:NSUTF8StringEncoding]);
31    [notification.object waitForDataInBackgroundAndNotify];
32}
33
34- (instancetype) initWithOptions : (RTaskOptions*) options
35{
36  self.userRequestedRestart = NO;
37  self.isRouterRunning = NO;
38  self.routerTask = [NSTask new];
39  self.processPipe = [NSPipe new];
40  [self.routerTask setLaunchPath:options.binPath];
41  [self.routerTask setArguments:options.arguments];
42  NSDictionary *envDict = @{
43    @"I2PBASE": options.i2pBaseDir
44  };
45  [self.routerTask setEnvironment: envDict];
46  NSLog(@"Using environment variables: %@", envDict);
47  [self.routerTask setStandardOutput:self.processPipe];
48        [self.routerTask setStandardError:self.processPipe];
49
50  [self.routerTask setTerminationHandler:^(NSTask* task) {
51    // Cleanup
52    NSLog(@"termHandler triggered!");
53    [[[RouterProcessStatus alloc] init] triggerEventWithEn:@"router_stop" details:@"normal shutdown"];
54    [[SBridge sharedInstance] setCurrentRouterInstance:nil];
55    sendUserNotification(APP_IDSTR, @"I2P Router has stopped");
56  }];
57  return self;
58}
59
60- (void) requestShutdown
61{
62    [self.routerTask interrupt];
63}
64
65- (void) requestRestart
66
67{    self.userRequestedRestart = YES;
68    kill([self.routerTask processIdentifier], SIGHUP);
69}
70
71- (BOOL) isRunning
72{
73    return self.routerTask.running;
74}
75
76- (int) execute
77{
78    @try {
79      [self.routerTask launch];
80      self.isRouterRunning = YES;
81      return 1;
82    }
83    @catch (NSException *e)
84        {
85                NSLog(@"Expection occurred %@", [e reason]);
86    self.isRouterRunning = NO;
87   
88    [[[RouterProcessStatus alloc] init] triggerEventWithEn:@"router_exception" details:[e reason]];
89   
90    [[SBridge sharedInstance] setCurrentRouterInstance:nil];
91    sendUserNotification(@"An error occured, can't start the I2P Router", [e reason]);
92    return 0;
93        }
94}
95
96- (int) getPID
97{
98  return [self.routerTask processIdentifier];
99}
100
101@end
102
103typedef struct kinfo_proc kinfo_proc;
104
105@implementation IIProcessInfo
106- (id) init
107{
108  self = [super init];
109  if (self != nil)
110  {
111    numberOfProcesses = -1; // means "not initialized"
112    processList = NULL;
113  }
114  return self;
115}
116
117- (int)numberOfProcesses
118{
119  return numberOfProcesses;
120}
121
122- (void)setNumberOfProcesses:(int)num
123{
124  numberOfProcesses = num;
125}
126
127- (int)getBSDProcessList:(kinfo_proc **)procList
128   withNumberOfProcesses:(size_t *)procCount
129{
130#ifdef __cplusplus
131  int             err;
132  kinfo_proc *    result;
133  bool            done;
134  static const int    name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
135  size_t          length;
136 
137  // a valid pointer procList holder should be passed
138  assert( procList != NULL );
139  // But it should not be pre-allocated
140  assert( *procList == NULL );
141  // a valid pointer to procCount should be passed
142  assert( procCount != NULL );
143 
144  *procCount = 0;
145  result = NULL;
146  done = false;
147 
148  do
149  {
150    assert( result == NULL );
151   
152    // Call sysctl with a NULL buffer to get proper length
153    length = 0;
154    err = sysctl((int *)name,(sizeof(name)/sizeof(*name))-1,NULL,&length,NULL,0);
155    if( err == -1 )
156      err = errno;
157   
158    // Now, proper length is optained
159    if( err == 0 )
160    {
161      result = (kinfo_proc *)malloc(length);
162      if( result == NULL )
163        err = ENOMEM;   // not allocated
164    }
165   
166    if( err == 0 )
167    {
168      err = sysctl( (int *)name, (sizeof(name)/sizeof(*name))-1, result, &length, NULL, 0);
169      if( err == -1 )
170        err = errno;
171     
172      if( err == 0 )
173        done = true;
174      else if( err == ENOMEM )
175      {
176        assert( result != NULL );
177        free( result );
178        result = NULL;
179        err = 0;
180      }
181    }
182  }while ( err == 0 && !done );
183 
184  // Clean up and establish post condition
185  if( err != 0 && result != NULL )
186  {
187    free(result);
188    result = NULL;
189  }
190 
191  *procList = result; // will return the result as procList
192  if( err == 0 )
193    *procCount = length / sizeof( kinfo_proc );
194  assert( (err == 0) == (*procList != NULL ) );
195  return err;
196}
197
198- (void)obtainFreshProcessList
199{
200  int i;
201  kinfo_proc *allProcs = 0;
202  size_t numProcs;
203  NSString *procName;
204 
205  int err =  [self getBSDProcessList:&allProcs withNumberOfProcesses:&numProcs];
206  if( err )
207  {
208    numberOfProcesses = -1;
209    processList = NULL;
210   
211    return;
212  }
213 
214  // Construct an array for ( process name, pid, arguments concat'ed )
215  processList = [NSMutableArray arrayWithCapacity:numProcs];
216  for( i = 0; i < numProcs; i++ )
217  {
218    int pid = (int)allProcs[i].kp_proc.p_pid;
219    procName = [NSString stringWithFormat:@"%s, pid %d, args: %s", allProcs[i].kp_proc.p_comm, pid, getArgvOfPid(pid).c_str()];
220    [processList addObject:procName];
221  }
222 
223  [self setNumberOfProcesses:(int)numProcs];
224  free( allProcs );
225#endif
226}
227
228
229- (BOOL)findProcessWithStringInNameOrArguments:(NSString *)procNameToSearch
230{
231  BOOL seenProcessThatMatch = NO;
232  for (NSString* processInfoStr in processList) {
233    if ([processInfoStr containsString:procNameToSearch]) {
234      seenProcessThatMatch = YES;
235      break;
236    }
237  }
238  return seenProcessThatMatch;
239}
240@end
Note: See TracBrowser for help on using the repository browser.