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.Globalization;
13 using System.Runtime.Diagnostics;
14 using System.Runtime.InteropServices;
15 using System.Runtime.Versioning;
16 using System.Security.AccessControl;
17 using System.ComponentModel;
18 using System.Security;
19 using System.Security.Cryptography;
20 using System.Security.Permissions;
21 using System.Security.Principal;
22 using System.ServiceModel;
23 using System.ServiceModel.Activation;
24 using System.ServiceModel.Diagnostics;
25 using System.ServiceModel.Diagnostics.Application;
26 using System.ServiceModel.Security;
28 using System.Threading;
29 using SafeCloseHandle = System.ServiceModel.Activation.SafeCloseHandle;
31 sealed class PipeConnection : IConnection
35 CloseState closeState;
37 bool isBoundToCompletionPort;
38 bool autoBindToCompletionPort;
39 TraceEventType exceptionEventType;
40 static byte[] zeroBuffer;
43 object readLock = new object();
44 bool inReadingState; // This keeps track of the state machine (IConnection interface).
45 bool isReadOutstanding; // This tracks whether an actual I/O is pending.
46 OverlappedContext readOverlapped;
47 byte[] asyncReadBuffer;
49 ManualResetEvent atEOFEvent;
51 OverlappedIOCompleteCallback onAsyncReadComplete;
52 Exception asyncReadException;
53 WaitCallback asyncReadCallback;
54 object asyncReadCallbackState;
58 object writeLock = new object();
59 bool inWritingState; // This keeps track of the state machine (IConnection interface).
60 bool isWriteOutstanding; // This tracks whether an actual I/O is pending.
61 OverlappedContext writeOverlapped;
62 Exception asyncWriteException;
63 WaitCallback asyncWriteCallback;
64 object asyncWriteCallbackState;
65 int asyncBytesToWrite;
66 bool isShutdownWritten;
68 byte[] pendingWriteBuffer;
69 BufferManager pendingWriteBufferManager;
70 OverlappedIOCompleteCallback onAsyncWriteComplete;
75 IOThreadTimer readTimer;
76 static Action<object> onReadTimeout;
77 string timeoutErrorString;
78 TransferOperation timeoutErrorTransferOperation;
79 TimeSpan writeTimeout;
80 IOThreadTimer writeTimer;
81 static Action<object> onWriteTimeout;
83 public PipeConnection(PipeHandle pipe, int connectionBufferSize, bool isBoundToCompletionPort, bool autoBindToCompletionPort)
86 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
88 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
90 this.closeState = CloseState.Open;
91 this.exceptionEventType = TraceEventType.Error;
92 this.isBoundToCompletionPort = isBoundToCompletionPort;
93 this.autoBindToCompletionPort = autoBindToCompletionPort;
95 this.readBufferSize = connectionBufferSize;
96 this.writeBufferSize = connectionBufferSize;
97 this.readOverlapped = new OverlappedContext();
98 this.asyncReadBuffer = DiagnosticUtility.Utility.AllocateByteArray(connectionBufferSize);
99 this.writeOverlapped = new OverlappedContext();
100 this.atEOFEvent = new ManualResetEvent(false);
101 this.onAsyncReadComplete = new OverlappedIOCompleteCallback(OnAsyncReadComplete);
102 this.onAsyncWriteComplete = new OverlappedIOCompleteCallback(OnAsyncWriteComplete);
105 public int AsyncReadBufferSize
109 return this.readBufferSize;
113 public byte[] AsyncReadBuffer
117 return this.asyncReadBuffer;
121 static byte[] ZeroBuffer
125 if (PipeConnection.zeroBuffer == null)
127 PipeConnection.zeroBuffer = new byte[1];
129 return PipeConnection.zeroBuffer;
133 public TraceEventType ExceptionEventType
135 get { return this.exceptionEventType; }
136 set { this.exceptionEventType = value; }
139 public IPEndPoint RemoteIPEndPoint
144 IOThreadTimer ReadTimer
148 if (this.readTimer == null)
150 if (onReadTimeout == null)
152 onReadTimeout = new Action<object>(OnReadTimeout);
155 this.readTimer = new IOThreadTimer(onReadTimeout, this, false);
158 return this.readTimer;
161 IOThreadTimer WriteTimer
165 if (this.writeTimer == null)
167 if (onWriteTimeout == null)
169 onWriteTimeout = new Action<object>(OnWriteTimeout);
172 this.writeTimer = new IOThreadTimer(onWriteTimeout, this, false);
175 return this.writeTimer;
179 static void OnReadTimeout(object state)
181 PipeConnection thisPtr = (PipeConnection)state;
182 thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, thisPtr.readTimeout), TransferOperation.Read);
185 static void OnWriteTimeout(object state)
187 PipeConnection thisPtr = (PipeConnection)state;
188 thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, thisPtr.writeTimeout), TransferOperation.Write);
193 Abort(null, TransferOperation.Undefined);
196 void Abort(string timeoutErrorString, TransferOperation transferOperation)
198 CloseHandle(true, timeoutErrorString, transferOperation);
201 Exception ConvertPipeException(PipeException pipeException, TransferOperation transferOperation)
203 return ConvertPipeException(pipeException.Message, pipeException, transferOperation);
206 Exception ConvertPipeException(string exceptionMessage, PipeException pipeException, TransferOperation transferOperation)
208 if (this.timeoutErrorString != null)
210 if (transferOperation == this.timeoutErrorTransferOperation)
212 return new TimeoutException(this.timeoutErrorString, pipeException);
216 return new CommunicationException(this.timeoutErrorString, pipeException);
219 else if (this.aborted)
221 return new CommunicationObjectAbortedException(exceptionMessage, pipeException);
225 return new CommunicationException(exceptionMessage, pipeException);
229 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
230 public unsafe AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout,
231 WaitCallback callback, object state)
233 ConnectionUtilities.ValidateBufferBounds(AsyncReadBuffer, offset, size);
239 ValidateEnterReadingState(true);
244 asyncReadException = null;
245 return AsyncCompletionResult.Completed;
248 if (autoBindToCompletionPort)
250 if (!isBoundToCompletionPort)
254 // readLock, writeLock acquired in order to prevent deadlock
255 EnsureBoundToCompletionPort();
260 if (this.isReadOutstanding)
262 throw Fx.AssertAndThrow("Read I/O already pending when BeginRead called.");
266 this.readTimeout = timeout;
268 if (this.readTimeout != TimeSpan.MaxValue)
270 this.ReadTimer.Set(this.readTimeout);
273 this.asyncReadCallback = callback;
274 this.asyncReadCallbackState = state;
276 this.isReadOutstanding = true;
277 this.readOverlapped.StartAsyncOperation(AsyncReadBuffer, this.onAsyncReadComplete, this.isBoundToCompletionPort);
278 if (UnsafeNativeMethods.ReadFile(this.pipe.DangerousGetHandle(), this.readOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.readOverlapped.NativeOverlapped) == 0)
280 int error = Marshal.GetLastWin32Error();
281 if (error != UnsafeNativeMethods.ERROR_IO_PENDING && error != UnsafeNativeMethods.ERROR_MORE_DATA)
283 this.isReadOutstanding = false;
284 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
290 if (!this.isReadOutstanding)
292 // Unbind the buffer.
293 this.readOverlapped.CancelAsyncOperation();
295 this.asyncReadCallback = null;
296 this.asyncReadCallbackState = null;
297 this.ReadTimer.Cancel();
301 if (!this.isReadOutstanding)
304 Exception readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
305 if (readException != null)
307 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(readException);
309 asyncBytesRead = bytesRead;
310 HandleReadComplete(asyncBytesRead);
317 return this.isReadOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
319 catch (PipeException e)
321 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
326 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
327 public unsafe AsyncCompletionResult BeginWrite(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout,
328 WaitCallback callback, object state)
330 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
331 FinishPendingWrite(timeout);
333 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
335 if (autoBindToCompletionPort && !isBoundToCompletionPort)
337 // Locks must be both taken, and in this order.
342 ValidateEnterWritingState(true);
344 EnsureBoundToCompletionPort();
353 ValidateEnterWritingState(true);
355 if (this.isWriteOutstanding)
357 throw Fx.AssertAndThrow("Write I/O already pending when BeginWrite called.");
362 this.writeTimeout = timeout;
363 this.WriteTimer.Set(timeoutHelper.RemainingTime());
365 this.asyncBytesToWrite = size;
366 this.asyncWriteException = null;
367 this.asyncWriteCallback = callback;
368 this.asyncWriteCallbackState = state;
370 this.isWriteOutstanding = true;
371 this.writeOverlapped.StartAsyncOperation(buffer, this.onAsyncWriteComplete, this.isBoundToCompletionPort);
372 if (UnsafeNativeMethods.WriteFile(this.pipe.DangerousGetHandle(), this.writeOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.writeOverlapped.NativeOverlapped) == 0)
374 int error = Marshal.GetLastWin32Error();
375 if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
377 this.isWriteOutstanding = false;
378 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
384 if (!this.isWriteOutstanding)
386 // Unbind the buffer.
387 this.writeOverlapped.CancelAsyncOperation();
389 this.ResetWriteState();
390 this.WriteTimer.Cancel();
394 if (!this.isWriteOutstanding)
397 Exception writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
398 if (writeException == null && bytesWritten != size)
400 writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
402 if (writeException != null)
404 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(writeException);
412 return this.isWriteOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
414 catch (PipeException e)
416 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
421 // CSDMain 112188: Note asyncAndLinger has no effect here. Async pooling for Tcp was
422 // added and NamedPipes currently doesn't obey the async model.
423 public void Close(TimeSpan timeout, bool asyncAndLinger)
425 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
426 FinishPendingWrite(timeout);
428 bool shouldCloseHandle = false;
431 bool existingReadIsPending = false;
432 bool shouldReadEOF = false;
433 bool shouldWriteEOF = false;
439 if (!isShutdownWritten && inWritingState)
441 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
442 new PipeException(SR.GetString(SR.PipeCantCloseWithPendingWrite)), ExceptionEventType);
445 if (closeState == CloseState.Closing || closeState == CloseState.HandleClosed)
447 // already closing or closed, so just return
451 closeState = CloseState.Closing;
453 shouldCloseHandle = true;
459 existingReadIsPending = true;
463 shouldReadEOF = true;
467 if (!isShutdownWritten)
469 shouldWriteEOF = true;
470 isShutdownWritten = true;
477 StartWriteZero(timeoutHelper.RemainingTime());
485 // wait for shutdown write to complete
488 WaitForWriteZero(timeoutHelper.RemainingTime(), true);
490 catch (TimeoutException e)
492 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
493 new TimeoutException(SR.GetString(SR.PipeShutdownWriteError), e), ExceptionEventType);
496 // ensure we have received EOF signal
501 WaitForReadZero(timeoutHelper.RemainingTime(), true);
503 catch (TimeoutException e)
505 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
506 new TimeoutException(SR.GetString(SR.PipeShutdownReadError), e), ExceptionEventType);
509 else if (existingReadIsPending)
511 if (!TimeoutHelper.WaitOne(atEOFEvent, timeoutHelper.RemainingTime()))
513 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
514 new TimeoutException(SR.GetString(SR.PipeShutdownReadError)), ExceptionEventType);
517 // else we had already seen EOF.
519 // at this point, we may get exceptions if the other side closes the handle first
522 // write an ack for eof
523 StartWriteZero(timeoutHelper.RemainingTime());
525 // read an ack for eof
528 // wait for write to complete/fail
529 WaitForWriteZero(timeoutHelper.RemainingTime(), false);
531 // wait for read to complete/fail
532 WaitForReadZero(timeoutHelper.RemainingTime(), false);
534 catch (PipeException e)
536 if (!IsBrokenPipeError(e.ErrorCode))
540 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
542 catch (CommunicationException e)
544 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
546 catch (TimeoutException e)
548 DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
551 catch (TimeoutException e)
553 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
554 new TimeoutException(SR.GetString(SR.PipeCloseFailed), e), ExceptionEventType);
556 catch (PipeException e)
558 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
559 ConvertPipeException(SR.GetString(SR.PipeCloseFailed), e, TransferOperation.Undefined), ExceptionEventType);
563 if (shouldCloseHandle)
565 CloseHandle(false, null, TransferOperation.Undefined);
570 void CloseHandle(bool abort, string timeoutErrorString, TransferOperation transferOperation)
576 if (this.closeState == CloseState.HandleClosed)
581 this.timeoutErrorString = timeoutErrorString;
582 this.timeoutErrorTransferOperation = transferOperation;
583 this.aborted = abort;
584 this.closeState = CloseState.HandleClosed;
586 this.readOverlapped.FreeOrDefer();
587 this.writeOverlapped.FreeOrDefer();
589 if (this.atEOFEvent != null)
591 this.atEOFEvent.Close();
594 // This should only do anything in the abort case.
597 FinishPendingWrite(TimeSpan.Zero);
599 catch (TimeoutException exception)
601 if (TD.CloseTimeoutIsEnabled())
603 TD.CloseTimeout(exception.Message);
605 DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
607 catch (CommunicationException exception)
609 DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
616 TraceEventType traceEventType = TraceEventType.Warning;
618 // we could be timing out a cached connection
619 if (this.ExceptionEventType == TraceEventType.Information)
621 traceEventType = this.ExceptionEventType;
624 if (DiagnosticUtility.ShouldTrace(traceEventType))
626 TraceUtility.TraceEvent(traceEventType, TraceCode.PipeConnectionAbort, SR.GetString(SR.TraceCodePipeConnectionAbort), this);
631 CommunicationException CreatePipeDuplicationFailedException(int win32Error)
633 Exception innerException = new PipeException(SR.GetString(SR.PipeDuplicationFailed), win32Error);
634 return new CommunicationException(innerException.Message, innerException);
637 public object DuplicateAndClose(int targetProcessId)
639 SafeCloseHandle targetProcessHandle = ListenerUnsafeNativeMethods.OpenProcess(ListenerUnsafeNativeMethods.PROCESS_DUP_HANDLE, false, targetProcessId);
640 if (targetProcessHandle.IsInvalid)
642 targetProcessHandle.SetHandleAsInvalid();
643 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
644 CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
648 // no need to close this handle, it's a pseudo handle. expected value is -1.
649 IntPtr sourceProcessHandle = ListenerUnsafeNativeMethods.GetCurrentProcess();
650 if (sourceProcessHandle == IntPtr.Zero)
652 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
653 CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
655 IntPtr duplicatedHandle;
656 bool success = UnsafeNativeMethods.DuplicateHandle(sourceProcessHandle, this.pipe, targetProcessHandle, out duplicatedHandle, 0, false, UnsafeNativeMethods.DUPLICATE_SAME_ACCESS);
659 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
660 CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
663 return duplicatedHandle;
667 targetProcessHandle.Close();
671 public object GetCoreTransport()
676 void EnsureBoundToCompletionPort()
678 // Both read and write locks must be acquired before doing this
679 if (!isBoundToCompletionPort)
681 ThreadPool.BindHandle(this.pipe);
682 isBoundToCompletionPort = true;
688 if (asyncReadException != null)
690 Exception exceptionToThrow = asyncReadException;
691 asyncReadException = null;
692 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
694 return asyncBytesRead;
697 public void EndWrite()
699 if (this.asyncWriteException != null)
701 Exception exceptionToThrow = this.asyncWriteException;
702 this.asyncWriteException = null;
703 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
707 void EnterReadingState()
709 inReadingState = true;
712 void EnterWritingState()
714 inWritingState = true;
717 void ExitReadingState()
719 inReadingState = false;
722 void ExitWritingState()
724 inWritingState = false;
727 void ReadIOCompleted()
729 this.readOverlapped.FreeIfDeferred();
732 void WriteIOCompleted()
734 this.writeOverlapped.FreeIfDeferred();
737 void FinishPendingWrite(TimeSpan timeout)
739 if (this.pendingWriteBuffer == null)
745 BufferManager bufferManager;
746 lock (this.writeLock)
748 if (this.pendingWriteBuffer == null)
753 buffer = this.pendingWriteBuffer;
754 this.pendingWriteBuffer = null;
756 bufferManager = this.pendingWriteBufferManager;
757 this.pendingWriteBufferManager = null;
762 bool success = false;
765 WaitForSyncWrite(timeout, true);
770 lock (this.writeLock)
776 FinishSyncWrite(true);
782 if (!this.isWriteOutstanding)
784 bufferManager.ReturnBuffer(buffer);
791 catch (PipeException e)
793 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
801 #pragma warning suppress 56523 // [....], Win32Exception ctor calls Marshal.GetLastWin32Error()
802 if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
804 Win32Exception e = new Win32Exception();
805 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
813 #pragma warning suppress 56523 // [....], Win32Exception ctor calls Marshal.GetLastWin32Error()
814 if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
816 Win32Exception e = new Win32Exception();
817 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
823 void HandleReadComplete(int bytesRead)
832 bool IsBrokenPipeError(int error)
834 return error == UnsafeNativeMethods.ERROR_NO_DATA ||
835 error == UnsafeNativeMethods.ERROR_BROKEN_PIPE;
838 Exception CreatePipeClosedException(TransferOperation transferOperation)
840 return ConvertPipeException(new PipeException(SR.GetString(SR.PipeClosed)), transferOperation);
843 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
844 unsafe void OnAsyncReadComplete(bool haveResult, int error, int numBytes)
846 WaitCallback callback;
855 if (this.readTimeout != TimeSpan.MaxValue && !this.ReadTimer.Cancel())
857 this.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
860 if (this.closeState == CloseState.HandleClosed)
862 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Read));
866 if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.readOverlapped.NativeOverlapped, out numBytes, 0) == 0)
868 error = Marshal.GetLastWin32Error();
876 if (error != 0 && error != UnsafeNativeMethods.ERROR_MORE_DATA)
878 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException((int)error));
880 this.asyncBytesRead = numBytes;
881 HandleReadComplete(this.asyncBytesRead);
883 catch (PipeException e)
885 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ConvertPipeException(e, TransferOperation.Read));
888 #pragma warning suppress 56500 // [....], transferring exception to caller
896 this.asyncReadException = e;
900 this.isReadOutstanding = false;
903 callback = this.asyncReadCallback;
904 this.asyncReadCallback = null;
905 state = this.asyncReadCallbackState;
906 this.asyncReadCallbackState = null;
913 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
914 unsafe void OnAsyncWriteComplete(bool haveResult, int error, int numBytes)
916 WaitCallback callback;
919 Exception writeException = null;
921 this.WriteTimer.Cancel();
928 if (this.closeState == CloseState.HandleClosed)
930 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Write));
934 if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.writeOverlapped.NativeOverlapped, out numBytes, 0) == 0)
936 error = Marshal.GetLastWin32Error();
946 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
948 else if (numBytes != this.asyncBytesToWrite)
950 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new PipeException(SR.GetString(SR.PipeWriteIncomplete)));
953 catch (PipeException e)
955 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
958 #pragma warning suppress 56500 // [....], transferring exception to another thread
970 this.isWriteOutstanding = false;
973 this.asyncWriteException = writeException;
974 callback = this.asyncWriteCallback;
975 state = this.asyncWriteCallbackState;
976 this.ResetWriteState();
980 if (callback != null)
986 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
987 unsafe public int Read(byte[] buffer, int offset, int size, TimeSpan timeout)
989 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
995 ValidateEnterReadingState(true);
1001 StartSyncRead(buffer, offset, size);
1002 EnterReadingState();
1006 bool success = false;
1009 WaitForSyncRead(timeout, true);
1014 lock (this.readLock)
1020 bytesRead = FinishSyncRead(true);
1021 HandleReadComplete(bytesRead);
1027 if (!this.isReadOutstanding)
1035 Fx.Assert(bytesRead >= 0, "Logic error in Read - bytesRead not set.");
1038 catch (PipeException e)
1040 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
1044 public void Shutdown(TimeSpan timeout)
1048 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1049 FinishPendingWrite(timeoutHelper.RemainingTime());
1053 ValidateEnterWritingState(true);
1054 StartWriteZero(timeoutHelper.RemainingTime());
1055 isShutdownWritten = true;
1058 catch (PipeException e)
1060 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Undefined), ExceptionEventType);
1064 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1065 unsafe void StartReadZero()
1067 lock (this.readLock)
1069 ValidateEnterReadingState(false);
1070 StartSyncRead(ZeroBuffer, 0, 1);
1071 EnterReadingState();
1075 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1076 unsafe void StartWriteZero(TimeSpan timeout)
1078 FinishPendingWrite(timeout);
1080 lock (this.writeLock)
1082 ValidateEnterWritingState(false);
1083 StartSyncWrite(ZeroBuffer, 0, 0);
1084 EnterWritingState();
1088 void ResetWriteState()
1090 this.asyncBytesToWrite = -1;
1091 this.asyncWriteCallback = null;
1092 this.asyncWriteCallbackState = null;
1095 public IAsyncResult BeginValidate(Uri uri, AsyncCallback callback, object state)
1097 return new CompletedAsyncResult<bool>(true, callback, state);
1100 public bool EndValidate(IAsyncResult result)
1102 return CompletedAsyncResult<bool>.End(result);
1105 void WaitForReadZero(TimeSpan timeout, bool traceExceptionsAsErrors)
1107 bool success = false;
1110 WaitForSyncRead(timeout, traceExceptionsAsErrors);
1115 lock (this.readLock)
1121 if (FinishSyncRead(traceExceptionsAsErrors) != 0)
1123 Exception exception = ConvertPipeException(new PipeException(SR.GetString(SR.PipeSignalExpected)), TransferOperation.Read);
1124 TraceEventType traceEventType = TraceEventType.Information;
1125 if (traceExceptionsAsErrors)
1127 traceEventType = TraceEventType.Error;
1129 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exception, traceEventType);
1136 if (!this.isReadOutstanding)
1145 void WaitForWriteZero(TimeSpan timeout, bool traceExceptionsAsErrors)
1147 bool success = false;
1150 WaitForSyncWrite(timeout, traceExceptionsAsErrors);
1155 lock (this.writeLock)
1161 FinishSyncWrite(traceExceptionsAsErrors);
1167 if (!this.isWriteOutstanding)
1176 public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
1178 WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
1181 // The holder is a perf optimization that lets us avoid repeatedly indexing into the array.
1182 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1183 unsafe void WriteHelper(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, ref object holder)
1187 FinishPendingWrite(timeout);
1189 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
1191 int bytesToWrite = size;
1192 if (size > this.writeBufferSize)
1194 size = this.writeBufferSize;
1197 while (bytesToWrite > 0)
1199 lock (this.writeLock)
1201 ValidateEnterWritingState(true);
1203 StartSyncWrite(buffer, offset, size, ref holder);
1204 EnterWritingState();
1207 bool success = false;
1210 WaitForSyncWrite(timeout, true, ref holder);
1215 lock (this.writeLock)
1221 FinishSyncWrite(true);
1227 if (!this.isWriteOutstanding)
1235 bytesToWrite -= size;
1237 if (size > bytesToWrite)
1239 size = bytesToWrite;
1243 catch (PipeException e)
1245 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
1249 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1250 public unsafe void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager)
1252 bool shouldReturnBuffer = true;
1256 if (size > this.writeBufferSize)
1258 WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
1262 FinishPendingWrite(timeout);
1264 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
1266 lock (this.writeLock)
1268 ValidateEnterWritingState(true);
1270 // This method avoids the call to GetOverlappedResult for synchronous completions. Perf?
1271 bool success = false;
1274 shouldReturnBuffer = false;
1275 StartSyncWrite(buffer, offset, size);
1280 if (!this.isWriteOutstanding)
1282 shouldReturnBuffer = true;
1288 EnterWritingState();
1290 Fx.Assert(this.pendingWriteBuffer == null, "Need to pend a write but one's already pending.");
1291 this.pendingWriteBuffer = buffer;
1292 this.pendingWriteBufferManager = bufferManager;
1298 catch (PipeException e)
1300 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
1304 if (shouldReturnBuffer)
1306 bufferManager.ReturnBuffer(buffer);
1311 void ValidateEnterReadingState(bool checkEOF)
1315 if (closeState == CloseState.Closing)
1317 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
1323 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeReadPending)), ExceptionEventType);
1326 if (closeState == CloseState.HandleClosed)
1328 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
1332 void ValidateEnterWritingState(bool checkShutdown)
1336 if (isShutdownWritten)
1338 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyShuttingDown)), ExceptionEventType);
1341 if (closeState == CloseState.Closing)
1343 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
1349 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeWritePending)), ExceptionEventType);
1352 if (closeState == CloseState.HandleClosed)
1354 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
1358 void StartSyncRead(byte[] buffer, int offset, int size)
1360 StartSyncRead(buffer, offset, size, ref this.readOverlapped.Holder[0]);
1363 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1364 unsafe void StartSyncRead(byte[] buffer, int offset, int size, ref object holder)
1366 if (this.isReadOutstanding)
1368 throw Fx.AssertAndThrow("StartSyncRead called when read I/O was already pending.");
1373 this.isReadOutstanding = true;
1374 this.readOverlapped.StartSyncOperation(buffer, ref holder);
1375 if (UnsafeNativeMethods.ReadFile(this.pipe.DangerousGetHandle(), this.readOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.readOverlapped.NativeOverlapped) == 0)
1377 int error = Marshal.GetLastWin32Error();
1378 if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
1380 this.isReadOutstanding = false;
1381 if (error != UnsafeNativeMethods.ERROR_MORE_DATA)
1383 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
1389 this.isReadOutstanding = false;
1394 if (!this.isReadOutstanding)
1396 this.readOverlapped.CancelSyncOperation(ref holder);
1401 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1402 unsafe void WaitForSyncRead(TimeSpan timeout, bool traceExceptionsAsErrors)
1404 if (this.isReadOutstanding)
1406 if (!this.readOverlapped.WaitForSyncOperation(timeout))
1408 Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
1410 Exception timeoutException = new TimeoutException(SR.GetString(SR.PipeReadTimedOut, timeout));
1411 TraceEventType traceEventType = TraceEventType.Information;
1412 if (traceExceptionsAsErrors)
1414 traceEventType = TraceEventType.Error;
1417 // This intentionally doesn't reset isReadOutstanding, because technically it still is, and we need to not free the buffer.
1418 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(timeoutException, traceEventType);
1422 this.isReadOutstanding = false;
1427 // Must be called in a lock.
1428 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1429 unsafe int FinishSyncRead(bool traceExceptionsAsErrors)
1432 Exception readException;
1434 if (this.closeState == CloseState.HandleClosed)
1436 readException = CreatePipeClosedException(TransferOperation.Read);
1440 readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
1442 if (readException != null)
1444 TraceEventType traceEventType = TraceEventType.Information;
1445 if (traceExceptionsAsErrors)
1447 traceEventType = TraceEventType.Error;
1449 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(readException, traceEventType);
1455 void StartSyncWrite(byte[] buffer, int offset, int size)
1457 StartSyncWrite(buffer, offset, size, ref this.writeOverlapped.Holder[0]);
1460 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1461 unsafe void StartSyncWrite(byte[] buffer, int offset, int size, ref object holder)
1463 if (this.isWriteOutstanding)
1465 throw Fx.AssertAndThrow("StartSyncWrite called when write I/O was already pending.");
1470 this.syncWriteSize = size;
1471 this.isWriteOutstanding = true;
1472 this.writeOverlapped.StartSyncOperation(buffer, ref holder);
1473 if (UnsafeNativeMethods.WriteFile(this.pipe.DangerousGetHandle(), this.writeOverlapped.BufferPtr + offset, size, IntPtr.Zero, this.writeOverlapped.NativeOverlapped) == 0)
1475 int error = Marshal.GetLastWin32Error();
1476 if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
1478 this.isWriteOutstanding = false;
1479 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
1484 this.isWriteOutstanding = false;
1489 if (!this.isWriteOutstanding)
1491 this.writeOverlapped.CancelSyncOperation(ref holder);
1496 void WaitForSyncWrite(TimeSpan timeout, bool traceExceptionsAsErrors)
1498 WaitForSyncWrite(timeout, traceExceptionsAsErrors, ref this.writeOverlapped.Holder[0]);
1501 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1502 unsafe void WaitForSyncWrite(TimeSpan timeout, bool traceExceptionsAsErrors, ref object holder)
1504 if (this.isWriteOutstanding)
1506 if (!this.writeOverlapped.WaitForSyncOperation(timeout, ref holder))
1508 Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, this.writeTimeout), TransferOperation.Write);
1510 Exception timeoutException = new TimeoutException(SR.GetString(SR.PipeWriteTimedOut, timeout));
1511 TraceEventType traceEventType = TraceEventType.Information;
1512 if (traceExceptionsAsErrors)
1514 traceEventType = TraceEventType.Error;
1517 // This intentionally doesn't reset isWriteOutstanding, because technically it still is, and we need to not free the buffer.
1518 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(timeoutException, traceEventType);
1522 this.isWriteOutstanding = false;
1527 // Must be called in a lock.
1528 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1529 unsafe void FinishSyncWrite(bool traceExceptionsAsErrors)
1532 Exception writeException;
1534 if (this.closeState == CloseState.HandleClosed)
1536 writeException = CreatePipeClosedException(TransferOperation.Write);
1540 writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
1541 if (writeException == null && bytesWritten != this.syncWriteSize)
1543 writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
1547 if (writeException != null)
1549 TraceEventType traceEventType = TraceEventType.Information;
1550 if (traceExceptionsAsErrors)
1552 traceEventType = TraceEventType.Error;
1554 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(writeException, traceEventType);
1565 enum TransferOperation
1572 static class Exceptions
1574 static PipeException CreateException(string resourceString, int error)
1576 return new PipeException(SR.GetString(resourceString, PipeError.GetErrorString(error)), error);
1579 public static PipeException CreateReadException(int error)
1581 return CreateException(SR.PipeReadError, error);
1584 public static PipeException CreateWriteException(int error)
1586 return CreateException(SR.PipeWriteError, error);
1589 // Must be called in a lock, after checking for HandleClosed.
1590 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1591 public static unsafe PipeException GetOverlappedWriteException(PipeHandle pipe,
1592 NativeOverlapped* nativeOverlapped, out int bytesWritten)
1594 if (UnsafeNativeMethods.GetOverlappedResult(pipe.DangerousGetHandle(), nativeOverlapped, out bytesWritten, 0) == 0)
1596 int error = Marshal.GetLastWin32Error();
1597 return Exceptions.CreateWriteException(error);
1605 // Must be called in a lock, after checking for HandleClosed.
1606 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1607 public static unsafe PipeException GetOverlappedReadException(PipeHandle pipe,
1608 NativeOverlapped* nativeOverlapped, out int bytesRead)
1610 if (UnsafeNativeMethods.GetOverlappedResult(pipe.DangerousGetHandle(), nativeOverlapped, out bytesRead, 0) == 0)
1612 int error = Marshal.GetLastWin32Error();
1613 if (error == UnsafeNativeMethods.ERROR_MORE_DATA)
1620 return Exceptions.CreateReadException(error);
1632 class PipeConnectionInitiator : IConnectionInitiator
1635 IPipeTransportFactorySettings pipeSettings;
1637 public PipeConnectionInitiator(int bufferSize, IPipeTransportFactorySettings pipeSettings)
1639 this.bufferSize = bufferSize;
1640 this.pipeSettings = pipeSettings;
1643 Exception CreateConnectFailedException(Uri remoteUri, PipeException innerException)
1645 return new CommunicationException(
1646 SR.GetString(SR.PipeConnectFailed, remoteUri.AbsoluteUri), innerException);
1649 public IConnection Connect(Uri remoteUri, TimeSpan timeout)
1651 string resolvedAddress;
1652 BackoffTimeoutHelper backoffHelper;
1653 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1654 this.PrepareConnect(remoteUri, timeoutHelper.RemainingTime(), out resolvedAddress, out backoffHelper);
1656 IConnection connection = null;
1657 while (connection == null)
1659 connection = this.TryConnect(remoteUri, resolvedAddress, backoffHelper);
1660 if (connection == null)
1662 backoffHelper.WaitAndBackoff();
1664 if (DiagnosticUtility.ShouldTraceInformation)
1666 TraceUtility.TraceEvent(
1667 TraceEventType.Information,
1668 TraceCode.FailedPipeConnect,
1670 SR.TraceCodeFailedPipeConnect,
1671 timeoutHelper.RemainingTime(),
1679 internal static string GetPipeName(Uri uri, IPipeTransportFactorySettings transportFactorySettings)
1681 AppContainerInfo appInfo = GetAppContainerInfo(transportFactorySettings);
1683 // for wildcard hostName support, we first try and connect to the StrongWildcard,
1684 // then the Exact HostName, and lastly the WeakWildcard
1685 string[] hostChoices = new string[] { "+", uri.Host, "*" };
1686 bool[] globalChoices = new bool[] { true, false };
1687 for (int i = 0; i < hostChoices.Length; i++)
1689 for (int iGlobal = 0; iGlobal < globalChoices.Length; iGlobal++)
1692 if (appInfo != null && globalChoices[iGlobal])
1694 // Don't look at shared memory to acces pipes
1695 // that are created in the local NamedObjectPath
1699 // walk up the path hierarchy, looking for first match
1700 string path = PipeUri.GetPath(uri);
1702 while (path.Length > 0)
1705 string sharedMemoryName = PipeUri.BuildSharedMemoryName(hostChoices[i], path, globalChoices[iGlobal], appInfo);
1708 PipeSharedMemory sharedMemory = PipeSharedMemory.Open(sharedMemoryName, uri);
1709 if (sharedMemory != null)
1713 string pipeName = sharedMemory.GetPipeName(appInfo);
1714 if (pipeName != null)
1721 sharedMemory.Dispose();
1725 catch (AddressAccessDeniedException exception)
1727 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(
1728 SR.EndpointNotFound, uri.AbsoluteUri), exception));
1731 path = PipeUri.GetParentPath(path);
1736 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1737 new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, uri.AbsoluteUri),
1738 new PipeException(SR.GetString(SR.PipeEndpointNotFound, uri.AbsoluteUri))));
1741 public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
1743 return new ConnectAsyncResult(this, uri, timeout, callback, state);
1746 public IConnection EndConnect(IAsyncResult result)
1748 return ConnectAsyncResult.End(result);
1751 void PrepareConnect(Uri remoteUri, TimeSpan timeout, out string resolvedAddress, out BackoffTimeoutHelper backoffHelper)
1753 PipeUri.Validate(remoteUri);
1754 if (DiagnosticUtility.ShouldTraceInformation)
1756 TraceUtility.TraceEvent(System.Diagnostics.TraceEventType.Information, TraceCode.InitiatingNamedPipeConnection,
1757 SR.GetString(SR.TraceCodeInitiatingNamedPipeConnection),
1758 new StringTraceRecord("Uri", remoteUri.ToString()), this, null);
1760 resolvedAddress = GetPipeName(remoteUri, this.pipeSettings);
1762 const int backoffBufferMilliseconds = 150;
1763 TimeSpan backoffTimeout;
1764 if (timeout >= TimeSpan.FromMilliseconds(backoffBufferMilliseconds * 2))
1766 backoffTimeout = TimeoutHelper.Add(timeout, TimeSpan.Zero - TimeSpan.FromMilliseconds(backoffBufferMilliseconds));
1770 backoffTimeout = Ticks.ToTimeSpan((Ticks.FromMilliseconds(backoffBufferMilliseconds) / 2) + 1);
1773 backoffHelper = new BackoffTimeoutHelper(backoffTimeout, TimeSpan.FromMinutes(5));
1776 [ResourceConsumption(ResourceScope.Machine)]
1777 IConnection TryConnect(Uri remoteUri, string resolvedAddress, BackoffTimeoutHelper backoffHelper)
1779 const int access = UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE;
1780 bool lastAttempt = backoffHelper.IsExpired();
1782 int flags = UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
1784 // By default Windows named pipe connection is created with impersonation, but we want
1785 // to create it with anonymous and let WCF take care of impersonation/identification.
1786 flags |= UnsafeNativeMethods.SECURITY_QOS_PRESENT | UnsafeNativeMethods.SECURITY_ANONYMOUS;
1788 PipeHandle pipeHandle = UnsafeNativeMethods.CreateFile(resolvedAddress, access, 0, IntPtr.Zero,
1789 UnsafeNativeMethods.OPEN_EXISTING, flags, IntPtr.Zero);
1790 int error = Marshal.GetLastWin32Error();
1791 if (pipeHandle.IsInvalid)
1793 pipeHandle.SetHandleAsInvalid();
1797 int mode = UnsafeNativeMethods.PIPE_READMODE_MESSAGE;
1798 if (UnsafeNativeMethods.SetNamedPipeHandleState(pipeHandle, ref mode, IntPtr.Zero, IntPtr.Zero) == 0)
1800 error = Marshal.GetLastWin32Error();
1802 PipeException innerException = new PipeException(SR.GetString(SR.PipeModeChangeFailed,
1803 PipeError.GetErrorString(error)), error);
1804 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1805 CreateConnectFailedException(remoteUri, innerException));
1807 return new PipeConnection(pipeHandle, bufferSize, false, true);
1810 if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND || error == UnsafeNativeMethods.ERROR_PIPE_BUSY)
1814 Exception innerException = new PipeException(SR.GetString(SR.PipeConnectAddressFailed,
1815 resolvedAddress, PipeError.GetErrorString(error)), error);
1817 TimeoutException timeoutException;
1818 string endpoint = remoteUri.AbsoluteUri;
1820 if (error == UnsafeNativeMethods.ERROR_PIPE_BUSY)
1822 timeoutException = new TimeoutException(SR.GetString(SR.PipeConnectTimedOutServerTooBusy,
1823 endpoint, backoffHelper.OriginalTimeout), innerException);
1827 timeoutException = new TimeoutException(SR.GetString(SR.PipeConnectTimedOut,
1828 endpoint, backoffHelper.OriginalTimeout), innerException);
1831 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(timeoutException);
1838 PipeException innerException = new PipeException(SR.GetString(SR.PipeConnectAddressFailed,
1839 resolvedAddress, PipeError.GetErrorString(error)), error);
1840 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1841 CreateConnectFailedException(remoteUri, innerException));
1845 static AppContainerInfo GetAppContainerInfo(IPipeTransportFactorySettings transportFactorySettings)
1847 if (AppContainerInfo.IsAppContainerSupported &&
1848 transportFactorySettings != null &&
1849 transportFactorySettings.PipeSettings != null)
1851 ApplicationContainerSettings appSettings = transportFactorySettings.PipeSettings.ApplicationContainerSettings;
1852 if (appSettings != null && appSettings.TargetingAppContainer)
1854 return AppContainerInfo.CreateAppContainerInfo(appSettings.PackageFullName, appSettings.SessionId);
1861 class ConnectAsyncResult : AsyncResult
1863 PipeConnectionInitiator parent;
1865 string resolvedAddress;
1866 BackoffTimeoutHelper backoffHelper;
1867 TimeoutHelper timeoutHelper;
1868 IConnection connection;
1869 static Action<object> waitCompleteCallback;
1871 public ConnectAsyncResult(PipeConnectionInitiator parent, Uri remoteUri, TimeSpan timeout,
1872 AsyncCallback callback, object state)
1873 : base(callback, state)
1875 this.parent = parent;
1876 this.remoteUri = remoteUri;
1877 this.timeoutHelper = new TimeoutHelper(timeout);
1878 parent.PrepareConnect(remoteUri, this.timeoutHelper.RemainingTime(), out this.resolvedAddress, out this.backoffHelper);
1880 if (this.ConnectAndWait())
1882 this.Complete(true);
1886 bool ConnectAndWait()
1888 this.connection = this.parent.TryConnect(this.remoteUri, this.resolvedAddress, this.backoffHelper);
1889 bool completed = (this.connection != null);
1892 if (waitCompleteCallback == null)
1894 waitCompleteCallback = new Action<object>(OnWaitComplete);
1896 this.backoffHelper.WaitAndBackoff(waitCompleteCallback, this);
1901 public static IConnection End(IAsyncResult result)
1903 ConnectAsyncResult thisPtr = AsyncResult.End<ConnectAsyncResult>(result);
1904 return thisPtr.connection;
1907 static void OnWaitComplete(object state)
1909 Exception exception = null;
1910 ConnectAsyncResult thisPtr = (ConnectAsyncResult)state;
1912 bool completeSelf = true;
1915 if (DiagnosticUtility.ShouldTraceInformation)
1917 TraceUtility.TraceEvent(
1918 TraceEventType.Information,
1919 TraceCode.FailedPipeConnect,
1921 SR.TraceCodeFailedPipeConnect,
1922 thisPtr.timeoutHelper.RemainingTime(),
1923 thisPtr.remoteUri));
1926 completeSelf = thisPtr.ConnectAndWait();
1939 thisPtr.Complete(false, exception);
1945 class PipeConnectionListener : IConnectionListener
1949 HostNameComparisonMode hostNameComparisonMode;
1952 List<PendingAccept> pendingAccepts;
1953 bool anyPipesCreated;
1954 PipeSharedMemory sharedMemory;
1955 List<SecurityIdentifier> allowedSids;
1956 bool useCompletionPort;
1959 public PipeConnectionListener(Uri pipeUri, HostNameComparisonMode hostNameComparisonMode, int bufferSize,
1960 List<SecurityIdentifier> allowedSids, bool useCompletionPort, int maxConnections)
1962 PipeUri.Validate(pipeUri);
1963 this.pipeUri = pipeUri;
1964 this.hostNameComparisonMode = hostNameComparisonMode;
1965 this.allowedSids = allowedSids;
1966 this.bufferSize = bufferSize;
1967 pendingAccepts = new List<PendingAccept>();
1968 this.useCompletionPort = useCompletionPort;
1969 this.maxInstances = Math.Min(maxConnections, UnsafeNativeMethods.PIPE_UNLIMITED_INSTANCES);
1974 get { return this; }
1977 public string PipeName { get { return sharedMemory.PipeName; } }
1979 public IAsyncResult BeginAccept(AsyncCallback callback, object state)
1985 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException("", SR.GetString(SR.PipeListenerDisposed)));
1990 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PipeListenerNotListening)));
1993 PipeHandle pipeHandle = CreatePipe();
1994 PendingAccept pendingAccept = new PendingAccept(this, pipeHandle, useCompletionPort, callback, state);
1995 if (!pendingAccept.CompletedSynchronously)
1997 this.pendingAccepts.Add(pendingAccept);
1999 return pendingAccept;
2003 public IConnection EndAccept(IAsyncResult result)
2005 PendingAccept pendingAccept = result as PendingAccept;
2006 if (pendingAccept == null)
2008 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("result", SR.GetString(SR.InvalidAsyncResult));
2011 PipeHandle acceptedPipe = pendingAccept.End();
2013 if (acceptedPipe == null)
2019 return new PipeConnection(acceptedPipe, bufferSize,
2020 pendingAccept.IsBoundToCompletionPort, pendingAccept.IsBoundToCompletionPort);
2024 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2025 [ResourceConsumption(ResourceScope.Machine)]
2026 unsafe PipeHandle CreatePipe()
2028 int openMode = UnsafeNativeMethods.PIPE_ACCESS_DUPLEX | UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
2029 if (!anyPipesCreated)
2031 openMode |= UnsafeNativeMethods.FILE_FLAG_FIRST_PIPE_INSTANCE;
2034 byte[] binarySecurityDescriptor;
2038 binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE);
2040 catch (Win32Exception e)
2042 // While Win32exceptions are not expected, if they do occur we need to obey the pipe/communication exception model.
2043 Exception innerException = new PipeException(e.Message, e);
2044 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
2047 PipeHandle pipeHandle;
2049 string pipeName = null;
2050 fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
2052 UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
2053 securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
2055 pipeName = this.sharedMemory.PipeName;
2056 pipeHandle = UnsafeNativeMethods.CreateNamedPipe(
2059 UnsafeNativeMethods.PIPE_TYPE_MESSAGE | UnsafeNativeMethods.PIPE_READMODE_MESSAGE,
2060 maxInstances, bufferSize, bufferSize, 0, securityAttributes);
2061 error = Marshal.GetLastWin32Error();
2064 if (pipeHandle.IsInvalid)
2066 pipeHandle.SetHandleAsInvalid();
2068 Exception innerException = new PipeException(SR.GetString(SR.PipeListenFailed,
2069 pipeUri.AbsoluteUri, PipeError.GetErrorString(error)), error);
2071 if (error == UnsafeNativeMethods.ERROR_ACCESS_DENIED)
2073 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAccessDeniedException(innerException.Message, innerException));
2075 else if (error == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
2077 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAlreadyInUseException(innerException.Message, innerException));
2081 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
2086 if (TD.NamedPipeCreatedIsEnabled())
2088 TD.NamedPipeCreated(pipeName);
2092 bool closePipe = true;
2095 if (useCompletionPort)
2097 ThreadPool.BindHandle(pipeHandle);
2099 anyPipesCreated = true;
2112 public void Dispose()
2118 if (sharedMemory != null)
2120 sharedMemory.Dispose();
2122 for (int i = 0; i < pendingAccepts.Count; i++)
2124 pendingAccepts[i].Abort();
2131 public void Listen()
2137 string sharedMemoryName = PipeUri.BuildSharedMemoryName(pipeUri, hostNameComparisonMode, true);
2138 if (!PipeSharedMemory.TryCreate(allowedSids, pipeUri, sharedMemoryName, out this.sharedMemory))
2140 PipeSharedMemory tempSharedMemory = null;
2142 // first see if we're in RANU by creating a unique Uri in the global namespace
2143 Uri tempUri = new Uri(pipeUri, Guid.NewGuid().ToString());
2144 string tempSharedMemoryName = PipeUri.BuildSharedMemoryName(tempUri, hostNameComparisonMode, true);
2145 if (PipeSharedMemory.TryCreate(allowedSids, tempUri, tempSharedMemoryName, out tempSharedMemory))
2147 // we're not RANU, throw PipeNameInUse
2148 tempSharedMemory.Dispose();
2149 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
2150 PipeSharedMemory.CreatePipeNameInUseException(UnsafeNativeMethods.ERROR_ACCESS_DENIED, pipeUri));
2154 // try the session namespace since we're RANU
2155 sharedMemoryName = PipeUri.BuildSharedMemoryName(pipeUri, hostNameComparisonMode, false);
2156 this.sharedMemory = PipeSharedMemory.Create(allowedSids, pipeUri, sharedMemoryName);
2165 void RemovePendingAccept(PendingAccept pendingAccept)
2169 Fx.Assert(this.pendingAccepts.Contains(pendingAccept), "An unknown PendingAccept is removing itself.");
2170 this.pendingAccepts.Remove(pendingAccept);
2174 class PendingAccept : AsyncResult
2176 PipeHandle pipeHandle;
2178 OverlappedIOCompleteCallback onAcceptComplete;
2179 static Action<object> onStartAccept;
2180 OverlappedContext overlapped;
2181 bool isBoundToCompletionPort;
2182 PipeConnectionListener listener;
2183 EventTraceActivity eventTraceActivity;
2185 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2186 public unsafe PendingAccept(PipeConnectionListener listener, PipeHandle pipeHandle, bool isBoundToCompletionPort,
2187 AsyncCallback callback, object state)
2188 : base(callback, state)
2190 this.pipeHandle = pipeHandle;
2191 this.result = pipeHandle;
2192 this.listener = listener;
2193 onAcceptComplete = new OverlappedIOCompleteCallback(OnAcceptComplete);
2194 overlapped = new OverlappedContext();
2195 this.isBoundToCompletionPort = isBoundToCompletionPort;
2197 if (TD.PipeConnectionAcceptStartIsEnabled())
2199 this.eventTraceActivity = new EventTraceActivity();
2200 TD.PipeConnectionAcceptStart(this.eventTraceActivity, this.listener.pipeUri != null ? this.listener.pipeUri.ToString() : string.Empty);
2203 if (!Thread.CurrentThread.IsThreadPoolThread)
2205 if (onStartAccept == null)
2207 onStartAccept = new Action<object>(OnStartAccept);
2209 ActionItem.Schedule(onStartAccept, this);
2217 public bool IsBoundToCompletionPort
2219 get { return this.isBoundToCompletionPort; }
2222 static void OnStartAccept(object state)
2224 PendingAccept pendingAccept = (PendingAccept)state;
2225 pendingAccept.StartAccept(false);
2228 Exception CreatePipeAcceptFailedException(int errorCode)
2230 Exception innerException = new PipeException(SR.GetString(SR.PipeAcceptFailed,
2231 PipeError.GetErrorString(errorCode)), errorCode);
2232 return new CommunicationException(innerException.Message, innerException);
2235 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2236 unsafe void StartAccept(bool synchronous)
2238 Exception completionException = null;
2239 bool completeSelf = false;
2244 this.overlapped.StartAsyncOperation(null, onAcceptComplete, this.isBoundToCompletionPort);
2247 if (UnsafeNativeMethods.ConnectNamedPipe(pipeHandle, overlapped.NativeOverlapped) == 0)
2249 int error = Marshal.GetLastWin32Error();
2252 case UnsafeNativeMethods.ERROR_NO_DATA:
2253 if (UnsafeNativeMethods.DisconnectNamedPipe(pipeHandle) != 0)
2259 completeSelf = true;
2260 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeAcceptFailedException(error));
2262 case UnsafeNativeMethods.ERROR_PIPE_CONNECTED:
2263 completeSelf = true;
2265 case UnsafeNativeMethods.ERROR_IO_PENDING:
2268 completeSelf = true;
2269 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeAcceptFailedException(error));
2274 completeSelf = true;
2280 catch (ObjectDisposedException exception)
2282 // A ---- with Abort can cause PipeHandle to throw this.
2283 Fx.Assert(this.result == null, "Got an ObjectDisposedException but not an Abort!");
2284 DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
2285 completeSelf = true;
2291 this.overlapped.CancelAsyncOperation();
2292 this.overlapped.Free();
2296 #pragma warning suppress 56500 // [....], transferring exception to another thread
2304 completeSelf = true;
2305 completionException = e;
2311 this.listener.RemovePendingAccept(this);
2313 base.Complete(synchronous, completionException);
2317 // Must be called in PipeConnectionListener's lock.
2320 this.result = null; // we need to return null after an abort
2324 public PipeHandle End()
2326 AsyncResult.End<PendingAccept>(this);
2330 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2331 unsafe void OnAcceptComplete(bool haveResult, int error, int numBytes)
2333 this.listener.RemovePendingAccept(this);
2337 // No ---- with Abort here since Abort can't be called once RemovePendingAccept happens.
2338 if (this.result != null && UnsafeNativeMethods.GetOverlappedResult(this.pipeHandle,
2339 this.overlapped.NativeOverlapped, out numBytes, 0) == 0)
2341 error = Marshal.GetLastWin32Error();
2349 this.overlapped.Free();
2351 if (TD.PipeConnectionAcceptStopIsEnabled())
2353 TD.PipeConnectionAcceptStop(this.eventTraceActivity);
2358 this.pipeHandle.Close();
2359 base.Complete(false, CreatePipeAcceptFailedException(error));
2363 base.Complete(false);
2369 static class SecurityDescriptorHelper
2371 static byte[] worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork;
2372 static byte[] worldCreatorOwnerWithReadDescriptorDenyNetwork;
2374 static SecurityDescriptorHelper()
2376 worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork = FromSecurityIdentifiersFull(null, UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE);
2377 worldCreatorOwnerWithReadDescriptorDenyNetwork = FromSecurityIdentifiersFull(null, UnsafeNativeMethods.GENERIC_READ);
2380 internal static byte[] FromSecurityIdentifiers(List<SecurityIdentifier> allowedSids, int accessRights)
2382 if (allowedSids == null)
2384 if (accessRights == (UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE))
2386 return worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork;
2389 if (accessRights == UnsafeNativeMethods.GENERIC_READ)
2391 return worldCreatorOwnerWithReadDescriptorDenyNetwork;
2395 return FromSecurityIdentifiersFull(allowedSids, accessRights);
2398 static byte[] FromSecurityIdentifiersFull(List<SecurityIdentifier> allowedSids, int accessRights)
2400 int capacity = allowedSids == null ? 3 : 2 + allowedSids.Count;
2401 DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, capacity);
2403 // add deny ACE first so that we don't get short circuited
2404 dacl.AddAccess(AccessControlType.Deny, new SecurityIdentifier(WellKnownSidType.NetworkSid, null),
2405 UnsafeNativeMethods.GENERIC_ALL, InheritanceFlags.None, PropagationFlags.None);
2407 // clients get different rights, since they shouldn't be able to listen
2408 int clientAccessRights = GenerateClientAccessRights(accessRights);
2410 if (allowedSids == null)
2412 dacl.AddAccess(AccessControlType.Allow, new SecurityIdentifier(WellKnownSidType.WorldSid, null),
2413 clientAccessRights, InheritanceFlags.None, PropagationFlags.None);
2417 for (int i = 0; i < allowedSids.Count; i++)
2419 SecurityIdentifier allowedSid = allowedSids[i];
2420 dacl.AddAccess(AccessControlType.Allow, allowedSid,
2421 clientAccessRights, InheritanceFlags.None, PropagationFlags.None);
2425 dacl.AddAccess(AccessControlType.Allow, GetProcessLogonSid(), accessRights, InheritanceFlags.None, PropagationFlags.None);
2428 if (AppContainerInfo.IsRunningInAppContainer)
2430 // NamedPipeBinding requires dacl with current AppContainer SID
2431 // to setup multiple NamedPipes in the BeginAccept loop.
2433 AccessControlType.Allow,
2434 AppContainerInfo.GetCurrentAppContainerSid(),
2436 InheritanceFlags.None,
2437 PropagationFlags.None);
2440 CommonSecurityDescriptor securityDescriptor =
2441 new CommonSecurityDescriptor(false, false, ControlFlags.None, null, null, null, dacl);
2442 byte[] binarySecurityDescriptor = new byte[securityDescriptor.BinaryLength];
2443 securityDescriptor.GetBinaryForm(binarySecurityDescriptor, 0);
2444 return binarySecurityDescriptor;
2447 // Security: We cannot grant rights for FILE_CREATE_PIPE_INSTANCE to clients, otherwise other apps can intercept server side pipes.
2448 // FILE_CREATE_PIPE_INSTANCE is granted in 2 ways, via GENERIC_WRITE or directly specified. Remove both.
2449 static int GenerateClientAccessRights(int accessRights)
2451 int everyoneAccessRights = accessRights;
2453 if ((everyoneAccessRights & UnsafeNativeMethods.GENERIC_WRITE) != 0)
2455 everyoneAccessRights &= ~UnsafeNativeMethods.GENERIC_WRITE;
2457 // Since GENERIC_WRITE grants the permissions to write to a file, we need to add it back.
2458 const int clientWriteAccess = UnsafeNativeMethods.FILE_WRITE_ATTRIBUTES | UnsafeNativeMethods.FILE_WRITE_DATA | UnsafeNativeMethods.FILE_WRITE_EA;
2459 everyoneAccessRights |= clientWriteAccess;
2462 // Future proofing: FILE_CREATE_PIPE_INSTANCE isn't used currently but we need to ensure it is not granted.
2463 everyoneAccessRights &= ~UnsafeNativeMethods.FILE_CREATE_PIPE_INSTANCE;
2465 return everyoneAccessRights;
2468 // The logon sid is generated on process start up so it is unique to this process.
2469 static SecurityIdentifier GetProcessLogonSid()
2471 int pid = Process.GetCurrentProcess().Id;
2472 return System.ServiceModel.Activation.Utility.GetLogonSidForPid(pid);
2476 unsafe class PipeSharedMemory : IDisposable
2478 internal const string PipePrefix = @"\\.\pipe\";
2479 internal const string PipeLocalPrefix = @"\\.\pipe\Local\";
2480 SafeFileMappingHandle fileMapping;
2482 string pipeNameGuidPart;
2485 PipeSharedMemory(SafeFileMappingHandle fileMapping, Uri pipeUri)
2486 : this(fileMapping, pipeUri, null)
2490 PipeSharedMemory(SafeFileMappingHandle fileMapping, Uri pipeUri, string pipeName)
2492 this.pipeName = pipeName;
2493 this.fileMapping = fileMapping;
2494 this.pipeUri = pipeUri;
2497 public static PipeSharedMemory Create(List<SecurityIdentifier> allowedSids, Uri pipeUri, string sharedMemoryName)
2499 PipeSharedMemory result;
2500 if (TryCreate(allowedSids, pipeUri, sharedMemoryName, out result))
2506 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameInUseException(UnsafeNativeMethods.ERROR_ACCESS_DENIED, pipeUri));
2510 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2511 public unsafe static bool TryCreate(List<SecurityIdentifier> allowedSids, Uri pipeUri, string sharedMemoryName, out PipeSharedMemory result)
2513 Guid pipeGuid = Guid.NewGuid();
2514 string pipeName = BuildPipeName(pipeGuid.ToString());
2515 byte[] binarySecurityDescriptor;
2518 binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ);
2520 catch (Win32Exception e)
2522 // While Win32exceptions are not expected, if they do occur we need to obey the pipe/communication exception model.
2523 Exception innerException = new PipeException(e.Message, e);
2524 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
2527 SafeFileMappingHandle fileMapping;
2530 fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
2532 UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
2533 securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
2535 fileMapping = UnsafeNativeMethods.CreateFileMapping((IntPtr)(-1), securityAttributes,
2536 UnsafeNativeMethods.PAGE_READWRITE, 0, sizeof(SharedMemoryContents), sharedMemoryName);
2537 error = Marshal.GetLastWin32Error();
2540 if (fileMapping.IsInvalid)
2542 fileMapping.SetHandleAsInvalid();
2543 if (error == UnsafeNativeMethods.ERROR_ACCESS_DENIED)
2549 Exception innerException = new PipeException(SR.GetString(SR.PipeNameCantBeReserved,
2550 pipeUri.AbsoluteUri, PipeError.GetErrorString(error)), error);
2551 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAccessDeniedException(innerException.Message, innerException));
2555 // now we have a valid file mapping handle
2556 if (error == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
2558 fileMapping.Close();
2559 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameInUseException(error, pipeUri));
2561 PipeSharedMemory pipeSharedMemory = new PipeSharedMemory(fileMapping, pipeUri, pipeName);
2562 bool disposeSharedMemory = true;
2565 pipeSharedMemory.InitializeContents(pipeGuid);
2566 disposeSharedMemory = false;
2567 result = pipeSharedMemory;
2569 if (TD.PipeSharedMemoryCreatedIsEnabled())
2571 TD.PipeSharedMemoryCreated(sharedMemoryName);
2577 if (disposeSharedMemory)
2579 pipeSharedMemory.Dispose();
2584 [ResourceConsumption(ResourceScope.Machine)]
2585 public static PipeSharedMemory Open(string sharedMemoryName, Uri pipeUri)
2587 SafeFileMappingHandle fileMapping = UnsafeNativeMethods.OpenFileMapping(
2588 UnsafeNativeMethods.FILE_MAP_READ, false, sharedMemoryName);
2589 if (fileMapping.IsInvalid)
2591 int error = Marshal.GetLastWin32Error();
2592 fileMapping.SetHandleAsInvalid();
2593 if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
2595 fileMapping = UnsafeNativeMethods.OpenFileMapping(
2596 UnsafeNativeMethods.FILE_MAP_READ, false, "Global\\" + sharedMemoryName);
2597 if (fileMapping.IsInvalid)
2599 error = Marshal.GetLastWin32Error();
2600 fileMapping.SetHandleAsInvalid();
2601 if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
2605 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2607 return new PipeSharedMemory(fileMapping, pipeUri);
2610 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2612 return new PipeSharedMemory(fileMapping, pipeUri);
2615 public void Dispose()
2617 if (fileMapping != null)
2619 fileMapping.Close();
2624 public string PipeName
2626 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2629 if (pipeName == null)
2631 SafeViewOfFileHandle view = GetView(false);
2634 SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
2635 if (contents->isInitialized)
2637 Thread.MemoryBarrier();
2638 this.pipeNameGuidPart = contents->pipeGuid.ToString();
2639 this.pipeName = BuildPipeName(this.pipeNameGuidPart);
2651 internal string GetPipeName(AppContainerInfo appInfo)
2653 if (appInfo == null)
2655 return this.PipeName;
2657 else if (this.PipeName != null)
2659 // Build the PipeName for a pipe inside an AppContainer as follows
2660 // \\.\pipe\Sessions\<SessionId>\<NamedObjectPath>\<PipeGuid>
2661 return string.Format(
2662 CultureInfo.InvariantCulture,
2663 @"\\.\pipe\Sessions\{0}\{1}\{2}",
2665 appInfo.NamedObjectPath,
2666 this.pipeNameGuidPart);
2672 [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2673 void InitializeContents(Guid pipeGuid)
2675 SafeViewOfFileHandle view = GetView(true);
2678 SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
2679 contents->pipeGuid = pipeGuid;
2680 Thread.MemoryBarrier();
2681 contents->isInitialized = true;
2689 public static Exception CreatePipeNameInUseException(int error, Uri pipeUri)
2691 Exception innerException = new PipeException(SR.GetString(SR.PipeNameInUse, pipeUri.AbsoluteUri), error);
2692 return new AddressAlreadyInUseException(innerException.Message, innerException);
2695 static Exception CreatePipeNameCannotBeAccessedException(int error, Uri pipeUri)
2697 Exception innerException = new PipeException(SR.GetString(SR.PipeNameCanNotBeAccessed,
2698 PipeError.GetErrorString(error)), error);
2699 return new AddressAccessDeniedException(SR.GetString(SR.PipeNameCanNotBeAccessed2, pipeUri.AbsoluteUri), innerException);
2702 SafeViewOfFileHandle GetView(bool writable)
2704 SafeViewOfFileHandle handle = UnsafeNativeMethods.MapViewOfFile(fileMapping,
2705 writable ? UnsafeNativeMethods.FILE_MAP_WRITE : UnsafeNativeMethods.FILE_MAP_READ,
2706 0, 0, (IntPtr)sizeof(SharedMemoryContents));
2707 if (handle.IsInvalid)
2709 int error = Marshal.GetLastWin32Error();
2710 handle.SetHandleAsInvalid();
2711 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2716 static string BuildPipeName(string pipeGuid)
2718 return (AppContainerInfo.IsRunningInAppContainer ? PipeLocalPrefix : PipePrefix) + pipeGuid;
2721 [StructLayout(LayoutKind.Sequential)]
2722 struct SharedMemoryContents
2724 public bool isInitialized;
2725 public Guid pipeGuid;
2729 static class PipeUri
2731 public static string BuildSharedMemoryName(Uri uri, HostNameComparisonMode hostNameComparisonMode, bool global)
2733 string path = PipeUri.GetPath(uri);
2736 switch (hostNameComparisonMode)
2738 case HostNameComparisonMode.StrongWildcard:
2741 case HostNameComparisonMode.Exact:
2744 case HostNameComparisonMode.WeakWildcard:
2749 return PipeUri.BuildSharedMemoryName(host, path, global);
2752 internal static string BuildSharedMemoryName(string hostName, string path, bool global, AppContainerInfo appContainerInfo)
2754 if (appContainerInfo == null)
2756 return BuildSharedMemoryName(hostName, path, global);
2760 Fx.Assert(appContainerInfo.SessionId != ApplicationContainerSettingsDefaults.CurrentSession, "Session has not yet been initialized.");
2761 Fx.Assert(!String.IsNullOrEmpty(appContainerInfo.NamedObjectPath),
2762 "NamedObjectPath cannot be empty when creating the SharedMemoryName when running in an AppContainer.");
2764 //We need to use a session symlink for the lowbox appcontainer.
2765 // Session\{0}\{1}\{2}\<SharedMemoryName>
2766 return string.Format(
2767 CultureInfo.InvariantCulture,
2768 @"Session\{0}\{1}\{2}",
2769 appContainerInfo.SessionId,
2770 appContainerInfo.NamedObjectPath,
2771 BuildSharedMemoryName(hostName, path, global));
2775 static string BuildSharedMemoryName(string hostName, string path, bool global)
2777 StringBuilder builder = new StringBuilder();
2778 builder.Append(Uri.UriSchemeNetPipe);
2779 builder.Append("://");
2780 builder.Append(hostName.ToUpperInvariant());
2781 builder.Append(path);
2782 string canonicalName = builder.ToString();
2784 byte[] canonicalBytes = Encoding.UTF8.GetBytes(canonicalName);
2788 if (canonicalBytes.Length >= 128)
2790 using (HashAlgorithm hash = GetHashAlgorithm())
2792 hashedBytes = hash.ComputeHash(canonicalBytes);
2798 hashedBytes = canonicalBytes;
2802 builder = new StringBuilder();
2805 // we may need to create the shared memory in the global namespace so we work with terminal services+admin
2806 builder.Append("Global\\");
2810 builder.Append("Local\\");
2812 builder.Append(Uri.UriSchemeNetPipe);
2813 builder.Append(separator);
2814 builder.Append(Convert.ToBase64String(hashedBytes));
2815 return builder.ToString();
2818 static HashAlgorithm GetHashAlgorithm()
2820 if (SecurityUtilsEx.RequiresFipsCompliance)
2821 return new SHA1CryptoServiceProvider();
2823 return new SHA1Managed();
2826 public static string GetPath(Uri uri)
2828 string path = uri.LocalPath.ToUpperInvariant();
2829 if (!path.EndsWith("/", StringComparison.Ordinal))
2834 public static string GetParentPath(string path)
2836 if (path.EndsWith("/", StringComparison.Ordinal))
2837 path = path.Substring(0, path.Length - 1);
2838 if (path.Length == 0)
2840 return path.Substring(0, path.LastIndexOf('/') + 1);
2843 public static void Validate(Uri uri)
2845 if (uri.Scheme != Uri.UriSchemeNetPipe)
2846 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("uri", SR.GetString(SR.PipeUriSchemeWrong));
2850 static class PipeError
2852 public static string GetErrorString(int error)
2854 StringBuilder stringBuilder = new StringBuilder(512);
2855 if (UnsafeNativeMethods.FormatMessage(UnsafeNativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS |
2856 UnsafeNativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | UnsafeNativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY,
2857 IntPtr.Zero, error, CultureInfo.CurrentCulture.LCID, stringBuilder, stringBuilder.Capacity, IntPtr.Zero) != 0)
2859 stringBuilder = stringBuilder.Replace("\n", "");
2860 stringBuilder = stringBuilder.Replace("\r", "");
2861 return SR.GetString(
2862 SR.PipeKnownWin32Error,
2863 stringBuilder.ToString(),
2864 error.ToString(CultureInfo.InvariantCulture),
2865 Convert.ToString(error, 16));
2869 return SR.GetString(
2870 SR.PipeUnknownWin32Error,
2871 error.ToString(CultureInfo.InvariantCulture),
2872 Convert.ToString(error, 16));