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
.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
44 internal class ChannelInfo
: IChannelInfo
46 object [] channelData
= null;
50 channelData
= ChannelServices
.GetCurrentChannelInfo ();
53 public ChannelInfo (object remoteChannelData
)
55 channelData
= new object[] { remoteChannelData }
;
58 public object[] ChannelData
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
);
117 delayedClientChannels
.Remove (sender
);
118 RegisterChannel (sender
);
128 internal static IMessageSink
CreateClientChannelSinkChain (IChannelSender sender
, string url
, object[] channelDataArray
, out string objectUri
)
131 if (channelDataArray
== null) {
132 return sender
.CreateMessageSink (url
, null, out objectUri
);
135 foreach (object data
in channelDataArray
) {
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
);
143 sink
= sender
.CreateMessageSink (url
, data
, out objectUri
);
145 if (sink
!= null) return sink
;
151 public static IChannel
[] RegisteredChannels
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;
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
,
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
;
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
;
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
;
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
;
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
)
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
)
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)
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
;
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
;
324 // Create the channel
326 Type type
= Type
.GetType (channel
.Type
);
327 if (type
== null) throw new RemotingException ("Type '" + channel
.Type
+ "' not found");
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}
;
339 signature
= new Type
[] {typeof(IDictionary), typeof(IClientChannelSinkProvider)}
;
340 parms
= new Object
[] {channel.CustomProperties, clientSinks}
;
343 signature
= new Type
[] {typeof(IDictionary), typeof(IServerChannelSinkProvider)}
;
344 parms
= new Object
[] {channel.CustomProperties, serverSinks}
;
347 throw new RemotingException (type
+ " is not a valid channel type");
349 ConstructorInfo ctor
= type
.GetConstructor (signature
);
351 throw new RemotingException (type
+ " does not have a valid constructor");
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
);
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
);
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
);
401 replySink
.SyncProcessMessage (CheckReturnMessage (msg
, ret
));
406 if (RemotingConfiguration
.CustomErrorsEnabled (IsLocalCall (msg
)))
407 replySink
= new ExceptionFilterSink (msg
, replySink
);
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
);
425 internal static IMessage
CheckReturnMessage (IMessage callMsg
, IMessage retMsg
)
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
);
441 static bool IsLocalCall (IMessage callMsg
)
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
)
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);
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
;
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
508 public ExceptionFilterSink (IMessage call
, IMessageSink 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; }