_SafeNetHandles.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Net / System / Net / _SafeNetHandles.cs / 1305376 / _SafeNetHandles.cs

                            /*++ 
Copyright (c) Microsoft Corporation

Module Name:
 
    _SafeNetHandles.cs
 
Abstract: 
        The file contains _all_ SafeHandles implementations for System.Net namespace.
        These handle wrappers do guarantee that OS resources get cleaned up when the app domain dies. 

        All PInvoke declarations that do freeing  the  OS resources  _must_ be in this file
        All PInvoke declarations that do allocation the OS resources _must_ be in this file
 

Details: 
 
        The protection from leaking OF the OS resources is based on two technologies
        1) SafeHandle class 
        2) Non interuptible regions using Constrained Execution Region (CER) technology

        For simple cases SafeHandle class does all the job. The Prerequisites are:
        - A resource is able to be represented by IntPtr type (32 bits on 32 bits platforms). 
        - There is a PInvoke availble that does the creation of the resource.
          That PInvoke either returns the handle value or it writes the handle into out/ref parameter. 
        - The above PInvoke as part of the call does NOT free any OS resource. 

        For those "simple" cases we desinged SafeHandle-derived classes that provide 
        static methods to allocate a handle object.
        Each such derived class provides a handle release method that is run as non-interrupted.

        For more complicated cases we employ the support for non-interruptible methods (CERs). 
        Each CER is a tree of code rooted at a catch or finally clause for a specially marked exception
        handler (preceded by the RuntimeHelpers.PrepareConstrainedRegions() marker) or the Dispose or 
        ReleaseHandle method of a SafeHandle derived class. The graph is automatically computed by the 
        runtime (typically at the jit time of the root method), but cannot follow virtual or interface
        calls (these must be explicitly prepared via RuntimeHelpers.PrepareMethod once the definite target 
        method is known). Also, methods in the graph that must be included in the CER must be marked with
        a reliability contract stating guarantees about the consistency of the system if an error occurs
        while they are executing. Look for ReliabilityContract for examples (a full explanation of the
        semantics of this contract is beyond the scope of this comment). 

        An example of the top-level of a CER: 
 
            RuntimeHelpers.PrepareConstrainedRegions();
            try 
            {
                // Normal code
            }
            finally 
            {
                // Guaranteed to get here even in low memory scenarios. Thread abort will not interrupt 
                // this clause and we won't fail because of a jit allocation of any method called (modulo 
                // restrictions on interface/virtual calls listed above and further restrictions listed
                // below). 
            }

        Another common pattern is an empty-try (where you really just want a region of code the runtime
        won't interrupt you in): 

            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {} finally 
            {
                // Non-interruptible code here 
            }

        This ugly syntax will be supplanted with compiler support at some point.
 
        While within a CER region certain restrictions apply in order to avoid having the runtime inject
        a potential fault point into your code (and of course you're are responsible for ensuring your 
        code doesn't inject any explicit fault points of its own unless you know how to tolerate them). 

        A quick and dirty guide to the possible causes of fault points in CER regions: 
        - Explicit allocations (though allocating a value type only implies allocation on the stack,
          which may not present an issue).
        - Boxing a value type (C# does this implicitly for you in many cases, so be careful).
        - Use of Monitor.Enter or the lock keyword. 
        - Accessing a multi-dimensional array.
        - Calling any method outside your control that doesn't make a guarantee (e.g. via a 
          ReliabilityAttribute) that it doesn't introduce failure points. 
        - Making P/Invoke calls with non-blittable parameters types. Blittable types are:
            - SafeHandle when used as an [in] parameter 
            - NON BOXED base types that fit onto a machine word
            - ref struct with blittable fields
            - class type with blittable fields
            - pinned Unicode strings using "fixed" statement 
            - pointers of any kind
            - IntPtr type 
        - P/Invokes should not have any CharSet attribute on it's declaration. 
          Obvioulsy string types should not appear in the parameters.
        - String type MUST not appear in a field of a marshaled ref struct or class in a P?Invoke 

Author:

    Alexei Vopilov    04-Sept-2002 

Revision History: 
 
--*/
 
namespace System.Net {
    using System.Net.Cache;
    using System.Net.Sockets;
    using System.Net.NetworkInformation; 
    using System.Security;
    using System.Runtime.InteropServices; 
    using System.Runtime.CompilerServices; 
    using System.Threading;
    using System.Security.Authentication.ExtendedProtection; 
    using System.Security.Permissions;
    using System.ComponentModel;
    using System.Text;
    using System.Globalization; 
    using Microsoft.Win32.SafeHandles;
    using System.Runtime.ConstrainedExecution; 
    using System.Diagnostics.CodeAnalysis; 

#if DEBUG 
    //
    // This is a helper class for debugging GC-ed handles that we define.
    // As a general rule normal code path should always destroy handles explicitly
    // 
    internal abstract class DebugSafeHandle: SafeHandleZeroOrMinusOneIsInvalid {
        string m_Trace; 
 
        protected DebugSafeHandle(bool ownsHandle): base(ownsHandle) {
            Trace(); 
        }

        protected DebugSafeHandle(IntPtr invalidValue, bool ownsHandle): base(ownsHandle) {
            SetHandle(invalidValue); 
            Trace();
        } 
 
        [EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)]
        private void Trace() { 
            m_Trace = "WARNING! GC-ed  >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n";
#if TRAVE
            (new FileIOPermission(PermissionState.Unrestricted)).Assert();
            string stacktrace = Environment.StackTrace; 
            m_Trace += stacktrace;
            FileIOPermission.RevertAssert(); 
#endif //TRAVE 
        }
 
        [ReliabilityContract(Consistency.MayCorruptAppDomain, Cer.None)]
        ~DebugSafeHandle() {
            GlobalLog.SetThreadSource(ThreadKinds.Finalization);
            GlobalLog.Print(m_Trace); 
        }
    } 
 
    //
    // This is a helper class for debugging GC-ed handles that we define. 
    // As a general rule normal code path should always destroy handles explicitly
    //
    internal abstract class DebugCriticalHandleMinusOneIsInvalid : CriticalHandleMinusOneIsInvalid {
        string m_Trace; 

        protected DebugCriticalHandleMinusOneIsInvalid(): base() { 
            Trace(); 
        }
 
        [EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)]
        private void Trace() {
            m_Trace = "WARNING! GC-ed  >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n";
            GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName); 
#if TRAVE
            (new FileIOPermission(PermissionState.Unrestricted)).Assert(); 
            string stacktrace = Environment.StackTrace; 
            m_Trace += stacktrace;
            FileIOPermission.RevertAssert(); 
#endif //TRAVE
        }

        ~DebugCriticalHandleMinusOneIsInvalid() { 
            GlobalLog.SetThreadSource(ThreadKinds.Finalization);
            GlobalLog.Print(m_Trace); 
        } 
    }
 
    //
    // This is a helper class for debugging GC-ed handles that we define.
    // As a general rule normal code path should always destroy handles explicitly
    // 
    internal abstract class DebugSafeHandleMinusOneIsInvalid : SafeHandleMinusOneIsInvalid {
        string m_Trace; 
 
        protected DebugSafeHandleMinusOneIsInvalid(bool ownsHandle): base(ownsHandle) {
            Trace(); 
        }

        [EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)]
        private void Trace() { 
            m_Trace = "WARNING! GC-ed  >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n";
            GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName); 
#if TRAVE 
            (new FileIOPermission(PermissionState.Unrestricted)).Assert();
            string stacktrace = Environment.StackTrace; 
            m_Trace += stacktrace;
            FileIOPermission.RevertAssert();
#endif //TRAVE
        } 

        ~DebugSafeHandleMinusOneIsInvalid() { 
            GlobalLog.SetThreadSource(ThreadKinds.Finalization); 
            GlobalLog.Print(m_Trace);
        } 
    }

    //
    // This is a helper class for debugging GC-ed handles that we define. 
    // As a general rule normal code path should always destroy handles explicitly
    // 
    internal abstract class DebugCriticalHandleZeroOrMinusOneIsInvalid : CriticalHandleZeroOrMinusOneIsInvalid { 
        string m_Trace;
 
        protected DebugCriticalHandleZeroOrMinusOneIsInvalid(): base() {
            Trace();
        }
 
        [SuppressMessage("Microsoft.Security","CA2106:SecureAsserts", Justification="DEBUG use only: Require access to Environment.StackTrace regardless of app permissions")]
        [EnvironmentPermission(SecurityAction.Assert, Unrestricted=true)] 
        private void Trace() { 
            m_Trace = "WARNING! GC-ed  >>" + this.GetType().FullName + "<< (should be excplicitly closed) \r\n";
            GlobalLog.Print("Creating SafeHandle, type = " + this.GetType().FullName); 
#if TRAVE
            (new FileIOPermission(PermissionState.Unrestricted)).Assert();
            string stacktrace = Environment.StackTrace;
            m_Trace += stacktrace; 
            FileIOPermission.RevertAssert();
#endif //TRAVE 
        } 

        ~DebugCriticalHandleZeroOrMinusOneIsInvalid() { 
            GlobalLog.SetThreadSource(ThreadKinds.Finalization);
            GlobalLog.Print(m_Trace);
        }
    } 
#endif // DEBUG
 
 
#if !FEATURE_PAL
 
    ///////////////////////////////////////////////////////////////
    //
    // This is safe handle implementaion that depends on
    // ws2_32.dll freeaddrinfo. It's only used by Dns class 
    //
    /////////////////////////////////////////////////////////////// 
    [SuppressUnmanagedCodeSecurity] 
