ChannelServices.cs: Catch errors when creating configured channels.
[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 using System.Collections;
12 using System.Reflection;
13 using System.Runtime.Remoting;
14 using System.Runtime.Remoting.Channels;
15 using System.Runtime.Remoting.Messaging;
16 using System.Runtime.Remoting.Contexts;
17
18 namespace System.Runtime.Remoting
19 {
20         [Serializable]
21         internal class ChannelInfo : IChannelInfo
22         {
23                 object [] channelData = null;
24
25                 public ChannelInfo ()
26                 {
27                         channelData = ChannelServices.GetCurrentChannelInfo ();
28                 }
29
30                 public ChannelInfo (object remoteChannelData)
31                 {
32                         channelData = new object[] { remoteChannelData };
33                 }
34                 
35                 public object[] ChannelData 
36                 {
37                         get {
38                                 return channelData;
39                         }
40                         
41                         set {
42                                 channelData = value;
43                         }
44                 }
45         }
46 }
47
48 namespace System.Runtime.Remoting.Channels
49 {
50         public sealed class ChannelServices
51         {
52                 private static ArrayList registeredChannels = new ArrayList ();
53                 private static ArrayList delayedClientChannels = new ArrayList ();
54                 
55                 private static CrossContextChannel _crossContextSink = new CrossContextChannel();
56                 
57                 internal static string CrossContextUrl = "__CrossContext";
58
59                 private ChannelServices ()
60                 {
61                 }
62
63                 internal static CrossContextChannel CrossContextChannel
64                 {
65                         get { return _crossContextSink; }
66                 }
67
68                 internal static IMessageSink CreateClientChannelSinkChain(string url, object remoteChannelData, out string objectUri)
69                 {
70                         // Locate a channel that can parse the url. This channel will be used to
71                         // create the sink chain.
72
73                         object[] channelDataArray = (object[])remoteChannelData;
74
75                         lock (registeredChannels.SyncRoot)
76                         {
77                                 // First of all, try registered channels
78                                 foreach (IChannel c in registeredChannels) 
79                                 {
80                                         IChannelSender sender = c as IChannelSender;
81                                         if (sender == null) continue;
82         
83                                         IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
84                                         if (sink != null) return sink;
85                                 }
86                                 
87                                 // Not found. Try now creation delayed channels
88                                 foreach (IChannelSender sender in delayedClientChannels) 
89                                 {
90                                         IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
91                                         if (sink != null) {
92                                                 delayedClientChannels.Remove (sender);
93                                                 RegisterChannel (sender);
94                                                 return sink;
95                                         }
96                                 }
97                         }
98                         
99                         objectUri = null;
100                         return null;
101                 }
102                 
103                 internal static IMessageSink CreateClientChannelSinkChain (IChannelSender sender, string url, object[] channelDataArray, out string objectUri)
104                 {
105                         objectUri = null;
106                         if (channelDataArray == null) {
107                                 return sender.CreateMessageSink (url, null, out objectUri);
108                         }
109                         else {
110                                 foreach (object data in channelDataArray) {
111                                         IMessageSink sink = sender.CreateMessageSink (url, data, out objectUri);
112                                         if (sink != null) return sink;          
113                                 }
114                         }
115                         return null;
116                 }
117                 
118                 public static IChannel[] RegisteredChannels
119                 {
120                         get {
121                                 lock (registeredChannels.SyncRoot)
122                                 {
123                                         IChannel[] channels = new IChannel[registeredChannels.Count];
124         
125                                         for (int i = 0; i < registeredChannels.Count; i++)
126                                                 channels[i] = (IChannel) registeredChannels[i];
127         
128                                         return channels;
129                                 }
130                         }
131                 }
132
133                 [MonoTODO]
134                 public static IMessageCtrl AsyncDispatchMessage (IMessage msg,
135                                                                  IMessageSink replySink)
136                 {
137                         throw new NotImplementedException ();
138                 }
139
140                 public static IServerChannelSink CreateServerChannelSinkChain (
141                         IServerChannelSinkProvider provider, IChannelReceiver channel)
142             {
143                         IServerChannelSinkProvider tmp = provider;
144                         while (tmp.Next != null) tmp = tmp.Next;
145                         tmp.Next = new ServerDispatchSinkProvider ();
146
147                         // Every provider has to call CreateSink() of its next provider
148                         return  provider.CreateSink (channel);
149                 }
150
151                 [MonoTODO]
152                 public static ServerProcessing DispatchMessage (
153                         IServerChannelSinkStack sinkStack,
154                         IMessage msg,
155                         out IMessage replyMsg)
156                 {
157                         // TODO: Async processing
158
159                         replyMsg = SyncDispatchMessage (msg);
160
161                         if (RemotingServices.IsOneWay (((IMethodMessage) msg).MethodBase))
162                                 return ServerProcessing.OneWay;
163                         else
164                                 return ServerProcessing.Complete;
165                 }
166
167                 public static IChannel GetChannel (string name)
168                 {
169                         lock (registeredChannels.SyncRoot)
170                         {
171                                 foreach (IChannel chnl in registeredChannels) {
172                                         if (chnl.ChannelName == name && !(chnl is CrossAppDomainChannel)) return chnl;
173                                 }
174                                 return null;
175                         }
176                 }
177
178                 [MonoTODO]
179                 public static IDictionary GetChannelSinkProperties (object obj)
180                 {
181                         throw new NotImplementedException ();
182                 }
183
184                 public static string[] GetUrlsForObject (MarshalByRefObject obj)
185                 {
186                         string uri = RemotingServices.GetObjectUri (obj);
187                         if (uri == null) return new string [0];
188
189                         ArrayList list = new ArrayList ();
190
191                         lock (registeredChannels.SyncRoot)
192                         {
193                                 foreach (object chnl_obj in registeredChannels) {
194                                         if (chnl_obj is CrossAppDomainChannel) continue;
195                                         
196                                         IChannelReceiver chnl = chnl_obj as IChannelReceiver;
197         
198                                         if (chnl != null)
199                                                 list.AddRange (chnl.GetUrlsForUri (uri));
200                                 }
201                         }
202                         
203                         return  (string[]) list.ToArray (typeof(string));
204                 }
205
206                 public static void RegisterChannel (IChannel chnl)
207                 {
208                         // Put the channel in the correct place according to its priority.
209                         // Since there are not many channels, a linear search is ok.
210
211                         lock (registeredChannels.SyncRoot)
212                         {
213                                 int pos = -1;
214                                 for (int n = 0; n < registeredChannels.Count; n++) 
215                                 {
216                                         IChannel regc = (IChannel) registeredChannels[n];
217                                         
218                                         if (regc.ChannelName == chnl.ChannelName)
219                                                 throw new RemotingException ("Channel " + regc.ChannelName + " already registered");
220                                                 
221                                         if (regc.ChannelPriority < chnl.ChannelPriority && pos==-1)
222                                                 pos = n;
223                                 }
224                                 
225                                 if (pos != -1) registeredChannels.Insert (pos, chnl);
226                                 else registeredChannels.Add (chnl);
227                                 
228                                 IChannelReceiver receiver = chnl as IChannelReceiver;
229                                 if (receiver != null) receiver.StartListening (null);
230                         }
231                 }
232
233                 internal static void RegisterChannelConfig (ChannelData channel)
234                 {
235                         IServerChannelSinkProvider serverSinks = null;
236                         IClientChannelSinkProvider clientSinks = null;
237                         
238                         // Create server providers
239                         for (int n=channel.ServerProviders.Count-1; n>=0; n--)
240                         {
241                                 ProviderData prov = channel.ServerProviders[n] as ProviderData;
242                                 IServerChannelSinkProvider sinkp = (IServerChannelSinkProvider) CreateProvider (prov);
243                                 sinkp.Next = serverSinks;
244                                 serverSinks = sinkp;
245                         }
246                         
247                         // Create client providers
248                         for (int n=channel.ClientProviders.Count-1; n>=0; n--)
249                         {
250                                 ProviderData prov = channel.ClientProviders[n] as ProviderData;
251                                 IClientChannelSinkProvider sinkp = (IClientChannelSinkProvider) CreateProvider (prov);
252                                 sinkp.Next = clientSinks;
253                                 clientSinks = sinkp;
254                         }
255
256                         // Create the channel
257                         
258                         Type type = Type.GetType (channel.Type);
259                         if (type == null) throw new RemotingException ("Type '" + channel.Type + "' not found");
260                         
261                         Object[] parms;                 
262                         Type[] signature;                       
263                         bool clienc = typeof (IChannelSender).IsAssignableFrom (type);
264                         bool serverc = typeof (IChannelReceiver).IsAssignableFrom (type);
265                         
266                         if (clienc && serverc) {
267                                 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider), typeof(IServerChannelSinkProvider)};
268                                 parms = new Object[] {channel.CustomProperties, clientSinks, serverSinks};
269                         }
270                         else if (clienc) {
271                                 signature = new Type [] {typeof(IDictionary), typeof(IClientChannelSinkProvider)};
272                                 parms = new Object[] {channel.CustomProperties, clientSinks};
273                         }
274                         else if (serverc) {
275                                 signature = new Type [] {typeof(IDictionary), typeof(IServerChannelSinkProvider)};
276                                 parms = new Object[] {channel.CustomProperties, serverSinks};
277                         }
278                         else
279                                 throw new RemotingException (type + " is not a valid channel type");
280                                 
281                         ConstructorInfo ctor = type.GetConstructor (signature);
282                         if (ctor == null)
283                                 throw new RemotingException (type + " does not have a valid constructor");
284
285                         IChannel ch;
286                         try
287                         {
288                                 ch = (IChannel) ctor.Invoke (parms);
289                         }
290                         catch (TargetInvocationException ex)
291                         {
292                                 throw ex.InnerException;
293                         }
294                         
295                         lock (registeredChannels.SyncRoot)
296                         {
297                                 if (channel.DelayLoadAsClientChannel == "true" && !(ch is IChannelReceiver))
298                                         delayedClientChannels.Add (ch);
299                                 else
300                                         RegisterChannel (ch);
301                         }
302                 }
303                 
304                 static object CreateProvider (ProviderData prov)
305                 {
306                         Type pvtype = Type.GetType (prov.Type);
307                         if (pvtype == null) throw new RemotingException ("Type '" + prov.Type + "' not found");
308                         Object[] pvparms = new Object[] {prov.CustomProperties, prov.CustomData};
309                         
310                         try
311                         {
312                                 return Activator.CreateInstance (pvtype, pvparms);
313                         }
314                         catch (Exception ex)
315                         {
316                                 if (ex is TargetInvocationException) ex = ((TargetInvocationException)ex).InnerException;
317                                 throw new RemotingException ("An instance of provider '" + pvtype + "' could not be created: " + ex.Message);
318                         }
319                 }
320
321                 public static IMessage SyncDispatchMessage (IMessage msg)
322                 {
323                         IMethodMessage call = (IMethodMessage)msg;
324                         ServerIdentity identity = RemotingServices.GetIdentityForUri(call.Uri) as ServerIdentity;
325                         if (identity == null) return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg);
326
327                         RemotingServices.SetMessageTargetIdentity (msg, identity);
328                         return _crossContextSink.SyncProcessMessage (msg);
329                 }
330
331                 public static void UnregisterChannel (IChannel chnl)
332                 {
333                         if (chnl == null)
334                                 throw new ArgumentNullException ();
335                                 
336                         lock (registeredChannels.SyncRoot)
337                         {
338                                 if (!registeredChannels.Contains ((object) chnl))
339                                         throw new RemotingException ();
340         
341                                 registeredChannels.Remove ((object) chnl);
342         
343                                 IChannelReceiver chnlReceiver = chnl as IChannelReceiver;
344                                 if(chnlReceiver != null)
345                                         chnlReceiver.StopListening(null);
346                         }
347                 }
348
349                 internal static object [] GetCurrentChannelInfo ()
350                 {
351                         ArrayList list = new ArrayList ();
352                         
353                         lock (registeredChannels.SyncRoot)
354                         {
355                                 foreach (object chnl_obj in registeredChannels) {
356                                         IChannelReceiver chnl = chnl_obj as IChannelReceiver;
357                                 
358                                         if (chnl != null) {
359                                                 object chnl_data = chnl.ChannelData;
360                                                 if (chnl_data != null)
361                                                         list.Add (chnl_data);
362                                         }
363                                 }
364                         }
365                         
366                         return  list.ToArray ();
367                 }
368         }
369 }