/// <summary> /// This function attempts to find out if there is currently a node running /// for a given index. The node is running if the global mutex with a /// "Node_" + nodeId + "_ActiveReady" as a name was created /// </summary> private static bool checkIfNodeActive(int nodeNumber) { bool nodeIsActive = false; EventWaitHandle nodeActiveHandle = null; try { nodeActiveHandle = EventWaitHandle.OpenExisting(LocalNodeProviderGlobalNames.NodeActiveEventName(nodeNumber)); nodeIsActive = true; } catch (WaitHandleCannotBeOpenedException) { // Assume that the node is not running } finally { if (nodeActiveHandle != null) { nodeActiveHandle.Close(); } } return(nodeIsActive); }
/// <summary> /// This function launches a new node given a node index /// </summary> private void LaunchNode(int nodeIndex) { EventWaitHandle nodeReadyEvent = null; string msbuildLocation = Path.Combine(locationOfMSBuildExe, "MSBuild.exe"); ErrorUtilities.VerifyThrow(File.Exists(msbuildLocation), "Msbuild.exe cannot be found at: " + msbuildLocation); bool exitedDueToError = true; try { NativeMethods.STARTUPINFO startInfo = new NativeMethods.STARTUPINFO(); startInfo.cb = Marshal.SizeOf(startInfo); uint dwCreationFlags = NativeMethods.NORMAL_PRIORITY_CLASS; if (!Engine.debugMode) { startInfo.hStdError = NativeMethods.InvalidHandle; startInfo.hStdInput = NativeMethods.InvalidHandle; startInfo.hStdOutput = NativeMethods.InvalidHandle; startInfo.dwFlags = NativeMethods.STARTF_USESTDHANDLES; dwCreationFlags = dwCreationFlags | NativeMethods.CREATE_NO_WINDOW; } NativeMethods.SECURITY_ATTRIBUTES pSec = new NativeMethods.SECURITY_ATTRIBUTES(); NativeMethods.SECURITY_ATTRIBUTES tSec = new NativeMethods.SECURITY_ATTRIBUTES(); pSec.nLength = Marshal.SizeOf(pSec); tSec.nLength = Marshal.SizeOf(tSec); NativeMethods.PROCESS_INFORMATION pInfo = new NativeMethods.PROCESS_INFORMATION(); string appName = msbuildLocation; // Repeat the executable name as the first token of the command line because the command line // parser logic expects it and will otherwise skip the first argument string cmdLine = msbuildLocation + " /nologo /oldom /nodemode:" + nodeData[nodeIndex].NodeNumber; NativeMethods.CreateProcess(appName, cmdLine, ref pSec, ref tSec, false, dwCreationFlags, NativeMethods.NullPtr, null, ref startInfo, out pInfo); nodeReadyEvent = new EventWaitHandle(false, EventResetMode.ManualReset, LocalNodeProviderGlobalNames.NodeActiveEventName(nodeData[nodeIndex].NodeNumber)); // Wait until the node is ready to process the requests if (nodeReadyEvent.WaitOne(launchTimeout, false)) { exitedDueToError = false; } } finally { // Dispose before losing scope if (nodeReadyEvent != null) { nodeReadyEvent.Close(); } if (exitedDueToError) { nodeData[nodeIndex].CommunicationFailed = true; } } }
/// <summary> /// Create global events necessary for handshaking with the parent /// </summary> /// <param name="nodeNumber"></param> /// <returns>True if events created successfully and false otherwise</returns> private static bool CreateGlobalEvents(int nodeNumber) { bool createdNew = false; if (NativeMethods.IsUserAdministrator()) { EventWaitHandleSecurity mSec = new EventWaitHandleSecurity(); // Add a rule that grants the access only to admins and systems mSec.SetSecurityDescriptorSddlForm(NativeMethods.ADMINONLYSDDL); // Create an initiation event to allow the parent side to prove to the child that we have the same level of privilege as it does. // this is done by having the parent set this event which means it needs to have administrative permissions to do so. globalInitiateActivationEvent = new EventWaitHandle(false, EventResetMode.ManualReset, LocalNodeProviderGlobalNames.NodeInitiateActivationEventName(nodeNumber), out createdNew, mSec); } else { // Create an initiation event to allow the parent side to prove to the child that we have the same level of privilege as it does. // this is done by having the parent set this event which means it has atleast the same permissions as the child process globalInitiateActivationEvent = new EventWaitHandle(false, EventResetMode.ManualReset, LocalNodeProviderGlobalNames.NodeInitiateActivationEventName(nodeNumber), out createdNew); } // This process must be the creator of the event to prevent squating by a lower privilaged attacker if (!createdNew) { return(false); } // Informs the parent process that the child process has been created. globalNodeActive = new EventWaitHandle(false, EventResetMode.ManualReset, LocalNodeProviderGlobalNames.NodeActiveEventName(nodeNumber)); globalNodeActive.Set(); // Indicate to the parent process, this node is currently is ready to start to recieve requests globalNodeInUse = new EventWaitHandle(false, EventResetMode.ManualReset, LocalNodeProviderGlobalNames.NodeInUseEventName(nodeNumber)); // Used by the parent process to inform the child process to shutdown due to the child process // not recieving the initialization command. globalNodeErrorShutdown = new EventWaitHandle(false, EventResetMode.ManualReset, LocalNodeProviderGlobalNames.NodeErrorShutdownEventName(nodeNumber)); // Inform the parent process the node has started its communication threads. globalNodeActivate = new EventWaitHandle(false, EventResetMode.ManualReset, LocalNodeProviderGlobalNames.NodeActivedEventName(nodeNumber)); return(true); }