#if DEBUG
    internal sealed class SafeFreeAddrInfo : DebugSafeHandle { 
#else
    internal sealed class SafeFreeAddrInfo : SafeHandleZeroOrMinusOneIsInvalid {
#endif
        private const string WS2_32 = "ws2_32.dll"; 

        private SafeFreeAddrInfo(): base(true) {} 
 
        internal static int GetAddrInfo(string nodename, string servicename, ref AddressInfo hints, out SafeFreeAddrInfo outAddrInfo) {
            return UnsafeNclNativeMethods.SafeNetHandlesXPOrLater.getaddrinfo(nodename, servicename, ref hints, out outAddrInfo); 
        }

        override protected bool ReleaseHandle()
        { 
            UnsafeNclNativeMethods.SafeNetHandlesXPOrLater.freeaddrinfo(handle);
            return true; 
        } 
    }
 
#endif // !FEATURE_PAL

    ///////////////////////////////////////////////////////////////
    // 
    // This is safe handle factory for any object that depends on
    // KERNEL32 CloseHandle as the handle disposal method. 
    // 
    ///////////////////////////////////////////////////////////////
    [SuppressUnmanagedCodeSecurity] 
#if DEBUG
    internal sealed class SafeCloseHandle : DebugCriticalHandleZeroOrMinusOneIsInvalid {
#else
    internal sealed class SafeCloseHandle : CriticalHandleZeroOrMinusOneIsInvalid { 
#endif
        private const string SECURITY = "security.dll"; 
        private const string ADVAPI32 = "advapi32.dll"; 
        private const string HTTPAPI = "httpapi.dll";
 
        private int _disposed;

        private SafeCloseHandle() : base() {
        } 

        internal IntPtr DangerousGetHandle() { 
            return handle; 
        }
 
        protected override bool ReleaseHandle() {
            if (!IsInvalid) {
                if (Interlocked.Increment(ref _disposed) == 1) {
                    return UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(handle); 
                }
            } 
            return true; 
        }
 
#if !FEATURE_PAL
        // This method will bypass refCount check done by VM
        // Means it will force handle release if has a valid value
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        internal void Abort() {
            ReleaseHandle(); 
            SetHandleAsInvalid(); 
        }
 
#endif // !FEATURE_PAL

    }
    // 
    // This class is a wrapper for Http.sys V2 request queue handle.
    // 
    [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", 
        Justification = "Suppress due to tools issues with unit test infrastructure")]
    [SuppressUnmanagedCodeSecurity] 
#if DEBUG
    internal sealed class HttpRequestQueueV2Handle : DebugCriticalHandleZeroOrMinusOneIsInvalid {
#else
    internal sealed class HttpRequestQueueV2Handle : CriticalHandleZeroOrMinusOneIsInvalid { 
#endif
 
        private int disposed; 

        private HttpRequestQueueV2Handle() : base() { 
        }

        internal IntPtr DangerousGetHandle() {
            return handle; 
        }
 
        protected override bool ReleaseHandle() { 
            if (!IsInvalid) {
                if (Interlocked.Increment(ref disposed) == 1) { 
                    return (UnsafeNclNativeMethods.SafeNetHandles.HttpCloseRequestQueue(handle) ==
                        UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS);
                }
            } 
            return true;
        } 
    } 

    // 
    // This class is a wrapper for Http.sys V2 server session. CreateServerSession returns an ID and not a real handle
    // but we use CriticalHandle because it provides us the guarantee that CloseServerSession will always get called.
    //
    [SuppressUnmanagedCodeSecurity] 
#if DEBUG
    internal sealed class HttpServerSessionHandle : DebugCriticalHandleZeroOrMinusOneIsInvalid { 
#else 
    internal sealed class HttpServerSessionHandle : CriticalHandleZeroOrMinusOneIsInvalid {
#endif 

        private int disposed;
        private ulong serverSessionId;
 
        internal HttpServerSessionHandle(ulong id) : base() {
            serverSessionId = id; 
 
            //
            // This class uses no real handle so we need to set a dummy handle. Otherwise, IsInvalid always remains 
            // true.
            //
            SetHandle(new IntPtr(1));
        } 

        internal ulong DangerousGetServerSessionId() { 
            return serverSessionId; 
        }
 
        protected override bool ReleaseHandle() {
            if (!IsInvalid) {
                if (Interlocked.Increment(ref disposed) == 1) {
 
                    //
                    // Closing server session also closes all open url groups under that server session. 
                    // 
                    return (UnsafeNclNativeMethods.HttpApi.HttpCloseServerSession(serverSessionId) ==
                        UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS); 
                }
            }
            return true;
        } 
    }
 
    // 
    // SafeHandle to wrap handles created by IcmpCreateFile or Icmp6CreateFile
    // from either icmp.dll or iphlpapi.dll. These handles must be closed by 
    // IcmpCloseHandle.
    //
    // Code creating handles will use ComNetOS.IsPostWin2K to determine
    // which DLL being used. This code uses same construct to determine 
    // which DLL being used but stashes the OS query results away at ctor
    // time so it is always available at critical finalizer time. 
    // 
    [SuppressUnmanagedCodeSecurity]
    internal sealed class SafeCloseIcmpHandle : SafeHandleZeroOrMinusOneIsInvalid { 

        private SafeCloseIcmpHandle() : base(true) {
        }
 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
        override protected bool ReleaseHandle() { 
            return UnsafeNetInfoNativeMethods.IcmpCloseHandle(handle); 
        }
    } 

    //
    // Used when working with WinHTTP APIs, like WinHttpOpen(). Holds the HINTERNET handle.
    // 
    [SuppressUnmanagedCodeSecurity]
#if DEBUG 
    internal sealed class SafeInternetHandle : DebugSafeHandle { 
#else
    internal sealed class SafeInternetHandle : SafeHandleZeroOrMinusOneIsInvalid { 
#endif
        public SafeInternetHandle() : base(true) {
        }
 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        protected override bool ReleaseHandle() { 
            return UnsafeNclNativeMethods.WinHttp.WinHttpCloseHandle(handle); 
        }
    } 


#if !FEATURE_PAL
 
    ///////////////////////////////////////////////////////////////
    // 
    //  A set of Safe Handles that depend on native FreeContextBuffer finalizer 
    //
    /////////////////////////////////////////////////////////////// 
//--------------------------------------------------------
    internal enum SecurDll {
        SECURITY    = 0,
        SECUR32     = 1, 
        SCHANNEL    = 2,
    } 
//======================================================= 
    [SuppressUnmanagedCodeSecurity]
#if DEBUG 
    internal abstract class SafeFreeContextBuffer : DebugSafeHandle {
#else
    internal abstract class SafeFreeContextBuffer : SafeHandleZeroOrMinusOneIsInvalid {
#endif 
        protected SafeFreeContextBuffer(): base(true) {}
 
        // This must be ONLY called from this file and in the context of a CER 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        internal unsafe void Set(IntPtr value) { 
            this.handle = value;
        }

        // 
        //
        internal static int EnumeratePackages(SecurDll Dll, out int pkgnum, out SafeFreeContextBuffer pkgArray) { 
 
            int res = -1;
            switch (Dll) { 
            case SecurDll.SECURITY:
                SafeFreeContextBuffer_SECURITY pkgArray_SECURITY = null;
                res = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.EnumerateSecurityPackagesW(out pkgnum, out pkgArray_SECURITY);
                pkgArray = pkgArray_SECURITY; 
                break;
 
            case SecurDll.SECUR32: 
                SafeFreeContextBuffer_SECUR32 pkgArray_SECUR32 = null;
                res = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.EnumerateSecurityPackagesA(out pkgnum, out pkgArray_SECUR32); 
                pkgArray = pkgArray_SECUR32;
                break;

            case SecurDll.SCHANNEL: 
                SafeFreeContextBuffer_SCHANNEL pkgArray_SCHANNEL = null;
                res = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.EnumerateSecurityPackagesA(out pkgnum, out pkgArray_SCHANNEL); 
                pkgArray = pkgArray_SCHANNEL; 
                break;
 
            default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "Dll");
            }
            if (res != 0 && pkgArray != null) {
                pkgArray.SetHandleAsInvalid(); 
            }
            return res; 
        } 

        // 
        //
        internal static SafeFreeContextBuffer CreateEmptyHandle(SecurDll dll) {
            switch (dll) {
            case SecurDll.SECURITY: return new SafeFreeContextBuffer_SECURITY(); 
            case SecurDll.SECUR32:  return new SafeFreeContextBuffer_SECUR32();
            case SecurDll.SCHANNEL: return new SafeFreeContextBuffer_SCHANNEL(); 
            default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "dll"); 
            }
        } 

        //
        // After PINvoke call the method will fix the refHandle.handle with the returned value.
        // The caller is responsible for creating a correct SafeHandle template or null can be passed if no handle is returned. 
        //
        // This method switches between three non-interruptible helper methods.  (This method can't be both non-interruptible and 
        // reference imports from all three DLLs - doing so would cause all three DLLs to try to be bound to.) 
        //
        public unsafe static int QueryContextAttributes(SecurDll dll, SafeDeleteContext phContext, ContextAttribute contextAttribute, byte* buffer, SafeHandle refHandle) 
        {
            switch (dll)
            {
                case SecurDll.SECURITY: 
                    return QueryContextAttributes_SECURITY(phContext, contextAttribute, buffer, refHandle);
 
                case SecurDll.SECUR32: 
                    return QueryContextAttributes_SECUR32(phContext, contextAttribute, buffer, refHandle);
 
                case SecurDll.SCHANNEL:
                    return QueryContextAttributes_SCHANNEL(phContext, contextAttribute, buffer, refHandle);

                default: 
                    return -1;
            } 
        } 

        private unsafe static int QueryContextAttributes_SECURITY( 
            SafeDeleteContext phContext,
            ContextAttribute contextAttribute,
            byte* buffer,
            SafeHandle refHandle) 
        {
            int status = (int)SecurityStatus.InvalidHandle; 
            bool b = false; 

            // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit 
            // one of the following methods. So run within a CER non-interruptible block.
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                phContext.DangerousAddRef(ref b); 
            }
            catch(Exception e) { 
                if (b) 
                {
                    phContext.DangerousRelease(); 
                    b = false;
                }
                if (!(e is ObjectDisposedException))
                    throw; 
            }
            finally { 
 
                if (b)
                { 
                    status = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer);
                    phContext.DangerousRelease();
                }
 
                if (status == 0 && refHandle != null) {
                    if (refHandle is SafeFreeContextBuffer) { 
                        ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); 
                    }
                    else { 
                        ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer);
                    }
                }
 
                if (status != 0 && refHandle != null) {
                    refHandle.SetHandleAsInvalid(); 
                } 
            }
 
            return status;
        }

        private unsafe static int QueryContextAttributes_SECUR32( 
            SafeDeleteContext phContext,
            ContextAttribute contextAttribute, 
            byte* buffer, 
            SafeHandle refHandle)
        { 
            int status = (int)SecurityStatus.InvalidHandle;
            bool b = false;

            // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit 
            // one of the following methods. So run within a CER non-interruptible block.
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try { 
                phContext.DangerousAddRef(ref b);
            } 
            catch(Exception e) {
                if (b)
                {
                    phContext.DangerousRelease(); 
                    b = false;
                } 
                if (!(e is ObjectDisposedException)) 
                    throw;
            } 
            finally {

                if (b)
                { 
                    status = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.QueryContextAttributesA(ref phContext._handle, contextAttribute, buffer);
                    phContext.DangerousRelease(); 
                } 

                if (status == 0 && refHandle != null) { 
                    if (refHandle is SafeFreeContextBuffer) {
                        ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer);
                    }
                    else { 
                        ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer);
                    } 
                } 

                if (status != 0 && refHandle != null) { 
                    refHandle.SetHandleAsInvalid();
                }
            }
 
            return status;
        } 
 
        private unsafe static int QueryContextAttributes_SCHANNEL(
            SafeDeleteContext phContext, 
            ContextAttribute contextAttribute,
            byte* buffer,
            SafeHandle refHandle)
        { 
            int status = (int)SecurityStatus.InvalidHandle;
            bool b = false; 
 
            // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit
            // one of the following methods. So run within a CER non-interruptible block. 
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                phContext.DangerousAddRef(ref b);
            } 
            catch(Exception e) {
                if (b) 
                { 
                    phContext.DangerousRelease();
                    b = false; 
                }
                if (!(e is ObjectDisposedException))
                    throw;
            } 
            finally {
 
                if (b) 
                {
                    status = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.QueryContextAttributesA(ref phContext._handle, contextAttribute, buffer); 
                    phContext.DangerousRelease();
                }

                if (status == 0 && refHandle != null) { 
                    if (refHandle is SafeFreeContextBuffer) {
                        ((SafeFreeContextBuffer)refHandle).Set(*(IntPtr*)buffer); 
                    } 
                    else {
                        ((SafeFreeCertContext)refHandle).Set(*(IntPtr*)buffer); 
                    }
                }

                if (status != 0 && refHandle != null) { 
                    refHandle.SetHandleAsInvalid();
                } 
            } 

            return status; 
        }
    }

    //======================================================= 
    [SuppressUnmanagedCodeSecurity]
    internal sealed class SafeFreeContextBuffer_SECURITY : SafeFreeContextBuffer { 
        private const string SECURITY = "security.dll"; 

        internal SafeFreeContextBuffer_SECURITY(): base() {} 

        override protected bool ReleaseHandle()
        {
            return UnsafeNclNativeMethods.SafeNetHandles_SECURITY.FreeContextBuffer(handle) == 0; 
        }
 
    } 
