// // System.Runtime.Remoting.Channels.ChannelServices.cs // // Author: Rodrigo Moya (rodrigo@ximian.com) // Dietmar Maurer (dietmar@ximian.com) // Lluis Sanchez Gual (lluis@ideary.com) // // 2002 (C) Copyright, Ximian, Inc. // // // Copyright (C) 2004 Novell, Inc (http://www.novell.com) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System.Collections; using System.Reflection; using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Messaging; using System.Runtime.Remoting.Contexts; namespace System.Runtime.Remoting { [Serializable] internal class ChannelInfo : IChannelInfo { object [] channelData = null; public ChannelInfo () { channelData = ChannelServices.GetCurrentChannelInfo (); } public ChannelInfo (object remoteChannelData) { channelData = new object[] { remoteChannelData }; } public object[] ChannelData { get { return channelData; } set { channelData = value; } } } } namespace System.Runtime.Remoting.Channels { public sealed class ChannelServices { private static ArrayList registeredChannels = new ArrayList (); private static ArrayList delayedClientChannels = new ArrayList (); private static CrossContextChannel _crossContextSink = new CrossContextChannel(); internal static string CrossContextUrl = "__CrossContext"; private ChannelServices () { } internal static CrossContextChannel CrossContextChannel { get { return _crossContextSink; } } internal static IMessageSink CreateClientChannelSinkChain(string url, object remoteChannelData, out string objectUri) { // Locate a channel that can parse the url. This channel will be used to // create the sink chain. object[] channelDataArray = (object[])remoteChannelData; lock (registeredChannels.SyncRoot) { // First of all, try registered channels foreach (IChannel c in registeredChannels) { IChannelSender sender = c as IChannelSender; if (sender == null) continue; IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri); if (sink != null) return sink; } // Not found. Try now creation delayed channels RemotingConfiguration.LoadDefaultDelayedChannels (); foreach (IChannelSender sender in delayedClientChannels) { IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri); if (sink != null) { delayedClientChannels.Remove (sender); RegisterChannel (sender); return sink; } } } objectUri = null; return null; } internal static IMessageSink CreateClientChannelSinkChain (IChannelSender sender, string url, object[] channelDataArray, out string objectUri) { objectUri = null; if (channelDataArray == null) { return sender.CreateMessageSink (url, null, out objectUri); } else { foreach (object data in channelDataArray) { IMessageSink sink = sender.CreateMessageSink (url, data, out objectUri); if (sink != null) return sink; } } return null; } public static IChannel[] RegisteredChannels { get { lock (registeredChannels.SyncRoot) { IChannel[] channels = new IChannel[registeredChannels.Count]; for (int i = 0; i < registeredChannels.Count; i++) channels[i] = (IChannel) registeredChannels[i]; return channels; } } } public static IServerChannelSink CreateServerChannelSinkChain ( IServerChannelSinkProvider provider, IChannelReceiver channel) { IServerChannelSinkProvider tmp = provider; while (tmp.Next != null) tmp = tmp.Next; tmp.Next = new ServerDispatchSinkProvider (); // Every provider has to call CreateSink() of its next provider return provider.CreateSink (channel); } public static ServerProcessing DispatchMessage ( IServerChannelSinkStack sinkStack, IMessage msg, out IMessage replyMsg) { if (msg == null) throw new ArgumentNullException ("msg"); // Async processing is not done here because there isn't any way // to know if a message is to be dispatched sync or asynchronously. replyMsg = SyncDispatchMessage (msg); if (RemotingServices.IsOneWay (((IMethodMessage) msg).MethodBase)) return ServerProcessing.OneWay; else return ServerProcessing.Complete; } public static IChannel GetChannel (string name) { lock (registeredChannels.SyncRoot) { foreach (IChannel chnl in registeredChannels) { if (chnl.ChannelName == name && !(chnl is CrossAppDomainChannel)) return chnl; } return null; } } public static IDictionary GetChannelSinkProperties (object obj) { if (!RemotingServices.IsTransparentProxy (obj)) throw new ArgumentException ("obj must be a proxy","obj"); ClientIdentity ident = (ClientIdentity) RemotingServices.GetRealProxy (obj).ObjectIdentity; IMessageSink sink = ident.ChannelSink; ArrayList dics = new ArrayList (); while (sink != null && !(sink is IClientChannelSink)) sink = sink.NextSink; if (sink == null) return new Hashtable (); IClientChannelSink csink = sink as IClientChannelSink; while (csink != null) { dics.Add (csink.Properties); csink = csink.NextChannelSink; } IDictionary[] adics = (IDictionary[]) dics.ToArray (typeof(IDictionary[])); return new AggregateDictionary (adics); } public static string[] GetUrlsForObject (MarshalByRefObject obj) { string uri = RemotingServices.GetObjectUri (obj); if (uri == null) return new string [0]; ArrayList list = new ArrayList (); lock (registeredChannels.SyncRoot) { foreach (object chnl_obj in registeredChannels) { if (chnl_obj is CrossAppDomainChannel) continue; IChannelReceiver chnl = chnl_obj as IChannelReceiver; if (chnl != null) list.AddRange (chnl.GetUrlsForUri (uri)); } } return (string[]) list.ToArray (typeof(string)); } public static void RegisterChannel (IChannel chnl) { // Put the channel in the correct place according to its priority. // Since there are not many channels, a linear search is ok. lock (registeredChannels.SyncRoot) { int pos = -1; for (int n = 0; n < registeredChannels.Count; n++) { IChannel regc = (IChannel) registeredChannels[n]; if (regc.ChannelName == chnl.ChannelName && chnl.ChannelName != "") throw new RemotingException ("Channel " + regc.ChannelName + " already registered"); if (regc.ChannelPriority < chnl.ChannelPriority && pos==-1) pos = n; } if (pos != -1) registeredChannels.Insert (pos, chnl); else registeredChannels.Add (chnl); IChannelReceiver receiver = chnl as IChannelReceiver; if (receiver != null) receiver.StartListening (null); } } internal static void RegisterChannelConfig (ChannelData channel) { IServerChannelSinkProvider serverSinks = null; IClientChannelSinkProvider clientSinks = null; // Create server providers for (int n=channel.ServerProviders.Count-1; n>=0; n--) { ProviderData prov = channel.ServerProviders[n] as ProviderData; IServerChannelSinkProvider sinkp = (IServerChannelSinkProvider) CreateProvider (prov); sinkp.Next = serverSinks; serverSinks = sinkp; } // Create client providers for (int n=channel.ClientProviders.Count-1; n>=0; n--) { ProviderData prov = channel.ClientProviders[n] as ProviderData; IClientChannelSinkProvider sinkp = (IClientChannelSinkProvider) CreateProvider (prov); sinkp.Next = clientSinks; clientSinks = sinkp; } // Create the channel Type type = Type.GetType (channel.Type); if (type == null) throw new RemotingException ("Type '" + channel.Type + "' not found"); Object[] parms; Type[] signature; bool clienc = typeof (IChannelSender).IsAssignableFrom (type); bool serverc = typeof (IChannelReceiver).IsAssignableFrom (type); if (clienc && serverc) { signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider), typeof(IServerChannelSinkProvider)}; parms = new Object[] {channel.CustomProperties, clientSinks, serverSinks}; } else if (clienc) { signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider)}; parms = new Object[] {channel.CustomProperties, clientSinks}; } else if (serverc) { signature = new Type [] {typeof(IDictionary), typeof(IServerChannelSinkProvider)}; parms = new Object[] {channel.CustomProperties, serverSinks}; } else throw new RemotingException (type + " is not a valid channel type"); ConstructorInfo ctor = type.GetConstructor (signature); if (ctor == null) throw new RemotingException (type + " does not have a valid constructor"); IChannel ch; try { ch = (IChannel) ctor.Invoke (parms); } catch (TargetInvocationException ex) { throw ex.InnerException; } lock (registeredChannels.SyncRoot) { if (channel.DelayLoadAsClientChannel == "true" && !(ch is IChannelReceiver)) delayedClientChannels.Add (ch); else RegisterChannel (ch); } } static object CreateProvider (ProviderData prov) { Type pvtype = Type.GetType (prov.Type); if (pvtype == null) throw new RemotingException ("Type '" + prov.Type + "' not found"); Object[] pvparms = new Object[] {prov.CustomProperties, prov.CustomData}; try { return Activator.CreateInstance (pvtype, pvparms); } catch (Exception ex) { if (ex is TargetInvocationException) ex = ((TargetInvocationException)ex).InnerException; throw new RemotingException ("An instance of provider '" + pvtype + "' could not be created: " + ex.Message); } } public static IMessage SyncDispatchMessage (IMessage msg) { IMessage ret = CheckIncomingMessage (msg); if (ret != null) return CheckReturnMessage (msg, ret); ret = _crossContextSink.SyncProcessMessage (msg); return CheckReturnMessage (msg, ret); } public static IMessageCtrl AsyncDispatchMessage (IMessage msg, IMessageSink replySink) { IMessage ret = CheckIncomingMessage (msg); if (ret != null) { replySink.SyncProcessMessage (CheckReturnMessage (msg, ret)); return null; } #if NET_1_1 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (msg))) replySink = new ExceptionFilterSink (msg, replySink); #endif return _crossContextSink.AsyncProcessMessage (msg, replySink); } static ReturnMessage CheckIncomingMessage (IMessage msg) { IMethodMessage call = (IMethodMessage)msg; ServerIdentity identity = RemotingServices.GetIdentityForUri (call.Uri) as ServerIdentity; if (identity == null) return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg); RemotingServices.SetMessageTargetIdentity (msg, identity); return null; } internal static IMessage CheckReturnMessage (IMessage callMsg, IMessage retMsg) { #if NET_1_1 IMethodReturnMessage ret = retMsg as IMethodReturnMessage; if (ret != null && ret.Exception != null) { if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (callMsg))) { Exception ex = new Exception ("Server encountered an internal error. For more information, turn off customErrors in the server's .config file."); retMsg = new MethodResponse (ex, (IMethodCallMessage)callMsg); } } #endif return retMsg; } static bool IsLocalCall (IMessage callMsg) { return true; /* How can I know if a call is local?!? object isLocal = callMsg.Properties ["__isLocalCall"]; if (isLocal == null) return false; return (bool)isLocal; */ } public static void UnregisterChannel (IChannel chnl) { if (chnl == null) throw new ArgumentNullException (); lock (registeredChannels.SyncRoot) { for (int n=0; n