using System.Diagnostics.Contracts; // ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== //* File: Channel.cs //* //* Author: Tarun Anand ([....]) //* //* 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.Runtime.Versioning; using System.Threading; using System.Security; using System.Security.Permissions; using System.Globalization; // ChannelServices [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)] internal struct Perf_Contexts { internal volatile int cRemoteCalls; internal volatile int cChannels; }; [System.Runtime.InteropServices.ComVisible(true)] public sealed class ChannelServices { // This gets refreshed when a channel is registered/unregistered. private static volatile Object[] s_currentChannelData = null; [System.Security.SecuritySafeCritical] // static constructors should be safe to call static ChannelServices() { } internal static Object[] CurrentChannelData { [System.Security.SecurityCritical] // auto-generated 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 // Note that the channel list is read outside of the lock, which is why it's marked volatile. private static Object s_channelLock = new Object(); private static volatile 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 (note: statics are per-AppDomain now, so these members // could just be declared as statics on ChannelServices). private static long remoteCalls { get { return Thread.GetDomain().RemotingData.ChannelServicesData.remoteCalls; } set { Thread.GetDomain().RemotingData.ChannelServicesData.remoteCalls = value; } } private static volatile IMessageSink xCtxChannel; [System.Security.SecurityCritical] // auto-generated [MethodImplAttribute(MethodImplOptions.InternalCall)] [ResourceExposure(ResourceScope.None)] static unsafe extern Perf_Contexts* GetPrivateContextsPerfCounters(); [SecurityCritical] unsafe private static volatile Perf_Contexts *perf_Contexts = GetPrivateContextsPerfCounters(); [System.Security.SecuritySafeCritical] // auto-generated [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] public static void RegisterChannel(IChannel chnl, bool ensureSecurity) { RegisterChannelInternal(chnl, ensureSecurity); } [System.Security.SecuritySafeCritical] // auto-generated [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; [System.Security.SecurityCritical] // auto-generated unsafe internal static void RegisterChannelInternal(IChannel chnl, bool ensureSecurity) { // Validate arguments if(null == chnl) { throw new ArgumentNullException("chnl"); } Contract.EndContractBlock(); bool fLocked = false; RuntimeHelpers.PrepareConstrainedRegions(); try { Monitor.Enter(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(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(Environment.GetResourceString("Remoting_ChannelNameAlreadyRegistered", chnl.ChannelName)); } RefreshChannelData(); } // lock (s_channelLock) finally { if (fLocked) { Monitor.Exit(s_channelLock); } } } // RegisterChannelInternal [System.Security.SecuritySafeCritical] // auto-generated [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.Enter(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(Environment.GetResourceString("Remoting_ChannelNotRegistered", chnl.ChannelName)); } RegisteredChannel[] oldList = regChnlList.RegisteredChannels; RegisteredChannel[] newList = null; Contract.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 { [System.Security.SecurityCritical] // auto-generated_required 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 [System.Security.SecurityCritical] // auto-generated 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 [System.Security.SecurityCritical] // auto-generated internal static IMessageSink CreateMessageSink(Object data) { String objectUri; return CreateMessageSink(null, data, out objectUri); } // CreateMessageSink [System.Security.SecurityCritical] // auto-generated_required 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 [System.Security.SecurityCritical] // auto-generated_required 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 // < [System.Security.SecurityCritical] // auto-generated 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; Contract.Assert(null != idObj,"null != idObj"); sink = idObj.ChannelSink; } } return sink; } // GetChannelSinkForProxy // Get the message sink dictionary of properties for a given proxy [System.Security.SecuritySafeCritical] // auto-generated [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 [System.Security.SecurityCritical] // auto-generated unsafe internal static void IncrementRemoteCalls(long cCalls) { remoteCalls += cCalls; if (perf_Contexts != null) perf_Contexts->cRemoteCalls += (int)cCalls; } // IncrementRemoteCalls [System.Security.SecurityCritical] // auto-generated internal static void IncrementRemoteCalls() { IncrementRemoteCalls( 1 ); } // IncrementRemoteCalls [System.Security.SecurityCritical] // auto-generated internal static void RefreshChannelData() { bool fLocked = false; RuntimeHelpers.PrepareConstrainedRegions(); try { Monitor.Enter(s_channelLock, ref fLocked); s_currentChannelData = CollectChannelDataFromChannels(); } finally { if (fLocked) { Monitor.Exit(s_channelLock); } } } // RefreshChannelData [System.Security.SecurityCritical] // auto-generated 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(Environment.GetResourceString("Remoting_ChannelNotRegistered", "")); } if (regChnlList.IsReceiver(i)) { BCLDebug.Trace("REMOTE", "Setting info for receiver " + j.ToString(CultureInfo.InvariantCulture) + "\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 ------------------------ //-------------------------------------------------------------------- [System.Security.SecurityCritical] // auto-generated_required 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 check to make sure that the // target object implements IMessageSink and dispatch synchronously. 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. // [System.Security.SecurityCritical] // auto-generated_required 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. // [System.Security.SecurityCritical] // auto-generated_required 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) [System.Security.SecurityCritical] // auto-generated_required 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. [System.Security.SecurityCritical] // auto-generated 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 check whether the // request if for a well known object. If yes, then we should // create the well known object lazily and marshal it. 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(Environment.GetResourceString("Remoting_Disconnected",uri)); } return ident; } // Channel Services AppDomain Unload Event Handler [System.Security.SecurityCritical] // auto-generated internal static void UnloadHandler(Object sender, EventArgs e) { StopListeningOnAllChannels(); } [System.Security.SecurityCritical] // auto-generated 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 // [System.Security.SecurityCritical] // auto-generated 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. [System.Security.SecurityCritical] // auto-generated 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. // < 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 [System.Security.SecurityCritical] // auto-generated 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) { Contract.Assert(nextSink != null, "null IMessageSink passed to ServerAsyncReplyTerminatorSink ctor."); _nextSink = nextSink; } [System.Security.SecurityCritical] // auto-generated public virtual IMessage SyncProcessMessage(IMessage replyMsg) { // If this class has been brought into the picture, then the following must be true. Contract.Assert(RemotingServices.CORProfilerTrackRemoting(), "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!"); Contract.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); } [System.Security.SecurityCritical] // auto-generated 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) Contract.Assert(false, "ServerAsyncReplyTerminatorSink.AsyncProcessMessage called!"); return null; } public IMessageSink NextSink { [System.Security.SecurityCritical] // auto-generated get { return _nextSink; } } // Do I need a finalize here? } }