merge r67228-r67235, r67237, r67251 and r67256-67259 to trunk (they are
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Channels / ChannelServices.cs
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 //
10
11 //
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 //
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.
32 //
33
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;
40
41 namespace System.Runtime.Remoting
42 {
43         [Serializable]
44         internal class ChannelInfo : IChannelInfo
45         {
46                 object [] channelData = null;
47
48                 public ChannelInfo ()
49                 {
50                         channelData = ChannelServices.GetCurrentChannelInfo ();
51                 }
52
53                 public ChannelInfo (object remoteChannelData)
54                 {
55                         channelData = new object[] { remoteChannelData };
56                 }
57                 
58                 public object[] ChannelData 
59                 {
60                         get {
61                                 return channelData;
62                         }
63                         
64                         set {
65                                 channelData = value;
66                         }
67                 }
68         }
69 }
70
71 namespace System.Runtime.Remoting.Channels
72 {
73         public sealed class ChannelServices
74         {
75                 private static ArrayList registeredChannels = new ArrayList ();
76                 private static ArrayList delayedClientChannels = new ArrayList ();
77                 
78                 private static CrossContextChannel _crossContextSink = new CrossContextChannel();
79                 
80                 internal static string CrossContextUrl = "__CrossContext";
81
82                 private ChannelServices ()
83                 {
84                 }
85
86                 internal static CrossContextChannel CrossContextChannel
87                 {
88                         get { return _crossContextSink; }
89                 }
90
91                 internal static IMessageSink CreateClientChannelSinkChain(string url, object remoteChannelData, out string objectUri)
92                 {
93                         // Locate a channel that can parse the url. This channel will be used to
94                         // create the sink chain.
95
96                         object[] channelDataArray = (object[])remoteChannelData;
97
98                         lock (registeredChannels.SyncRoot)
99                         {
100                                 // First of all, try registered channels
101                                 foreach (IChannel c in registeredChannels) 
102                                 {
103                                         IChannelSender sender = c as IChannelSender;
104                                         if (sender == null) continue;
105         
106                                         IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
107                                         if (sink != null) return sink;
108                                 }
109                                 
110                                 // Not found. Try now creation delayed channels
111                                 RemotingConfiguration.LoadDefaultDelayedChannels ();
112                                 foreach (IChannelSender sender in delayedClientChannels) 
113                                 {
114                                         IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
115                                         if (sink != null) {
116                                                 delayedClientChannels.Remove (sender);
117                                                 RegisterChannel (sender);
118                                                 return sink;
119                                         }
120                                 }
121                         }
122                         
123                         objectUri = null;
124                         return null;
125                 }
126                 
127                 internal static IMessageSink CreateClientChannelSinkChain (IChannelSender sender, string url, object[] channelDataArray, out string objectUri)
128                 {
129                         objectUri = null;
130                         if (channelDataArray == null) {
131                                 return sender.CreateMessageSink (url, null, out objectUri);
132                         }
133                         else {
134                                 foreach (object data in channelDataArray) {
135                                         IMessageSink sink = sender.CreateMessageSink (url, data, out objectUri);
136                                         if (sink != null) return sink;          
137                                 }
138                         }
139                         return null;
140                 }
141                 
142                 public static IChannel[] RegisteredChannels
143                 {
144                         get {
145                                 lock (registeredChannels.SyncRoot)
146                                 {
147                                         ArrayList list = new ArrayList ();
148                                         
149                                         for (int i = 0; i < registeredChannels.Count; i++) {
150                                                 IChannel ch = (IChannel) registeredChannels[i];
151                                                 if (ch is CrossAppDomainChannel) continue;
152                                                 list.Add (ch);
153                                         }
154
155                                         return (IChannel[]) list.ToArray (typeof(IChannel));
156                                 }
157                         }
158                 }
159
160                 public static IServerChannelSink CreateServerChannelSinkChain (
161                         IServerChannelSinkProvider provider, IChannelReceiver channel)
162             {
163                         IServerChannelSinkProvider tmp = provider;
164                         while (tmp.Next != null) tmp = tmp.Next;
165                         tmp.Next = new ServerDispatchSinkProvider ();
166
167                         // Every provider has to call CreateSink() of its next provider
168                         return  provider.CreateSink (channel);
169                 }
170
171                 public static ServerProcessing DispatchMessage (
172                         IServerChannelSinkStack sinkStack,
173                         IMessage msg,
174                         out IMessage replyMsg)
175                 {
176                         if (msg == null) throw new ArgumentNullException ("msg");
177                         
178                         // Async processing is not done here because there isn't any way
179                         // to know if a message is to be dispatched sync or asynchronously.
180
181                         replyMsg = SyncDispatchMessage (msg);
182
183                         if (RemotingServices.IsOneWay (((IMethodMessage) msg).MethodBase))
184                                 return ServerProcessing.OneWay;
185                         else
186                                 return ServerProcessing.Complete;
187                 }
188
189                 public static IChannel GetChannel (string name)
190                 {
191                         lock (registeredChannels.SyncRoot)
192                         {
193                                 foreach (IChannel chnl in registeredChannels) {
194                                         if (chnl.ChannelName == name && !(chnl is CrossAppDomainChannel)) return chnl;
195                                 }
196                                 return null;
197                         }
198                 }
199
200                 public static IDictionary GetChannelSinkProperties (object obj)
201                 {
202                         if (!RemotingServices.IsTransparentProxy (obj))
203                                 throw new ArgumentException ("obj must be a proxy","obj");
204                                 
205                         ClientIdentity ident = (ClientIdentity) RemotingServices.GetRealProxy (obj).ObjectIdentity;
206                         IMessageSink sink = ident.ChannelSink;
207                         ArrayList dics = new ArrayList ();
208                         
209                         while (sink != null && !(sink is IClientChannelSink))
210                                 sink = sink.NextSink;
211
212                         if (sink == null)
213                                 return new Hashtable ();
214
215                         IClientChannelSink csink = sink as IClientChannelSink;
216                         while (csink != null)
217                         {
218                                 dics.Add (csink.Properties);
219                                 csink = csink.NextChannelSink;
220                         }
221
222                         IDictionary[] adics = (IDictionary[]) dics.ToArray (typeof(IDictionary[]));
223                         return new AggregateDictionary (adics);
224                 }
225
226                 public static string[] GetUrlsForObject (MarshalByRefObject obj)
227                 {
228                         string uri = RemotingServices.GetObjectUri (obj);
229                         if (uri == null) return new string [0];
230
231                         ArrayList list = new ArrayList ();
232
233                         lock (registeredChannels.SyncRoot)
234                         {
235                                 foreach (object chnl_obj in registeredChannels) {
236                                         if (chnl_obj is CrossAppDomainChannel) continue;
237                                         
238                                         IChannelReceiver chnl = chnl_obj as IChannelReceiver;
239         
240                                         if (chnl != null)
241                                                 list.AddRange (chnl.GetUrlsForUri (uri));
242                                 }
243                         }
244                         
245                         return  (string[]) list.ToArray (typeof(string));
246                 }
247
248                 public static void RegisterChannel (IChannel chnl)
249                 {
250                         RegisterChannel (chnl, false);
251                 }
252
253 #if NET_2_0
254                 [MonoTODO ("Implement ensureSecurity")]
255                 public
256 #else
257                 internal
258 #endif
259                 static void RegisterChannel (IChannel chnl, bool ensureSecurity)
260                 {
261                         
262                         // Put the channel in the correct place according to its priority.
263                         // Since there are not many channels, a linear search is ok.
264
265                         lock (registeredChannels.SyncRoot)
266                         {
267                                 int pos = -1;
268                                 for (int n = 0; n < registeredChannels.Count; n++) 
269                                 {
270                                         IChannel regc = (IChannel) registeredChannels[n];
271                                         
272                                         if (regc.ChannelName == chnl.ChannelName && chnl.ChannelName != "")
273                                                 throw new RemotingException ("Channel " + regc.ChannelName + " already registered");
274                                                 
275                                         if (regc.ChannelPriority < chnl.ChannelPriority && pos==-1)
276                                                 pos = n;
277                                 }
278                                 
279                                 if (pos != -1) registeredChannels.Insert (pos, chnl);
280                                 else registeredChannels.Add (chnl);
281                                 
282                                 IChannelReceiver receiver = chnl as IChannelReceiver;
283                                 if (receiver != null) receiver.StartListening (null);
284                         }
285                 }
286
287                 internal static void RegisterChannelConfig (ChannelData channel)
288                 {
289                         IServerChannelSinkProvider serverSinks = null;
290                         IClientChannelSinkProvider clientSinks = null;
291                         
292                         // Create server providers
293                         for (int n=channel.ServerProviders.Count-1; n>=0; n--)
294                         {
295                                 ProviderData prov = channel.ServerProviders[n] as ProviderData;
296                                 IServerChannelSinkProvider sinkp = (IServerChannelSinkProvider) CreateProvider (prov);
297                                 sinkp.Next = serverSinks;
298                                 serverSinks = sinkp;
299                         }
300                         
301                         // Create client providers
302                         for (int n=channel.ClientProviders.Count-1; n>=0; n--)
303                         {
304                                 ProviderData prov = channel.ClientProviders[n] as ProviderData;
305                                 IClientChannelSinkProvider sinkp = (IClientChannelSinkProvider) CreateProvider (prov);
306                                 sinkp.Next = clientSinks;
307                                 clientSinks = sinkp;
308                         }
309
310                         // Create the channel
311                         
312                         Type type = Type.GetType (channel.Type);
313                         if (type == null) throw new RemotingException ("Type '" + channel.Type + "' not found");
314                         
315                         Object[] parms;                 
316                         Type[] signature;                       
317                         bool clienc = typeof (IChannelSender).IsAssignableFrom (type);
318                         bool serverc = typeof (IChannelReceiver).IsAssignableFrom (type);
319                         
320                         if (clienc && serverc) {
321                                 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider), typeof(IServerChannelSinkProvider)};
322                                 parms = new Object[] {channel.CustomProperties, clientSinks, serverSinks};
323                         }
324                         else if (clienc) {
325                                 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider)};
326                                 parms = new Object[] {channel.CustomProperties, clientSinks};
327                         }
328                         else if (serverc) {
329                                 signature = new Type [] {typeof(IDictionary), typeof(IServerChannelSinkProvider)};
330                                 parms = new Object[] {channel.CustomProperties, serverSinks};
331                         }
332                         else
333                                 throw new RemotingException (type + " is not a valid channel type");
334                                 
335                         ConstructorInfo ctor = type.GetConstructor (signature);
336                         if (ctor == null)
337                                 throw new RemotingException (type + " does not have a valid constructor");
338
339                         IChannel ch;
340                         try
341                         {
342                                 ch = (IChannel) ctor.Invoke (parms);
343                         }
344                         catch (TargetInvocationException ex)
345                         {
346                                 throw ex.InnerException;
347                         }
348                         
349                         lock (registeredChannels.SyncRoot)
350                         {
351                                 if (channel.DelayLoadAsClientChannel == "true" && !(ch is IChannelReceiver))
352                                         delayedClientChannels.Add (ch);
353                                 else
354                                         RegisterChannel (ch);
355                         }
356                 }
357                 
358                 static object CreateProvider (ProviderData prov)
359                 {
360                         Type pvtype = Type.GetType (prov.Type);
361                         if (pvtype == null) throw new RemotingException ("Type '" + prov.Type + "' not found");
362                         Object[] pvparms = new Object[] {prov.CustomProperties, prov.CustomData};
363                         
364                         try
365                         {
366                                 return Activator.CreateInstance (pvtype, pvparms);
367                         }
368                         catch (Exception ex)
369                         {
370                                 if (ex is TargetInvocationException) ex = ((TargetInvocationException)ex).InnerException;
371                                 throw new RemotingException ("An instance of provider '" + pvtype + "' could not be created: " + ex.Message);
372                         }
373                 }
374
375                 public static IMessage SyncDispatchMessage (IMessage msg)
376                 {
377                         IMessage ret = CheckIncomingMessage (msg);
378                         if (ret != null) return CheckReturnMessage (msg, ret);
379                         ret = _crossContextSink.SyncProcessMessage (msg);
380                         return CheckReturnMessage (msg, ret);
381                 }
382
383                 public static IMessageCtrl AsyncDispatchMessage (IMessage msg, IMessageSink replySink)
384                 {
385                         IMessage ret = CheckIncomingMessage (msg);
386                         if (ret != null) {
387                                 replySink.SyncProcessMessage (CheckReturnMessage (msg, ret));
388                                 return null;
389                         }
390                         
391 #if NET_1_1
392                         if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (msg)))
393                                 replySink = new ExceptionFilterSink (msg, replySink);
394 #endif
395                         
396                         return _crossContextSink.AsyncProcessMessage (msg, replySink);          
397                 }
398                 
399                 static ReturnMessage CheckIncomingMessage (IMessage msg)
400                 {
401                         IMethodMessage call = (IMethodMessage)msg;
402                         ServerIdentity identity = RemotingServices.GetIdentityForUri (call.Uri) as ServerIdentity;
403
404                         if (identity == null) 
405                                 return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg);
406
407                         RemotingServices.SetMessageTargetIdentity (msg, identity);
408                         return null;
409                 }
410
411                 internal static IMessage CheckReturnMessage (IMessage callMsg, IMessage retMsg)
412                 {
413 #if NET_1_1
414                         IMethodReturnMessage ret = retMsg as IMethodReturnMessage;
415                         if (ret != null && ret.Exception != null)
416                         {
417                                 if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (callMsg)))
418                                 {
419                                         Exception ex = new Exception ("Server encountered an internal error. For more information, turn off customErrors in the server's .config file.");
420                                         retMsg = new MethodResponse (ex, (IMethodCallMessage)callMsg);
421                                 }
422                         }
423 #endif
424                         return retMsg;
425                 }
426                 
427                 static bool IsLocalCall (IMessage callMsg)
428                 {
429                         return true;
430                         
431 /*                      How can I know if a call is local?!?
432                         
433                         object isLocal = callMsg.Properties ["__isLocalCall"];
434                         if (isLocal == null) return false;
435                         return (bool)isLocal;
436 */
437                 }
438
439                 public static void UnregisterChannel (IChannel chnl)
440                 {
441                         if (chnl == null)
442                                 throw new ArgumentNullException ();
443                                 
444                         lock (registeredChannels.SyncRoot)
445                         {
446                                 for (int n=0; n<registeredChannels.Count; n++) 
447                                 {
448                                         if (registeredChannels [n] == (object)chnl) {
449                                                 registeredChannels.RemoveAt (n);
450                                                 IChannelReceiver chnlReceiver = chnl as IChannelReceiver;
451                                                 if(chnlReceiver != null)
452                                                         chnlReceiver.StopListening(null);
453                                                 return;
454                                         }
455                                 }
456                                 
457                                 throw new RemotingException ("Channel not registered");
458         
459                         }
460                 }
461
462                 internal static object [] GetCurrentChannelInfo ()
463                 {
464                         ArrayList list = new ArrayList ();
465                         
466                         lock (registeredChannels.SyncRoot)
467                         {
468                                 foreach (object chnl_obj in registeredChannels) {
469                                         IChannelReceiver chnl = chnl_obj as IChannelReceiver;
470                                 
471                                         if (chnl != null) {
472                                                 object chnl_data = chnl.ChannelData;
473                                                 if (chnl_data != null)
474                                                         list.Add (chnl_data);
475                                         }
476                                 }
477                         }
478                         
479                         return  list.ToArray ();
480                 }
481         }
482         
483         internal class ExceptionFilterSink: IMessageSink
484         {
485                 IMessageSink _next;
486                 IMessage _call;
487                 
488                 public ExceptionFilterSink (IMessage call, IMessageSink next)
489                 {
490                         _call = call;
491                         _next = next;
492                 }
493                 
494                 public IMessage SyncProcessMessage (IMessage msg)
495                 {
496                         return _next.SyncProcessMessage (ChannelServices.CheckReturnMessage (_call, msg));
497                 }
498
499                 public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
500                 {
501                         throw new InvalidOperationException();
502                 }
503
504                 public IMessageSink NextSink 
505                 { 
506                         get { return _next; }
507                 }
508         }
509 }