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
;
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
;
29 using System
.Threading
;
30 using SafeCloseHandle
= System
.ServiceModel
.Activation
.SafeCloseHandle
;
32 sealed class PipeConnection
: IConnection
36 CloseState closeState
;
38 bool isBoundToCompletionPort
;
39 bool autoBindToCompletionPort
;
40 TraceEventType exceptionEventType
;
41 static byte[] zeroBuffer
;
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
;
50 ManualResetEvent atEOFEvent
;
52 OverlappedIOCompleteCallback onAsyncReadComplete
;
53 Exception asyncReadException
;
54 WaitCallback asyncReadCallback
;
55 object asyncReadCallbackState
;
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
;
69 byte[] pendingWriteBuffer
;
70 BufferManager pendingWriteBufferManager
;
71 OverlappedIOCompleteCallback onAsyncWriteComplete
;
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
)
87 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperArgumentNull("pipe");
89 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperArgumentNull("pipe");
91 this.closeState
= CloseState
.Open
;
92 this.exceptionEventType
= TraceEventType
.Error
;
93 this.isBoundToCompletionPort
= isBoundToCompletionPort
;
94 this.autoBindToCompletionPort
= autoBindToCompletionPort
;
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
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
);
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
);
217 return new CommunicationException(this.timeoutErrorString
, pipeException
);
220 else if (this.aborted
)
222 return new CommunicationObjectAbortedException(exceptionMessage
, pipeException
);
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
);
240 ValidateEnterReadingState(true);
245 asyncReadException
= null;
246 return AsyncCompletionResult
.Completed
;
249 if (autoBindToCompletionPort
)
251 if (!isBoundToCompletionPort
)
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
));
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
)
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
);
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.
343 ValidateEnterWritingState(true);
345 EnsureBoundToCompletionPort();
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
));
385 if (!this.isWriteOutstanding
)
387 // Unbind the buffer.
388 this.writeOverlapped
.CancelAsyncOperation();
390 this.ResetWriteState();
391 this.WriteTimer
.Cancel();
395 if (!this.isWriteOutstanding
)
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
);
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;
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
452 closeState
= CloseState
.Closing
;
454 shouldCloseHandle
= true;
460 existingReadIsPending
= true;
464 shouldReadEOF
= true;
468 if (!isShutdownWritten
)
470 shouldWriteEOF
= true;
471 isShutdownWritten
= true;
478 StartWriteZero(timeoutHelper
.RemainingTime());
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
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
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
))
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
);
564 if (shouldCloseHandle
)
566 CloseHandle(false, null, TransferOperation
.Undefined
);
571 void CloseHandle(bool abort
, string timeoutErrorString
, TransferOperation transferOperation
)
577 if (this.closeState
== CloseState
.HandleClosed
)
582 this.timeoutErrorString
= timeoutErrorString
;
583 this.timeoutErrorTransferOperation
= transferOperation
;
584 this.aborted
= abort
;
585 this.closeState
= CloseState
.HandleClosed
;
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
);
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
);
660 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelper(
661 CreatePipeDuplicationFailedException(Marshal
.GetLastWin32Error()), ExceptionEventType
);
664 return duplicatedHandle
;
668 targetProcessHandle
.Close();
672 public object GetCoreTransport()
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;
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)
746 BufferManager bufferManager
;
747 lock (this.writeLock
)
749 if (this.pendingWriteBuffer
== null)
754 buffer
= this.pendingWriteBuffer
;
755 this.pendingWriteBuffer
= null;
757 bufferManager
= this.pendingWriteBufferManager
;
758 this.pendingWriteBufferManager
= null;
763 bool success
= false;
766 WaitForSyncWrite(timeout
, true);
771 lock (this.writeLock
)
777 FinishSyncWrite(true);
783 if (!this.isWriteOutstanding
)
785 bufferManager
.ReturnBuffer(buffer
);
792 catch (PipeException e
)
794 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelper(ConvertPipeException(e
, TransferOperation
.Write
), ExceptionEventType
);
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
));
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
));
824 void HandleReadComplete(int bytesRead
)
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
;
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
));
867 if (UnsafeNativeMethods
.GetOverlappedResult(this.pipe
.DangerousGetHandle(), this.readOverlapped
.NativeOverlapped
, out numBytes
, 0) == 0)
869 error
= Marshal
.GetLastWin32Error();
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
897 this.asyncReadException
= e
;
901 this.isReadOutstanding
= false;
904 callback
= this.asyncReadCallback
;
905 this.asyncReadCallback
= null;
906 state
= this.asyncReadCallbackState
;
907 this.asyncReadCallbackState
= null;
914 [PermissionSet(SecurityAction
.Demand
, Unrestricted
= true), SecuritySafeCritical
]
915 unsafe void OnAsyncWriteComplete(bool haveResult
, int error
, int numBytes
)
917 WaitCallback callback
;
920 Exception writeException
= null;
922 this.WriteTimer
.Cancel();
929 if (this.closeState
== CloseState
.HandleClosed
)
931 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(CreatePipeClosedException(TransferOperation
.Write
));
935 if (UnsafeNativeMethods
.GetOverlappedResult(this.pipe
.DangerousGetHandle(), this.writeOverlapped
.NativeOverlapped
, out numBytes
, 0) == 0)
937 error
= Marshal
.GetLastWin32Error();
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
971 this.isWriteOutstanding
= false;
974 this.asyncWriteException
= writeException
;
975 callback
= this.asyncWriteCallback
;
976 state
= this.asyncWriteCallbackState
;
977 this.ResetWriteState();
981 if (callback
!= null)
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
);
996 ValidateEnterReadingState(true);
1002 StartSyncRead(buffer
, offset
, size
);
1003 EnterReadingState();
1007 bool success
= false;
1010 WaitForSyncRead(timeout
, true);
1015 lock (this.readLock
)
1021 bytesRead
= FinishSyncRead(true);
1022 HandleReadComplete(bytesRead
);
1028 if (!this.isReadOutstanding
)
1036 Fx
.Assert(bytesRead
>= 0, "Logic error in Read - bytesRead not set.");
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());
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
);
1116 lock (this.readLock
)
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
);
1137 if (!this.isReadOutstanding
)
1146 void WaitForWriteZero(TimeSpan timeout
, bool traceExceptionsAsErrors
)
1148 bool success
= false;
1151 WaitForSyncWrite(timeout
, traceExceptionsAsErrors
);
1156 lock (this.writeLock
)
1162 FinishSyncWrite(traceExceptionsAsErrors
);
1168 if (!this.isWriteOutstanding
)
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
);
1216 lock (this.writeLock
)
1222 FinishSyncWrite(true);
1228 if (!this.isWriteOutstanding
)
1236 bytesToWrite
-= 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]);
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
);
1281 if (!this.isWriteOutstanding
)
1283 shouldReturnBuffer
= true;
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
);
1305 if (shouldReturnBuffer
)
1307 bufferManager
.ReturnBuffer(buffer
);
1312 void ValidateEnterReadingState(bool checkEOF
)
1316 if (closeState
== CloseState
.Closing
)
1318 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelper(new PipeException(SR
.GetString(SR
.PipeAlreadyClosing
)), ExceptionEventType
);
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
)
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
);
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
));
1390 this.isReadOutstanding
= false;
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
);
1423 this.isReadOutstanding
= false;
1428 // Must be called in a lock.
1429 [PermissionSet(SecurityAction
.Demand
, Unrestricted
= true), SecuritySafeCritical
]
1430 unsafe int FinishSyncRead(bool traceExceptionsAsErrors
)
1433 Exception readException
;
1435 if (this.closeState
== CloseState
.HandleClosed
)
1437 readException
= CreatePipeClosedException(TransferOperation
.Read
);
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
);
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
));
1485 this.isWriteOutstanding
= false;
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
);
1523 this.isWriteOutstanding
= false;
1528 // Must be called in a lock.
1529 [PermissionSet(SecurityAction
.Demand
, Unrestricted
= true), SecuritySafeCritical
]
1530 unsafe void FinishSyncWrite(bool traceExceptionsAsErrors
)
1533 Exception writeException
;
1535 if (this.closeState
== CloseState
.HandleClosed
)
1537 writeException
= CreatePipeClosedException(TransferOperation
.Write
);
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
);
1566 enum TransferOperation
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
);
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
)
1621 return Exceptions
.CreateReadException(error
);
1633 class PipeConnectionInitiator
: IConnectionInitiator
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
,
1671 SR
.TraceCodeFailedPipeConnect
,
1672 timeoutHelper
.RemainingTime(),
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
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
)
1728 matchPipeName
= pipeName
;
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
));
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();
1819 int mode
= UnsafeNativeMethods
.PIPE_READMODE_MESSAGE
;
1820 if (UnsafeNativeMethods
.SetNamedPipeHandleState(pipeHandle
, ref mode
, IntPtr
.Zero
, IntPtr
.Zero
) == 0)
1822 error
= Marshal
.GetLastWin32Error();
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
)
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
);
1849 timeoutException
= new TimeoutException(SR
.GetString(SR
.PipeConnectTimedOut
,
1850 endpoint
, backoffHelper
.OriginalTimeout
), innerException
);
1853 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(timeoutException
);
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
);
1883 class ConnectAsyncResult
: AsyncResult
1885 PipeConnectionInitiator parent
;
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);
1914 if (waitCompleteCallback
== null)
1916 waitCompleteCallback
= new Action
<object>(OnWaitComplete
);
1918 this.backoffHelper
.WaitAndBackoff(waitCompleteCallback
, this);
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
,
1943 SR
.TraceCodeFailedPipeConnect
,
1944 thisPtr
.timeoutHelper
.RemainingTime(),
1945 thisPtr
.remoteUri
));
1948 completeSelf
= thisPtr
.ConnectAndWait();
1961 thisPtr
.Complete(false, exception
);
1967 class PipeConnectionListener
: IConnectionListener
1971 HostNameComparisonMode hostNameComparisonMode
;
1974 List
<PendingAccept
> pendingAccepts
;
1975 bool anyPipesCreated
;
1976 PipeSharedMemory sharedMemory
;
1977 List
<SecurityIdentifier
> allowedSids
;
1978 bool useCompletionPort
;
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
);
1996 get { return this; }
1999 public string PipeName { get { return sharedMemory.PipeName; }
}
2001 public IAsyncResult
BeginAccept(AsyncCallback callback
, object state
)
2007 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new ObjectDisposedException("", SR
.GetString(SR
.PipeListenerDisposed
)));
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)
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
;
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(
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
));
2103 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(new CommunicationException(innerException
.Message
, innerException
));
2108 if (TD
.NamedPipeCreatedIsEnabled())
2110 TD
.NamedPipeCreated(pipeName
);
2114 bool closePipe
= true;
2117 if (useCompletionPort
)
2119 ThreadPool
.BindHandle(pipeHandle
);
2121 anyPipesCreated
= true;
2134 public void Dispose()
2140 if (sharedMemory
!= null)
2142 sharedMemory
.Dispose();
2144 for (int i
= 0; i
< pendingAccepts
.Count
; i
++)
2146 pendingAccepts
[i
].Abort();
2153 public void Listen()
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
));
2176 // try the session namespace since we're RANU
2177 sharedMemoryName
= PipeUri
.BuildSharedMemoryName(pipeUri
, hostNameComparisonMode
, false);
2178 this.sharedMemory
= PipeSharedMemory
.Create(allowedSids
, pipeUri
, sharedMemoryName
);
2187 void RemovePendingAccept(PendingAccept pendingAccept
)
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
;
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);
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
);
2269 if (UnsafeNativeMethods
.ConnectNamedPipe(pipeHandle
, overlapped
.NativeOverlapped
) == 0)
2271 int error
= Marshal
.GetLastWin32Error();
2274 case UnsafeNativeMethods
.ERROR_NO_DATA
:
2275 if (UnsafeNativeMethods
.DisconnectNamedPipe(pipeHandle
) != 0)
2281 completeSelf
= true;
2282 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(CreatePipeAcceptFailedException(error
));
2284 case UnsafeNativeMethods
.ERROR_PIPE_CONNECTED
:
2285 completeSelf
= true;
2287 case UnsafeNativeMethods
.ERROR_IO_PENDING
:
2290 completeSelf
= true;
2291 throw DiagnosticUtility
.ExceptionUtility
.ThrowHelperError(CreatePipeAcceptFailedException(error
));
2296 completeSelf
= true;
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;
2313 this.overlapped
.CancelAsyncOperation();
2314 this.overlapped
.Free();
2318 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
2326 completeSelf
= true;
2327 completionException
= e
;
2333 this.listener
.RemovePendingAccept(this);
2335 base.Complete(synchronous
, completionException
);
2339 // Must be called in PipeConnectionListener's lock.
2342 this.result
= null; // we need to return null after an abort
2346 public PipeHandle
End()
2348 AsyncResult
.End
<PendingAccept
>(this);
2352 [PermissionSet(SecurityAction
.Demand
, Unrestricted
= true), SecuritySafeCritical
]
2353 unsafe void OnAcceptComplete(bool haveResult
, int error
, int numBytes
)
2355 this.listener
.RemovePendingAccept(this);
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();
2371 this.overlapped
.Free();
2373 if (TD
.PipeConnectionAcceptStopIsEnabled())
2375 TD
.PipeConnectionAcceptStop(this.eventTraceActivity
);
2380 this.pipeHandle
.Close();
2381 base.Complete(false, CreatePipeAcceptFailedException(error
));
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
);
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.
2455 AccessControlType
.Allow
,
2456 AppContainerInfo
.GetCurrentAppContainerSid(),
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
;
2504 string pipeNameGuidPart
;
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
))
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
;
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
)
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
);
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
)
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();
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
);
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}",
2687 appInfo
.NamedObjectPath
,
2688 this.pipeNameGuidPart
);
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;
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
));
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
);
2758 switch (hostNameComparisonMode
)
2760 case HostNameComparisonMode
.StrongWildcard
:
2763 case HostNameComparisonMode
.Exact
:
2766 case HostNameComparisonMode
.WeakWildcard
:
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);
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
);
2810 if (canonicalBytes
.Length
>= 128)
2812 using (HashAlgorithm hash
= GetHashAlgorithm())
2814 hashedBytes
= hash
.ComputeHash(canonicalBytes
);
2820 hashedBytes
= canonicalBytes
;
2824 builder
= new StringBuilder();
2827 // we may need to create the shared memory in the global namespace so we work with terminal services+admin
2828 builder
.Append("Global\\");
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();
2848 return new SHA256Managed();
2852 if (SecurityUtilsEx
.RequiresFipsCompliance
)
2853 return new SHA1CryptoServiceProvider();
2855 return new SHA1Managed();
2859 public static string GetPath(Uri uri
)
2861 string path
= uri
.LocalPath
.ToUpperInvariant();
2862 if (!path
.EndsWith("/", StringComparison
.Ordinal
))
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)
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));
2902 return SR
.GetString(
2903 SR
.PipeUnknownWin32Error
,
2904 error
.ToString(CultureInfo
.InvariantCulture
),
2905 Convert
.ToString(error
, 16));