PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/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
  1. namespace Microsoft.Build.BackEnd
  2. {
  3. using Microsoft.Build;
  4. using Microsoft.Build.Execution;
  5. using Microsoft.Build.Internal;
  6. using Microsoft.Build.Shared;
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Diagnostics;
  10. using System.Globalization;
  11. using System.IO;
  12. using System.IO.Pipes;
  13. using System.Runtime;
  14. using System.Runtime.InteropServices;
  15. using System.Security.AccessControl;
  16. using System.Security.Principal;
  17. using System.Threading;
  18. internal class NodeEndpointOutOfProc : INodeEndpoint
  19. {
  20. private object asyncDataMonitor;
  21. private const int ClientConnectTimeout = 0xea60;
  22. private IBuildComponentHost componentHost;
  23. private bool debugCommunications;
  24. private Utilities.LogDebugCommunications logDebugCommunications;
  25. private LinkStatusChangedDelegate OnLinkStatusChanged;
  26. private AutoResetEvent packetAvailable;
  27. private INodePacketFactory packetFactory;
  28. private Thread packetPump;
  29. private Queue<INodePacket> packetQueue;
  30. private const int PipeBufferSize = 0x20000;
  31. private NamedPipeServerStream pipeServer;
  32. private SharedReadBuffer sharedReadBuffer;
  33. private Microsoft.Build.BackEnd.LinkStatus status;
  34. private AutoResetEvent terminatePacketPump;
  35. public event LinkStatusChangedDelegate OnLinkStatusChanged
  36. {
  37. add
  38. {
  39. LinkStatusChangedDelegate delegate3;
  40. LinkStatusChangedDelegate onLinkStatusChanged = this.OnLinkStatusChanged;
  41. do
  42. {
  43. delegate3 = onLinkStatusChanged;
  44. LinkStatusChangedDelegate delegate4 = (LinkStatusChangedDelegate) Delegate.Combine(delegate3, value);
  45. onLinkStatusChanged = Interlocked.CompareExchange<LinkStatusChangedDelegate>(ref this.OnLinkStatusChanged, delegate4, delegate3);
  46. }
  47. while (onLinkStatusChanged != delegate3);
  48. }
  49. remove
  50. {
  51. LinkStatusChangedDelegate delegate3;
  52. LinkStatusChangedDelegate onLinkStatusChanged = this.OnLinkStatusChanged;
  53. do
  54. {
  55. delegate3 = onLinkStatusChanged;
  56. LinkStatusChangedDelegate delegate4 = (LinkStatusChangedDelegate) Delegate.Remove(delegate3, value);
  57. onLinkStatusChanged = Interlocked.CompareExchange<LinkStatusChangedDelegate>(ref this.OnLinkStatusChanged, delegate4, delegate3);
  58. }
  59. while (onLinkStatusChanged != delegate3);
  60. }
  61. }
  62. internal NodeEndpointOutOfProc(string pipeName, IBuildComponentHost host)
  63. {
  64. ErrorUtilities.VerifyThrowArgumentLength(pipeName, "pipeName");
  65. ErrorUtilities.VerifyThrowArgumentNull(host, "host");
  66. this.debugCommunications = Environment.GetEnvironmentVariable("MSBUILDDEBUGCOMM") == "1";
  67. this.status = Microsoft.Build.BackEnd.LinkStatus.Inactive;
  68. this.componentHost = host;
  69. this.asyncDataMonitor = new object();
  70. this.sharedReadBuffer = InterningBinaryReader.CreateSharedBuffer();
  71. SecurityIdentifier owner = WindowsIdentity.GetCurrent().Owner;
  72. PipeSecurity pipeSecurity = new PipeSecurity();
  73. PipeAccessRule rule = new PipeAccessRule(owner, PipeAccessRights.ReadWrite, AccessControlType.Allow);
  74. pipeSecurity.AddAccessRule(rule);
  75. pipeSecurity.SetOwner(owner);
  76. this.pipeServer = new NamedPipeServerStream(pipeName, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous | PipeOptions.WriteThrough, 0x20000, 0x20000, pipeSecurity, HandleInheritability.None);
  77. this.logDebugCommunications = new Utilities.LogDebugCommunications(this.DebugCommunications);
  78. }
  79. private void ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus newStatus)
  80. {
  81. ErrorUtilities.VerifyThrow(this.status != newStatus, "Attempting to change status to existing status {0}.", this.status);
  82. this.status = newStatus;
  83. this.RaiseLinkStatusChanged(this.status);
  84. }
  85. public void Connect(INodePacketFactory factory)
  86. {
  87. ErrorUtilities.ThrowInternalError("Connect() not valid on the out of proc endpoint.", new object[0]);
  88. }
  89. private void DebugCommunications(string format, params object[] stuff)
  90. {
  91. if (this.debugCommunications)
  92. {
  93. lock (this)
  94. {
  95. string str = string.Format(CultureInfo.CurrentCulture, format, stuff);
  96. StreamWriter writer = new StreamWriter(string.Format(CultureInfo.CurrentCulture, Path.Combine(Path.GetTempPath(), "MSBuild_CommsTrace_{0}.txt"), new object[] { Process.GetCurrentProcess().Id }), true);
  97. writer.WriteLine(str);
  98. writer.Flush();
  99. writer.Close();
  100. }
  101. }
  102. }
  103. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  104. public void Disconnect()
  105. {
  106. this.InternalDisconnect();
  107. }
  108. private void EnqueuePacket(INodePacket packet)
  109. {
  110. ErrorUtilities.VerifyThrowArgumentNull(packet, "packet");
  111. ErrorUtilities.VerifyThrow(null != this.packetQueue, "packetQueue is null");
  112. ErrorUtilities.VerifyThrow(null != this.packetAvailable, "packetAvailable is null");
  113. lock (this.packetQueue)
  114. {
  115. this.packetQueue.Enqueue(packet);
  116. this.packetAvailable.Set();
  117. }
  118. }
  119. private void InitializeAsyncPacketThread()
  120. {
  121. lock (this.asyncDataMonitor)
  122. {
  123. this.packetPump = new Thread(new ThreadStart(this.PacketPumpProc));
  124. this.packetPump.IsBackground = true;
  125. this.packetPump.Name = "OutOfProc Endpoint Packet Pump";
  126. this.packetAvailable = new AutoResetEvent(false);
  127. this.terminatePacketPump = new AutoResetEvent(false);
  128. this.packetQueue = new Queue<INodePacket>();
  129. this.packetPump.Start();
  130. }
  131. }
  132. private void InternalDisconnect()
  133. {
  134. ErrorUtilities.VerifyThrow(this.packetPump.ManagedThreadId != Thread.CurrentThread.ManagedThreadId, "Can't join on the same thread.");
  135. this.terminatePacketPump.Set();
  136. this.packetPump.Join();
  137. this.terminatePacketPump.Close();
  138. this.pipeServer.Close();
  139. this.packetPump = null;
  140. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Inactive);
  141. }
  142. public void Listen(INodePacketFactory factory)
  143. {
  144. ErrorUtilities.VerifyThrow(this.status == Microsoft.Build.BackEnd.LinkStatus.Inactive, "Link not inactive. Status is {0}", this.status);
  145. ErrorUtilities.VerifyThrowArgumentNull(factory, "factory");
  146. this.packetFactory = factory;
  147. this.InitializeAsyncPacketThread();
  148. }
  149. private void PacketPumpProc()
  150. {
  151. NamedPipeServerStream pipeServer = this.pipeServer;
  152. AutoResetEvent packetAvailable = this.packetAvailable;
  153. AutoResetEvent terminatePacketPump = this.terminatePacketPump;
  154. Queue<INodePacket> packetQueue = this.packetQueue;
  155. DateTime utcNow = DateTime.UtcNow;
  156. bool flag = false;
  157. while (!flag)
  158. {
  159. TimeSpan span = (TimeSpan) (DateTime.UtcNow - utcNow);
  160. int millisecondsTimeout = Math.Max(0, BuildParameters.NodeConnectionTimeout - ((int) span.TotalMilliseconds));
  161. IAsyncResult result = pipeServer.BeginWaitForConnection(null, null);
  162. this.DebugCommunications("Waiting for connection {0} ms...", new object[] { millisecondsTimeout });
  163. if (!result.AsyncWaitHandle.WaitOne(millisecondsTimeout, false))
  164. {
  165. this.DebugCommunications("Connection timed out waiting a host to contact us. Exiting comm thread.", new object[0]);
  166. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.ConnectionFailed);
  167. return;
  168. }
  169. try
  170. {
  171. WindowsIdentity clientIdentity;
  172. this.DebugCommunications("Handshaking with host..", new object[0]);
  173. pipeServer.EndWaitForConnection(result);
  174. long num2 = pipeServer.ReadLongForHandshake(new byte[] { 0x5f, 0x60 }, 0xff, this.logDebugCommunications);
  175. WindowsIdentity current = WindowsIdentity.GetCurrent();
  176. pipeServer.GetImpersonationUserName();
  177. if (num2 != NodeProviderOutOfProc.HostHandshake)
  178. {
  179. this.DebugCommunications("Handshake failed. Received {0} from host not {1}. Probably the host is a different MSBuild build.", new object[] { num2, NodeProviderOutOfProc.HostHandshake });
  180. pipeServer.Disconnect();
  181. }
  182. else
  183. {
  184. clientIdentity = null;
  185. pipeServer.RunAsClient(delegate {
  186. clientIdentity = WindowsIdentity.GetCurrent(true);
  187. });
  188. if ((clientIdentity == null) || !string.Equals(clientIdentity.Name, current.Name, StringComparison.OrdinalIgnoreCase))
  189. {
  190. this.DebugCommunications("Handshake failed. Host user is {0} but we were created by {1}.", new object[] { (clientIdentity == null) ? "<unknown>" : clientIdentity.Name, current.Name });
  191. pipeServer.Disconnect();
  192. }
  193. else
  194. {
  195. flag = true;
  196. }
  197. }
  198. continue;
  199. }
  200. catch (Exception exception)
  201. {
  202. if (ExceptionHandling.IsCriticalException(exception))
  203. {
  204. throw;
  205. }
  206. this.DebugCommunications("Client connection failed. Exiting comm thread. {0}", new object[] { exception });
  207. ExceptionHandling.DumpExceptionToFile(exception);
  208. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
  209. return;
  210. }
  211. }
  212. pipeServer.WriteLongForHandshake(NodeProviderOutOfProc.ClientHandshake);
  213. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Active);
  214. this.DebugCommunications("Entering read loop.", new object[0]);
  215. byte[] buffer = new byte[5];
  216. IAsyncResult asyncResult = pipeServer.BeginRead(buffer, 0, buffer.Length, null, null);
  217. bool flag3 = false;
  218. do
  219. {
  220. int num3 = WaitHandle.WaitAny(new WaitHandle[] { asyncResult.AsyncWaitHandle, packetAvailable, terminatePacketPump });
  221. switch (num3)
  222. {
  223. case 0:
  224. {
  225. int num4 = 0;
  226. try
  227. {
  228. num4 = pipeServer.EndRead(asyncResult);
  229. }
  230. catch (Exception exception2)
  231. {
  232. this.DebugCommunications("Exception reading from server. {0}", new object[] { exception2 });
  233. ExceptionHandling.DumpExceptionToFile(exception2);
  234. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Inactive);
  235. flag3 = true;
  236. break;
  237. }
  238. if (num4 != buffer.Length)
  239. {
  240. this.DebugCommunications("Incomplete header read from server. {0} of {1} bytes read", new object[] { num4, buffer.Length });
  241. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
  242. flag3 = true;
  243. }
  244. else
  245. {
  246. NodePacketType packetType = (NodePacketType) Enum.ToObject(typeof(NodePacketType), buffer[0]);
  247. BitConverter.ToInt32(buffer, 1);
  248. try
  249. {
  250. this.packetFactory.DeserializeAndRoutePacket(0, packetType, NodePacketTranslator.GetReadTranslator(this.pipeServer, this.sharedReadBuffer));
  251. }
  252. catch (Exception exception3)
  253. {
  254. this.DebugCommunications("Exception while deserializing packet {0}: {1}", new object[] { packetType, exception3 });
  255. ExceptionHandling.DumpExceptionToFile(exception3);
  256. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
  257. flag3 = true;
  258. break;
  259. }
  260. asyncResult = pipeServer.BeginRead(buffer, 0, buffer.Length, null, null);
  261. }
  262. break;
  263. }
  264. case 1:
  265. case 2:
  266. try
  267. {
  268. for (int i = packetQueue.Count; i > 0; i--)
  269. {
  270. INodePacket packet;
  271. lock (this.packetQueue)
  272. {
  273. packet = packetQueue.Dequeue();
  274. }
  275. MemoryStream stream = new MemoryStream();
  276. INodePacketTranslator writeTranslator = NodePacketTranslator.GetWriteTranslator(stream);
  277. stream.WriteByte((byte) packet.Type);
  278. stream.Write(BitConverter.GetBytes(0), 0, 4);
  279. packet.Translate(writeTranslator);
  280. stream.Position = 1L;
  281. stream.Write(BitConverter.GetBytes((int) (((int) stream.Length) - 5)), 0, 4);
  282. pipeServer.Write(stream.GetBuffer(), 0, (int) stream.Length);
  283. }
  284. }
  285. catch (Exception exception4)
  286. {
  287. this.DebugCommunications("Exception while serializing packets: {0}", new object[] { exception4 });
  288. ExceptionHandling.DumpExceptionToFile(exception4);
  289. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
  290. flag3 = true;
  291. break;
  292. }
  293. if (num3 == 2)
  294. {
  295. this.ChangeLinkStatus(Microsoft.Build.BackEnd.LinkStatus.Failed);
  296. flag3 = true;
  297. }
  298. break;
  299. default:
  300. ErrorUtilities.ThrowInternalError("waitId {0} out of range.", new object[] { num3 });
  301. break;
  302. }
  303. }
  304. while (!flag3);
  305. try
  306. {
  307. if (pipeServer.IsConnected)
  308. {
  309. pipeServer.WaitForPipeDrain();
  310. pipeServer.Disconnect();
  311. }
  312. }
  313. catch (Exception)
  314. {
  315. }
  316. }
  317. private void RaiseLinkStatusChanged(Microsoft.Build.BackEnd.LinkStatus newStatus)
  318. {
  319. if (this.OnLinkStatusChanged != null)
  320. {
  321. LinkStatusChangedDelegate delegate2 = (LinkStatusChangedDelegate) this.OnLinkStatusChanged.Clone();
  322. delegate2(this, newStatus);
  323. }
  324. }
  325. public void SendData(INodePacket packet)
  326. {
  327. ErrorUtilities.VerifyThrow(this.status == Microsoft.Build.BackEnd.LinkStatus.Active, "Cannot send when link status is not active. Current status {0}", this.status);
  328. this.EnqueuePacket(packet);
  329. }
  330. public Microsoft.Build.BackEnd.LinkStatus LinkStatus
  331. {
  332. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  333. get
  334. {
  335. return this.status;
  336. }
  337. }
  338. [StructLayout(LayoutKind.Sequential)]
  339. internal struct EndpointPair
  340. {
  341. internal readonly NodeEndpointInProc NodeEndpoint;
  342. internal readonly NodeEndpointInProc ManagerEndpoint;
  343. [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
  344. internal EndpointPair(NodeEndpointInProc node, NodeEndpointInProc manager)
  345. {
  346. this.NodeEndpoint = node;
  347. this.ManagerEndpoint = manager;
  348. }
  349. }
  350. }
  351. }