//=======================================================
    [SuppressUnmanagedCodeSecurity] 
    internal sealed class SafeFreeContextBuffer_SCHANNEL : SafeFreeContextBuffer {
        private const string SCHANNEL = "schannel.dll";

        internal SafeFreeContextBuffer_SCHANNEL(): base() {} 

        override protected bool ReleaseHandle() 
        { 
            return UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.FreeContextBuffer(handle) == 0;
        } 
    }
//========================================================
    [SuppressUnmanagedCodeSecurity]
    internal sealed class SafeFreeContextBuffer_SECUR32: SafeFreeContextBuffer { 
        private const string SECUR32 = "secur32.dll";
 
        internal SafeFreeContextBuffer_SECUR32(): base() {} 

        override protected bool ReleaseHandle() 
        {
            return UnsafeNclNativeMethods.SafeNetHandles_SECUR32.FreeContextBuffer(handle) == 0;
        }
    } 

#endif // !FEATURE_PAL 
 
    ///////////////////////////////////////////////////////////////
    // 
    // This is implementaion of Safe AllocHGlobal which is turned out
    // to be LocalAlloc down in CLR
    //
    /////////////////////////////////////////////////////////////// 
    [SuppressUnmanagedCodeSecurity]
#if DEBUG 
    internal sealed class SafeLocalFree : DebugSafeHandle { 
#else
    internal sealed class SafeLocalFree : SafeHandleZeroOrMinusOneIsInvalid { 
#endif
        private const int LMEM_FIXED = 0;
        private const int NULL = 0;
 
        // This returned handle cannot be modified by the application.
        public static SafeLocalFree Zero = new SafeLocalFree(false); 
 
        private SafeLocalFree() : base(true) {}
 
        private SafeLocalFree(bool ownsHandle) : base(ownsHandle) {}

        public static SafeLocalFree LocalAlloc(int cb) {
            SafeLocalFree result = UnsafeNclNativeMethods.SafeNetHandles.LocalAlloc(LMEM_FIXED, (UIntPtr) cb); 
            if (result.IsInvalid) {
                result.SetHandleAsInvalid(); 
                throw new OutOfMemoryException(); 
            }
            return result; 
        }

        override protected bool ReleaseHandle()
        { 
            return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero;
        } 
    } 

    /////////////////////////////////////////////////////////////// 
    //
    // A few Win32 APIs return pointers to blobs that need GlobalFree().
    //
    /////////////////////////////////////////////////////////////// 
    [SuppressUnmanagedCodeSecurity]
#if DEBUG 
    internal sealed class SafeGlobalFree : DebugSafeHandle { 
#else
    internal sealed class SafeGlobalFree : SafeHandleZeroOrMinusOneIsInvalid 
    {
#endif
        private SafeGlobalFree() : base(true) { }
        private SafeGlobalFree(bool ownsHandle) : base(ownsHandle) { } 

        override protected bool ReleaseHandle() 
        { 
            return UnsafeNclNativeMethods.SafeNetHandles.GlobalFree(handle) == IntPtr.Zero;
        } 
    }

    [ComVisible(false)]
#if DEBUG 
    internal sealed class SafeOverlappedFree : DebugSafeHandle {
#else 
    internal sealed class SafeOverlappedFree : SafeHandleZeroOrMinusOneIsInvalid { 
#endif
        private const int LPTR = 0x0040; 

        private SafeCloseSocket             _socketHandle;

        private SafeOverlappedFree() : base(true) {} 
        private SafeOverlappedFree(bool ownsHandle) : base(ownsHandle) {}
 
        public static SafeOverlappedFree Alloc() { 
            SafeOverlappedFree result = UnsafeNclNativeMethods.SafeNetHandlesSafeOverlappedFree.LocalAlloc(LPTR, (UIntPtr) Win32.OverlappedSize);
            if (result.IsInvalid) { 
                result.SetHandleAsInvalid();
                throw new OutOfMemoryException();
            }
            return result; 
        }
 
        public static SafeOverlappedFree Alloc(SafeCloseSocket socketHandle) { 
            SafeOverlappedFree result = Alloc();
            result._socketHandle = socketHandle; 
            return result;
        }

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        public void Close (bool resetOwner)
        { 
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {} finally {
                if (resetOwner) { 
                    _socketHandle = null;
                }
                Close();
            } 
        }
 
        unsafe override protected bool ReleaseHandle() 
        {
            SafeCloseSocket socketHandle = _socketHandle; 
            if (socketHandle != null && !socketHandle.IsInvalid)
            {
                // We are being finalized while the I/O operation associated
                // with the current overlapped is still pending (e.g. on app 
                // domain shutdown). The socket has to be closed first to
                // avoid reuse after delete of the native overlapped structure. 
                socketHandle.Dispose(); 
            }
            // Release the native overlapped structure 
            return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero;
        }
    }
 
#if !FEATURE_PAL
    [SuppressUnmanagedCodeSecurity] 
#if DEBUG 
    internal sealed class SafeLoadLibrary : DebugSafeHandle {
#else 
    internal sealed class SafeLoadLibrary : SafeHandleZeroOrMinusOneIsInvalid {
#endif
        private const string KERNEL32 = "kernel32.dll";
 
        public static readonly SafeLoadLibrary Zero = new SafeLoadLibrary(false);
 
        private SafeLoadLibrary() : base(true) { 
        }
 
        private SafeLoadLibrary(bool ownsHandle) : base(ownsHandle) {
        }

        public unsafe static SafeLoadLibrary LoadLibraryEx(string library) { 

            SafeLoadLibrary result = ComNetOS.IsWin9x ? UnsafeNclNativeMethods.SafeNetHandles.LoadLibraryExA(library, null, 0): UnsafeNclNativeMethods.SafeNetHandles.LoadLibraryExW(library, null, 0); 
            if (result.IsInvalid) { 
                result.SetHandleAsInvalid();
            } 
            return result;
        }

        protected override bool ReleaseHandle() { 
            return UnsafeNclNativeMethods.SafeNetHandles.FreeLibrary(handle);
        } 
 
    }
 
    ///////////////////////////////////////////////////////////////
    //
    // Implementation of handles that require CertFreeCertificateChain
    // 
    ///////////////////////////////////////////////////////////////
    [SuppressUnmanagedCodeSecurity] 
#if DEBUG 
    internal sealed class SafeFreeCertChain : DebugSafeHandle {
#else 
    internal sealed class SafeFreeCertChain : SafeHandleZeroOrMinusOneIsInvalid {
#endif
        private const string CRYPT32 = "crypt32.dll";
 
        // This ctor will create a handle that we >>don't<< own
        internal SafeFreeCertChain(IntPtr handle) : base(false) 
        { 
            SetHandle(handle);
        } 

        public override string ToString()
        {
            return "0x"+DangerousGetHandle().ToString("x"); 
        }
 
        override protected bool ReleaseHandle() 
        {
            UnsafeNclNativeMethods.SafeNetHandles.CertFreeCertificateChain(handle); 
            return true;
        }
    }
 
    ///////////////////////////////////////////////////////////////
    // 
    // Implementation of handles required CertFreeCertificateContext 
    //
    /////////////////////////////////////////////////////////////// 
    [SuppressUnmanagedCodeSecurity]
#if DEBUG
    internal sealed class SafeFreeCertContext : DebugSafeHandle {
#else 
    internal sealed class SafeFreeCertContext : SafeHandleZeroOrMinusOneIsInvalid {
#endif 
        private const string CRYPT32 = "crypt32.dll"; 
        private const string ADVAPI32 = "advapi32.dll";
 
        internal SafeFreeCertContext() : base(true) {}

        // This must be ONLY called from this file within a CER.
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        internal unsafe void Set(IntPtr value) {
            this.handle = value; 
        } 

        const uint CRYPT_ACQUIRE_SILENT_FLAG = 0x00000040; 

        override protected bool ReleaseHandle() {
            UnsafeNclNativeMethods.SafeNetHandles.CertFreeCertificateContext(handle);
            return true; 
        }
    } 
 
    [StructLayout(LayoutKind.Sequential, Pack=1)]
    internal struct SSPIHandle { 
        private IntPtr HandleHi;
        private IntPtr HandleLo;

        public bool IsZero { 
            get {return HandleHi == IntPtr.Zero && HandleLo == IntPtr.Zero;}
 
        } 

        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        internal void SetToInvalid() {
            HandleHi = IntPtr.Zero;
            HandleLo = IntPtr.Zero;
        } 

        public override string ToString() { 
            {   return HandleHi.ToString("x") + ":" + HandleLo.ToString("x");} 
        }
    } 

    ///////////////////////////////////////////////////////////////
    //
    // Implementation of handles dependable on FreeCredentialsHandle 
    //
    // 
    /////////////////////////////////////////////////////////////// 
    //-----------------------------------------------------------
#if DEBUG 
    internal abstract class SafeFreeCredentials : DebugSafeHandle {
#else
    internal abstract class SafeFreeCredentials : SafeHandle {
#endif 

        internal SSPIHandle _handle;    //should be always used as by ref in PINvokes parameters 
 
        protected SafeFreeCredentials(): base(IntPtr.Zero, true) {
            _handle = new SSPIHandle(); 
        }

#if TRAVE
        public override string ToString() { 
            return "0x"+_handle.ToString();
        } 
#endif 

        public override bool IsInvalid 
        {
            get {return IsClosed || _handle.IsZero;}
        }
 
#if DEBUG
        //This method should never be called for this type 
        public new IntPtr DangerousGetHandle() 
        {
            throw new InvalidOperationException(); 
        }
#endif

        public unsafe static int AcquireCredentialsHandle( SecurDll dll, 
                                                    string package,
                                                    CredentialUse intent, 
                                                    ref AuthIdentity authdata, 
                                                    out SafeFreeCredentials outCredential
                                                    ) 
        {

            GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#1("
                            + dll + "," 
                            + package + ", "
                            + intent + ", " 
                            + authdata + ")" 
                            );
 
            int errorCode = -1;
            long timeStamp;

            switch (dll) { 
            case SecurDll.SECURITY:
                        outCredential = new SafeFreeCredential_SECURITY(); 
 
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try {} finally { 

                            errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.AcquireCredentialsHandleW(
                                                                   null,
                                                                   package, 
                                                                   (int)intent,
                                                                   null, 
                                                                   ref authdata, 
                                                                   null,
                                                                   null, 
                                                                   ref outCredential._handle,
                                                                   out timeStamp
                                                                   );
                        } 

                        break; 
            case SecurDll.SECUR32: 
                        outCredential = new SafeFreeCredential_SECUR32();
 
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try {} finally {

                            errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.AcquireCredentialsHandleA( 
                                                               null,
                                                               package, 
                                                               (int)intent, 
                                                               null,
                                                               ref authdata, 
                                                               null,
                                                               null,
                                                               ref outCredential._handle,
                                                               out timeStamp 
                                                               );
                        } 
                        break; 

            default:  throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "Dll"); 
            }
#if TRAVE
            GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x"
                            + String.Format("{0:x}", errorCode) 
                            + ", handle = " + outCredential.ToString()
                            ); 
#endif 

            if (errorCode != 0) { 
                outCredential.SetHandleAsInvalid();
            }
            return errorCode;
 
        }
 
        public unsafe static int AcquireDefaultCredential( SecurDll dll, 
                                                    string package,
                                                    CredentialUse intent, 
                                                    out SafeFreeCredentials outCredential
                                                    )
        {
 
            GlobalLog.Print("SafeFreeCredentials::AcquireDefaultCredential("
                            + dll + "," 
                            + package + ", " 
                            + intent + ")"
                            ); 

            int errorCode = -1;
            long timeStamp;
 
            switch (dll) {
            case SecurDll.SECURITY: 
                        outCredential = new SafeFreeCredential_SECURITY(); 

                        RuntimeHelpers.PrepareConstrainedRegions(); 
                        try {} finally {

                            errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.AcquireCredentialsHandleW(
                                                               null, 
                                                               package,
                                                               (int)intent, 
                                                               null, 
                                                               IntPtr.Zero,
                                                               null, 
                                                               null,
                                                               ref outCredential._handle,
                                                               out timeStamp
                                                               ); 
                        }
                        break; 
            case SecurDll.SECUR32: 
                        outCredential = new SafeFreeCredential_SECUR32();
 
                        RuntimeHelpers.PrepareConstrainedRegions();
                        try {} finally {

                            errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.AcquireCredentialsHandleA( 
                                                               null,
                                                               package, 
                                                               (int)intent, 
                                                               null,
                                                               IntPtr.Zero, 
                                                               null,
                                                               null,
                                                               ref outCredential._handle,
                                                               out timeStamp 
                                                               );
                        } 
                        break; 

            default:  throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "Dll"); 
            }

#if TRAVE
            GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x" 
                            + errorCode.ToString("x")
                            + ", handle = " + outCredential.ToString() 
                            ); 
#endif
 
            if (errorCode != 0) {
                outCredential.SetHandleAsInvalid();
            }
            return errorCode; 

        } 
 
        public unsafe static int AcquireCredentialsHandle( SecurDll dll,
                                                    string package, 
                                                    CredentialUse intent,
                                                    ref SecureCredential authdata,
                                                    out SafeFreeCredentials outCredential
                                                    ) 
        {
 
            GlobalLog.Print("SafeFreeCredentials::AcquireCredentialsHandle#2(" 
                            + dll + ","
                            + package + ", " 
                            + intent + ", "
                            + authdata + ")"
                            );
 
            int errorCode = -1;
            long timeStamp; 
 

            // If there is a certificate, wrap it into an array. 
            // Not threadsafe.
            IntPtr copiedPtr = authdata.certContextArray;
            try
            { 
                IntPtr certArrayPtr = new IntPtr(&copiedPtr);
                if (copiedPtr != IntPtr.Zero) { 
                    authdata.certContextArray = certArrayPtr; 
                }
 
                switch (dll) {
                case SecurDll.SECURITY:
                            outCredential = new SafeFreeCredential_SECURITY();
 
                            RuntimeHelpers.PrepareConstrainedRegions();
                            try {} finally { 
 
                                errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.AcquireCredentialsHandleW(
                                                                   null, 
                                                                   package,
                                                                   (int)intent,
                                                                   null,
                                                                   ref authdata, 
                                                                   null,
                                                                   null, 
                                                                   ref outCredential._handle, 
                                                                   out timeStamp
                                                                   ); 
                            }
                            break;

                case SecurDll.SCHANNEL: 
                            outCredential = new SafeFreeCredential_SCHANNEL();
 
                            RuntimeHelpers.PrepareConstrainedRegions(); 
                            try {} finally {
 
                                errorCode = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.AcquireCredentialsHandleA(
                                                                   null,
                                                                   package,
                                                                   (int)intent, 
                                                                   null,
                                                                   ref authdata, 
                                                                   null, 
                                                                   null,
                                                                   ref outCredential._handle, 
                                                                   out timeStamp
                                                                   );
                            }
                            break; 

                default:  throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "Dll"); 
                } 
            }
            finally 
            {
                authdata.certContextArray = copiedPtr;
            }
 
#if TRAVE
            GlobalLog.Print("Unmanaged::AcquireCredentialsHandle() returns 0x" 
                            + errorCode.ToString("x") 
                            + ", handle = " + outCredential.ToString()
                            ); 
#endif

            if (errorCode != 0) {
                outCredential.SetHandleAsInvalid(); 
            }
            return errorCode; 
 
        }
 
    }
    //
    // This is a class holding a Credential handle reference, used for static handles cache
    // 
#if DEBUG
    internal sealed class SafeCredentialReference: DebugCriticalHandleMinusOneIsInvalid { 
#else 
    internal sealed class SafeCredentialReference: CriticalHandleMinusOneIsInvalid {
#endif 

        //
        // Static cache will return the target handle if found the reference in the table.
        // 
        internal SafeFreeCredentials _Target;
 
        // 
        //
        internal static SafeCredentialReference CreateReference(SafeFreeCredentials target) 
        {
            SafeCredentialReference result = new SafeCredentialReference(target);
            if (result.IsInvalid)
                return null; 

            return result; 
        } 
        private SafeCredentialReference(SafeFreeCredentials target): base()
        { 
            // Bumps up the refcount on Target to signify that target handle is statically cached so
            // its dispose should be postponed
            bool b = false;
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try
            { 
                target.DangerousAddRef(ref b); 
            }
            catch 
            {
                if (b)
                {
                    target.DangerousRelease(); 
                    b = false;
                } 
            } 
            finally
            { 
                if (b)
                {
                    _Target = target;
                    SetHandle(new IntPtr(0));   // make this handle valid 
                }
            } 
        } 

        override protected bool ReleaseHandle() 
        {
            SafeFreeCredentials target = _Target;
            if (target != null)
                target.DangerousRelease(); 
            _Target = null;
            return true; 
        } 
    }
 
//======================================================================
    [SuppressUnmanagedCodeSecurity]
    internal sealed class SafeFreeCredential_SECURITY: SafeFreeCredentials {
 
        private const string SECURITY = "security.Dll";
 
        public SafeFreeCredential_SECURITY() : base() {} 

        override protected bool ReleaseHandle() 
        {
            return UnsafeNclNativeMethods.SafeNetHandles_SECURITY.FreeCredentialsHandle(ref _handle) == 0;
        }
 
    }
//====================================================================== 
    [SuppressUnmanagedCodeSecurity] 
    internal sealed class SafeFreeCredential_SECUR32: SafeFreeCredentials {
 
        private const string SECUR32 = "secur32.Dll";

        public SafeFreeCredential_SECUR32() : base() {}
 
        override protected bool ReleaseHandle()
        { 
            return UnsafeNclNativeMethods.SafeNetHandles_SECUR32.FreeCredentialsHandle(ref _handle) == 0; 
        }
 
    }
//=====================================================================
    [SuppressUnmanagedCodeSecurity]
    internal sealed class SafeFreeCredential_SCHANNEL: SafeFreeCredentials { 

        private const string SCHANNEL = "schannel.Dll"; 
 
        public SafeFreeCredential_SCHANNEL() : base() {}
 
        override protected bool ReleaseHandle()
        {
            return UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.FreeCredentialsHandle(ref _handle) == 0;
        } 

    } 
 

    /////////////////////////////////////////////////////////////// 
    //
    // Implementation of handles that are dependent on DeleteSecurityContext
    //
    // 
    ///////////////////////////////////////////////////////////////
#if DEBUG 
    internal abstract class SafeDeleteContext : DebugSafeHandle { 
#else
    internal abstract class SafeDeleteContext : SafeHandle { 
#endif
        private const           string dummyStr = " ";
        private static readonly byte[] dummyBytes = new byte[] {0};
 
        //
        // ATN: _handle is internal since it is used on PInvokes by other wrapper methods. 
        //      However all such wrappers MUST manually and reliably adjust refCounter of SafeDeleteContext handle. 
        //
        internal SSPIHandle             _handle; 

        protected SafeFreeCredentials _EffectiveCredential;

        protected SafeDeleteContext(): base(IntPtr.Zero, true) { 
            _handle = new SSPIHandle();
        } 
 
        public override bool IsInvalid {
            get { 
                return IsClosed || _handle.IsZero;
            }
        }
 
        public override string ToString() {
            return _handle.ToString(); 
        } 

#if DEBUG 
        //This method should never be called for this type
        public new IntPtr DangerousGetHandle()
        {
            throw new InvalidOperationException(); 
        }
#endif 
 
        //--------------------------------------------------------------------
        internal unsafe static int InitializeSecurityContext( 
                                                    SecurDll                dll,
                                                    ref SafeFreeCredentials inCredentials,
                                                    ref SafeDeleteContext   refContext,
                                                    string                  targetName, 
                                                    ContextFlags            inFlags,
                                                    Endianness              endianness, 
                                                    SecurityBuffer          inSecBuffer, 
                                                    SecurityBuffer[]        inSecBuffers,
                                                    SecurityBuffer          outSecBuffer, 
                                                    ref ContextFlags        outFlags)
        {

#if TRAVE 
            GlobalLog.Enter("SafeDeleteContext::InitializeSecurityContext");
            GlobalLog.Print("    DLL              = " + dll); 
            GlobalLog.Print("    credential       = " + inCredentials.ToString()); 
            GlobalLog.Print("    refContext       = " + ValidationHelper.ToString(refContext));
            GlobalLog.Print("    targetName       = " + targetName); 
            GlobalLog.Print("    inFlags          = " + inFlags);
//            GlobalLog.Print("    reservedI        = 0x0");
//            GlobalLog.Print("    endianness       = " + endianness);
 
            if (inSecBuffers==null)
            { 
                GlobalLog.Print("    inSecBuffers     = (null)"); 
            }
            else 
            {
                GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
//                for (int index=0; index 0)
                        { 
                            outSecBuffer.token = new byte[outSecBuffer.size]; 
                            Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size);
                        } 
                        else
                        {
                            outSecBuffer.token = null;
                        } 
                    }
                } 
            } 
            finally {
                if (pinnedInBytes!=null) 
                {
                    for (int index=0; indextoken); //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes
                        if (handleTemplate.IsInvalid) 
                            handleTemplate.SetHandleAsInvalid(); 
                    }
                } 


                if (inContextPtr == null && (errorCode & 0x80000000) != 0)
                { 
                    // an error on the first call, need to set the out handle to invalid value
                    outContext._handle.SetToInvalid(); 
                } 
            }
 
            return errorCode;
        }

        // 
        // After PINvoke call the method will fix the handleTemplate.handle with the returned value.
        // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned. 
        // 
        // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system.
        // 
        private static unsafe int MustRunInitializeSecurityContext_SECUR32(
                                                  ref SafeFreeCredentials inCredentials,
                                                  void*            inContextPtr,
                                                  byte*            targetName, 
                                                  ContextFlags     inFlags,
                                                  Endianness       endianness, 
                                                  SecurityBufferDescriptor inputBuffer, 
                                                  SafeDeleteContext outContext,
                                                  SecurityBufferDescriptor outputBuffer, 
                                                  ref ContextFlags attributes,
                                                  SafeFreeContextBuffer handleTemplate)
        {
            int errorCode = (int) SecurityStatus.InvalidHandle; 
            bool b1 = false;
            bool b2 = false; 
 
            // Run the body of this method as a non-interruptible block.
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try
            {
                inCredentials.DangerousAddRef(ref b1);
                outContext.DangerousAddRef(ref b2); 
            }
            catch(Exception e) 
            { 
                if (b1)
                { 
                    inCredentials.DangerousRelease();
                    b1 = false;
                }
                if (b2) 
                {
                    outContext.DangerousRelease(); 
                    b2 = false; 
                }
                if (!(e is ObjectDisposedException)) 
                    throw;
            }
            finally
            { 
                SSPIHandle credentialHandle = inCredentials._handle;
 
                long timeStamp; 
                if (b1 && b2)
                { 
                    errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.InitializeSecurityContextA(
                                ref credentialHandle,
                                inContextPtr,
                                targetName, 
                                inFlags,
                                0, 
                                endianness, 
                                inputBuffer,
                                0, 
                                ref outContext._handle,
                                outputBuffer,
                                ref attributes,
                                out timeStamp); 

                    // 
                    // When a credential handle is first associated with the context we keep credential 
                    // ref count bumped up to ensure ordered finalization.
                    // If the credential handle has been changed we de-ref the old one and associate the 
                    //  context with the new cred handle but only if the call was successful.
                    if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0)
                    {
                        // Disassociate the previous credential handle 
                        if (outContext._EffectiveCredential != null)
                            outContext._EffectiveCredential.DangerousRelease(); 
                        outContext._EffectiveCredential = inCredentials; 
                    }
                    else 
                    {
                        inCredentials.DangerousRelease();
                    }
 
                    outContext.DangerousRelease();
 
                    // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer. 
                    if (handleTemplate != null)
                    { 
                        handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes
                        if (handleTemplate.IsInvalid)
                            handleTemplate.SetHandleAsInvalid();
                    } 
                }
 
                if (inContextPtr == null && (errorCode & 0x80000000) != 0) 
                {
                    // an error on the first call, need to set the out handle to invalid value 
                    outContext._handle.SetToInvalid();
                }
            }
 
            return errorCode;
        } 
 
        //
        // After PINvoke call the method will fix the handleTemplate.handle with the returned value. 
        // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned.
        //
        // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system.
        // 
        private static unsafe int MustRunInitializeSecurityContext_SCHANNEL(
                                                  ref SafeFreeCredentials inCredentials, 
                                                  void*            inContextPtr, 
                                                  byte*            targetName,
                                                  ContextFlags     inFlags, 
                                                  Endianness       endianness,
                                                  SecurityBufferDescriptor inputBuffer,
                                                  SafeDeleteContext outContext,
                                                  SecurityBufferDescriptor outputBuffer, 
                                                  ref ContextFlags attributes,
                                                  SafeFreeContextBuffer handleTemplate) 
        { 
            int errorCode = (int) SecurityStatus.InvalidHandle;
            bool b1 = false; 
            bool b2 = false;

            // Run the body of this method as a non-interruptible block.
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try
            { 
                inCredentials.DangerousAddRef(ref b1); 
                outContext.DangerousAddRef(ref b2);
            } 
            catch(Exception e)
            {
                if (b1)
                { 
                    inCredentials.DangerousRelease();
                    b1 = false; 
                } 
                if (b2)
                { 
                    outContext.DangerousRelease();
                    b2 = false;
                }
                if (!(e is ObjectDisposedException)) 
                    throw;
            } 
            finally 
            {
                SSPIHandle credentialHandle = inCredentials._handle; 
                long timeStamp;

                if (b1 && b2)
                { 
                    errorCode = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.InitializeSecurityContextA(
                                ref credentialHandle, 
                                inContextPtr, 
                                targetName,
                                inFlags, 
                                0,
                                endianness,
                                inputBuffer,
                                0, 
                                ref outContext._handle,
                                outputBuffer, 
                                ref attributes, 
                                out timeStamp);
 
                    //
                    // When a credential handle is first associated with the context we keep credential
                    // ref count bumped up to ensure ordered finalization.
                    // If the credential handle has been changed we de-ref the old one and associate the 
                    //  context with the new cred handle but only if the call was successful.
                    if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) 
                    { 
                        // Disassociate the previous credential handle
                        if (outContext._EffectiveCredential != null) 
                            outContext._EffectiveCredential.DangerousRelease();
                        outContext._EffectiveCredential = inCredentials;
                    }
                    else 
                    {
                        inCredentials.DangerousRelease(); 
                    } 

                    outContext.DangerousRelease(); 

                    // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer.
                    if (handleTemplate != null)
                    { 
                        handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes
                        if (handleTemplate.IsInvalid) 
                            handleTemplate.SetHandleAsInvalid(); 
                    }
                } 

                if (inContextPtr == null && (errorCode & 0x80000000) != 0)
                {
                    // an error on the first call, need to set the out handle to invalid value 
                    outContext._handle.SetToInvalid();
                } 
            } 

            return errorCode; 
        }

        //-------------------------------------------------------------------
        internal unsafe static int AcceptSecurityContext( 
            SecurDll                dll,
            ref SafeFreeCredentials inCredentials, 
            ref SafeDeleteContext   refContext, 
            ContextFlags            inFlags,
            Endianness              endianness, 
            SecurityBuffer          inSecBuffer,
            SecurityBuffer[]        inSecBuffers,
            SecurityBuffer          outSecBuffer,
            ref ContextFlags        outFlags) { 

#if TRAVE 
            GlobalLog.Enter("SafeDeleteContext::AcceptSecurityContex"); 
            GlobalLog.Print("    DLL              = " + dll);
            GlobalLog.Print("    credential       = " + inCredentials.ToString()); 
            GlobalLog.Print("    refContext       = " + ValidationHelper.ToString(refContext));

            GlobalLog.Print("    inFlags          = " + inFlags);
//            GlobalLog.Print("    endianness       = " + endianness); 
//            GlobalLog.Print("    inSecBuffer      = " + SecurityBuffer.ToString(inSecBuffer));
// 
            if (inSecBuffers==null) 
            {
                GlobalLog.Print("    inSecBuffers     = (null)"); 
            }
            else
            {
                GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length); 
//                for (int index=0; index 0)
                        {
                            outSecBuffer.token = new byte[outSecBuffer.size]; 
                            Marshal.Copy(outUnmanagedBuffer[0].token, outSecBuffer.token, 0, outSecBuffer.size);
                        } 
                        else 
                        {
                            outSecBuffer.token = null; 
                        }
                    }
                }
            } 
            finally {
                if (pinnedInBytes!=null) 
                { 
                    for (int index=0; indextoken); //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes 
                        if (handleTemplate.IsInvalid) 
                        {
                            handleTemplate.SetHandleAsInvalid(); 
                        }
                    }
                }
 
                if (inContextPtr == null && (errorCode & 0x80000000) != 0)
                { 
                    // an error on the first call, need to set the out handle to invalid value 
                    outContext._handle.SetToInvalid();
                } 
            }

            return errorCode;
        } 

        // 
        // After PINvoke call the method will fix the handleTemplate.handle with the returned value. 
        // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned.
        // 
        // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system.
        //
        private static unsafe int MustRunAcceptSecurityContext_SECUR32(
                                                  ref SafeFreeCredentials     inCredentials, 
                                                  void*            inContextPtr,
                                                  SecurityBufferDescriptor inputBuffer, 
                                                  ContextFlags     inFlags, 
                                                  Endianness       endianness,
                                                  SafeDeleteContext outContext, 
                                                  SecurityBufferDescriptor outputBuffer,
                                                  ref ContextFlags outFlags,
                                                  SafeFreeContextBuffer handleTemplate)
        { 
            int errorCode = (int) SecurityStatus.InvalidHandle;
            bool b1 = false; 
            bool b2 = false; 

            // Run the body of this method as a non-interruptible block. 
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                inCredentials.DangerousAddRef(ref b1);
                outContext.DangerousAddRef(ref b2); 
            }
            catch(Exception e) { 
                if (b1) 
                {
                    inCredentials.DangerousRelease(); 
                    b1 = false;
                }
                if (b2)
                { 
                    outContext.DangerousRelease();
                    b2 = false; 
                } 
                if (!(e is ObjectDisposedException))
                    throw; 
            }
            finally {
                SSPIHandle credentialHandle = inCredentials._handle;
                long timeStamp; 

                if (b1 && b2) 
                { 
                    errorCode = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.AcceptSecurityContext(
                                ref credentialHandle, 
                                inContextPtr,
                                inputBuffer,
                                inFlags,
                                endianness, 
                                ref outContext._handle,
                                outputBuffer, 
                                ref outFlags, 
                                out timeStamp);
 
                    //
                    // When a credential handle is first associated with the context we keep credential
                    // ref count bumped up to ensure ordered finalization.
                    // If the credential handle has been changed we de-ref the old one and associate the 
                    //  context with the new cred handle but only if the call was successful.
                    if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) 
                    { 
                        // Disassociate the previous credential handle
                        if (outContext._EffectiveCredential != null) 
                            outContext._EffectiveCredential.DangerousRelease();
                        outContext._EffectiveCredential = inCredentials;
                    }
                    else 
                    {
                        inCredentials.DangerousRelease(); 
                    } 

                    outContext.DangerousRelease(); 

                    // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer.
                    if (handleTemplate != null)
                    { 
                        handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes
                        if (handleTemplate.IsInvalid) 
                        { 
                            handleTemplate.SetHandleAsInvalid();
                        } 
                    }

                }
 
                if (inContextPtr == null && (errorCode & 0x80000000) != 0)
                { 
                    // an error on the first call, need to set the out handle to invalid value 
                    outContext._handle.SetToInvalid();
                } 
            }

            return errorCode;
        } 

        // 
        // After PINvoke call the method will fix the handleTemplate.handle with the returned value. 
        // The caller is responsible for creating a correct SafeFreeContextBuffer_XXX flavour or null can be passed if no handle is returned.
        // 
        // Since it has a CER, this method can't have any references to imports from DLLs that may not exist on the system.
        //
        private static unsafe int MustRunAcceptSecurityContext_SCHANNEL(
                                                  ref SafeFreeCredentials     inCredentials, 
                                                  void*            inContextPtr,
                                                  SecurityBufferDescriptor inputBuffer, 
                                                  ContextFlags     inFlags, 
                                                  Endianness       endianness,
                                                  SafeDeleteContext outContext, 
                                                  SecurityBufferDescriptor outputBuffer,
                                                  ref ContextFlags outFlags,
                                                  SafeFreeContextBuffer handleTemplate)
        { 
            int errorCode = (int) SecurityStatus.InvalidHandle;
            bool b1 = false; 
            bool b2 = false; 

            // Run the body of this method as a non-interruptible block. 
            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                inCredentials.DangerousAddRef(ref b1);
                outContext.DangerousAddRef(ref b2); 
            }
            catch(Exception e) { 
                if (b1) 
                {
                    inCredentials.DangerousRelease(); 
                    b1 = false;
                }
                if (b2)
                { 
                    outContext.DangerousRelease();
                    b2 = false; 
                } 
                if (!(e is ObjectDisposedException))
                    throw; 
            }
            finally {
                SSPIHandle credentialHandle = inCredentials._handle;
                long timeStamp; 

                if (b1 && b2) 
                { 
                    errorCode = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.AcceptSecurityContext(
                                ref credentialHandle, 
                                inContextPtr,
                                inputBuffer,
                                inFlags,
                                endianness, 
                                ref outContext._handle,
                                outputBuffer, 
                                ref outFlags, 
                                out timeStamp);
 
                    //
                    // When a credential handle is first associated with the context we keep credential
                    // ref count bumped up to ensure ordered finalization.
                    // If the credential handle has been changed we de-ref the old one and associate the 
                    //  context with the new cred handle but only if the call was successful.
                    if (outContext._EffectiveCredential != inCredentials && (errorCode & 0x80000000) == 0) 
                    { 
                        // Disassociate the previous credential handle
                        if (outContext._EffectiveCredential != null) 
                            outContext._EffectiveCredential.DangerousRelease();
                        outContext._EffectiveCredential = inCredentials;
                    }
                    else 
                    {
                        inCredentials.DangerousRelease(); 
                    } 

                    outContext.DangerousRelease(); 

                    // The idea is that SSPI has allocated a block and filled up outUnmanagedBuffer+8 slot with the pointer.
                    if (handleTemplate != null)
                    { 
                        handleTemplate.Set(((SecurityBufferStruct*)outputBuffer.UnmanagedPointer)->token); //ATTN: on 64 BIT that is still +8 cause of 2* c++ unsigned long == 8 bytes
                        if (handleTemplate.IsInvalid) 
                        { 
                            handleTemplate.SetHandleAsInvalid();
                        } 
                    }
                }

                if (inContextPtr == null && (errorCode & 0x80000000) != 0) 
                {
                    // an error on the first call, need to set the out handle to invalid value 
                    outContext._handle.SetToInvalid(); 
                }
            } 

            return errorCode;
        }
 
        //
        // 
        // 
        internal unsafe static int CompleteAuthToken(
            SecurDll                dll, 
            ref SafeDeleteContext   refContext,
            SecurityBuffer[]        inSecBuffers) {

            GlobalLog.Enter("SafeDeleteContext::CompleteAuthToken"); 
            GlobalLog.Print("    DLL              = " + dll);
            GlobalLog.Print("    refContext       = " + ValidationHelper.ToString(refContext)); 
#if TRAVE 
            GlobalLog.Print("    inSecBuffers[]   = length:" + inSecBuffers.Length);
//            for (int index=0; index(ref m_InnerSocket, null);
            if (innerSocket != null) 
            {
                innerSocket.DangerousRelease();
            }
            return true; 
        }
 
        internal void CloseAsIs() 
        {
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try { }
            finally
            {
#if DEBUG 
                // If this throws it could be very bad.
                try 
                { 
#endif
                InnerSafeCloseSocket innerSocket = m_InnerSocket == null ? null : Interlocked.Exchange(ref m_InnerSocket, null); 
                Close();
                if (innerSocket != null)
                {
                    // Wait until it's safe. 
                    while (!m_Released)
                    { 
                        Thread.SpinWait(1); 
                    }
 
                    // Now free it with blocking.
                    innerSocket.BlockingRelease();
                }
#if DEBUG 
                }
                catch (Exception exception) 
                { 
                    if (!NclUtilities.IsFatal(exception)){
                        GlobalLog.Assert("SafeCloseSocket::CloseAsIs(handle:" + handle.ToString("x") + ")", exception.Message); 
                    }
                    throw;
                }
#endif 
            }
        } 
 
        internal class InnerSafeCloseSocket : SafeHandleMinusOneIsInvalid
        { 
            protected InnerSafeCloseSocket() : base(true) { }

            private static readonly byte [] tempBuffer = new byte[1];
            private bool m_Blockable; 

            public override bool IsInvalid { 
                [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
                get {
                    return IsClosed || base.IsInvalid; 
                }
            }

            // This method is implicitly reliable and called from a CER. 
            protected override bool ReleaseHandle()
            { 
                bool ret = false; 

#if DEBUG 
                try
                {
#endif
                GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ")"); 

                SocketError errorCode; 
 
                // If m_Blockable was set in BlockingRelease, it's safe to block here, which means
                // we can honor the linger options set on the socket.  It also means closesocket() might return WSAEWOULDBLOCK, in which 
                // case we need to do some recovery.
                if (m_Blockable)
                {
                    GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") Following 'blockable' branch."); 

                    errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle); 
#if DEBUG 
                    m_CloseSocketHandle = handle;
                    m_CloseSocketResult = errorCode; 
#endif
                    if (errorCode == SocketError.SocketError) errorCode = (SocketError) Marshal.GetLastWin32Error();
                    GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket()#1:" + errorCode.ToString());
 
                    // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed.
                    if (errorCode != SocketError.WouldBlock) 
                    { 
                        return ret = errorCode == SocketError.Success;
                    } 

                    // The socket must be non-blocking with a linger timeout set.
                    // We have to set the socket to blocking.
                    int nonBlockCmd = 0; 
                    errorCode = UnsafeNclNativeMethods.SafeNetHandles.ioctlsocket(
                        handle, 
                        IoctlSocketConstants.FIONBIO, 
                        ref nonBlockCmd);
                    if (errorCode == SocketError.SocketError) errorCode = (SocketError) Marshal.GetLastWin32Error(); 
                    GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket()#1:" + errorCode.ToString());

                    // This can fail if there's a pending WSAEventSelect.  Try canceling it.
                    if (errorCode == SocketError.InvalidArgument) 
                    {
                        errorCode = UnsafeNclNativeMethods.SafeNetHandles.WSAEventSelect( 
                            handle, 
                            IntPtr.Zero,
                            AsyncEventBits.FdNone); 
                        GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") WSAEventSelect():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString());

                        // Now retry the ioctl.
                        errorCode = UnsafeNclNativeMethods.SafeNetHandles.ioctlsocket( 
                            handle,
                            IoctlSocketConstants.FIONBIO, 
                            ref nonBlockCmd); 
                        GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") ioctlsocket#2():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString());
                    } 

                    // If that succeeded, try again.
                    if (errorCode == SocketError.Success)
                    { 
                        errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle);
#if DEBUG 
                        m_CloseSocketHandle = handle; 
                        m_CloseSocketResult = errorCode;
#endif 
                        if (errorCode == SocketError.SocketError) errorCode = (SocketError) Marshal.GetLastWin32Error();
                        GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#2():" + errorCode.ToString());

                        // If it's not WSAEWOULDBLOCK, there's no more recourse - we either succeeded or failed. 
                        if (errorCode != SocketError.WouldBlock)
                        { 
                            return ret = errorCode == SocketError.Success; 
                        }
                    } 

                    // It failed.  Fall through to the regular abortive close.
                }
 
                // By default or if CloseAsIs() path failed, set linger timeout to zero to get an abortive close (RST).
                Linger lingerStruct; 
                lingerStruct.OnOff = 1; 
                lingerStruct.Time = 0;
 
                errorCode = UnsafeNclNativeMethods.SafeNetHandles.setsockopt(
                    handle,
                    SocketOptionLevel.Socket,
                    SocketOptionName.Linger, 
                    ref lingerStruct,
                    4); 
