/** Enterprise Control Configuration and Logging Copyright (C) 2014 Free Software Foundation, Inc. Written by: Richard Frith-Macdonald Date: March 2014 Originally developed from 1996 to 2012 by Brainstorm, and donated to the FSF. This file is part of the GNUstep project. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. */ #import #if !defined(EC_DEFAULTS_PREFIX) #define EC_DEFAULTS_PREFIX nil #endif #if !defined(EC_EFFECTIVE_USER) #define EC_EFFECTIVE_USER nil #endif #import "EcProcess.h" #import "EcUserDefaults.h" #import "EcHost.h" #import "EcTest.h" static NSUserDefaults* defaults() { static NSUserDefaults *defs = nil; if (nil == defs) { NSString *pref; NSDictionary *dict; pref = EC_DEFAULTS_PREFIX; if (nil == pref) { pref = @""; } ASSIGN(defs, [NSUserDefaults userDefaultsWithPrefix: pref]); dict = [defs dictionaryForKey: @"WellKnownHostNames"]; if (nil != dict) { [NSHost setWellKnownNames: dict]; } } return defs; } id EcTestConnect(NSString *name, NSString *host, NSTimeInterval timeout) { CREATE_AUTORELEASE_POOL(pool); BOOL triedLaunching = NO; id proxy = nil; NSUserDefaults *defs; NSDate *when; [EcProcess class]; defs = defaults(); if (nil == host) host = @""; if (timeout > 0) { when = [NSDate dateWithTimeIntervalSinceNow: timeout]; } else { when = [NSDate distantFuture]; } while (nil == proxy && [when timeIntervalSinceNow] > 0.0) { NS_DURING { proxy = (id)[NSConnection rootProxyForConnectionWithRegisteredName: name host: host usingNameServer: [NSSocketPortNameServer sharedInstance]]; } NS_HANDLER { proxy = nil; } NS_ENDHANDLER if (nil == proxy) { /* Where the initial contact attempt failed, * try launching the process. */ if (NO == triedLaunching) { NS_DURING { id cmd; NSString *cmdName; cmdName = [defs stringForKey: @"CommandName"]; if (nil == cmdName) { cmdName = @"Command"; } cmd = (id)[NSConnection rootProxyForConnectionWithRegisteredName: cmdName host: host usingNameServer: [NSSocketPortNameServer sharedInstance]]; [cmd launch: name]; } NS_HANDLER { NSLog(@"Failed to get 'Command' on '%@' to launch '%@': %@", host, name, localException); } NS_ENDHANDLER triedLaunching = YES; } [NSThread sleepForTimeInterval: 0.1]; } NS_DURING { if (YES == [(EcProcess*)proxy cmdIsClient]) { if (NO == [(EcProcess*)proxy ecDidAwakenCompletely]) { /* We must wait for the connected process to register * with the Command server (if it's not transient) and * configure itself and wake up. */ proxy = nil; [NSThread sleepForTimeInterval: 0.1]; } } } NS_HANDLER { NSLog(@"Failed to communicate with '%@': %@", name, localException); } NS_ENDHANDLER } [proxy retain]; DESTROY(pool); return [proxy autorelease]; } id EcTestGetConfig(id process, NSString *key) { id val; NSCAssert([key isKindOfClass: [NSString class]], NSInvalidArgumentException); [EcProcess class]; val = [process ecTestConfigForKey: key]; if (nil != val) { val = [NSPropertyListSerialization propertyListWithData: val options: NSPropertyListMutableContainers format: 0 error: 0]; } return val; } void EcTestSetConfig(id process, NSString *key, id value) { NSCAssert([key isKindOfClass: [NSString class]], NSInvalidArgumentException); [EcProcess class]; if (nil != value) { value = [NSPropertyListSerialization dataFromPropertyList: value format: NSPropertyListBinaryFormat_v1_0 errorDescription: 0]; } [process ecTestSetConfig: value forKey: key]; } BOOL EcTestShutdown(id process, NSTimeInterval timeout) { int pid; NSConnection *conn; NSDate *when; [EcProcess class]; conn = [(NSDistantObject*)process connectionForProxy]; if (NO == [conn isValid]) { [[conn sendPort] invalidate]; return NO; } pid = [(id)process processIdentifier]; [(id)process cmdQuit: 0]; if (timeout > 0) { when = [NSDate dateWithTimeIntervalSinceNow: timeout]; } else { when = [NSDate distantFuture]; } while ([conn isValid] && [when timeIntervalSinceNow] > 0.0) { NS_DURING [(id)process processIdentifier]; [NSThread sleepForTimeInterval: 0.1]; NS_HANDLER if ([conn isValid]) { [localException raise]; } NS_ENDHANDLER } if ([conn isValid]) { kill(pid, 9); [[conn sendPort] invalidate]; [conn invalidate]; return NO; } return YES; } BOOL EcTestShutdownByName(NSString *name, NSString *host, NSTimeInterval timeout) { NSPortNameServer *ns; NSPort *port; id proxy = nil; NSConnection *conn; NSDate *when; int pid; [EcProcess class]; if (nil == host) host = @""; if (timeout > 0) { when = [NSDate dateWithTimeIntervalSinceNow: timeout]; } else { when = [NSDate distantFuture]; } ns = [NSSocketPortNameServer sharedInstance]; port = [ns portForName: name onHost: host]; if (nil == port) { return YES; } NS_DURING { proxy = (id)[NSConnection rootProxyForConnectionWithRegisteredName: name host: host usingNameServer: ns]; } NS_HANDLER { proxy = nil; } NS_ENDHANDLER if (nil == proxy) { NSLog(@"Unable to contact %@ found on %@", name, port); return NO; } conn = [(NSDistantObject*)proxy connectionForProxy]; if (NO == [conn isValid]) { [[conn sendPort] invalidate]; return NO; } pid = [(id)proxy processIdentifier]; [(id)proxy cmdQuit: 0]; while ([conn isValid] && [when timeIntervalSinceNow] > 0.0) { NS_DURING [(id)proxy processIdentifier]; [NSThread sleepForTimeInterval: 0.1]; NS_HANDLER if ([conn isValid]) { [localException raise]; } NS_ENDHANDLER } if ([conn isValid]) { kill(pid, 9); [[conn sendPort] invalidate]; [conn invalidate]; return NO; } return YES; }