The Labs \ Source Viewer \ SSCLI \ System.Net \ SafeCloseSocketAndEvent

  1. //------------------------------------------------------------------------------
  2. // <copyright file="_SafeNetHandles.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. /*++ 
  16. Abstract:
  17.         The file contains _all_ SafeHandles implementations for System.Net namespace.
  18.         These handle wrappers do guarantee that OS resources get cleaned up when the app domain dies.
  19.         All PInvoke declarations that do freeing  the  OS resources  _must_ be in this file
  20.         All PInvoke declarations that do allocation the OS resources _must_ be in this file
  21. Details:
  22.         The protection from leaking OF the OS resources is based on two technologies
  23.         1) SafeHandle class
  24.         2) Non interuptible regions using Constrained Execution Region (CER) technology
  25.         For simple cases SafeHandle class does all the job. The Prerequisites are:
  26.         - A resource is able to be represented by IntPtr type (32 bits on 32 bits platforms).
  27.         - There is a PInvoke availble that does the creation of the resource.
  28.           That PInvoke either returns the handle value or it writes the handle into out/ref parameter.
  29.         - The above PInvoke as part of the call does NOT free any OS resource.
  30.         For those "simple" cases we desinged SafeHandle-derived classes that provide
  31.         static methods to allocate a handle object.
  32.         Each such derived class provides a handle release method that is run as non-interrupted.
  33.         For more complicated cases we employ the support for non-interruptible methods (CERs).
  34.         Each CER is a tree of code rooted at a catch or finally clause for a specially marked exception
  35.         handler (preceded by the RuntimeHelpers.PrepareConstrainedRegions() marker) or the Dispose or
  36.         ReleaseHandle method of a SafeHandle derived class. The graph is automatically computed by the
  37.         runtime (typically at the jit time of the root method), but cannot follow virtual or interface
  38.         calls (these must be explicitly prepared via RuntimeHelpers.PrepareMethod once the definite target
  39.         method is known). Also, methods in the graph that must be included in the CER must be marked with
  40.         a reliability contract stating guarantees about the consistency of the system if an error occurs
  41.         while they are executing. Look for ReliabilityContract for examples (a full explanation of the
  42.         semantics of this contract is beyond the scope of this comment).
  43.         An example of the top-level of a CER:
  44.             RuntimeHelpers.PrepareConstrainedRegions();
  45.             try
  46.             {
  47.                 // Normal code
  48.             }
  49.             finally
  50.             {
  51.                 // Guaranteed to get here even in low memory scenarios. Thread abort will not interrupt
  52.                 // this clause and we won't fail because of a jit allocation of any method called (modulo
  53.                 // restrictions on interface/virtual calls listed above and further restrictions listed
  54.                 // below).
  55.             }
  56.         Another common pattern is an empty-try (where you really just want a region of code the runtime
  57.         won't interrupt you in):
  58.             RuntimeHelpers.PrepareConstrainedRegions();
  59.             try {} finally
  60.             {
  61.                 // Non-interruptible code here
  62.             }
  63.         This ugly syntax will be supplanted with compiler support at some point.
  64.         While within a CER region certain restrictions apply in order to avoid having the runtime inject
  65.         a potential fault point into your code (and of course you're are responsible for ensuring your
  66.         code doesn't inject any explicit fault points of its own unless you know how to tolerate them).
  67.         A quick and dirty guide to the possible causes of fault points in CER regions:
  68.         - Explicit allocations (though allocating a value type only implies allocation on the stack,
  69.           which may not present an issue).
  70.         - Boxing a value type (C# does this implicitly for you in many cases, so be careful).
  71.         - Use of Monitor.Enter or the lock keyword.
  72.         - Accessing a multi-dimensional array.
  73.         - Calling any method outside your control that doesn't make a guarantee (e.g. via a
  74.           ReliabilityAttribute) that it doesn't introduce failure points.
  75.         - Making P/Invoke calls with non-blittable parameters types. Blittable types are:
  76.             - SafeHandle when used as an [in] parameter
  77.             - NON BOXED base types that fit onto a machine word
  78.             - ref struct with blittable fields
  79.             - class type with blittable fields
  80.             - pinned Unicode strings using "fixed" statement
  81.             - pointers of any kind
  82.             - IntPtr type
  83.         - P/Invokes should not have any CharSet attribute on it's declaration.
  84.           Obvioulsy string types should not appear in the parameters.
  85.         - String type MUST not appear in a field of a marshaled ref struct or class in a P?Invoke
  86. Author:
  87.     Alexei Vopilov    04-Sept-2002
  88. Revision History:
  89. --*/
  90. namespace System.Net
  91. {
  92.     using System.Net.Cache;
  93.     using System.Net.Sockets;
  94.     using System.Security;
  95.     using System.Runtime.InteropServices;
  96.     using System.Runtime.CompilerServices;
  97.     using System.Threading;
  98.     using System.Security.Permissions;
  99.     using System.ComponentModel;
  100.     using System.Text;
  101.     using System.Globalization;
  102.     using Microsoft.Win32.SafeHandles;
  103.     using System.Runtime.ConstrainedExecution;
  104.    
  105.     #if DEBUG
  106.     //
  107.     // This is a helper class for debugging GC-ed handles that we define.
  108.     // As a general rule normal code path should always destroy handles explicitly
  109.     //
  110.     internal abstract class DebugSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
  111.     {
  112.         string m_Trace;
  113.        
  114.         protected DebugSafeHandle(bool ownsHandle) : base(ownsHandle)
  115.         {
  116.             Trace();
  117.         }
  118.        
  119.         protected DebugSafeHandle(IntPtr invalidValue, bool ownsHandle) : base(ownsHandle)
  120.         {
  121.             SetHandle(invalidValue);
  122.             Trace();
  123.         }
  124.        
  125.         [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
  126.         private void Trace()
  127.         {
  128.             m_Trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n";
  129.         }
  130.        
  131.         [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
  132.         ~DebugSafeHandle()
  133.         {
  134.             GlobalLog.SetThreadSource(ThreadKinds.Finalization);
  135.             GlobalLog.Print(m_Trace);
  136.         }
  137.     }
  138.    
  139.     //
  140.     // This is a helper class for debugging GC-ed handles that we define.
  141.     // As a general rule normal code path should always destroy handles explicitly
  142.     //
  143.     internal abstract class DebugCriticalHandleMinusOneIsInvalid : CriticalHandleMinusOneIsInvalid
  144.     {
  145.         string m_Trace;
  146.        
  147.         protected DebugCriticalHandleMinusOneIsInvalid() : base()
  148.         {
  149.             Trace();
  150.         }
  151.        
  152.         [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
  153.         private void Trace()
  154.         {
  155.             m_Trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n";
  156.             GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName);
  157.         }
  158.        
  159.         ~DebugCriticalHandleMinusOneIsInvalid()
  160.         {
  161.             GlobalLog.SetThreadSource(ThreadKinds.Finalization);
  162.             GlobalLog.Print(m_Trace);
  163.         }
  164.     }
  165.    
  166.     //
  167.     // This is a helper class for debugging GC-ed handles that we define.
  168.     // As a general rule normal code path should always destroy handles explicitly
  169.     //
  170.     internal abstract class DebugSafeHandleMinusOneIsInvalid : SafeHandleMinusOneIsInvalid
  171.     {
  172.         string m_Trace;
  173.        
  174.         protected DebugSafeHandleMinusOneIsInvalid(bool ownsHandle) : base(ownsHandle)
  175.         {
  176.             Trace();
  177.         }
  178.        
  179.         [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
  180.         private void Trace()
  181.         {
  182.             m_Trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n";
  183.             GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName);
  184.         }
  185.        
  186.         ~DebugSafeHandleMinusOneIsInvalid()
  187.         {
  188.             GlobalLog.SetThreadSource(ThreadKinds.Finalization);
  189.             GlobalLog.Print(m_Trace);
  190.         }
  191.     }
  192.    
  193.     //
  194.     // This is a helper class for debugging GC-ed handles that we define.
  195.     // As a general rule normal code path should always destroy handles explicitly
  196.     //
  197.     internal abstract class DebugCriticalHandleZeroOrMinusOneIsInvalid : CriticalHandleZeroOrMinusOneIsInvalid
  198.     {
  199.         string m_Trace;
  200.        
  201.         protected DebugCriticalHandleZeroOrMinusOneIsInvalid() : base()
  202.         {
  203.             Trace();
  204.         }
  205.        
  206.         [EnvironmentPermission(SecurityAction.Assert, Unrestricted = true)]
  207.         private void Trace()
  208.         {
  209.             m_Trace = "WARNING! GC-ed >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n";
  210.             GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName);
  211.         }
  212.        
  213.         ~DebugCriticalHandleZeroOrMinusOneIsInvalid()
  214.         {
  215.             GlobalLog.SetThreadSource(ThreadKinds.Finalization);
  216.             GlobalLog.Print(m_Trace);
  217.         }
  218.     }
  219.     #endif // DEBUG
  220.    
  221.    
  222.    
  223.     ///////////////////////////////////////////////////////////////
  224.     //
  225.     // This is safe handle factory for any object that depends on
  226.     // KERNEL32 CloseHandle as the handle disposal method.
  227.     //
  228.     ///////////////////////////////////////////////////////////////
  229.     [SuppressUnmanagedCodeSecurity()]
  230.     #if DEBUG
  231.     internal sealed class SafeCloseHandle : DebugCriticalHandleZeroOrMinusOneIsInvalid
  232.     {
  233.         #else
  234.         internal sealed class SafeCloseHandle : CriticalHandleZeroOrMinusOneIsInvalid
  235.         {
  236.             #endif
  237.             private const string SECURITY = "security.dll";
  238.             private const string ADVAPI32 = "advapi32.dll";
  239.             private const string HTTPAPI = "httpapi.dll";
  240.            
  241.             private int _disposed;
  242.            
  243.             private SafeCloseHandle() : base()
  244.             {
  245.             }
  246.            
  247.             internal IntPtr DangerousGetHandle()
  248.             {
  249.                 return handle;
  250.             }
  251.            
  252.             protected override bool ReleaseHandle()
  253.             {
  254.                 if (!IsInvalid) {
  255.                     if (Interlocked.Increment(ref _disposed) == 1) {
  256.                         return UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(handle);
  257.                     }
  258.                 }
  259.                 return true;
  260.             }
  261.            
  262.            
  263.         }
  264.        
  265.        
  266.         ///////////////////////////////////////////////////////////////
  267.         //
  268.         // This is implementaion of Safe AllocHGlobal which is turned out
  269.         // to be LocalAlloc down in CLR
  270.         //
  271.         ///////////////////////////////////////////////////////////////
  272.         [SuppressUnmanagedCodeSecurity()]
  273.         #if DEBUG
  274.         internal sealed class SafeLocalFree : DebugSafeHandle
  275.         {
  276.             #else
  277.             internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid
  278.             {
  279.                 #endif
  280.                 private const int LMEM_FIXED = 0;
  281.                 private const int NULL = 0;
  282.                
  283.                 // This returned handle cannot be modified by the application.
  284.                 public static SafeLocalFree Zero = new SafeLocalFree(false);
  285.                
  286.                 private SafeLocalFree() : base(true)
  287.                 {
  288.                 }
  289.                
  290.                 private SafeLocalFree(bool ownsHandle) : base(ownsHandle)
  291.                 {
  292.                 }
  293.                
  294.                 public static SafeLocalFree LocalAlloc(int cb)
  295.                 {
  296.                     SafeLocalFree result = UnsafeNclNativeMethods.SafeNetHandles.LocalAlloc(LMEM_FIXED, (UIntPtr)cb);
  297.                     if (result.IsInvalid) {
  298.                         result.SetHandleAsInvalid();
  299.                         throw new OutOfMemoryException();
  300.                     }
  301.                     return result;
  302.                 }
  303.                
  304.                 protected override bool ReleaseHandle()
  305.                 {
  306.                     return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero;
  307.                 }
  308.             }
  309.            
  310.             ///////////////////////////////////////////////////////////////
  311.             //
  312.             // A few Win32 APIs return pointers to blobs that need GlobalFree().
  313.             //
  314.             ///////////////////////////////////////////////////////////////
  315.             [SuppressUnmanagedCodeSecurity()]
  316.             #if DEBUG
  317.             internal sealed class SafeGlobalFree : DebugSafeHandle
  318.             {
  319.                 #else
  320.                 internal sealed class SafeGlobalFree : SafeHandleZeroOrMinusOneIsInvalid
  321.                 {
  322.                     #endif
  323.                     private SafeGlobalFree() : base(true)
  324.                     {
  325.                     }
  326.                     private SafeGlobalFree(bool ownsHandle) : base(ownsHandle)
  327.                     {
  328.                     }
  329.                    
  330.                     protected override bool ReleaseHandle()
  331.                     {
  332.                         return UnsafeNclNativeMethods.SafeNetHandles.GlobalFree(handle) == IntPtr.Zero;
  333.                     }
  334.                 }
  335.                
  336.                 [ComVisible(false)]
  337.                 #if DEBUG
  338.                 internal sealed class SafeOverlappedFree : DebugSafeHandle
  339.                 {
  340.                     #else
  341.                     internal sealed class SafeOverlappedFree : SafeHandleZeroOrMinusOneIsInvalid
  342.                     {
  343.                         #endif
  344.                         private const int LPTR = 64;
  345.                        
  346.                         private SafeCloseSocket _socketHandle;
  347.                        
  348.                         private SafeOverlappedFree() : base(true)
  349.                         {
  350.                         }
  351.                         private SafeOverlappedFree(bool ownsHandle) : base(ownsHandle)
  352.                         {
  353.                         }
  354.                        
  355.                         public static SafeOverlappedFree Alloc()
  356.                         {
  357.                             SafeOverlappedFree result = UnsafeNclNativeMethods.SafeNetHandlesSafeOverlappedFree.LocalAlloc(LPTR, (UIntPtr)Win32.OverlappedSize);
  358.                             if (result.IsInvalid) {
  359.                                 result.SetHandleAsInvalid();
  360.                                 throw new OutOfMemoryException();
  361.                             }
  362.                             return result;
  363.                         }
  364.                        
  365.                         public static SafeOverlappedFree Alloc(SafeCloseSocket socketHandle)
  366.                         {
  367.                             SafeOverlappedFree result = Alloc();
  368.                             result._socketHandle = socketHandle;
  369.                             return result;
  370.                         }
  371.                        
  372.                         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  373.                         public void Close(bool resetOwner)
  374.                         {
  375.                             RuntimeHelpers.PrepareConstrainedRegions();
  376.                             try {
  377.                             }
  378.                             finally {
  379.                                 if (resetOwner) {
  380.                                     _socketHandle = null;
  381.                                 }
  382.                                 Close();
  383.                             }
  384.                         }
  385.                        
  386.                         unsafe protected override bool ReleaseHandle()
  387.                         {
  388.                             SafeCloseSocket socketHandle = _socketHandle;
  389.                             if (socketHandle != null && !socketHandle.IsInvalid) {
  390.                                 // We are being finalized while the I/O operation associated
  391.                                 // with the current overlapped is still pending (e.g. on app
  392.                                 // domain shutdown). The socket has to be closed first to
  393.                                 // avoid reuse after delete of the native overlapped structure.
  394.                                 socketHandle.Dispose();
  395.                             }
  396.                             // Release the native overlapped structure
  397.                             return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero;
  398.                         }
  399.                     }
  400.                    
  401.                    
  402.                    
  403.                     ///////////////////////////////////////////////////////////////
  404.                     //
  405.                     // This class implements a safe socket handle.
  406.                     // It uses an inner and outer SafeHandle to do so. The inner
  407.                     // SafeHandle holds the actual socket, but only ever has one
  408.                     // reference to it. The outer SafeHandle guards the inner
  409.                     // SafeHandle with real ref counting. When the outer SafeHandle
  410.                     // is cleaned up, it releases the inner SafeHandle - since
  411.                     // its ref is the only ref to the inner SafeHandle, it deterministically
  412.                     // gets closed at that point - no races with concurrent IO calls.
  413.                     // This allows Close() on the outer SafeHandle to deterministically
  414.                     // close the inner SafeHandle, in turn allowing the inner SafeHandle
  415.                     // to block the user thread in case a graceful close has been
  416.                     // requested. (It's not legal to block any other thread - such closes
  417.                     // are always abortive.)
  418.                     //
  419.                     ///////////////////////////////////////////////////////////////
  420.                     [SuppressUnmanagedCodeSecurity()]
  421.                     #if DEBUG
  422.                     internal class SafeCloseSocket : DebugSafeHandleMinusOneIsInvalid
  423.                     {
  424.                         #else
  425.                         internal class SafeCloseSocket : SafeHandleMinusOneIsInvalid
  426.                         {
  427.                             #endif
  428.                             protected SafeCloseSocket() : base(true)
  429.                             {
  430.                             }
  431.                            
  432.                             private InnerSafeCloseSocket m_InnerSocket;
  433.                             private volatile bool m_Released;
  434.                             #if DEBUG
  435.                             private InnerSafeCloseSocket m_InnerSocketCopy;
  436.                             #endif
  437.                            
  438.                             public override bool IsInvalid {
  439.                                 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  440.                                 get { return IsClosed || base.IsInvalid; }
  441.                             }
  442.                            
  443.                             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  444.                             private void SetInnerSocket(InnerSafeCloseSocket socket)
  445.                             {
  446.                                 m_InnerSocket = socket;
  447.                                 SetHandle(socket.DangerousGetHandle());
  448.                                 #if DEBUG
  449.                                 m_InnerSocketCopy = socket;
  450.                                 #endif
  451.                             }
  452.                            
  453.                             private static SafeCloseSocket CreateSocket(InnerSafeCloseSocket socket)
  454.                             {
  455.                                 SafeCloseSocket ret = new SafeCloseSocket();
  456.                                 CreateSocket(socket, ret);
  457.                                 return ret;
  458.                             }
  459.                            
  460.                             protected static void CreateSocket(InnerSafeCloseSocket socket, SafeCloseSocket target)
  461.                             {
  462.                                 if (socket != null && socket.IsInvalid) {
  463.                                     target.SetHandleAsInvalid();
  464.                                     return;
  465.                                 }
  466.                                
  467.                                 bool b = false;
  468.                                 RuntimeHelpers.PrepareConstrainedRegions();
  469.                                 try {
  470.                                     socket.DangerousAddRef(ref b);
  471.                                 }
  472.                                 catch {
  473.                                     if (b) {
  474.                                         socket.DangerousRelease();
  475.                                         b = false;
  476.                                     }
  477.                                 }
  478.                                 finally {
  479.                                     if (b) {
  480.                                         target.SetInnerSocket(socket);
  481.                                         socket.Close();
  482.                                     }
  483.                                     else {
  484.                                         target.SetHandleAsInvalid();
  485.                                     }
  486.                                 }
  487.                             }
  488.                            
  489.                             unsafe static internal SafeCloseSocket CreateWSASocket(byte* pinnedBuffer)
  490.                             {
  491.                                 return CreateSocket(InnerSafeCloseSocket.CreateWSASocket(pinnedBuffer));
  492.                             }
  493.                            
  494.                             static internal SafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
  495.                             {
  496.                                 return CreateSocket(InnerSafeCloseSocket.CreateWSASocket(addressFamily, socketType, protocolType));
  497.                             }
  498.                            
  499.                             static internal SafeCloseSocket Accept(SafeCloseSocket socketHandle, byte[] socketAddress, ref int socketAddressSize)
  500.                             {
  501.                                 return CreateSocket(InnerSafeCloseSocket.Accept(socketHandle, socketAddress, ref socketAddressSize));
  502.                             }
  503.                            
  504.                             protected override bool ReleaseHandle()
  505.                             {
  506.                                 m_Released = true;
  507.                                 InnerSafeCloseSocket innerSocket = m_InnerSocket == null ? null : Interlocked.Exchange<InnerSafeCloseSocket>(ref m_InnerSocket, null);
  508.                                 if (innerSocket != null) {
  509.                                     innerSocket.DangerousRelease();
  510.                                 }
  511.                                 return true;
  512.                             }
  513.                            
  514.                             internal void CloseAsIs()
  515.                             {
  516.                                 RuntimeHelpers.PrepareConstrainedRegions();
  517.                                 try {
  518.                                 }
  519.                                 finally {
  520.                                     #if DEBUG
  521.                                     // If this throws it could be very bad.
  522.                                     try {
  523.                                         #endif
  524.                                         InnerSafeCloseSocket innerSocket = m_InnerSocket == null ? null : Interlocked.Exchange<InnerSafeCloseSocket>(ref m_InnerSocket, null);
  525.                                         Close();
  526.                                         if (innerSocket != null) {
  527.                                             // Wait until it's safe.
  528.                                             while (!m_Released) {
  529.                                                 Thread.SpinWait(1);
  530.                                             }
  531.                                            
  532.                                             // Now free it with blocking.
  533.                                             innerSocket.BlockingRelease();
  534.                                         }
  535.                                         #if DEBUG
  536.                                     }
  537.                                     catch (Exception exception) {
  538.                                         if (!NclUtilities.IsFatal(exception)) {
  539.                                             GlobalLog.Assert("SafeCloseSocket::CloseAsIs(handle:" + handle.ToString("x") + ")", exception.Message);
  540.                                         }
  541.                                         throw;
  542.                                     }
  543.                                     #endif
  544.                                 }
  545.                             }
  546.                            
  547.                             internal class InnerSafeCloseSocket : SafeHandleMinusOneIsInvalid
  548.                             {
  549.                                 protected InnerSafeCloseSocket() : base(true)
  550.                                 {
  551.                                 }
  552.                                
  553.                                 private static readonly byte[] tempBuffer = new byte[1];
  554.                                 private bool m_Blockable;
  555.                                
  556.                                 public override bool IsInvalid {
  557.                                     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  558.                                     get { return IsClosed || base.IsInvalid; }
  559.                                 }
  560.                                
  561.                                 // This method is implicitly reliable and called from a CER.
  562.                                 protected override bool ReleaseHandle()
  563.                                 {
  564.                                     bool ret = false;
  565.                                    
  566.                                     #if DEBUG
  567.                                     try {
  568.                                         #endif
  569.                                         GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ")");
  570.                                        
  571.                                         SocketError errorCode;
  572.                                        
  573.                                         // If m_Blockable was set in BlockingRelease, it's safe to block here, which means
  574.                                         // we can honor the linger options set on the socket. It also means closesocket() might return WSAEWOULDBLOCK, in which
  575.                                         // case we need to do some recovery.
  576.                                         if (m_Blockable) {
  577.                                             GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") Following 'blockable' branch.");
  578.                                            
  579.                                             errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle);
  580.                                             #if DEBUG
  581.                                             m_CloseSocketHandle = handle;
  582.                                             m_CloseSocketResult = errorCode;
  583.                                             #endif
  584.                                             if (errorCode == SocketError.SocketError)
  585.                                                 errorCode = (SocketError)Marshal.GetLastWin32Error();
  586.                                             GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket()#1:" + errorCode.ToString());
  587.                                            
  588.                                             // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed.
  589.                                             if (errorCode != SocketError.WouldBlock) {
  590.                                                 return ret = errorCode == SocketError.Success;
  591.                                             }
  592.                                            
  593.                                             // The socket must be non-blocking with a linger timeout set.
  594.                                             // We have to set the socket to blocking.
  595.                                             int nonBlockCmd = 0;
  596.                                             errorCode = UnsafeNclNativeMethods.SafeNetHandles.ioctlsocket(handle, IoctlSocketConstants.FIONBIO, ref nonBlockCmd);
  597.                                             if (errorCode == SocketError.SocketError)
  598.                                                 errorCode = (SocketError)Marshal.GetLastWin32Error();
  599.                                             GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket()#1:" + errorCode.ToString());
  600.                                            
  601.                                             // This can fail if there's a pending WSAEventSelect. Try canceling it.
  602.                                             if (errorCode == SocketError.InvalidArgument) {
  603.                                                 errorCode = UnsafeNclNativeMethods.SafeNetHandles.WSAEventSelect(handle, IntPtr.Zero, AsyncEventBits.FdNone);
  604.                                                 GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") WSAEventSelect():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString());
  605.                                                
  606.                                                 // Now retry the ioctl.
  607.                                                 errorCode = UnsafeNclNativeMethods.SafeNetHandles.ioctlsocket(handle, IoctlSocketConstants.FIONBIO, ref nonBlockCmd);
  608.                                                 GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket#2():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString());
  609.                                             }
  610.                                            
  611.                                             // If that succeeded, try again.
  612.                                             if (errorCode == SocketError.Success) {
  613.                                                 errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle);
  614.                                                 #if DEBUG
  615.                                                 m_CloseSocketHandle = handle;
  616.                                                 m_CloseSocketResult = errorCode;
  617.                                                 #endif
  618.                                                 if (errorCode == SocketError.SocketError)
  619.                                                     errorCode = (SocketError)Marshal.GetLastWin32Error();
  620.                                                 GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#2():" + errorCode.ToString());
  621.                                                
  622.                                                 // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed.
  623.                                                 if (errorCode != SocketError.WouldBlock) {
  624.                                                     return ret = errorCode == SocketError.Success;
  625.                                                 }
  626.                                             }
  627.                                            
  628.                                             // It failed. Fall through to the regular abortive close.
  629.                                         }
  630.                                        
  631.                                         // By default or if CloseAsIs() path failed, set linger timeout to zero to get an abortive close (RST).
  632.                                         Linger lingerStruct;
  633.                                         lingerStruct.OnOff = 1;
  634.                                         lingerStruct.Time = (short)0;
  635.                                        
  636.                                         errorCode = UnsafeNclNativeMethods.SafeNetHandles.setsockopt(handle, SocketOptionLevel.Socket, SocketOptionName.Linger, ref lingerStruct, Linger.Size);
  637.                                         #if DEBUG
  638.                                         m_CloseSocketLinger = errorCode;
  639.                                         #endif
  640.                                         if (errorCode == SocketError.SocketError)
  641.                                             errorCode = (SocketError)Marshal.GetLastWin32Error();
  642.                                         GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") setsockopt():" + errorCode.ToString());
  643.                                        
  644.                                         if (errorCode != SocketError.Success && errorCode != SocketError.InvalidArgument && errorCode != SocketError.ProtocolOption) {
  645.                                             // Too dangerous to try closesocket() - it might block!
  646.                                             return ret = false;
  647.                                         }
  648.                                        
  649.                                         errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle);
  650.                                         #if DEBUG
  651.                                         m_CloseSocketHandle = handle;
  652.                                         m_CloseSocketResult = errorCode;
  653.                                         #endif
  654.                                         GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#3():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString());
  655.                                        
  656.                                         return ret = errorCode == SocketError.Success;
  657.                                         #if DEBUG
  658.                                     }
  659.                                     catch (Exception exception) {
  660.                                         if (!NclUtilities.IsFatal(exception)) {
  661.                                             GlobalLog.Assert("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ")", exception.Message);
  662.                                         }
  663.                                         ret = true;
  664.                                         // Avoid a second assert.
  665.                                         throw;
  666.                                     }
  667.                                     finally {
  668.                                         m_CloseSocketThread = Thread.CurrentThread.ManagedThreadId;
  669.                                         m_CloseSocketTick = Environment.TickCount;
  670.                                         GlobalLog.Assert(ret, "SafeCloseSocket::ReleaseHandle(handle:{0:x})|ReleaseHandle failed.", handle);
  671.                                     }
  672.                                     #endif
  673.                                 }
  674.                                
  675.                                 #if DEBUG
  676.                                 private IntPtr m_CloseSocketHandle;
  677.                                 private SocketError m_CloseSocketResult = unchecked((SocketError)3735928559u);
  678.                                 private SocketError m_CloseSocketLinger = unchecked((SocketError)3735928559u);
  679.                                 private int m_CloseSocketThread;
  680.                                 private int m_CloseSocketTick;
  681.                                 #endif
  682.                                
  683.                                 // Use this method to close the socket handle using the linger options specified on the socket.
  684.                                 // Guaranteed to only be called once, under a CER, and not if regular DangerousRelease is called.
  685.                                 [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  686.                                 internal void BlockingRelease()
  687.                                 {
  688.                                     m_Blockable = true;
  689.                                     DangerousRelease();
  690.                                 }
  691.                                
  692.                                 unsafe static internal InnerSafeCloseSocket CreateWSASocket(byte* pinnedBuffer)
  693.                                 {
  694.                                     //-1 is the value for FROM_PROTOCOL_INFO
  695.                                     InnerSafeCloseSocket result = UnsafeNclNativeMethods.OSSOCK.WSASocket((AddressFamily)(-1), (SocketType)(-1), (ProtocolType)(-1), pinnedBuffer, 0, SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
  696.                                     if (result.IsInvalid) {
  697.                                         result.SetHandleAsInvalid();
  698.                                     }
  699.                                     return result;
  700.                                 }
  701.                                
  702.                                 static internal InnerSafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
  703.                                 {
  704.                                     InnerSafeCloseSocket result = UnsafeNclNativeMethods.OSSOCK.WSASocket(addressFamily, socketType, protocolType, IntPtr.Zero, 0, SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
  705.                                     if (result.IsInvalid) {
  706.                                         result.SetHandleAsInvalid();
  707.                                     }
  708.                                     return result;
  709.                                 }
  710.                                
  711.                                 static internal InnerSafeCloseSocket Accept(SafeCloseSocket socketHandle, byte[] socketAddress, ref int socketAddressSize)
  712.                                 {
  713.                                     InnerSafeCloseSocket result = UnsafeNclNativeMethods.SafeNetHandles.accept(socketHandle.DangerousGetHandle(), socketAddress, ref socketAddressSize);
  714.                                     if (result.IsInvalid) {
  715.                                         result.SetHandleAsInvalid();
  716.                                     }
  717.                                     return result;
  718.                                 }
  719.                             }
  720.                         }
  721.                        
  722.                        
  723.                         [SuppressUnmanagedCodeSecurity()]
  724.                         internal sealed class SafeCloseSocketAndEvent : SafeCloseSocket
  725.                         {
  726.                             internal SafeCloseSocketAndEvent() : base()
  727.                             {
  728.                             }
  729.                             private AutoResetEvent waitHandle;
  730.                            
  731.                             protected override bool ReleaseHandle()
  732.                             {
  733.                                 bool result = base.ReleaseHandle();
  734.                                 DeleteEvent();
  735.                                 return result;
  736.                             }
  737.                            
  738.                             static internal SafeCloseSocketAndEvent CreateWSASocketWithEvent(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, bool autoReset, bool signaled)
  739.                             {
  740.                                 SafeCloseSocketAndEvent result = new SafeCloseSocketAndEvent();
  741.                                 CreateSocket(InnerSafeCloseSocket.CreateWSASocket(addressFamily, socketType, protocolType), result);
  742.                                 if (result.IsInvalid) {
  743.                                     throw new SocketException();
  744.                                 }
  745.                                
  746.                                 result.waitHandle = new AutoResetEvent(false);
  747.                                 CompleteInitialization(result);
  748.                                 return result;
  749.                             }
  750.                            
  751.                             static internal void CompleteInitialization(SafeCloseSocketAndEvent socketAndEventHandle)
  752.                             {
  753.                                 SafeWaitHandle handle = socketAndEventHandle.waitHandle.SafeWaitHandle;
  754.                                 bool b = false;
  755.                                 RuntimeHelpers.PrepareConstrainedRegions();
  756.                                 try {
  757.                                     handle.DangerousAddRef(ref b);
  758.                                 }
  759.                                 catch {
  760.                                     if (b) {
  761.                                         handle.DangerousRelease();
  762.                                         socketAndEventHandle.waitHandle = null;
  763.                                         b = false;
  764.                                     }
  765.                                 }
  766.                                 finally {
  767.                                     if (b) {
  768.                                         handle.Dispose();
  769.                                     }
  770.                                 }
  771.                             }
  772.                            
  773.                            
  774.                             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  775.                             private void DeleteEvent()
  776.                             {
  777.                                 try {
  778.                                     if (waitHandle != null) {
  779.                                         waitHandle.SafeWaitHandle.DangerousRelease();
  780.                                     }
  781.                                 }
  782.                                 catch {
  783.                                 }
  784.                             }
  785.                            
  786.                             internal WaitHandle GetEventHandle()
  787.                             {
  788.                                 return waitHandle;
  789.                             }
  790.                         }
  791.                        
  792.                        
  793.                        
  794.                     }
  795.                 }
  796.             }
  797.         }
  798.     }
  799. }

Developer Fusion