ChannelServices.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / clr / src / BCL / System / Runtime / Remoting / ChannelServices.cs / 2 / ChannelServices.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//* File:    Channel.cs
//* 
//* Author:  [....] Anand (TarunA) 
//*
//* Purpose: Defines the general purpose remoting proxy 
//*
//* Date:    May 27, 1999
//*
namespace System.Runtime.Remoting.Channels { 
    using System;
    using System.Collections; 
    using System.IO; 
    using System.Reflection;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices;
    using System.Runtime.Remoting;
    using System.Runtime.Remoting.Activation;
    using System.Runtime.Remoting.Messaging; 
    using System.Runtime.Remoting.Metadata;
    using System.Runtime.Remoting.Proxies; 
    using System.Threading; 
    using System.Security.Permissions;
    using System.Globalization; 

    // ChannelServices

    [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)] 
    internal struct Perf_Contexts {
        internal int cRemoteCalls; 
        internal int cChannels; 
    };
 
[System.Runtime.InteropServices.ComVisible(true)]
    public sealed class ChannelServices
    {
        // This gets refreshed when a channel is registered/unregistered. 
        private static Object[] s_currentChannelData = null;
 
        internal static Object[] CurrentChannelData 
        {
            get 
            {
                if (s_currentChannelData == null)
                    RefreshChannelData();
 
                return s_currentChannelData;
            } 
        } // CurrentChannelData 

 
        // hide the default constructor
        private ChannelServices()
        {
        } 

        // list of registered channels and a lock to take when adding or removing channels 
        private static Object s_channelLock = new Object(); 
        private static RegisteredChannelList s_registeredChannels = new RegisteredChannelList();
 

        // Private member variables
        // These have all been converted to getters and setters to get the effect of
        // per-AppDomain statics ( 

 
        private static long remoteCalls 
        {
            get { return Thread.GetDomain().RemotingData.ChannelServicesData.remoteCalls; } 
            set { Thread.GetDomain().RemotingData.ChannelServicesData.remoteCalls = value; }
        }

        private static IMessageSink xCtxChannel; 

 
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        static unsafe extern Perf_Contexts* GetPrivateContextsPerfCounters();
 
        unsafe private static Perf_Contexts *perf_Contexts = GetPrivateContextsPerfCounters();


        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 
        public static void RegisterChannel(IChannel chnl, bool ensureSecurity)
        { 
            RegisterChannelInternal(chnl, ensureSecurity); 
        }
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
        [Obsolete("Use System.Runtime.Remoting.ChannelServices.RegisterChannel(IChannel chnl, bool ensureSecurity) instead.", false)]
        public static void RegisterChannel(IChannel chnl)
        { 
            RegisterChannelInternal(chnl, false/*ensureSecurity*/);
        } 
 

        static bool unloadHandlerRegistered = false; 
        unsafe internal static void RegisterChannelInternal(IChannel chnl, bool ensureSecurity)
        {
            // Validate arguments
            if(null == chnl) 
            {
                throw new ArgumentNullException("chnl"); 
            } 

            bool fLocked = false; 
            RuntimeHelpers.PrepareConstrainedRegions();
            try
            {
                Monitor.ReliableEnter(s_channelLock, ref fLocked); 
                String chnlName = chnl.ChannelName;
 
                RegisteredChannelList regChnlList = s_registeredChannels; 

                // Check to make sure that the channel has not been registered 
                if((chnlName == null) ||
                   (chnlName.Length == 0) ||
                   (-1 == regChnlList.FindChannelIndex(chnl.ChannelName)))
                { 
                    if (ensureSecurity)
                    { 
                        ISecurableChannel securableChannel = chnl as ISecurableChannel; 
                        if (securableChannel != null)
                            securableChannel.IsSecured = ensureSecurity; 
                        else
                            throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Channel_CannotBeSecured"), chnl.ChannelName??chnl.ToString()));

                    } 
                    RegisteredChannel[] oldList = regChnlList.RegisteredChannels;
                    RegisteredChannel[] newList = null; 
                    if (oldList == null) 
                    {
                        newList = new RegisteredChannel[1]; 
                    }
                    else
                        newList = new RegisteredChannel[oldList.Length + 1];
 
                    if (!unloadHandlerRegistered && !(chnl is CrossAppDomainChannel))
                    { 
                        // Register a unload handler only once and if the channel being registered 
                        // is not the x-domain channel. x-domain channel does nothing inside its
                        // StopListening implementation 
                        AppDomain.CurrentDomain.DomainUnload += new EventHandler(UnloadHandler);
                        unloadHandlerRegistered = true;
                    }
 
                    // Add the interface to the array in priority order
                    int priority = chnl.ChannelPriority; 
                    int current = 0; 

                    // Find the place in the array to insert 
                    while (current < oldList.Length)
                    {
                        RegisteredChannel oldChannel = oldList[current];
                        if (priority > oldChannel.Channel.ChannelPriority) 
                        {
                            newList[current] = new RegisteredChannel(chnl); 
                            break; 
                        }
                        else 
                        {
                            newList[current] = oldChannel;
                            current++;
                        } 
                    }
 
                    if (current == oldList.Length) 
                    {
                        // chnl has lower priority than all old channels, so we insert 
                        //   it at the end of the list.
                        newList[oldList.Length] = new RegisteredChannel(chnl);
                    }
                    else 
                    {
                        // finish copying rest of the old channels 
                        while (current < oldList.Length) 
                        {
                            newList[current + 1] = oldList[current]; 
                            current++;
                        }
                    }
 
                    if (perf_Contexts != null) {
                        perf_Contexts->cChannels++; 
                    } 

                    s_registeredChannels = new RegisteredChannelList(newList); 
                }
                else
                {
                    throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ChannelNameAlreadyRegistered"), chnl.ChannelName)); 
                }
 
                RefreshChannelData(); 
            } // lock (s_channelLock)
            finally 
            {
                if (fLocked)
                {
                    Monitor.Exit(s_channelLock); 
                }
            } 
        } // RegisterChannelInternal 

 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
        unsafe public static void UnregisterChannel(IChannel chnl)
        {
            // we allow null to be passed in, so we can use this api to trigger the 
            //   refresh of the channel data <
 
 
            bool fLocked = false;
            RuntimeHelpers.PrepareConstrainedRegions(); 
            try
            {
                Monitor.ReliableEnter(s_channelLock, ref fLocked);
                if (chnl != null) 
                {
                    RegisteredChannelList regChnlList = s_registeredChannels; 
 
                    // Check to make sure that the channel has been registered
                    int matchingIdx = regChnlList.FindChannelIndex(chnl); 
                    if(-1 == matchingIdx)
                    {
                        throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ChannelNotRegistered"), chnl.ChannelName));
                    } 

                    RegisteredChannel[] oldList = regChnlList.RegisteredChannels; 
                    RegisteredChannel[] newList = null; 
                    BCLDebug.Assert((oldList != null) && (oldList.Length != 0), "channel list should not be empty");
 
                    newList = new RegisteredChannel[oldList.Length - 1];

                    // Call stop listening on the channel if it is a receiver.
                    IChannelReceiver srvChannel = chnl as IChannelReceiver; 
                    if (srvChannel != null)
                        srvChannel.StopListening(null); 
 
                    int current = 0;
                    int oldPos = 0; 
                    while (oldPos < oldList.Length)
                    {
                        if (oldPos == matchingIdx)
                        { 
                            oldPos++;
                        } 
                        else 
                        {
                            newList[current] = oldList[oldPos]; 
                            current++;
                            oldPos++;
                        }
                    } 

                    if (perf_Contexts != null) { 
                        perf_Contexts->cChannels--; 
                    }
 
                    s_registeredChannels = new RegisteredChannelList(newList);
                }

                RefreshChannelData(); 
            } // lock (s_channelLock)
            finally 
            { 
                if (fLocked)
                { 
                    Monitor.Exit(s_channelLock);
                }
            }
        } // UnregisterChannel 

 
        public static IChannel[] RegisteredChannels 
        {
            [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
            get
            {
                RegisteredChannelList regChnlList = s_registeredChannels;
                int count = regChnlList.Count; 

                if (0 == count) 
                { 
                    return new IChannel[0];
                } 
                else
                {
                    // we hide the CrossAppDomainChannel, so the number of visible
                    //   channels is one less than the number of registered channels. 
                    int visibleChannels = count - 1;
 
                    // Copy the array of visible channels into a new array 
                    // and return
                    int co = 0; 
                    IChannel[] temp = new IChannel[visibleChannels];
                    for (int i = 0; i < count; i++)
                    {
                        IChannel channel = regChnlList.GetChannel(i); 
                        // add the channel to the array if it is not the CrossAppDomainChannel
                        if (!(channel is CrossAppDomainChannel)) 
                            temp[co++] = channel; 
                    }
                    return temp; 
                }
            }
        } // RegisteredChannels
 
        internal static IMessageSink CreateMessageSink(String url, Object data, out String objectURI)
        { 
            BCLDebug.Trace("REMOTE", "ChannelServices::CreateMessageSink for url " + url + "\n"); 
            IMessageSink msgSink = null;
            objectURI = null; 

            RegisteredChannelList regChnlList = s_registeredChannels;
            int count = regChnlList.Count;
 
            for(int i = 0; i < count; i++)
            { 
                if(regChnlList.IsSender(i)) 
                {
                    IChannelSender chnl = (IChannelSender)regChnlList.GetChannel(i); 
                    msgSink = chnl.CreateMessageSink(url, data, out objectURI);

                    if(msgSink != null)
                        break; 
                }
            } 
 
            // If the object uri has not been set, set it to the url as
            // default value 
            if(null == objectURI)
            {
                objectURI = url;
            } 

            return msgSink; 
        } // CreateMessageSink 

        internal static IMessageSink CreateMessageSink(Object data) 
        {
            String objectUri;
            return CreateMessageSink(null, data, out objectUri);
        } // CreateMessageSink 

 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)] 
        public static IChannel GetChannel(String name)
        { 
            RegisteredChannelList regChnlList = s_registeredChannels;

            int matchingIdx = regChnlList.FindChannelIndex(name);
            if(0 <= matchingIdx) 
            {
                IChannel channel = regChnlList.GetChannel(matchingIdx); 
                if ((channel is CrossAppDomainChannel) || (channel is CrossContextChannel)) 
                    return null;
                else 
                    return channel;
            }
            else
            { 
                return null;
            } 
        } // GetChannel 

 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static String[] GetUrlsForObject(MarshalByRefObject obj)
        {
            if(null == obj) 
            {
                return null; 
            } 

            RegisteredChannelList regChnlList = s_registeredChannels; 
            int count = regChnlList.Count;

            Hashtable table = new Hashtable();
            bool fServer; 
            Identity id = MarshalByRefObject.GetIdentity(obj, out fServer);
 
            if(null != id) 
            {
                String uri = id.ObjURI; 

                if (null != uri)
                {
                    for(int i = 0; i < count; i++) 
                    {
                        if(regChnlList.IsReceiver(i)) 
                        { 
                            try
                            { 
                                String[] urls = ((IChannelReceiver)regChnlList.GetChannel(i)).GetUrlsForUri(uri);
                                // Add the strings to the table
                                for(int j = 0; j < urls.Length; j++)
                                { 
                                    table.Add(urls[j], urls[j]);
                                } 
                            } 
                            catch(NotSupportedException )
                            { 
                                // We do not count the channels that do not
                                // support this method
                            }
                        } 
                    }
                } 
            } 

            // copy url's into string array 
            ICollection keys = table.Keys;
            String[] urlList = new String[keys.Count];
            int co = 0;
            foreach (String key in keys) 
            {
                urlList[co++] = key; 
            } 
            return urlList;
        } 

       // Find the channel message sink associated with a given proxy
        // <
        internal static IMessageSink GetChannelSinkForProxy(Object obj) 
        {
            IMessageSink sink = null; 
            if (RemotingServices.IsTransparentProxy(obj)) 
            {
                RealProxy rp = RemotingServices.GetRealProxy(obj); 
                RemotingProxy remProxy = rp as RemotingProxy;
                if (null != remProxy)
                {
                    Identity idObj = remProxy.IdentityObject; 
                    BCLDebug.Assert(null != idObj,"null != idObj");
                    sink = idObj.ChannelSink; 
                } 
            }
 
            return sink;
        } // GetChannelSinkForProxy

 
        //  Get the message sink dictionary of properties for a given proxy
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 
        public static IDictionary GetChannelSinkProperties(Object obj)
        { 
            IMessageSink sink = GetChannelSinkForProxy(obj);
            IClientChannelSink chnlSink = sink as IClientChannelSink;
            if (null != chnlSink)
            { 
                // collect dictionaries for all channel sinks and return
                //   aggregate dictionary 
                ArrayList dictionaries = new ArrayList(); 

                do 
                {
                    IDictionary dict = chnlSink.Properties;
                    if (dict != null)
                        dictionaries.Add(dict); 

                    chnlSink = chnlSink.NextChannelSink; 
                } while (chnlSink != null); 

                return new AggregateDictionary(dictionaries); 
            }
            else
            {
                IDictionary dict = sink as IDictionary; 
                if(null != dict)
                { 
                    return dict; 
                }
                else 
                {
                    return null;
                }
            } 
        } // GetChannelSinkProperties
 
 
        internal static IMessageSink GetCrossContextChannelSink()
        { 
            if(null == xCtxChannel)
            {
                xCtxChannel = CrossContextChannel.MessageSink;
            } 

            return xCtxChannel; 
        } // GetCrossContextChannelSink 

 
