2010-05-27 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.Runtime.Remoting.Channels / ChannelServices.cs
blob05794041cbcb787cbe281aa8735fc74abf8d770b
1 //
2 // System.Runtime.Remoting.Channels.ChannelServices.cs
3 //
4 // Author: Rodrigo Moya (rodrigo@ximian.com)
5 // Dietmar Maurer (dietmar@ximian.com)
6 // Lluis Sanchez Gual (lluis@ideary.com)
7 //
8 // 2002 (C) Copyright, Ximian, Inc.
9 //
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:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
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.Reflection;
36 using System.Runtime.Remoting;
37 using System.Runtime.Remoting.Channels;
38 using System.Runtime.Remoting.Messaging;
39 using System.Runtime.Remoting.Contexts;
41 namespace System.Runtime.Remoting
43 [Serializable]
44 internal class ChannelInfo : IChannelInfo
46 object [] channelData = null;
48 public ChannelInfo ()
50 channelData = ChannelServices.GetCurrentChannelInfo ();
53 public ChannelInfo (object remoteChannelData)
55 channelData = new object[] { remoteChannelData };
58 public object[] ChannelData
60 get {
61 return channelData;
64 set {
65 channelData = value;
71 namespace System.Runtime.Remoting.Channels
73 [System.Runtime.InteropServices.ComVisible (true)]
74 public sealed class ChannelServices
76 private static ArrayList registeredChannels = new ArrayList ();
77 private static ArrayList delayedClientChannels = new ArrayList ();
79 private static CrossContextChannel _crossContextSink = new CrossContextChannel();
81 internal static string CrossContextUrl = "__CrossContext";
83 private ChannelServices ()
87 internal static CrossContextChannel CrossContextChannel
89 get { return _crossContextSink; }
92 internal static IMessageSink CreateClientChannelSinkChain(string url, object remoteChannelData, out string objectUri)
94 // Locate a channel that can parse the url. This channel will be used to
95 // create the sink chain.
97 object[] channelDataArray = (object[])remoteChannelData;
99 lock (registeredChannels.SyncRoot)
101 // First of all, try registered channels
102 foreach (IChannel c in registeredChannels)
104 IChannelSender sender = c as IChannelSender;
105 if (sender == null) continue;
107 IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
108 if (sink != null) return sink;
111 // Not found. Try now creation delayed channels
112 RemotingConfiguration.LoadDefaultDelayedChannels ();
113 foreach (IChannelSender sender in delayedClientChannels)
115 IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
116 if (sink != null) {
117 delayedClientChannels.Remove (sender);
118 RegisterChannel (sender);
119 return sink;
124 objectUri = null;
125 return null;
128 internal static IMessageSink CreateClientChannelSinkChain (IChannelSender sender, string url, object[] channelDataArray, out string objectUri)
130 objectUri = null;
131 if (channelDataArray == null) {
132 return sender.CreateMessageSink (url, null, out objectUri);
134 else {
135 foreach (object data in channelDataArray) {
136 IMessageSink sink;
138 if (data is IChannelDataStore) {
139 // Don't provide the url in this case, since some channels won't
140 // check the channelData parameter if the url is not null.
141 sink = sender.CreateMessageSink (null, data, out objectUri);
142 } else {
143 sink = sender.CreateMessageSink (url, data, out objectUri);
145 if (sink != null) return sink;
148 return null;
151 public static IChannel[] RegisteredChannels
153 get {
154 lock (registeredChannels.SyncRoot)
156 ArrayList list = new ArrayList ();
158 for (int i = 0; i < registeredChannels.Count; i++) {
159 IChannel ch = (IChannel) registeredChannels[i];
160 if (ch is CrossAppDomainChannel) continue;
161 list.Add (ch);
164 return (IChannel[]) list.ToArray (typeof(IChannel));
169 public static IServerChannelSink CreateServerChannelSinkChain (
170 IServerChannelSinkProvider provider, IChannelReceiver channel)
172 IServerChannelSinkProvider tmp = provider;
173 while (tmp.Next != null) tmp = tmp.Next;
174 tmp.Next = new ServerDispatchSinkProvider ();
176 // Every provider has to call CreateSink() of its next provider
177 return provider.CreateSink (channel);
180 public static ServerProcessing DispatchMessage (
181 IServerChannelSinkStack sinkStack,
182 IMessage msg,
183 out IMessage replyMsg)
185 if (msg == null) throw new ArgumentNullException ("msg");
187 // Async processing is not done here because there isn't any way
188 // to know if a message is to be dispatched sync or asynchronously.
190 replyMsg = SyncDispatchMessage (msg);
192 if (RemotingServices.IsOneWay (((IMethodMessage) msg).MethodBase))
193 return ServerProcessing.OneWay;
194 else
195 return ServerProcessing.Complete;
198 public static IChannel GetChannel (string name)
200 lock (registeredChannels.SyncRoot)
202 foreach (IChannel chnl in registeredChannels) {
203 if (chnl.ChannelName == name && !(chnl is CrossAppDomainChannel)) return chnl;
205 return null;
209 public static IDictionary GetChannelSinkProperties (object obj)
211 if (!RemotingServices.IsTransparentProxy (obj))
212 throw new ArgumentException ("obj must be a proxy","obj");
214 ClientIdentity ident = (ClientIdentity) RemotingServices.GetRealProxy (obj).ObjectIdentity;
215 IMessageSink sink = ident.ChannelSink;
216 ArrayList dics = new ArrayList ();
218 while (sink != null && !(sink is IClientChannelSink))
219 sink = sink.NextSink;
221 if (sink == null)
222 return new Hashtable ();
224 IClientChannelSink csink = sink as IClientChannelSink;
225 while (csink != null)
227 dics.Add (csink.Properties);
228 csink = csink.NextChannelSink;
231 IDictionary[] adics = (IDictionary[]) dics.ToArray (typeof(IDictionary[]));
232 return new AggregateDictionary (adics);
235 public static string[] GetUrlsForObject (MarshalByRefObject obj)
237 string uri = RemotingServices.GetObjectUri (obj);
238 if (uri == null) return new string [0];
240 ArrayList list = new ArrayList ();
242 lock (registeredChannels.SyncRoot)
244 foreach (object chnl_obj in registeredChannels) {
245 if (chnl_obj is CrossAppDomainChannel) continue;
247 IChannelReceiver chnl = chnl_obj as IChannelReceiver;
249 if (chnl != null)
250 list.AddRange (chnl.GetUrlsForUri (uri));
254 return (string[]) list.ToArray (typeof(string));
257 [Obsolete ("Use RegisterChannel(IChannel,Boolean)")]
258 public static void RegisterChannel (IChannel chnl)
260 RegisterChannel (chnl, false);
263 public static void RegisterChannel (IChannel chnl, bool ensureSecurity)
265 if (chnl == null)
266 throw new ArgumentNullException ("chnl");
268 if (ensureSecurity) {
269 ISecurableChannel securable = chnl as ISecurableChannel;
270 if (securable == null)
271 throw new RemotingException (String.Format ("Channel {0} is not securable while ensureSecurity is specified as true", chnl.ChannelName));
272 securable.IsSecured = true;
275 // Put the channel in the correct place according to its priority.
276 // Since there are not many channels, a linear search is ok.
278 lock (registeredChannels.SyncRoot)
280 int pos = -1;
281 for (int n = 0; n < registeredChannels.Count; n++)
283 IChannel regc = (IChannel) registeredChannels[n];
285 if (regc.ChannelName == chnl.ChannelName && chnl.ChannelName != "")
286 throw new RemotingException ("Channel " + regc.ChannelName + " already registered");
288 if (regc.ChannelPriority < chnl.ChannelPriority && pos==-1)
289 pos = n;
292 if (pos != -1) registeredChannels.Insert (pos, chnl);
293 else registeredChannels.Add (chnl);
295 IChannelReceiver receiver = chnl as IChannelReceiver;
296 if (receiver != null && oldStartModeTypes.Contains (chnl.GetType().ToString ()))
297 receiver.StartListening (null);
301 internal static void RegisterChannelConfig (ChannelData channel)
303 IServerChannelSinkProvider serverSinks = null;
304 IClientChannelSinkProvider clientSinks = null;
306 // Create server providers
307 for (int n=channel.ServerProviders.Count-1; n>=0; n--)
309 ProviderData prov = channel.ServerProviders[n] as ProviderData;
310 IServerChannelSinkProvider sinkp = (IServerChannelSinkProvider) CreateProvider (prov);
311 sinkp.Next = serverSinks;
312 serverSinks = sinkp;
315 // Create client providers
316 for (int n=channel.ClientProviders.Count-1; n>=0; n--)
318 ProviderData prov = channel.ClientProviders[n] as ProviderData;
319 IClientChannelSinkProvider sinkp = (IClientChannelSinkProvider) CreateProvider (prov);
320 sinkp.Next = clientSinks;
321 clientSinks = sinkp;
324 // Create the channel
326 Type type = Type.GetType (channel.Type);
327 if (type == null) throw new RemotingException ("Type '" + channel.Type + "' not found");
329 Object[] parms;
330 Type[] signature;
331 bool clienc = typeof (IChannelSender).IsAssignableFrom (type);
332 bool serverc = typeof (IChannelReceiver).IsAssignableFrom (type);
334 if (clienc && serverc) {
335 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider), typeof(IServerChannelSinkProvider)};
336 parms = new Object[] {channel.CustomProperties, clientSinks, serverSinks};
338 else if (clienc) {
339 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider)};
340 parms = new Object[] {channel.CustomProperties, clientSinks};
342 else if (serverc) {
343 signature = new Type [] {typeof(IDictionary), typeof(IServerChannelSinkProvider)};
344 parms = new Object[] {channel.CustomProperties, serverSinks};
346 else
347 throw new RemotingException (type + " is not a valid channel type");
349 ConstructorInfo ctor = type.GetConstructor (signature);
350 if (ctor == null)
351 throw new RemotingException (type + " does not have a valid constructor");
353 IChannel ch;
356 ch = (IChannel) ctor.Invoke (parms);
358 catch (TargetInvocationException ex)
360 throw ex.InnerException;
363 lock (registeredChannels.SyncRoot)
365 if (channel.DelayLoadAsClientChannel == "true" && !(ch is IChannelReceiver))
366 delayedClientChannels.Add (ch);
367 else
368 RegisterChannel (ch);
372 static object CreateProvider (ProviderData prov)
374 Type pvtype = Type.GetType (prov.Type);
375 if (pvtype == null) throw new RemotingException ("Type '" + prov.Type + "' not found");
376 Object[] pvparms = new Object[] {prov.CustomProperties, prov.CustomData};
380 return Activator.CreateInstance (pvtype, pvparms);
382 catch (Exception ex)
384 if (ex is TargetInvocationException) ex = ((TargetInvocationException)ex).InnerException;
385 throw new RemotingException ("An instance of provider '" + pvtype + "' could not be created: " + ex.Message);
389 public static IMessage SyncDispatchMessage (IMessage msg)
391 IMessage ret = CheckIncomingMessage (msg);
392 if (ret != null) return CheckReturnMessage (msg, ret);
393 ret = _crossContextSink.SyncProcessMessage (msg);
394 return CheckReturnMessage (msg, ret);
397 public static IMessageCtrl AsyncDispatchMessage (IMessage msg, IMessageSink replySink)
399 IMessage ret = CheckIncomingMessage (msg);
400 if (ret != null) {
401 replySink.SyncProcessMessage (CheckReturnMessage (msg, ret));
402 return null;
405 #if NET_1_1
406 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (msg)))
407 replySink = new ExceptionFilterSink (msg, replySink);
408 #endif
410 return _crossContextSink.AsyncProcessMessage (msg, replySink);
413 static ReturnMessage CheckIncomingMessage (IMessage msg)
415 IMethodMessage call = (IMethodMessage)msg;
416 ServerIdentity identity = RemotingServices.GetIdentityForUri (call.Uri) as ServerIdentity;
418 if (identity == null)
419 return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg);
421 RemotingServices.SetMessageTargetIdentity (msg, identity);
422 return null;
425 internal static IMessage CheckReturnMessage (IMessage callMsg, IMessage retMsg)
427 #if NET_1_1
428 IMethodReturnMessage ret = retMsg as IMethodReturnMessage;
429 if (ret != null && ret.Exception != null)
431 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (callMsg)))
433 Exception ex = new Exception ("Server encountered an internal error. For more information, turn off customErrors in the server's .config file.");
434 retMsg = new MethodResponse (ex, (IMethodCallMessage)callMsg);
437 #endif
438 return retMsg;
441 static bool IsLocalCall (IMessage callMsg)
443 return true;
445 /* How can I know if a call is local?!?
447 object isLocal = callMsg.Properties ["__isLocalCall"];
448 if (isLocal == null) return false;
449 return (bool)isLocal;
453 public static void UnregisterChannel (IChannel chnl)
455 if (chnl == null)
456 throw new ArgumentNullException ();
458 lock (registeredChannels.SyncRoot)
460 for (int n=0; n<registeredChannels.Count; n++)
462 if (registeredChannels [n] == (object)chnl) {
463 registeredChannels.RemoveAt (n);
464 IChannelReceiver chnlReceiver = chnl as IChannelReceiver;
465 if(chnlReceiver != null)
466 chnlReceiver.StopListening(null);
467 return;
471 throw new RemotingException ("Channel not registered");
476 internal static object [] GetCurrentChannelInfo ()
478 ArrayList list = new ArrayList ();
480 lock (registeredChannels.SyncRoot)
482 foreach (object chnl_obj in registeredChannels) {
483 IChannelReceiver chnl = chnl_obj as IChannelReceiver;
485 if (chnl != null) {
486 object chnl_data = chnl.ChannelData;
487 if (chnl_data != null)
488 list.Add (chnl_data);
493 return list.ToArray ();
496 // Back compatibility fix. StartListener will be called for the types listed here
497 static IList oldStartModeTypes = new string[] {
498 "Novell.Zenworks.Zmd.Public.UnixServerChannel",
499 "Novell.Zenworks.Zmd.Public.UnixChannel"
503 internal class ExceptionFilterSink: IMessageSink
505 IMessageSink _next;
506 IMessage _call;
508 public ExceptionFilterSink (IMessage call, IMessageSink next)
510 _call = call;
511 _next = next;
514 public IMessage SyncProcessMessage (IMessage msg)
516 return _next.SyncProcessMessage (ChannelServices.CheckReturnMessage (_call, msg));
519 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
521 throw new InvalidOperationException();
524 public IMessageSink NextSink
526 get { return _next; }