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