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 public sealed class ChannelServices
75 private static ArrayList registeredChannels
= new ArrayList ();
76 private static ArrayList delayedClientChannels
= new ArrayList ();
78 private static CrossContextChannel _crossContextSink
= new CrossContextChannel();
80 internal static string CrossContextUrl
= "__CrossContext";
82 private ChannelServices ()
86 internal static CrossContextChannel CrossContextChannel
88 get { return _crossContextSink; }
91 internal static IMessageSink
CreateClientChannelSinkChain(string url
, object remoteChannelData
, out string objectUri
)
93 // Locate a channel that can parse the url. This channel will be used to
94 // create the sink chain.
96 object[] channelDataArray
= (object[])remoteChannelData
;
98 lock (registeredChannels
.SyncRoot
)
100 // First of all, try registered channels
101 foreach (IChannel c
in registeredChannels
)
103 IChannelSender sender
= c
as IChannelSender
;
104 if (sender
== null) continue;
106 IMessageSink sink
= CreateClientChannelSinkChain (sender
, url
, channelDataArray
, out objectUri
);
107 if (sink
!= null) return sink
;
110 // Not found. Try now creation delayed channels
111 RemotingConfiguration
.LoadDefaultDelayedChannels ();
112 foreach (IChannelSender sender
in delayedClientChannels
)
114 IMessageSink sink
= CreateClientChannelSinkChain (sender
, url
, channelDataArray
, out objectUri
);
116 delayedClientChannels
.Remove (sender
);
117 RegisterChannel (sender
);
127 internal static IMessageSink
CreateClientChannelSinkChain (IChannelSender sender
, string url
, object[] channelDataArray
, out string objectUri
)
130 if (channelDataArray
== null) {
131 return sender
.CreateMessageSink (url
, null, out objectUri
);
134 foreach (object data
in channelDataArray
) {
135 IMessageSink sink
= sender
.CreateMessageSink (url
, data
, out objectUri
);
136 if (sink
!= null) return sink
;
142 public static IChannel
[] RegisteredChannels
145 lock (registeredChannels
.SyncRoot
)
147 IChannel
[] channels
= new IChannel
[registeredChannels
.Count
];
149 for (int i
= 0; i
< registeredChannels
.Count
; i
++)
150 channels
[i
] = (IChannel
) registeredChannels
[i
];
157 public static IServerChannelSink
CreateServerChannelSinkChain (
158 IServerChannelSinkProvider provider
, IChannelReceiver channel
)
160 IServerChannelSinkProvider tmp
= provider
;
161 while (tmp
.Next
!= null) tmp
= tmp
.Next
;
162 tmp
.Next
= new ServerDispatchSinkProvider ();
164 // Every provider has to call CreateSink() of its next provider
165 return provider
.CreateSink (channel
);
168 public static ServerProcessing
DispatchMessage (
169 IServerChannelSinkStack sinkStack
,
171 out IMessage replyMsg
)
173 if (msg
== null) throw new ArgumentNullException ("msg");
175 // Async processing is not done here because there isn't any way
176 // to know if a message is to be dispatched sync or asynchronously.
178 replyMsg
= SyncDispatchMessage (msg
);
180 if (RemotingServices
.IsOneWay (((IMethodMessage
) msg
).MethodBase
))
181 return ServerProcessing
.OneWay
;
183 return ServerProcessing
.Complete
;
186 public static IChannel
GetChannel (string name
)
188 lock (registeredChannels
.SyncRoot
)
190 foreach (IChannel chnl
in registeredChannels
) {
191 if (chnl
.ChannelName
== name
&& !(chnl
is CrossAppDomainChannel
)) return chnl
;
197 public static IDictionary
GetChannelSinkProperties (object obj
)
199 if (!RemotingServices
.IsTransparentProxy (obj
))
200 throw new ArgumentException ("obj must be a proxy","obj");
202 ClientIdentity ident
= (ClientIdentity
) RemotingServices
.GetRealProxy (obj
).ObjectIdentity
;
203 IMessageSink sink
= ident
.ChannelSink
;
204 ArrayList dics
= new ArrayList ();
206 while (sink
!= null && !(sink
is IClientChannelSink
))
207 sink
= sink
.NextSink
;
210 return new Hashtable ();
212 IClientChannelSink csink
= sink
as IClientChannelSink
;
213 while (csink
!= null)
215 dics
.Add (csink
.Properties
);
216 csink
= csink
.NextChannelSink
;
219 IDictionary
[] adics
= (IDictionary
[]) dics
.ToArray (typeof(IDictionary
[]));
220 return new AggregateDictionary (adics
);
223 public static string[] GetUrlsForObject (MarshalByRefObject obj
)
225 string uri
= RemotingServices
.GetObjectUri (obj
);
226 if (uri
== null) return new string [0];
228 ArrayList list
= new ArrayList ();
230 lock (registeredChannels
.SyncRoot
)
232 foreach (object chnl_obj
in registeredChannels
) {
233 if (chnl_obj
is CrossAppDomainChannel
) continue;
235 IChannelReceiver chnl
= chnl_obj
as IChannelReceiver
;
238 list
.AddRange (chnl
.GetUrlsForUri (uri
));
242 return (string[]) list
.ToArray (typeof(string));
245 public static void RegisterChannel (IChannel chnl
)
247 // Put the channel in the correct place according to its priority.
248 // Since there are not many channels, a linear search is ok.
250 lock (registeredChannels
.SyncRoot
)
253 for (int n
= 0; n
< registeredChannels
.Count
; n
++)
255 IChannel regc
= (IChannel
) registeredChannels
[n
];
257 if (regc
.ChannelName
== chnl
.ChannelName
&& chnl
.ChannelName
!= "")
258 throw new RemotingException ("Channel " + regc
.ChannelName
+ " already registered");
260 if (regc
.ChannelPriority
< chnl
.ChannelPriority
&& pos
==-1)
264 if (pos
!= -1) registeredChannels
.Insert (pos
, chnl
);
265 else registeredChannels
.Add (chnl
);
267 IChannelReceiver receiver
= chnl
as IChannelReceiver
;
268 if (receiver
!= null) receiver
.StartListening (null);
272 internal static void RegisterChannelConfig (ChannelData channel
)
274 IServerChannelSinkProvider serverSinks
= null;
275 IClientChannelSinkProvider clientSinks
= null;
277 // Create server providers
278 for (int n
=channel
.ServerProviders
.Count
-1; n
>=0; n
--)
280 ProviderData prov
= channel
.ServerProviders
[n
] as ProviderData
;
281 IServerChannelSinkProvider sinkp
= (IServerChannelSinkProvider
) CreateProvider (prov
);
282 sinkp
.Next
= serverSinks
;
286 // Create client providers
287 for (int n
=channel
.ClientProviders
.Count
-1; n
>=0; n
--)
289 ProviderData prov
= channel
.ClientProviders
[n
] as ProviderData
;
290 IClientChannelSinkProvider sinkp
= (IClientChannelSinkProvider
) CreateProvider (prov
);
291 sinkp
.Next
= clientSinks
;
295 // Create the channel
297 Type type
= Type
.GetType (channel
.Type
);
298 if (type
== null) throw new RemotingException ("Type '" + channel
.Type
+ "' not found");
302 bool clienc
= typeof (IChannelSender
).IsAssignableFrom (type
);
303 bool serverc
= typeof (IChannelReceiver
).IsAssignableFrom (type
);
305 if (clienc
&& serverc
) {
306 signature
= new Type
[] {typeof(IDictionary), typeof(IClientChannelSinkProvider), typeof(IServerChannelSinkProvider)}
;
307 parms
= new Object
[] {channel.CustomProperties, clientSinks, serverSinks}
;
310 signature
= new Type
[] {typeof(IDictionary), typeof(IClientChannelSinkProvider)}
;
311 parms
= new Object
[] {channel.CustomProperties, clientSinks}
;
314 signature
= new Type
[] {typeof(IDictionary), typeof(IServerChannelSinkProvider)}
;
315 parms
= new Object
[] {channel.CustomProperties, serverSinks}
;
318 throw new RemotingException (type
+ " is not a valid channel type");
320 ConstructorInfo ctor
= type
.GetConstructor (signature
);
322 throw new RemotingException (type
+ " does not have a valid constructor");
327 ch
= (IChannel
) ctor
.Invoke (parms
);
329 catch (TargetInvocationException ex
)
331 throw ex
.InnerException
;
334 lock (registeredChannels
.SyncRoot
)
336 if (channel
.DelayLoadAsClientChannel
== "true" && !(ch
is IChannelReceiver
))
337 delayedClientChannels
.Add (ch
);
339 RegisterChannel (ch
);
343 static object CreateProvider (ProviderData prov
)
345 Type pvtype
= Type
.GetType (prov
.Type
);
346 if (pvtype
== null) throw new RemotingException ("Type '" + prov
.Type
+ "' not found");
347 Object
[] pvparms
= new Object
[] {prov.CustomProperties, prov.CustomData}
;
351 return Activator
.CreateInstance (pvtype
, pvparms
);
355 if (ex
is TargetInvocationException
) ex
= ((TargetInvocationException
)ex
).InnerException
;
356 throw new RemotingException ("An instance of provider '" + pvtype
+ "' could not be created: " + ex
.Message
);
360 public static IMessage
SyncDispatchMessage (IMessage msg
)
362 IMessage ret
= CheckIncomingMessage (msg
);
363 if (ret
!= null) return CheckReturnMessage (msg
, ret
);
364 ret
= _crossContextSink
.SyncProcessMessage (msg
);
365 return CheckReturnMessage (msg
, ret
);
368 public static IMessageCtrl
AsyncDispatchMessage (IMessage msg
, IMessageSink replySink
)
370 IMessage ret
= CheckIncomingMessage (msg
);
372 replySink
.SyncProcessMessage (CheckReturnMessage (msg
, ret
));
377 if (RemotingConfiguration
.CustomErrorsEnabled (IsLocalCall (msg
)))
378 replySink
= new ExceptionFilterSink (msg
, replySink
);
381 return _crossContextSink
.AsyncProcessMessage (msg
, replySink
);
384 static ReturnMessage
CheckIncomingMessage (IMessage msg
)
386 IMethodMessage call
= (IMethodMessage
)msg
;
387 ServerIdentity identity
= RemotingServices
.GetIdentityForUri (call
.Uri
) as ServerIdentity
;
389 if (identity
== null)
390 return new ReturnMessage (new RemotingException ("No receiver for uri " + call
.Uri
), (IMethodCallMessage
) msg
);
392 RemotingServices
.SetMessageTargetIdentity (msg
, identity
);
396 internal static IMessage
CheckReturnMessage (IMessage callMsg
, IMessage retMsg
)
399 IMethodReturnMessage ret
= retMsg
as IMethodReturnMessage
;
400 if (ret
!= null && ret
.Exception
!= null)
402 if (RemotingConfiguration
.CustomErrorsEnabled (IsLocalCall (callMsg
)))
404 Exception ex
= new Exception ("Server encountered an internal error. For more information, turn off customErrors in the server's .config file.");
405 retMsg
= new MethodResponse (ex
, (IMethodCallMessage
)callMsg
);
412 static bool IsLocalCall (IMessage callMsg
)
416 /* How can I know if a call is local?!?
418 object isLocal = callMsg.Properties ["__isLocalCall"];
419 if (isLocal == null) return false;
420 return (bool)isLocal;
424 public static void UnregisterChannel (IChannel chnl
)
427 throw new ArgumentNullException ();
429 lock (registeredChannels
.SyncRoot
)
431 for (int n
=0; n
<registeredChannels
.Count
; n
++)
433 if (registeredChannels
[n
] == (object)chnl
) {
434 registeredChannels
.RemoveAt (n
);
435 IChannelReceiver chnlReceiver
= chnl
as IChannelReceiver
;
436 if(chnlReceiver
!= null)
437 chnlReceiver
.StopListening(null);
442 throw new RemotingException ("Channel not registered");
447 internal static object [] GetCurrentChannelInfo ()
449 ArrayList list
= new ArrayList ();
451 lock (registeredChannels
.SyncRoot
)
453 foreach (object chnl_obj
in registeredChannels
) {
454 IChannelReceiver chnl
= chnl_obj
as IChannelReceiver
;
457 object chnl_data
= chnl
.ChannelData
;
458 if (chnl_data
!= null)
459 list
.Add (chnl_data
);
464 return list
.ToArray ();
468 internal class ExceptionFilterSink
: IMessageSink
473 public ExceptionFilterSink (IMessage call
, IMessageSink next
)
479 public IMessage
SyncProcessMessage (IMessage msg
)
481 return _next
.SyncProcessMessage (ChannelServices
.CheckReturnMessage (_call
, msg
));
484 public IMessageCtrl
AsyncProcessMessage (IMessage msg
, IMessageSink replySink
)
486 throw new InvalidOperationException();
489 public IMessageSink NextSink
491 get { return _next; }