#if DEBUG 
                m_CloseSocketLinger = errorCode;
#endif 
                if (errorCode == SocketError.SocketError) errorCode = (SocketError) Marshal.GetLastWin32Error();
                GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") setsockopt():" + errorCode.ToString());

                if (errorCode != SocketError.Success && errorCode != SocketError.InvalidArgument && errorCode != SocketError.ProtocolOption) 
                {
                    // Too dangerous to try closesocket() - it might block! 
                    return ret = false; 
                }
 
                errorCode = UnsafeNclNativeMethods.SafeNetHandles.closesocket(handle);
#if DEBUG
                m_CloseSocketHandle = handle;
                m_CloseSocketResult = errorCode; 
#endif
                GlobalLog.Print("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ") closesocket#3():" + (errorCode == SocketError.SocketError ? (SocketError)Marshal.GetLastWin32Error() : errorCode).ToString()); 
 
                return ret = errorCode == SocketError.Success;
#if DEBUG 
                }
                catch (Exception exception)
                {
                    if (!NclUtilities.IsFatal(exception)){ 
                        GlobalLog.Assert("SafeCloseSocket::ReleaseHandle(handle:" + handle.ToString("x") + ")", exception.Message);
                    } 
                    ret = true;  // Avoid a second assert. 
                    throw;
                } 
                finally
                {
                    m_CloseSocketThread = Thread.CurrentThread.ManagedThreadId;
                    m_CloseSocketTick = Environment.TickCount; 
                    GlobalLog.Assert(ret, "SafeCloseSocket::ReleaseHandle(handle:{0:x})|ReleaseHandle failed.", handle);
                } 
