File: System\ServiceModel\Activation\ListenerAdapterBase.cs
Project: ndp\cdf\src\WCF\SMSvcHost\SMSvcHost.csproj (SMSvcHost)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
namespace System.ServiceModel.Activation
{
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Globalization;
    using System.Runtime;
    using System.Runtime.Diagnostics;
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning;
    using System.Security.Principal;
    using System.ServiceModel;
    using System.ServiceModel.Activation.Diagnostics;    
    using System.ServiceModel.Diagnostics;    
    using System.Threading;    
 
    abstract class ListenerAdapterBase
    {
        WebHostUnsafeNativeMethods.WebhostListenerCallbacks listenerCallbacks;
        int protocolHandle = 0;
        int closed;
 
        const int WebhostMajorVersion = 7;
        const int WebhostMinorVersion = 0;
        static WebHostUnsafeNativeMethods.SafeFreeLibrary webHostIpm;
        static WebHostUnsafeNativeMethods.WebhostGetVersion webhostGetVersion;
        static WebHostUnsafeNativeMethods.WebhostRegisterProtocol webhostRegisterProtocol;
        static WebHostUnsafeNativeMethods.WebhostOpenListenerChannelInstance webhostOpenListenerChannelInstance;
        static WebHostUnsafeNativeMethods.WebhostCloseAllListenerChannelInstances webhostCloseAllListenerChannelInstances;
        static WebHostUnsafeNativeMethods.WebhostUnregisterProtocol webhostUnregisterProtocol;
        EventTraceActivity eventTraceActivity;
 
        [ResourceConsumption(ResourceScope.Process)]
        static ListenerAdapterBase()
        {
#pragma warning suppress 56523 // Microsoft, the Win32Exception ctor calls Marshal.GetLastWin32Error
            webHostIpm = WebHostUnsafeNativeMethods.LoadLibraryEx(SMSvcHost.ListenerAdapterNativeLibrary, IntPtr.Zero, WebHostUnsafeNativeMethods.LOAD_WITH_ALTERED_SEARCH_PATH);
            if (webHostIpm.IsInvalid)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception());
            }
 
