/Microsoft.Build/Microsoft.Build/Microsoft/Build/BackEnd/NodeEndpointOutOfProc.cs
C# | 369 lines | 351 code | 18 blank | 0 comment | 31 complexity | 5d498a880e98fd43271171150d5ffcaf MD5 | raw file
Possible License(s): Apache-2.0, LGPL-3.0
- namespace Microsoft.Build.BackEnd
- {
- using Microsoft.Build;
- using Microsoft.Build.Execution;
- using Microsoft.Build.Internal;
- using Microsoft.Build.Shared;
- using System;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Globalization;
- using System.IO;
- using System.IO.Pipes;
- using System.Runtime;
- using System.Runtime.InteropServices;
- using System.Security.AccessControl;
- using System.Security.Principal;
- using System.Threading;
-
- internal class NodeEndpointOutOfProc : INodeEndpoint
- {
- private object asyncDataMonitor;
- private const int ClientConnectTimeout = 0xea60;
- private IBuildComponentHost componentHost;
- private bool debugCommunications;
- private Utilities.LogDebugCommunications logDebugCommunications;
- private LinkStatusChangedDelegate OnLinkStatusChanged;
- private AutoResetEvent packetAvailable;
- private INodePacketFactory packetFactory;
- private Thread packetPump;
- private Queue<INodePacket> packetQueue;
- private const int PipeBufferSize = 0x20000;
- private NamedPipeServerStream pipeServer;
- private SharedReadBuffer sharedReadBuffer;
- private Microsoft.Build.BackEnd.LinkStatus status;
- private AutoResetEvent terminatePacketPump;
-
- public event LinkStatusChangedDelegate OnLinkStatusChanged
- {
- add
- {
- LinkStatusChangedDelegate delegate3;
- LinkStatusChangedDelegate onLinkStatusChanged = this.OnLinkStatusChanged;
- do
- {
- delegate3 = onLinkStatusChanged;
- LinkStatusChangedDelegate delegate4 = (LinkStatusChangedDelegate) Delegate.Combine(delegate3, value);
- onLinkStatusChanged = Interlocked.CompareExchange<LinkStatusChangedDelegate>(ref this.OnLinkStatusChanged, delegate4, delegate3);
- }
- while (onLinkStatusChanged != delegate3);
- }
- remove
- {
- LinkStatusChangedDelegate delegate3;
- LinkStatusChangedDelegate onLinkStatusChanged = this.OnLinkStatusChanged;
- do
- {
- delegate3 = onLinkStatusChanged;
- LinkStatusChangedDelegate delegate4 = (LinkStatusChangedDelegate) Delegate.Remove(delegate3, value);
- onLinkStatusChanged = Interlocked.CompareExchange<LinkStatusChangedDelegate>(ref this.OnLinkStatusChanged, delegate4, delegate3);
- }
- while (onLinkStatusChanged != delegate3);
- }
- }
-
- internal NodeEndpointOutOfProc(string pipeName, IBuildComponentHost host)
- {
- ErrorUtilities.VerifyThrowArgumentLength(pipeName, "pipeName");
- ErrorUtilities.VerifyThrowArgumentNull(host, "host");
- this.debugCommunications = Environment.GetEnvironmentVariable("MSBUILDDEBUGCOMM") == "1";
- this.status = Microsoft.Build.BackEnd.LinkStatus.Inactive;
- this.componentHost = host;
- this.asyncDataMonitor = new object();
- this.sharedReadBuffer = InterningBinaryReader.CreateSharedBuffer();
- SecurityIdentifier owner = WindowsIdentity.GetCurrent().Owner;
- PipeSecurity pipeSecurity = new PipeSecurity();
- PipeAccessRule rule = new PipeAccessRule(owner, PipeAccessRights.ReadWrite, AccessControlType.Allow);
- pipeSecurity.AddAccessRule(rule);
- pipeSecurity.SetOwner(owner);
- this.pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, 0x20000, 0x20000, pipeSecurity, HandleInheritability.None);
- this.logDebugCommunications = new Utilities.LogDebugCommunications(this.DebugCommunications);
- }
-
- private void ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus newStatus)
- {
- ErrorUtilities.VerifyThrow(this.status != newStatus, "Attempting to change status to existing status {0}.", this.status);
- this.status = newStatus;
- this.RaiseLinkStatusChanged(this.status);
- }
-
- public void Connect(INodePacketFactory factory)
- {
- ErrorUtilities.ThrowInternalError("Connect() not valid on the out of proc endpoint.", new object[0]);
- }
-
- private void DebugCommunications(string format, params object[] stuff)
- {
- if (this.debugCommunications)
- {
- lock (this)
- {
- string str = string.Format(CultureInfo.CurrentCulture, format, stuff);
- StreamWriter writer = new StreamWriter(string.Format(CultureInfo.CurrentCulture, Path.Combine(Path.GetTempPath(), "MSBuild_CommsTrace_{0}.txt"), new object[] { Process.GetCurrentProcess().Id }), true);
- writer.WriteLine(str);
- writer.Flush();
- writer.Close();
- }
- }
- }
-
- [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
- public void Disconnect()
- {
- this.InternalDisconnect();
- }
-
- private void EnqueuePacket(INodePacket packet)
- {
- ErrorUtilities.VerifyThrowArgumentNull(packet, "packet");
- ErrorUtilities.VerifyThrow(null != this.packetQueue, "packetQueue is null");
- ErrorUtilities.VerifyThrow(null != this.packetAvailable, "packetAvailable is null");
- lock (this.packetQueue)
- {
- this.packetQueue.Enqueue(packet);
- this.packetAvailable.Set();
- }
- }
-
- private void InitializeAsyncPacketThread()
- {
- lock (this.asyncDataMonitor)
- {
- this.packetPump = new Thread(new ThreadStart(this.PacketPumpProc));
- this.packetPump.IsBackground = true;
- this.packetPump.Name = "OutOfProc Endpoint Packet Pump";
- this.packetAvailable = new AutoResetEvent(false);
- this.terminatePacketPump = new AutoResetEvent(false);
- this.packetQueue = new Queue<INodePacket>();
- this.packetPump.Start();
- }
- }
-
- private void InternalDisconnect()
- {
- ErrorUtilities.VerifyThrow(this.packetPump.ManagedThreadId != Thread.CurrentThread.ManagedThreadId, "Can't join on the same thread.");
- this.terminatePacketPump.Set();
- this.packetPump.Join();
- this.terminatePacketPump.Close();
- this.pipeServer.Close();
- this.packetPump = null;
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Inactive);
- }
-
- public void Listen(INodePacketFactory factory)
- {
- ErrorUtilities.VerifyThrow(this.status == Microsoft.Build.BackEnd.LinkStatus.Inactive, "Link not inactive. Status is {0}", this.status);
- ErrorUtilities.VerifyThrowArgumentNull(factory, "factory");
- this.packetFactory = factory;
- this.InitializeAsyncPacketThread();
- }
-
- private void PacketPumpProc()
- {
- NamedPipeServerStream pipeServer = this.pipeServer;
- AutoResetEvent packetAvailable = this.packetAvailable;
- AutoResetEvent terminatePacketPump = this.terminatePacketPump;
- Queue<INodePacket> packetQueue = this.packetQueue;
- DateTime utcNow = DateTime.UtcNow;
- bool flag = false;
- while (!flag)
- {
- TimeSpan span = (TimeSpan) (DateTime.UtcNow - utcNow);
- int millisecondsTimeout = Math.Max(0, BuildParameters.NodeConnectionTimeout - ((int) span.TotalMilliseconds));
- IAsyncResult result = pipeServer.BeginWaitForConnection(null, null);
- this.DebugCommunications("Waiting for connection {0} ms...", new object[] { millisecondsTimeout });
- if (!result.AsyncWaitHandle.WaitOne(millisecondsTimeout, false))
- {
- this.DebugCommunications("Connection timed out waiting a host to contact us. Exiting comm thread.", new object[0]);
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.ConnectionFailed);
- return;
- }
- try
- {
- WindowsIdentity clientIdentity;
- this.DebugCommunications("Handshaking with host..", new object[0]);
- pipeServer.EndWaitForConnection(result);
- long num2 = pipeServer.ReadLongForHandshake(new byte[] { 0x5f, 0x60 }, 0xff, this.logDebugCommunications);
- WindowsIdentity current = WindowsIdentity.GetCurrent();
- pipeServer.GetImpersonationUserName();
- if (num2 != NodeProviderOutOfProc.HostHandshake)
- {
- this.DebugCommunications("Handshake failed. Received {0} from host not {1}. Probably the host is a different MSBuild build.", new object[] { num2, NodeProviderOutOfProc.HostHandshake });
- pipeServer.Disconnect();
- }
- else
- {
- clientIdentity = null;
- pipeServer.RunAsClient(delegate {
- clientIdentity = WindowsIdentity.GetCurrent(true);
- });
- if ((clientIdentity == null) || !string.Equals(clientIdentity.Name, current.Name, StringComparison.OrdinalIgnoreCase))
- {
- this.DebugCommunications("Handshake failed. Host user is {0} but we were created by {1}.", new object[] { (clientIdentity == null) ? "<unknown>" : clientIdentity.Name, current.Name });
- pipeServer.Disconnect();
- }
- else
- {
- flag = true;
- }
- }
- continue;
- }
- catch (Exception exception)
- {
- if (ExceptionHandling.IsCriticalException(exception))
- {
- throw;
- }
- this.DebugCommunications("Client connection failed. Exiting comm thread. {0}", new object[] { exception });
- ExceptionHandling.DumpExceptionToFile(exception);
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
- return;
- }
- }
- pipeServer.WriteLongForHandshake(NodeProviderOutOfProc.ClientHandshake);
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Active);
- this.DebugCommunications("Entering read loop.", new object[0]);
- byte[] buffer = new byte[5];
- IAsyncResult asyncResult = pipeServer.BeginRead(buffer, 0, buffer.Length, null, null);
- bool flag3 = false;
- do
- {
- int num3 = WaitHandle.WaitAny(new WaitHandle[] { asyncResult.AsyncWaitHandle, packetAvailable, terminatePacketPump });
- switch (num3)
- {
- case 0:
- {
- int num4 = 0;
- try
- {
- num4 = pipeServer.EndRead(asyncResult);
- }
- catch (Exception exception2)
- {
- this.DebugCommunications("Exception reading from server. {0}", new object[] { exception2 });
- ExceptionHandling.DumpExceptionToFile(exception2);
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Inactive);
- flag3 = true;
- break;
- }
- if (num4 != buffer.Length)
- {
- this.DebugCommunications("Incomplete header read from server. {0} of {1} bytes read", new object[] { num4, buffer.Length });
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
- flag3 = true;
- }
- else
- {
- NodePacketType packetType = (NodePacketType) Enum.ToObject(typeof(NodePacketType), buffer[0]);
- BitConverter.ToInt32(buffer, 1);
- try
- {
- this.packetFactory.DeserializeAndRoutePacket(0, packetType, NodePacketTranslator.GetReadTranslator(this.pipeServer, this.sharedReadBuffer));
- }
- catch (Exception exception3)
- {
- this.DebugCommunications("Exception while deserializing packet {0}: {1}", new object[] { packetType, exception3 });
- ExceptionHandling.DumpExceptionToFile(exception3);
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
- flag3 = true;
- break;
- }
- asyncResult = pipeServer.BeginRead(buffer, 0, buffer.Length, null, null);
- }
- break;
- }
- case 1:
- case 2:
- try
- {
- for (int i = packetQueue.Count; i > 0; i--)
- {
- INodePacket packet;
- lock (this.packetQueue)
- {
- packet = packetQueue.Dequeue();
- }
- MemoryStream stream = new MemoryStream();
- INodePacketTranslator writeTranslator = NodePacketTranslator.GetWriteTranslator(stream);
- stream.WriteByte((byte) packet.Type);
- stream.Write(BitConverter.GetBytes(0), 0, 4);
- packet.Translate(writeTranslator);
- stream.Position = 1L;
- stream.Write(BitConverter.GetBytes((int) (((int) stream.Length) - 5)), 0, 4);
- pipeServer.Write(stream.GetBuffer(), 0, (int) stream.Length);
- }
- }
- catch (Exception exception4)
- {
- this.DebugCommunications("Exception while serializing packets: {0}", new object[] { exception4 });
- ExceptionHandling.DumpExceptionToFile(exception4);
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
- flag3 = true;
- break;
- }
- if (num3 == 2)
- {
- this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
- flag3 = true;
- }
- break;
-
- default:
- ErrorUtilities.ThrowInternalError("waitId {0} out of range.", new object[] { num3 });
- break;
- }
- }
- while (!flag3);
- try
- {
- if (pipeServer.IsConnected)
- {
- pipeServer.WaitForPipeDrain();
- pipeServer.Disconnect();
- }
- }
- catch (Exception)
- {
- }
- }
-
- private void RaiseLinkStatusChanged(Microsoft.Build.BackEnd.LinkStatus newStatus)
- {
- if (this.OnLinkStatusChanged != null)
- {
- LinkStatusChangedDelegate delegate2 = (LinkStatusChangedDelegate) this.OnLinkStatusChanged.Clone();
- delegate2(this, newStatus);
- }
- }
-
- public void SendData(INodePacket packet)
- {
- ErrorUtilities.VerifyThrow(this.status == Microsoft.Build.BackEnd.LinkStatus.Active, "Cannot send when link status is not active. Current status {0}", this.status);
- this.EnqueuePacket(packet);
- }
-
- public Microsoft.Build.BackEnd.LinkStatus LinkStatus
- {
- [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
- get
- {
- return this.status;
- }
- }
-
- [StructLayout(LayoutKind.Sequential)]
- internal struct EndpointPair
- {
- internal readonly NodeEndpointInProc NodeEndpoint;
- internal readonly NodeEndpointInProc ManagerEndpoint;
- [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
- internal EndpointPair(NodeEndpointInProc node, NodeEndpointInProc manager)
- {
- this.NodeEndpoint = node;
- this.ManagerEndpoint = manager;
- }
- }
- }
- }
-