//
// 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<registeredChannels.Count; n++)
+ {
+ if (registeredChannels [n] == (object)chnl) {
+ registeredChannels.RemoveAt (n);
+ IChannelReceiver chnlReceiver = chnl as IChannelReceiver;
+ if(chnlReceiver != null)
+ chnlReceiver.StopListening(null);
+ return;
+ }
+ }
+
+ throw new RemotingException ("Channel not registered");
+
+ }
}
internal static object [] GetCurrentChannelInfo ()
{
ArrayList list = new ArrayList ();
- foreach (object chnl_obj in registeredChannels) {
- IChannelReceiver chnl = chnl_obj as IChannelReceiver;
-
- if (chnl != null) {
- object chnl_data = chnl.ChannelData;
- if (chnl_data != null)
- list.Add (chnl_data);
+ lock (registeredChannels.SyncRoot)
+ {
+ foreach (object chnl_obj in registeredChannels) {
+ IChannelReceiver chnl = chnl_obj as IChannelReceiver;
+
+ if (chnl != null) {
+ object chnl_data = chnl.ChannelData;
+ if (chnl_data != null)
+ list.Add (chnl_data);
+ }
}
}
-
+
return list.ToArray ();
}
}
+
+ internal class ExceptionFilterSink: IMessageSink
+ {
+ IMessageSink _next;
+ IMessage _call;
+
+ public ExceptionFilterSink (IMessage call, IMessageSink next)
+ {
+ _call = call;
+ _next = next;
+ }
+
+ public IMessage SyncProcessMessage (IMessage msg)
+ {
+ return _next.SyncProcessMessage (ChannelServices.CheckReturnMessage (_call, msg));
+ }
+
+ public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
+ {
+ throw new InvalidOperationException();
+ }
+
+ public IMessageSink NextSink
+ {
+ get { return _next; }
+ }
+ }
}