PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs

https://github.com/pruiz/mono
C# | 1350 lines | 1183 code | 139 blank | 28 comment | 154 complexity | 1dbb20ca4fe779a0d464122b34da925d MD5 | raw file
Possible License(s): LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //------------------------------------------------------------
  4. namespace System.ServiceModel.Channels
  5. {
  6. using System.Collections.Generic;
  7. using System.Diagnostics;
  8. using System.Diagnostics.CodeAnalysis;
  9. using System.Globalization;
  10. using System.IO;
  11. using System.Net;
  12. using System.Runtime;
  13. using System.Runtime.Diagnostics;
  14. using System.Runtime.InteropServices;
  15. using System.Runtime.Versioning;
  16. using System.Security.AccessControl;
  17. using System.ComponentModel;
  18. using System.Security;
  19. using System.Security.Cryptography;
  20. using System.Security.Permissions;
  21. using System.Security.Principal;
  22. using System.ServiceModel;
  23. using System.ServiceModel.Activation;
  24. using System.ServiceModel.Diagnostics;
  25. using System.ServiceModel.Diagnostics.Application;
  26. using System.ServiceModel.Security;
  27. using System.Text;
  28. using System.Threading;
  29. using SafeCloseHandle = System.ServiceModel.Activation.SafeCloseHandle;
  30. sealed class PipeConnection : IConnection
  31. {
  32. // common state
  33. PipeHandle pipe;
  34. CloseState closeState;
  35. bool aborted;
  36. bool isBoundToCompletionPort;
  37. bool autoBindToCompletionPort;
  38. TraceEventType exceptionEventType;
  39. static byte[] zeroBuffer;
  40. // read state
  41. object readLock = new object();
  42. bool inReadingState; // This keeps track of the state machine (IConnection interface).
  43. bool isReadOutstanding; // This tracks whether an actual I/O is pending.
  44. OverlappedContext readOverlapped;
  45. byte[] asyncReadBuffer;
  46. int readBufferSize;
  47. ManualResetEvent atEOFEvent;
  48. bool isAtEOF;
  49. OverlappedIOCompleteCallback onAsyncReadComplete;
  50. Exception asyncReadException;
  51. WaitCallback asyncReadCallback;
  52. object asyncReadCallbackState;
  53. int asyncBytesRead;
  54. // write state
  55. object writeLock = new object();
  56. bool inWritingState; // This keeps track of the state machine (IConnection interface).
  57. bool isWriteOutstanding; // This tracks whether an actual I/O is pending.
  58. OverlappedContext writeOverlapped;
  59. Exception asyncWriteException;
  60. WaitCallback asyncWriteCallback;
  61. object asyncWriteCallbackState;
  62. int asyncBytesToWrite;
  63. bool isShutdownWritten;
  64. int syncWriteSize;
  65. byte[] pendingWriteBuffer;
  66. BufferManager pendingWriteBufferManager;
  67. OverlappedIOCompleteCallback onAsyncWriteComplete;
  68. int writeBufferSize;
  69. // timeout support
  70. TimeSpan readTimeout;
  71. IOThreadTimer readTimer;
  72. static Action<object> onReadTimeout;
  73. string timeoutErrorString;
  74. TransferOperation timeoutErrorTransferOperation;
  75. TimeSpan writeTimeout;
  76. IOThreadTimer writeTimer;
  77. static Action<object> onWriteTimeout;
  78. public PipeConnection(PipeHandle pipe, int connectionBufferSize, bool isBoundToCompletionPort, bool autoBindToCompletionPort)
  79. {
  80. if (pipe == null)
  81. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
  82. if (pipe.IsInvalid)
  83. throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
  84. this.closeState = CloseState.Open;
  85. this.exceptionEventType = TraceEventType.Error;
  86. this.isBoundToCompletionPort = isBoundToCompletionPort;
  87. this.autoBindToCompletionPort = autoBindToCompletionPort;
  88. this.pipe = pipe;
  89. this.readBufferSize = connectionBufferSize;
  90. this.writeBufferSize = connectionBufferSize;
  91. this.readOverlapped = new OverlappedContext();
  92. this.asyncReadBuffer = DiagnosticUtility.Utility.AllocateByteArray(connectionBufferSize);
  93. this.writeOverlapped = new OverlappedContext();
  94. this.atEOFEvent = new ManualResetEvent(false);
  95. this.onAsyncReadComplete = new OverlappedIOCompleteCallback(OnAsyncReadComplete);
  96. this.onAsyncWriteComplete = new OverlappedIOCompleteCallback(OnAsyncWriteComplete);
  97. }
  98. public int AsyncReadBufferSize
  99. {
  100. get
  101. {
  102. return this.readBufferSize;
  103. }
  104. }
  105. public byte[] AsyncReadBuffer
  106. {
  107. get
  108. {
  109. return this.asyncReadBuffer;
  110. }
  111. }
  112. static byte[] ZeroBuffer
  113. {
  114. get
  115. {
  116. if (PipeConnection.zeroBuffer == null)
  117. {
  118. PipeConnection.zeroBuffer = new byte[1];
  119. }
  120. return PipeConnection.zeroBuffer;
  121. }
  122. }
  123. public TraceEventType ExceptionEventType
  124. {
  125. get { return this.exceptionEventType; }
  126. set { this.exceptionEventType = value; }
  127. }
  128. public IPEndPoint RemoteIPEndPoint
  129. {
  130. get { return null; }
  131. }
  132. IOThreadTimer ReadTimer
  133. {
  134. get
  135. {
  136. if (this.readTimer == null)
  137. {
  138. if (onReadTimeout == null)
  139. {
  140. onReadTimeout = new Action<object>(OnReadTimeout);
  141. }
  142. this.readTimer = new IOThreadTimer(onReadTimeout, this, false);
  143. }
  144. return this.readTimer;
  145. }
  146. }
  147. IOThreadTimer WriteTimer
  148. {
  149. get
  150. {
  151. if (this.writeTimer == null)
  152. {
  153. if (onWriteTimeout == null)
  154. {
  155. onWriteTimeout = new Action<object>(OnWriteTimeout);
  156. }
  157. this.writeTimer = new IOThreadTimer(onWriteTimeout, this, false);
  158. }
  159. return this.writeTimer;
  160. }
  161. }
  162. static void OnReadTimeout(object state)
  163. {
  164. PipeConnection thisPtr = (PipeConnection)state;
  165. thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, thisPtr.readTimeout), TransferOperation.Read);
  166. }
  167. static void OnWriteTimeout(object state)
  168. {
  169. PipeConnection thisPtr = (PipeConnection)state;
  170. thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, thisPtr.writeTimeout), TransferOperation.Write);
  171. }
  172. public void Abort()
  173. {
  174. Abort(null, TransferOperation.Undefined);
  175. }
  176. void Abort(string timeoutErrorString, TransferOperation transferOperation)
  177. {
  178. CloseHandle(true, timeoutErrorString, transferOperation);
  179. }
  180. Exception ConvertPipeException(PipeException pipeException, TransferOperation transferOperation)
  181. {
  182. return ConvertPipeException(pipeException.Message, pipeException, transferOperation);
  183. }
  184. Exception ConvertPipeException(string exceptionMessage, PipeException pipeException, TransferOperation transferOperation)
  185. {
  186. if (this.timeoutErrorString != null)
  187. {
  188. if (transferOperation == this.timeoutErrorTransferOperation)
  189. {
  190. return new TimeoutException(this.timeoutErrorString, pipeException);
  191. }
  192. else
  193. {
  194. return new CommunicationException(this.timeoutErrorString, pipeException);
  195. }
  196. }
  197. else if (this.aborted)
  198. {
  199. return new CommunicationObjectAbortedException(exceptionMessage, pipeException);
  200. }
  201. else
  202. {
  203. return new CommunicationException(exceptionMessage, pipeException);
  204. }
  205. }
  206. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  207. public unsafe AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout,
  208. WaitCallback callback, object state)
  209. {
  210. ConnectionUtilities.ValidateBufferBounds(AsyncReadBuffer, offset, size);
  211. lock (readLock)
  212. {
  213. try
  214. {
  215. ValidateEnterReadingState(true);
  216. if (isAtEOF)
  217. {
  218. asyncBytesRead = 0;
  219. asyncReadException = null;
  220. return AsyncCompletionResult.Completed;
  221. }
  222. if (autoBindToCompletionPort)
  223. {
  224. if (!isBoundToCompletionPort)
  225. {
  226. lock (writeLock)
  227. {
  228. // readLock, writeLock acquired in order to prevent deadlock
  229. EnsureBoundToCompletionPort();
  230. }
  231. }
  232. }
  233. if (this.isReadOutstanding)
  234. {
  235. throw Fx.AssertAndThrow("Read I/O already pending when BeginRead called.");
  236. }
  237. try
  238. {
  239. this.readTimeout = timeout;
  240. if (this.readTimeout != TimeSpan.MaxValue)
  241. {
  242. this.ReadTimer.Set(this.readTimeout);
  243. }
  244. this.asyncReadCallback = callback;
  245. this.asyncReadCallbackState = state;
  246. this.isReadOutstanding = true;
  247. this.readOverlapped.StartAsyncOperation(AsyncReadBuffer, this.onAsyncReadComplete, this.isBoundToCompletionPort);
  248. if (UnsafeNativeMethods.ReadFile(this.pipe.DangerousGetHandle(), this.readOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.readOverlapped.NativeOverlapped) == 0)
  249. {
  250. int error = Marshal.GetLastWin32Error();
  251. if (error != UnsafeNativeMethods.ERROR_IO_PENDING && error != UnsafeNativeMethods.ERROR_MORE_DATA)
  252. {
  253. this.isReadOutstanding = false;
  254. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
  255. }
  256. }
  257. }
  258. finally
  259. {
  260. if (!this.isReadOutstanding)
  261. {
  262. // Unbind the buffer.
  263. this.readOverlapped.CancelAsyncOperation();
  264. this.asyncReadCallback = null;
  265. this.asyncReadCallbackState = null;
  266. this.ReadTimer.Cancel();
  267. }
  268. }
  269. if (!this.isReadOutstanding)
  270. {
  271. int bytesRead;
  272. Exception readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
  273. if (readException != null)
  274. {
  275. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(readException);
  276. }
  277. asyncBytesRead = bytesRead;
  278. HandleReadComplete(asyncBytesRead);
  279. }
  280. else
  281. {
  282. EnterReadingState();
  283. }
  284. return this.isReadOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
  285. }
  286. catch (PipeException e)
  287. {
  288. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
  289. }
  290. }
  291. }
  292. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  293. public unsafe AsyncCompletionResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout,
  294. WaitCallback callback, object state)
  295. {
  296. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  297. FinishPendingWrite(timeout);
  298. ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
  299. if (autoBindToCompletionPort && !isBoundToCompletionPort)
  300. {
  301. // Locks must be both taken, and in this order.
  302. lock (readLock)
  303. {
  304. lock (writeLock)
  305. {
  306. ValidateEnterWritingState(true);
  307. EnsureBoundToCompletionPort();
  308. }
  309. }
  310. }
  311. lock (writeLock)
  312. {
  313. try
  314. {
  315. ValidateEnterWritingState(true);
  316. if (this.isWriteOutstanding)
  317. {
  318. throw Fx.AssertAndThrow("Write I/O already pending when BeginWrite called.");
  319. }
  320. try
  321. {
  322. this.writeTimeout = timeout;
  323. this.WriteTimer.Set(timeoutHelper.RemainingTime());
  324. this.asyncBytesToWrite = size;
  325. this.asyncWriteException = null;
  326. this.asyncWriteCallback = callback;
  327. this.asyncWriteCallbackState = state;
  328. this.isWriteOutstanding = true;
  329. this.writeOverlapped.StartAsyncOperation(buffer, this.onAsyncWriteComplete, this.isBoundToCompletionPort);
  330. if (UnsafeNativeMethods.WriteFile(this.pipe.DangerousGetHandle(), this.writeOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.writeOverlapped.NativeOverlapped) == 0)
  331. {
  332. int error = Marshal.GetLastWin32Error();
  333. if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
  334. {
  335. this.isWriteOutstanding = false;
  336. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
  337. }
  338. }
  339. }
  340. finally
  341. {
  342. if (!this.isWriteOutstanding)
  343. {
  344. // Unbind the buffer.
  345. this.writeOverlapped.CancelAsyncOperation();
  346. this.ResetWriteState();
  347. this.WriteTimer.Cancel();
  348. }
  349. }
  350. if (!this.isWriteOutstanding)
  351. {
  352. int bytesWritten;
  353. Exception writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
  354. if (writeException == null && bytesWritten != size)
  355. {
  356. writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
  357. }
  358. if (writeException != null)
  359. {
  360. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(writeException);
  361. }
  362. }
  363. else
  364. {
  365. EnterWritingState();
  366. }
  367. return this.isWriteOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
  368. }
  369. catch (PipeException e)
  370. {
  371. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
  372. }
  373. }
  374. }
  375. // CSDMain 112188: Note asyncAndLinger has no effect here. Async pooling for Tcp was
  376. // added and NamedPipes currently doesn't obey the async model.
  377. public void Close(TimeSpan timeout, bool asyncAndLinger)
  378. {
  379. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  380. FinishPendingWrite(timeout);
  381. bool shouldCloseHandle = false;
  382. try
  383. {
  384. bool existingReadIsPending = false;
  385. bool shouldReadEOF = false;
  386. bool shouldWriteEOF = false;
  387. lock (readLock)
  388. {
  389. lock (writeLock)
  390. {
  391. if (!isShutdownWritten && inWritingState)
  392. {
  393. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  394. new PipeException(SR.GetString(SR.PipeCantCloseWithPendingWrite)), ExceptionEventType);
  395. }
  396. if (closeState == CloseState.Closing || closeState == CloseState.HandleClosed)
  397. {
  398. // already closing or closed, so just return
  399. return;
  400. }
  401. closeState = CloseState.Closing;
  402. shouldCloseHandle = true;
  403. if (!isAtEOF)
  404. {
  405. if (inReadingState)
  406. {
  407. existingReadIsPending = true;
  408. }
  409. else
  410. {
  411. shouldReadEOF = true;
  412. }
  413. }
  414. if (!isShutdownWritten)
  415. {
  416. shouldWriteEOF = true;
  417. isShutdownWritten = true;
  418. }
  419. }
  420. }
  421. if (shouldWriteEOF)
  422. {
  423. StartWriteZero(timeoutHelper.RemainingTime());
  424. }
  425. if (shouldReadEOF)
  426. {
  427. StartReadZero();
  428. }
  429. // wait for shutdown write to complete
  430. try
  431. {
  432. WaitForWriteZero(timeoutHelper.RemainingTime(), true);
  433. }
  434. catch (TimeoutException e)
  435. {
  436. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  437. new TimeoutException(SR.GetString(SR.PipeShutdownWriteError), e), ExceptionEventType);
  438. }
  439. // ensure we have received EOF signal
  440. if (shouldReadEOF)
  441. {
  442. try
  443. {
  444. WaitForReadZero(timeoutHelper.RemainingTime(), true);
  445. }
  446. catch (TimeoutException e)
  447. {
  448. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  449. new TimeoutException(SR.GetString(SR.PipeShutdownReadError), e), ExceptionEventType);
  450. }
  451. }
  452. else if (existingReadIsPending)
  453. {
  454. if (!TimeoutHelper.WaitOne(atEOFEvent, timeoutHelper.RemainingTime()))
  455. {
  456. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  457. new TimeoutException(SR.GetString(SR.PipeShutdownReadError)), ExceptionEventType);
  458. }
  459. }
  460. // else we had already seen EOF.
  461. // at this point, we may get exceptions if the other side closes the handle first
  462. try
  463. {
  464. // write an ack for eof
  465. StartWriteZero(timeoutHelper.RemainingTime());
  466. // read an ack for eof
  467. StartReadZero();
  468. // wait for write to complete/fail
  469. WaitForWriteZero(timeoutHelper.RemainingTime(), false);
  470. // wait for read to complete/fail
  471. WaitForReadZero(timeoutHelper.RemainingTime(), false);
  472. }
  473. catch (PipeException e)
  474. {
  475. if (!IsBrokenPipeError(e.ErrorCode))
  476. {
  477. throw;
  478. }
  479. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  480. }
  481. catch (CommunicationException e)
  482. {
  483. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  484. }
  485. catch (TimeoutException e)
  486. {
  487. DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
  488. }
  489. }
  490. catch (TimeoutException e)
  491. {
  492. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  493. new TimeoutException(SR.GetString(SR.PipeCloseFailed), e), ExceptionEventType);
  494. }
  495. catch (PipeException e)
  496. {
  497. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  498. ConvertPipeException(SR.GetString(SR.PipeCloseFailed), e, TransferOperation.Undefined), ExceptionEventType);
  499. }
  500. finally
  501. {
  502. if (shouldCloseHandle)
  503. {
  504. CloseHandle(false, null, TransferOperation.Undefined);
  505. }
  506. }
  507. }
  508. void CloseHandle(bool abort, string timeoutErrorString, TransferOperation transferOperation)
  509. {
  510. lock (readLock)
  511. {
  512. lock (writeLock)
  513. {
  514. if (this.closeState == CloseState.HandleClosed)
  515. {
  516. return;
  517. }
  518. this.timeoutErrorString = timeoutErrorString;
  519. this.timeoutErrorTransferOperation = transferOperation;
  520. this.aborted = abort;
  521. this.closeState = CloseState.HandleClosed;
  522. this.pipe.Close();
  523. this.readOverlapped.FreeOrDefer();
  524. this.writeOverlapped.FreeOrDefer();
  525. if (this.atEOFEvent != null)
  526. {
  527. this.atEOFEvent.Close();
  528. }
  529. // This should only do anything in the abort case.
  530. try
  531. {
  532. FinishPendingWrite(TimeSpan.Zero);
  533. }
  534. catch (TimeoutException exception)
  535. {
  536. if (TD.CloseTimeoutIsEnabled())
  537. {
  538. TD.CloseTimeout(exception.Message);
  539. }
  540. DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
  541. }
  542. catch (CommunicationException exception)
  543. {
  544. DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
  545. }
  546. }
  547. }
  548. if (abort)
  549. {
  550. TraceEventType traceEventType = TraceEventType.Warning;
  551. // we could be timing out a cached connection
  552. if (this.ExceptionEventType == TraceEventType.Information)
  553. {
  554. traceEventType = this.ExceptionEventType;
  555. }
  556. if (DiagnosticUtility.ShouldTrace(traceEventType))
  557. {
  558. TraceUtility.TraceEvent(traceEventType, TraceCode.PipeConnectionAbort, SR.GetString(SR.TraceCodePipeConnectionAbort), this);
  559. }
  560. }
  561. }
  562. CommunicationException CreatePipeDuplicationFailedException(int win32Error)
  563. {
  564. Exception innerException = new PipeException(SR.GetString(SR.PipeDuplicationFailed), win32Error);
  565. return new CommunicationException(innerException.Message, innerException);
  566. }
  567. public object DuplicateAndClose(int targetProcessId)
  568. {
  569. SafeCloseHandle targetProcessHandle = ListenerUnsafeNativeMethods.OpenProcess(ListenerUnsafeNativeMethods.PROCESS_DUP_HANDLE, false, targetProcessId);
  570. if (targetProcessHandle.IsInvalid)
  571. {
  572. targetProcessHandle.SetHandleAsInvalid();
  573. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  574. CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
  575. }
  576. try
  577. {
  578. // no need to close this handle, it's a pseudo handle. expected value is -1.
  579. IntPtr sourceProcessHandle = ListenerUnsafeNativeMethods.GetCurrentProcess();
  580. if (sourceProcessHandle == IntPtr.Zero)
  581. {
  582. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  583. CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
  584. }
  585. IntPtr duplicatedHandle;
  586. bool success = UnsafeNativeMethods.DuplicateHandle(sourceProcessHandle, this.pipe, targetProcessHandle, out duplicatedHandle, 0, false, UnsafeNativeMethods.DUPLICATE_SAME_ACCESS);
  587. if (!success)
  588. {
  589. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
  590. CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
  591. }
  592. this.Abort();
  593. return duplicatedHandle;
  594. }
  595. finally
  596. {
  597. targetProcessHandle.Close();
  598. }
  599. }
  600. public object GetCoreTransport()
  601. {
  602. return pipe;
  603. }
  604. void EnsureBoundToCompletionPort()
  605. {
  606. // Both read and write locks must be acquired before doing this
  607. if (!isBoundToCompletionPort)
  608. {
  609. ThreadPool.BindHandle(this.pipe);
  610. isBoundToCompletionPort = true;
  611. }
  612. }
  613. public int EndRead()
  614. {
  615. if (asyncReadException != null)
  616. {
  617. Exception exceptionToThrow = asyncReadException;
  618. asyncReadException = null;
  619. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
  620. }
  621. return asyncBytesRead;
  622. }
  623. public void EndWrite()
  624. {
  625. if (this.asyncWriteException != null)
  626. {
  627. Exception exceptionToThrow = this.asyncWriteException;
  628. this.asyncWriteException = null;
  629. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
  630. }
  631. }
  632. void EnterReadingState()
  633. {
  634. inReadingState = true;
  635. }
  636. void EnterWritingState()
  637. {
  638. inWritingState = true;
  639. }
  640. void ExitReadingState()
  641. {
  642. inReadingState = false;
  643. }
  644. void ExitWritingState()
  645. {
  646. inWritingState = false;
  647. }
  648. void ReadIOCompleted()
  649. {
  650. this.readOverlapped.FreeIfDeferred();
  651. }
  652. void WriteIOCompleted()
  653. {
  654. this.writeOverlapped.FreeIfDeferred();
  655. }
  656. void FinishPendingWrite(TimeSpan timeout)
  657. {
  658. if (this.pendingWriteBuffer == null)
  659. {
  660. return;
  661. }
  662. byte[] buffer;
  663. BufferManager bufferManager;
  664. lock (this.writeLock)
  665. {
  666. if (this.pendingWriteBuffer == null)
  667. {
  668. return;
  669. }
  670. buffer = this.pendingWriteBuffer;
  671. this.pendingWriteBuffer = null;
  672. bufferManager = this.pendingWriteBufferManager;
  673. this.pendingWriteBufferManager = null;
  674. }
  675. try
  676. {
  677. bool success = false;
  678. try
  679. {
  680. WaitForSyncWrite(timeout, true);
  681. success = true;
  682. }
  683. finally
  684. {
  685. lock (this.writeLock)
  686. {
  687. try
  688. {
  689. if (success)
  690. {
  691. FinishSyncWrite(true);
  692. }
  693. }
  694. finally
  695. {
  696. ExitWritingState();
  697. if (!this.isWriteOutstanding)
  698. {
  699. bufferManager.ReturnBuffer(buffer);
  700. WriteIOCompleted();
  701. }
  702. }
  703. }
  704. }
  705. }
  706. catch (PipeException e)
  707. {
  708. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
  709. }
  710. }
  711. #if FUTURE
  712. ulong GetServerPid()
  713. {
  714. ulong id;
  715. #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
  716. if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
  717. {
  718. Win32Exception e = new Win32Exception();
  719. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
  720. }
  721. return id;
  722. }
  723. ulong GetClientPid()
  724. {
  725. ulong id;
  726. #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
  727. if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
  728. {
  729. Win32Exception e = new Win32Exception();
  730. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
  731. }
  732. return id;
  733. }
  734. #endif
  735. void HandleReadComplete(int bytesRead)
  736. {
  737. if (bytesRead == 0)
  738. {
  739. isAtEOF = true;
  740. atEOFEvent.Set();
  741. }
  742. }
  743. bool IsBrokenPipeError(int error)
  744. {
  745. return error == UnsafeNativeMethods.ERROR_NO_DATA ||
  746. error == UnsafeNativeMethods.ERROR_BROKEN_PIPE;
  747. }
  748. Exception CreatePipeClosedException(TransferOperation transferOperation)
  749. {
  750. return ConvertPipeException(new PipeException(SR.GetString(SR.PipeClosed)), transferOperation);
  751. }
  752. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  753. unsafe void OnAsyncReadComplete(bool haveResult, int error, int numBytes)
  754. {
  755. WaitCallback callback;
  756. object state;
  757. lock (readLock)
  758. {
  759. try
  760. {
  761. try
  762. {
  763. if (this.readTimeout != TimeSpan.MaxValue && !this.ReadTimer.Cancel())
  764. {
  765. this.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
  766. }
  767. if (this.closeState == CloseState.HandleClosed)
  768. {
  769. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Read));
  770. }
  771. if (!haveResult)
  772. {
  773. if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.readOverlapped.NativeOverlapped, out numBytes, 0) == 0)
  774. {
  775. error = Marshal.GetLastWin32Error();
  776. }
  777. else
  778. {
  779. error = 0;
  780. }
  781. }
  782. if (error != 0 && error != UnsafeNativeMethods.ERROR_MORE_DATA)
  783. {
  784. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException((int)error));
  785. }
  786. this.asyncBytesRead = numBytes;
  787. HandleReadComplete(this.asyncBytesRead);
  788. }
  789. catch (PipeException e)
  790. {
  791. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ConvertPipeException(e, TransferOperation.Read));
  792. }
  793. }
  794. #pragma warning suppress 56500 // Microsoft, transferring exception to caller
  795. catch (Exception e)
  796. {
  797. if (Fx.IsFatal(e))
  798. {
  799. throw;
  800. }
  801. this.asyncReadException = e;
  802. }
  803. finally
  804. {
  805. this.isReadOutstanding = false;
  806. ReadIOCompleted();
  807. ExitReadingState();
  808. callback = this.asyncReadCallback;
  809. this.asyncReadCallback = null;
  810. state = this.asyncReadCallbackState;
  811. this.asyncReadCallbackState = null;
  812. }
  813. }
  814. callback(state);
  815. }
  816. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  817. unsafe void OnAsyncWriteComplete(bool haveResult, int error, int numBytes)
  818. {
  819. WaitCallback callback;
  820. object state;
  821. Exception writeException = null;
  822. this.WriteTimer.Cancel();
  823. lock (writeLock)
  824. {
  825. try
  826. {
  827. try
  828. {
  829. if (this.closeState == CloseState.HandleClosed)
  830. {
  831. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Write));
  832. }
  833. if (!haveResult)
  834. {
  835. if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.writeOverlapped.NativeOverlapped, out numBytes, 0) == 0)
  836. {
  837. error = Marshal.GetLastWin32Error();
  838. }
  839. else
  840. {
  841. error = 0;
  842. }
  843. }
  844. if (error != 0)
  845. {
  846. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
  847. }
  848. else if (numBytes != this.asyncBytesToWrite)
  849. {
  850. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new PipeException(SR.GetString(SR.PipeWriteIncomplete)));
  851. }
  852. }
  853. catch (PipeException e)
  854. {
  855. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
  856. }
  857. }
  858. #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
  859. catch (Exception e)
  860. {
  861. if (Fx.IsFatal(e))
  862. {
  863. throw;
  864. }
  865. writeException = e;
  866. }
  867. finally
  868. {
  869. this.isWriteOutstanding = false;
  870. WriteIOCompleted();
  871. ExitWritingState();
  872. this.asyncWriteException = writeException;
  873. callback = this.asyncWriteCallback;
  874. state = this.asyncWriteCallbackState;
  875. this.ResetWriteState();
  876. }
  877. }
  878. if (callback != null)
  879. {
  880. callback(state);
  881. }
  882. }
  883. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  884. unsafe public int Read(byte[] buffer, int offset, int size, TimeSpan timeout)
  885. {
  886. ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
  887. try
  888. {
  889. lock (readLock)
  890. {
  891. ValidateEnterReadingState(true);
  892. if (isAtEOF)
  893. {
  894. return 0;
  895. }
  896. StartSyncRead(buffer, offset, size);
  897. EnterReadingState();
  898. }
  899. int bytesRead = -1;
  900. bool success = false;
  901. try
  902. {
  903. WaitForSyncRead(timeout, true);
  904. success = true;
  905. }
  906. finally
  907. {
  908. lock (this.readLock)
  909. {
  910. try
  911. {
  912. if (success)
  913. {
  914. bytesRead = FinishSyncRead(true);
  915. HandleReadComplete(bytesRead);
  916. }
  917. }
  918. finally
  919. {
  920. ExitReadingState();
  921. if (!this.isReadOutstanding)
  922. {
  923. ReadIOCompleted();
  924. }
  925. }
  926. }
  927. }
  928. Fx.Assert(bytesRead >= 0, "Logic error in Read - bytesRead not set.");
  929. return bytesRead;
  930. }
  931. catch (PipeException e)
  932. {
  933. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
  934. }
  935. }
  936. public void Shutdown(TimeSpan timeout)
  937. {
  938. try
  939. {
  940. TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
  941. FinishPendingWrite(timeoutHelper.RemainingTime());
  942. lock (writeLock)
  943. {
  944. ValidateEnterWritingState(true);
  945. StartWriteZero(timeoutHelper.RemainingTime());
  946. isShutdownWritten = true;
  947. }
  948. }
  949. catch (PipeException e)
  950. {
  951. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Undefined), ExceptionEventType);
  952. }
  953. }
  954. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  955. unsafe void StartReadZero()
  956. {
  957. lock (this.readLock)
  958. {
  959. ValidateEnterReadingState(false);
  960. StartSyncRead(ZeroBuffer, 0, 1);
  961. EnterReadingState();
  962. }
  963. }
  964. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  965. unsafe void StartWriteZero(TimeSpan timeout)
  966. {
  967. FinishPendingWrite(timeout);
  968. lock (this.writeLock)
  969. {
  970. ValidateEnterWritingState(false);
  971. StartSyncWrite(ZeroBuffer, 0, 0);
  972. EnterWritingState();
  973. }
  974. }
  975. void ResetWriteState()
  976. {
  977. this.asyncBytesToWrite = -1;
  978. this.asyncWriteCallback = null;
  979. this.asyncWriteCallbackState = null;
  980. }
  981. public IAsyncResult BeginValidate(Uri uri, AsyncCallback callback, object state)
  982. {
  983. return new CompletedAsyncResult<bool>(true, callback, state);
  984. }
  985. public bool EndValidate(IAsyncResult result)
  986. {
  987. return CompletedAsyncResult<bool>.End(result);
  988. }
  989. void WaitForReadZero(TimeSpan timeout, bool traceExceptionsAsErrors)
  990. {
  991. bool success = false;
  992. try
  993. {
  994. WaitForSyncRead(timeout, traceExceptionsAsErrors);
  995. success = true;
  996. }
  997. finally
  998. {
  999. lock (this.readLock)
  1000. {
  1001. try
  1002. {
  1003. if (success)
  1004. {
  1005. if (FinishSyncRead(traceExceptionsAsErrors) != 0)
  1006. {
  1007. Exception exception = ConvertPipeException(new PipeException(SR.GetString(SR.PipeSignalExpected)), TransferOperation.Read);
  1008. TraceEventType traceEventType = TraceEventType.Information;
  1009. if (traceExceptionsAsErrors)
  1010. {
  1011. traceEventType = TraceEventType.Error;
  1012. }
  1013. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exception, traceEventType);
  1014. }
  1015. }
  1016. }
  1017. finally
  1018. {
  1019. ExitReadingState();
  1020. if (!this.isReadOutstanding)
  1021. {
  1022. ReadIOCompleted();
  1023. }
  1024. }
  1025. }
  1026. }
  1027. }
  1028. void WaitForWriteZero(TimeSpan timeout, bool traceExceptionsAsErrors)
  1029. {
  1030. bool success = false;
  1031. try
  1032. {
  1033. WaitForSyncWrite(timeout, traceExceptionsAsErrors);
  1034. success = true;
  1035. }
  1036. finally
  1037. {
  1038. lock (this.writeLock)
  1039. {
  1040. try
  1041. {
  1042. if (success)
  1043. {
  1044. FinishSyncWrite(traceExceptionsAsErrors);
  1045. }
  1046. }
  1047. finally
  1048. {
  1049. ExitWritingState();
  1050. if (!this.isWriteOutstanding)
  1051. {
  1052. WriteIOCompleted();
  1053. }
  1054. }
  1055. }
  1056. }
  1057. }
  1058. public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
  1059. {
  1060. WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
  1061. }
  1062. // The holder is a perf optimization that lets us avoid repeatedly indexing into the array.
  1063. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  1064. unsafe void WriteHelper(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, ref object holder)
  1065. {
  1066. try
  1067. {
  1068. FinishPendingWrite(timeout);
  1069. ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
  1070. int bytesToWrite = size;
  1071. if (size > this.writeBufferSize)
  1072. {
  1073. size = this.writeBufferSize;
  1074. }
  1075. while (bytesToWrite > 0)
  1076. {
  1077. lock (this.writeLock)
  1078. {
  1079. ValidateEnterWritingState(true);
  1080. StartSyncWrite(buffer, offset, size, ref holder);
  1081. EnterWritingState();
  1082. }
  1083. bool success = false;
  1084. try
  1085. {
  1086. WaitForSyncWrite(timeout, true, ref holder);
  1087. success = true;
  1088. }
  1089. finally
  1090. {
  1091. lock (this.writeLock)
  1092. {
  1093. try
  1094. {
  1095. if (success)
  1096. {
  1097. FinishSyncWrite(true);
  1098. }
  1099. }
  1100. finally
  1101. {
  1102. ExitWritingState();
  1103. if (!this.isWriteOutstanding)
  1104. {
  1105. WriteIOCompleted();
  1106. }
  1107. }
  1108. }
  1109. }
  1110. bytesToWrite -= size;
  1111. offset += size;
  1112. if (size > bytesToWrite)
  1113. {
  1114. size = bytesToWrite;
  1115. }
  1116. }
  1117. }
  1118. catch (PipeException e)
  1119. {
  1120. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
  1121. }
  1122. }
  1123. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
  1124. public unsafe void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager)
  1125. {
  1126. bool shouldReturnBuffer = true;
  1127. try
  1128. {
  1129. if (size > this.writeBufferSize)
  1130. {
  1131. WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
  1132. return;
  1133. }
  1134. FinishPendingWrite(timeout);
  1135. ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
  1136. lock (this.writeLock)
  1137. {
  1138. ValidateEnterWritingState(true);
  1139. // This method avoids the call to GetOverlappedResult for synchronous completions. Perf?
  1140. bool success = false;
  1141. try
  1142. {
  1143. shouldReturnBuffer = false;
  1144. StartSyncWrite(buffer, offset, size);
  1145. success = true;
  1146. }
  1147. finally
  1148. {
  1149. if (!this.isWriteOutstanding)
  1150. {
  1151. shouldReturnBuffer = true;
  1152. }
  1153. else
  1154. {
  1155. if (success)
  1156. {
  1157. EnterWritingState();
  1158. Fx.Assert(this.pendingWriteBuffer == null, "Need to pend a write but one's already pending.");
  1159. this.pendingWriteBuffer = buffer;
  1160. this.pendingWriteBufferManager = bufferManager;
  1161. }
  1162. }
  1163. }
  1164. }
  1165. }
  1166. catch (PipeException e)
  1167. {
  1168. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
  1169. }
  1170. finally
  1171. {
  1172. if (shouldReturnBuffer)
  1173. {
  1174. bufferManager.ReturnBuffer(buffer);
  1175. }
  1176. }
  1177. }
  1178. void ValidateEnterReadingState(bool checkEOF)
  1179. {
  1180. if (checkEOF)
  1181. {
  1182. if (closeState == CloseState.Closing)
  1183. {
  1184. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
  1185. }
  1186. }
  1187. if (inReadingState)
  1188. {
  1189. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeReadPending)), ExceptionEventType);
  1190. }
  1191. if (closeState == CloseState.HandleClosed)
  1192. {
  1193. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
  1194. }
  1195. }
  1196. void ValidateEnterWritingState(bool checkShutdown)
  1197. {
  1198. if (checkShutdown)
  1199. {
  1200. if (isShutdownWritten)
  1201. {
  1202. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyShuttingDown)), ExceptionEventType);
  1203. }
  1204. if (closeState == CloseState.Closing)
  1205. {
  1206. throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
  1207. }
  1208. }
  1209. if (inWritingState)
  1210. {
  1211. throw DiagnosticUtility.ExceptionUtility.ThrowH