#if DEBUG
        // A few methods to count the number of calls made across appdomains,
        // processes and machines
        internal static long GetNumberOfRemoteCalls() 
        {
            return remoteCalls; 
        } // GetNumberOfRemoteCalls 
#endif //DEBUG
 
        unsafe internal static void IncrementRemoteCalls(long cCalls)
        {
            remoteCalls += cCalls;
            if (perf_Contexts != null) 
              perf_Contexts->cRemoteCalls += (int)cCalls;
        } // IncrementRemoteCalls 
 
        internal static void IncrementRemoteCalls()
        { 
            IncrementRemoteCalls( 1 );
        } // IncrementRemoteCalls

 
        internal static void RefreshChannelData()
        { 
            bool fLocked = false; 
            RuntimeHelpers.PrepareConstrainedRegions();
            try 
            {
                Monitor.ReliableEnter(s_channelLock, ref fLocked);
                s_currentChannelData = CollectChannelDataFromChannels();
            } 
            finally
            { 
                if (fLocked) 
                {
                    Monitor.Exit(s_channelLock); 
                }
            }
        } // RefreshChannelData
 
        private static Object[] CollectChannelDataFromChannels()
        { 
            // Ensure that our native cross-context & cross-domain channels 
            // are registered
            RemotingServices.RegisterWellKnownChannels(); 

            RegisteredChannelList regChnlList = s_registeredChannels;
            int count = regChnlList.Count;
 
            // Compute the number of channels that implement IChannelReceiver
            int numChnls = regChnlList.ReceiverCount; 
 
            // Allocate array for channel data
            Object[] data = new Object[numChnls]; 

            // we need to remove null entries
            int nonNullDataCount = 0;
 
            // Set the channel data, names and mime types
            for (int i = 0, j = 0; i < count; i++) 
            { 

                IChannel chnl = regChnlList.GetChannel(i); 

                if (null == chnl)
                {
                    throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ChannelNotRegistered"), "")); 
                }
 
                if (regChnlList.IsReceiver(i)) 
                {
                    BCLDebug.Trace("REMOTE", "Setting info for receiver " + j + "\n"); 
                    // Extract the data
                    Object channelData = ((IChannelReceiver)chnl).ChannelData;
                    data[j] = channelData;
                    if (channelData != null) 
                        nonNullDataCount++;
 
                    // Increment the counter 
                    j++;
                } 
            }

            if (nonNullDataCount != numChnls)
            { 
                // there were null entries, so remove them.
                Object[] nonNullData = new Object[nonNullDataCount]; 
                int nonNullCounter = 0; 
                for (int co = 0; co < numChnls; co++)
                { 
                    Object channelData = data[co];
                    if (channelData != null)
                        nonNullData[nonNullCounter++] = channelData;
                } 

                data = nonNullData; 
            } 

            return data; 
        } // CollectChannelDataFromChannels

        // Checks to make sure the remote method being invoked is callable
        static bool IsMethodReallyPublic(MethodInfo mi) 
        {
            if (!mi.IsPublic || mi.IsStatic) 
                return false; 

            if (!mi.IsGenericMethod) 
                return true;

            foreach (Type t in mi.GetGenericArguments())
                if (!t.IsVisible) 
                    return false;
 
            return true; 
        }
 
        //--------------------------------------------------------------------
        //-----------------------  Dispatch Support   ------------------------
        //-------------------------------------------------------------------
 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static ServerProcessing DispatchMessage( 
            IServerChannelSinkStack sinkStack, 
            IMessage msg,
            out IMessage replyMsg) 
        {
            ServerProcessing processing = ServerProcessing.Complete;
            replyMsg = null;
 
            try
            { 
                if(null == msg) 
                {
                    throw new ArgumentNullException("msg"); 
                }

                BCLDebug.Trace("REMOTE", "Dispatching for URI " + InternalSink.GetURI(msg));
 
                // we must switch to the target context of the object and call the context chains etc...
                // Currenly XContextChannel does exactly so. So this method is just a wrapper.. 
 
                // <
 

                // Make sure that incoming calls are counted as a remote call. This way it
                // makes more sense on a server.
                IncrementRemoteCalls(); 

                // Check if the object has been disconnected or if it is 
                // a well known object then we have to create it lazily. 
                ServerIdentity srvId = CheckDisconnectedOrCreateWellKnownObject(msg);
 
                // Make sure that this isn't an AppDomain object since we don't allow
                //   calls to the AppDomain from out of process (and x-process calls
                //   are always dispatched through this method)
                if (srvId.ServerType == typeof(System.AppDomain)) 
                {
                    throw new RemotingException( 
                        Environment.GetResourceString( 
                            "Remoting_AppDomainsCantBeCalledRemotely"));
                } 


                IMethodCallMessage mcm = msg as IMethodCallMessage;
 
                if (mcm == null)
                { 
                    // It's a plain IMessage, so just 

 
                    if (!typeof(IMessageSink).IsAssignableFrom(srvId.ServerType))
                    {
                        throw new RemotingException(
                            Environment.GetResourceString( 
                                "Remoting_AppDomainsCantBeCalledRemotely"));
                    } 
 
                    processing = ServerProcessing.Complete;
                    replyMsg = ChannelServices.GetCrossContextChannelSink().SyncProcessMessage(msg); 
                }
                else
                {
                    // It's an IMethodCallMessage. 

                    // Check if the method is one way. Dispatch one way calls in 
                    // an asynchronous manner 
                    MethodInfo method = (MethodInfo)mcm.MethodBase;
 
                    // X-process / X-machine calls should be to non-static
                    // public methods only! Non-public or static methods can't
                    // be called remotely.
                    if (!IsMethodReallyPublic(method) && 
                          !RemotingServices.IsMethodAllowedRemotely(method))
                    { 
                        throw new RemotingException( 
                            Environment.GetResourceString(
                                "Remoting_NonPublicOrStaticCantBeCalledRemotely")); 
                    }

                    RemotingMethodCachedData cache = (RemotingMethodCachedData)
                        InternalRemotingServices.GetReflectionCachedData(method); 

                    /* 
 

 



 

 
 

 



 

 
 

 



 

 
*/ 
                    if(RemotingServices.IsOneWay(method))
                    { 
                        processing = ServerProcessing.OneWay;
                        ChannelServices.GetCrossContextChannelSink().AsyncProcessMessage(msg, null);
                    }
                    else 
                    {
                        // regular processing 
                        processing = ServerProcessing.Complete; 
                        if (!srvId.ServerType.IsContextful)
                        { 
                            Object[] args = new Object[]{msg, srvId.ServerContext};
                            replyMsg = (IMessage) CrossContextChannel.SyncProcessMessageCallback(args);
                        }
                        else 
                            replyMsg = ChannelServices.GetCrossContextChannelSink().SyncProcessMessage(msg);
                    } 
                } // end of case for IMethodCallMessage 
            }
            catch(Exception e) 
            {
                if(processing != ServerProcessing.OneWay)
                {
                    try 
                    {
                        IMethodCallMessage mcm = 
                            (IMethodCallMessage) ((msg!=null)?msg:new ErrorMessage()); 
                        replyMsg = (IMessage)new ReturnMessage(e, mcm);
                        if (msg != null) 
                        {
                            ((ReturnMessage)replyMsg).SetLogicalCallContext(
                                    (LogicalCallContext)
                                        msg.Properties[Message.CallContextKey]); 
                        }
                    } 
                    catch(Exception ) 
                    {
                        // Fatal exception .. ignore 
                    }
                }
            }
 
            return processing;
        } // DispatchMessage 
 
       // This method is used by the channel to dispatch the incoming messages
       // to the server side chain(s) based on the URI embedded in the message. 
       // The URI uniquely identifies the receiving object.
       //
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static IMessage SyncDispatchMessage(IMessage msg) 
        {
            IMessage msgRet = null; 
            bool fIsOneWay = false; 

            try 
            {
                if(null == msg)
                {
                    throw new ArgumentNullException("msg"); 
                }
 
 

                // For ContextBoundObject's, 
                // we must switch to the target context of the object and call the context chains etc...
                // Currenly XContextChannel does exactly so. So this method is just a wrapper..

 
                // Make sure that incoming calls are counted as a remote call. This way it
                // makes more sense on a server. 
                IncrementRemoteCalls(); 

                // < 
                if (!(msg is TransitionCall))
                {
                    // Check if the object has been disconnected or if it is
                    // a well known object then we have to create it lazily. 
                    CheckDisconnectedOrCreateWellKnownObject(msg);
 
                    MethodBase method = ((IMethodMessage)msg).MethodBase; 

                    // Check if the method is one way. Dispatch one way calls in 
                    // an asynchronous manner
                    fIsOneWay = RemotingServices.IsOneWay(method);
                }
 
                // <
                IMessageSink nextSink = ChannelServices.GetCrossContextChannelSink(); 
 
                if(!fIsOneWay)
                { 
                    msgRet = nextSink.SyncProcessMessage(msg);
                }
                else
                { 
                    nextSink.AsyncProcessMessage(msg, null);
                } 
            } 
            catch(Exception e)
            { 
                if(!fIsOneWay)
                {
                    try
                    { 
                        IMethodCallMessage mcm =
                            (IMethodCallMessage) ((msg!=null)?msg:new ErrorMessage()); 
                        msgRet = (IMessage)new ReturnMessage(e, mcm); 
                        if (msg!=null)
                        { 
                            ((ReturnMessage)msgRet).SetLogicalCallContext(
                                mcm.LogicalCallContext);
                        }
                    } 
                    catch(Exception )
                    { 
                        // Fatal exception .. ignore 
                    }
                } 
            }

            return msgRet;
        } 

       // This method is used by the channel to dispatch the incoming messages 
       // to the server side chain(s) based on the URI embedded in the message. 
       // The URI uniquely identifies the receiving object.
       // 
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static IMessageCtrl AsyncDispatchMessage(IMessage msg, IMessageSink replySink)
        {
            IMessageCtrl ctrl = null; 

            try 
            { 
                if(null == msg)
                { 
                    throw new ArgumentNullException("msg");
                }

                // we must switch to the target context of the object and call the context chains etc... 
                // Currenly XContextChannel does exactly so. So this method is just a wrapper..
 
                // Make sure that incoming calls are counted as a remote call. This way it 
                // makes more sense on a server.
                IncrementRemoteCalls(); 

                if (!(msg is TransitionCall))
                {
                    // Check if the object has been disconnected or if it is 
                    // a well known object then we have to create it lazily.
                    CheckDisconnectedOrCreateWellKnownObject(msg); 
                } 

                // < 

                ctrl = ChannelServices.GetCrossContextChannelSink().AsyncProcessMessage(msg, replySink);
            }
            catch(Exception e) 
            {
                if(null != replySink) 
                { 
                    try
                    { 
                        IMethodCallMessage mcm = (IMethodCallMessage)msg;
                        ReturnMessage retMsg = new ReturnMessage(e, (IMethodCallMessage)msg);
                        if (msg!=null)
                        { 
                            retMsg.SetLogicalCallContext(mcm.LogicalCallContext);
                        } 
                        replySink.SyncProcessMessage(retMsg); 
                    }
                    catch(Exception ) 
                    {
                        // Fatal exception... ignore
                    }
                } 
            }
 
            return ctrl; 
        } // AsyncDispatchMessage
 

        // Creates a channel sink chain (adds special dispatch sink to the end of the chain)
        [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.Infrastructure)]
        public static IServerChannelSink CreateServerChannelSinkChain( 
            IServerChannelSinkProvider provider, IChannelReceiver channel)
        { 
            if (provider == null) 
                return new DispatchChannelSink();
 
            // add dispatch provider to end (first find last provider)
            IServerChannelSinkProvider lastProvider = provider;
            while (lastProvider.Next != null)
                lastProvider = lastProvider.Next; 
            lastProvider.Next = new DispatchChannelSinkProvider();
 
            IServerChannelSink sinkChain = provider.CreateSink(channel); 

            // remove dispatch provider from end 
            lastProvider.Next = null;

            return sinkChain;
        } // CreateServerChannelSinkChain 

 
 
        // Check if the object has been disconnected or if it is
        // a well known object then we have to create it lazily. 
        internal static ServerIdentity CheckDisconnectedOrCreateWellKnownObject(IMessage msg)
        {
            ServerIdentity ident = InternalSink.GetServerIdentity(msg);
 
            BCLDebug.Trace("REMOTE", "Identity found = " + (ident == null ? "null" : "ServerIdentity"));
 
            // If the identity is null, then we should 

 
            if ((ident == null) || ident.IsRemoteDisconnected())
            {
                String uri = InternalSink.GetURI(msg);
                BCLDebug.Trace("REMOTE", "URI " + uri); 
                if (uri != null)
                { 
                    ServerIdentity newIdent = RemotingConfigHandler.CreateWellKnownObject(uri); 
                    if (newIdent != null)
                    { 
                        // The uri was a registered wellknown object.
                        ident = newIdent;
                        BCLDebug.Trace("REMOTE", "Identity created = " + (ident == null ? "null" : "ServerIdentity"));
                    } 
                }
 
            } 

 
            if ((ident == null) || (ident.IsRemoteDisconnected()))
            {
                String uri = InternalSink.GetURI(msg);
                throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Disconnected"),uri)); 
            }
            return ident; 
        } 

        // Channel Services AppDomain Unload Event Handler 
        internal static void UnloadHandler(Object sender, EventArgs e)
        {
            StopListeningOnAllChannels();
        } 

        private static void StopListeningOnAllChannels() 
        { 
            try
            { 
                RegisteredChannelList regChnlList = s_registeredChannels;
                int count = regChnlList.Count;

                for(int i = 0; i < count; i++) 
                {
                    if(regChnlList.IsReceiver(i)) 
                    { 
                        IChannelReceiver chnl = (IChannelReceiver)regChnlList.GetChannel(i);
                        chnl.StopListening(null); 
                    }
                }
            }
            catch (Exception) 
            {
                // Ignore ... appdomain is shutting down.. 
            } 
        }
 



        // 
        // INTERNAL PROFILER NOTIFICATION SERVICES
        // 
 
        internal static void NotifyProfiler(IMessage msg, RemotingProfilerEvent profilerEvent)
        { 
            switch (profilerEvent)
            {

            case RemotingProfilerEvent.ClientSend: 
            {
                if (RemotingServices.CORProfilerTrackRemoting()) 
                { 
                    Guid g;
 
                    RemotingServices.CORProfilerRemotingClientSendingMessage(out g, false);

                    if (RemotingServices.CORProfilerTrackRemotingCookie())
                        msg.Properties["CORProfilerCookie"] = g; 
                }
                break; 
            } // case RemotingProfilerEvent.ClientSend 

            case RemotingProfilerEvent.ClientReceive: 
            {
                if (RemotingServices.CORProfilerTrackRemoting())
                {
                    Guid g = Guid.Empty; 

                    if (RemotingServices.CORProfilerTrackRemotingCookie()) 
                    { 
                        Object obj = msg.Properties["CORProfilerCookie"];
 
                        if (obj != null)
                        {
                            g = (Guid) obj;
                        } 
                    }
 
                    RemotingServices.CORProfilerRemotingClientReceivingReply(g, false); 
                }
                break; 
            } // case RemotingProfilerEvent.ClientReceive

            } // switch (event)
        } // NotifyProfiler 

 
 
        // This is a helper used by UrlObjRef's.
        // Finds an http channel and returns first url for this object. 
        internal static String FindFirstHttpUrlForObject(String objectUri)
        {
            if (objectUri == null)
                return null; 

            RegisteredChannelList regChnlList = s_registeredChannels; 
            int count = regChnlList.Count; 

            for (int i = 0; i < count; i++) 
            {
                if(regChnlList.IsReceiver(i))
                {
                    IChannelReceiver chnl = (IChannelReceiver)regChnlList.GetChannel(i); 
                    String chnlType = chnl.GetType().FullName;
                    if ((String.CompareOrdinal(chnlType, "System.Runtime.Remoting.Channels.Http.HttpChannel") == 0) || 
                        (String.CompareOrdinal(chnlType, "System.Runtime.Remoting.Channels.Http.HttpServerChannel") == 0)) 
                    {
                        String[] urls = chnl.GetUrlsForUri(objectUri); 
                        if ((urls != null) && (urls.Length > 0))
                            return urls[0];
                    }
                } 
            }
 
            return null; 
        } // FindFirstHttpUrlForObject
 

        //
        // DEBUG Helpers
        //   Note: These methods should be included even in retail builds so that 
        //     they can be called from the debugger.
        // 
#if DEBUG 
        internal static void DumpRegisteredChannels()
        { 
            // To use from cordbg:
            //   f System.Runtime.Remoting.Channels.ChannelServices::DumpRegisteredChannels

            RegisteredChannelList regChnlList = s_registeredChannels; 
            int count = regChnlList.Count;
 
            Console.Error.WriteLine("Registered Channels:"); 

            for (int i = 0; i < count; i++) 
            {
                IChannel chnl = regChnlList.GetChannel(i);
                Console.Error.WriteLine(chnl);
            } 
        } // DumpRegisteredChannels
#endif // DEBUG 
 

    } // class ChannelServices 


    // used by ChannelServices.NotifyProfiler
   [Serializable] 
    internal enum RemotingProfilerEvent
    { 
        ClientSend, 
        ClientReceive
    } // RemotingProfilerEvent 



 
    internal class RegisteredChannel
    { 
        // private member variables 
        private IChannel channel;
        private byte flags; 
        private const byte SENDER      = 0x1;
        private const byte RECEIVER    = 0x2;

        internal RegisteredChannel(IChannel chnl) 
        {
            channel = chnl; 
            flags = 0; 
            if(chnl is IChannelSender)
            { 
                flags |= SENDER;
            }
            if(chnl is IChannelReceiver)
            { 
                flags |= RECEIVER;
            } 
        } 

        internal virtual IChannel Channel 
        {
            get { return channel; }
        }
 
        internal virtual bool IsSender()
        { 
            return ((flags & SENDER) != 0); 
        }
 
        internal virtual bool IsReceiver()
        {
            return ((flags & RECEIVER) != 0);
        } 
    }// class RegisteredChannel
 
 

    // This list should be considered immutable once created. 
    //   Ideally, this class would encapsulate more functionality, but
    //   to help minimize the number of changes in the RTM tree, only
    //   a small amount of code has been moved here.
    internal class RegisteredChannelList 
    {
        private RegisteredChannel[] _channels; 
 
        internal RegisteredChannelList()
        { 
            _channels = new RegisteredChannel[0];
        } // RegisteredChannelList

        internal RegisteredChannelList(RegisteredChannel[] channels) 
        {
            _channels = channels; 
        } // RegisteredChannelList 

        internal RegisteredChannel[] RegisteredChannels 
        {
            get { return _channels; }
        } // RegisteredChannels
 
        internal int Count
        { 
            get 
            {
                if (_channels == null) 
                    return 0;

                return _channels.Length;
            } 
        } // Count
 
        internal IChannel GetChannel(int index) 
        {
            return _channels[index].Channel; 
        } // GetChannel

        internal bool IsSender(int index)
        { 
            return _channels[index].IsSender();
        } // IsSender 
 
        internal bool IsReceiver(int index)
        { 
            return _channels[index].IsReceiver();
        } // IsReceiver

        internal int ReceiverCount 
        {
            get 
            { 
                if (_channels == null)
                    return 0; 

                int total = 0;
                for (int i = 0; i < _channels.Length; i++)
                { 
                    if (IsReceiver(i))
                        total++; 
                } 

                return total; 
            }
        } // ReceiverCount

        internal int FindChannelIndex(IChannel channel) 
        {
            Object chnlAsObject = (Object)channel; 
 
            for (int i = 0; i < _channels.Length; i++)
            { 
                if (chnlAsObject == (Object)GetChannel(i))
                    return i;
            }
 
            return -1;
        } // FindChannelIndex 
 
        internal int FindChannelIndex(String name)
        { 
            for (int i = 0; i < _channels.Length; i++)
            {
                if(String.Compare(name, GetChannel(i).ChannelName, StringComparison.OrdinalIgnoreCase) == 0)
                    return i; 
            }
 
            return -1; 
        } // FindChannelIndex
 

    } // class RegisteredChannelList

 

 
    internal class ChannelServicesData 
    {
        internal long remoteCalls = 0; 
        internal CrossContextChannel xctxmessageSink = null;
        internal CrossAppDomainChannel xadmessageSink = null;
        internal bool fRegisterWellKnownChannels = false;
    } 

   // 
   // Terminator sink used for profiling so that we can intercept asynchronous 
   // replies on the server side.
   // 

    /* package scope */
    internal class ServerAsyncReplyTerminatorSink : IMessageSink
    { 
        internal IMessageSink _nextSink;
 
        internal ServerAsyncReplyTerminatorSink(IMessageSink nextSink) 
        {
            BCLDebug.Assert(nextSink != null, 
                            "null IMessageSink passed to ServerAsyncReplyTerminatorSink ctor.");
            _nextSink = nextSink;
        }
 
        public virtual IMessage SyncProcessMessage(IMessage replyMsg)
        { 
            // If this class has been brought into the picture, then the following must be true. 
            BCLDebug.Assert(RemotingServices.CORProfilerTrackRemoting(),
                            "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!"); 
            BCLDebug.Assert(RemotingServices.CORProfilerTrackRemotingAsync(),
                            "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");

            Guid g; 

            // Notify the profiler that we are receiving an async reply from the server-side 
            RemotingServices.CORProfilerRemotingServerSendingReply(out g, true); 

            // If GUID cookies are active, then we save it for the other end of the channel 
            if (RemotingServices.CORProfilerTrackRemotingCookie())
                replyMsg.Properties["CORProfilerCookie"] = g;

            // Now that we've done the intercepting, pass the message on to the regular chain 
            return _nextSink.SyncProcessMessage(replyMsg);
        } 
 
        public virtual IMessageCtrl AsyncProcessMessage(IMessage replyMsg, IMessageSink replySink)
        { 
            // Since this class is only used for intercepting async replies, this function should
            // never get called. (Async replies are synchronous, ironically)
            BCLDebug.Assert(false, "ServerAsyncReplyTerminatorSink.AsyncProcessMessage called!");
 
            return null;
        } 
 
        public IMessageSink NextSink
        { 
            get
            {
                return _nextSink;
            } 
        }
 
        // Do I need a finalize here? 
    }
} 

// 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