The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting.Channels \ ChannelServicesData

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. //* File: Channel.cs
  16. //*
  17. //*
  18. //*
  19. //* Purpose: Defines the general purpose remoting proxy
  20. //*
  21. //* Date: May 27, 1999
  22. //*
  23. namespace System.Runtime.Remoting.Channels
  24. {
  25.     using System;
  26.     using System.Collections;
  27.     using System.IO;
  28.     using System.Reflection;
  29.     using System.Runtime.CompilerServices;
  30.     using System.Runtime.InteropServices;
  31.     using System.Runtime.Remoting;
  32.     using System.Runtime.Remoting.Activation;
  33.     using System.Runtime.Remoting.Messaging;
  34.     using System.Runtime.Remoting.Metadata;
  35.     using System.Runtime.Remoting.Proxies;
  36.     using System.Threading;
  37.     using System.Security.Permissions;
  38.     using System.Globalization;
  39.    
  40.     // ChannelServices
  41.    
  42.     [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
  43.     internal struct Perf_Contexts
  44.     {
  45.         internal int cRemoteCalls;
  46.         internal int cChannels;
  47.     }
  48.    
  49.     [System.Runtime.InteropServices.ComVisible(true)]
  50.     public sealed class ChannelServices
  51.     {
  52.         // This gets refreshed when a channel is registered/unregistered.
  53.         private static object[] s_currentChannelData = null;
  54.        
  55.         static internal object[] CurrentChannelData {
  56.             get {
  57.                 if (s_currentChannelData == null)
  58.                     RefreshChannelData();
  59.                
  60.                 return s_currentChannelData;
  61.             }
  62.         }
  63.         // CurrentChannelData
  64.        
  65.         // hide the default constructor
  66.         private ChannelServices()
  67.         {
  68.         }
  69.        
  70.         // list of registered channels and a lock to take when adding or removing channels
  71.         private static object s_channelLock = new object();
  72.         private static RegisteredChannelList s_registeredChannels = new RegisteredChannelList();
  73.        
  74.        
  75.         // Private member variables
  76.         // These have all been converted to getters and setters to get the effect of
  77.         // per-AppDomain statics (note: statics are per-AppDomain now, so these members
  78.         // could just be declared as statics on ChannelServices).
  79.        
  80.         private static long remoteCalls {
  81.             get { return Thread.GetDomain().RemotingData.ChannelServicesData.remoteCalls; }
  82.             set { Thread.GetDomain().RemotingData.ChannelServicesData.remoteCalls = value; }
  83.         }
  84.        
  85.         private static IMessageSink xCtxChannel;
  86.        
  87.        
  88.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  89.         unsafe static extern Perf_Contexts* GetPrivateContextsPerfCounters();
  90.        
  91.         unsafe private static Perf_Contexts* perf_Contexts = GetPrivateContextsPerfCounters();
  92.        
  93.        
  94.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.RemotingConfiguration)]
  95.         public static void RegisterChannel(IChannel chnl, bool ensureSecurity)
  96.         {
  97.             RegisterChannelInternal(chnl, ensureSecurity);
  98.         }
  99.        
  100.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.RemotingConfiguration)]
  101.         [Obsolete("Use System.Runtime.Remoting.ChannelServices.RegisterChannel(IChannel chnl, bool ensureSecurity) instead.", false)]
  102.         public static void RegisterChannel(IChannel chnl)
  103.         {
  104.                 /*ensureSecurity*/            RegisterChannelInternal(chnl, false);
  105.         }
  106.        
  107.        
  108.         static bool unloadHandlerRegistered = false;
  109.         unsafe static internal void RegisterChannelInternal(IChannel chnl, bool ensureSecurity)
  110.         {
  111.             // Validate arguments
  112.             if (null == chnl) {
  113.                 throw new ArgumentNullException("chnl");
  114.             }
  115.            
  116.             bool fLocked = false;
  117.             RuntimeHelpers.PrepareConstrainedRegions();
  118.             try {
  119.                 Monitor.ReliableEnter(s_channelLock, ref fLocked);
  120.                 string chnlName = chnl.ChannelName;
  121.                
  122.                 RegisteredChannelList regChnlList = s_registeredChannels;
  123.                
  124.                 // Check to make sure that the channel has not been registered
  125.                 if ((chnlName == null) || (chnlName.Length == 0) || (-1 == regChnlList.FindChannelIndex(chnl.ChannelName))) {
  126.                     if (ensureSecurity) {
  127.                         ISecurableChannel securableChannel = chnl as ISecurableChannel;
  128.                         if (securableChannel != null)
  129.                             securableChannel.IsSecured = ensureSecurity;
  130.                         else
  131.                             throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Channel_CannotBeSecured"), chnl.ChannelName ?? chnl.ToString()));
  132.                        
  133.                     }
  134.                     RegisteredChannel[] oldList = regChnlList.RegisteredChannels;
  135.                     RegisteredChannel[] newList = null;
  136.                     if (oldList == null) {
  137.                         newList = new RegisteredChannel[1];
  138.                     }
  139.                     else
  140.                         newList = new RegisteredChannel[oldList.Length + 1];
  141.                    
  142.                     if (!unloadHandlerRegistered && !(chnl is CrossAppDomainChannel)) {
  143.                         // Register a unload handler only once and if the channel being registered
  144.                         // is not the x-domain channel. x-domain channel does nothing inside its
  145.                         // StopListening implementation
  146.                         AppDomain.CurrentDomain.DomainUnload += new EventHandler(UnloadHandler);
  147.                         unloadHandlerRegistered = true;
  148.                     }
  149.                    
  150.                     // Add the interface to the array in priority order
  151.                     int priority = chnl.ChannelPriority;
  152.                     int current = 0;
  153.                    
  154.                     // Find the place in the array to insert
  155.                     while (current < oldList.Length) {
  156.                         RegisteredChannel oldChannel = oldList[current];
  157.                         if (priority > oldChannel.Channel.ChannelPriority) {
  158.                             newList[current] = new RegisteredChannel(chnl);
  159.                             break;
  160.                         }
  161.                         else {
  162.                             newList[current] = oldChannel;
  163.                             current++;
  164.                         }
  165.                     }
  166.                    
  167.                     if (current == oldList.Length) {
  168.                         // chnl has lower priority than all old channels, so we insert
  169.                         // it at the end of the list.
  170.                         newList[oldList.Length] = new RegisteredChannel(chnl);
  171.                     }
  172.                     else {
  173.                         // finish copying rest of the old channels
  174.                         while (current < oldList.Length) {
  175.                             newList[current + 1] = oldList[current];
  176.                             current++;
  177.                         }
  178.                     }
  179.                    
  180.                     if (perf_Contexts != null) {
  181.                         perf_Contexts->cChannels++;
  182.                     }
  183.                    
  184.                     s_registeredChannels = new RegisteredChannelList(newList);
  185.                 }
  186.                 else {
  187.                     throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ChannelNameAlreadyRegistered"), chnl.ChannelName));
  188.                 }
  189.                
  190.                 RefreshChannelData();
  191.             }
  192.             // lock (s_channelLock)
  193.             finally {
  194.                 if (fLocked) {
  195.                     Monitor.Exit(s_channelLock);
  196.                 }
  197.             }
  198.         }
  199.         // RegisterChannelInternal
  200.        
  201.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.RemotingConfiguration)]
  202.         unsafe public static void UnregisterChannel(IChannel chnl)
  203.         {
  204.             // we allow null to be passed in, so we can use this api to trigger the
  205.             // refresh of the channel data
  206.            
  207.             bool fLocked = false;
  208.             RuntimeHelpers.PrepareConstrainedRegions();
  209.             try {
  210.                 Monitor.ReliableEnter(s_channelLock, ref fLocked);
  211.                 if (chnl != null) {
  212.                     RegisteredChannelList regChnlList = s_registeredChannels;
  213.                    
  214.                     // Check to make sure that the channel has been registered
  215.                     int matchingIdx = regChnlList.FindChannelIndex(chnl);
  216.                     if (-1 == matchingIdx) {
  217.                         throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ChannelNotRegistered"), chnl.ChannelName));
  218.                     }
  219.                    
  220.                     RegisteredChannel[] oldList = regChnlList.RegisteredChannels;
  221.                     RegisteredChannel[] newList = null;
  222.                     BCLDebug.Assert((oldList != null) && (oldList.Length != 0), "channel list should not be empty");
  223.                    
  224.                     newList = new RegisteredChannel[oldList.Length - 1];
  225.                    
  226.                     // Call stop listening on the channel if it is a receiver.
  227.                     IChannelReceiver srvChannel = chnl as IChannelReceiver;
  228.                     if (srvChannel != null)
  229.                         srvChannel.StopListening(null);
  230.                    
  231.                     int current = 0;
  232.                     int oldPos = 0;
  233.                     while (oldPos < oldList.Length) {
  234.                         if (oldPos == matchingIdx) {
  235.                             oldPos++;
  236.                         }
  237.                         else {
  238.                             newList[current] = oldList[oldPos];
  239.                             current++;
  240.                             oldPos++;
  241.                         }
  242.                     }
  243.                    
  244.                     if (perf_Contexts != null) {
  245.                         perf_Contexts->cChannels--;
  246.                     }
  247.                    
  248.                     s_registeredChannels = new RegisteredChannelList(newList);
  249.                 }
  250.                
  251.                 RefreshChannelData();
  252.             }
  253.             // lock (s_channelLock)
  254.             finally {
  255.                 if (fLocked) {
  256.                     Monitor.Exit(s_channelLock);
  257.                 }
  258.             }
  259.         }
  260.         // UnregisterChannel
  261.        
  262.         public static IChannel[] RegisteredChannels {
  263.             [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  264.             get {
  265.                 RegisteredChannelList regChnlList = s_registeredChannels;
  266.                 int count = regChnlList.Count;
  267.                
  268.                 if (0 == count) {
  269.                     return new IChannel[0];
  270.                 }
  271.                 else {
  272.                     // we hide the CrossAppDomainChannel, so the number of visible
  273.                     // channels is one less than the number of registered channels.
  274.                     int visibleChannels = count - 1;
  275.                    
  276.                     // Copy the array of visible channels into a new array
  277.                     // and return
  278.                     int co = 0;
  279.                     IChannel[] temp = new IChannel[visibleChannels];
  280.                     for (int i = 0; i < count; i++) {
  281.                         IChannel channel = regChnlList.GetChannel(i);
  282.                         // add the channel to the array if it is not the CrossAppDomainChannel
  283.                         if (!(channel is CrossAppDomainChannel))
  284.                             temp[co++] = channel;
  285.                     }
  286.                     return temp;
  287.                 }
  288.             }
  289.         }
  290.         // RegisteredChannels
  291.         static internal IMessageSink CreateMessageSink(string url, object data, out string objectURI)
  292.         {
  293.             BCLDebug.Trace("REMOTE", "ChannelServices::CreateMessageSink for url " + url + "\n");
  294.             IMessageSink msgSink = null;
  295.             objectURI = null;
  296.            
  297.             RegisteredChannelList regChnlList = s_registeredChannels;
  298.             int count = regChnlList.Count;
  299.            
  300.             for (int i = 0; i < count; i++) {
  301.                 if (regChnlList.IsSender(i)) {
  302.                     IChannelSender chnl = (IChannelSender)regChnlList.GetChannel(i);
  303.                     msgSink = chnl.CreateMessageSink(url, data, out objectURI);
  304.                    
  305.                     if (msgSink != null)
  306.                         break;
  307.                 }
  308.             }
  309.            
  310.             // If the object uri has not been set, set it to the url as
  311.             // default value
  312.             if (null == objectURI) {
  313.                 objectURI = url;
  314.             }
  315.            
  316.             return msgSink;
  317.         }
  318.         // CreateMessageSink
  319.         static internal IMessageSink CreateMessageSink(object data)
  320.         {
  321.             string objectUri;
  322.             return CreateMessageSink(null, data, out objectUri);
  323.         }
  324.         // CreateMessageSink
  325.        
  326.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  327.         public static IChannel GetChannel(string name)
  328.         {
  329.             RegisteredChannelList regChnlList = s_registeredChannels;
  330.            
  331.             int matchingIdx = regChnlList.FindChannelIndex(name);
  332.             if (0 <= matchingIdx) {
  333.                 IChannel channel = regChnlList.GetChannel(matchingIdx);
  334.                 if ((channel is CrossAppDomainChannel) || (channel is CrossContextChannel))
  335.                     return null;
  336.                 else
  337.                     return channel;
  338.             }
  339.             else {
  340.                 return null;
  341.             }
  342.         }
  343.         // GetChannel
  344.        
  345.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  346.         public static string[] GetUrlsForObject(MarshalByRefObject obj)
  347.         {
  348.             if (null == obj) {
  349.                 return null;
  350.             }
  351.            
  352.             RegisteredChannelList regChnlList = s_registeredChannels;
  353.             int count = regChnlList.Count;
  354.            
  355.             Hashtable table = new Hashtable();
  356.             bool fServer;
  357.             Identity id = MarshalByRefObject.GetIdentity(obj, out fServer);
  358.            
  359.             if (null != id) {
  360.                 string uri = id.ObjURI;
  361.                
  362.                 if (null != uri) {
  363.                     for (int i = 0; i < count; i++) {
  364.                         if (regChnlList.IsReceiver(i)) {
  365.                             try {
  366.                                 string[] urls = ((IChannelReceiver)regChnlList.GetChannel(i)).GetUrlsForUri(uri);
  367.                                 // Add the strings to the table
  368.                                 for (int j = 0; j < urls.Length; j++) {
  369.                                     table.Add(urls[j], urls[j]);
  370.                                 }
  371.                             }
  372.                             catch (NotSupportedException) {
  373.                                 // We do not count the channels that do not
  374.                                 // support this method
  375.                             }
  376.                         }
  377.                     }
  378.                 }
  379.             }
  380.            
  381.             // copy url's into string array
  382.             ICollection keys = table.Keys;
  383.             string[] urlList = new string[keys.Count];
  384.             int co = 0;
  385.             foreach (string key in keys) {
  386.                 urlList[co++] = key;
  387.             }
  388.             return urlList;
  389.         }
  390.        
  391.         // Find the channel message sink associated with a given proxy
  392.         static internal IMessageSink GetChannelSinkForProxy(object obj)
  393.         {
  394.             IMessageSink sink = null;
  395.             if (RemotingServices.IsTransparentProxy(obj)) {
  396.                 RealProxy rp = RemotingServices.GetRealProxy(obj);
  397.                 RemotingProxy remProxy = rp as RemotingProxy;
  398.                 if (null != remProxy) {
  399.                     Identity idObj = remProxy.IdentityObject;
  400.                     BCLDebug.Assert(null != idObj, "null != idObj");
  401.                     sink = idObj.ChannelSink;
  402.                 }
  403.             }
  404.            
  405.             return sink;
  406.         }
  407.         // GetChannelSinkForProxy
  408.        
  409.         // Get the message sink dictionary of properties for a given proxy
  410.        
  411.         [SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.RemotingConfiguration)]
  412.         public static IDictionary GetChannelSinkProperties(object obj)
  413.         {
  414.             IMessageSink sink = GetChannelSinkForProxy(obj);
  415.             IClientChannelSink chnlSink = sink as IClientChannelSink;
  416.             if (null != chnlSink) {
  417.                 // collect dictionaries for all channel sinks and return
  418.                 // aggregate dictionary
  419.                 ArrayList dictionaries = new ArrayList();
  420.                
  421.                 do {
  422.                     IDictionary dict = chnlSink.Properties;
  423.                     if (dict != null)
  424.                         dictionaries.Add(dict);
  425.                    
  426.                     chnlSink = chnlSink.NextChannelSink;
  427.                 }
  428.                 while (chnlSink != null);
  429.                
  430.                 return new AggregateDictionary(dictionaries);
  431.             }
  432.             else {
  433.                 IDictionary dict = sink as IDictionary;
  434.                 if (null != dict) {
  435.                     return dict;
  436.                 }
  437.                 else {
  438.                     return null;
  439.                 }
  440.             }
  441.         }
  442.         // GetChannelSinkProperties
  443.        
  444.         static internal IMessageSink GetCrossContextChannelSink()
  445.         {
  446.             if (null == xCtxChannel) {
  447.                 xCtxChannel = CrossContextChannel.MessageSink;
  448.             }
  449.            
  450.             return xCtxChannel;
  451.         }
  452.         // GetCrossContextChannelSink
  453.        
  454.         #if DEBUG
  455.         // A few methods to count the number of calls made across appdomains,
  456.         // processes and machines
  457.         static internal long GetNumberOfRemoteCalls()
  458.         {
  459.             return remoteCalls;
  460.         }
  461.         // GetNumberOfRemoteCalls
  462.         #endif //DEBUG
  463.         unsafe static internal void IncrementRemoteCalls(long cCalls)
  464.         {
  465.             remoteCalls += cCalls;
  466.             if (perf_Contexts != null)
  467.                 perf_Contexts->cRemoteCalls += (int)cCalls;
  468.         }
  469.         // IncrementRemoteCalls
  470.         static internal void IncrementRemoteCalls()
  471.         {
  472.             IncrementRemoteCalls(1);
  473.         }
  474.         // IncrementRemoteCalls
  475.        
  476.         static internal void RefreshChannelData()
  477.         {
  478.             bool fLocked = false;
  479.             RuntimeHelpers.PrepareConstrainedRegions();
  480.             try {
  481.                 Monitor.ReliableEnter(s_channelLock, ref fLocked);
  482.                 s_currentChannelData = CollectChannelDataFromChannels();
  483.             }
  484.             finally {
  485.                 if (fLocked) {
  486.                     Monitor.Exit(s_channelLock);
  487.                 }
  488.             }
  489.         }
  490.         // RefreshChannelData
  491.         private static object[] CollectChannelDataFromChannels()
  492.         {
  493.             // Ensure that our native cross-context & cross-domain channels
  494.             // are registered
  495.             RemotingServices.RegisterWellKnownChannels();
  496.            
  497.             RegisteredChannelList regChnlList = s_registeredChannels;
  498.             int count = regChnlList.Count;
  499.            
  500.             // Compute the number of channels that implement IChannelReceiver
  501.             int numChnls = regChnlList.ReceiverCount;
  502.            
  503.             // Allocate array for channel data
  504.             object[] data = new object[numChnls];
  505.            
  506.             // we need to remove null entries
  507.             int nonNullDataCount = 0;
  508.            
  509.             // Set the channel data, names and mime types
  510.             for (int i = 0int j = 0; i < count; i++) {
  511.                
  512.                 IChannel chnl = regChnlList.GetChannel(i);
  513.                
  514.                 if (null == chnl) {
  515.                     throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_ChannelNotRegistered"), ""));
  516.                 }
  517.                
  518.                 if (regChnlList.IsReceiver(i)) {
  519.                     BCLDebug.Trace("REMOTE", "Setting info for receiver " + j + "\n");
  520.                     // Extract the data
  521.                     object channelData = ((IChannelReceiver)chnl).ChannelData;
  522.                     data[j] = channelData;
  523.                     if (channelData != null)
  524.                         nonNullDataCount++;
  525.                    
  526.                     // Increment the counter
  527.                     j++;
  528.                 }
  529.             }
  530.            
  531.             if (nonNullDataCount != numChnls) {
  532.                 // there were null entries, so remove them.
  533.                 object[] nonNullData = new object[nonNullDataCount];
  534.                 int nonNullCounter = 0;
  535.                 for (int co = 0; co < numChnls; co++) {
  536.                     object channelData = data[co];
  537.                     if (channelData != null)
  538.                         nonNullData[nonNullCounter++] = channelData;
  539.                 }
  540.                
  541.                 data = nonNullData;
  542.             }
  543.            
  544.             return data;
  545.         }
  546.         // CollectChannelDataFromChannels
  547.         // Checks to make sure the remote method being invoked is callable
  548.         static bool IsMethodReallyPublic(MethodInfo mi)
  549.         {
  550.             if (!mi.IsPublic || mi.IsStatic)
  551.                 return false;
  552.            
  553.             if (!mi.IsGenericMethod)
  554.                 return true;
  555.            
  556.             foreach (Type t in mi.GetGenericArguments())
  557.                 if (!t.IsVisible)
  558.                     return false;
  559.            
  560.             return true;
  561.         }
  562.        
  563.         //--------------------------------------------------------------------
  564.         //----------------------- Dispatch Support ------------------------
  565.         //--------------------------------------------------------------------
  566.        
  567.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  568.         public static ServerProcessing DispatchMessage(IServerChannelSinkStack sinkStack, IMessage msg, out IMessage replyMsg)
  569.         {
  570.             ServerProcessing processing = ServerProcessing.Complete;
  571.             replyMsg = null;
  572.            
  573.             try {
  574.                 if (null == msg) {
  575.                     throw new ArgumentNullException("msg");
  576.                 }
  577.                
  578.                 BCLDebug.Trace("REMOTE", "Dispatching for URI " + InternalSink.GetURI(msg));
  579.                
  580.                 // we must switch to the target context of the object and call the context chains etc...
  581.                 // Currenly XContextChannel does exactly so. So this method is just a wrapper..
  582.                
  583.                
  584.                 // Make sure that incoming calls are counted as a remote call. This way it
  585.                 // makes more sense on a server.
  586.                 IncrementRemoteCalls();
  587.                
  588.                 // Check if the object has been disconnected or if it is
  589.                 // a well known object then we have to create it lazily.
  590.                 ServerIdentity srvId = CheckDisconnectedOrCreateWellKnownObject(msg);
  591.                
  592.                 // Make sure that this isn't an AppDomain object since we don't allow
  593.                 // calls to the AppDomain from out of process (and x-process calls
  594.                 // are always dispatched through this method)
  595.                 if (srvId.ServerType == typeof(System.AppDomain)) {
  596.                     throw new RemotingException(Environment.GetResourceString("Remoting_AppDomainsCantBeCalledRemotely"));
  597.                 }
  598.                
  599.                
  600.                 IMethodCallMessage mcm = msg as IMethodCallMessage;
  601.                
  602.                 if (mcm == null) {
  603.                     // It's a plain IMessage, so just check to make sure that the
  604.                     // target object implements IMessageSink and dispatch synchronously.
  605.                    
  606.                     if (!typeof(IMessageSink).IsAssignableFrom(srvId.ServerType)) {
  607.                         throw new RemotingException(Environment.GetResourceString("Remoting_AppDomainsCantBeCalledRemotely"));
  608.                     }
  609.                    
  610.                     processing = ServerProcessing.Complete;
  611.                     replyMsg = ChannelServices.GetCrossContextChannelSink().SyncProcessMessage(msg);
  612.                 }
  613.                 else {
  614.                     // It's an IMethodCallMessage.
  615.                    
  616.                     // Check if the method is one way. Dispatch one way calls in
  617.                     // an asynchronous manner
  618.                     MethodInfo method = (MethodInfo)mcm.MethodBase;
  619.                    
  620.                     // X-process / X-machine calls should be to non-static
  621.                     // public methods only! Non-public or static methods can't
  622.                     // be called remotely.
  623.                     if (!IsMethodReallyPublic(method) && !RemotingServices.IsMethodAllowedRemotely(method)) {
  624.                         throw new RemotingException(Environment.GetResourceString("Remoting_NonPublicOrStaticCantBeCalledRemotely"));
  625.                     }
  626.                    
  627.                     RemotingMethodCachedData cache = (RemotingMethodCachedData)InternalRemotingServices.GetReflectionCachedData(method);
  628.                    
  629.                     /*
  630.                         FUTURE:
  631.                         Dispatching asynchronously was cut from v1. We should reactivate
  632.                         the following code in v1.x or v2.
  633.                    
  634.                     // look for async method version             
  635.                     MethodInfo begin;
  636.                     MethodInfo end;
  637.                     ServerChannelSinkStack serverSinkStack = sinkStack as ServerChannelSinkStack;
  638.                     if ((sinkStack != null) &&
  639.                         cache.GetAsyncMethodVersion(out begin, out end))
  640.                     {
  641.                         processing = ServerProcessing.Async;
  642.                         IMessage asyncMsg =
  643.                             new AsyncMethodCallMessageWrapper(
  644.                                 (IMethodCallMessage)msg,
  645.                                 begin,
  646.                                 new AsyncCallback(sinkStack.ServerCallback),
  647.                                 null);
  648.                         serverSinkStack.AsyncMessage = asyncMsg;           
  649.                         serverSinkStack.AsyncEnd = end;
  650.                         serverSinkStack.Message = (IMethodCallMessage)msg;
  651.                         asyncMsg.Properties["__SinkStack"] = sinkStack;
  652.    
  653.                         // We don't dispatch yet. That happens when the server transport sink
  654.                         //  eventually calls sinkStack.StoreAndDispatch(...).
  655.                     }
  656.                     else
  657.                     */                   
  658. if (RemotingServices.IsOneWay(method)) {
  659.                         processing = ServerProcessing.OneWay;
  660.                         ChannelServices.GetCrossContextChannelSink().AsyncProcessMessage(msg, null);
  661.                     }
  662.                     else {
  663.                         // regular processing
  664.                         processing = ServerProcessing.Complete;
  665.                         if (!srvId.ServerType.IsContextful) {
  666.                             object[] args = new object[] {msg, srvId.ServerContext};
  667.                             replyMsg = (IMessage)CrossContextChannel.SyncProcessMessageCallback(args);
  668.                         }
  669.                         else
  670.                             replyMsg = ChannelServices.GetCrossContextChannelSink().SyncProcessMessage(msg);
  671.                     }
  672.                 }
  673.                 // end of case for IMethodCallMessage
  674.             }
  675.             catch (Exception e) {
  676.                 if (processing != ServerProcessing.OneWay) {
  677.                     try {
  678.                         IMethodCallMessage mcm = (IMethodCallMessage)((msg != null) ? msg : new ErrorMessage());
  679.                         replyMsg = (IMessage)new ReturnMessage(e, mcm);
  680.                         if (msg != null) {
  681.                             ((ReturnMessage)replyMsg).SetLogicalCallContext((LogicalCallContext)msg.Properties[Message.CallContextKey]);
  682.                         }
  683.                     }
  684.                     catch (Exception) {
  685.                         // Fatal exception .. ignore
  686.                     }
  687.                 }
  688.             }
  689.            
  690.             return processing;
  691.         }
  692.         // DispatchMessage
  693.         // This method is used by the channel to dispatch the incoming messages
  694.         // to the server side chain(s) based on the URI embedded in the message.
  695.         // The URI uniquely identifies the receiving object.
  696.         //
  697.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  698.         public static IMessage SyncDispatchMessage(IMessage msg)
  699.         {
  700.             IMessage msgRet = null;
  701.             bool fIsOneWay = false;
  702.            
  703.             try {
  704.                 if (null == msg) {
  705.                     throw new ArgumentNullException("msg");
  706.                 }
  707.                
  708.                
  709.                
  710.                
  711.                
  712.                 IncrementRemoteCalls();
  713.                
  714.                 if (!(msg is TransitionCall)) {
  715.                     // Check if the object has been disconnected or if it is
  716.                     // a well known object then we have to create it lazily.
  717.                     CheckDisconnectedOrCreateWellKnownObject(msg);
  718.                    
  719.                     MethodBase method = ((IMethodMessage)msg).MethodBase;
  720.                    
  721.                     // Check if the method is one way. Dispatch one way calls in
  722.                     // an asynchronous manner
  723.                     fIsOneWay = RemotingServices.IsOneWay(method);
  724.                 }
  725.                
  726.                 IMessageSink nextSink = ChannelServices.GetCrossContextChannelSink();
  727.                
  728.                 if (!fIsOneWay) {
  729.                     msgRet = nextSink.SyncProcessMessage(msg);
  730.                 }
  731.                 else {
  732.                     nextSink.AsyncProcessMessage(msg, null);
  733.                 }
  734.             }
  735.             catch (Exception e) {
  736.                 if (!fIsOneWay) {
  737.                     try {
  738.                         IMethodCallMessage mcm = (IMethodCallMessage)((msg != null) ? msg : new ErrorMessage());
  739.                         msgRet = (IMessage)new ReturnMessage(e, mcm);
  740.                         if (msg != null) {
  741.                             ((ReturnMessage)msgRet).SetLogicalCallContext(mcm.LogicalCallContext);
  742.                         }
  743.                     }
  744.                     catch (Exception) {
  745.                         // Fatal exception .. ignore
  746.                     }
  747.                 }
  748.             }
  749.            
  750.             return msgRet;
  751.         }
  752.        
  753.         // This method is used by the channel to dispatch the incoming messages
  754.         // to the server side chain(s) based on the URI embedded in the message.
  755.         // The URI uniquely identifies the receiving object.
  756.         //
  757.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  758.         public static IMessageCtrl AsyncDispatchMessage(IMessage msg, IMessageSink replySink)
  759.         {
  760.             IMessageCtrl ctrl = null;
  761.            
  762.             try {
  763.                 if (null == msg) {
  764.                     throw new ArgumentNullException("msg");
  765.                 }
  766.                
  767.                
  768.                 IncrementRemoteCalls();
  769.                
  770.                 if (!(msg is TransitionCall)) {
  771.                     // Check if the object has been disconnected or if it is
  772.                     // a well known object then we have to create it lazily.
  773.                     CheckDisconnectedOrCreateWellKnownObject(msg);
  774.                 }
  775.                
  776.                 ctrl = ChannelServices.GetCrossContextChannelSink().AsyncProcessMessage(msg, replySink);
  777.             }
  778.             catch (Exception e) {
  779.                 if (null != replySink) {
  780.                     try {
  781.                         IMethodCallMessage mcm = (IMethodCallMessage)msg;
  782.                         ReturnMessage retMsg = new ReturnMessage(e, (IMethodCallMessage)msg);
  783.                         if (msg != null) {
  784.                             retMsg.SetLogicalCallContext(mcm.LogicalCallContext);
  785.                         }
  786.                         replySink.SyncProcessMessage(retMsg);
  787.                     }
  788.                     catch (Exception) {
  789.                         // Fatal exception... ignore
  790.                     }
  791.                 }
  792.             }
  793.            
  794.             return ctrl;
  795.         }
  796.         // AsyncDispatchMessage
  797.        
  798.         // Creates a channel sink chain (adds special dispatch sink to the end of the chain)
  799.         [SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]
  800.         public static IServerChannelSink CreateServerChannelSinkChain(IServerChannelSinkProvider provider, IChannelReceiver channel)
  801.         {
  802.             if (provider == null)
  803.                 return new DispatchChannelSink();
  804.            
  805.             // add dispatch provider to end (first find last provider)
  806.             IServerChannelSinkProvider lastProvider = provider;
  807.             while (lastProvider.Next != null)
  808.                 lastProvider = lastProvider.Next;
  809.             lastProvider.Next = new DispatchChannelSinkProvider();
  810.            
  811.             IServerChannelSink sinkChain = provider.CreateSink(channel);
  812.            
  813.             // remove dispatch provider from end
  814.             lastProvider.Next = null;
  815.            
  816.             return sinkChain;
  817.         }
  818.         // CreateServerChannelSinkChain
  819.        
  820.        
  821.         // Check if the object has been disconnected or if it is
  822.         // a well known object then we have to create it lazily.
  823.         static internal ServerIdentity CheckDisconnectedOrCreateWellKnownObject(IMessage msg)
  824.         {
  825.             ServerIdentity ident = InternalSink.GetServerIdentity(msg);
  826.            
  827.             BCLDebug.Trace("REMOTE", "Identity found = " + (ident == null ? "null" : "ServerIdentity"));
  828.            
  829.             // If the identity is null, then we should check whether the
  830.             // request if for a well known object. If yes, then we should
  831.             // create the well known object lazily and marshal it.
  832.             if ((ident == null) || ident.IsRemoteDisconnected()) {
  833.                 string uri = InternalSink.GetURI(msg);
  834.                 BCLDebug.Trace("REMOTE", "URI " + uri);
  835.                 if (uri != null) {
  836.                     ServerIdentity newIdent = RemotingConfigHandler.CreateWellKnownObject(uri);
  837.                     if (newIdent != null) {
  838.                         // The uri was a registered wellknown object.
  839.                         ident = newIdent;
  840.                         BCLDebug.Trace("REMOTE", "Identity created = " + (ident == null ? "null" : "ServerIdentity"));
  841.                     }
  842.                 }
  843.                
  844.             }
  845.            
  846.            
  847.             if ((ident == null) || (ident.IsRemoteDisconnected())) {
  848.                 string uri = InternalSink.GetURI(msg);
  849.                 throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Disconnected"), uri));
  850.             }
  851.             return ident;
  852.         }
  853.        
  854.         // Channel Services AppDomain Unload Event Handler
  855.         static internal void UnloadHandler(object sender, EventArgs e)
  856.         {
  857.             StopListeningOnAllChannels();
  858.         }
  859.        
  860.         private static void StopListeningOnAllChannels()
  861.         {
  862.             try {
  863.                 RegisteredChannelList regChnlList = s_registeredChannels;
  864.                 int count = regChnlList.Count;
  865.                
  866.                 for (int i = 0; i < count; i++) {
  867.                     if (regChnlList.IsReceiver(i)) {
  868.                         IChannelReceiver chnl = (IChannelReceiver)regChnlList.GetChannel(i);
  869.                         chnl.StopListening(null);
  870.                     }
  871.                 }
  872.             }
  873.             catch (Exception) {
  874.                 // Ignore ... appdomain is shutting down..
  875.             }
  876.         }
  877.        
  878.        
  879.        
  880.        
  881.         //
  882.         // INTERNAL PROFILER NOTIFICATION SERVICES
  883.         //
  884.        
  885.         static internal void NotifyProfiler(IMessage msg, RemotingProfilerEvent profilerEvent)
  886.         {
  887.             switch (profilerEvent) {
  888.                 case RemotingProfilerEvent.ClientSend:
  889.                    
  890.                    
  891.                     {
  892.                         if (RemotingServices.CORProfilerTrackRemoting()) {
  893.                             Guid g;
  894.                            
  895.                             RemotingServices.CORProfilerRemotingClientSendingMessage(out g, false);
  896.                            
  897.                             if (RemotingServices.CORProfilerTrackRemotingCookie())
  898.                                 msg.Properties["CORProfilerCookie"] = g;
  899.                         }
  900.                         break;
  901.                     }
  902.                     break;
  903.                 case RemotingProfilerEvent.ClientReceive:
  904.                     // case RemotingProfilerEvent.ClientSend
  905.                    
  906.                     {
  907.                         if (RemotingServices.CORProfilerTrackRemoting()) {
  908.                             Guid g = Guid.Empty;
  909.                            
  910.                             if (RemotingServices.CORProfilerTrackRemotingCookie()) {
  911.                                 object obj = msg.Properties["CORProfilerCookie"];
  912.                                
  913.                                 if (obj != null) {
  914.                                     g = (Guid)obj;
  915.                                 }
  916.                             }
  917.                            
  918.                             RemotingServices.CORProfilerRemotingClientReceivingReply(g, false);
  919.                         }
  920.                         break;
  921.                     }
  922.                     break;
  923.                 // case RemotingProfilerEvent.ClientReceive
  924.             }
  925.             // switch (event)
  926.         }
  927.         // NotifyProfiler
  928.        
  929.        
  930.         // This is a helper used by UrlObjRef's.
  931.         // Finds an http channel and returns first url for this object.
  932.         static internal string FindFirstHttpUrlForObject(string objectUri)
  933.         {
  934.             if (objectUri == null)
  935.                 return null;
  936.            
  937.             RegisteredChannelList regChnlList = s_registeredChannels;
  938.             int count = regChnlList.Count;
  939.            
  940.             for (int i = 0; i < count; i++) {
  941.                 if (regChnlList.IsReceiver(i)) {
  942.                     IChannelReceiver chnl = (IChannelReceiver)regChnlList.GetChannel(i);
  943.                     string chnlType = chnl.GetType().FullName;
  944.                     if ((String.CompareOrdinal(chnlType, "System.Runtime.Remoting.Channels.Http.HttpChannel") == 0) || (String.CompareOrdinal(chnlType, "System.Runtime.Remoting.Channels.Http.HttpServerChannel") == 0)) {
  945.                         string[] urls = chnl.GetUrlsForUri(objectUri);
  946.                         if ((urls != null) && (urls.Length > 0))
  947.                             return urls[0];
  948.                     }
  949.                 }
  950.             }
  951.            
  952.             return null;
  953.         }
  954.         // FindFirstHttpUrlForObject
  955.        
  956.         //
  957.         // DEBUG Helpers
  958.         // Note: These methods should be included even in retail builds so that
  959.         // they can be called from the debugger.
  960.         //
  961.         #if DEBUG
  962.         static internal void DumpRegisteredChannels()
  963.         {
  964.             // To use from cordbg:
  965.             // f System.Runtime.Remoting.Channels.ChannelServices::DumpRegisteredChannels
  966.            
  967.             RegisteredChannelList regChnlList = s_registeredChannels;
  968.             int count = regChnlList.Count;
  969.            
  970.             Console.Error.WriteLine("Registered Channels:");
  971.            
  972.             for (int i = 0; i < count; i++) {
  973.                 IChannel chnl = regChnlList.GetChannel(i);
  974.                 Console.Error.WriteLine(chnl);
  975.             }
  976.         }
  977.         // DumpRegisteredChannels
  978.         #endif // DEBUG
  979.        
  980.     }
  981.     // class ChannelServices
  982.    
  983.     // used by ChannelServices.NotifyProfiler
  984.     [Serializable()]
  985.     internal enum RemotingProfilerEvent
  986.     {
  987.         ClientSend,
  988.         ClientReceive
  989.     }
  990.     // RemotingProfilerEvent
  991.    
  992.    
  993.    
  994.     internal class RegisteredChannel
  995.     {
  996.         // private member variables
  997.         private IChannel channel;
  998.         private byte flags;
  999.         private const byte SENDER = 1;
  1000.         private const byte RECEIVER = 2;
  1001.        
  1002.         internal RegisteredChannel(IChannel chnl)
  1003.         {
  1004.             channel = chnl;
  1005.             flags = 0;
  1006.             if (chnl is IChannelSender) {
  1007.                 flags |= SENDER;
  1008.             }
  1009.             if (chnl is IChannelReceiver) {
  1010.                 flags |= RECEIVER;
  1011.             }
  1012.         }
  1013.        
  1014.         internal virtual IChannel Channel {
  1015.             get { return channel; }
  1016.         }
  1017.        
  1018.         internal virtual bool IsSender()
  1019.         {
  1020.             return ((flags & SENDER) != 0);
  1021.         }
  1022.        
  1023.         internal virtual bool IsReceiver()
  1024.         {
  1025.             return ((flags & RECEIVER) != 0);
  1026.         }
  1027.     }
  1028.     // class RegisteredChannel
  1029.    
  1030.    
  1031.     // This list should be considered immutable once created.
  1032.     internal class RegisteredChannelList
  1033.     {
  1034.         private RegisteredChannel[] _channels;
  1035.        
  1036.         internal RegisteredChannelList()
  1037.         {
  1038.             _channels = new RegisteredChannel[0];
  1039.         }
  1040.         // RegisteredChannelList
  1041.         internal RegisteredChannelList(RegisteredChannel[] channels)
  1042.         {
  1043.             _channels = channels;
  1044.         }
  1045.         // RegisteredChannelList
  1046.         internal RegisteredChannel[] RegisteredChannels {
  1047.             get { return _channels; }
  1048.         }
  1049.         // RegisteredChannels
  1050.         internal int Count {
  1051.             get {
  1052.                 if (_channels == null)
  1053.                     return 0;
  1054.                
  1055.                 return _channels.Length;
  1056.             }
  1057.         }
  1058.         // Count
  1059.         internal IChannel GetChannel(int index)
  1060.         {
  1061.             return _channels[index].Channel;
  1062.         }
  1063.         // GetChannel
  1064.         internal bool IsSender(int index)
  1065.         {
  1066.             return _channels[index].IsSender();
  1067.         }
  1068.         // IsSender
  1069.         internal bool IsReceiver(int index)
  1070.         {
  1071.             return _channels[index].IsReceiver();
  1072.         }
  1073.         // IsReceiver
  1074.         internal int ReceiverCount {
  1075.             get {
  1076.                 if (_channels == null)
  1077.                     return 0;
  1078.                
  1079.                 int total = 0;
  1080.                 for (int i = 0; i < _channels.Length; i++) {
  1081.                     if (IsReceiver(i))
  1082.                         total++;
  1083.                 }
  1084.                
  1085.                 return total;
  1086.             }
  1087.         }
  1088.         // ReceiverCount
  1089.         internal int FindChannelIndex(IChannel channel)
  1090.         {
  1091.             object chnlAsObject = (object)channel;
  1092.            
  1093.             for (int i = 0; i < _channels.Length; i++) {
  1094.                 if (chnlAsObject == (object)GetChannel(i))
  1095.                     return i;
  1096.             }
  1097.            
  1098.             return -1;
  1099.         }
  1100.         // FindChannelIndex
  1101.         internal int FindChannelIndex(string name)
  1102.         {
  1103.             for (int i = 0; i < _channels.Length; i++) {
  1104.                 if (String.Compare(name, GetChannel(i).ChannelName, StringComparison.OrdinalIgnoreCase) == 0)
  1105.                     return i;
  1106.             }
  1107.            
  1108.             return -1;
  1109.         }
  1110.         // FindChannelIndex
  1111.        
  1112.     }
  1113.     // class RegisteredChannelList
  1114.    
  1115.    
  1116.    
  1117.     internal class ChannelServicesData
  1118.     {
  1119.         internal long remoteCalls = 0;
  1120.         internal CrossContextChannel xctxmessageSink = null;
  1121.         internal CrossAppDomainChannel xadmessageSink = null;
  1122.         internal bool fRegisterWellKnownChannels = false;
  1123.     }
  1124.    
  1125.     //
  1126.     // Terminator sink used for profiling so that we can intercept asynchronous
  1127.     // replies on the server side.
  1128.     //
  1129.    
  1130. /* package scope */   
  1131.     internal class ServerAsyncReplyTerminatorSink : IMessageSink
  1132.     {
  1133.         internal IMessageSink _nextSink;
  1134.        
  1135.         internal ServerAsyncReplyTerminatorSink(IMessageSink nextSink)
  1136.         {
  1137.             BCLDebug.Assert(nextSink != null, "null IMessageSink passed to ServerAsyncReplyTerminatorSink ctor.");
  1138.             _nextSink = nextSink;
  1139.         }
  1140.        
  1141.         public virtual IMessage SyncProcessMessage(IMessage replyMsg)
  1142.         {
  1143.             // If this class has been brought into the picture, then the following must be true.
  1144.             BCLDebug.Assert(RemotingServices.CORProfilerTrackRemoting(), "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");
  1145.             BCLDebug.Assert(RemotingServices.CORProfilerTrackRemotingAsync(), "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");
  1146.            
  1147.             Guid g;
  1148.            
  1149.             // Notify the profiler that we are receiving an async reply from the server-side
  1150.             RemotingServices.CORProfilerRemotingServerSendingReply(out g, true);
  1151.            
  1152.             // If GUID cookies are active, then we save it for the other end of the channel
  1153.             if (RemotingServices.CORProfilerTrackRemotingCookie())
  1154.                 replyMsg.Properties["CORProfilerCookie"] = g;
  1155.            
  1156.             // Now that we've done the intercepting, pass the message on to the regular chain
  1157.             return _nextSink.SyncProcessMessage(replyMsg);
  1158.         }
  1159.        
  1160.         public virtual IMessageCtrl AsyncProcessMessage(IMessage replyMsg, IMessageSink replySink)
  1161.         {
  1162.             // Since this class is only used for intercepting async replies, this function should
  1163.             // never get called. (Async replies are synchronous, ironically)
  1164.             BCLDebug.Assert(false, "ServerAsyncReplyTerminatorSink.AsyncProcessMessage called!");
  1165.            
  1166.             return null;
  1167.         }
  1168.        
  1169.         public IMessageSink NextSink {
  1170.             get { return _nextSink; }
  1171.         }
  1172.        
  1173.         // Do I need a finalize here?
  1174.     }
  1175. }

Developer Fusion