[CryptoStream] Invalid enum in ctor
[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 #if NET_1_1
368                 public static bool CustomErrorsEnabled (bool isLocalRequest)
369                 {
370                         if (_errorMode == "off") return false;
371                         if (_errorMode == "on") return true;
372                         return !isLocalRequest;
373                 }
374 #endif
375
376                 internal static void SetCustomErrorsMode (string mode)
377                 {
378                         if (mode == null)
379                                 throw new RemotingException ("mode attribute is required");
380
381                         // the mode is case insensitive
382                         string m = mode.ToLower ();
383
384                         if (m != "on" && m != "off" && m != "remoteonly")
385                                 throw new RemotingException ("Invalid custom error mode: " + mode);
386                                 
387                         _errorMode = m;
388                 }
389         }
390
391         /***************************************************************
392          * Internal classes used by RemotingConfiguration.Configure () *
393          ***************************************************************/
394          
395         internal class ConfigHandler : SmallXmlParser.IContentHandler 
396         {
397                 ArrayList typeEntries = new ArrayList ();
398                 ArrayList channelInstances = new ArrayList ();
399                 
400                 ChannelData currentChannel = null;
401                 Stack currentProviderData = null;
402                 
403                 string currentClientUrl = null;
404                 string appName;
405                 
406                 string currentXmlPath = "";
407                 bool onlyDelayedChannels;
408                 
409                 public ConfigHandler (bool onlyDelayedChannels)
410                 {
411                         this.onlyDelayedChannels = onlyDelayedChannels;
412                 }
413                 
414                 void ValidatePath (string element, params string[] paths)
415                 {
416                         foreach (string path in paths)
417                                 if (CheckPath (path)) return;
418                                 
419                         throw new RemotingException ("Element " + element + " not allowed in this context");
420                 }
421                 
422                 bool CheckPath (string path)
423                 {
424                         CompareInfo ci = CultureInfo.InvariantCulture.CompareInfo;
425                         if (ci.IsPrefix (path, "/", CompareOptions.Ordinal))
426                                 return path == currentXmlPath;
427                         else
428                                 return ci.IsSuffix (currentXmlPath, path, CompareOptions.Ordinal);
429                 }
430                 
431                 public void OnStartParsing (SmallXmlParser parser) {}
432                 
433                 public void OnProcessingInstruction (string name, string text) {}
434
435                 public void OnIgnorableWhitespace (string s) {}
436
437                 public void OnStartElement (string name, SmallXmlParser.IAttrList attrs)
438                 {
439                         try
440                         {
441                                 if (currentXmlPath.StartsWith ("/configuration/system.runtime.remoting"))
442                                         ParseElement (name, attrs);
443                                         
444                                 currentXmlPath += "/" + name;
445                         }
446                         catch (Exception ex)
447                         {
448                                 throw new RemotingException ("Error in element " + name + ": " + ex.Message, ex);
449                         }
450                 }
451                 
452                 public void ParseElement (string name, SmallXmlParser.IAttrList attrs)
453                 {
454                         if (currentProviderData != null)
455                         {
456                                 ReadCustomProviderData (name, attrs);
457                                 return;
458                         }
459                         
460                         switch (name) 
461                         {
462                                 case "application":
463                                         ValidatePath (name, "system.runtime.remoting");
464                                         if (attrs.Names.Length > 0)
465                                                 appName = attrs.Values[0];
466                                         break;
467                                         
468                                 case "lifetime":
469                                         ValidatePath (name, "application");
470                                         ReadLifetine (attrs);
471                                         break;
472                                         
473                                 case "channels":
474                                         ValidatePath (name, "system.runtime.remoting", "application");
475                                         break;
476                                         
477                                 case "channel":
478                                         ValidatePath (name, "channels");
479                                         if (currentXmlPath.IndexOf ("application") != -1)
480                                                 ReadChannel (attrs, false);
481                                         else
482                                                 ReadChannel (attrs, true);
483                                         break;
484                                         
485                                 case "serverProviders":
486                                         ValidatePath (name, "channelSinkProviders", "channel");
487                                         break;
488                                         
489                                 case "clientProviders":
490                                         ValidatePath (name, "channelSinkProviders", "channel");
491                                         break;
492                                         
493                                 case "provider":
494                                 case "formatter":
495                                         ProviderData prov;
496                                         
497                                         if (CheckPath ("application/channels/channel/serverProviders") ||
498                                                 CheckPath ("channels/channel/serverProviders"))
499                                         {
500                                                 prov = ReadProvider (name, attrs, false);
501                                                 currentChannel.ServerProviders.Add (prov);
502                                         }
503                                         else if (CheckPath ("application/channels/channel/clientProviders") ||
504                                                 CheckPath ("channels/channel/clientProviders"))
505                                         {
506                                                 prov = ReadProvider (name, attrs, false);
507                                                 currentChannel.ClientProviders.Add (prov);
508                                         }
509                                         else if (CheckPath ("channelSinkProviders/serverProviders"))
510                                         {
511                                                 prov = ReadProvider (name, attrs, true);
512                                                 RemotingConfiguration.RegisterServerProviderTemplate (prov);
513                                         }
514                                         else if (CheckPath ("channelSinkProviders/clientProviders"))
515                                         {
516                                                 prov = ReadProvider (name, attrs, true);
517                                                 RemotingConfiguration.RegisterClientProviderTemplate (prov);
518                                         }
519                                         else 
520                                                 ValidatePath (name);
521                                         break;
522                                         
523                                 case "client":
524                                         ValidatePath (name, "application");
525                                         currentClientUrl = attrs.GetValue ("url");
526                                         break;
527                                         
528                                 case "service":
529                                         ValidatePath (name, "application");
530                                         break;
531                                         
532                                 case "wellknown":
533                                         ValidatePath (name, "client", "service");
534                                         if (CheckPath ("client"))
535                                                 ReadClientWellKnown (attrs);
536                                         else
537                                                 ReadServiceWellKnown (attrs);
538                                         break;
539                                         
540                                 case "activated":
541                                         ValidatePath (name, "client", "service");
542                                         if (CheckPath ("client"))
543                                                 ReadClientActivated (attrs);
544                                         else
545                                                 ReadServiceActivated (attrs);
546                                         break;
547                                         
548                                 case "soapInterop":
549                                         ValidatePath (name, "application");
550                                         break;
551                                         
552                                 case "interopXmlType":
553                                         ValidatePath (name, "soapInterop");
554                                         ReadInteropXml (attrs, false);
555                                         break;
556                                         
557                                 case "interopXmlElement":
558                                         ValidatePath (name, "soapInterop");
559                                         ReadInteropXml (attrs, false);
560                                         break;
561                                         
562                                 case "preLoad":
563                                         ValidatePath (name, "soapInterop");
564                                         ReadPreload (attrs);
565                                         break;
566                                         
567                                 case "debug":
568                                         ValidatePath (name, "system.runtime.remoting");
569                                         break;
570                                         
571                                 case "channelSinkProviders":
572                                         ValidatePath (name, "system.runtime.remoting");
573                                         break;
574                                         
575                                 case "customErrors":
576                                         ValidatePath (name, "system.runtime.remoting");
577                                         RemotingConfiguration.SetCustomErrorsMode (attrs.GetValue ("mode"));
578                                         break;
579                                         
580                                 default:
581                                         throw new RemotingException ("Element '" + name + "' is not valid in system.remoting.configuration section");
582                         }
583                 }
584                 
585                 public void OnEndElement (string name)
586                 {
587                         if (currentProviderData != null)
588                         {
589                                 currentProviderData.Pop ();
590                                 if (currentProviderData.Count == 0) 
591                                         currentProviderData = null;
592                         }
593                         
594                         currentXmlPath = currentXmlPath.Substring (0, currentXmlPath.Length - name.Length - 1);
595                 }
596                 
597                 void ReadCustomProviderData (string name, SmallXmlParser.IAttrList attrs)
598                 {
599                         SinkProviderData parent = (SinkProviderData) currentProviderData.Peek ();
600                         
601                         SinkProviderData data = new SinkProviderData (name);
602                         for (int i=0; i < attrs.Names.Length; ++i) 
603                                 data.Properties [attrs.Names[i]] = attrs.GetValue (i);
604                                 
605                         parent.Children.Add (data);
606                         currentProviderData.Push (data);
607                 }
608
609                 void ReadLifetine (SmallXmlParser.IAttrList attrs)
610                 {
611                         for (int i=0; i < attrs.Names.Length; ++i) {
612                                 switch (attrs.Names[i]) {
613                                 case "leaseTime":
614                                         LifetimeServices.LeaseTime = ParseTime (attrs.GetValue(i));
615                                         break;
616                                 case "sponsorshipTimeout":
617                                         LifetimeServices.SponsorshipTimeout = ParseTime (attrs.GetValue(i));
618                                         break;
619                                 case "renewOnCallTime":
620                                         LifetimeServices.RenewOnCallTime = ParseTime (attrs.GetValue(i));
621                                         break;
622                                 case "leaseManagerPollTime":
623                                         LifetimeServices.LeaseManagerPollTime = ParseTime (attrs.GetValue(i));
624                                         break;
625                                 default:
626                                         throw new RemotingException ("Invalid attribute: " + attrs.Names[i]);
627                                 }
628                         }
629                 }
630                 
631                 TimeSpan ParseTime (string s)
632                 {
633                         if (s == "" || s == null) throw new RemotingException ("Invalid time value");
634                         
635                         int i = s.IndexOfAny (new char[] { 'D','H','M','S' });
636                         
637                         string unit;
638                         if (i == -1) 
639                                 unit = "S";
640                         else { 
641                                 unit = s.Substring (i);
642                                 s = s.Substring (0,i);
643                         }
644                         double val;
645                         
646                         try {
647                                 val = double.Parse (s);
648                         }
649                         catch {
650                                 throw new RemotingException ("Invalid time value: " + s);
651                         }
652                         
653                         if (unit == "D") return TimeSpan.FromDays (val);
654                         if (unit == "H") return TimeSpan.FromHours (val);
655                         if (unit == "M") return TimeSpan.FromMinutes (val);
656                         if (unit == "S") return TimeSpan.FromSeconds (val);
657                         if (unit == "MS") return TimeSpan.FromMilliseconds (val);
658                         throw new RemotingException ("Invalid time unit: " + unit);
659                 }
660                 
661                 void ReadChannel (SmallXmlParser.IAttrList attrs, bool isTemplate)
662                 {
663                         ChannelData channel = new ChannelData ();
664                         
665                         for (int i=0; i < attrs.Names.Length; ++i) 
666                         {
667                                 string at = attrs.Names[i];
668                                 string val = attrs.Values[i];
669                                 
670                                 if (at == "ref" && !isTemplate)
671                                         channel.Ref = val;
672                                 else if (at == "delayLoadAsClientChannel")
673                                         channel.DelayLoadAsClientChannel = val;
674                                 else if (at == "id" && isTemplate)
675                                         channel.Id = val;
676                                 else if (at == "type")
677                                         channel.Type = val;
678                                 else
679                                         channel.CustomProperties.Add (at, val);
680                         }
681                         
682                         if (isTemplate)
683                         {
684                                 if (channel.Id == null) throw new RemotingException ("id attribute is required");
685                                 if (channel.Type == null) throw new RemotingException ("id attribute is required");
686                                 RemotingConfiguration.RegisterChannelTemplate (channel);
687                         }
688                         else
689                                 channelInstances.Add (channel);
690                                 
691                         currentChannel = channel;
692                 }
693                 
694                 ProviderData ReadProvider (string name, SmallXmlParser.IAttrList attrs, bool isTemplate)
695                 {
696                         ProviderData prov = (name == "provider") ? new ProviderData () : new FormatterData ();
697                         SinkProviderData data = new SinkProviderData ("root");
698                         prov.CustomData = data.Children;
699                         
700                         currentProviderData = new Stack ();
701                         currentProviderData.Push (data);
702                         
703                         for (int i=0; i < attrs.Names.Length; ++i) 
704                         {
705                                 string at = attrs.Names[i];
706                                 string val = attrs.Values[i];
707                                 
708                                 if (at == "id" && isTemplate)
709                                         prov.Id = val;
710                                 else if (at == "type")
711                                         prov.Type = val;
712                                 else if (at == "ref" && !isTemplate)
713                                         prov.Ref = val;
714                                 else
715                                         prov.CustomProperties.Add (at, val);
716                         }
717                         
718                         if (prov.Id == null && isTemplate) throw new RemotingException ("id attribute is required");
719                         return prov;
720                 }
721                 
722                 void ReadClientActivated (SmallXmlParser.IAttrList attrs)
723                 {
724                         string type = GetNotNull (attrs, "type");
725                         string assm = ExtractAssembly (ref type);
726                         
727                         if (currentClientUrl == null || currentClientUrl == "") 
728                                 throw new RemotingException ("url attribute is required in client element when it contains activated entries");
729
730                         typeEntries.Add (new ActivatedClientTypeEntry (type, assm, currentClientUrl));
731                 }
732                 
733                 void ReadServiceActivated (SmallXmlParser.IAttrList attrs)
734                 {
735                         string type = GetNotNull (attrs, "type");
736                         string assm = ExtractAssembly (ref type);
737                         
738                         typeEntries.Add (new ActivatedServiceTypeEntry (type, assm));
739                 }
740                 
741                 void ReadClientWellKnown (SmallXmlParser.IAttrList attrs)
742                 {
743                         string url = GetNotNull (attrs, "url");
744                         string type = GetNotNull (attrs, "type");
745                         string assm = ExtractAssembly (ref type);
746                         
747                         typeEntries.Add (new WellKnownClientTypeEntry (type, assm, url));
748                 }
749                 
750                 void ReadServiceWellKnown (SmallXmlParser.IAttrList attrs)
751                 {
752                         string objectUri = GetNotNull (attrs, "objectUri");
753                         string smode = GetNotNull (attrs, "mode");
754                         string type = GetNotNull (attrs, "type");
755                         string assm = ExtractAssembly (ref type);
756                         
757                         WellKnownObjectMode mode;
758                         if (smode == "SingleCall") mode = WellKnownObjectMode.SingleCall;
759                         else if (smode == "Singleton") mode = WellKnownObjectMode.Singleton;
760                         else throw new RemotingException ("wellknown object mode '" + smode + "' is invalid");
761                         
762                         typeEntries.Add (new WellKnownServiceTypeEntry (type, assm, objectUri, mode));
763                 }
764                 
765                 void ReadInteropXml (SmallXmlParser.IAttrList attrs, bool isElement)
766                 {
767                         Type t = Type.GetType (GetNotNull (attrs, "clr"));
768                         string[] xmlName = GetNotNull (attrs, "xml").Split (',');
769                         string localName = xmlName [0].Trim ();
770                         string ns = xmlName.Length > 0 ? xmlName[1].Trim() : null;
771                         
772                         if (isElement) SoapServices.RegisterInteropXmlElement (localName, ns, t);
773                         else SoapServices.RegisterInteropXmlType (localName, ns, t);
774                 }
775                 
776                 void ReadPreload (SmallXmlParser.IAttrList attrs)
777                 {
778                         string type = attrs.GetValue ("type");
779                         string assm = attrs.GetValue ("assembly");
780                         
781                         if (type != null && assm != null)
782                                 throw new RemotingException ("Type and assembly attributes cannot be specified together");
783                                 
784                         if (type != null)
785                                 SoapServices.PreLoad (Type.GetType (type));
786                         else if (assm != null)
787                                 SoapServices.PreLoad (Assembly.Load (assm));
788                         else
789                                 throw new RemotingException ("Either type or assembly attributes must be specified");
790                 }
791                                         
792                 string GetNotNull (SmallXmlParser.IAttrList attrs, string name)
793                 {
794                         string value = attrs.GetValue (name);
795                         if (value == null || value == "") 
796                                 throw new RemotingException (name + " attribute is required");
797                         return value;
798                 }
799                 
800                 string ExtractAssembly (ref string type)
801                 {
802                         int i = type.IndexOf (',');
803                         if (i == -1) return "";
804                         
805                         string asm = type.Substring (i+1).Trim();
806                         type = type.Substring (0, i).Trim();
807                         return asm;
808                 }
809                 
810                 public void OnChars (string ch) {}
811                 
812                 public void OnEndParsing (SmallXmlParser parser)
813                 {
814                         RemotingConfiguration.RegisterChannels (channelInstances, onlyDelayedChannels);
815                         if (appName != null) RemotingConfiguration.ApplicationName = appName;
816                         
817                         if (!onlyDelayedChannels)
818                                 RemotingConfiguration.RegisterTypes (typeEntries);
819                 }
820         }
821
822
823                 /*******************************************************************
824          * Internal data structures used by ConfigHandler, to store             *
825          * machine.config's remoting related data.                         *
826          * If having them implemented this way, makes configuration too    *
827          * slow, we can use string arrays.                                 *
828          *******************************************************************/
829                  
830         internal class ChannelData {
831                 internal string Ref;
832                 internal string Type;
833                 internal string Id;
834                 internal string DelayLoadAsClientChannel;
835                 
836                 ArrayList _serverProviders = new ArrayList ();
837                 ArrayList _clientProviders = new ArrayList ();
838                 Hashtable _customProperties = new Hashtable ();
839                 
840                 internal ArrayList ServerProviders {
841                         get {
842                                 if (_serverProviders == null) _serverProviders = new ArrayList ();
843                                 return _serverProviders;
844                         }
845                 }
846                 
847                 public ArrayList ClientProviders {
848                         get {
849                                 if (_clientProviders == null) _clientProviders = new ArrayList ();
850                                 return _clientProviders;
851                         }
852                 }
853                 
854                 public Hashtable CustomProperties {
855                         get {
856                                 if (_customProperties == null) _customProperties = new Hashtable ();
857                                 return _customProperties;
858                         }
859                 }
860                 
861                 public void CopyFrom (ChannelData other)
862                 {
863                         if (Ref == null) Ref = other.Ref;
864                         if (Id == null) Id = other.Id;
865                         if (Type == null) Type = other.Type;
866                         if (DelayLoadAsClientChannel == null) DelayLoadAsClientChannel = other.DelayLoadAsClientChannel;
867
868                         if (other._customProperties != null)
869                         {
870                                 foreach (DictionaryEntry entry in other._customProperties)
871                                         if (!CustomProperties.ContainsKey (entry.Key))
872                                                 CustomProperties [entry.Key] = entry.Value;
873                         }
874                         
875                         if (_serverProviders == null && other._serverProviders != null)
876                         {
877                                 foreach (ProviderData prov in other._serverProviders)
878                                 {
879                                         ProviderData np = new ProviderData();
880                                         np.CopyFrom (prov);
881                                         ServerProviders.Add (np);
882                                 }
883                         }
884                         
885                         if (_clientProviders == null && other._clientProviders != null)
886                         {
887                                 foreach (ProviderData prov in other._clientProviders)
888                                 {
889                                         ProviderData np = new ProviderData();
890                                         np.CopyFrom (prov);
891                                         ClientProviders.Add (np);
892                                 }
893                         }
894                 }
895         }
896         
897         internal class ProviderData {
898                 internal string Ref;
899                 internal string Type;
900                 internal string Id;
901                 
902                 internal Hashtable CustomProperties = new Hashtable ();
903                 internal IList CustomData;
904                 
905                 public void CopyFrom (ProviderData other)
906                 {
907                         if (Ref == null) Ref = other.Ref;
908                         if (Id == null) Id = other.Id;
909                         if (Type == null) Type = other.Type;
910                         
911                         foreach (DictionaryEntry entry in other.CustomProperties)
912                                 if (!CustomProperties.ContainsKey (entry.Key))
913                                         CustomProperties [entry.Key] = entry.Value;
914                                         
915                         if (other.CustomData != null)
916                         {
917                                 if (CustomData == null) CustomData = new ArrayList ();
918                                 foreach (SinkProviderData data in other.CustomData)
919                                         CustomData.Add (data);
920                         }
921                 }
922         }
923         
924         internal class FormatterData: ProviderData {
925         }       
926 }