#endif 
            }
 
#if DEBUG
            private IntPtr m_CloseSocketHandle;
            private SocketError m_CloseSocketResult = unchecked((SocketError) 0xdeadbeef);
            private SocketError m_CloseSocketLinger = unchecked((SocketError) 0xdeadbeef); 
            private int m_CloseSocketThread;
            private int m_CloseSocketTick; 
#endif 

            // Use this method to close the socket handle using the linger options specified on the socket. 
            // Guaranteed to only be called once, under a CER, and not if regular DangerousRelease is called.
            [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
            internal void BlockingRelease()
            { 
                m_Blockable = true;
                DangerousRelease(); 
            } 

            internal unsafe static InnerSafeCloseSocket CreateWSASocket(byte* pinnedBuffer) 
            {
                //-1 is the value for FROM_PROTOCOL_INFO
                InnerSafeCloseSocket result = UnsafeNclNativeMethods.OSSOCK.WSASocket((AddressFamily) (-1),(SocketType) (-1),(ProtocolType) (-1), pinnedBuffer, 0, SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
                if (result.IsInvalid) { 
                    result.SetHandleAsInvalid();
                } 
                return result; 
            }
 
            internal static InnerSafeCloseSocket CreateWSASocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
            {
                InnerSafeCloseSocket result = UnsafeNclNativeMethods.OSSOCK.WSASocket(addressFamily, socketType, protocolType, IntPtr.Zero, 0, SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
                if (result.IsInvalid) { 
                    result.SetHandleAsInvalid();
                } 
                return result; 
            }
 
            internal static InnerSafeCloseSocket Accept(SafeCloseSocket socketHandle, byte[] socketAddress, ref int socketAddressSize)
            {
                InnerSafeCloseSocket result = UnsafeNclNativeMethods.SafeNetHandles.accept(socketHandle.DangerousGetHandle(), socketAddress, ref socketAddressSize);
                if (result.IsInvalid) { 
                    result.SetHandleAsInvalid();
                } 
                return result; 
            }
        } 
    }


    [SuppressUnmanagedCodeSecurity] 
    internal sealed class SafeCloseSocketAndEvent: SafeCloseSocket {
        internal SafeCloseSocketAndEvent() : base() {} 
        private AutoResetEvent waitHandle; 

        override protected bool ReleaseHandle() 
        {
            bool result = base.ReleaseHandle();
            DeleteEvent();
            return result; 
         }
 
        internal static SafeCloseSocketAndEvent CreateWSASocketWithEvent(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType, bool autoReset, bool signaled){ 
            SafeCloseSocketAndEvent result = new SafeCloseSocketAndEvent();
            CreateSocket(InnerSafeCloseSocket.CreateWSASocket(addressFamily, socketType, protocolType), result); 
            if (result.IsInvalid) {
                throw new SocketException();
            }
 
            result.waitHandle = new AutoResetEvent(false);
            CompleteInitialization(result); 
            return result; 
        }
 
        internal static void CompleteInitialization(SafeCloseSocketAndEvent socketAndEventHandle){
            SafeWaitHandle handle = socketAndEventHandle.waitHandle.SafeWaitHandle;
            bool b = false;
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try
            { 
                handle.DangerousAddRef(ref b); 
            }
            catch 
            {
                if (b)
                {
                    handle.DangerousRelease(); 
                    socketAndEventHandle.waitHandle = null;
                    b = false; 
                } 
            }
            finally 
            {
                if (b)
                {
                    handle.Dispose(); 
                }
            } 
        } 

 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        private void DeleteEvent(){
            try{
                if(waitHandle != null){ 
                    waitHandle.SafeWaitHandle.DangerousRelease();
                } 
            } 
            catch{
            } 
        }

        internal WaitHandle GetEventHandle(){
            return waitHandle; 
        }
    } 
 
    // Based on SafeLocalFree
    [SuppressUnmanagedCodeSecurity] 
    internal class SafeLocalFreeChannelBinding : ChannelBinding
    {
        private const int LMEM_FIXED = 0;
        private int size; 

        public override int Size 
        { 
            get { return size; }
        } 

        public static SafeLocalFreeChannelBinding LocalAlloc(int cb)
        {
            SafeLocalFreeChannelBinding result; 

            result = UnsafeNclNativeMethods.SafeNetHandles.LocalAllocChannelBinding(LMEM_FIXED, (UIntPtr)cb); 
            if (result.IsInvalid) 
            {
                result.SetHandleAsInvalid(); 
                throw new OutOfMemoryException();
            }

            result.size = cb; 
            return result;
        } 
 
        override protected bool ReleaseHandle()
        { 
            return UnsafeNclNativeMethods.SafeNetHandles.LocalFree(handle) == IntPtr.Zero;
        }
    }
 
    // Based on SafeFreeContextBuffer
    [SuppressUnmanagedCodeSecurity] 
    internal abstract class SafeFreeContextBufferChannelBinding : ChannelBinding 
    {
        private int size; 

        public override int Size
        {
            get { return size; } 
        }
 
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
        internal unsafe void Set(IntPtr value)
        { 
            this.handle = value;
        }

        internal static SafeFreeContextBufferChannelBinding CreateEmptyHandle(SecurDll dll) 
        {
            switch (dll) 
            { 
                case SecurDll.SECURITY: return new SafeFreeContextBufferChannelBinding_SECURITY();
                case SecurDll.SECUR32: return new SafeFreeContextBufferChannelBinding_SECUR32(); 
                case SecurDll.SCHANNEL: return new SafeFreeContextBufferChannelBinding_SCHANNEL();
                default: throw new ArgumentException(SR.GetString(SR.net_invalid_enum, "SecurDll"), "dll");
            }
        } 

        public unsafe static int QueryContextChannelBinding(SecurDll dll, SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle) 
        { 
            switch (dll)
            { 
                case SecurDll.SECURITY:
                    return QueryContextChannelBinding_SECURITY(phContext, contextAttribute, buffer, refHandle);

                case SecurDll.SECUR32: 
                    return QueryContextChannelBinding_SECUR32(phContext, contextAttribute, buffer, refHandle);
 
                case SecurDll.SCHANNEL: 
                    return QueryContextChannelBinding_SCHANNEL(phContext, contextAttribute, buffer, refHandle);
 
                default:
                    return -1;
            }
        } 

        private unsafe static int QueryContextChannelBinding_SECURITY(SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle) 
        { 
            int status = (int)SecurityStatus.InvalidHandle;
            bool b = false; 

            // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit
            // one of the following methods. So run within a CER non-interruptible block.
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                phContext.DangerousAddRef(ref b); 
            } 
            catch(Exception e) {
                if (b) 
                {
                    phContext.DangerousRelease();
                    b = false;
                } 
                if (!(e is ObjectDisposedException))
                    throw; 
            } 
            finally {
 
                if (b)
                {
                    status = UnsafeNclNativeMethods.SafeNetHandles_SECURITY.QueryContextAttributesW(ref phContext._handle, contextAttribute, buffer);
                    phContext.DangerousRelease(); 
                }
 
                if (status == 0 && refHandle != null) { 
                    refHandle.Set((*buffer).pBindings);
                    refHandle.size = (*buffer).BindingsLength; 
                }

                if (status != 0 && refHandle != null) {
                    refHandle.SetHandleAsInvalid(); 
                }
            } 
 
            return status;
        } 

        private unsafe static int QueryContextChannelBinding_SECUR32(SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle)
        {
            int status = (int)SecurityStatus.InvalidHandle; 
            bool b = false;
 
            // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit 
            // one of the following methods. So run within a CER non-interruptible block.
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {
                phContext.DangerousAddRef(ref b);
            }
            catch(Exception e) { 
                if (b)
                { 
                    phContext.DangerousRelease(); 
                    b = false;
                } 
                if (!(e is ObjectDisposedException))
                    throw;
            }
            finally { 

                if (b) 
                { 
                    status = UnsafeNclNativeMethods.SafeNetHandles_SECUR32.QueryContextAttributesA(ref phContext._handle, contextAttribute, buffer);
                    phContext.DangerousRelease(); 
                }

                if (status == 0 && refHandle != null) {
                    refHandle.Set((*buffer).pBindings); 
                    refHandle.size = (*buffer).BindingsLength;
                } 
 
                if (status != 0 && refHandle != null) {
                    refHandle.SetHandleAsInvalid(); 
                }
            }

            return status; 
        }
 
        private unsafe static int QueryContextChannelBinding_SCHANNEL(SafeDeleteContext phContext, ContextAttribute contextAttribute, Bindings* buffer, SafeFreeContextBufferChannelBinding refHandle) 
        {
            int status = (int)SecurityStatus.InvalidHandle; 
            bool b = false;

            // We don't want to be interrupted by thread abort exceptions or unexpected out-of-memory errors failing to jit
            // one of the following methods. So run within a CER non-interruptible block. 
            RuntimeHelpers.PrepareConstrainedRegions();
            try { 
                phContext.DangerousAddRef(ref b); 
            }
            catch(Exception e) { 
                if (b)
                {
                    phContext.DangerousRelease();
                    b = false; 
                }
                if (!(e is ObjectDisposedException)) 
                    throw; 
            }
            finally { 

                if (b)
                {
                    status = UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.QueryContextAttributesA(ref phContext._handle, contextAttribute, buffer); 
                    phContext.DangerousRelease();
                } 
 
                if (status == 0 && refHandle != null) {
                    refHandle.Set((*buffer).pBindings); 
                    refHandle.size = (*buffer).BindingsLength;
                }

                if (status != 0 && refHandle != null) { 
                    refHandle.SetHandleAsInvalid();
                } 
            } 

            return status; 
        }
    }

    [SuppressUnmanagedCodeSecurity] 
    internal sealed class SafeFreeContextBufferChannelBinding_SECURITY : SafeFreeContextBufferChannelBinding
    { 
        override protected bool ReleaseHandle() 
        {
            return UnsafeNclNativeMethods.SafeNetHandles_SECURITY.FreeContextBuffer(handle) == 0; 
        }

    }
 
    [SuppressUnmanagedCodeSecurity]
    internal sealed class SafeFreeContextBufferChannelBinding_SCHANNEL : SafeFreeContextBufferChannelBinding 
    { 
        override protected bool ReleaseHandle()
        { 
            return UnsafeNclNativeMethods.SafeNetHandles_SCHANNEL.FreeContextBuffer(handle) == 0;
        }
    }
 
    [SuppressUnmanagedCodeSecurity]
    internal sealed class SafeFreeContextBufferChannelBinding_SECUR32 : SafeFreeContextBufferChannelBinding 
    { 
        override protected bool ReleaseHandle()
        { 
            return UnsafeNclNativeMethods.SafeNetHandles_SECUR32.FreeContextBuffer(handle) == 0;
        }
    }
 
