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