70538c75bfc7ac7eec59adfffa4d0ac753f098ee
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / PipeConnection.cs
1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4
5 namespace System.ServiceModel.Channels
6 {
7     using System.Collections.Generic;
8     using System.Diagnostics;
9     using System.Globalization;
10     using System.IO;
11     using System.Net;
12     using System.Runtime;
13     using System.Runtime.Diagnostics;
14     using System.Runtime.InteropServices;
15     using System.Runtime.Versioning;
16     using System.Security.AccessControl;
17     using System.ComponentModel;
18     using System.Security;
19     using System.Security.Cryptography;
20     using System.Security.Permissions;
21     using System.Security.Principal;
22     using System.ServiceModel;
23     using System.ServiceModel.Activation;
24     using System.ServiceModel.Diagnostics;
25     using System.ServiceModel.Diagnostics.Application;
26     using System.ServiceModel.Security;
27     using System.Text;
28     using System.Threading;
29     using SafeCloseHandle = System.ServiceModel.Activation.SafeCloseHandle;
30
31     sealed class PipeConnection : IConnection
32     {
33         // common state
34         PipeHandle pipe;
35         CloseState closeState;
36         bool aborted;
37         bool isBoundToCompletionPort;
38         bool autoBindToCompletionPort;
39         TraceEventType exceptionEventType;
40         static byte[] zeroBuffer;
41
42         // read state
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;
48         int readBufferSize;
49         ManualResetEvent atEOFEvent;
50         bool isAtEOF;
51         OverlappedIOCompleteCallback onAsyncReadComplete;
52         Exception asyncReadException;
53         WaitCallback asyncReadCallback;
54         object asyncReadCallbackState;
55         int asyncBytesRead;
56
57         // write state
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;
67         int syncWriteSize;
68         byte[] pendingWriteBuffer;
69         BufferManager pendingWriteBufferManager;
70         OverlappedIOCompleteCallback onAsyncWriteComplete;
71         int writeBufferSize;
72
73         // timeout support
74         TimeSpan readTimeout;
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;
82
83         public PipeConnection(PipeHandle pipe, int connectionBufferSize, bool isBoundToCompletionPort, bool autoBindToCompletionPort)
84         {
85             if (pipe == null)
86                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
87             if (pipe.IsInvalid)
88                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("pipe");
89
90             this.closeState = CloseState.Open;
91             this.exceptionEventType = TraceEventType.Error;
92             this.isBoundToCompletionPort = isBoundToCompletionPort;
93             this.autoBindToCompletionPort = autoBindToCompletionPort;
94             this.pipe = pipe;
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);
103         }
104
105         public int AsyncReadBufferSize
106         {
107             get
108             {
109                 return this.readBufferSize;
110             }
111         }
112
113         public byte[] AsyncReadBuffer
114         {
115             get
116             {
117                 return this.asyncReadBuffer;
118             }
119         }
120
121         static byte[] ZeroBuffer
122         {
123             get
124             {
125                 if (PipeConnection.zeroBuffer == null)
126                 {
127                     PipeConnection.zeroBuffer = new byte[1];
128                 }
129                 return PipeConnection.zeroBuffer;
130             }
131         }
132
133         public TraceEventType ExceptionEventType
134         {
135             get { return this.exceptionEventType; }
136             set { this.exceptionEventType = value; }
137         }
138
139         public IPEndPoint RemoteIPEndPoint
140         {
141             get { return null; }
142         }
143
144         IOThreadTimer ReadTimer
145         {
146             get
147             {
148                 if (this.readTimer == null)
149                 {
150                     if (onReadTimeout == null)
151                     {
152                         onReadTimeout = new Action<object>(OnReadTimeout);
153                     }
154
155                     this.readTimer = new IOThreadTimer(onReadTimeout, this, false);
156                 }
157
158                 return this.readTimer;
159             }
160         }
161         IOThreadTimer WriteTimer
162         {
163             get
164             {
165                 if (this.writeTimer == null)
166                 {
167                     if (onWriteTimeout == null)
168                     {
169                         onWriteTimeout = new Action<object>(OnWriteTimeout);
170                     }
171
172                     this.writeTimer = new IOThreadTimer(onWriteTimeout, this, false);
173                 }
174
175                 return this.writeTimer;
176             }
177         }
178
179         static void OnReadTimeout(object state)
180         {
181             PipeConnection thisPtr = (PipeConnection)state;
182             thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, thisPtr.readTimeout), TransferOperation.Read);
183         }
184
185         static void OnWriteTimeout(object state)
186         {
187             PipeConnection thisPtr = (PipeConnection)state;
188             thisPtr.Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, thisPtr.writeTimeout), TransferOperation.Write);
189         }
190
191         public void Abort()
192         {
193             Abort(null, TransferOperation.Undefined);
194         }
195
196         void Abort(string timeoutErrorString, TransferOperation transferOperation)
197         {
198             CloseHandle(true, timeoutErrorString, transferOperation);
199         }
200
201         Exception ConvertPipeException(PipeException pipeException, TransferOperation transferOperation)
202         {
203             return ConvertPipeException(pipeException.Message, pipeException, transferOperation);
204         }
205
206         Exception ConvertPipeException(string exceptionMessage, PipeException pipeException, TransferOperation transferOperation)
207         {
208             if (this.timeoutErrorString != null)
209             {
210                 if (transferOperation == this.timeoutErrorTransferOperation)
211                 {
212                     return new TimeoutException(this.timeoutErrorString, pipeException);
213                 }
214                 else
215                 {
216                     return new CommunicationException(this.timeoutErrorString, pipeException);
217                 }
218             }
219             else if (this.aborted)
220             {
221                 return new CommunicationObjectAbortedException(exceptionMessage, pipeException);
222             }
223             else
224             {
225                 return new CommunicationException(exceptionMessage, pipeException);
226             }
227         }
228
229         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
230         public unsafe AsyncCompletionResult BeginRead(int offset, int size, TimeSpan timeout,
231             WaitCallback callback, object state)
232         {
233             ConnectionUtilities.ValidateBufferBounds(AsyncReadBuffer, offset, size);
234
235             lock (readLock)
236             {
237                 try
238                 {
239                     ValidateEnterReadingState(true);
240
241                     if (isAtEOF)
242                     {
243                         asyncBytesRead = 0;
244                         asyncReadException = null;
245                         return AsyncCompletionResult.Completed;
246                     }
247
248                     if (autoBindToCompletionPort)
249                     {
250                         if (!isBoundToCompletionPort)
251                         {
252                             lock (writeLock)
253                             {
254                                 // readLock, writeLock acquired in order to prevent deadlock
255                                 EnsureBoundToCompletionPort();
256                             }
257                         }
258                     }
259
260                     if (this.isReadOutstanding)
261                     {
262                         throw Fx.AssertAndThrow("Read I/O already pending when BeginRead called.");
263                     }
264                     try
265                     {
266                         this.readTimeout = timeout;
267
268                         if (this.readTimeout != TimeSpan.MaxValue)
269                         {
270                             this.ReadTimer.Set(this.readTimeout);
271                         }
272
273                         this.asyncReadCallback = callback;
274                         this.asyncReadCallbackState = state;
275
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)
279                         {
280                             int error = Marshal.GetLastWin32Error();
281                             if (error != UnsafeNativeMethods.ERROR_IO_PENDING && error != UnsafeNativeMethods.ERROR_MORE_DATA)
282                             {
283                                 this.isReadOutstanding = false;
284                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
285                             }
286                         }
287                     }
288                     finally
289                     {
290                         if (!this.isReadOutstanding)
291                         {
292                             // Unbind the buffer.
293                             this.readOverlapped.CancelAsyncOperation();
294
295                             this.asyncReadCallback = null;
296                             this.asyncReadCallbackState = null;
297                             this.ReadTimer.Cancel();
298                         }
299                     }
300
301                     if (!this.isReadOutstanding)
302                     {
303                         int bytesRead;
304                         Exception readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
305                         if (readException != null)
306                         {
307                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(readException);
308                         }
309                         asyncBytesRead = bytesRead;
310                         HandleReadComplete(asyncBytesRead);
311                     }
312                     else
313                     {
314                         EnterReadingState();
315                     }
316
317                     return this.isReadOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
318                 }
319                 catch (PipeException e)
320                 {
321                     throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
322                 }
323             }
324         }
325
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)
329         {
330             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
331             FinishPendingWrite(timeout);
332
333             ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
334
335             if (autoBindToCompletionPort && !isBoundToCompletionPort)
336             {
337                 // Locks must be both taken, and in this order.
338                 lock (readLock)
339                 {
340                     lock (writeLock)
341                     {
342                         ValidateEnterWritingState(true);
343
344                         EnsureBoundToCompletionPort();
345                     }
346                 }
347             }
348
349             lock (writeLock)
350             {
351                 try
352                 {
353                     ValidateEnterWritingState(true);
354
355                     if (this.isWriteOutstanding)
356                     {
357                         throw Fx.AssertAndThrow("Write I/O already pending when BeginWrite called.");
358                     }
359
360                     try
361                     {
362                         this.writeTimeout = timeout;
363                         this.WriteTimer.Set(timeoutHelper.RemainingTime());
364
365                         this.asyncBytesToWrite = size;
366                         this.asyncWriteException = null;
367                         this.asyncWriteCallback = callback;
368                         this.asyncWriteCallbackState = state;
369
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)
373                         {
374                             int error = Marshal.GetLastWin32Error();
375                             if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
376                             {
377                                 this.isWriteOutstanding = false;
378                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
379                             }
380                         }
381                     }
382                     finally
383                     {
384                         if (!this.isWriteOutstanding)
385                         {
386                             // Unbind the buffer.
387                             this.writeOverlapped.CancelAsyncOperation();
388
389                             this.ResetWriteState();
390                             this.WriteTimer.Cancel();
391                         }
392                     }
393
394                     if (!this.isWriteOutstanding)
395                     {
396                         int bytesWritten;
397                         Exception writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
398                         if (writeException == null && bytesWritten != size)
399                         {
400                             writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
401                         }
402                         if (writeException != null)
403                         {
404                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(writeException);
405                         }
406                     }
407                     else
408                     {
409                         EnterWritingState();
410                     }
411
412                     return this.isWriteOutstanding ? AsyncCompletionResult.Queued : AsyncCompletionResult.Completed;
413                 }
414                 catch (PipeException e)
415                 {
416                     throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
417                 }
418             }
419         }
420
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)
424         {
425             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
426             FinishPendingWrite(timeout);
427
428             bool shouldCloseHandle = false;
429             try
430             {
431                 bool existingReadIsPending = false;
432                 bool shouldReadEOF = false;
433                 bool shouldWriteEOF = false;
434
435                 lock (readLock)
436                 {
437                     lock (writeLock)
438                     {
439                         if (!isShutdownWritten && inWritingState)
440                         {
441                             throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
442                                 new PipeException(SR.GetString(SR.PipeCantCloseWithPendingWrite)), ExceptionEventType);
443                         }
444
445                         if (closeState == CloseState.Closing || closeState == CloseState.HandleClosed)
446                         {
447                             // already closing or closed, so just return
448                             return;
449                         }
450
451                         closeState = CloseState.Closing;
452
453                         shouldCloseHandle = true;
454
455                         if (!isAtEOF)
456                         {
457                             if (inReadingState)
458                             {
459                                 existingReadIsPending = true;
460                             }
461                             else
462                             {
463                                 shouldReadEOF = true;
464                             }
465                         }
466
467                         if (!isShutdownWritten)
468                         {
469                             shouldWriteEOF = true;
470                             isShutdownWritten = true;
471                         }
472                     }
473                 }
474
475                 if (shouldWriteEOF)
476                 {
477                     StartWriteZero(timeoutHelper.RemainingTime());
478                 }
479
480                 if (shouldReadEOF)
481                 {
482                     StartReadZero();
483                 }
484
485                 // wait for shutdown write to complete
486                 try
487                 {
488                     WaitForWriteZero(timeoutHelper.RemainingTime(), true);
489                 }
490                 catch (TimeoutException e)
491                 {
492                     throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
493                         new TimeoutException(SR.GetString(SR.PipeShutdownWriteError), e), ExceptionEventType);
494                 }
495
496                 // ensure we have received EOF signal
497                 if (shouldReadEOF)
498                 {
499                     try
500                     {
501                         WaitForReadZero(timeoutHelper.RemainingTime(), true);
502                     }
503                     catch (TimeoutException e)
504                     {
505                         throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
506                             new TimeoutException(SR.GetString(SR.PipeShutdownReadError), e), ExceptionEventType);
507                     }
508                 }
509                 else if (existingReadIsPending)
510                 {
511                     if (!TimeoutHelper.WaitOne(atEOFEvent, timeoutHelper.RemainingTime()))
512                     {
513                         throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
514                             new TimeoutException(SR.GetString(SR.PipeShutdownReadError)), ExceptionEventType);
515                     }
516                 }
517                 // else we had already seen EOF.
518
519                 // at this point, we may get exceptions if the other side closes the handle first
520                 try
521                 {
522                     // write an ack for eof
523                     StartWriteZero(timeoutHelper.RemainingTime());
524
525                     // read an ack for eof
526                     StartReadZero();
527
528                     // wait for write to complete/fail
529                     WaitForWriteZero(timeoutHelper.RemainingTime(), false);
530
531                     // wait for read to complete/fail
532                     WaitForReadZero(timeoutHelper.RemainingTime(), false);
533                 }
534                 catch (PipeException e)
535                 {
536                     if (!IsBrokenPipeError(e.ErrorCode))
537                     {
538                         throw;
539                     }
540                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
541                 }
542                 catch (CommunicationException e)
543                 {
544                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
545                 }
546                 catch (TimeoutException e)
547                 {
548                     DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
549                 }
550             }
551             catch (TimeoutException e)
552             {
553                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
554                     new TimeoutException(SR.GetString(SR.PipeCloseFailed), e), ExceptionEventType);
555             }
556             catch (PipeException e)
557             {
558                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
559                     ConvertPipeException(SR.GetString(SR.PipeCloseFailed), e, TransferOperation.Undefined), ExceptionEventType);
560             }
561             finally
562             {
563                 if (shouldCloseHandle)
564                 {
565                     CloseHandle(false, null, TransferOperation.Undefined);
566                 }
567             }
568         }
569
570         void CloseHandle(bool abort, string timeoutErrorString, TransferOperation transferOperation)
571         {
572             lock (readLock)
573             {
574                 lock (writeLock)
575                 {
576                     if (this.closeState == CloseState.HandleClosed)
577                     {
578                         return;
579                     }
580
581                     this.timeoutErrorString = timeoutErrorString;
582                     this.timeoutErrorTransferOperation = transferOperation;
583                     this.aborted = abort;
584                     this.closeState = CloseState.HandleClosed;
585                     this.pipe.Close();
586                     this.readOverlapped.FreeOrDefer();
587                     this.writeOverlapped.FreeOrDefer();
588
589                     if (this.atEOFEvent != null)
590                     {
591                         this.atEOFEvent.Close();
592                     }
593
594                     // This should only do anything in the abort case.
595                     try
596                     {
597                         FinishPendingWrite(TimeSpan.Zero);
598                     }
599                     catch (TimeoutException exception)
600                     {
601                         if (TD.CloseTimeoutIsEnabled())
602                         {
603                             TD.CloseTimeout(exception.Message);
604                         }
605                         DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
606                     }
607                     catch (CommunicationException exception)
608                     {
609                         DiagnosticUtility.TraceHandledException(exception, TraceEventType.Information);
610                     }
611                 }
612             }
613
614             if (abort)
615             {
616                 TraceEventType traceEventType = TraceEventType.Warning;
617
618                 // we could be timing out a cached connection
619                 if (this.ExceptionEventType == TraceEventType.Information)
620                 {
621                     traceEventType = this.ExceptionEventType;
622                 }
623
624                 if (DiagnosticUtility.ShouldTrace(traceEventType))
625                 {
626                     TraceUtility.TraceEvent(traceEventType, TraceCode.PipeConnectionAbort, SR.GetString(SR.TraceCodePipeConnectionAbort), this);
627                 }
628             }
629         }
630
631         CommunicationException CreatePipeDuplicationFailedException(int win32Error)
632         {
633             Exception innerException = new PipeException(SR.GetString(SR.PipeDuplicationFailed), win32Error);
634             return new CommunicationException(innerException.Message, innerException);
635         }
636
637         public object DuplicateAndClose(int targetProcessId)
638         {
639             SafeCloseHandle targetProcessHandle = ListenerUnsafeNativeMethods.OpenProcess(ListenerUnsafeNativeMethods.PROCESS_DUP_HANDLE, false, targetProcessId);
640             if (targetProcessHandle.IsInvalid)
641             {
642                 targetProcessHandle.SetHandleAsInvalid();
643                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
644                     CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
645             }
646             try
647             {
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)
651                 {
652                     throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
653                         CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
654                 }
655                 IntPtr duplicatedHandle;
656                 bool success = UnsafeNativeMethods.DuplicateHandle(sourceProcessHandle, this.pipe, targetProcessHandle, out duplicatedHandle, 0, false, UnsafeNativeMethods.DUPLICATE_SAME_ACCESS);
657                 if (!success)
658                 {
659                     throw DiagnosticUtility.ExceptionUtility.ThrowHelper(
660                         CreatePipeDuplicationFailedException(Marshal.GetLastWin32Error()), ExceptionEventType);
661                 }
662                 this.Abort();
663                 return duplicatedHandle;
664             }
665             finally
666             {
667                 targetProcessHandle.Close();
668             }
669         }
670
671         public object GetCoreTransport()
672         {
673             return pipe;
674         }
675
676         void EnsureBoundToCompletionPort()
677         {
678             // Both read and write locks must be acquired before doing this
679             if (!isBoundToCompletionPort)
680             {
681                 ThreadPool.BindHandle(this.pipe);
682                 isBoundToCompletionPort = true;
683             }
684         }
685
686         public int EndRead()
687         {
688             if (asyncReadException != null)
689             {
690                 Exception exceptionToThrow = asyncReadException;
691                 asyncReadException = null;
692                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
693             }
694             return asyncBytesRead;
695         }
696
697         public void EndWrite()
698         {
699             if (this.asyncWriteException != null)
700             {
701                 Exception exceptionToThrow = this.asyncWriteException;
702                 this.asyncWriteException = null;
703                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exceptionToThrow, ExceptionEventType);
704             }
705         }
706
707         void EnterReadingState()
708         {
709             inReadingState = true;
710         }
711
712         void EnterWritingState()
713         {
714             inWritingState = true;
715         }
716
717         void ExitReadingState()
718         {
719             inReadingState = false;
720         }
721
722         void ExitWritingState()
723         {
724             inWritingState = false;
725         }
726
727         void ReadIOCompleted()
728         {
729             this.readOverlapped.FreeIfDeferred();
730         }
731
732         void WriteIOCompleted()
733         {
734             this.writeOverlapped.FreeIfDeferred();
735         }
736
737         void FinishPendingWrite(TimeSpan timeout)
738         {
739             if (this.pendingWriteBuffer == null)
740             {
741                 return;
742             }
743
744             byte[] buffer;
745             BufferManager bufferManager;
746             lock (this.writeLock)
747             {
748                 if (this.pendingWriteBuffer == null)
749                 {
750                     return;
751                 }
752
753                 buffer = this.pendingWriteBuffer;
754                 this.pendingWriteBuffer = null;
755
756                 bufferManager = this.pendingWriteBufferManager;
757                 this.pendingWriteBufferManager = null;
758             }
759
760             try
761             {
762                 bool success = false;
763                 try
764                 {
765                     WaitForSyncWrite(timeout, true);
766                     success = true;
767                 }
768                 finally
769                 {
770                     lock (this.writeLock)
771                     {
772                         try
773                         {
774                             if (success)
775                             {
776                                 FinishSyncWrite(true);
777                             }
778                         }
779                         finally
780                         {
781                             ExitWritingState();
782                             if (!this.isWriteOutstanding)
783                             {
784                                 bufferManager.ReturnBuffer(buffer);
785                                 WriteIOCompleted();
786                             }
787                         }
788                     }
789                 }
790             }
791             catch (PipeException e)
792             {
793                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
794             }
795         }
796
797 #if FUTURE
798         ulong GetServerPid()
799         {
800             ulong id;
801 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
802             if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
803             {
804                 Win32Exception e = new Win32Exception();
805                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
806             }
807             return id;
808         }
809
810         ulong GetClientPid()
811         {
812             ulong id;
813 #pragma warning suppress 56523 // Microsoft, Win32Exception ctor calls Marshal.GetLastWin32Error()
814             if (!UnsafeNativeMethods.GetNamedPipeServerProcessId(pipe, out id))
815             {
816                 Win32Exception e = new Win32Exception();
817                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(e.Message, e));
818             }
819             return id;
820         }
821 #endif
822
823         void HandleReadComplete(int bytesRead)
824         {
825             if (bytesRead == 0)
826             {
827                 isAtEOF = true;
828                 atEOFEvent.Set();
829             }
830         }
831
832         bool IsBrokenPipeError(int error)
833         {
834             return error == UnsafeNativeMethods.ERROR_NO_DATA ||
835                 error == UnsafeNativeMethods.ERROR_BROKEN_PIPE;
836         }
837
838         Exception CreatePipeClosedException(TransferOperation transferOperation)
839         {
840             return ConvertPipeException(new PipeException(SR.GetString(SR.PipeClosed)), transferOperation);
841         }
842
843         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
844         unsafe void OnAsyncReadComplete(bool haveResult, int error, int numBytes)
845         {
846             WaitCallback callback;
847             object state;
848
849             lock (readLock)
850             {
851                 try
852                 {
853                     try
854                     {
855                         if (this.readTimeout != TimeSpan.MaxValue && !this.ReadTimer.Cancel())
856                         {
857                             this.Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
858                         }
859
860                         if (this.closeState == CloseState.HandleClosed)
861                         {
862                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Read));
863                         }
864                         if (!haveResult)
865                         {
866                             if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.readOverlapped.NativeOverlapped, out numBytes, 0) == 0)
867                             {
868                                 error = Marshal.GetLastWin32Error();
869                             }
870                             else
871                             {
872                                 error = 0;
873                             }
874                         }
875
876                         if (error != 0 && error != UnsafeNativeMethods.ERROR_MORE_DATA)
877                         {
878                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException((int)error));
879                         }
880                         this.asyncBytesRead = numBytes;
881                         HandleReadComplete(this.asyncBytesRead);
882                     }
883                     catch (PipeException e)
884                     {
885                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(ConvertPipeException(e, TransferOperation.Read));
886                     }
887                 }
888 #pragma warning suppress 56500 // Microsoft, transferring exception to caller
889                 catch (Exception e)
890                 {
891                     if (Fx.IsFatal(e))
892                     {
893                         throw;
894                     }
895
896                     this.asyncReadException = e;
897                 }
898                 finally
899                 {
900                     this.isReadOutstanding = false;
901                     ReadIOCompleted();
902                     ExitReadingState();
903                     callback = this.asyncReadCallback;
904                     this.asyncReadCallback = null;
905                     state = this.asyncReadCallbackState;
906                     this.asyncReadCallbackState = null;
907                 }
908             }
909
910             callback(state);
911         }
912
913         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
914         unsafe void OnAsyncWriteComplete(bool haveResult, int error, int numBytes)
915         {
916             WaitCallback callback;
917             object state;
918
919             Exception writeException = null;
920
921             this.WriteTimer.Cancel();
922             lock (writeLock)
923             {
924                 try
925                 {
926                     try
927                     {
928                         if (this.closeState == CloseState.HandleClosed)
929                         {
930                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeClosedException(TransferOperation.Write));
931                         }
932                         if (!haveResult)
933                         {
934                             if (UnsafeNativeMethods.GetOverlappedResult(this.pipe.DangerousGetHandle(), this.writeOverlapped.NativeOverlapped, out numBytes, 0) == 0)
935                             {
936                                 error = Marshal.GetLastWin32Error();
937                             }
938                             else
939                             {
940                                 error = 0;
941                             }
942                         }
943
944                         if (error != 0)
945                         {
946                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
947                         }
948                         else if (numBytes != this.asyncBytesToWrite)
949                         {
950                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new PipeException(SR.GetString(SR.PipeWriteIncomplete)));
951                         }
952                     }
953                     catch (PipeException e)
954                     {
955                         throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
956                     }
957                 }
958 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
959                 catch (Exception e)
960                 {
961                     if (Fx.IsFatal(e))
962                     {
963                         throw;
964                     }
965
966                     writeException = e;
967                 }
968                 finally
969                 {
970                     this.isWriteOutstanding = false;
971                     WriteIOCompleted();
972                     ExitWritingState();
973                     this.asyncWriteException = writeException;
974                     callback = this.asyncWriteCallback;
975                     state = this.asyncWriteCallbackState;
976                     this.ResetWriteState();
977                 }
978             }
979
980             if (callback != null)
981             {
982                 callback(state);
983             }
984         }
985
986         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
987         unsafe public int Read(byte[] buffer, int offset, int size, TimeSpan timeout)
988         {
989             ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
990
991             try
992             {
993                 lock (readLock)
994                 {
995                     ValidateEnterReadingState(true);
996                     if (isAtEOF)
997                     {
998                         return 0;
999                     }
1000
1001                     StartSyncRead(buffer, offset, size);
1002                     EnterReadingState();
1003                 }
1004
1005                 int bytesRead = -1;
1006                 bool success = false;
1007                 try
1008                 {
1009                     WaitForSyncRead(timeout, true);
1010                     success = true;
1011                 }
1012                 finally
1013                 {
1014                     lock (this.readLock)
1015                     {
1016                         try
1017                         {
1018                             if (success)
1019                             {
1020                                 bytesRead = FinishSyncRead(true);
1021                                 HandleReadComplete(bytesRead);
1022                             }
1023                         }
1024                         finally
1025                         {
1026                             ExitReadingState();
1027                             if (!this.isReadOutstanding)
1028                             {
1029                                 ReadIOCompleted();
1030                             }
1031                         }
1032                     }
1033                 }
1034
1035                 Fx.Assert(bytesRead >= 0, "Logic error in Read - bytesRead not set.");
1036                 return bytesRead;
1037             }
1038             catch (PipeException e)
1039             {
1040                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Read), ExceptionEventType);
1041             }
1042         }
1043
1044         public void Shutdown(TimeSpan timeout)
1045         {
1046             try
1047             {
1048                 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1049                 FinishPendingWrite(timeoutHelper.RemainingTime());
1050
1051                 lock (writeLock)
1052                 {
1053                     ValidateEnterWritingState(true);
1054                     StartWriteZero(timeoutHelper.RemainingTime());
1055                     isShutdownWritten = true;
1056                 }
1057             }
1058             catch (PipeException e)
1059             {
1060                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Undefined), ExceptionEventType);
1061             }
1062         }
1063
1064         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1065         unsafe void StartReadZero()
1066         {
1067             lock (this.readLock)
1068             {
1069                 ValidateEnterReadingState(false);
1070                 StartSyncRead(ZeroBuffer, 0, 1);
1071                 EnterReadingState();
1072             }
1073         }
1074
1075         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1076         unsafe void StartWriteZero(TimeSpan timeout)
1077         {
1078             FinishPendingWrite(timeout);
1079
1080             lock (this.writeLock)
1081             {
1082                 ValidateEnterWritingState(false);
1083                 StartSyncWrite(ZeroBuffer, 0, 0);
1084                 EnterWritingState();
1085             }
1086         }
1087
1088         void ResetWriteState()
1089         {
1090             this.asyncBytesToWrite = -1;
1091             this.asyncWriteCallback = null;
1092             this.asyncWriteCallbackState = null;
1093         }
1094
1095         public IAsyncResult BeginValidate(Uri uri, AsyncCallback callback, object state)
1096         {
1097             return new CompletedAsyncResult<bool>(true, callback, state);
1098         }
1099
1100         public bool EndValidate(IAsyncResult result)
1101         {
1102             return CompletedAsyncResult<bool>.End(result);
1103         }
1104
1105         void WaitForReadZero(TimeSpan timeout, bool traceExceptionsAsErrors)
1106         {
1107             bool success = false;
1108             try
1109             {
1110                 WaitForSyncRead(timeout, traceExceptionsAsErrors);
1111                 success = true;
1112             }
1113             finally
1114             {
1115                 lock (this.readLock)
1116                 {
1117                     try
1118                     {
1119                         if (success)
1120                         {
1121                             if (FinishSyncRead(traceExceptionsAsErrors) != 0)
1122                             {
1123                                 Exception exception = ConvertPipeException(new PipeException(SR.GetString(SR.PipeSignalExpected)), TransferOperation.Read);
1124                                 TraceEventType traceEventType = TraceEventType.Information;
1125                                 if (traceExceptionsAsErrors)
1126                                 {
1127                                     traceEventType = TraceEventType.Error;
1128                                 }
1129                                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(exception, traceEventType);
1130                             }
1131                         }
1132                     }
1133                     finally
1134                     {
1135                         ExitReadingState();
1136                         if (!this.isReadOutstanding)
1137                         {
1138                             ReadIOCompleted();
1139                         }
1140                     }
1141                 }
1142             }
1143         }
1144
1145         void WaitForWriteZero(TimeSpan timeout, bool traceExceptionsAsErrors)
1146         {
1147             bool success = false;
1148             try
1149             {
1150                 WaitForSyncWrite(timeout, traceExceptionsAsErrors);
1151                 success = true;
1152             }
1153             finally
1154             {
1155                 lock (this.writeLock)
1156                 {
1157                     try
1158                     {
1159                         if (success)
1160                         {
1161                             FinishSyncWrite(traceExceptionsAsErrors);
1162                         }
1163                     }
1164                     finally
1165                     {
1166                         ExitWritingState();
1167                         if (!this.isWriteOutstanding)
1168                         {
1169                             WriteIOCompleted();
1170                         }
1171                     }
1172                 }
1173             }
1174         }
1175
1176         public void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout)
1177         {
1178             WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
1179         }
1180
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)
1184         {
1185             try
1186             {
1187                 FinishPendingWrite(timeout);
1188
1189                 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
1190
1191                 int bytesToWrite = size;
1192                 if (size > this.writeBufferSize)
1193                 {
1194                     size = this.writeBufferSize;
1195                 }
1196
1197                 while (bytesToWrite > 0)
1198                 {
1199                     lock (this.writeLock)
1200                     {
1201                         ValidateEnterWritingState(true);
1202
1203                         StartSyncWrite(buffer, offset, size, ref holder);
1204                         EnterWritingState();
1205                     }
1206
1207                     bool success = false;
1208                     try
1209                     {
1210                         WaitForSyncWrite(timeout, true, ref holder);
1211                         success = true;
1212                     }
1213                     finally
1214                     {
1215                         lock (this.writeLock)
1216                         {
1217                             try
1218                             {
1219                                 if (success)
1220                                 {
1221                                     FinishSyncWrite(true);
1222                                 }
1223                             }
1224                             finally
1225                             {
1226                                 ExitWritingState();
1227                                 if (!this.isWriteOutstanding)
1228                                 {
1229                                     WriteIOCompleted();
1230                                 }
1231                             }
1232                         }
1233                     }
1234
1235                     bytesToWrite -= size;
1236                     offset += size;
1237                     if (size > bytesToWrite)
1238                     {
1239                         size = bytesToWrite;
1240                     }
1241                 }
1242             }
1243             catch (PipeException e)
1244             {
1245                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
1246             }
1247         }
1248
1249         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1250         public unsafe void Write(byte[] buffer, int offset, int size, bool immediate, TimeSpan timeout, BufferManager bufferManager)
1251         {
1252             bool shouldReturnBuffer = true;
1253
1254             try
1255             {
1256                 if (size > this.writeBufferSize)
1257                 {
1258                     WriteHelper(buffer, offset, size, immediate, timeout, ref this.writeOverlapped.Holder[0]);
1259                     return;
1260                 }
1261
1262                 FinishPendingWrite(timeout);
1263
1264                 ConnectionUtilities.ValidateBufferBounds(buffer, offset, size);
1265
1266                 lock (this.writeLock)
1267                 {
1268                     ValidateEnterWritingState(true);
1269
1270                     // This method avoids the call to GetOverlappedResult for synchronous completions.  Perf?
1271                     bool success = false;
1272                     try
1273                     {
1274                         shouldReturnBuffer = false;
1275                         StartSyncWrite(buffer, offset, size);
1276                         success = true;
1277                     }
1278                     finally
1279                     {
1280                         if (!this.isWriteOutstanding)
1281                         {
1282                             shouldReturnBuffer = true;
1283                         }
1284                         else
1285                         {
1286                             if (success)
1287                             {
1288                                 EnterWritingState();
1289
1290                                 Fx.Assert(this.pendingWriteBuffer == null, "Need to pend a write but one's already pending.");
1291                                 this.pendingWriteBuffer = buffer;
1292                                 this.pendingWriteBufferManager = bufferManager;
1293                             }
1294                         }
1295                     }
1296                 }
1297             }
1298             catch (PipeException e)
1299             {
1300                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(ConvertPipeException(e, TransferOperation.Write), ExceptionEventType);
1301             }
1302             finally
1303             {
1304                 if (shouldReturnBuffer)
1305                 {
1306                     bufferManager.ReturnBuffer(buffer);
1307                 }
1308             }
1309         }
1310
1311         void ValidateEnterReadingState(bool checkEOF)
1312         {
1313             if (checkEOF)
1314             {
1315                 if (closeState == CloseState.Closing)
1316                 {
1317                     throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
1318                 }
1319             }
1320
1321             if (inReadingState)
1322             {
1323                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeReadPending)), ExceptionEventType);
1324             }
1325
1326             if (closeState == CloseState.HandleClosed)
1327             {
1328                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
1329             }
1330         }
1331
1332         void ValidateEnterWritingState(bool checkShutdown)
1333         {
1334             if (checkShutdown)
1335             {
1336                 if (isShutdownWritten)
1337                 {
1338                     throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyShuttingDown)), ExceptionEventType);
1339                 }
1340
1341                 if (closeState == CloseState.Closing)
1342                 {
1343                     throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeAlreadyClosing)), ExceptionEventType);
1344                 }
1345             }
1346
1347             if (inWritingState)
1348             {
1349                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeWritePending)), ExceptionEventType);
1350             }
1351
1352             if (closeState == CloseState.HandleClosed)
1353             {
1354                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(new PipeException(SR.GetString(SR.PipeClosed)), ExceptionEventType);
1355             }
1356         }
1357
1358         void StartSyncRead(byte[] buffer, int offset, int size)
1359         {
1360             StartSyncRead(buffer, offset, size, ref this.readOverlapped.Holder[0]);
1361         }
1362
1363         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1364         unsafe void StartSyncRead(byte[] buffer, int offset, int size, ref object holder)
1365         {
1366             if (this.isReadOutstanding)
1367             {
1368                 throw Fx.AssertAndThrow("StartSyncRead called when read I/O was already pending.");
1369             }
1370
1371             try
1372             {
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)
1376                 {
1377                     int error = Marshal.GetLastWin32Error();
1378                     if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
1379                     {
1380                         this.isReadOutstanding = false;
1381                         if (error != UnsafeNativeMethods.ERROR_MORE_DATA)
1382                         {
1383                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateReadException(error));
1384                         }
1385                     }
1386                 }
1387                 else
1388                 {
1389                     this.isReadOutstanding = false;
1390                 }
1391             }
1392             finally
1393             {
1394                 if (!this.isReadOutstanding)
1395                 {
1396                     this.readOverlapped.CancelSyncOperation(ref holder);
1397                 }
1398             }
1399         }
1400
1401         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1402         unsafe void WaitForSyncRead(TimeSpan timeout, bool traceExceptionsAsErrors)
1403         {
1404             if (this.isReadOutstanding)
1405             {
1406                 if (!this.readOverlapped.WaitForSyncOperation(timeout))
1407                 {
1408                     Abort(SR.GetString(SR.PipeConnectionAbortedReadTimedOut, this.readTimeout), TransferOperation.Read);
1409
1410                     Exception timeoutException = new TimeoutException(SR.GetString(SR.PipeReadTimedOut, timeout));
1411                     TraceEventType traceEventType = TraceEventType.Information;
1412                     if (traceExceptionsAsErrors)
1413                     {
1414                         traceEventType = TraceEventType.Error;
1415                     }
1416
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);
1419                 }
1420                 else
1421                 {
1422                     this.isReadOutstanding = false;
1423                 }
1424             }
1425         }
1426
1427         // Must be called in a lock.
1428         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1429         unsafe int FinishSyncRead(bool traceExceptionsAsErrors)
1430         {
1431             int bytesRead = -1;
1432             Exception readException;
1433
1434             if (this.closeState == CloseState.HandleClosed)
1435             {
1436                 readException = CreatePipeClosedException(TransferOperation.Read);
1437             }
1438             else
1439             {
1440                 readException = Exceptions.GetOverlappedReadException(this.pipe, this.readOverlapped.NativeOverlapped, out bytesRead);
1441             }
1442             if (readException != null)
1443             {
1444                 TraceEventType traceEventType = TraceEventType.Information;
1445                 if (traceExceptionsAsErrors)
1446                 {
1447                     traceEventType = TraceEventType.Error;
1448                 }
1449                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(readException, traceEventType);
1450             }
1451
1452             return bytesRead;
1453         }
1454
1455         void StartSyncWrite(byte[] buffer, int offset, int size)
1456         {
1457             StartSyncWrite(buffer, offset, size, ref this.writeOverlapped.Holder[0]);
1458         }
1459
1460         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1461         unsafe void StartSyncWrite(byte[] buffer, int offset, int size, ref object holder)
1462         {
1463             if (this.isWriteOutstanding)
1464             {
1465                 throw Fx.AssertAndThrow("StartSyncWrite called when write I/O was already pending.");
1466             }
1467
1468             try
1469             {
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)
1474                 {
1475                     int error = Marshal.GetLastWin32Error();
1476                     if (error != UnsafeNativeMethods.ERROR_IO_PENDING)
1477                     {
1478                         this.isWriteOutstanding = false;
1479                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exceptions.CreateWriteException(error));
1480                     }
1481                 }
1482                 else
1483                 {
1484                     this.isWriteOutstanding = false;
1485                 }
1486             }
1487             finally
1488             {
1489                 if (!this.isWriteOutstanding)
1490                 {
1491                     this.writeOverlapped.CancelSyncOperation(ref holder);
1492                 }
1493             }
1494         }
1495
1496         void WaitForSyncWrite(TimeSpan timeout, bool traceExceptionsAsErrors)
1497         {
1498             WaitForSyncWrite(timeout, traceExceptionsAsErrors, ref this.writeOverlapped.Holder[0]);
1499         }
1500
1501         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1502         unsafe void WaitForSyncWrite(TimeSpan timeout, bool traceExceptionsAsErrors, ref object holder)
1503         {
1504             if (this.isWriteOutstanding)
1505             {
1506                 if (!this.writeOverlapped.WaitForSyncOperation(timeout, ref holder))
1507                 {
1508                     Abort(SR.GetString(SR.PipeConnectionAbortedWriteTimedOut, this.writeTimeout), TransferOperation.Write);
1509
1510                     Exception timeoutException = new TimeoutException(SR.GetString(SR.PipeWriteTimedOut, timeout));
1511                     TraceEventType traceEventType = TraceEventType.Information;
1512                     if (traceExceptionsAsErrors)
1513                     {
1514                         traceEventType = TraceEventType.Error;
1515                     }
1516
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);
1519                 }
1520                 else
1521                 {
1522                     this.isWriteOutstanding = false;
1523                 }
1524             }
1525         }
1526
1527         // Must be called in a lock.
1528         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
1529         unsafe void FinishSyncWrite(bool traceExceptionsAsErrors)
1530         {
1531             int bytesWritten;
1532             Exception writeException;
1533
1534             if (this.closeState == CloseState.HandleClosed)
1535             {
1536                 writeException = CreatePipeClosedException(TransferOperation.Write);
1537             }
1538             else
1539             {
1540                 writeException = Exceptions.GetOverlappedWriteException(this.pipe, this.writeOverlapped.NativeOverlapped, out bytesWritten);
1541                 if (writeException == null && bytesWritten != this.syncWriteSize)
1542                 {
1543                     writeException = new PipeException(SR.GetString(SR.PipeWriteIncomplete));
1544                 }
1545             }
1546
1547             if (writeException != null)
1548             {
1549                 TraceEventType traceEventType = TraceEventType.Information;
1550                 if (traceExceptionsAsErrors)
1551                 {
1552                     traceEventType = TraceEventType.Error;
1553                 }
1554                 throw DiagnosticUtility.ExceptionUtility.ThrowHelper(writeException, traceEventType);
1555             }
1556         }
1557
1558         enum CloseState
1559         {
1560             Open,
1561             Closing,
1562             HandleClosed,
1563         }
1564
1565         enum TransferOperation
1566         {
1567             Write,
1568             Read,
1569             Undefined,
1570         }
1571
1572         static class Exceptions
1573         {
1574             static PipeException CreateException(string resourceString, int error)
1575             {
1576                 return new PipeException(SR.GetString(resourceString, PipeError.GetErrorString(error)), error);
1577             }
1578
1579             public static PipeException CreateReadException(int error)
1580             {
1581                 return CreateException(SR.PipeReadError, error);
1582             }
1583
1584             public static PipeException CreateWriteException(int error)
1585             {
1586                 return CreateException(SR.PipeWriteError, error);
1587             }
1588
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)
1593             {
1594                 if (UnsafeNativeMethods.GetOverlappedResult(pipe.DangerousGetHandle(), nativeOverlapped, out bytesWritten, 0) == 0)
1595                 {
1596                     int error = Marshal.GetLastWin32Error();
1597                     return Exceptions.CreateWriteException(error);
1598                 }
1599                 else
1600                 {
1601                     return null;
1602                 }
1603             }
1604
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)
1609             {
1610                 if (UnsafeNativeMethods.GetOverlappedResult(pipe.DangerousGetHandle(), nativeOverlapped, out bytesRead, 0) == 0)
1611                 {
1612                     int error = Marshal.GetLastWin32Error();
1613                     if (error == UnsafeNativeMethods.ERROR_MORE_DATA)
1614                     {
1615                         return null;
1616                     }
1617
1618                     else
1619                     {
1620                         return Exceptions.CreateReadException(error);
1621                     }
1622                 }
1623                 else
1624                 {
1625                     return null;
1626                 }
1627             }
1628         }
1629     }
1630
1631
1632     class PipeConnectionInitiator : IConnectionInitiator
1633     {
1634         int bufferSize;
1635         IPipeTransportFactorySettings pipeSettings;
1636
1637         public PipeConnectionInitiator(int bufferSize, IPipeTransportFactorySettings pipeSettings)
1638         {
1639             this.bufferSize = bufferSize;
1640             this.pipeSettings = pipeSettings;
1641         }
1642
1643         Exception CreateConnectFailedException(Uri remoteUri, PipeException innerException)
1644         {
1645             return new CommunicationException(
1646                 SR.GetString(SR.PipeConnectFailed, remoteUri.AbsoluteUri), innerException);
1647         }
1648
1649         public IConnection Connect(Uri remoteUri, TimeSpan timeout)
1650         {
1651             string resolvedAddress;
1652             BackoffTimeoutHelper backoffHelper;
1653             TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
1654             this.PrepareConnect(remoteUri, timeoutHelper.RemainingTime(), out resolvedAddress, out backoffHelper);
1655
1656             IConnection connection = null;
1657             while (connection == null)
1658             {
1659                 connection = this.TryConnect(remoteUri, resolvedAddress, backoffHelper);
1660                 if (connection == null)
1661                 {
1662                     backoffHelper.WaitAndBackoff();
1663
1664                     if (DiagnosticUtility.ShouldTraceInformation)
1665                     {
1666                         TraceUtility.TraceEvent(
1667                             TraceEventType.Information,
1668                             TraceCode.FailedPipeConnect,
1669                             SR.GetString(
1670                                 SR.TraceCodeFailedPipeConnect,
1671                                 timeoutHelper.RemainingTime(),
1672                                 remoteUri));
1673                     }
1674                 }
1675             }
1676             return connection;
1677         }
1678
1679         internal static string GetPipeName(Uri uri, IPipeTransportFactorySettings transportFactorySettings)
1680         {
1681             AppContainerInfo appInfo = GetAppContainerInfo(transportFactorySettings);
1682
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++)
1688             {
1689                 for (int iGlobal = 0; iGlobal < globalChoices.Length; iGlobal++)
1690                 {
1691
1692                     if (appInfo != null && globalChoices[iGlobal])
1693                     {
1694                         // Don't look at shared memory to acces pipes 
1695                         // that are created in the local NamedObjectPath
1696                         continue;
1697                     }
1698
1699                     // walk up the path hierarchy, looking for first match
1700                     string path = PipeUri.GetPath(uri);
1701
1702                     while (path.Length > 0)
1703                     {
1704
1705                         string sharedMemoryName = PipeUri.BuildSharedMemoryName(hostChoices[i], path, globalChoices[iGlobal], appInfo);
1706                         try
1707                         {
1708                             PipeSharedMemory sharedMemory = PipeSharedMemory.Open(sharedMemoryName, uri);
1709                             if (sharedMemory != null)
1710                             {
1711                                 try
1712                                 {
1713                                     string pipeName = sharedMemory.GetPipeName(appInfo);
1714                                     if (pipeName != null)
1715                                     {
1716                                         return pipeName;
1717                                     }
1718                                 }
1719                                 finally
1720                                 {
1721                                     sharedMemory.Dispose();
1722                                 }
1723                             }
1724                         }
1725                         catch (AddressAccessDeniedException exception)
1726                         {
1727                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new EndpointNotFoundException(SR.GetString(
1728                                 SR.EndpointNotFound, uri.AbsoluteUri), exception));
1729                         }
1730
1731                         path = PipeUri.GetParentPath(path);
1732                     }
1733                 }
1734             }
1735
1736             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1737                 new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, uri.AbsoluteUri),
1738                 new PipeException(SR.GetString(SR.PipeEndpointNotFound, uri.AbsoluteUri))));
1739         }
1740
1741         public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state)
1742         {
1743             return new ConnectAsyncResult(this, uri, timeout, callback, state);
1744         }
1745
1746         public IConnection EndConnect(IAsyncResult result)
1747         {
1748             return ConnectAsyncResult.End(result);
1749         }
1750
1751         void PrepareConnect(Uri remoteUri, TimeSpan timeout, out string resolvedAddress, out BackoffTimeoutHelper backoffHelper)
1752         {
1753             PipeUri.Validate(remoteUri);
1754             if (DiagnosticUtility.ShouldTraceInformation)
1755             {
1756                 TraceUtility.TraceEvent(System.Diagnostics.TraceEventType.Information, TraceCode.InitiatingNamedPipeConnection,
1757                     SR.GetString(SR.TraceCodeInitiatingNamedPipeConnection),
1758                     new StringTraceRecord("Uri", remoteUri.ToString()), this, null);
1759             }
1760             resolvedAddress = GetPipeName(remoteUri, this.pipeSettings);
1761
1762             const int backoffBufferMilliseconds = 150;
1763             TimeSpan backoffTimeout;
1764             if (timeout >= TimeSpan.FromMilliseconds(backoffBufferMilliseconds * 2))
1765             {
1766                 backoffTimeout = TimeoutHelper.Add(timeout, TimeSpan.Zero - TimeSpan.FromMilliseconds(backoffBufferMilliseconds));
1767             }
1768             else
1769             {
1770                 backoffTimeout = Ticks.ToTimeSpan((Ticks.FromMilliseconds(backoffBufferMilliseconds) / 2) + 1);
1771             }
1772
1773             backoffHelper = new BackoffTimeoutHelper(backoffTimeout, TimeSpan.FromMinutes(5));
1774         }
1775
1776         [ResourceConsumption(ResourceScope.Machine)]
1777         IConnection TryConnect(Uri remoteUri, string resolvedAddress, BackoffTimeoutHelper backoffHelper)
1778         {
1779             const int access = UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE;
1780             bool lastAttempt = backoffHelper.IsExpired();
1781
1782             int flags = UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
1783
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;
1787
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)
1792             {
1793                 pipeHandle.SetHandleAsInvalid();
1794             }
1795             else
1796             {
1797                 int mode = UnsafeNativeMethods.PIPE_READMODE_MESSAGE;
1798                 if (UnsafeNativeMethods.SetNamedPipeHandleState(pipeHandle, ref mode, IntPtr.Zero, IntPtr.Zero) == 0)
1799                 {
1800                     error = Marshal.GetLastWin32Error();
1801                     pipeHandle.Close();
1802                     PipeException innerException = new PipeException(SR.GetString(SR.PipeModeChangeFailed,
1803                         PipeError.GetErrorString(error)), error);
1804                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1805                         CreateConnectFailedException(remoteUri, innerException));
1806                 }
1807                 return new PipeConnection(pipeHandle, bufferSize, false, true);
1808             }
1809
1810             if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND || error == UnsafeNativeMethods.ERROR_PIPE_BUSY)
1811             {
1812                 if (lastAttempt)
1813                 {
1814                     Exception innerException = new PipeException(SR.GetString(SR.PipeConnectAddressFailed,
1815                         resolvedAddress, PipeError.GetErrorString(error)), error);
1816
1817                     TimeoutException timeoutException;
1818                     string endpoint = remoteUri.AbsoluteUri;
1819
1820                     if (error == UnsafeNativeMethods.ERROR_PIPE_BUSY)
1821                     {
1822                         timeoutException = new TimeoutException(SR.GetString(SR.PipeConnectTimedOutServerTooBusy,
1823                             endpoint, backoffHelper.OriginalTimeout), innerException);
1824                     }
1825                     else
1826                     {
1827                         timeoutException = new TimeoutException(SR.GetString(SR.PipeConnectTimedOut,
1828                             endpoint, backoffHelper.OriginalTimeout), innerException);
1829                     }
1830
1831                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(timeoutException);
1832                 }
1833
1834                 return null;
1835             }
1836             else
1837             {
1838                 PipeException innerException = new PipeException(SR.GetString(SR.PipeConnectAddressFailed,
1839                     resolvedAddress, PipeError.GetErrorString(error)), error);
1840                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1841                     CreateConnectFailedException(remoteUri, innerException));
1842             }
1843         }
1844
1845         static AppContainerInfo GetAppContainerInfo(IPipeTransportFactorySettings transportFactorySettings)
1846         {
1847             if (AppContainerInfo.IsAppContainerSupported &&
1848                 transportFactorySettings != null &&
1849                 transportFactorySettings.PipeSettings != null)
1850             {
1851                 ApplicationContainerSettings appSettings = transportFactorySettings.PipeSettings.ApplicationContainerSettings;
1852                 if (appSettings != null && appSettings.TargetingAppContainer)
1853                 {
1854                     return AppContainerInfo.CreateAppContainerInfo(appSettings.PackageFullName, appSettings.SessionId);
1855                 }
1856             }
1857
1858             return null;
1859         }
1860
1861         class ConnectAsyncResult : AsyncResult
1862         {
1863             PipeConnectionInitiator parent;
1864             Uri remoteUri;
1865             string resolvedAddress;
1866             BackoffTimeoutHelper backoffHelper;
1867             TimeoutHelper timeoutHelper;
1868             IConnection connection;
1869             static Action<object> waitCompleteCallback;
1870
1871             public ConnectAsyncResult(PipeConnectionInitiator parent, Uri remoteUri, TimeSpan timeout,
1872                 AsyncCallback callback, object state)
1873                 : base(callback, state)
1874             {
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);
1879
1880                 if (this.ConnectAndWait())
1881                 {
1882                     this.Complete(true);
1883                 }
1884             }
1885
1886             bool ConnectAndWait()
1887             {
1888                 this.connection = this.parent.TryConnect(this.remoteUri, this.resolvedAddress, this.backoffHelper);
1889                 bool completed = (this.connection != null);
1890                 if (!completed)
1891                 {
1892                     if (waitCompleteCallback == null)
1893                     {
1894                         waitCompleteCallback = new Action<object>(OnWaitComplete);
1895                     }
1896                     this.backoffHelper.WaitAndBackoff(waitCompleteCallback, this);
1897                 }
1898                 return completed;
1899             }
1900
1901             public static IConnection End(IAsyncResult result)
1902             {
1903                 ConnectAsyncResult thisPtr = AsyncResult.End<ConnectAsyncResult>(result);
1904                 return thisPtr.connection;
1905             }
1906
1907             static void OnWaitComplete(object state)
1908             {
1909                 Exception exception = null;
1910                 ConnectAsyncResult thisPtr = (ConnectAsyncResult)state;
1911
1912                 bool completeSelf = true;
1913                 try
1914                 {
1915                     if (DiagnosticUtility.ShouldTraceInformation)
1916                     {
1917                         TraceUtility.TraceEvent(
1918                             TraceEventType.Information,
1919                             TraceCode.FailedPipeConnect,
1920                             SR.GetString(
1921                                 SR.TraceCodeFailedPipeConnect,
1922                                 thisPtr.timeoutHelper.RemainingTime(),
1923                                 thisPtr.remoteUri));
1924                     }
1925
1926                     completeSelf = thisPtr.ConnectAndWait();
1927                 }
1928                 catch (Exception e)
1929                 {
1930                     if (Fx.IsFatal(e))
1931                     {
1932                         throw;
1933                     }
1934                     exception = e;
1935                 }
1936
1937                 if (completeSelf)
1938                 {
1939                     thisPtr.Complete(false, exception);
1940                 }
1941             }
1942         }
1943     }
1944
1945     class PipeConnectionListener : IConnectionListener
1946     {
1947         Uri pipeUri;
1948         int bufferSize;
1949         HostNameComparisonMode hostNameComparisonMode;
1950         bool isDisposed;
1951         bool isListening;
1952         List<PendingAccept> pendingAccepts;
1953         bool anyPipesCreated;
1954         PipeSharedMemory sharedMemory;
1955         List<SecurityIdentifier> allowedSids;
1956         bool useCompletionPort;
1957         int maxInstances;
1958
1959         public PipeConnectionListener(Uri pipeUri, HostNameComparisonMode hostNameComparisonMode, int bufferSize,
1960             List<SecurityIdentifier> allowedSids, bool useCompletionPort, int maxConnections)
1961         {
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);
1970         }
1971
1972         object ThisLock
1973         {
1974             get { return this; }
1975         }
1976
1977         public string PipeName { get { return sharedMemory.PipeName; } }
1978
1979         public IAsyncResult BeginAccept(AsyncCallback callback, object state)
1980         {
1981             lock (ThisLock)
1982             {
1983                 if (isDisposed)
1984                 {
1985                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ObjectDisposedException("", SR.GetString(SR.PipeListenerDisposed)));
1986                 }
1987
1988                 if (!isListening)
1989                 {
1990                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.PipeListenerNotListening)));
1991                 }
1992
1993                 PipeHandle pipeHandle = CreatePipe();
1994                 PendingAccept pendingAccept = new PendingAccept(this, pipeHandle, useCompletionPort, callback, state);
1995                 if (!pendingAccept.CompletedSynchronously)
1996                 {
1997                     this.pendingAccepts.Add(pendingAccept);
1998                 }
1999                 return pendingAccept;
2000             }
2001         }
2002
2003         public IConnection EndAccept(IAsyncResult result)
2004         {
2005             PendingAccept pendingAccept = result as PendingAccept;
2006             if (pendingAccept == null)
2007             {
2008                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("result", SR.GetString(SR.InvalidAsyncResult));
2009             }
2010
2011             PipeHandle acceptedPipe = pendingAccept.End();
2012
2013             if (acceptedPipe == null)
2014             {
2015                 return null;
2016             }
2017             else
2018             {
2019                 return new PipeConnection(acceptedPipe, bufferSize,
2020                     pendingAccept.IsBoundToCompletionPort, pendingAccept.IsBoundToCompletionPort);
2021             }
2022         }
2023
2024         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2025         [ResourceConsumption(ResourceScope.Machine)]
2026         unsafe PipeHandle CreatePipe()
2027         {
2028             int openMode = UnsafeNativeMethods.PIPE_ACCESS_DUPLEX | UnsafeNativeMethods.FILE_FLAG_OVERLAPPED;
2029             if (!anyPipesCreated)
2030             {
2031                 openMode |= UnsafeNativeMethods.FILE_FLAG_FIRST_PIPE_INSTANCE;
2032             }
2033
2034             byte[] binarySecurityDescriptor;
2035
2036             try
2037             {
2038                 binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE);
2039             }
2040             catch (Win32Exception e)
2041             {
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));
2045             }
2046
2047             PipeHandle pipeHandle;
2048             int error;
2049             string pipeName = null;
2050             fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
2051             {
2052                 UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
2053                 securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
2054
2055                 pipeName = this.sharedMemory.PipeName;
2056                 pipeHandle = UnsafeNativeMethods.CreateNamedPipe(
2057                                                     pipeName,
2058                                                     openMode,
2059                                                     UnsafeNativeMethods.PIPE_TYPE_MESSAGE | UnsafeNativeMethods.PIPE_READMODE_MESSAGE,
2060                                                     maxInstances, bufferSize, bufferSize, 0, securityAttributes);
2061                 error = Marshal.GetLastWin32Error();
2062             }
2063
2064             if (pipeHandle.IsInvalid)
2065             {
2066                 pipeHandle.SetHandleAsInvalid();
2067
2068                 Exception innerException = new PipeException(SR.GetString(SR.PipeListenFailed,
2069                     pipeUri.AbsoluteUri, PipeError.GetErrorString(error)), error);
2070
2071                 if (error == UnsafeNativeMethods.ERROR_ACCESS_DENIED)
2072                 {
2073                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAccessDeniedException(innerException.Message, innerException));
2074                 }
2075                 else if (error == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
2076                 {
2077                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new AddressAlreadyInUseException(innerException.Message, innerException));
2078                 }
2079                 else
2080                 {
2081                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(innerException.Message, innerException));
2082                 }
2083             }
2084             else
2085             {
2086                 if (TD.NamedPipeCreatedIsEnabled())
2087                 {
2088                     TD.NamedPipeCreated(pipeName);
2089                 }
2090             }
2091
2092             bool closePipe = true;
2093             try
2094             {
2095                 if (useCompletionPort)
2096                 {
2097                     ThreadPool.BindHandle(pipeHandle);
2098                 }
2099                 anyPipesCreated = true;
2100                 closePipe = false;
2101                 return pipeHandle;
2102             }
2103             finally
2104             {
2105                 if (closePipe)
2106                 {
2107                     pipeHandle.Close();
2108                 }
2109             }
2110         }
2111
2112         public void Dispose()
2113         {
2114             lock (ThisLock)
2115             {
2116                 if (!isDisposed)
2117                 {
2118                     if (sharedMemory != null)
2119                     {
2120                         sharedMemory.Dispose();
2121                     }
2122                     for (int i = 0; i < pendingAccepts.Count; i++)
2123                     {
2124                         pendingAccepts[i].Abort();
2125                     }
2126                     isDisposed = true;
2127                 }
2128             }
2129         }
2130
2131         public void Listen()
2132         {
2133             lock (ThisLock)
2134             {
2135                 if (!isListening)
2136                 {
2137                     string sharedMemoryName = PipeUri.BuildSharedMemoryName(pipeUri, hostNameComparisonMode, true);
2138                     if (!PipeSharedMemory.TryCreate(allowedSids, pipeUri, sharedMemoryName, out this.sharedMemory))
2139                     {
2140                         PipeSharedMemory tempSharedMemory = null;
2141
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))
2146                         {
2147                             // we're not RANU, throw PipeNameInUse
2148                             tempSharedMemory.Dispose();
2149                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
2150                                 PipeSharedMemory.CreatePipeNameInUseException(UnsafeNativeMethods.ERROR_ACCESS_DENIED, pipeUri));
2151                         }
2152                         else
2153                         {
2154                             // try the session namespace since we're RANU
2155                             sharedMemoryName = PipeUri.BuildSharedMemoryName(pipeUri, hostNameComparisonMode, false);
2156                             this.sharedMemory = PipeSharedMemory.Create(allowedSids, pipeUri, sharedMemoryName);
2157                         }
2158                     }
2159
2160                     isListening = true;
2161                 }
2162             }
2163         }
2164
2165         void RemovePendingAccept(PendingAccept pendingAccept)
2166         {
2167             lock (ThisLock)
2168             {
2169                 Fx.Assert(this.pendingAccepts.Contains(pendingAccept), "An unknown PendingAccept is removing itself.");
2170                 this.pendingAccepts.Remove(pendingAccept);
2171             }
2172         }
2173
2174         class PendingAccept : AsyncResult
2175         {
2176             PipeHandle pipeHandle;
2177             PipeHandle result;
2178             OverlappedIOCompleteCallback onAcceptComplete;
2179             static Action<object> onStartAccept;
2180             OverlappedContext overlapped;
2181             bool isBoundToCompletionPort;
2182             PipeConnectionListener listener;
2183             EventTraceActivity eventTraceActivity;
2184
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)
2189             {
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;
2196
2197                 if (TD.PipeConnectionAcceptStartIsEnabled())
2198                 {
2199                     this.eventTraceActivity = new EventTraceActivity();
2200                     TD.PipeConnectionAcceptStart(this.eventTraceActivity, this.listener.pipeUri != null ? this.listener.pipeUri.ToString() : string.Empty);
2201                 }
2202
2203                 if (!Thread.CurrentThread.IsThreadPoolThread)
2204                 {
2205                     if (onStartAccept == null)
2206                     {
2207                         onStartAccept = new Action<object>(OnStartAccept);
2208                     }
2209                     ActionItem.Schedule(onStartAccept, this);
2210                 }
2211                 else
2212                 {
2213                     StartAccept(true);
2214                 }
2215             }
2216
2217             public bool IsBoundToCompletionPort
2218             {
2219                 get { return this.isBoundToCompletionPort; }
2220             }
2221
2222             static void OnStartAccept(object state)
2223             {
2224                 PendingAccept pendingAccept = (PendingAccept)state;
2225                 pendingAccept.StartAccept(false);
2226             }
2227
2228             Exception CreatePipeAcceptFailedException(int errorCode)
2229             {
2230                 Exception innerException = new PipeException(SR.GetString(SR.PipeAcceptFailed,
2231                     PipeError.GetErrorString(errorCode)), errorCode);
2232                 return new CommunicationException(innerException.Message, innerException);
2233             }
2234
2235             [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2236             unsafe void StartAccept(bool synchronous)
2237             {
2238                 Exception completionException = null;
2239                 bool completeSelf = false;
2240                 try
2241                 {
2242                     try
2243                     {
2244                         this.overlapped.StartAsyncOperation(null, onAcceptComplete, this.isBoundToCompletionPort);
2245                         while (true)
2246                         {
2247                             if (UnsafeNativeMethods.ConnectNamedPipe(pipeHandle, overlapped.NativeOverlapped) == 0)
2248                             {
2249                                 int error = Marshal.GetLastWin32Error();
2250                                 switch (error)
2251                                 {
2252                                     case UnsafeNativeMethods.ERROR_NO_DATA:
2253                                         if (UnsafeNativeMethods.DisconnectNamedPipe(pipeHandle) != 0)
2254                                         {
2255                                             continue;
2256                                         }
2257                                         else
2258                                         {
2259                                             completeSelf = true;
2260                                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeAcceptFailedException(error));
2261                                         }
2262                                     case UnsafeNativeMethods.ERROR_PIPE_CONNECTED:
2263                                         completeSelf = true;
2264                                         break;
2265                                     case UnsafeNativeMethods.ERROR_IO_PENDING:
2266                                         break;
2267                                     default:
2268                                         completeSelf = true;
2269                                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeAcceptFailedException(error));
2270                                 }
2271                             }
2272                             else
2273                             {
2274                                 completeSelf = true;
2275                             }
2276
2277                             break;
2278                         }
2279                     }
2280                     catch (ObjectDisposedException exception)
2281                     {
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;
2286                     }
2287                     finally
2288                     {
2289                         if (completeSelf)
2290                         {
2291                             this.overlapped.CancelAsyncOperation();
2292                             this.overlapped.Free();
2293                         }
2294                     }
2295                 }
2296 #pragma warning suppress 56500 // Microsoft, transferring exception to another thread
2297                 catch (Exception e)
2298                 {
2299                     if (Fx.IsFatal(e))
2300                     {
2301                         throw;
2302                     }
2303
2304                     completeSelf = true;
2305                     completionException = e;
2306                 }
2307                 if (completeSelf)
2308                 {
2309                     if (!synchronous)
2310                     {
2311                         this.listener.RemovePendingAccept(this);
2312                     }
2313                     base.Complete(synchronous, completionException);
2314                 }
2315             }
2316
2317             // Must be called in PipeConnectionListener's lock.
2318             public void Abort()
2319             {
2320                 this.result = null; // we need to return null after an abort
2321                 pipeHandle.Close();
2322             }
2323
2324             public PipeHandle End()
2325             {
2326                 AsyncResult.End<PendingAccept>(this);
2327                 return this.result;
2328             }
2329
2330             [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2331             unsafe void OnAcceptComplete(bool haveResult, int error, int numBytes)
2332             {
2333                 this.listener.RemovePendingAccept(this);
2334
2335                 if (!haveResult)
2336                 {
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)
2340                     {
2341                         error = Marshal.GetLastWin32Error();
2342                     }
2343                     else
2344                     {
2345                         error = 0;
2346                     }
2347                 }
2348
2349                 this.overlapped.Free();
2350
2351                 if (TD.PipeConnectionAcceptStopIsEnabled())
2352                 {
2353                     TD.PipeConnectionAcceptStop(this.eventTraceActivity);
2354                 }
2355
2356                 if (error != 0)
2357                 {
2358                     this.pipeHandle.Close();
2359                     base.Complete(false, CreatePipeAcceptFailedException(error));
2360                 }
2361                 else
2362                 {
2363                     base.Complete(false);
2364                 }
2365             }
2366         }
2367     }
2368
2369     static class SecurityDescriptorHelper
2370     {
2371         static byte[] worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork;
2372         static byte[] worldCreatorOwnerWithReadDescriptorDenyNetwork;
2373
2374         static SecurityDescriptorHelper()
2375         {
2376             worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork = FromSecurityIdentifiersFull(null, UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE);
2377             worldCreatorOwnerWithReadDescriptorDenyNetwork = FromSecurityIdentifiersFull(null, UnsafeNativeMethods.GENERIC_READ);
2378         }
2379
2380         internal static byte[] FromSecurityIdentifiers(List<SecurityIdentifier> allowedSids, int accessRights)
2381         {
2382             if (allowedSids == null)
2383             {
2384                 if (accessRights == (UnsafeNativeMethods.GENERIC_READ | UnsafeNativeMethods.GENERIC_WRITE))
2385                 {
2386                     return worldCreatorOwnerWithReadAndWriteDescriptorDenyNetwork;
2387                 }
2388
2389                 if (accessRights == UnsafeNativeMethods.GENERIC_READ)
2390                 {
2391                     return worldCreatorOwnerWithReadDescriptorDenyNetwork;
2392                 }
2393             }
2394
2395             return FromSecurityIdentifiersFull(allowedSids, accessRights);
2396         }
2397
2398         static byte[] FromSecurityIdentifiersFull(List<SecurityIdentifier> allowedSids, int accessRights)
2399         {
2400             int capacity = allowedSids == null ? 3 : 2 + allowedSids.Count;
2401             DiscretionaryAcl dacl = new DiscretionaryAcl(false, false, capacity);
2402
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);
2406
2407             // clients get different rights, since they shouldn't be able to listen
2408             int clientAccessRights = GenerateClientAccessRights(accessRights);
2409
2410             if (allowedSids == null)
2411             {
2412                 dacl.AddAccess(AccessControlType.Allow, new SecurityIdentifier(WellKnownSidType.WorldSid, null),
2413                     clientAccessRights, InheritanceFlags.None, PropagationFlags.None);
2414             }
2415             else
2416             {
2417                 for (int i = 0; i < allowedSids.Count; i++)
2418                 {
2419                     SecurityIdentifier allowedSid = allowedSids[i];
2420                     dacl.AddAccess(AccessControlType.Allow, allowedSid,
2421                         clientAccessRights, InheritanceFlags.None, PropagationFlags.None);
2422                 }
2423             }
2424
2425             dacl.AddAccess(AccessControlType.Allow, GetProcessLogonSid(), accessRights, InheritanceFlags.None, PropagationFlags.None);
2426
2427
2428             if (AppContainerInfo.IsRunningInAppContainer)
2429             {
2430                 // NamedPipeBinding requires dacl with current AppContainer SID
2431                 // to setup multiple NamedPipes in the BeginAccept loop.                
2432                 dacl.AddAccess(
2433                             AccessControlType.Allow,
2434                             AppContainerInfo.GetCurrentAppContainerSid(),
2435                             accessRights,
2436                             InheritanceFlags.None,
2437                             PropagationFlags.None);
2438             }
2439
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;
2445         }
2446
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)
2450         {
2451             int everyoneAccessRights = accessRights;
2452
2453             if ((everyoneAccessRights & UnsafeNativeMethods.GENERIC_WRITE) != 0)
2454             {
2455                 everyoneAccessRights &= ~UnsafeNativeMethods.GENERIC_WRITE;
2456
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;
2460             }
2461
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;
2464
2465             return everyoneAccessRights;
2466         }
2467
2468         // The logon sid is generated on process start up so it is unique to this process.
2469         static SecurityIdentifier GetProcessLogonSid()
2470         {
2471             int pid = Process.GetCurrentProcess().Id;
2472             return System.ServiceModel.Activation.Utility.GetLogonSidForPid(pid);
2473         }
2474     }
2475
2476     unsafe class PipeSharedMemory : IDisposable
2477     {
2478         internal const string PipePrefix = @"\\.\pipe\";
2479         internal const string PipeLocalPrefix = @"\\.\pipe\Local\";
2480         SafeFileMappingHandle fileMapping;
2481         string pipeName;
2482         string pipeNameGuidPart;
2483         Uri pipeUri;
2484
2485         PipeSharedMemory(SafeFileMappingHandle fileMapping, Uri pipeUri)
2486             : this(fileMapping, pipeUri, null)
2487         {
2488         }
2489
2490         PipeSharedMemory(SafeFileMappingHandle fileMapping, Uri pipeUri, string pipeName)
2491         {
2492             this.pipeName = pipeName;
2493             this.fileMapping = fileMapping;
2494             this.pipeUri = pipeUri;
2495         }
2496
2497         public static PipeSharedMemory Create(List<SecurityIdentifier> allowedSids, Uri pipeUri, string sharedMemoryName)
2498         {
2499             PipeSharedMemory result;
2500             if (TryCreate(allowedSids, pipeUri, sharedMemoryName, out result))
2501             {
2502                 return result;
2503             }
2504             else
2505             {
2506                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameInUseException(UnsafeNativeMethods.ERROR_ACCESS_DENIED, pipeUri));
2507             }
2508         }
2509
2510         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2511         public unsafe static bool TryCreate(List<SecurityIdentifier> allowedSids, Uri pipeUri, string sharedMemoryName, out PipeSharedMemory result)
2512         {
2513             Guid pipeGuid = Guid.NewGuid();
2514             string pipeName = BuildPipeName(pipeGuid.ToString());
2515             byte[] binarySecurityDescriptor;
2516             try
2517             {
2518                 binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ);
2519             }
2520             catch (Win32Exception e)
2521             {
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));
2525             }
2526
2527             SafeFileMappingHandle fileMapping;
2528             int error;
2529             result = null;
2530             fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
2531             {
2532                 UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
2533                 securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
2534
2535                 fileMapping = UnsafeNativeMethods.CreateFileMapping((IntPtr)(-1), securityAttributes,
2536                     UnsafeNativeMethods.PAGE_READWRITE, 0, sizeof(SharedMemoryContents), sharedMemoryName);
2537                 error = Marshal.GetLastWin32Error();
2538             }
2539
2540             if (fileMapping.IsInvalid)
2541             {
2542                 fileMapping.SetHandleAsInvalid();
2543                 if (error == UnsafeNativeMethods.ERROR_ACCESS_DENIED)
2544                 {
2545                     return false;
2546                 }
2547                 else
2548                 {
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));
2552                 }
2553             }
2554
2555             // now we have a valid file mapping handle
2556             if (error == UnsafeNativeMethods.ERROR_ALREADY_EXISTS)
2557             {
2558                 fileMapping.Close();
2559                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameInUseException(error, pipeUri));
2560             }
2561             PipeSharedMemory pipeSharedMemory = new PipeSharedMemory(fileMapping, pipeUri, pipeName);
2562             bool disposeSharedMemory = true;
2563             try
2564             {
2565                 pipeSharedMemory.InitializeContents(pipeGuid);
2566                 disposeSharedMemory = false;
2567                 result = pipeSharedMemory;
2568
2569                 if (TD.PipeSharedMemoryCreatedIsEnabled())
2570                 {
2571                     TD.PipeSharedMemoryCreated(sharedMemoryName);
2572                 }
2573                 return true;
2574             }
2575             finally
2576             {
2577                 if (disposeSharedMemory)
2578                 {
2579                     pipeSharedMemory.Dispose();
2580                 }
2581             }
2582         }
2583
2584         [ResourceConsumption(ResourceScope.Machine)]
2585         public static PipeSharedMemory Open(string sharedMemoryName, Uri pipeUri)
2586         {
2587             SafeFileMappingHandle fileMapping = UnsafeNativeMethods.OpenFileMapping(
2588                 UnsafeNativeMethods.FILE_MAP_READ, false, sharedMemoryName);
2589             if (fileMapping.IsInvalid)
2590             {
2591                 int error = Marshal.GetLastWin32Error();
2592                 fileMapping.SetHandleAsInvalid();
2593                 if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
2594                 {
2595                     fileMapping = UnsafeNativeMethods.OpenFileMapping(
2596                         UnsafeNativeMethods.FILE_MAP_READ, false, "Global\\" + sharedMemoryName);
2597                     if (fileMapping.IsInvalid)
2598                     {
2599                         error = Marshal.GetLastWin32Error();
2600                         fileMapping.SetHandleAsInvalid();
2601                         if (error == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
2602                         {
2603                             return null;
2604                         }
2605                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2606                     }
2607                     return new PipeSharedMemory(fileMapping, pipeUri);
2608                 }
2609
2610                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2611             }
2612             return new PipeSharedMemory(fileMapping, pipeUri);
2613         }
2614
2615         public void Dispose()
2616         {
2617             if (fileMapping != null)
2618             {
2619                 fileMapping.Close();
2620                 fileMapping = null;
2621             }
2622         }
2623
2624         public string PipeName
2625         {
2626             [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2627             get
2628             {
2629                 if (pipeName == null)
2630                 {
2631                     SafeViewOfFileHandle view = GetView(false);
2632                     try
2633                     {
2634                         SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
2635                         if (contents->isInitialized)
2636                         {
2637                             Thread.MemoryBarrier();
2638                             this.pipeNameGuidPart = contents->pipeGuid.ToString();
2639                             this.pipeName = BuildPipeName(this.pipeNameGuidPart);
2640                         }
2641                     }
2642                     finally
2643                     {
2644                         view.Close();
2645                     }
2646                 }
2647                 return pipeName;
2648             }
2649         }
2650
2651         internal string GetPipeName(AppContainerInfo appInfo)
2652         {
2653             if (appInfo == null)
2654             {
2655                 return this.PipeName;
2656             }
2657             else if (this.PipeName != null)
2658             {
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}",
2664                             appInfo.SessionId,
2665                             appInfo.NamedObjectPath,
2666                             this.pipeNameGuidPart);
2667             }
2668
2669             return null;
2670         }
2671
2672         [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
2673         void InitializeContents(Guid pipeGuid)
2674         {
2675             SafeViewOfFileHandle view = GetView(true);
2676             try
2677             {
2678                 SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
2679                 contents->pipeGuid = pipeGuid;
2680                 Thread.MemoryBarrier();
2681                 contents->isInitialized = true;
2682             }
2683             finally
2684             {
2685                 view.Close();
2686             }
2687         }
2688
2689         public static Exception CreatePipeNameInUseException(int error, Uri pipeUri)
2690         {
2691             Exception innerException = new PipeException(SR.GetString(SR.PipeNameInUse, pipeUri.AbsoluteUri), error);
2692             return new AddressAlreadyInUseException(innerException.Message, innerException);
2693         }
2694
2695         static Exception CreatePipeNameCannotBeAccessedException(int error, Uri pipeUri)
2696         {
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);
2700         }
2701
2702         SafeViewOfFileHandle GetView(bool writable)
2703         {
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)
2708             {
2709                 int error = Marshal.GetLastWin32Error();
2710                 handle.SetHandleAsInvalid();
2711                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreatePipeNameCannotBeAccessedException(error, pipeUri));
2712             }
2713             return handle;
2714         }
2715
2716         static string BuildPipeName(string pipeGuid)
2717         {
2718             return (AppContainerInfo.IsRunningInAppContainer ? PipeLocalPrefix : PipePrefix) + pipeGuid;
2719         }
2720
2721         [StructLayout(LayoutKind.Sequential)]
2722         struct SharedMemoryContents
2723         {
2724             public bool isInitialized;
2725             public Guid pipeGuid;
2726         }
2727     }
2728
2729     static class PipeUri
2730     {
2731         public static string BuildSharedMemoryName(Uri uri, HostNameComparisonMode hostNameComparisonMode, bool global)
2732         {
2733             string path = PipeUri.GetPath(uri);
2734             string host = null;
2735
2736             switch (hostNameComparisonMode)
2737             {
2738                 case HostNameComparisonMode.StrongWildcard:
2739                     host = "+";
2740                     break;
2741                 case HostNameComparisonMode.Exact:
2742                     host = uri.Host;
2743                     break;
2744                 case HostNameComparisonMode.WeakWildcard:
2745                     host = "*";
2746                     break;
2747             }
2748
2749             return PipeUri.BuildSharedMemoryName(host, path, global);
2750         }
2751
2752         internal static string BuildSharedMemoryName(string hostName, string path, bool global, AppContainerInfo appContainerInfo)
2753         {
2754             if (appContainerInfo == null)
2755             {
2756                 return BuildSharedMemoryName(hostName, path, global);
2757             }
2758             else
2759             {
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.");
2763
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));
2772             }
2773         }
2774
2775         static string BuildSharedMemoryName(string hostName, string path, bool global)
2776         {
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();
2783
2784             byte[] canonicalBytes = Encoding.UTF8.GetBytes(canonicalName);
2785             byte[] hashedBytes;
2786             string separator;
2787
2788             if (canonicalBytes.Length >= 128)
2789             {
2790                 using (HashAlgorithm hash = GetHashAlgorithm())
2791                 {
2792                     hashedBytes = hash.ComputeHash(canonicalBytes);
2793                 }
2794                 separator = ":H";
2795             }
2796             else
2797             {
2798                 hashedBytes = canonicalBytes;
2799                 separator = ":E";
2800             }
2801
2802             builder = new StringBuilder();
2803             if (global)
2804             {
2805                 // we may need to create the shared memory in the global namespace so we work with terminal services+admin 
2806                 builder.Append("Global\\");
2807             }
2808             else
2809             {
2810                 builder.Append("Local\\");
2811             }
2812             builder.Append(Uri.UriSchemeNetPipe);
2813             builder.Append(separator);
2814             builder.Append(Convert.ToBase64String(hashedBytes));
2815             return builder.ToString();
2816         }
2817
2818         static HashAlgorithm GetHashAlgorithm()
2819         {
2820             if (SecurityUtilsEx.RequiresFipsCompliance)
2821                 return new SHA1CryptoServiceProvider();
2822             else
2823                 return new SHA1Managed();
2824         }
2825
2826         public static string GetPath(Uri uri)
2827         {
2828             string path = uri.LocalPath.ToUpperInvariant();
2829             if (!path.EndsWith("/", StringComparison.Ordinal))
2830                 path = path + "/";
2831             return path;
2832         }
2833
2834         public static string GetParentPath(string path)
2835         {
2836             if (path.EndsWith("/", StringComparison.Ordinal))
2837                 path = path.Substring(0, path.Length - 1);
2838             if (path.Length == 0)
2839                 return path;
2840             return path.Substring(0, path.LastIndexOf('/') + 1);
2841         }
2842
2843         public static void Validate(Uri uri)
2844         {
2845             if (uri.Scheme != Uri.UriSchemeNetPipe)
2846                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("uri", SR.GetString(SR.PipeUriSchemeWrong));
2847         }
2848     }
2849
2850     static class PipeError
2851     {
2852         public static string GetErrorString(int error)
2853         {
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)
2858             {
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));
2866             }
2867             else
2868             {
2869                 return SR.GetString(
2870                     SR.PipeUnknownWin32Error,
2871                     error.ToString(CultureInfo.InvariantCulture),
2872                     Convert.ToString(error, 16));
2873             }
2874         }
2875     }
2876 }