#if !FEATURE_PAL
 
    /////////////////////////////////////////////////////////////// 
    //
    // This class implements a safe handle for WinInet cache stream 
    //
    ///////////////////////////////////////////////////////////////
#if DEBUG
    internal sealed class SafeUnlockUrlCacheEntryFile : DebugSafeHandle { 
#else
    internal sealed class SafeUnlockUrlCacheEntryFile : SafeHandleZeroOrMinusOneIsInvalid { 
#endif 
        private string      m_KeyString;
 
        private SafeUnlockUrlCacheEntryFile(string keyString): base(true) {
            m_KeyString = keyString;
        }
 
#if DEBUG
        //This method should never be called for this type 
        public new IntPtr DangerousGetHandle() 
        {
            throw new InvalidOperationException(); 
        }
#endif

        override unsafe protected bool ReleaseHandle() 
        {
            fixed (char *ptrStr = m_KeyString) { 
                UnsafeNclNativeMethods.SafeNetHandles.UnlockUrlCacheEntryFileW(ptrStr, 0); 
            }
            SetHandle(IntPtr.Zero); 
            m_KeyString = null;
            return true;
        }
 
        internal unsafe static _WinInetCache.Status GetAndLockFile(string key, byte* entryPtr, ref int entryBufSize, out SafeUnlockUrlCacheEntryFile handle) {
 
            if (ValidationHelper.IsBlankString(key)) { 
                throw new ArgumentNullException("key");
            } 

            handle = new SafeUnlockUrlCacheEntryFile(key);
            fixed (char* keyPtr = key) {
                return MustRunGetAndLockFile(keyPtr, entryPtr, ref entryBufSize, handle); 
            }
 
        } 
        //
        // Whis will check the result from PInvoke and make a valid safeHandle on success 
        //
        unsafe private static _WinInetCache.Status MustRunGetAndLockFile(char* key, byte* entryPtr, ref int entryBufSize, SafeUnlockUrlCacheEntryFile handle) {
            _WinInetCache.Status error = _WinInetCache.Status.Success;
 
            // Run the body of this method as a non-interruptible block.
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try {} finally { 

                if (!UnsafeNclNativeMethods.SafeNetHandles.RetrieveUrlCacheEntryFileW(key, entryPtr, ref entryBufSize, 0)) 
                {
                    error = (_WinInetCache.Status)Marshal.GetLastWin32Error();
                    handle.SetHandleAsInvalid();
                } 
                else {
                    // Hack: that will return 1 in place of a handle 
                    // The real handle here is a "key" string 
                    handle.SetHandle((IntPtr)1);
                } 
            }

            return error;
        } 

    } 
 

    [System.Security.SuppressUnmanagedCodeSecurityAttribute()] 
    internal sealed unsafe class SafeRegistryHandle :
#if DEBUG
    DebugSafeHandle
#else 
    SafeHandleZeroOrMinusOneIsInvalid
#endif 
    { 
        private SafeRegistryHandle() : base(true) { }
 
        internal static uint RegOpenKeyEx(IntPtr key, string subKey, uint ulOptions, uint samDesired, out SafeRegistryHandle resultSubKey)
        {
            return UnsafeNclNativeMethods.RegistryHelper.RegOpenKeyEx(key, subKey, ulOptions, samDesired, out resultSubKey);
        } 

        internal uint RegOpenKeyEx(string subKey, uint ulOptions, uint samDesired, out SafeRegistryHandle resultSubKey) 
        { 
            return UnsafeNclNativeMethods.RegistryHelper.RegOpenKeyEx(this, subKey, ulOptions, samDesired, out resultSubKey);
        } 

        internal uint RegCloseKey()
        {
            Close(); 
            return resClose;
        } 
 
        internal uint QueryValue(string name, out object data)
        { 
            data = null;

            byte[] blob = null;
            uint size = 0; 
            uint type;
            uint errorCode; 
 
            while (true)
            { 
                errorCode = UnsafeNclNativeMethods.RegistryHelper.RegQueryValueEx(this, name, IntPtr.Zero, out type, blob, ref size);
                if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA &&
                    (blob != null || errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS))
                { 
                    break;
                } 
 
                blob = new byte[size];
            } 

            if (errorCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
            {
                return errorCode; 
            }
 
            switch (type) 
            {
                case UnsafeNclNativeMethods.RegistryHelper.REG_BINARY: 
                    if (size != blob.Length)
                    {
                        byte[] oldBlob = blob;
                        blob = new byte[size]; 
                        Buffer.BlockCopy(oldBlob, 0, blob, 0, (int) size);
                    } 
                    data = blob; 
                    return UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS;
 
                default:
                    return UnsafeNclNativeMethods.ErrorCodes.ERROR_NOT_SUPPORTED;
            }
        } 

        internal uint RegNotifyChangeKeyValue(bool watchSubTree, uint notifyFilter, SafeWaitHandle regEvent, bool async) 
        { 
            return UnsafeNclNativeMethods.RegistryHelper.RegNotifyChangeKeyValue(this, watchSubTree, notifyFilter, regEvent, async);
        } 

        internal static uint RegOpenCurrentUser(uint samDesired, out SafeRegistryHandle resultKey)
        {
            if (ComNetOS.IsWin9x) { 
                return UnsafeNclNativeMethods.RegistryHelper.RegOpenKeyEx(UnsafeNclNativeMethods.RegistryHelper.HKEY_CURRENT_USER, null, 0, samDesired, out resultKey);
            } 
            else { 
                return UnsafeNclNativeMethods.RegistryHelper.RegOpenCurrentUser(samDesired, out resultKey);
            } 
        }


        override protected bool ReleaseHandle() 
        {
            if(!IsInvalid) 
                resClose = UnsafeNclNativeMethods.RegistryHelper.RegCloseKey(handle); 
            SetHandleAsInvalid();
            return true; 
        }

        private uint resClose;
    } 
#endif // !FEATURE_PAL
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK