File: System\ServiceModel\Activation\SharedMemory.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------------------
 
namespace System.ServiceModel.Activation
{
    using System;
    using System.Collections.Generic;
    using System.Runtime;
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning;
    using System.Security;
    using System.Security.Principal;
    using System.Security.Permissions;
    using System.ServiceModel.Channels;
    using System.Threading;
    using System.ServiceModel;
    using System.ComponentModel;
 
    unsafe class SharedMemory : IDisposable
    {
        SafeFileMappingHandle fileMapping;
 
        SharedMemory(SafeFileMappingHandle fileMapping)
        {
            this.fileMapping = fileMapping;
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        public static unsafe SharedMemory Create(string name, Guid content, List<SecurityIdentifier> allowedSids)
        {
            int errorCode = UnsafeNativeMethods.ERROR_SUCCESS;
            byte[] binarySecurityDescriptor = SecurityDescriptorHelper.FromSecurityIdentifiers(allowedSids, UnsafeNativeMethods.GENERIC_READ);
            SafeFileMappingHandle fileMapping;
            UnsafeNativeMethods.SECURITY_ATTRIBUTES securityAttributes = new UnsafeNativeMethods.SECURITY_ATTRIBUTES();
            fixed (byte* pinnedSecurityDescriptor = binarySecurityDescriptor)
            {
                securityAttributes.lpSecurityDescriptor = (IntPtr)pinnedSecurityDescriptor;
                fileMapping = UnsafeNativeMethods.CreateFileMapping((IntPtr)(-1), securityAttributes, UnsafeNativeMethods.PAGE_READWRITE, 0, sizeof(SharedMemoryContents), name);
                errorCode = Marshal.GetLastWin32Error();
            }
 
            if (fileMapping.IsInvalid)
            {
                fileMapping.SetHandleAsInvalid();
                fileMapping.Close();
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
            }
 
            SharedMemory sharedMemory = new SharedMemory(fileMapping);
            SafeViewOfFileHandle view;
 
            // Ignore return value.
            GetView(fileMapping, true, out view);
 
            try
            {
                SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
                contents->pipeGuid = content;
                Thread.MemoryBarrier();
                contents->isInitialized = true;
                return sharedMemory;
            }
            finally
            {
                view.Close();
            }
        }
 
        public void Dispose()
        {
            if (fileMapping != null)
            {
                fileMapping.Close();
                fileMapping = null;
            }
        }
 
        static bool GetView(SafeFileMappingHandle fileMapping, bool writable, out SafeViewOfFileHandle handle)
        {
            handle = UnsafeNativeMethods.MapViewOfFile(fileMapping, writable ? UnsafeNativeMethods.FILE_MAP_WRITE : UnsafeNativeMethods.FILE_MAP_READ, 0, 0, (IntPtr)sizeof(SharedMemoryContents));
            int errorCode = Marshal.GetLastWin32Error();
            if (!handle.IsInvalid)
            {
                return true;
            }
            else
            {
                handle.SetHandleAsInvalid();
                fileMapping.Close();
 
                // Only return false when it's reading time.
                if (!writable && errorCode == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
                {
                    return false;
                }
 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
            }
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        public static string Read(string name)
        {
            string content;
            if (Read(name, out content))
            {
                return content;
            }
 
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(UnsafeNativeMethods.ERROR_FILE_NOT_FOUND));
        }
 
        [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical]
        [ResourceConsumption(ResourceScope.Machine)]
        public static bool Read(string name, out string content)
        {
            content = null;
 
            SafeFileMappingHandle fileMapping = UnsafeNativeMethods.OpenFileMapping(UnsafeNativeMethods.FILE_MAP_READ, false, ListenerConstants.GlobalPrefix + name);
            int errorCode = Marshal.GetLastWin32Error();
            if (fileMapping.IsInvalid)
            {
                fileMapping.SetHandleAsInvalid();
                fileMapping.Close();
                if (errorCode == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND)
                {
                    return false;
                }
 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(errorCode));
            }
 
            try
            {
                SafeViewOfFileHandle view;
                if (!GetView(fileMapping, false, out view))
                {
                    return false;
                }
 
                try
                {
                    SharedMemoryContents* contents = (SharedMemoryContents*)view.DangerousGetHandle();
                    content = contents->isInitialized ? contents->pipeGuid.ToString() : null;
                    return true;
                }
                finally
                {
                    view.Close();
                }
            }
            finally
            {
                fileMapping.Close();
            }
        }
 
        [StructLayout(LayoutKind.Sequential)]
        struct SharedMemoryContents
        {
            public bool isInitialized;
            public Guid pipeGuid;
        }
    }
}