[bcl] Updates referencesource to 4.7.1
[mono-project.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / PipeConnection.cs
blob16f89740523d779047c60efbcd0d72466c266f9c
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //------------------------------------------------------------
5 namespace System.ServiceModel.Channels
7 using System.Collections.Generic;
8 using System.Diagnostics;
9 using System.Diagnostics.CodeAnalysis;
10 using System.Globalization;
11 using System.IO;
12 using System.Net;
13 using System.Runtime;
14 using System.Runtime.Diagnostics;
15 using System.Runtime.InteropServices;
16 using System.Runtime.Versioning;
17 using System.Security.AccessControl;
18 using System.ComponentModel;
19 using System.Security;
20 using System.Security.Cryptography;
21 using System.Security.Permissions;
22 using System.Security.Principal;
23 using System.ServiceModel;
24 using System.ServiceModel.Activation;
25 using System.ServiceModel.Diagnostics;
26 using System.ServiceModel.Diagnostics.Application;
27 using System.ServiceModel.Security;
28 using System.Text;
29 using System.Threading;
30 using SafeCloseHandle = System.ServiceModel.Activation.SafeCloseHandle;
32 sealed class PipeConnection : IConnection
34 // common state
35 PipeHandle pipe;
36 CloseState closeState;
37 bool aborted;
38 bool isBoundToCompletionPort;
39 bool autoBindToCompletionPort;
40 TraceEventType exceptionEventType;
41 static byte[] zeroBuffer;
43 // read state
44 object readLock = new object();
45 bool inReadingState; // This keeps track of the state machine (IConnection interface).
46 bool isReadOutstanding; // This tracks whether an actual I/O is pending.
47 OverlappedContext readOverlapped;
48 byte[] asyncReadBuffer;
49 int readBufferSize;
50 ManualResetEvent atEOFEvent;
51 bool isAtEOF;
52 OverlappedIOCompleteCallback onAsyncReadComplete;
53 Exception asyncReadException;
54 WaitCallback asyncReadCallback;
55 object asyncReadCallbackState;
56 int asyncBytesRead;
58 // write state
59 object writeLock = new object();
60 bool inWritingState; // This keeps track of the state machine (IConnection interface).
61 bool isWriteOutstanding; // This tracks whether an actual I/O is pending.
62 OverlappedContext writeOverlapped;
63 Exception asyncWriteException;
64 WaitCallback asyncWriteCallback;
65 object asyncWriteCallbackState;
66 int asyncBytesToWrite;
67 bool isShutdownWritten;
68 int syncWriteSize;
69 byte[] pendingWriteBuffer;
70 BufferManager pendingWriteBufferManager;
71 OverlappedIOCompleteCallback onAsyncWriteComplete;
72 int writeBufferSize;
74 // timeout support
75 TimeSpan readTimeout;
76 IOThreadTimer readTimer;
77 static Action<object> onReadTimeout;
78 string timeoutErrorString;
79 TransferOperation timeoutErrorTransferOperation;
80 TimeSpan writeTimeout;
81 IOThreadTimer writeTimer;
82 static Action<object> onWriteTimeout;
84 public PipeConnection(PipeHandle pipe, int connectionBufferSize, bool isBoundToCompletionPort, bool autoBindToCompletionPort)
86 if (pipe == null)
87 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
88 if (pipe.IsInvalid)
89 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
91 this.closeState = CloseState.Open;
92 this.exceptionEventType = TraceEventType.Error;
93 this.isBoundToCompletionPort = isBoundToCompletionPort;
94 this.autoBindToCompletionPort = autoBindToCompletionPort;
95 this.pipe = pipe;
96 this.readBufferSize = connectionBufferSize;
97 this.writeBufferSize = connectionBufferSize;
98 this.readOverlapped = new OverlappedContext();
99 this.asyncReadBuffer = DiagnosticUtility.Utility.AllocateByteArray(connectionBufferSize);
100 this.writeOverlapped = new OverlappedContext();
101 this.atEOFEvent = new ManualResetEvent(false);
102 this.onAsyncReadComplete = new OverlappedIOCompleteCallback(OnAsyncReadComplete);
103 this.onAsyncWriteComplete = new OverlappedIOCompleteCallback(OnAsyncWriteComplete);
106 public int AsyncReadBufferSize
110 return this.readBufferSize;
114 public byte[] AsyncReadBuffer
118 return this.asyncReadBuffer;
122 static byte[] ZeroBuffer
126 if (PipeConnection.zeroBuffer == null)
128 PipeConnection.zeroBuffer = new byte[1];
130 return PipeConnection.zeroBuffer;
134 public TraceEventType ExceptionEventType
136 get { return this.exceptionEventType; }
137 set { this.exceptionEventType = value; }
140 public IPEndPoint RemoteIPEndPoint
142 get { return null; }
145 IOThreadTimer ReadTimer
149 if (this.readTimer == null)
151 if (onReadTimeout == null)
153 onReadTimeout = new Action<object>(OnReadTimeout);
156 this.readTimer = new IOThreadTimer(onReadTimeout, this, false);
159 return this.readTimer;
162 IOThreadTimer WriteTimer
166 if (this.writeTimer == null)
168 if (onWriteTimeout == null)
170 onWriteTimeout = new Action<object>(OnWriteTimeout);
173 this.writeTimer = new IOThreadTimer(onWriteTimeout, this, false);
176 return this.writeTimer;
180 static void OnReadTimeout(object state)
182 PipeConnection thisPtr = (PipeConnection)state;
183 thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, thisPtr.readTimeout), TransferOperation.Read);
186 static void OnWriteTimeout(object state)
188 PipeConnection thisPtr = (PipeConnection)state;
189 thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, thisPtr.writeTimeout), TransferOperation.Write);
192 public void Abort()
194 Abort(null, TransferOperation.Undefined);
197 void Abort(string timeoutErrorString, TransferOperation transferOperation)
199 CloseHandle(true, timeoutErrorString, transferOperation);
202 Exception ConvertPipeException(PipeException pipeException, TransferOperation transferOperation)
204 return ConvertPipeException(pipeException.Message, pipeException, transferOperation);
207 Exception ConvertPipeException(string exceptionMessage, PipeException pipeException, TransferOperation transferOperation)
209 if (this.timeoutErrorString != null)
211 if (transferOperation == this.timeoutErrorTransferOperation)
213 return new TimeoutException(this.timeoutErrorString, pipeException);
215 else
217 return new CommunicationException(this.timeoutErrorString, pipeException);
220 else if (this.aborted)
222 return new CommunicationObjectAbortedException(exceptionMessage, pipeException);
224 else
226 return new CommunicationException(exceptionMessage, pipeException);
230 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
231 public unsafe AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout,
232 WaitCallback callback, object state)
234 ConnectionUtilities.ValidateBufferBounds(AsyncReadBuffer, offset, size);
236 lock (readLock)
240 ValidateEnterReadingState(true);
242 if (isAtEOF)
244 asyncBytesRead = 0;
245 asyncReadException = null;
246 return AsyncCompletionResult.Completed;
249 if (autoBindToCompletionPort)
251 if (!isBoundToCompletionPort)
253 lock (writeLock)
255 // readLock, writeLock acquired in order to prevent deadlock
256 EnsureBoundToCompletionPort();
261 if (this.isReadOutstanding)
263 throw Fx.AssertAndThrow("Read I/O already pending when BeginRead called.");
267 this.readTimeout = timeout;
269 if (this.readTimeout != TimeSpan.MaxValue)
271 this.ReadTimer.Set(this.readTimeout);
274 this.asyncReadCallback = callback;
275 this.asyncReadCallbackState = state;
277 this.isReadOutstanding = true;
278 this.readOverlapped.StartAsyncOperation(AsyncReadBuffer, this.onAsyncReadComplete, this.isBoundToCompletionPort);
279 if (UnsafeNativeMethods.ReadFile(this.pipe.DangerousGetHandle(), this.readOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.readOverlapped.NativeOverlapped) == 0)
281 int error = Marshal.GetLastWin32Error();
282 if (error != UnsafeNativeMethods.ERROR_IO_PENDING && error != UnsafeNativeMethods.ERROR_MORE_DATA)
284 this.isReadOutstanding = false;
285 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
289 finally
291 if (!this.isReadOutstanding)
293 // Unbind the buffer.
294 this.readOverlapped.CancelAsyncOperation();
296 this.asyncReadCallback = null;
297 this.asyncReadCallbackState = null;
298 this.ReadTimer.Cancel();
302 if (!this.isReadOutstanding)
304 int bytesRead;
305 Exception readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
306 if (readException != null)
308 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(readException);
310 asyncBytesRead = bytesRead;
311 HandleReadComplete(asyncBytesRead);
313 else
315 EnterReadingState();
318 return this.isReadOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
320 catch (PipeException e)
322 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
327 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
328 public unsafe AsyncCompletionResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout,
329 WaitCallback callback, object state)
331 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
332 FinishPendingWrite(timeout);
334 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
336 if (autoBindToCompletionPort && !isBoundToCompletionPort)
338 // Locks must be both taken, and in this order.
339 lock (readLock)
341 lock (writeLock)
343 ValidateEnterWritingState(true);
345 EnsureBoundToCompletionPort();
350 lock (writeLock)
354 ValidateEnterWritingState(true);
356 if (this.isWriteOutstanding)
358 throw Fx.AssertAndThrow("Write I/O already pending when BeginWrite called.");
363 this.writeTimeout = timeout;
364 this.WriteTimer.Set(timeoutHelper.RemainingTime());
366 this.asyncBytesToWrite = size;
367 this.asyncWriteException = null;
368 this.asyncWriteCallback = callback;
369 this.asyncWriteCallbackState = state;
371 this.isWriteOutstanding = true;
372 this.writeOverlapped.StartAsyncOperation(buffer, this.onAsyncWriteComplete, this.isBoundToCompletionPort);
373 if (UnsafeNativeMethods.WriteFile(this.pipe.DangerousGetHandle(), this.writeOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.writeOverlapped.NativeOverlapped) == 0)
375 int error = Marshal.GetLastWin32Error();
376 if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
378 this.isWriteOutstanding = false;
379 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
383 finally
385 if (!this.isWriteOutstanding)
387 // Unbind the buffer.
388 this.writeOverlapped.CancelAsyncOperation();
390 this.ResetWriteState();
391 this.WriteTimer.Cancel();
395 if (!this.isWriteOutstanding)
397 int bytesWritten;
398 Exception writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
399 if (writeException == null && bytesWritten != size)
401 writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
403 if (writeException != null)
405 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(writeException);
408 else
410 EnterWritingState();
413 return this.isWriteOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
415 catch (PipeException e)
417 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
422 // CSDMain 112188: Note asyncAndLinger has no effect here. Async pooling for Tcp was
423 // added and NamedPipes currently doesn't obey the async model.
424 public void Close(TimeSpan timeout, bool asyncAndLinger)
426 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
427 FinishPendingWrite(timeout);
429 bool shouldCloseHandle = false;
432 bool existingReadIsPending = false;
433 bool shouldReadEOF = false;
434 bool shouldWriteEOF = false;
436 lock (readLock)
438 lock (writeLock)
440 if (!isShutdownWritten && inWritingState)
442 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
443 new PipeException(SR.GetString(SR.PipeCantCloseWithPendingWrite)), ExceptionEventType);
446 if (closeState == CloseState.Closing || closeState == CloseState.HandleClosed)
448 // already closing or closed, so just return
449 return;
452 closeState = CloseState.Closing;
454 shouldCloseHandle = true;
456 if (!isAtEOF)
458 if (inReadingState)
460 existingReadIsPending = true;
462 else
464 shouldReadEOF = true;
468 if (!isShutdownWritten)
470 shouldWriteEOF = true;
471 isShutdownWritten = true;
476 if (shouldWriteEOF)
478 StartWriteZero(timeoutHelper.RemainingTime());
481 if (shouldReadEOF)
483 StartReadZero();
486 // wait for shutdown write to complete
489 WaitForWriteZero(timeoutHelper.RemainingTime(), true);
491 catch (TimeoutException e)
493 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
494 new TimeoutException(SR.GetString(SR.PipeShutdownWriteError), e), ExceptionEventType);
497 // ensure we have received EOF signal
498 if (shouldReadEOF)
502 WaitForReadZero(timeoutHelper.RemainingTime(), true);
504 catch (TimeoutException e)
506 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
507 new TimeoutException(SR.GetString(SR.PipeShutdownReadError), e), ExceptionEventType);
510 else if (existingReadIsPending)
512 if (!TimeoutHelper.WaitOne(atEOFEvent, timeoutHelper.RemainingTime()))
514 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
515 new TimeoutException(SR.GetString(SR.PipeShutdownReadError)), ExceptionEventType);
518 // else we had already seen EOF.
520 // at this point, we may get exceptions if the other side closes the handle first
523 // write an ack for eof
524 StartWriteZero(timeoutHelper.RemainingTime());
526 // read an ack for eof
527 StartReadZero();
529 // wait for write to complete/fail
530 WaitForWriteZero(timeoutHelper.RemainingTime(), false);
532 // wait for read to complete/fail
533 WaitForReadZero(timeoutHelper.RemainingTime(), false);
535 catch (PipeException e)
537 if (!IsBrokenPipeError(e.ErrorCode))
539 throw;
541 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
543 catch (CommunicationException e)
545 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
547 catch (TimeoutException e)
549 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
552 catch (TimeoutException e)
554 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
555 new TimeoutException(SR.GetString(SR.PipeCloseFailed), e), ExceptionEventType);
557 catch (PipeException e)
559 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
560 ConvertPipeException(SR.GetString(SR.PipeCloseFailed), e, TransferOperation.Undefined), ExceptionEventType);
562 finally
564 if (shouldCloseHandle)
566 CloseHandle(false, null, TransferOperation.Undefined);
571 void CloseHandle(bool abort, string timeoutErrorString, TransferOperation transferOperation)
573 lock (readLock)
575 lock (writeLock)
577 if (this.closeState == CloseState.HandleClosed)
579 return;
582 this.timeoutErrorString = timeoutErrorString;
583 this.timeoutErrorTransferOperation = transferOperation;
584 this.aborted = abort;
585 this.closeState = CloseState.HandleClosed;
586 this.pipe.Close();
587 this.readOverlapped.FreeOrDefer();
588 this.writeOverlapped.FreeOrDefer();
590 if (this.atEOFEvent != null)
592 this.atEOFEvent.Close();
595 // This should only do anything in the abort case.
598 FinishPendingWrite(TimeSpan.Zero);
600 catch (TimeoutException exception)
602 if (TD.CloseTimeoutIsEnabled())
604 TD.CloseTimeout(exception.Message);
606 DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
608 catch (CommunicationException exception)
610 DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
615 if (abort)
617 TraceEventType traceEventType = TraceEventType.Warning;
619 // we could be timing out a cached connection
620 if (this.ExceptionEventType == TraceEventType.Information)
622 traceEventType = this.ExceptionEventType;
625 if (DiagnosticUtility.ShouldTrace(traceEventType))
627 TraceUtility.TraceEvent(traceEventType, TraceCode.PipeConnectionAbort, SR.GetString(SR.TraceCodePipeConnectionAbort), this);
632 CommunicationException CreatePipeDuplicationFailedException(int win32Error)
634 Exception innerException = new PipeException(SR.GetString(SR.PipeDuplicationFailed), win32Error);
635 return new CommunicationException(innerException.Message, innerException);
638 public object DuplicateAndClose(int targetProcessId)
640 SafeCloseHandle targetProcessHandle = ListenerUnsafeNativeMethods.OpenProcess(ListenerUnsafeNativeMethods.PROCESS_DUP_HANDLE, false, targetProcessId);
641 if (targetProcessHandle.IsInvalid)
643 targetProcessHandle.SetHandleAsInvalid();
644 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
645 CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
649 // no need to close this handle, it's a pseudo handle. expected value is -1.
650 IntPtr sourceProcessHandle = ListenerUnsafeNativeMethods.GetCurrentProcess();
651 if (sourceProcessHandle == IntPtr.Zero)
653 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
654 CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
656 IntPtr duplicatedHandle;
657 bool success = UnsafeNativeMethods.DuplicateHandle(sourceProcessHandle, this.pipe, targetProcessHandle, out duplicatedHandle, 0, false, UnsafeNativeMethods.DUPLICATE_SAME_ACCESS);
658 if (!success)
660 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
661 CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
663 this.Abort();
664 return duplicatedHandle;
666 finally
668 targetProcessHandle.Close();
672 public object GetCoreTransport()
674 return pipe;
677 void EnsureBoundToCompletionPort()
679 // Both read and write locks must be acquired before doing this
680 if (!isBoundToCompletionPort)
682 ThreadPool.BindHandle(this.pipe);
683 isBoundToCompletionPort = true;
687 public int EndRead()
689 if (asyncReadException != null)
691 Exception exceptionToThrow = asyncReadException;
692 asyncReadException = null;
693 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
695 return asyncBytesRead;
698 public void EndWrite()
700 if (this.asyncWriteException != null)
702 Exception exceptionToThrow = this.asyncWriteException;
703 this.asyncWriteException = null;
704 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
708 void EnterReadingState()
710 inReadingState = true;
713 void EnterWritingState()
715 inWritingState = true;
718 void ExitReadingState()
720 inReadingState = false;
723 void ExitWritingState()
725 inWritingState = false;
728 void ReadIOCompleted()
730 this.readOverlapped.FreeIfDeferred();
733 void WriteIOCompleted()
735 this.writeOverlapped.FreeIfDeferred();
738 void FinishPendingWrite(TimeSpan timeout)
740 if (this.pendingWriteBuffer == null)
742 return;
745 byte[] buffer;
746 BufferManager bufferManager;
747 lock (this.writeLock)
749 if (this.pendingWriteBuffer == null)
751 return;
754 buffer = this.pendingWriteBuffer;
755 this.pendingWriteBuffer = null;
757 bufferManager = this.pendingWriteBufferManager;
758 this.pendingWriteBufferManager = null;
763 bool success = false;
766 WaitForSyncWrite(timeout, true);
767 success = true;
769 finally
771 lock (this.writeLock)
775 if (success)
777 FinishSyncWrite(true);
780 finally
782 ExitWritingState();
783 if (!this.isWriteOutstanding)
785 bufferManager.ReturnBuffer(buffer);
786 WriteIOCompleted();
792 catch (PipeException e)
794 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
798 #if FUTURE
799 ulong GetServerPid()
801 ulong id;
802 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
803 if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
805 Win32Exception e = new Win32Exception();
806 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
808 return id;
811 ulong GetClientPid()
813 ulong id;
814 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
815 if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
817 Win32Exception e = new Win32Exception();
818 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
820 return id;
822 #endif
824 void HandleReadComplete(int bytesRead)
826 if (bytesRead == 0)
828 isAtEOF = true;
829 atEOFEvent.Set();
833 bool IsBrokenPipeError(int error)
835 return error == UnsafeNativeMethods.ERROR_NO_DATA ||
836 error == UnsafeNativeMethods.ERROR_BROKEN_PIPE;
839 Exception CreatePipeClosedException(TransferOperation transferOperation)
841 return ConvertPipeException(new PipeException(SR.GetString(SR.PipeClosed)), transferOperation);
844 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
845 unsafe void OnAsyncReadComplete(bool haveResult, int error, int numBytes)
847 WaitCallback callback;
848 object state;
850 lock (readLock)
856 if (this.readTimeout != TimeSpan.MaxValue && !this.ReadTimer.Cancel())
858 this.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
861 if (this.closeState == CloseState.HandleClosed)
863 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Read));
865 if (!haveResult)
867 if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.readOverlapped.NativeOverlapped, out numBytes, 0) == 0)
869 error = Marshal.GetLastWin32Error();
871 else
873 error = 0;
877 if (error != 0 && error != UnsafeNativeMethods.ERROR_MORE_DATA)
879 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException((int)error));
881 this.asyncBytesRead = numBytes;
882 HandleReadComplete(this.asyncBytesRead);
884 catch (PipeException e)
886 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ConvertPipeException(e, TransferOperation.Read));
889 #pragma warning suppress 56500 // Microsoft, transferring exception to caller
890 catch (Exception e)
892 if (Fx.IsFatal(e))
894 throw;
897 this.asyncReadException = e;
899 finally
901 this.isReadOutstanding = false;
902 ReadIOCompleted();
903 ExitReadingState();
904 callback = this.asyncReadCallback;
905 this.asyncReadCallback = null;
906 state = this.asyncReadCallbackState;
907 this.asyncReadCallbackState = null;
911 callback(state);
914 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
915 unsafe void OnAsyncWriteComplete(bool haveResult, int error, int numBytes)
917 WaitCallback callback;
918 object state;
920 Exception writeException = null;
922 this.WriteTimer.Cancel();
923 lock (writeLock)
929 if (this.closeState == CloseState.HandleClosed)
931 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Write));
933 if (!haveResult)
935 if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.writeOverlapped.NativeOverlapped, out numBytes, 0) == 0)
937 error = Marshal.GetLastWin32Error();
939 else
941 error = 0;
945 if (error != 0)
947 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
949 else if (numBytes != this.asyncBytesToWrite)
951 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new PipeException(SR.GetString(SR.PipeWriteIncomplete)));
954 catch (PipeException e)
956 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
959 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
960 catch (Exception e)
962 if (Fx.IsFatal(e))
964 throw;
967 writeException = e;
969 finally
971 this.isWriteOutstanding = false;
972 WriteIOCompleted();
973 ExitWritingState();
974 this.asyncWriteException = writeException;
975 callback = this.asyncWriteCallback;
976 state = this.asyncWriteCallbackState;
977 this.ResetWriteState();
981 if (callback != null)
983 callback(state);
987 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
988 unsafe public int Read(byte[] buffer, int offset, int size, TimeSpan timeout)
990 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
994 lock (readLock)
996 ValidateEnterReadingState(true);
997 if (isAtEOF)
999 return 0;
1002 StartSyncRead(buffer, offset, size);
1003 EnterReadingState();
1006 int bytesRead = -1;
1007 bool success = false;
1010 WaitForSyncRead(timeout, true);
1011 success = true;
1013 finally
1015 lock (this.readLock)
1019 if (success)
1021 bytesRead = FinishSyncRead(true);
1022 HandleReadComplete(bytesRead);
1025 finally
1027 ExitReadingState();
1028 if (!this.isReadOutstanding)
1030 ReadIOCompleted();
1036 Fx.Assert(bytesRead >= 0, "Logic error in Read - bytesRead not set.");
1037 return bytesRead;
1039 catch (PipeException e)
1041 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
1045 public void Shutdown(TimeSpan timeout)
1049 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1050 FinishPendingWrite(timeoutHelper.RemainingTime());
1052 lock (writeLock)
1054 ValidateEnterWritingState(true);
1055 StartWriteZero(timeoutHelper.RemainingTime());
1056 isShutdownWritten = true;
1059 catch (PipeException e)
1061 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Undefined), ExceptionEventType);
1065 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1066 unsafe void StartReadZero()
1068 lock (this.readLock)
1070 ValidateEnterReadingState(false);
1071 StartSyncRead(ZeroBuffer, 0, 1);
1072 EnterReadingState();
1076 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1077 unsafe void StartWriteZero(TimeSpan timeout)
1079 FinishPendingWrite(timeout);
1081 lock (this.writeLock)
1083 ValidateEnterWritingState(false);
1084 StartSyncWrite(ZeroBuffer, 0, 0);
1085 EnterWritingState();
1089 void ResetWriteState()
1091 this.asyncBytesToWrite = -1;
1092 this.asyncWriteCallback = null;
1093 this.asyncWriteCallbackState = null;
1096 public IAsyncResult BeginValidate(Uri uri, AsyncCallback callback, object state)
1098 return new CompletedAsyncResult<bool>(true, callback, state);
1101 public bool EndValidate(IAsyncResult result)
1103 return CompletedAsyncResult<bool>.End(result);
1106 void WaitForReadZero(TimeSpan timeout, bool traceExceptionsAsErrors)
1108 bool success = false;
1111 WaitForSyncRead(timeout, traceExceptionsAsErrors);
1112 success = true;
1114 finally
1116 lock (this.readLock)
1120 if (success)
1122 if (FinishSyncRead(traceExceptionsAsErrors) != 0)
1124 Exception exception = ConvertPipeException(new PipeException(SR.GetString(SR.PipeSignalExpected)), TransferOperation.Read);
1125 TraceEventType traceEventType = TraceEventType.Information;
1126 if (traceExceptionsAsErrors)
1128 traceEventType = TraceEventType.Error;
1130 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exception, traceEventType);
1134 finally
1136 ExitReadingState();
1137 if (!this.isReadOutstanding)
1139 ReadIOCompleted();
1146 void WaitForWriteZero(TimeSpan timeout, bool traceExceptionsAsErrors)
1148 bool success = false;
1151 WaitForSyncWrite(timeout, traceExceptionsAsErrors);
1152 success = true;
1154 finally
1156 lock (this.writeLock)
1160 if (success)
1162 FinishSyncWrite(traceExceptionsAsErrors);
1165 finally
1167 ExitWritingState();
1168 if (!this.isWriteOutstanding)
1170 WriteIOCompleted();
1177 public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
1179 WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
1182 // The holder is a perf optimization that lets us avoid repeatedly indexing into the array.
1183 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1184 unsafe void WriteHelper(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, ref object holder)
1188 FinishPendingWrite(timeout);
1190 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
1192 int bytesToWrite = size;
1193 if (size > this.writeBufferSize)
1195 size = this.writeBufferSize;
1198 while (bytesToWrite > 0)
1200 lock (this.writeLock)
1202 ValidateEnterWritingState(true);
1204 StartSyncWrite(buffer, offset, size, ref holder);
1205 EnterWritingState();
1208 bool success = false;
1211 WaitForSyncWrite(timeout, true, ref holder);
1212 success = true;
1214 finally
1216 lock (this.writeLock)
1220 if (success)
1222 FinishSyncWrite(true);
1225 finally
1227 ExitWritingState();
1228 if (!this.isWriteOutstanding)
1230 WriteIOCompleted();
1236 bytesToWrite -= size;
1237 offset += size;
1238 if (size > bytesToWrite)
1240 size = bytesToWrite;
1244 catch (PipeException e)
1246 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
1250 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1251 public unsafe void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager)
1253 bool shouldReturnBuffer = true;
1257 if (size > this.writeBufferSize)
1259 WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
1260 return;
1263 FinishPendingWrite(timeout);
1265 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
1267 lock (this.writeLock)
1269 ValidateEnterWritingState(true);
1271 // This method avoids the call to GetOverlappedResult for synchronous completions. Perf?
1272 bool success = false;
1275 shouldReturnBuffer = false;
1276 StartSyncWrite(buffer, offset, size);
1277 success = true;
1279 finally
1281 if (!this.isWriteOutstanding)
1283 shouldReturnBuffer = true;
1285 else
1287 if (success)
1289 EnterWritingState();
1291 Fx.Assert(this.pendingWriteBuffer == null, "Need to pend a write but one's already pending.");
1292 this.pendingWriteBuffer = buffer;
1293 this.pendingWriteBufferManager = bufferManager;
1299 catch (PipeException e)
1301 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
1303 finally
1305 if (shouldReturnBuffer)
1307 bufferManager.ReturnBuffer(buffer);
1312 void ValidateEnterReadingState(bool checkEOF)
1314 if (checkEOF)
1316 if (closeState == CloseState.Closing)
1318 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
1322 if (inReadingState)
1324 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeReadPending)), ExceptionEventType);
1327 if (closeState == CloseState.HandleClosed)
1329 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
1333 void ValidateEnterWritingState(bool checkShutdown)
1335 if (checkShutdown)
1337 if (isShutdownWritten)
1339 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyShuttingDown)), ExceptionEventType);
1342 if (closeState == CloseState.Closing)
1344 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
1348 if (inWritingState)
1350 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeWritePending)), ExceptionEventType);
1353 if (closeState == CloseState.HandleClosed)
1355 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
1359 void StartSyncRead(byte[] buffer, int offset, int size)
1361 StartSyncRead(buffer, offset, size, ref this.readOverlapped.Holder[0]);
1364 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1365 unsafe void StartSyncRead(byte[] buffer, int offset, int size, ref object holder)
1367 if (this.isReadOutstanding)
1369 throw Fx.AssertAndThrow("StartSyncRead called when read I/O was already pending.");
1374 this.isReadOutstanding = true;
1375 this.readOverlapped.StartSyncOperation(buffer, ref holder);
1376 if (UnsafeNativeMethods.ReadFile(this.pipe.DangerousGetHandle(), this.readOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.readOverlapped.NativeOverlapped) == 0)
1378 int error = Marshal.GetLastWin32Error();
1379 if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
1381 this.isReadOutstanding = false;
1382 if (error != UnsafeNativeMethods.ERROR_MORE_DATA)
1384 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
1388 else
1390 this.isReadOutstanding = false;
1393 finally
1395 if (!this.isReadOutstanding)
1397 this.readOverlapped.CancelSyncOperation(ref holder);
1402 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1403 unsafe void WaitForSyncRead(TimeSpan timeout, bool traceExceptionsAsErrors)
1405 if (this.isReadOutstanding)
1407 if (!this.readOverlapped.WaitForSyncOperation(timeout))
1409 Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
1411 Exception timeoutException = new TimeoutException(SR.GetString(SR.PipeReadTimedOut, timeout));
1412 TraceEventType traceEventType = TraceEventType.Information;
1413 if (traceExceptionsAsErrors)
1415 traceEventType = TraceEventType.Error;
1418 // This intentionally doesn't reset isReadOutstanding, because technically it still is, and we need to not free the buffer.
1419 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(timeoutException, traceEventType);
1421 else
1423 this.isReadOutstanding = false;
1428 // Must be called in a lock.
1429 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1430 unsafe int FinishSyncRead(bool traceExceptionsAsErrors)
1432 int bytesRead = -1;
1433 Exception readException;
1435 if (this.closeState == CloseState.HandleClosed)
1437 readException = CreatePipeClosedException(TransferOperation.Read);
1439 else
1441 readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
1443 if (readException != null)
1445 TraceEventType traceEventType = TraceEventType.Information;
1446 if (traceExceptionsAsErrors)
1448 traceEventType = TraceEventType.Error;
1450 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(readException, traceEventType);
1453 return bytesRead;
1456 void StartSyncWrite(byte[] buffer, int offset, int size)
1458 StartSyncWrite(buffer, offset, size, ref this.writeOverlapped.Holder[0]);
1461 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1462 unsafe void StartSyncWrite(byte[] buffer, int offset, int size, ref object holder)
1464 if (this.isWriteOutstanding)
1466 throw Fx.AssertAndThrow("StartSyncWrite called when write I/O was already pending.");
1471 this.syncWriteSize = size;
1472 this.isWriteOutstanding = true;
1473 this.writeOverlapped.StartSyncOperation(buffer, ref holder);
1474 if (UnsafeNativeMethods.WriteFile(this.pipe.DangerousGetHandle(), this.writeOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.writeOverlapped.NativeOverlapped) == 0)
1476 int error = Marshal.GetLastWin32Error();
1477 if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
1479 this.isWriteOutstanding = false;
1480 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
1483 else
1485 this.isWriteOutstanding = false;
1488 finally
1490 if (!this.isWriteOutstanding)
1492 this.writeOverlapped.CancelSyncOperation(ref holder);
1497 void WaitForSyncWrite(TimeSpan timeout, bool traceExceptionsAsErrors)
1499 WaitForSyncWrite(timeout, traceExceptionsAsErrors, ref this.writeOverlapped.Holder[0]);
1502 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1503 unsafe void WaitForSyncWrite(TimeSpan timeout, bool traceExceptionsAsErrors, ref object holder)
1505 if (this.isWriteOutstanding)
1507 if (!this.writeOverlapped.WaitForSyncOperation(timeout, ref holder))
1509 Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, this.writeTimeout), TransferOperation.Write);
1511 Exception timeoutException = new TimeoutException(SR.GetString(SR.PipeWriteTimedOut, timeout));
1512 TraceEventType traceEventType = TraceEventType.Information;
1513 if (traceExceptionsAsErrors)
1515 traceEventType = TraceEventType.Error;
1518 // This intentionally doesn't reset isWriteOutstanding, because technically it still is, and we need to not free the buffer.
1519 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(timeoutException, traceEventType);
1521 else
1523 this.isWriteOutstanding = false;
1528 // Must be called in a lock.
1529 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1530 unsafe void FinishSyncWrite(bool traceExceptionsAsErrors)
1532 int bytesWritten;
1533 Exception writeException;
1535 if (this.closeState == CloseState.HandleClosed)
1537 writeException = CreatePipeClosedException(TransferOperation.Write);
1539 else
1541 writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
1542 if (writeException == null && bytesWritten != this.syncWriteSize)
1544 writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
1548 if (writeException != null)
1550 TraceEventType traceEventType = TraceEventType.Information;
1551 if (traceExceptionsAsErrors)
1553 traceEventType = TraceEventType.Error;
1555 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(writeException, traceEventType);
1559 enum CloseState
1561 Open,
1562 Closing,
1563 HandleClosed,
1566 enum TransferOperation
1568 Write,
1569 Read,
1570 Undefined,
1573 static class Exceptions
1575 static PipeException CreateException(string resourceString, int error)
1577 return new PipeException(SR.GetString(resourceString, PipeError.GetErrorString(error)), error);
1580 public static PipeException CreateReadException(int error)
1582 return CreateException(SR.PipeReadError, error);
1585 public static PipeException CreateWriteException(int error)
1587 return CreateException(SR.PipeWriteError, error);
1590 // Must be called in a lock, after checking for HandleClosed.
1591 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1592 public static unsafe PipeException GetOverlappedWriteException(PipeHandle pipe,
1593 NativeOverlapped* nativeOverlapped, out int bytesWritten)
1595 if (UnsafeNativeMethods.GetOverlappedResult(pipe.DangerousGetHandle(), nativeOverlapped, out bytesWritten, 0) == 0)
1597 int error = Marshal.GetLastWin32Error();
1598 return Exceptions.CreateWriteException(error);
1600 else
1602 return null;
1606 // Must be called in a lock, after checking for HandleClosed.
1607 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1608 public static unsafe PipeException GetOverlappedReadException(PipeHandle pipe,
1609 NativeOverlapped* nativeOverlapped, out int bytesRead)
1611 if (UnsafeNativeMethods.GetOverlappedResult(pipe.DangerousGetHandle(), nativeOverlapped, out bytesRead, 0) == 0)
1613 int error = Marshal.GetLastWin32Error();
1614 if (error == UnsafeNativeMethods.ERROR_MORE_DATA)
1616 return null;
1619 else
1621 return Exceptions.CreateReadException(error);
1624 else
1626 return null;
1633 class PipeConnectionInitiator : IConnectionInitiator
1635 int bufferSize;
1636 IPipeTransportFactorySettings pipeSettings;
1638 public PipeConnectionInitiator(int bufferSize, IPipeTransportFactorySettings pipeSettings)
1640 this.bufferSize = bufferSize;
1641 this.pipeSettings = pipeSettings;
1644 Exception CreateConnectFailedException(Uri remoteUri, PipeException innerException)
1646 return new CommunicationException(
1647 SR.GetString(SR.PipeConnectFailed, remoteUri.AbsoluteUri), innerException);
1650 public IConnection Connect(Uri remoteUri, TimeSpan timeout)
1652 string resolvedAddress;
1653 BackoffTimeoutHelper backoffHelper;
1654 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1655 this.PrepareConnect(remoteUri, timeoutHelper.RemainingTime(), out resolvedAddress, out backoffHelper);
1657 IConnection connection = null;
1658 while (connection == null)
1660 connection = this.TryConnect(remoteUri, resolvedAddress, backoffHelper);
1661 if (connection == null)
1663 backoffHelper.WaitAndBackoff();
1665 if (DiagnosticUtility.ShouldTraceInformation)
1667 TraceUtility.TraceEvent(
1668 TraceEventType.Information,
1669 TraceCode.FailedPipeConnect,
1670 SR.GetString(
1671 SR.TraceCodeFailedPipeConnect,
1672 timeoutHelper.RemainingTime(),
1673 remoteUri));
1677 return connection;
1680 internal static string GetPipeName(Uri uri, IPipeTransportFactorySettings transportFactorySettings)
1682 AppContainerInfo appInfo = GetAppContainerInfo(transportFactorySettings);
1684 // for wildcard hostName support, we first try and connect to the StrongWildcard,
1685 // then the Exact HostName, and lastly the WeakWildcard
1686 string[] hostChoices = new string[] { "+", uri.Host, "*" };
1687 bool[] globalChoices = new bool[] { true, false };
1688 string matchPath = String.Empty;
1689 string matchPipeName = null;
1691 for (int i = 0; i < hostChoices.Length; i++)
1693 for (int iGlobal = 0; iGlobal < globalChoices.Length; iGlobal++)
1696 if (appInfo != null && globalChoices[iGlobal])
1698 // Don't look at shared memory to acces pipes
1699 // that are created in the local NamedObjectPath
1700 continue;
1703 // walk up the path hierarchy, looking for match
1704 string path = PipeUri.GetPath(uri);
1706 while (path.Length > 0)
1709 string sharedMemoryName = PipeUri.BuildSharedMemoryName(hostChoices[i], path, globalChoices[iGlobal], appInfo);
1712 PipeSharedMemory sharedMemory = PipeSharedMemory.Open(sharedMemoryName, uri);
1713 if (sharedMemory != null)
1717 string pipeName = sharedMemory.GetPipeName(appInfo);
1718 if (pipeName != null)
1720 // Found a matching pipe name.
1721 // If the best match app setting is enabled, save the match if it is the best so far and continue.
1722 // Otherwise, just return the first match we find.
1723 if (ServiceModelAppSettings.UseBestMatchNamedPipeUri)
1725 if (path.Length > matchPath.Length)
1727 matchPath = path;
1728 matchPipeName = pipeName;
1731 else
1733 return pipeName;
1737 finally
1739 sharedMemory.Dispose();
1743 catch (AddressAccessDeniedException exception)
1745 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(
1746 SR.EndpointNotFound, uri.AbsoluteUri), exception));
1749 path = PipeUri.GetParentPath(path);
1754 if (string.IsNullOrEmpty(matchPipeName))
1756 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1757 new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, uri.AbsoluteUri),
1758 new PipeException(SR.GetString(SR.PipeEndpointNotFound, uri.AbsoluteUri))));
1761 return matchPipeName;
1764 public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
1766 return new ConnectAsyncResult(this, uri, timeout, callback, state);
1769 public IConnection EndConnect(IAsyncResult result)
1771 return ConnectAsyncResult.End(result);
1774 void PrepareConnect(Uri remoteUri, TimeSpan timeout, out string resolvedAddress, out BackoffTimeoutHelper backoffHelper)
1776 PipeUri.Validate(remoteUri);
1777 if (DiagnosticUtility.ShouldTraceInformation)
1779 TraceUtility.TraceEvent(System.Diagnostics.TraceEventType.Information, TraceCode.InitiatingNamedPipeConnection,
1780 SR.GetString(SR.TraceCodeInitiatingNamedPipeConnection),
1781 new StringTraceRecord("Uri", remoteUri.ToString()), this, null);
1783 resolvedAddress = GetPipeName(remoteUri, this.pipeSettings);
1784 const int backoffBufferMilliseconds = 150;
1785 TimeSpan backoffTimeout;
1786 if (timeout >= TimeSpan.FromMilliseconds(backoffBufferMilliseconds * 2))
1788 backoffTimeout = TimeoutHelper.Add(timeout, TimeSpan.Zero - TimeSpan.FromMilliseconds(backoffBufferMilliseconds));
1790 else
1792 backoffTimeout = Ticks.ToTimeSpan((Ticks.FromMilliseconds(backoffBufferMilliseconds) / 2) + 1);
1795 backoffHelper = new BackoffTimeoutHelper(backoffTimeout, TimeSpan.FromMinutes(5));
1798 [ResourceConsumption(ResourceScope.Machine)]
1799 IConnection TryConnect(Uri remoteUri, string resolvedAddress, BackoffTimeoutHelper backoffHelper)
1801 const int access = UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE;
1802 bool lastAttempt = backoffHelper.IsExpired();
1804 int flags = UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
1806 // By default Windows named pipe connection is created with impersonation, but we want
1807 // to create it with anonymous and let WCF take care of impersonation/identification.
1808 flags |= UnsafeNativeMethods.SECURITY_QOS_PRESENT | UnsafeNativeMethods.SECURITY_ANONYMOUS;
1810 PipeHandle pipeHandle = UnsafeNativeMethods.CreateFile(resolvedAddress, access, 0, IntPtr.Zero,
1811 UnsafeNativeMethods.OPEN_EXISTING, flags, IntPtr.Zero);
1812 int error = Marshal.GetLastWin32Error();
1813 if (pipeHandle.IsInvalid)
1815 pipeHandle.SetHandleAsInvalid();
1817 else
1819 int mode = UnsafeNativeMethods.PIPE_READMODE_MESSAGE;
1820 if (UnsafeNativeMethods.SetNamedPipeHandleState(pipeHandle, ref mode, IntPtr.Zero, IntPtr.Zero) == 0)
1822 error = Marshal.GetLastWin32Error();
1823 pipeHandle.Close();
1824 PipeException innerException = new PipeException(SR.GetString(SR.PipeModeChangeFailed,
1825 PipeError.GetErrorString(error)), error);
1826 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1827 CreateConnectFailedException(remoteUri, innerException));
1829 return new PipeConnection(pipeHandle, bufferSize, false, true);
1832 if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND || error == UnsafeNativeMethods.ERROR_PIPE_BUSY)
1834 if (lastAttempt)
1836 Exception innerException = new PipeException(SR.GetString(SR.PipeConnectAddressFailed,
1837 resolvedAddress, PipeError.GetErrorString(error)), error);
1839 TimeoutException timeoutException;
1840 string endpoint = remoteUri.AbsoluteUri;
1842 if (error == UnsafeNativeMethods.ERROR_PIPE_BUSY)
1844 timeoutException = new TimeoutException(SR.GetString(SR.PipeConnectTimedOutServerTooBusy,
1845 endpoint, backoffHelper.OriginalTimeout), innerException);
1847 else
1849 timeoutException = new TimeoutException(SR.GetString(SR.PipeConnectTimedOut,
1850 endpoint, backoffHelper.OriginalTimeout), innerException);
1853 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(timeoutException);
1856 return null;
1858 else
1860 PipeException innerException = new PipeException(SR.GetString(SR.PipeConnectAddressFailed,
1861 resolvedAddress, PipeError.GetErrorString(error)), error);
1862 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1863 CreateConnectFailedException(remoteUri, innerException));
1867 static AppContainerInfo GetAppContainerInfo(IPipeTransportFactorySettings transportFactorySettings)
1869 if (AppContainerInfo.IsAppContainerSupported &&
1870 transportFactorySettings != null &&
1871 transportFactorySettings.PipeSettings != null)
1873 ApplicationContainerSettings appSettings = transportFactorySettings.PipeSettings.ApplicationContainerSettings;
1874 if (appSettings != null && appSettings.TargetingAppContainer)
1876 return AppContainerInfo.CreateAppContainerInfo(appSettings.PackageFullName, appSettings.SessionId);
1880 return null;
1883 class ConnectAsyncResult : AsyncResult
1885 PipeConnectionInitiator parent;
1886 Uri remoteUri;
1887 string resolvedAddress;
1888 BackoffTimeoutHelper backoffHelper;
1889 TimeoutHelper timeoutHelper;
1890 IConnection connection;
1891 static Action<object> waitCompleteCallback;
1893 public ConnectAsyncResult(PipeConnectionInitiator parent, Uri remoteUri, TimeSpan timeout,
1894 AsyncCallback callback, object state)
1895 : base(callback, state)
1897 this.parent = parent;
1898 this.remoteUri = remoteUri;
1899 this.timeoutHelper = new TimeoutHelper(timeout);
1900 parent.PrepareConnect(remoteUri, this.timeoutHelper.RemainingTime(), out this.resolvedAddress, out this.backoffHelper);
1902 if (this.ConnectAndWait())
1904 this.Complete(true);
1908 bool ConnectAndWait()
1910 this.connection = this.parent.TryConnect(this.remoteUri, this.resolvedAddress, this.backoffHelper);
1911 bool completed = (this.connection != null);
1912 if (!completed)
1914 if (waitCompleteCallback == null)
1916 waitCompleteCallback = new Action<object>(OnWaitComplete);
1918 this.backoffHelper.WaitAndBackoff(waitCompleteCallback, this);
1920 return completed;
1923 public static IConnection End(IAsyncResult result)
1925 ConnectAsyncResult thisPtr = AsyncResult.End<ConnectAsyncResult>(result);
1926 return thisPtr.connection;
1929 static void OnWaitComplete(object state)
1931 Exception exception = null;
1932 ConnectAsyncResult thisPtr = (ConnectAsyncResult)state;
1934 bool completeSelf = true;
1937 if (DiagnosticUtility.ShouldTraceInformation)
1939 TraceUtility.TraceEvent(
1940 TraceEventType.Information,
1941 TraceCode.FailedPipeConnect,
1942 SR.GetString(
1943 SR.TraceCodeFailedPipeConnect,
1944 thisPtr.timeoutHelper.RemainingTime(),
1945 thisPtr.remoteUri));
1948 completeSelf = thisPtr.ConnectAndWait();
1950 catch (Exception e)
1952 if (Fx.IsFatal(e))
1954 throw;
1956 exception = e;
1959 if (completeSelf)
1961 thisPtr.Complete(false, exception);
1967 class PipeConnectionListener : IConnectionListener
1969 Uri pipeUri;
1970 int bufferSize;
1971 HostNameComparisonMode hostNameComparisonMode;
1972 bool isDisposed;
1973 bool isListening;
1974 List<PendingAccept> pendingAccepts;
1975 bool anyPipesCreated;
1976 PipeSharedMemory sharedMemory;
1977 List<SecurityIdentifier> allowedSids;
1978 bool useCompletionPort;
1979 int maxInstances;
1981 public PipeConnectionListener(Uri pipeUri, HostNameComparisonMode hostNameComparisonMode, int bufferSize,
1982 List<SecurityIdentifier> allowedSids, bool useCompletionPort, int maxConnections)
1984 PipeUri.Validate(pipeUri);
1985 this.pipeUri = pipeUri;
1986 this.hostNameComparisonMode = hostNameComparisonMode;
1987 this.allowedSids = allowedSids;
1988 this.bufferSize = bufferSize;
1989 pendingAccepts = new List<PendingAccept>();
1990 this.useCompletionPort = useCompletionPort;
1991 this.maxInstances = Math.Min(maxConnections, UnsafeNativeMethods.PIPE_UNLIMITED_INSTANCES);
1994 object ThisLock
1996 get { return this; }
1999 public string PipeName { get { return sharedMemory.PipeName; } }
2001 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
2003 lock (ThisLock)
2005 if (isDisposed)
2007 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException("", SR.GetString(SR.PipeListenerDisposed)));
2010 if (!isListening)
2012 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PipeListenerNotListening)));
2015 PipeHandle pipeHandle = CreatePipe();
2016 PendingAccept pendingAccept = new PendingAccept(this, pipeHandle, useCompletionPort, callback, state);
2017 if (!pendingAccept.CompletedSynchronously)
2019 this.pendingAccepts.Add(pendingAccept);
2021 return pendingAccept;
2025 public IConnection EndAccept(IAsyncResult result)
2027 PendingAccept pendingAccept = result as PendingAccept;
2028 if (pendingAccept == null)
2030 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("result", SR.GetString(SR.InvalidAsyncResult));
2033 PipeHandle acceptedPipe = pendingAccept.End();
2035 if (acceptedPipe == null)
2037 return null;
2039 else
2041 return new PipeConnection(acceptedPipe, bufferSize,
2042 pendingAccept.IsBoundToCompletionPort, pendingAccept.IsBoundToCompletionPort);
2046 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2047 [ResourceConsumption(ResourceScope.Machine)]
2048 unsafe PipeHandle CreatePipe()
2050 int openMode = UnsafeNativeMethods.PIPE_ACCESS_DUPLEX | UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
2051 if (!anyPipesCreated)
2053 openMode |= UnsafeNativeMethods.FILE_FLAG_FIRST_PIPE_INSTANCE;
2056 byte[] binarySecurityDescriptor;
2060 binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE);
2062 catch (Win32Exception e)
2064 // While Win32exceptions are not expected, if they do occur we need to obey the pipe/communication exception model.
2065 Exception innerException = new PipeException(e.Message, e);
2066 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
2069 PipeHandle pipeHandle;
2070 int error;
2071 string pipeName = null;
2072 fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
2074 UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
2075 securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
2077 pipeName = this.sharedMemory.PipeName;
2078 pipeHandle = UnsafeNativeMethods.CreateNamedPipe(
2079 pipeName,
2080 openMode,
2081 UnsafeNativeMethods.PIPE_TYPE_MESSAGE | UnsafeNativeMethods.PIPE_READMODE_MESSAGE,
2082 maxInstances, bufferSize, bufferSize, 0, securityAttributes);
2083 error = Marshal.GetLastWin32Error();
2086 if (pipeHandle.IsInvalid)
2088 pipeHandle.SetHandleAsInvalid();
2090 Exception innerException = new PipeException(SR.GetString(SR.PipeListenFailed,
2091 pipeUri.AbsoluteUri, PipeError.GetErrorString(error)), error);
2093 if (error == UnsafeNativeMethods.ERROR_ACCESS_DENIED)
2095 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAccessDeniedException(innerException.Message, innerException));
2097 else if (error == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
2099 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAlreadyInUseException(innerException.Message, innerException));
2101 else
2103 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
2106 else
2108 if (TD.NamedPipeCreatedIsEnabled())
2110 TD.NamedPipeCreated(pipeName);
2114 bool closePipe = true;
2117 if (useCompletionPort)
2119 ThreadPool.BindHandle(pipeHandle);
2121 anyPipesCreated = true;
2122 closePipe = false;
2123 return pipeHandle;
2125 finally
2127 if (closePipe)
2129 pipeHandle.Close();
2134 public void Dispose()
2136 lock (ThisLock)
2138 if (!isDisposed)
2140 if (sharedMemory != null)
2142 sharedMemory.Dispose();
2144 for (int i = 0; i < pendingAccepts.Count; i++)
2146 pendingAccepts[i].Abort();
2148 isDisposed = true;
2153 public void Listen()
2155 lock (ThisLock)
2157 if (!isListening)
2159 string sharedMemoryName = PipeUri.BuildSharedMemoryName(pipeUri, hostNameComparisonMode, true);
2160 if (!PipeSharedMemory.TryCreate(allowedSids, pipeUri, sharedMemoryName, out this.sharedMemory))
2162 PipeSharedMemory tempSharedMemory = null;
2164 // first see if we're in RANU by creating a unique Uri in the global namespace
2165 Uri tempUri = new Uri(pipeUri, Guid.NewGuid().ToString());
2166 string tempSharedMemoryName = PipeUri.BuildSharedMemoryName(tempUri, hostNameComparisonMode, true);
2167 if (PipeSharedMemory.TryCreate(allowedSids, tempUri, tempSharedMemoryName, out tempSharedMemory))
2169 // we're not RANU, throw PipeNameInUse
2170 tempSharedMemory.Dispose();
2171 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
2172 PipeSharedMemory.CreatePipeNameInUseException(UnsafeNativeMethods.ERROR_ACCESS_DENIED, pipeUri));
2174 else
2176 // try the session namespace since we're RANU
2177 sharedMemoryName = PipeUri.BuildSharedMemoryName(pipeUri, hostNameComparisonMode, false);
2178 this.sharedMemory = PipeSharedMemory.Create(allowedSids, pipeUri, sharedMemoryName);
2182 isListening = true;
2187 void RemovePendingAccept(PendingAccept pendingAccept)
2189 lock (ThisLock)
2191 Fx.Assert(this.pendingAccepts.Contains(pendingAccept), "An unknown PendingAccept is removing itself.");
2192 this.pendingAccepts.Remove(pendingAccept);
2196 class PendingAccept : AsyncResult
2198 PipeHandle pipeHandle;
2199 PipeHandle result;
2200 OverlappedIOCompleteCallback onAcceptComplete;
2201 static Action<object> onStartAccept;
2202 OverlappedContext overlapped;
2203 bool isBoundToCompletionPort;
2204 PipeConnectionListener listener;
2205 EventTraceActivity eventTraceActivity;
2207 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2208 public unsafe PendingAccept(PipeConnectionListener listener, PipeHandle pipeHandle, bool isBoundToCompletionPort,
2209 AsyncCallback callback, object state)
2210 : base(callback, state)
2212 this.pipeHandle = pipeHandle;
2213 this.result = pipeHandle;
2214 this.listener = listener;
2215 onAcceptComplete = new OverlappedIOCompleteCallback(OnAcceptComplete);
2216 overlapped = new OverlappedContext();
2217 this.isBoundToCompletionPort = isBoundToCompletionPort;
2219 if (TD.PipeConnectionAcceptStartIsEnabled())
2221 this.eventTraceActivity = new EventTraceActivity();
2222 TD.PipeConnectionAcceptStart(this.eventTraceActivity, this.listener.pipeUri != null ? this.listener.pipeUri.ToString() : string.Empty);
2225 if (!Thread.CurrentThread.IsThreadPoolThread)
2227 if (onStartAccept == null)
2229 onStartAccept = new Action<object>(OnStartAccept);
2231 ActionItem.Schedule(onStartAccept, this);
2233 else
2235 StartAccept(true);
2239 public bool IsBoundToCompletionPort
2241 get { return this.isBoundToCompletionPort; }
2244 static void OnStartAccept(object state)
2246 PendingAccept pendingAccept = (PendingAccept)state;
2247 pendingAccept.StartAccept(false);
2250 Exception CreatePipeAcceptFailedException(int errorCode)
2252 Exception innerException = new PipeException(SR.GetString(SR.PipeAcceptFailed,
2253 PipeError.GetErrorString(errorCode)), errorCode);
2254 return new CommunicationException(innerException.Message, innerException);
2257 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2258 unsafe void StartAccept(bool synchronous)
2260 Exception completionException = null;
2261 bool completeSelf = false;
2266 this.overlapped.StartAsyncOperation(null, onAcceptComplete, this.isBoundToCompletionPort);
2267 while (true)
2269 if (UnsafeNativeMethods.ConnectNamedPipe(pipeHandle, overlapped.NativeOverlapped) == 0)
2271 int error = Marshal.GetLastWin32Error();
2272 switch (error)
2274 case UnsafeNativeMethods.ERROR_NO_DATA:
2275 if (UnsafeNativeMethods.DisconnectNamedPipe(pipeHandle) != 0)
2277 continue;
2279 else
2281 completeSelf = true;
2282 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeAcceptFailedException(error));
2284 case UnsafeNativeMethods.ERROR_PIPE_CONNECTED:
2285 completeSelf = true;
2286 break;
2287 case UnsafeNativeMethods.ERROR_IO_PENDING:
2288 break;
2289 default:
2290 completeSelf = true;
2291 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeAcceptFailedException(error));
2294 else
2296 completeSelf = true;
2299 break;
2302 catch (ObjectDisposedException exception)
2304 // A ---- with Abort can cause PipeHandle to throw this.
2305 Fx.Assert(this.result == null, "Got an ObjectDisposedException but not an Abort!");
2306 DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
2307 completeSelf = true;
2309 finally
2311 if (completeSelf)
2313 this.overlapped.CancelAsyncOperation();
2314 this.overlapped.Free();
2318 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
2319 catch (Exception e)
2321 if (Fx.IsFatal(e))
2323 throw;
2326 completeSelf = true;
2327 completionException = e;
2329 if (completeSelf)
2331 if (!synchronous)
2333 this.listener.RemovePendingAccept(this);
2335 base.Complete(synchronous, completionException);
2339 // Must be called in PipeConnectionListener's lock.
2340 public void Abort()
2342 this.result = null; // we need to return null after an abort
2343 pipeHandle.Close();
2346 public PipeHandle End()
2348 AsyncResult.End<PendingAccept>(this);
2349 return this.result;
2352 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2353 unsafe void OnAcceptComplete(bool haveResult, int error, int numBytes)
2355 this.listener.RemovePendingAccept(this);
2357 if (!haveResult)
2359 // No ---- with Abort here since Abort can't be called once RemovePendingAccept happens.
2360 if (this.result != null && UnsafeNativeMethods.GetOverlappedResult(this.pipeHandle,
2361 this.overlapped.NativeOverlapped, out numBytes, 0) == 0)
2363 error = Marshal.GetLastWin32Error();
2365 else
2367 error = 0;
2371 this.overlapped.Free();
2373 if (TD.PipeConnectionAcceptStopIsEnabled())
2375 TD.PipeConnectionAcceptStop(this.eventTraceActivity);
2378 if (error != 0)
2380 this.pipeHandle.Close();
2381 base.Complete(false, CreatePipeAcceptFailedException(error));
2383 else
2385 base.Complete(false);
2391 static class SecurityDescriptorHelper
2393 static byte[] worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork;
2394 static byte[] worldCreatorOwnerWithReadDescriptorDenyNetwork;
2396 static SecurityDescriptorHelper()
2398 worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork = FromSecurityIdentifiersFull(null, UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE);
2399 worldCreatorOwnerWithReadDescriptorDenyNetwork = FromSecurityIdentifiersFull(null, UnsafeNativeMethods.GENERIC_READ);
2402 internal static byte[] FromSecurityIdentifiers(List<SecurityIdentifier> allowedSids, int accessRights)
2404 if (allowedSids == null)
2406 if (accessRights == (UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE))
2408 return worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork;
2411 if (accessRights == UnsafeNativeMethods.GENERIC_READ)
2413 return worldCreatorOwnerWithReadDescriptorDenyNetwork;
2417 return FromSecurityIdentifiersFull(allowedSids, accessRights);
2420 static byte[] FromSecurityIdentifiersFull(List<SecurityIdentifier> allowedSids, int accessRights)
2422 int capacity = allowedSids == null ? 3 : 2 + allowedSids.Count;
2423 DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, capacity);
2425 // add deny ACE first so that we don't get short circuited
2426 dacl.AddAccess(AccessControlType.Deny, new SecurityIdentifier(WellKnownSidType.NetworkSid, null),
2427 UnsafeNativeMethods.GENERIC_ALL, InheritanceFlags.None, PropagationFlags.None);
2429 // clients get different rights, since they shouldn't be able to listen
2430 int clientAccessRights = GenerateClientAccessRights(accessRights);
2432 if (allowedSids == null)
2434 dacl.AddAccess(AccessControlType.Allow, new SecurityIdentifier(WellKnownSidType.WorldSid, null),
2435 clientAccessRights, InheritanceFlags.None, PropagationFlags.None);
2437 else
2439 for (int i = 0; i < allowedSids.Count; i++)
2441 SecurityIdentifier allowedSid = allowedSids[i];
2442 dacl.AddAccess(AccessControlType.Allow, allowedSid,
2443 clientAccessRights, InheritanceFlags.None, PropagationFlags.None);
2447 dacl.AddAccess(AccessControlType.Allow, GetProcessLogonSid(), accessRights, InheritanceFlags.None, PropagationFlags.None);
2450 if (AppContainerInfo.IsRunningInAppContainer)
2452 // NamedPipeBinding requires dacl with current AppContainer SID
2453 // to setup multiple NamedPipes in the BeginAccept loop.
2454 dacl.AddAccess(
2455 AccessControlType.Allow,
2456 AppContainerInfo.GetCurrentAppContainerSid(),
2457 accessRights,
2458 InheritanceFlags.None,
2459 PropagationFlags.None);
2462 CommonSecurityDescriptor securityDescriptor =
2463 new CommonSecurityDescriptor(false, false, ControlFlags.None, null, null, null, dacl);
2464 byte[] binarySecurityDescriptor = new byte[securityDescriptor.BinaryLength];
2465 securityDescriptor.GetBinaryForm(binarySecurityDescriptor, 0);
2466 return binarySecurityDescriptor;
2469 // Security: We cannot grant rights for FILE_CREATE_PIPE_INSTANCE to clients, otherwise other apps can intercept server side pipes.
2470 // FILE_CREATE_PIPE_INSTANCE is granted in 2 ways, via GENERIC_WRITE or directly specified. Remove both.
2471 static int GenerateClientAccessRights(int accessRights)
2473 int everyoneAccessRights = accessRights;
2475 if ((everyoneAccessRights & UnsafeNativeMethods.GENERIC_WRITE) != 0)
2477 everyoneAccessRights &= ~UnsafeNativeMethods.GENERIC_WRITE;
2479 // Since GENERIC_WRITE grants the permissions to write to a file, we need to add it back.
2480 const int clientWriteAccess = UnsafeNativeMethods.FILE_WRITE_ATTRIBUTES | UnsafeNativeMethods.FILE_WRITE_DATA | UnsafeNativeMethods.FILE_WRITE_EA;
2481 everyoneAccessRights |= clientWriteAccess;
2484 // Future proofing: FILE_CREATE_PIPE_INSTANCE isn't used currently but we need to ensure it is not granted.
2485 everyoneAccessRights &= ~UnsafeNativeMethods.FILE_CREATE_PIPE_INSTANCE;
2487 return everyoneAccessRights;
2490 // The logon sid is generated on process start up so it is unique to this process.
2491 static SecurityIdentifier GetProcessLogonSid()
2493 int pid = Process.GetCurrentProcess().Id;
2494 return System.ServiceModel.Activation.Utility.GetLogonSidForPid(pid);
2498 unsafe class PipeSharedMemory : IDisposable
2500 internal const string PipePrefix = @"\\.\pipe\";
2501 internal const string PipeLocalPrefix = @"\\.\pipe\Local\";
2502 SafeFileMappingHandle fileMapping;
2503 string pipeName;
2504 string pipeNameGuidPart;
2505 Uri pipeUri;
2507 PipeSharedMemory(SafeFileMappingHandle fileMapping, Uri pipeUri)
2508 : this(fileMapping, pipeUri, null)
2512 PipeSharedMemory(SafeFileMappingHandle fileMapping, Uri pipeUri, string pipeName)
2514 this.pipeName = pipeName;
2515 this.fileMapping = fileMapping;
2516 this.pipeUri = pipeUri;
2519 public static PipeSharedMemory Create(List<SecurityIdentifier> allowedSids, Uri pipeUri, string sharedMemoryName)
2521 PipeSharedMemory result;
2522 if (TryCreate(allowedSids, pipeUri, sharedMemoryName, out result))
2524 return result;
2526 else
2528 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameInUseException(UnsafeNativeMethods.ERROR_ACCESS_DENIED, pipeUri));
2532 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2533 public unsafe static bool TryCreate(List<SecurityIdentifier> allowedSids, Uri pipeUri, string sharedMemoryName, out PipeSharedMemory result)
2535 Guid pipeGuid = Guid.NewGuid();
2536 string pipeName = BuildPipeName(pipeGuid.ToString());
2537 byte[] binarySecurityDescriptor;
2540 binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ);
2542 catch (Win32Exception e)
2544 // While Win32exceptions are not expected, if they do occur we need to obey the pipe/communication exception model.
2545 Exception innerException = new PipeException(e.Message, e);
2546 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
2549 SafeFileMappingHandle fileMapping;
2550 int error;
2551 result = null;
2552 fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
2554 UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
2555 securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
2557 fileMapping = UnsafeNativeMethods.CreateFileMapping((IntPtr)(-1), securityAttributes,
2558 UnsafeNativeMethods.PAGE_READWRITE, 0, sizeof(SharedMemoryContents), sharedMemoryName);
2559 error = Marshal.GetLastWin32Error();
2562 if (fileMapping.IsInvalid)
2564 fileMapping.SetHandleAsInvalid();
2565 if (error == UnsafeNativeMethods.ERROR_ACCESS_DENIED)
2567 return false;
2569 else
2571 Exception innerException = new PipeException(SR.GetString(SR.PipeNameCantBeReserved,
2572 pipeUri.AbsoluteUri, PipeError.GetErrorString(error)), error);
2573 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAccessDeniedException(innerException.Message, innerException));
2577 // now we have a valid file mapping handle
2578 if (error == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
2580 fileMapping.Close();
2581 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameInUseException(error, pipeUri));
2583 PipeSharedMemory pipeSharedMemory = new PipeSharedMemory(fileMapping, pipeUri, pipeName);
2584 bool disposeSharedMemory = true;
2587 pipeSharedMemory.InitializeContents(pipeGuid);
2588 disposeSharedMemory = false;
2589 result = pipeSharedMemory;
2591 if (TD.PipeSharedMemoryCreatedIsEnabled())
2593 TD.PipeSharedMemoryCreated(sharedMemoryName);
2595 return true;
2597 finally
2599 if (disposeSharedMemory)
2601 pipeSharedMemory.Dispose();
2606 [ResourceConsumption(ResourceScope.Machine)]
2607 public static PipeSharedMemory Open(string sharedMemoryName, Uri pipeUri)
2609 SafeFileMappingHandle fileMapping = UnsafeNativeMethods.OpenFileMapping(
2610 UnsafeNativeMethods.FILE_MAP_READ, false, sharedMemoryName);
2611 if (fileMapping.IsInvalid)
2613 int error = Marshal.GetLastWin32Error();
2614 fileMapping.SetHandleAsInvalid();
2615 if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
2617 fileMapping = UnsafeNativeMethods.OpenFileMapping(
2618 UnsafeNativeMethods.FILE_MAP_READ, false, "Global\\" + sharedMemoryName);
2619 if (fileMapping.IsInvalid)
2621 error = Marshal.GetLastWin32Error();
2622 fileMapping.SetHandleAsInvalid();
2623 if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
2625 return null;
2627 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2629 return new PipeSharedMemory(fileMapping, pipeUri);
2632 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2634 return new PipeSharedMemory(fileMapping, pipeUri);
2637 public void Dispose()
2639 if (fileMapping != null)
2641 fileMapping.Close();
2642 fileMapping = null;
2646 public string PipeName
2648 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2651 if (pipeName == null)
2653 SafeViewOfFileHandle view = GetView(false);
2656 SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
2657 if (contents->isInitialized)
2659 Thread.MemoryBarrier();
2660 this.pipeNameGuidPart = contents->pipeGuid.ToString();
2661 this.pipeName = BuildPipeName(this.pipeNameGuidPart);
2664 finally
2666 view.Close();
2669 return pipeName;
2673 internal string GetPipeName(AppContainerInfo appInfo)
2675 if (appInfo == null)
2677 return this.PipeName;
2679 else if (this.PipeName != null)
2681 // Build the PipeName for a pipe inside an AppContainer as follows
2682 // \\.\pipe\Sessions\<SessionId>\<NamedObjectPath>\<PipeGuid>
2683 return string.Format(
2684 CultureInfo.InvariantCulture,
2685 @"\\.\pipe\Sessions\{0}\{1}\{2}",
2686 appInfo.SessionId,
2687 appInfo.NamedObjectPath,
2688 this.pipeNameGuidPart);
2691 return null;
2694 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2695 void InitializeContents(Guid pipeGuid)
2697 SafeViewOfFileHandle view = GetView(true);
2700 SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
2701 contents->pipeGuid = pipeGuid;
2702 Thread.MemoryBarrier();
2703 contents->isInitialized = true;
2705 finally
2707 view.Close();
2711 public static Exception CreatePipeNameInUseException(int error, Uri pipeUri)
2713 Exception innerException = new PipeException(SR.GetString(SR.PipeNameInUse, pipeUri.AbsoluteUri), error);
2714 return new AddressAlreadyInUseException(innerException.Message, innerException);
2717 static Exception CreatePipeNameCannotBeAccessedException(int error, Uri pipeUri)
2719 Exception innerException = new PipeException(SR.GetString(SR.PipeNameCanNotBeAccessed,
2720 PipeError.GetErrorString(error)), error);
2721 return new AddressAccessDeniedException(SR.GetString(SR.PipeNameCanNotBeAccessed2, pipeUri.AbsoluteUri), innerException);
2724 SafeViewOfFileHandle GetView(bool writable)
2726 SafeViewOfFileHandle handle = UnsafeNativeMethods.MapViewOfFile(fileMapping,
2727 writable ? UnsafeNativeMethods.FILE_MAP_WRITE : UnsafeNativeMethods.FILE_MAP_READ,
2728 0, 0, (IntPtr)sizeof(SharedMemoryContents));
2729 if (handle.IsInvalid)
2731 int error = Marshal.GetLastWin32Error();
2732 handle.SetHandleAsInvalid();
2733 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2735 return handle;
2738 static string BuildPipeName(string pipeGuid)
2740 return (AppContainerInfo.IsRunningInAppContainer ? PipeLocalPrefix : PipePrefix) + pipeGuid;
2743 [StructLayout(LayoutKind.Sequential)]
2744 struct SharedMemoryContents
2746 public bool isInitialized;
2747 public Guid pipeGuid;
2751 static class PipeUri
2753 public static string BuildSharedMemoryName(Uri uri, HostNameComparisonMode hostNameComparisonMode, bool global)
2755 string path = PipeUri.GetPath(uri);
2756 string host = null;
2758 switch (hostNameComparisonMode)
2760 case HostNameComparisonMode.StrongWildcard:
2761 host = "+";
2762 break;
2763 case HostNameComparisonMode.Exact:
2764 host = uri.Host;
2765 break;
2766 case HostNameComparisonMode.WeakWildcard:
2767 host = "*";
2768 break;
2771 return PipeUri.BuildSharedMemoryName(host, path, global);
2774 internal static string BuildSharedMemoryName(string hostName, string path, bool global, AppContainerInfo appContainerInfo)
2776 if (appContainerInfo == null)
2778 return BuildSharedMemoryName(hostName, path, global);
2780 else
2782 Fx.Assert(appContainerInfo.SessionId != ApplicationContainerSettingsDefaults.CurrentSession, "Session has not yet been initialized.");
2783 Fx.Assert(!String.IsNullOrEmpty(appContainerInfo.NamedObjectPath),
2784 "NamedObjectPath cannot be empty when creating the SharedMemoryName when running in an AppContainer.");
2786 //We need to use a session symlink for the lowbox appcontainer.
2787 // Session\{0}\{1}\{2}\<SharedMemoryName>
2788 return string.Format(
2789 CultureInfo.InvariantCulture,
2790 @"Session\{0}\{1}\{2}",
2791 appContainerInfo.SessionId,
2792 appContainerInfo.NamedObjectPath,
2793 BuildSharedMemoryName(hostName, path, global));
2797 static string BuildSharedMemoryName(string hostName, string path, bool global)
2799 StringBuilder builder = new StringBuilder();
2800 builder.Append(Uri.UriSchemeNetPipe);
2801 builder.Append("://");
2802 builder.Append(hostName.ToUpperInvariant());
2803 builder.Append(path);
2804 string canonicalName = builder.ToString();
2806 byte[] canonicalBytes = Encoding.UTF8.GetBytes(canonicalName);
2807 byte[] hashedBytes;
2808 string separator;
2810 if (canonicalBytes.Length >= 128)
2812 using (HashAlgorithm hash = GetHashAlgorithm())
2814 hashedBytes = hash.ComputeHash(canonicalBytes);
2816 separator = ":H";
2818 else
2820 hashedBytes = canonicalBytes;
2821 separator = ":E";
2824 builder = new StringBuilder();
2825 if (global)
2827 // we may need to create the shared memory in the global namespace so we work with terminal services+admin
2828 builder.Append("Global\\");
2830 else
2832 builder.Append("Local\\");
2834 builder.Append(Uri.UriSchemeNetPipe);
2835 builder.Append(separator);
2836 builder.Append(Convert.ToBase64String(hashedBytes));
2837 return builder.ToString();
2840 [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. It will cause compatibility issue. Not used for cryptographic purposes.")]
2841 static HashAlgorithm GetHashAlgorithm()
2843 if (!LocalAppContextSwitches.UseSha1InPipeConnectionGetHashAlgorithm)
2845 if (SecurityUtilsEx.RequiresFipsCompliance)
2846 return new SHA256CryptoServiceProvider();
2847 else
2848 return new SHA256Managed();
2850 else
2852 if (SecurityUtilsEx.RequiresFipsCompliance)
2853 return new SHA1CryptoServiceProvider();
2854 else
2855 return new SHA1Managed();
2859 public static string GetPath(Uri uri)
2861 string path = uri.LocalPath.ToUpperInvariant();
2862 if (!path.EndsWith("/", StringComparison.Ordinal))
2863 path = path + "/";
2864 return path;
2867 public static string GetParentPath(string path)
2869 if (path.EndsWith("/", StringComparison.Ordinal))
2870 path = path.Substring(0, path.Length - 1);
2871 if (path.Length == 0)
2872 return path;
2873 return path.Substring(0, path.LastIndexOf('/') + 1);
2876 public static void Validate(Uri uri)
2878 if (uri.Scheme != Uri.UriSchemeNetPipe)
2879 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("uri", SR.GetString(SR.PipeUriSchemeWrong));
2883 static class PipeError
2885 public static string GetErrorString(int error)
2887 StringBuilder stringBuilder = new StringBuilder(512);
2888 if (UnsafeNativeMethods.FormatMessage(UnsafeNativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS |
2889 UnsafeNativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | UnsafeNativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY,
2890 IntPtr.Zero, error, CultureInfo.CurrentCulture.LCID, stringBuilder, stringBuilder.Capacity, IntPtr.Zero) != 0)
2892 stringBuilder = stringBuilder.Replace("\n", "");
2893 stringBuilder = stringBuilder.Replace("\r", "");
2894 return SR.GetString(
2895 SR.PipeKnownWin32Error,
2896 stringBuilder.ToString(),
2897 error.ToString(CultureInfo.InvariantCulture),
2898 Convert.ToString(error, 16));
2900 else
2902 return SR.GetString(
2903 SR.PipeUnknownWin32Error,
2904 error.ToString(CultureInfo.InvariantCulture),
2905 Convert.ToString(error, 16));