In System.IO:
[mono.git] / mcs / class / corlib / System.Runtime.Remoting / RemotingConfiguration.cs
1 //
2 // System.Runtime.Remoting.RemotingConfiguration.cs
3 //
4 // Author: Jaime Anguiano Olarra (jaime@gnome.org)
5 //         Lluis Sanchez Gual (lluis@ideary.com)
6 //
7 // (C) 2002, Jaime Anguiano Olarra
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System;
34 using System.IO;
35 using System.Reflection;
36 using System.Collections;
37 using System.Runtime.Remoting.Activation;
38 using System.Runtime.Remoting.Channels;
39 using System.Runtime.Remoting.Lifetime;
40 using Mono.Xml;
41
42 namespace System.Runtime.Remoting
43 {       
44 #if NET_2_0
45         [System.Runtime.InteropServices.ComVisible (true)]
46         public static class RemotingConfiguration
47 #else
48         public class RemotingConfiguration
49 #endif
50         {
51 #if !NET_2_0
52                 //
53                 // Private constructor: nobody instantiates this.
54                 //
55                 private RemotingConfiguration ()
56                 {
57                 }
58 #endif
59                 
60                 static string applicationID = null;
61                 static string applicationName = null;
62                 static string configFile = "";
63                 static SmallXmlParser parser = null; 
64                 static string processGuid = null;
65                 static bool defaultConfigRead = false;
66                 static bool defaultDelayedConfigRead = false;
67                 static string _errorMode;
68
69                 static Hashtable wellKnownClientEntries = new Hashtable();
70                 static Hashtable activatedClientEntries = new Hashtable();
71                 static Hashtable wellKnownServiceEntries = new Hashtable();
72                 static Hashtable activatedServiceEntries = new Hashtable();
73                 
74                 static Hashtable channelTemplates = new Hashtable ();
75                 static Hashtable clientProviderTemplates = new Hashtable ();
76                 static Hashtable serverProviderTemplates = new Hashtable ();
77                 
78                 // public properties
79                 // At this time the ID will be the application name 
80                 public static string ApplicationId 
81                 {
82                         get 
83                         {
84                                 applicationID = ApplicationName; 
85                                 return applicationID;
86                         }
87                 }
88                 
89                 public static string ApplicationName 
90                 {
91                         get { return applicationName; }
92                         set { applicationName = value; }
93                 }
94
95 #if NET_2_0
96                 [MonoTODO]
97                 public static CustomErrorsModes CustomErrorsMode
98                 {
99                         get { throw new NotImplementedException (); }
100                         set { throw new NotImplementedException (); }
101                 }
102 #endif
103
104                 public static string ProcessId 
105                 {
106                         get {
107                                 if (processGuid == null)
108                                         processGuid = AppDomain.GetProcessGuid ();
109
110                                 return processGuid;
111                         }
112                 }
113
114
115                 // public methods
116                 
117 #if NET_2_0
118                 [MonoTODO ("Implement ensureSecurity")]
119                 public
120 #else
121                 internal
122 #endif
123                 static void Configure (string filename, bool ensureSecurity) 
124                 {
125                         lock (channelTemplates) {
126                                 if (!defaultConfigRead) {
127                                         ReadConfigFile (Environment.GetMachineConfigPath ());
128                                         defaultConfigRead = true;
129                                 }
130
131                                 if (filename != null)
132                                         ReadConfigFile (filename);
133                         }
134                 }
135 #if NET_2_0
136                 [Obsolete ("Use Configure(String,Boolean)")]
137 #endif
138                 public static void Configure (string filename) 
139                 {
140                         Configure (filename, false);
141                 }
142
143                 private static void ReadConfigFile (string filename)
144                 {
145                         try
146                         {
147                                 SmallXmlParser parser = new SmallXmlParser ();
148                                 using (TextReader rreader = new StreamReader (filename)) {
149                                         ConfigHandler handler = new ConfigHandler (false);
150                                         parser.Parse (rreader, handler);
151                                 }
152                         }
153                         catch (Exception ex)
154                         {
155                                 throw new RemotingException ("Configuration file '" + filename + "' could not be loaded: " + ex.Message, ex);
156                         }
157                 }
158                 
159                 internal static void LoadDefaultDelayedChannels ()
160                 {
161                         lock (channelTemplates)
162                         {
163                                 if (defaultDelayedConfigRead || defaultConfigRead) return;
164                                 
165                                 SmallXmlParser parser = new SmallXmlParser ();
166                                 using (TextReader rreader = new StreamReader (Environment.GetMachineConfigPath ())) {
167                                         ConfigHandler handler = new ConfigHandler (true);
168                                         parser.Parse (rreader, handler);
169                                 }
170                                 defaultDelayedConfigRead = true;
171                         }
172                 }
173         
174                 public static ActivatedClientTypeEntry[] GetRegisteredActivatedClientTypes () 
175                 {
176                         lock (channelTemplates)
177                         {
178                                 ActivatedClientTypeEntry[] entries = new ActivatedClientTypeEntry[activatedClientEntries.Count];
179                                 activatedClientEntries.Values.CopyTo (entries,0);
180                                 return entries;
181                         }
182                 }
183
184                 public static ActivatedServiceTypeEntry[] GetRegisteredActivatedServiceTypes () 
185                 {
186                         lock (channelTemplates)
187                         {
188                                 ActivatedServiceTypeEntry[] entries = new ActivatedServiceTypeEntry[activatedServiceEntries.Count];
189                                 activatedServiceEntries.Values.CopyTo (entries,0);
190                                 return entries;
191                         }
192                 }
193
194                 public static WellKnownClientTypeEntry[] GetRegisteredWellKnownClientTypes () 
195                 {
196                         lock (channelTemplates)
197                         {
198                                 WellKnownClientTypeEntry[] entries = new WellKnownClientTypeEntry[wellKnownClientEntries.Count];
199                                 wellKnownClientEntries.Values.CopyTo (entries,0);
200                                 return entries;
201                         }
202                 }
203
204                 public static WellKnownServiceTypeEntry[] GetRegisteredWellKnownServiceTypes () 
205                 {
206                         lock (channelTemplates)
207                         {
208                                 WellKnownServiceTypeEntry[] entries = new WellKnownServiceTypeEntry[wellKnownServiceEntries.Count];
209                                 wellKnownServiceEntries.Values.CopyTo (entries,0);
210                                 return entries;
211                         }
212                 }
213
214                 public static bool IsActivationAllowed (Type serverType) 
215                 {
216                         lock (channelTemplates)
217                         {
218                                 return activatedServiceEntries.ContainsKey (serverType);
219                         }
220                 }
221
222                 public static ActivatedClientTypeEntry IsRemotelyActivatedClientType (Type serviceType) 
223                 {
224                         lock (channelTemplates)
225                         {
226                                 return activatedClientEntries [serviceType] as ActivatedClientTypeEntry;
227                         }
228                 }
229
230                 public static ActivatedClientTypeEntry IsRemotelyActivatedClientType (string typeName, string assemblyName) 
231                 {
232                         return IsRemotelyActivatedClientType (Assembly.Load(assemblyName).GetType (typeName));
233                 }
234
235                 public static WellKnownClientTypeEntry IsWellKnownClientType (Type serviceType) 
236                 {
237                         lock (channelTemplates)
238                         {
239                                 return wellKnownClientEntries [serviceType] as WellKnownClientTypeEntry;
240                         }
241                 }
242
243                 public static WellKnownClientTypeEntry IsWellKnownClientType (string typeName, string assemblyName) 
244                 {
245                         return IsWellKnownClientType (Assembly.Load(assemblyName).GetType (typeName));
246                 }
247
248                 public static void RegisterActivatedClientType (ActivatedClientTypeEntry entry) 
249                 {
250                         lock (channelTemplates)
251                         {
252                                 if (wellKnownClientEntries.ContainsKey (entry.ObjectType) || activatedClientEntries.ContainsKey (entry.ObjectType))
253                                         throw new RemotingException ("Attempt to redirect activation of type '" + entry.ObjectType.FullName + "' which is already redirected.");
254         
255                                 activatedClientEntries[entry.ObjectType] = entry;
256                                 ActivationServices.EnableProxyActivation (entry.ObjectType, true);
257                         }
258                 }
259
260                 public static void RegisterActivatedClientType (Type type, string appUrl) 
261                 {
262                         if (type == null) throw new ArgumentNullException ("type");
263                         if (appUrl == null) throw new ArgumentNullException ("appUrl");
264
265                         RegisterActivatedClientType (new ActivatedClientTypeEntry (type, appUrl));
266                 }
267
268                 public static void RegisterActivatedServiceType (ActivatedServiceTypeEntry entry) 
269                 {
270                         lock (channelTemplates)
271                         {
272                                 activatedServiceEntries.Add (entry.ObjectType, entry);
273                         }
274                 }
275
276                 public static void RegisterActivatedServiceType (Type type) 
277                 {
278                         RegisterActivatedServiceType (new ActivatedServiceTypeEntry (type));
279                 }
280
281                 public static void RegisterWellKnownClientType (Type type, string objectUrl) 
282                 {
283                         if (type == null) throw new ArgumentNullException ("type");
284                         if (objectUrl == null) throw new ArgumentNullException ("objectUrl");
285
286                         RegisterWellKnownClientType (new WellKnownClientTypeEntry (type, objectUrl));
287                 }
288
289                 public static void RegisterWellKnownClientType (WellKnownClientTypeEntry entry) 
290                 {
291                         lock (channelTemplates)
292                         {
293                                 if (wellKnownClientEntries.ContainsKey (entry.ObjectType) || activatedClientEntries.ContainsKey (entry.ObjectType))
294                                         throw new RemotingException ("Attempt to redirect activation of type '" + entry.ObjectType.FullName + "' which is already redirected.");
295         
296                                 wellKnownClientEntries[entry.ObjectType] = entry;
297                                 ActivationServices.EnableProxyActivation (entry.ObjectType, true);
298                         }
299                 }
300
301                 public static void RegisterWellKnownServiceType (Type type, string objectUrl, WellKnownObjectMode mode) 
302                 {
303                         RegisterWellKnownServiceType (new WellKnownServiceTypeEntry (type, objectUrl, mode));
304                 }
305
306                 public static void RegisterWellKnownServiceType (WellKnownServiceTypeEntry entry) 
307                 {
308                         lock (channelTemplates)
309                         {
310                                 wellKnownServiceEntries [entry.ObjectUri] = entry;
311                                 RemotingServices.CreateWellKnownServerIdentity (entry.ObjectType, entry.ObjectUri, entry.Mode);
312                         }
313                 }
314
315                 internal static void RegisterChannelTemplate (ChannelData channel)
316                 {
317                         channelTemplates [channel.Id] = channel;
318                 }
319                 
320                 internal static void RegisterClientProviderTemplate (ProviderData prov)
321                 {
322                         clientProviderTemplates [prov.Id] = prov;
323                 }
324                 
325                 internal static void RegisterServerProviderTemplate (ProviderData prov)
326                 {
327                         serverProviderTemplates [prov.Id] = prov;
328                 }
329                 
330                 internal static void RegisterChannels (ArrayList channels, bool onlyDelayed)
331                 {
332                         foreach (ChannelData channel in channels)
333                         {
334                                 if (onlyDelayed && channel.DelayLoadAsClientChannel != "true")
335                                         continue;
336                                         
337                                 if (defaultDelayedConfigRead && channel.DelayLoadAsClientChannel == "true")
338                                         continue;
339                                         
340                                 if (channel.Ref != null)
341                                 {
342                                         ChannelData template = (ChannelData) channelTemplates [channel.Ref];
343                                         if (template == null) throw new RemotingException ("Channel template '" + channel.Ref + "' not found");
344                                         channel.CopyFrom (template);
345                                 }
346                                 
347                                 foreach (ProviderData prov in channel.ServerProviders)
348                                 {
349                                         if (prov.Ref != null)
350                                         {
351                                                 ProviderData template = (ProviderData) serverProviderTemplates [prov.Ref];
352                                                 if (template == null) throw new RemotingException ("Provider template '" + prov.Ref + "' not found");
353                                                 prov.CopyFrom (template);
354                                         }
355                                 }
356                                 
357                                 foreach (ProviderData prov in channel.ClientProviders)
358                                 {
359                                         if (prov.Ref != null)
360                                         {
361                                                 ProviderData template = (ProviderData) clientProviderTemplates [prov.Ref];
362                                                 if (template == null) throw new RemotingException ("Provider template '" + prov.Ref + "' not found");
363                                                 prov.CopyFrom (template);
364                                         }
365                                 }
366                                 
367                                 ChannelServices.RegisterChannelConfig (channel);
368                         }
369                 }
370                 
371                 internal static void RegisterTypes (ArrayList types)
372                 {
373                         foreach (TypeEntry type in types)
374                         {
375                                 if (type is ActivatedClientTypeEntry)
376                                         RegisterActivatedClientType ((ActivatedClientTypeEntry)type);
377                                 else if (type is ActivatedServiceTypeEntry)
378                                         RegisterActivatedServiceType ((ActivatedServiceTypeEntry)type);
379                                 else if (type is WellKnownClientTypeEntry)
380                                         RegisterWellKnownClientType ((WellKnownClientTypeEntry)type);
381                                 else if (type is WellKnownServiceTypeEntry)
382                                         RegisterWellKnownServiceType ((WellKnownServiceTypeEntry)type);
383                         }
384                 }
385                 
386 #if NET_1_1
387                 public static bool CustomErrorsEnabled (bool isLocalRequest)
388                 {
389                         if (_errorMode == "off") return false;
390                         if (_errorMode == "on") return true;
391                         return !isLocalRequest;
392                 }
393 #endif
394
395                 internal static void SetCustomErrorsMode (string mode)
396                 {
397                         if (mode == null)
398                                 throw new RemotingException ("mode attribute is required");
399
400                         // the mode is case insensitive
401                         string m = mode.ToLower ();
402
403                         if (m != "on" && m != "off" && m != "remoteonly")
404                                 throw new RemotingException ("Invalid custom error mode: " + mode);
405                                 
406                         _errorMode = m;
407                 }
408         }
409
410         /***************************************************************
411          * Internal classes used by RemotingConfiguration.Configure () *
412          ***************************************************************/
413          
414         internal class ConfigHandler : SmallXmlParser.IContentHandler 
415         {
416                 ArrayList typeEntries = new ArrayList ();
417                 ArrayList channelInstances = new ArrayList ();
418                 
419                 ChannelData currentChannel = null;
420                 Stack currentProviderData = null;
421                 
422                 string currentClientUrl = null;
423                 string appName;
424                 
425                 string currentXmlPath = "";
426                 bool onlyDelayedChannels;
427                 
428                 public ConfigHandler (bool onlyDelayedChannels)
429                 {
430                         this.onlyDelayedChannels = onlyDelayedChannels;
431                 }
432                 
433                 void ValidatePath (string element, params string[] paths)
434                 {
435                         foreach (string path in paths)
436                                 if (CheckPath (path)) return;
437                                 
438                         throw new RemotingException ("Element " + element + " not allowed in this context");
439                 }
440                 
441                 bool CheckPath (string path)
442                 {
443                         if (path.StartsWith ("/"))
444                                 return path == currentXmlPath;
445                         else
446                                 return currentXmlPath.EndsWith (path);
447                 }
448                 
449                 public void OnStartParsing (SmallXmlParser parser) {}
450                 
451                 public void OnProcessingInstruction (string name, string text) {}
452
453                 public void OnIgnorableWhitespace (string s) {}
454
455                 public void OnStartElement (string name, SmallXmlParser.IAttrList attrs)
456                 {
457                         try
458                         {
459                                 if (currentXmlPath.StartsWith ("/configuration/system.runtime.remoting"))
460                                         ParseElement (name, attrs);
461                                         
462                                 currentXmlPath += "/" + name;
463                         }
464                         catch (Exception ex)
465                         {
466                                 throw new RemotingException ("Error in element " + name + ": " + ex.Message, ex);
467                         }
468                 }
469                 
470                 public void ParseElement (string name, SmallXmlParser.IAttrList attrs)
471                 {
472                         if (currentProviderData != null)
473                         {
474                                 ReadCustomProviderData (name, attrs);
475                                 return;
476                         }
477                         
478                         switch (name) 
479                         {
480                                 case "application":
481                                         ValidatePath (name, "system.runtime.remoting");
482                                         if (attrs.Names.Length > 0)
483                                                 appName = attrs.Values[0];
484                                         break;
485                                         
486                                 case "lifetime":
487                                         ValidatePath (name, "application");
488                                         ReadLifetine (attrs);
489                                         break;
490                                         
491                                 case "channels":
492                                         ValidatePath (name, "system.runtime.remoting", "application");
493                                         break;
494                                         
495                                 case "channel":
496                                         ValidatePath (name, "channels");
497                                         if (currentXmlPath.IndexOf ("application") != -1)
498                                                 ReadChannel (attrs, false);
499                                         else
500                                                 ReadChannel (attrs, true);
501                                         break;
502                                         
503                                 case "serverProviders":
504                                         ValidatePath (name, "channelSinkProviders", "channel");
505                                         break;
506                                         
507                                 case "clientProviders":
508                                         ValidatePath (name, "channelSinkProviders", "channel");
509                                         break;
510                                         
511                                 case "provider":
512                                 case "formatter":
513                                         ProviderData prov;
514                                         
515                                         if (CheckPath ("application/channels/channel/serverProviders") ||
516                                                 CheckPath ("channels/channel/serverProviders"))
517                                         {
518                                                 prov = ReadProvider (name, attrs, false);
519                                                 currentChannel.ServerProviders.Add (prov);
520                                         }
521                                         else if (CheckPath ("application/channels/channel/clientProviders") ||
522                                                 CheckPath ("channels/channel/clientProviders"))
523                                         {
524                                                 prov = ReadProvider (name, attrs, false);
525                                                 currentChannel.ClientProviders.Add (prov);
526                                         }
527                                         else if (CheckPath ("channelSinkProviders/serverProviders"))
528                                         {
529                                                 prov = ReadProvider (name, attrs, true);
530                                                 RemotingConfiguration.RegisterServerProviderTemplate (prov);
531                                         }
532                                         else if (CheckPath ("channelSinkProviders/clientProviders"))
533                                         {
534                                                 prov = ReadProvider (name, attrs, true);
535                                                 RemotingConfiguration.RegisterClientProviderTemplate (prov);
536                                         }
537                                         else 
538                                                 ValidatePath (name);
539                                         break;
540                                         
541                                 case "client":
542                                         ValidatePath (name, "application");
543                                         currentClientUrl = attrs.GetValue ("url");
544                                         break;
545                                         
546                                 case "service":
547                                         ValidatePath (name, "application");
548                                         break;
549                                         
550                                 case "wellknown":
551                                         ValidatePath (name, "client", "service");
552                                         if (CheckPath ("client"))
553                                                 ReadClientWellKnown (attrs);
554                                         else
555                                                 ReadServiceWellKnown (attrs);
556                                         break;
557                                         
558                                 case "activated":
559                                         ValidatePath (name, "client", "service");
560                                         if (CheckPath ("client"))
561                                                 ReadClientActivated (attrs);
562                                         else
563                                                 ReadServiceActivated (attrs);
564                                         break;
565                                         
566                                 case "soapInterop":
567                                         ValidatePath (name, "application");
568                                         break;
569                                         
570                                 case "interopXmlType":
571                                         ValidatePath (name, "soapInterop");
572                                         ReadInteropXml (attrs, false);
573                                         break;
574                                         
575                                 case "interopXmlElement":
576                                         ValidatePath (name, "soapInterop");
577                                         ReadInteropXml (attrs, false);
578                                         break;
579                                         
580                                 case "preLoad":
581                                         ValidatePath (name, "soapInterop");
582                                         ReadPreload (attrs);
583                                         break;
584                                         
585                                 case "debug":
586                                         ValidatePath (name, "system.runtime.remoting");
587                                         break;
588                                         
589                                 case "channelSinkProviders":
590                                         ValidatePath (name, "system.runtime.remoting");
591                                         break;
592                                         
593                                 case "customErrors":
594                                         ValidatePath (name, "system.runtime.remoting");
595                                         RemotingConfiguration.SetCustomErrorsMode (attrs.GetValue ("mode"));
596                                         break;
597                                         
598                                 default:
599                                         throw new RemotingException ("Element '" + name + "' is not valid in system.remoting.configuration section");
600                         }
601                 }
602                 
603                 public void OnEndElement (string name)
604                 {
605                         if (currentProviderData != null)
606                         {
607                                 currentProviderData.Pop ();
608                                 if (currentProviderData.Count == 0) 
609                                         currentProviderData = null;
610                         }
611                         
612                         currentXmlPath = currentXmlPath.Substring (0, currentXmlPath.Length - name.Length - 1);
613                 }
614                 
615                 void ReadCustomProviderData (string name, SmallXmlParser.IAttrList attrs)
616                 {
617                         SinkProviderData parent = (SinkProviderData) currentProviderData.Peek ();
618                         
619                         SinkProviderData data = new SinkProviderData (name);
620                         for (int i=0; i < attrs.Names.Length; ++i) 
621                                 data.Properties [attrs.Names[i]] = attrs.GetValue (i);
622                                 
623                         parent.Children.Add (data);
624                         currentProviderData.Push (data);
625                 }
626
627                 void ReadLifetine (SmallXmlParser.IAttrList attrs)
628                 {
629                         for (int i=0; i < attrs.Names.Length; ++i) {
630                                 switch (attrs.Names[i]) {
631                                 case "leaseTime":
632                                         LifetimeServices.LeaseTime = ParseTime (attrs.GetValue(i));
633                                         break;
634                                 case "sponsorshipTimeout":
635                                         LifetimeServices.SponsorshipTimeout = ParseTime (attrs.GetValue(i));
636                                         break;
637                                 case "renewOnCallTime":
638                                         LifetimeServices.RenewOnCallTime = ParseTime (attrs.GetValue(i));
639                                         break;
640                                 case "leaseManagerPollTime":
641                                         LifetimeServices.LeaseManagerPollTime = ParseTime (attrs.GetValue(i));
642                                         break;
643                                 default:
644                                         throw new RemotingException ("Invalid attribute: " + attrs.Names[i]);
645                                 }
646                         }
647                 }
648                 
649                 TimeSpan ParseTime (string s)
650                 {
651                         if (s == "" || s == null) throw new RemotingException ("Invalid time value");
652                         
653                         int i = s.IndexOfAny (new char[] { 'D','H','M','S' });
654                         
655                         string unit;
656                         if (i == -1) 
657                                 unit = "S";
658                         else { 
659                                 unit = s.Substring (i);
660                                 s = s.Substring (0,i);
661                         }
662                         double val;
663                         
664                         try {
665                                 val = double.Parse (s);
666                         }
667                         catch {
668                                 throw new RemotingException ("Invalid time value: " + s);
669                         }
670                         
671                         if (unit == "D") return TimeSpan.FromDays (val);
672                         if (unit == "H") return TimeSpan.FromHours (val);
673                         if (unit == "M") return TimeSpan.FromMinutes (val);
674                         if (unit == "S") return TimeSpan.FromSeconds (val);
675                         if (unit == "MS") return TimeSpan.FromMilliseconds (val);
676                         throw new RemotingException ("Invalid time unit: " + unit);
677                 }
678                 
679                 void ReadChannel (SmallXmlParser.IAttrList attrs, bool isTemplate)
680                 {
681                         ChannelData channel = new ChannelData ();
682                         
683                         for (int i=0; i < attrs.Names.Length; ++i) 
684                         {
685                                 string at = attrs.Names[i];
686                                 string val = attrs.Values[i];
687                                 
688                                 if (at == "ref" && !isTemplate)
689                                         channel.Ref = val;
690                                 else if (at == "delayLoadAsClientChannel")
691                                         channel.DelayLoadAsClientChannel = val;
692                                 else if (at == "id" && isTemplate)
693                                         channel.Id = val;
694                                 else if (at == "type")
695                                         channel.Type = val;
696                                 else
697                                         channel.CustomProperties.Add (at, val);
698                         }
699                         
700                         if (isTemplate)
701                         {
702                                 if (channel.Id == null) throw new RemotingException ("id attribute is required");
703                                 if (channel.Type == null) throw new RemotingException ("id attribute is required");
704                                 RemotingConfiguration.RegisterChannelTemplate (channel);
705                         }
706                         else
707                                 channelInstances.Add (channel);
708                                 
709                         currentChannel = channel;
710                 }
711                 
712                 ProviderData ReadProvider (string name, SmallXmlParser.IAttrList attrs, bool isTemplate)
713                 {
714                         ProviderData prov = (name == "provider") ? new ProviderData () : new FormatterData ();
715                         SinkProviderData data = new SinkProviderData ("root");
716                         prov.CustomData = data.Children;
717                         
718                         currentProviderData = new Stack ();
719                         currentProviderData.Push (data);
720                         
721                         for (int i=0; i < attrs.Names.Length; ++i) 
722                         {
723                                 string at = attrs.Names[i];
724                                 string val = attrs.Values[i];
725                                 
726                                 if (at == "id" && isTemplate)
727                                         prov.Id = val;
728                                 else if (at == "type")
729                                         prov.Type = val;
730                                 else if (at == "ref" && !isTemplate)
731                                         prov.Ref = val;
732                                 else
733                                         prov.CustomProperties.Add (at, val);
734                         }
735                         
736                         if (prov.Id == null && isTemplate) throw new RemotingException ("id attribute is required");
737                         return prov;
738                 }
739                 
740                 void ReadClientActivated (SmallXmlParser.IAttrList attrs)
741                 {
742                         string type = GetNotNull (attrs, "type");
743                         string assm = ExtractAssembly (ref type);
744                         
745                         if (currentClientUrl == null || currentClientUrl == "") 
746                                 throw new RemotingException ("url attribute is required in client element when it contains activated entries");
747
748                         typeEntries.Add (new ActivatedClientTypeEntry (type, assm, currentClientUrl));
749                 }
750                 
751                 void ReadServiceActivated (SmallXmlParser.IAttrList attrs)
752                 {
753                         string type = GetNotNull (attrs, "type");
754                         string assm = ExtractAssembly (ref type);
755                         
756                         typeEntries.Add (new ActivatedServiceTypeEntry (type, assm));
757                 }
758                 
759                 void ReadClientWellKnown (SmallXmlParser.IAttrList attrs)
760                 {
761                         string url = GetNotNull (attrs, "url");
762                         string type = GetNotNull (attrs, "type");
763                         string assm = ExtractAssembly (ref type);
764                         
765                         typeEntries.Add (new WellKnownClientTypeEntry (type, assm, url));
766                 }
767                 
768                 void ReadServiceWellKnown (SmallXmlParser.IAttrList attrs)
769                 {
770                         string objectUri = GetNotNull (attrs, "objectUri");
771                         string smode = GetNotNull (attrs, "mode");
772                         string type = GetNotNull (attrs, "type");
773                         string assm = ExtractAssembly (ref type);
774                         
775                         WellKnownObjectMode mode;
776                         if (smode == "SingleCall") mode = WellKnownObjectMode.SingleCall;
777                         else if (smode == "Singleton") mode = WellKnownObjectMode.Singleton;
778                         else throw new RemotingException ("wellknown object mode '" + smode + "' is invalid");
779                         
780                         typeEntries.Add (new WellKnownServiceTypeEntry (type, assm, objectUri, mode));
781                 }
782                 
783                 void ReadInteropXml (SmallXmlParser.IAttrList attrs, bool isElement)
784                 {
785                         Type t = Type.GetType (GetNotNull (attrs, "clr"));
786                         string[] xmlName = GetNotNull (attrs, "xml").Split (',');
787                         string localName = xmlName [0].Trim ();
788                         string ns = xmlName.Length > 0 ? xmlName[1].Trim() : null;
789                         
790                         if (isElement) SoapServices.RegisterInteropXmlElement (localName, ns, t);
791                         else SoapServices.RegisterInteropXmlType (localName, ns, t);
792                 }
793                 
794                 void ReadPreload (SmallXmlParser.IAttrList attrs)
795                 {
796                         string type = attrs.GetValue ("type");
797                         string assm = attrs.GetValue ("assembly");
798                         
799                         if (type != null && assm != null)
800                                 throw new RemotingException ("Type and assembly attributes cannot be specified together");
801                                 
802                         if (type != null)
803                                 SoapServices.PreLoad (Type.GetType (type));
804                         else if (assm != null)
805                                 SoapServices.PreLoad (Assembly.Load (assm));
806                         else
807                                 throw new RemotingException ("Either type or assembly attributes must be specified");
808                 }
809                                         
810                 string GetNotNull (SmallXmlParser.IAttrList attrs, string name)
811                 {
812                         string value = attrs.GetValue (name);
813                         if (value == null || value == "") 
814                                 throw new RemotingException (name + " attribute is required");
815                         return value;
816                 }
817                 
818                 string ExtractAssembly (ref string type)
819                 {
820                         int i = type.IndexOf (',');
821                         if (i == -1) return "";
822                         
823                         string asm = type.Substring (i+1).Trim();
824                         type = type.Substring (0, i).Trim();
825                         return asm;
826                 }
827                 
828                 public void OnChars (string ch) {}
829                 
830                 public void OnEndParsing (SmallXmlParser parser)
831                 {
832                         RemotingConfiguration.RegisterChannels (channelInstances, onlyDelayedChannels);
833                         if (appName != null) RemotingConfiguration.ApplicationName = appName;
834                         
835                         if (!onlyDelayedChannels)
836                                 RemotingConfiguration.RegisterTypes (typeEntries);
837                 }
838         }
839
840
841                 /*******************************************************************
842          * Internal data structures used by ConfigHandler, to store             *
843          * machine.config's remoting related data.                         *
844          * If having them implemented this way, makes configuration too    *
845          * slow, we can use string arrays.                                 *
846          *******************************************************************/
847                  
848         internal class ChannelData {
849                 internal string Ref;
850                 internal string Type;
851                 internal string Id;
852                 internal string DelayLoadAsClientChannel;
853                 
854                 ArrayList _serverProviders = new ArrayList ();
855                 ArrayList _clientProviders = new ArrayList ();
856                 Hashtable _customProperties = new Hashtable ();
857                 
858                 internal ArrayList ServerProviders {
859                         get {
860                                 if (_serverProviders == null) _serverProviders = new ArrayList ();
861                                 return _serverProviders;
862                         }
863                 }
864                 
865                 public ArrayList ClientProviders {
866                         get {
867                                 if (_clientProviders == null) _clientProviders = new ArrayList ();
868                                 return _clientProviders;
869                         }
870                 }
871                 
872                 public Hashtable CustomProperties {
873                         get {
874                                 if (_customProperties == null) _customProperties = new Hashtable ();
875                                 return _customProperties;
876                         }
877                 }
878                 
879                 public void CopyFrom (ChannelData other)
880                 {
881                         if (Ref == null) Ref = other.Ref;
882                         if (Id == null) Id = other.Id;
883                         if (Type == null) Type = other.Type;
884                         if (DelayLoadAsClientChannel == null) DelayLoadAsClientChannel = other.DelayLoadAsClientChannel;
885
886                         if (other._customProperties != null)
887                         {
888                                 foreach (DictionaryEntry entry in other._customProperties)
889                                         if (!CustomProperties.ContainsKey (entry.Key))
890                                                 CustomProperties [entry.Key] = entry.Value;
891                         }
892                         
893                         if (_serverProviders == null && other._serverProviders != null)
894                         {
895                                 foreach (ProviderData prov in other._serverProviders)
896                                 {
897                                         ProviderData np = new ProviderData();
898                                         np.CopyFrom (prov);
899                                         ServerProviders.Add (np);
900                                 }
901                         }
902                         
903                         if (_clientProviders == null && other._clientProviders != null)
904                         {
905                                 foreach (ProviderData prov in other._clientProviders)
906                                 {
907                                         ProviderData np = new ProviderData();
908                                         np.CopyFrom (prov);
909                                         ClientProviders.Add (np);
910                                 }
911                         }
912                 }
913         }
914         
915         internal class ProviderData {
916                 internal string Ref;
917                 internal string Type;
918                 internal string Id;
919                 
920                 internal Hashtable CustomProperties = new Hashtable ();
921                 internal IList CustomData;
922                 
923                 public void CopyFrom (ProviderData other)
924                 {
925                         if (Ref == null) Ref = other.Ref;
926                         if (Id == null) Id = other.Id;
927                         if (Type == null) Type = other.Type;
928                         
929                         foreach (DictionaryEntry entry in other.CustomProperties)
930                                 if (!CustomProperties.ContainsKey (entry.Key))
931                                         CustomProperties [entry.Key] = entry.Value;
932                                         
933                         if (other.CustomData != null)
934                         {
935                                 if (CustomData == null) CustomData = new ArrayList ();
936                                 foreach (SinkProviderData data in other.CustomData)
937                                         CustomData.Add (data);
938                         }
939                 }
940         }
941         
942         internal class FormatterData: ProviderData {
943         }       
944 }