X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2Fcorlib%2FSystem.Runtime.Remoting.Channels%2FChannelServices.cs;h=124d01a44294f656c7278191d65f4bf86d5acec5;hb=6e03e95d020719ce4c0e50ec6842d537be4a2746;hp=ce36fbf5d658e769e0f3c4cbd55fd4dee0723f6b;hpb=bcc53e7badabb4b740736fbd02e870b84b9c33d1;p=mono.git diff --git a/mcs/class/corlib/System.Runtime.Remoting.Channels/ChannelServices.cs b/mcs/class/corlib/System.Runtime.Remoting.Channels/ChannelServices.cs index ce36fbf5d65..124d01a4429 100644 --- a/mcs/class/corlib/System.Runtime.Remoting.Channels/ChannelServices.cs +++ b/mcs/class/corlib/System.Runtime.Remoting.Channels/ChannelServices.cs @@ -3,138 +3,492 @@ // // 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.Channels +namespace System.Runtime.Remoting { - internal class ChannelInfoStore : IChannelInfo + [Serializable] + internal class ChannelInfo : IChannelInfo { - object [] data = null; + object [] channelData = null; - public ChannelInfoStore () + public ChannelInfo () { - this.data = ChannelServices.GetCurrentChannelInfo (); + channelData = ChannelServices.GetCurrentChannelInfo (); } - - public object[] ChannelData { + public ChannelInfo (object remoteChannelData) + { + channelData = new object[] { remoteChannelData }; + } + + public object[] ChannelData + { get { - return data; + return channelData; } set { - data = value; + 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 () { } - - public static IChannel[] RegisteredChannels + + internal static CrossContextChannel CrossContextChannel { - get { - IChannel[] channels = new IChannel[registeredChannels.Count]; + 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. - for (int i = 0; i < registeredChannels.Count; i++) - channels[i] = (IChannel) registeredChannels[i]; + object[] channelDataArray = (object[])remoteChannelData; - return channels; + 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; } - - [MonoTODO] - public static IMessageCtrl AsyncDispatchMessage (IMessage msg, - IMessageSink replySink) + + 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 { - throw new NotImplementedException (); + 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 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); } - [MonoTODO] public static ServerProcessing DispatchMessage ( IServerChannelSinkStack sinkStack, IMessage msg, out IMessage replyMsg) { - throw new NotImplementedException (); + 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; } - [MonoTODO] public static IChannel GetChannel (string name) - { - throw new NotImplementedException (); + { + lock (registeredChannels.SyncRoot) + { + foreach (IChannel chnl in registeredChannels) { + if (chnl.ChannelName == name && !(chnl is CrossAppDomainChannel)) return chnl; + } + return null; + } } - [MonoTODO] public static IDictionary GetChannelSinkProperties (object obj) { - throw new NotImplementedException (); + 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); } - [MonoTODO] public static string[] GetUrlsForObject (MarshalByRefObject obj) { - throw new NotImplementedException (); + 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) - { - // fixme: sort it by priority - registeredChannels.Add ((object) 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); + } } - [MonoTODO] public static IMessage SyncDispatchMessage (IMessage msg) { - throw new NotImplementedException (); + 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 (); - if (!registeredChannels.Contains ((object) chnl)) - throw new RemotingException (); - - registeredChannels.Remove ((object) chnl); + + lock (registeredChannels.SyncRoot) + { + for (int n=0; n