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