            webhostGetVersion = (WebHostUnsafeNativeMethods.WebhostGetVersion)GetProcDelegate<WebHostUnsafeNativeMethods.WebhostGetVersion>(webHostIpm, "WebhostGetVersion");
            webhostRegisterProtocol = (WebHostUnsafeNativeMethods.WebhostRegisterProtocol)GetProcDelegate<WebHostUnsafeNativeMethods.WebhostRegisterProtocol>(webHostIpm, "WebhostRegisterProtocol");
            webhostUnregisterProtocol = (WebHostUnsafeNativeMethods.WebhostUnregisterProtocol)GetProcDelegate<WebHostUnsafeNativeMethods.WebhostUnregisterProtocol>(webHostIpm, "WebhostUnregisterProtocol");
            webhostOpenListenerChannelInstance = (WebHostUnsafeNativeMethods.WebhostOpenListenerChannelInstance)GetProcDelegate<WebHostUnsafeNativeMethods.WebhostOpenListenerChannelInstance>(webHostIpm, "WebhostOpenListenerChannelInstance");
            webhostCloseAllListenerChannelInstances = (WebHostUnsafeNativeMethods.WebhostCloseAllListenerChannelInstances)GetProcDelegate<WebHostUnsafeNativeMethods.WebhostCloseAllListenerChannelInstances>(webHostIpm,
                "WebhostCloseAllListenerChannelInstances");
        }
 
        protected ListenerAdapterBase(string protocolName)
        {
            if (string.IsNullOrEmpty(protocolName))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("protocolName"));
            }
            this.ProtocolName = protocolName;
            listenerCallbacks = new WebHostUnsafeNativeMethods.WebhostListenerCallbacks();
            listenerCallbacks.dwBytesInCallbackStructure = Marshal.SizeOf(listenerCallbacks);
            listenerCallbacks.webhostListenerConfigManagerConnected = new WebHostUnsafeNativeMethods.WebhostListenerConfigManagerConnected(onConfigManagerConnected);
            listenerCallbacks.webhostListenerConfigManagerDisconnected = new WebHostUnsafeNativeMethods.WebhostListenerConfigManagerDisconnected(onConfigManagerDisconnected);
            listenerCallbacks.webhostListenerConfigManagerInitializationCompleted = new WebHostUnsafeNativeMethods.WebhostListenerConfigManagerInitializationCompleted(onConfigManagerInitializationCompleted);
            listenerCallbacks.webhostListenerApplicationPoolCreated = new WebHostUnsafeNativeMethods.WebhostListenerApplicationPoolCreated(onApplicationPoolCreated);
            listenerCallbacks.webhostListenerApplicationPoolDeleted = new WebHostUnsafeNativeMethods.WebhostListenerApplicationPoolDeleted(onApplicationPoolDeleted);
            listenerCallbacks.webhostListenerApplicationPoolIdentityChanged = new WebHostUnsafeNativeMethods.WebhostListenerApplicationPoolIdentityChanged(onApplicationPoolIdentityChanged);
            listenerCallbacks.webhostListenerApplicationPoolStateChanged = new WebHostUnsafeNativeMethods.WebhostListenerApplicationPoolStateChanged(onApplicationPoolStateChanged);
            listenerCallbacks.webhostListenerApplicationPoolCanOpenNewListenerChannelInstance = new WebHostUnsafeNativeMethods.WebhostListenerApplicationPoolCanOpenNewListenerChannelInstance(onApplicationPoolCanLaunchQueueInstance);
            listenerCallbacks.webhostListenerApplicationPoolAllListenerChannelInstancesStopped = new WebHostUnsafeNativeMethods.WebhostListenerApplicationPoolAllListenerChannelInstancesStopped(onApplicationPoolAllQueueInstancesStopped);
            listenerCallbacks.webhostListenerApplicationCreated = new WebHostUnsafeNativeMethods.WebhostListenerApplicationCreated(onApplicationCreated);
            listenerCallbacks.webhostListenerApplicationDeleted = new WebHostUnsafeNativeMethods.WebhostListenerApplicationDeleted(onApplicationDeleted);
            listenerCallbacks.webhostListenerApplicationBindingsChanged = new WebHostUnsafeNativeMethods.WebhostListenerApplicationBindingsChanged(onApplicationBindingsChanged);
            listenerCallbacks.webhostListenerApplicationAppPoolChanged = new WebHostUnsafeNativeMethods.WebhostListenerApplicationAppPoolChanged(onApplicationAppPoolChanged);
            listenerCallbacks.webhostListenerApplicationRequestsBlockedChanged = new WebHostUnsafeNativeMethods.WebhostListenerApplicationRequestsBlockedChanged(onApplicationRequestsBlockedChanged);
        }
 
        protected string ProtocolName 
        {
            get;
            private set;
        }
 
        protected EventTraceActivity EventTraceActivity
        {
            get
            {
                if (this.eventTraceActivity == null)
                {
                    this.eventTraceActivity = new EventTraceActivity();
                }
                return this.eventTraceActivity;
            }
        }
 
 
        static Delegate GetProcDelegate<TDelegate>(WebHostUnsafeNativeMethods.SafeFreeLibrary library, string procName)
        {
#pragma warning suppress 56523 // Microsoft, the Win32Exception ctor calls Marshal.GetLastWin32Error
            IntPtr funcPtr = WebHostUnsafeNativeMethods.GetProcAddress(library, procName);
            if (funcPtr == IntPtr.Zero)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(SR.GetString(SR.WebHostProcNotFound,
                    procName, SMSvcHost.ListenerAdapterNativeLibrary)));
            }
 
            return Marshal.GetDelegateForFunctionPointer(funcPtr, typeof(TDelegate));
        }
 
        protected string[] ParseBindings(IntPtr bindingsMultiSz, int numberOfBindings)
        {
            if (bindingsMultiSz == IntPtr.Zero)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("bindingsMultiSz"));
            }
            if (numberOfBindings < 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException("numberOfBindings"));
            }
            string[] bindings = new string[numberOfBindings];
            unsafe
            {
                ushort* bindingsBufferPtr = (ushort*)bindingsMultiSz;
                for (int i = 0; i < numberOfBindings; i++)
                {
                    string bindingString = Marshal.PtrToStringUni((IntPtr)bindingsBufferPtr);
                    if (string.IsNullOrEmpty(bindingString))
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException("bindingsMultiSz"));
                    }
                    bindings[i] = bindingString;
                    bindingsBufferPtr += bindingString.Length + 1;
                }
            }
            return bindings;
        }
 
        void onApplicationAppPoolChanged(IntPtr context, string appKey, string appPoolId)
        {
            this.OnApplicationAppPoolChanged(appKey, appPoolId);
        }
        protected abstract void OnApplicationAppPoolChanged(string appKey, string appPoolId);
 
        void onApplicationBindingsChanged(IntPtr context, string appKey, IntPtr bindingsMultiSz, int numberOfBindings)
        {
            this.OnApplicationBindingsChanged(appKey, bindingsMultiSz, numberOfBindings);
        }
        protected abstract void OnApplicationBindingsChanged(string appKey, IntPtr bindingsMultiSz, int numberOfBindings);
 
        void onApplicationCreated(IntPtr context, string appKey, string path, int siteId, string appPoolId, IntPtr bindingsMultiSz, int numberOfBindings, bool requestsBlocked)
        {
            this.OnApplicationCreated(appKey, path, siteId, appPoolId, bindingsMultiSz, numberOfBindings, requestsBlocked);
        }
        protected abstract void OnApplicationCreated(string appKey, string path, int siteId, string appPoolId, IntPtr bindingsMultiSz, int numberOfBindings, bool requestsBlocked);
 
        void onApplicationDeleted(IntPtr context, string appKey)
        {
            this.OnApplicationDeleted(appKey);
        }
        protected abstract void OnApplicationDeleted(string appKey);
 
        void onApplicationPoolAllQueueInstancesStopped(IntPtr context, string appPoolId, int listenerChannelId)
        {
            this.OnApplicationPoolAllQueueInstancesStopped(appPoolId, listenerChannelId);
        }
        protected abstract void OnApplicationPoolAllQueueInstancesStopped(string appPoolId, int listenerChannelId);
 
        void onApplicationPoolCanLaunchQueueInstance(IntPtr context, string appPoolId, int listenerChannelId)
        {
            this.OnApplicationPoolCanLaunchQueueInstance(appPoolId, listenerChannelId);
        }
        protected abstract void OnApplicationPoolCanLaunchQueueInstance(string appPoolId, int listenerChannelId);
 
        void onApplicationPoolCreated(IntPtr context, string appPoolId, IntPtr sid)
        {
            this.OnApplicationPoolCreated(appPoolId, new SecurityIdentifier(sid));
        }
        protected abstract void OnApplicationPoolCreated(string appPoolId, SecurityIdentifier sid);
 
        void onApplicationPoolDeleted(IntPtr context, string appPoolId)
        {
            this.OnApplicationPoolDeleted(appPoolId);
        }
        protected abstract void OnApplicationPoolDeleted(string appPoolId);
 
        void onApplicationPoolIdentityChanged(IntPtr context, string appPoolId, IntPtr sid)
        {
            this.OnApplicationPoolIdentityChanged(appPoolId, new SecurityIdentifier(sid));
        }
        protected abstract void OnApplicationPoolIdentityChanged(string appPoolId, SecurityIdentifier sid);
 
        void onApplicationPoolStateChanged(IntPtr context, string appPoolId, bool isEnabled)
        {
            this.OnApplicationPoolStateChanged(appPoolId, isEnabled);
        }
        protected abstract void OnApplicationPoolStateChanged(string appPoolId, bool isEnabled);
 
        void onApplicationRequestsBlockedChanged(IntPtr context, string appKey, bool requestsBlocked)
        {
            this.OnApplicationRequestsBlockedChanged(appKey, requestsBlocked);
        }
        protected abstract void OnApplicationRequestsBlockedChanged(string appKey, bool requestsBlocked);
 
        void onConfigManagerConnected(IntPtr context)
        {
            this.OnConfigManagerConnected();
        }
 
        protected abstract void OnConfigManagerConnected();
 
        void onConfigManagerDisconnected(IntPtr context, int hresult)
        {
            this.OnConfigManagerDisconnected(hresult);
        }
        protected abstract void OnConfigManagerDisconnected(int hresult);
 
        void onConfigManagerInitializationCompleted(IntPtr context)
        {
            this.OnConfigManagerInitializationCompleted();
        }
        protected abstract void OnConfigManagerInitializationCompleted();
 
        protected void Close()
        {
            if (Interlocked.Increment(ref closed) > 1)
            {
                return;
            }
            int hresult = webhostUnregisterProtocol(protocolHandle);
            if (hresult != 0)
            {
                if (DiagnosticUtility.ShouldTraceError)
                {
                    ListenerTraceUtility.TraceEvent(TraceEventType.Error, ListenerTraceCode.WasWebHostAPIFailed, SR.GetString(SR.TraceCodeWasWebHostAPIFailed), 
                        new StringTraceRecord("HRESULT", SR.GetString(SR.TraceCodeWasWebHostAPIFailed, "WebhostUnregisterProtocol",
                        hresult.ToString(CultureInfo.CurrentCulture))), this, null);
                }
            }
            if (TD.WebhostUnregisterProtocolFailedIsEnabled())
            {
                //TraceCodeWasWebHostAPIFailed
                TD.WebhostUnregisterProtocolFailed(this.EventTraceActivity, hresult.ToString(CultureInfo.CurrentCulture));
            }
        }
 
        protected int OpenListenerChannelInstance(string appPoolId, int listenerChannelId, byte[] queueBlob)
        {
            Fx.Assert(appPoolId != null, "");
 
            int queueBlobLength = (queueBlob != null) ? queueBlob.Length : 0;
            return webhostOpenListenerChannelInstance(protocolHandle, appPoolId, listenerChannelId, queueBlob, queueBlobLength);
        }
 
        internal virtual void Open()
        {
            int major, minor;
            int hresult = webhostGetVersion(out major, out minor);
            if (hresult != 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(hresult));
            }
 
            if (major != WebhostMajorVersion ||
                minor != WebhostMinorVersion)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new PlatformNotSupportedException(
                    SR.GetString(SR.WebHostVersionMismatch, WebhostMajorVersion, WebhostMinorVersion,
                    major, minor)));
            }
 
            hresult = webhostRegisterProtocol(ProtocolName, ref listenerCallbacks, IntPtr.Zero, out protocolHandle);
            if (hresult != 0 || protocolHandle == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new Win32Exception(hresult));
            }
        }
 
        protected int CloseAllListenerChannelInstances(string appPoolId, int listenerChannelId)
        {
            if (string.IsNullOrEmpty(appPoolId))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("appPoolId"));
            }
            return webhostCloseAllListenerChannelInstances(protocolHandle, appPoolId, listenerChannelId);
        }
    }
}