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.
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
35 using System.Collections.Generic;
36 using System.Reflection;
37 using System.Runtime.Remoting;
38 using System.Runtime.Remoting.Channels;
39 using System.Runtime.Remoting.Messaging;
40 using System.Runtime.Remoting.Contexts;
42 namespace System.Runtime.Remoting
45 internal class ChannelInfo : IChannelInfo
47 object [] channelData = null;
51 channelData = ChannelServices.GetCurrentChannelInfo ();
54 public ChannelInfo (object remoteChannelData)
56 channelData = new object[] { remoteChannelData };
59 public object[] ChannelData
72 namespace System.Runtime.Remoting.Channels
74 [System.Runtime.InteropServices.ComVisible (true)]
75 public sealed class ChannelServices
77 private static ArrayList registeredChannels = new ArrayList ();
78 private static ArrayList delayedClientChannels = new ArrayList ();
80 private static CrossContextChannel _crossContextSink = new CrossContextChannel();
82 internal static string CrossContextUrl = "__CrossContext";
84 private ChannelServices ()
88 internal static CrossContextChannel CrossContextChannel
90 get { return _crossContextSink; }
93 internal static IMessageSink CreateClientChannelSinkChain(string url, object remoteChannelData, out string objectUri)
95 // Locate a channel that can parse the url. This channel will be used to
96 // create the sink chain.
98 object[] channelDataArray = (object[])remoteChannelData;
100 lock (registeredChannels.SyncRoot)
102 // First of all, try registered channels
103 foreach (IChannel c in registeredChannels)
105 IChannelSender sender = c as IChannelSender;
106 if (sender == null) continue;
108 IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
109 if (sink != null) return sink;
112 // Not found. Try now creation delayed channels
113 RemotingConfiguration.LoadDefaultDelayedChannels ();
114 foreach (IChannelSender sender in delayedClientChannels)
116 IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
118 delayedClientChannels.Remove (sender);
119 RegisterChannel (sender);
129 internal static IMessageSink CreateClientChannelSinkChain (IChannelSender sender, string url, object[] channelDataArray, out string objectUri)
132 if (channelDataArray == null) {
133 return sender.CreateMessageSink (url, null, out objectUri);
136 foreach (object data in channelDataArray) {
139 if (data is IChannelDataStore) {
140 // Don't provide the url in this case, since some channels won't
141 // check the channelData parameter if the url is not null.
142 sink = sender.CreateMessageSink (null, data, out objectUri);
144 sink = sender.CreateMessageSink (url, data, out objectUri);
146 if (sink != null) return sink;
152 public static IChannel[] RegisteredChannels
155 lock (registeredChannels.SyncRoot)
157 var list = new List<IChannel> ();
159 for (int i = 0; i < registeredChannels.Count; i++) {
160 IChannel ch = (IChannel) registeredChannels[i];
161 if (ch is CrossAppDomainChannel) continue;
165 return list.ToArray ();
170 public static IServerChannelSink CreateServerChannelSinkChain (
171 IServerChannelSinkProvider provider, IChannelReceiver channel)
173 IServerChannelSinkProvider tmp = provider;
174 while (tmp.Next != null) tmp = tmp.Next;
175 tmp.Next = new ServerDispatchSinkProvider ();
177 // Every provider has to call CreateSink() of its next provider
178 return provider.CreateSink (channel);
181 public static ServerProcessing DispatchMessage (
182 IServerChannelSinkStack sinkStack,
184 out IMessage replyMsg)
186 if (msg == null) throw new ArgumentNullException ("msg");
188 // Async processing is not done here because there isn't any way
189 // to know if a message is to be dispatched sync or asynchronously.
191 replyMsg = SyncDispatchMessage (msg);
193 if (RemotingServices.IsOneWay (((IMethodMessage) msg).MethodBase))
194 return ServerProcessing.OneWay;
196 return ServerProcessing.Complete;
199 public static IChannel GetChannel (string name)
201 lock (registeredChannels.SyncRoot)
203 foreach (IChannel chnl in registeredChannels) {
204 if (chnl.ChannelName == name && !(chnl is CrossAppDomainChannel)) return chnl;
210 public static IDictionary GetChannelSinkProperties (object obj)
212 if (!RemotingServices.IsTransparentProxy (obj))
213 throw new ArgumentException ("obj must be a proxy","obj");
215 ClientIdentity ident = (ClientIdentity) RemotingServices.GetRealProxy (obj).ObjectIdentity;
216 IMessageSink sink = ident.ChannelSink;
217 var dics = new List<IDictionary> ();
219 while (sink != null && !(sink is IClientChannelSink))
220 sink = sink.NextSink;
223 return new Hashtable ();
225 IClientChannelSink csink = sink as IClientChannelSink;
226 while (csink != null)
228 dics.Add (csink.Properties);
229 csink = csink.NextChannelSink;
232 IDictionary[] adics = dics.ToArray ();
233 return new AggregateDictionary (adics);
236 public static string[] GetUrlsForObject (MarshalByRefObject obj)
238 string uri = RemotingServices.GetObjectUri (obj);
239 if (uri == null) return new string [0];
241 var list = new List<string> ();
243 lock (registeredChannels.SyncRoot)
245 foreach (object chnl_obj in registeredChannels) {
246 if (chnl_obj is CrossAppDomainChannel) continue;
248 IChannelReceiver chnl = chnl_obj as IChannelReceiver;
251 list.AddRange (chnl.GetUrlsForUri (uri));
255 return list.ToArray ();
258 [Obsolete ("Use RegisterChannel(IChannel,Boolean)")]
259 public static void RegisterChannel (IChannel chnl)
261 RegisterChannel (chnl, false);
264 public static void RegisterChannel (IChannel chnl, bool ensureSecurity)
267 throw new ArgumentNullException ("chnl");
269 if (ensureSecurity) {
270 ISecurableChannel securable = chnl as ISecurableChannel;
271 if (securable == null)
272 throw new RemotingException (String.Format ("Channel {0} is not securable while ensureSecurity is specified as true", chnl.ChannelName));
273 securable.IsSecured = true;
276 // Put the channel in the correct place according to its priority.
277 // Since there are not many channels, a linear search is ok.
279 lock (registeredChannels.SyncRoot)
282 for (int n = 0; n < registeredChannels.Count; n++)
284 IChannel regc = (IChannel) registeredChannels[n];
286 if (regc.ChannelName == chnl.ChannelName && chnl.ChannelName != "")
287 throw new RemotingException ("Channel " + regc.ChannelName + " already registered");
289 if (regc.ChannelPriority < chnl.ChannelPriority && pos==-1)
293 if (pos != -1) registeredChannels.Insert (pos, chnl);
294 else registeredChannels.Add (chnl);
296 IChannelReceiver receiver = chnl as IChannelReceiver;
297 if (receiver != null && oldStartModeTypes.Contains (chnl.GetType().ToString ()))
298 receiver.StartListening (null);
302 internal static void RegisterChannelConfig (ChannelData channel)
304 IServerChannelSinkProvider serverSinks = null;
305 IClientChannelSinkProvider clientSinks = null;
307 // Create server providers
308 for (int n=channel.ServerProviders.Count-1; n>=0; n--)
310 ProviderData prov = channel.ServerProviders[n] as ProviderData;
311 IServerChannelSinkProvider sinkp = (IServerChannelSinkProvider) CreateProvider (prov);
312 sinkp.Next = serverSinks;
316 // Create client providers
317 for (int n=channel.ClientProviders.Count-1; n>=0; n--)
319 ProviderData prov = channel.ClientProviders[n] as ProviderData;
320 IClientChannelSinkProvider sinkp = (IClientChannelSinkProvider) CreateProvider (prov);
321 sinkp.Next = clientSinks;
325 // Create the channel
327 Type type = Type.GetType (channel.Type);
328 if (type == null) throw new RemotingException ("Type '" + channel.Type + "' not found");
332 bool clienc = typeof (IChannelSender).IsAssignableFrom (type);
333 bool serverc = typeof (IChannelReceiver).IsAssignableFrom (type);
335 if (clienc && serverc) {
336 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider), typeof(IServerChannelSinkProvider)};
337 parms = new Object[] {channel.CustomProperties, clientSinks, serverSinks};
340 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider)};
341 parms = new Object[] {channel.CustomProperties, clientSinks};
344 signature = new Type [] {typeof(IDictionary), typeof(IServerChannelSinkProvider)};
345 parms = new Object[] {channel.CustomProperties, serverSinks};
348 throw new RemotingException (type + " is not a valid channel type");
350 ConstructorInfo ctor = type.GetConstructor (signature);
352 throw new RemotingException (type + " does not have a valid constructor");
357 ch = (IChannel) ctor.Invoke (parms);
359 catch (TargetInvocationException ex)
361 throw ex.InnerException;
364 lock (registeredChannels.SyncRoot)
366 if (channel.DelayLoadAsClientChannel == "true" && !(ch is IChannelReceiver))
367 delayedClientChannels.Add (ch);
369 RegisterChannel (ch);
373 static object CreateProvider (ProviderData prov)
375 Type pvtype = Type.GetType (prov.Type);
376 if (pvtype == null) throw new RemotingException ("Type '" + prov.Type + "' not found");
377 Object[] pvparms = new Object[] {prov.CustomProperties, prov.CustomData};
381 return Activator.CreateInstance (pvtype, pvparms);
385 if (ex is TargetInvocationException) ex = ((TargetInvocationException)ex).InnerException;
386 throw new RemotingException ("An instance of provider '" + pvtype + "' could not be created: " + ex.Message);
390 public static IMessage SyncDispatchMessage (IMessage msg)
392 IMessage ret = CheckIncomingMessage (msg);
393 if (ret != null) return CheckReturnMessage (msg, ret);
394 ret = _crossContextSink.SyncProcessMessage (msg);
395 return CheckReturnMessage (msg, ret);
398 public static IMessageCtrl AsyncDispatchMessage (IMessage msg, IMessageSink replySink)
400 IMessage ret = CheckIncomingMessage (msg);
402 replySink.SyncProcessMessage (CheckReturnMessage (msg, ret));
406 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (msg)))
407 replySink = new ExceptionFilterSink (msg, replySink);
409 return _crossContextSink.AsyncProcessMessage (msg, replySink);
412 static ReturnMessage CheckIncomingMessage (IMessage msg)
414 IMethodMessage call = (IMethodMessage)msg;
415 ServerIdentity identity = RemotingServices.GetIdentityForUri (call.Uri) as ServerIdentity;
417 if (identity == null)
418 return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg);
420 RemotingServices.SetMessageTargetIdentity (msg, identity);
424 internal static IMessage CheckReturnMessage (IMessage callMsg, IMessage retMsg)
426 IMethodReturnMessage ret = retMsg as IMethodReturnMessage;
427 if (ret != null && ret.Exception != null)
429 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (callMsg)))
431 Exception ex = new Exception ("Server encountered an internal error. For more information, turn off customErrors in the server's .config file.");
432 retMsg = new MethodResponse (ex, (IMethodCallMessage)callMsg);
438 static bool IsLocalCall (IMessage callMsg)
442 /* How can I know if a call is local?!?
444 object isLocal = callMsg.Properties ["__isLocalCall"];
445 if (isLocal == null) return false;
446 return (bool)isLocal;
450 public static void UnregisterChannel (IChannel chnl)
453 throw new ArgumentNullException ();
455 lock (registeredChannels.SyncRoot)
457 for (int n=0; n<registeredChannels.Count; n++)
459 if (registeredChannels [n] == (object)chnl) {
460 registeredChannels.RemoveAt (n);
461 IChannelReceiver chnlReceiver = chnl as IChannelReceiver;
462 if(chnlReceiver != null)
463 chnlReceiver.StopListening(null);
468 throw new RemotingException ("Channel not registered");
473 internal static object [] GetCurrentChannelInfo ()
475 var list = new List<object> ();
477 lock (registeredChannels.SyncRoot)
479 foreach (object chnl_obj in registeredChannels) {
480 IChannelReceiver chnl = chnl_obj as IChannelReceiver;
483 object chnl_data = chnl.ChannelData;
484 if (chnl_data != null)
485 list.Add (chnl_data);
490 return list.ToArray ();
493 // Back compatibility fix. StartListener will be called for the types listed here
494 static IList oldStartModeTypes = new string[] {
495 "Novell.Zenworks.Zmd.Public.UnixServerChannel",
496 "Novell.Zenworks.Zmd.Public.UnixChannel"
500 internal class ExceptionFilterSink: IMessageSink
505 public ExceptionFilterSink (IMessage call, IMessageSink next)
511 public IMessage SyncProcessMessage (IMessage msg)
513 return _next.SyncProcessMessage (ChannelServices.CheckReturnMessage (_call, msg));
516 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
518 throw new InvalidOperationException();
521 public IMessageSink NextSink
523 get { return _next; }