2 // System.Runtime.Remoting.Channels.ChannelServices.cs
4 // Author: Rodrigo Moya (rodrigo@ximian.com)
5 // Dietmar Maurer (dietmar@ximian.com)
6 // Lluis Sanchez Gual (lluis@ideary.com)
8 // 2002 (C) Copyright, Ximian, Inc.
11 using System.Collections;
12 using System.Reflection;
13 using System.Runtime.Remoting;
14 using System.Runtime.Remoting.Channels;
15 using System.Runtime.Remoting.Messaging;
16 using System.Runtime.Remoting.Contexts;
18 namespace System.Runtime.Remoting
21 internal class ChannelInfo : IChannelInfo
23 object [] channelData = null;
27 channelData = ChannelServices.GetCurrentChannelInfo ();
30 public ChannelInfo (object remoteChannelData)
32 channelData = new object[] { remoteChannelData };
35 public object[] ChannelData
48 namespace System.Runtime.Remoting.Channels
50 public sealed class ChannelServices
52 private static ArrayList registeredChannels = new ArrayList ();
53 private static ArrayList delayedClientChannels = new ArrayList ();
55 private static CrossContextChannel _crossContextSink = new CrossContextChannel();
57 internal static string CrossContextUrl = "__CrossContext";
59 private ChannelServices ()
63 internal static CrossContextChannel CrossContextChannel
65 get { return _crossContextSink; }
68 internal static IMessageSink CreateClientChannelSinkChain(string url, object remoteChannelData, out string objectUri)
70 // Locate a channel that can parse the url. This channel will be used to
71 // create the sink chain.
73 object[] channelDataArray = (object[])remoteChannelData;
75 lock (registeredChannels.SyncRoot)
77 // First of all, try registered channels
78 foreach (IChannel c in registeredChannels)
80 IChannelSender sender = c as IChannelSender;
81 if (sender == null) continue;
83 IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
84 if (sink != null) return sink;
87 // Not found. Try now creation delayed channels
88 RemotingConfiguration.LoadDefaultDelayedChannels ();
89 foreach (IChannelSender sender in delayedClientChannels)
91 IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
93 delayedClientChannels.Remove (sender);
94 RegisterChannel (sender);
104 internal static IMessageSink CreateClientChannelSinkChain (IChannelSender sender, string url, object[] channelDataArray, out string objectUri)
107 if (channelDataArray == null) {
108 return sender.CreateMessageSink (url, null, out objectUri);
111 foreach (object data in channelDataArray) {
112 IMessageSink sink = sender.CreateMessageSink (url, data, out objectUri);
113 if (sink != null) return sink;
119 public static IChannel[] RegisteredChannels
122 lock (registeredChannels.SyncRoot)
124 IChannel[] channels = new IChannel[registeredChannels.Count];
126 for (int i = 0; i < registeredChannels.Count; i++)
127 channels[i] = (IChannel) registeredChannels[i];
134 public static IServerChannelSink CreateServerChannelSinkChain (
135 IServerChannelSinkProvider provider, IChannelReceiver channel)
137 IServerChannelSinkProvider tmp = provider;
138 while (tmp.Next != null) tmp = tmp.Next;
139 tmp.Next = new ServerDispatchSinkProvider ();
141 // Every provider has to call CreateSink() of its next provider
142 return provider.CreateSink (channel);
145 public static ServerProcessing DispatchMessage (
146 IServerChannelSinkStack sinkStack,
148 out IMessage replyMsg)
150 if (msg == null) throw new ArgumentNullException ("msg");
152 // Async processing is not done here because there isn't any way
153 // to know if a message is to be dispatched sync or asynchronously.
155 replyMsg = SyncDispatchMessage (msg);
157 if (RemotingServices.IsOneWay (((IMethodMessage) msg).MethodBase))
158 return ServerProcessing.OneWay;
160 return ServerProcessing.Complete;
163 public static IChannel GetChannel (string name)
165 lock (registeredChannels.SyncRoot)
167 foreach (IChannel chnl in registeredChannels) {
168 if (chnl.ChannelName == name && !(chnl is CrossAppDomainChannel)) return chnl;
174 public static IDictionary GetChannelSinkProperties (object obj)
176 if (!RemotingServices.IsTransparentProxy (obj))
177 throw new ArgumentException ("obj must be a proxy","obj");
179 ClientIdentity ident = (ClientIdentity) RemotingServices.GetRealProxy (obj).ObjectIdentity;
180 IMessageSink sink = ident.ChannelSink;
181 ArrayList dics = new ArrayList ();
183 while (sink != null && !(sink is IClientChannelSink))
184 sink = sink.NextSink;
187 return new Hashtable ();
189 IClientChannelSink csink = sink as IClientChannelSink;
190 while (csink != null)
192 dics.Add (csink.Properties);
193 csink = csink.NextChannelSink;
196 IDictionary[] adics = (IDictionary[]) dics.ToArray (typeof(IDictionary[]));
197 return new AggregateDictionary (adics);
200 public static string[] GetUrlsForObject (MarshalByRefObject obj)
202 string uri = RemotingServices.GetObjectUri (obj);
203 if (uri == null) return new string [0];
205 ArrayList list = new ArrayList ();
207 lock (registeredChannels.SyncRoot)
209 foreach (object chnl_obj in registeredChannels) {
210 if (chnl_obj is CrossAppDomainChannel) continue;
212 IChannelReceiver chnl = chnl_obj as IChannelReceiver;
215 list.AddRange (chnl.GetUrlsForUri (uri));
219 return (string[]) list.ToArray (typeof(string));
222 public static void RegisterChannel (IChannel chnl)
224 // Put the channel in the correct place according to its priority.
225 // Since there are not many channels, a linear search is ok.
227 lock (registeredChannels.SyncRoot)
230 for (int n = 0; n < registeredChannels.Count; n++)
232 IChannel regc = (IChannel) registeredChannels[n];
234 if (regc.ChannelName == chnl.ChannelName)
235 throw new RemotingException ("Channel " + regc.ChannelName + " already registered");
237 if (regc.ChannelPriority < chnl.ChannelPriority && pos==-1)
241 if (pos != -1) registeredChannels.Insert (pos, chnl);
242 else registeredChannels.Add (chnl);
244 IChannelReceiver receiver = chnl as IChannelReceiver;
245 if (receiver != null) receiver.StartListening (null);
249 internal static void RegisterChannelConfig (ChannelData channel)
251 IServerChannelSinkProvider serverSinks = null;
252 IClientChannelSinkProvider clientSinks = null;
254 // Create server providers
255 for (int n=channel.ServerProviders.Count-1; n>=0; n--)
257 ProviderData prov = channel.ServerProviders[n] as ProviderData;
258 IServerChannelSinkProvider sinkp = (IServerChannelSinkProvider) CreateProvider (prov);
259 sinkp.Next = serverSinks;
263 // Create client providers
264 for (int n=channel.ClientProviders.Count-1; n>=0; n--)
266 ProviderData prov = channel.ClientProviders[n] as ProviderData;
267 IClientChannelSinkProvider sinkp = (IClientChannelSinkProvider) CreateProvider (prov);
268 sinkp.Next = clientSinks;
272 // Create the channel
274 Type type = Type.GetType (channel.Type);
275 if (type == null) throw new RemotingException ("Type '" + channel.Type + "' not found");
279 bool clienc = typeof (IChannelSender).IsAssignableFrom (type);
280 bool serverc = typeof (IChannelReceiver).IsAssignableFrom (type);
282 if (clienc && serverc) {
283 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider), typeof(IServerChannelSinkProvider)};
284 parms = new Object[] {channel.CustomProperties, clientSinks, serverSinks};
287 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider)};
288 parms = new Object[] {channel.CustomProperties, clientSinks};
291 signature = new Type [] {typeof(IDictionary), typeof(IServerChannelSinkProvider)};
292 parms = new Object[] {channel.CustomProperties, serverSinks};
295 throw new RemotingException (type + " is not a valid channel type");
297 ConstructorInfo ctor = type.GetConstructor (signature);
299 throw new RemotingException (type + " does not have a valid constructor");
304 ch = (IChannel) ctor.Invoke (parms);
306 catch (TargetInvocationException ex)
308 throw ex.InnerException;
311 lock (registeredChannels.SyncRoot)
313 if (channel.DelayLoadAsClientChannel == "true" && !(ch is IChannelReceiver))
314 delayedClientChannels.Add (ch);
316 RegisterChannel (ch);
320 static object CreateProvider (ProviderData prov)
322 Type pvtype = Type.GetType (prov.Type);
323 if (pvtype == null) throw new RemotingException ("Type '" + prov.Type + "' not found");
324 Object[] pvparms = new Object[] {prov.CustomProperties, prov.CustomData};
328 return Activator.CreateInstance (pvtype, pvparms);
332 if (ex is TargetInvocationException) ex = ((TargetInvocationException)ex).InnerException;
333 throw new RemotingException ("An instance of provider '" + pvtype + "' could not be created: " + ex.Message);
337 public static IMessage SyncDispatchMessage (IMessage msg)
339 IMessage ret = CheckIncomingMessage (msg);
340 if (ret != null) return CheckReturnMessage (msg, ret);
341 ret = _crossContextSink.SyncProcessMessage (msg);
342 return CheckReturnMessage (msg, ret);
345 public static IMessageCtrl AsyncDispatchMessage (IMessage msg, IMessageSink replySink)
347 IMessage ret = CheckIncomingMessage (msg);
349 replySink.SyncProcessMessage (CheckReturnMessage (msg, ret));
354 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (msg)))
355 replySink = new ExceptionFilterSink (msg, replySink);
358 return _crossContextSink.AsyncProcessMessage (msg, replySink);
361 static ReturnMessage CheckIncomingMessage (IMessage msg)
363 IMethodMessage call = (IMethodMessage)msg;
364 ServerIdentity identity = RemotingServices.GetIdentityForUri (call.Uri) as ServerIdentity;
366 if (identity == null)
367 return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg);
369 RemotingServices.SetMessageTargetIdentity (msg, identity);
373 internal static IMessage CheckReturnMessage (IMessage callMsg, IMessage retMsg)
376 IMethodReturnMessage ret = retMsg as IMethodReturnMessage;
377 if (ret != null && ret.Exception != null)
379 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (callMsg)))
381 Exception ex = new Exception ("Server encountered an internal error. For more information, turn off customErrors in the server's .config file.");
382 retMsg = new MethodResponse (ex, (IMethodCallMessage)callMsg);
389 static bool IsLocalCall (IMessage callMsg)
393 /* How can I know if a call is local?!?
395 object isLocal = callMsg.Properties ["__isLocalCall"];
396 if (isLocal == null) return false;
397 return (bool)isLocal;
401 public static void UnregisterChannel (IChannel chnl)
404 throw new ArgumentNullException ();
406 lock (registeredChannels.SyncRoot)
408 if (!registeredChannels.Contains ((object) chnl))
409 throw new RemotingException ();
411 registeredChannels.Remove ((object) chnl);
413 IChannelReceiver chnlReceiver = chnl as IChannelReceiver;
414 if(chnlReceiver != null)
415 chnlReceiver.StopListening(null);
419 internal static object [] GetCurrentChannelInfo ()
421 ArrayList list = new ArrayList ();
423 lock (registeredChannels.SyncRoot)
425 foreach (object chnl_obj in registeredChannels) {
426 IChannelReceiver chnl = chnl_obj as IChannelReceiver;
429 object chnl_data = chnl.ChannelData;
430 if (chnl_data != null)
431 list.Add (chnl_data);
436 return list.ToArray ();
440 internal class ExceptionFilterSink: IMessageSink
445 public ExceptionFilterSink (IMessage call, IMessageSink next)
451 public IMessage SyncProcessMessage (IMessage msg)
453 return _next.SyncProcessMessage (ChannelServices.CheckReturnMessage (_call, msg));
456 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
458 throw new InvalidOperationException();
461 public IMessageSink NextSink
463 get { return _next; }