Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / mscorlib / system / runtime / remoting / channelservices.cs
1 using System.Diagnostics.Contracts;
2 // ==++==
3 // 
4 //   Copyright (c) Microsoft Corporation.  All rights reserved.
5 // 
6 // ==--==
7 //* File:    Channel.cs
8 //*
9 //* <EMAIL>Author:  Tarun Anand (Microsoft)</EMAIL>
10 //*
11 //* Purpose: Defines the general purpose remoting proxy
12 //*
13 //* Date:    May 27, 1999
14 //*
15 namespace System.Runtime.Remoting.Channels {
16     using System;
17     using System.Collections;
18     using System.IO;
19     using System.Reflection;  
20     using System.Runtime.CompilerServices;
21     using System.Runtime.InteropServices;   
22     using System.Runtime.Remoting;
23     using System.Runtime.Remoting.Activation;
24     using System.Runtime.Remoting.Messaging;
25     using System.Runtime.Remoting.Metadata; 
26     using System.Runtime.Remoting.Proxies;
27     using System.Runtime.Versioning;
28     using System.Threading;
29     using System.Security;
30     using System.Security.Permissions;
31     using System.Globalization;
32  
33     // ChannelServices
34     
35     [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
36     internal struct Perf_Contexts {
37         internal volatile int cRemoteCalls;
38         internal volatile int cChannels;
39     };
40     
41 [System.Runtime.InteropServices.ComVisible(true)]
42     public sealed class ChannelServices
43     {
44         // This gets refreshed when a channel is registered/unregistered.
45         private static volatile Object[] s_currentChannelData = null;
46
47         [System.Security.SecuritySafeCritical] // static constructors should be safe to call
48         static ChannelServices()
49         { 
50         }
51
52         internal static Object[] CurrentChannelData
53         {
54             [System.Security.SecurityCritical]  // auto-generated
55             get 
56             {
57                 if (s_currentChannelData == null)
58                     RefreshChannelData();
59
60                 return s_currentChannelData; 
61             }
62         } // CurrentChannelData
63
64
65         // hide the default constructor
66         private ChannelServices()
67         {
68         }
69
70         // list of registered channels and a lock to take when adding or removing channels
71         // Note that the channel list is read outside of the lock, which is why it's marked volatile.
72         private static Object s_channelLock = new Object();
73         private static volatile RegisteredChannelList s_registeredChannels = new RegisteredChannelList();
74         
75     
76         // Private member variables        
77         // These have all been converted to getters and setters to get the effect of
78         // per-AppDomain statics (note: statics are per-AppDomain now, so these members
79         // could just be declared as statics on ChannelServices).
80
81         private static long remoteCalls
82         { 
83             get { return Thread.GetDomain().RemotingData.ChannelServicesData.remoteCalls; }
84             set { Thread.GetDomain().RemotingData.ChannelServicesData.remoteCalls = value; }
85         }
86         
87         private static volatile IMessageSink xCtxChannel;
88         
89
90         [System.Security.SecurityCritical]  // auto-generated
91         [MethodImplAttribute(MethodImplOptions.InternalCall)]      
92         [ResourceExposure(ResourceScope.None)]
93         static unsafe extern Perf_Contexts* GetPrivateContextsPerfCounters();
94     
95         [SecurityCritical]
96         unsafe private static volatile Perf_Contexts *perf_Contexts = GetPrivateContextsPerfCounters(); 
97     
98
99         [System.Security.SecuritySafeCritical]  // auto-generated
100         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
101         public static void RegisterChannel(IChannel chnl, bool ensureSecurity)
102         {
103             RegisterChannelInternal(chnl, ensureSecurity);
104         }
105         
106         [System.Security.SecuritySafeCritical]  // auto-generated
107         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
108         [Obsolete("Use System.Runtime.Remoting.ChannelServices.RegisterChannel(IChannel chnl, bool ensureSecurity) instead.", false)]
109         public static void RegisterChannel(IChannel chnl)
110         {
111             RegisterChannelInternal(chnl, false/*ensureSecurity*/);
112         }
113
114         
115         static bool unloadHandlerRegistered = false;
116         [System.Security.SecurityCritical]  // auto-generated
117         unsafe internal static void RegisterChannelInternal(IChannel chnl, bool ensureSecurity)
118         {
119             // Validate arguments
120             if(null == chnl)
121             {
122                 throw new ArgumentNullException("chnl");
123             }
124             Contract.EndContractBlock();
125         
126             bool fLocked = false;
127             RuntimeHelpers.PrepareConstrainedRegions();
128             try
129             {
130                 Monitor.Enter(s_channelLock, ref fLocked);
131                 String chnlName = chnl.ChannelName;
132
133                 RegisteredChannelList regChnlList = s_registeredChannels;
134         
135                 // Check to make sure that the channel has not been registered
136                 if((chnlName == null) ||
137                    (chnlName.Length == 0) ||
138                    (-1 == regChnlList.FindChannelIndex(chnl.ChannelName)))
139                 {
140                     if (ensureSecurity)
141                     {
142                         ISecurableChannel securableChannel = chnl as ISecurableChannel;
143                         if (securableChannel != null)
144                             securableChannel.IsSecured = ensureSecurity;
145                         else
146                             throw new RemotingException(Environment.GetResourceString("Remoting_Channel_CannotBeSecured", chnl.ChannelName??chnl.ToString()));
147                             
148                     }
149                     RegisteredChannel[] oldList = regChnlList.RegisteredChannels;
150                     RegisteredChannel[] newList = null;
151                     if (oldList == null)
152                     {                                            
153                         newList = new RegisteredChannel[1];
154                     }
155                     else
156                         newList = new RegisteredChannel[oldList.Length + 1];
157
158                     if (!unloadHandlerRegistered && !(chnl is CrossAppDomainChannel))
159                     {
160                         // Register a unload handler only once and if the channel being registered
161                         // is not the x-domain channel. x-domain channel does nothing inside its 
162                         // StopListening implementation
163                         AppDomain.CurrentDomain.DomainUnload += new EventHandler(UnloadHandler);
164                         unloadHandlerRegistered = true;
165                     }
166
167                     // Add the interface to the array in priority order
168                     int priority = chnl.ChannelPriority;
169                     int current = 0;
170     
171                     // Find the place in the array to insert
172                     while (current < oldList.Length)
173                     {
174                         RegisteredChannel oldChannel = oldList[current];
175                         if (priority > oldChannel.Channel.ChannelPriority)
176                         {
177                             newList[current] = new RegisteredChannel(chnl);
178                             break;
179                         }
180                         else
181                         {
182                             newList[current] = oldChannel;
183                             current++;
184                         }
185                     }
186
187                     if (current == oldList.Length)
188                     {
189                         // chnl has lower priority than all old channels, so we insert
190                         //   it at the end of the list.
191                         newList[oldList.Length] = new RegisteredChannel(chnl);
192                     }
193                     else
194                     {
195                         // finish copying rest of the old channels
196                         while (current < oldList.Length)
197                         {
198                             newList[current + 1] = oldList[current];
199                             current++;
200                         }
201                     }
202
203                     if (perf_Contexts != null) {
204                         perf_Contexts->cChannels++;
205                     }
206
207                     s_registeredChannels = new RegisteredChannelList(newList);
208                 }
209                 else
210                 {
211                     throw new RemotingException(Environment.GetResourceString("Remoting_ChannelNameAlreadyRegistered", chnl.ChannelName));
212                 }
213
214                 RefreshChannelData();
215             } // lock (s_channelLock)
216             finally
217             {
218                 if (fLocked)
219                 {
220                     Monitor.Exit(s_channelLock);
221                 }
222             }
223         } // RegisterChannelInternal
224     
225     
226         [System.Security.SecuritySafeCritical]  // auto-generated
227         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
228         unsafe public static void UnregisterChannel(IChannel chnl)
229         {
230             // we allow null to be passed in, so we can use this api to trigger the
231             //   refresh of the channel data <
232
233             
234             bool fLocked = false;
235             RuntimeHelpers.PrepareConstrainedRegions();
236             try
237             {
238                 Monitor.Enter(s_channelLock, ref fLocked);
239                 if (chnl != null)
240                 {
241                     RegisteredChannelList regChnlList = s_registeredChannels;
242                 
243                     // Check to make sure that the channel has been registered
244                     int matchingIdx = regChnlList.FindChannelIndex(chnl);
245                     if(-1 == matchingIdx)
246                     {
247                         throw new RemotingException(Environment.GetResourceString("Remoting_ChannelNotRegistered", chnl.ChannelName));
248                     }
249
250                     RegisteredChannel[] oldList = regChnlList.RegisteredChannels;
251                     RegisteredChannel[] newList = null;
252                     Contract.Assert((oldList != null) && (oldList.Length != 0), "channel list should not be empty");
253
254                     newList = new RegisteredChannel[oldList.Length - 1];
255
256                     // Call stop listening on the channel if it is a receiver.
257                     IChannelReceiver srvChannel = chnl as IChannelReceiver;
258                     if (srvChannel != null)
259                         srvChannel.StopListening(null);
260
261                     int current = 0;
262                     int oldPos = 0;
263                     while (oldPos < oldList.Length)
264                     {
265                         if (oldPos == matchingIdx)
266                         {
267                             oldPos++;
268                         }
269                         else
270                         {
271                             newList[current] = oldList[oldPos];
272                             current++;
273                             oldPos++;
274                         }
275                     }
276         
277                     if (perf_Contexts != null) {
278                         perf_Contexts->cChannels--;
279                     }
280
281                     s_registeredChannels = new RegisteredChannelList(newList);
282                 } 
283
284                 RefreshChannelData();
285             } // lock (s_channelLock)
286             finally
287             {
288                 if (fLocked)
289                 {
290                     Monitor.Exit(s_channelLock);
291                 }
292             }
293         } // UnregisterChannel
294
295     
296         public static IChannel[] RegisteredChannels
297         {       
298             [System.Security.SecurityCritical]  // auto-generated_required
299             get 
300             {
301                 RegisteredChannelList regChnlList = s_registeredChannels;
302                 int count = regChnlList.Count;
303             
304                 if (0 == count)
305                 {
306                     return new IChannel[0];
307                 }
308                 else 
309                 {
310                     // we hide the CrossAppDomainChannel, so the number of visible
311                     //   channels is one less than the number of registered channels.
312                     int visibleChannels = count - 1;
313
314                     // Copy the array of visible channels into a new array
315                     // and return
316                     int co = 0;
317                     IChannel[] temp = new IChannel[visibleChannels];
318                     for (int i = 0; i < count; i++)
319                     {
320                         IChannel channel = regChnlList.GetChannel(i);
321                         // add the channel to the array if it is not the CrossAppDomainChannel
322                         if (!(channel is CrossAppDomainChannel))
323                             temp[co++] = channel;
324                     }
325                     return temp;
326                 }
327             }
328         } // RegisteredChannels
329         
330         [System.Security.SecurityCritical]  // auto-generated
331         internal static IMessageSink CreateMessageSink(String url, Object data, out String objectURI) 
332         {
333             BCLDebug.Trace("REMOTE", "ChannelServices::CreateMessageSink for url " + url + "\n");
334             IMessageSink msgSink = null;
335             objectURI = null;
336
337             RegisteredChannelList regChnlList = s_registeredChannels;
338             int count = regChnlList.Count;
339             
340             for(int i = 0; i < count; i++)
341             {
342                 if(regChnlList.IsSender(i))
343                 {
344                     IChannelSender chnl = (IChannelSender)regChnlList.GetChannel(i);
345                     msgSink = chnl.CreateMessageSink(url, data, out objectURI);
346                     
347                     if(msgSink != null)
348                         break;
349                 }
350             }
351             
352             // If the object uri has not been set, set it to the url as 
353             // default value
354             if(null == objectURI)
355             {
356                 objectURI = url;
357             }
358             
359             return msgSink;
360         } // CreateMessageSink
361     
362         [System.Security.SecurityCritical]  // auto-generated
363         internal static IMessageSink CreateMessageSink(Object data)
364         {
365             String objectUri;
366             return CreateMessageSink(null, data, out objectUri);
367         } // CreateMessageSink
368     
369     
370         [System.Security.SecurityCritical]  // auto-generated_required
371         public static IChannel GetChannel(String name)
372         {
373             RegisteredChannelList regChnlList = s_registeredChannels;
374         
375             int matchingIdx = regChnlList.FindChannelIndex(name);
376             if(0 <= matchingIdx)
377             {
378                 IChannel channel = regChnlList.GetChannel(matchingIdx);
379                 if ((channel is CrossAppDomainChannel) || (channel is CrossContextChannel))
380                     return null;
381                 else
382                     return channel;
383             }
384             else
385             {
386                 return null;
387             }
388         } // GetChannel
389         
390         
391         [System.Security.SecurityCritical]  // auto-generated_required
392         public static String[] GetUrlsForObject(MarshalByRefObject obj)
393         {        
394             if(null == obj)
395             {
396                 return null;
397             }
398
399             RegisteredChannelList regChnlList = s_registeredChannels;
400             int count = regChnlList.Count;
401             
402             Hashtable table = new Hashtable();
403             bool fServer;
404             Identity id = MarshalByRefObject.GetIdentity(obj, out fServer);
405
406             if(null != id) 
407             {
408                 String uri = id.ObjURI;
409
410                 if (null != uri)
411                 {
412                     for(int i = 0; i < count; i++)
413                     {
414                         if(regChnlList.IsReceiver(i))
415                         {
416                             try
417                             {
418                                 String[] urls = ((IChannelReceiver)regChnlList.GetChannel(i)).GetUrlsForUri(uri);
419                                 // Add the strings to the table
420                                 for(int j = 0; j < urls.Length; j++)
421                                 {
422                                     table.Add(urls[j], urls[j]);
423                                 }
424                             }
425                             catch(NotSupportedException )
426                             {
427                                 // We do not count the channels that do not 
428                                 // support this method
429                             }
430                         }
431                     }
432                 }
433             }            
434
435             // copy url's into string array
436             ICollection keys = table.Keys;
437             String[] urlList = new String[keys.Count];
438             int co = 0;
439             foreach (String key in keys)
440             {
441                 urlList[co++] = key;
442             }
443             return urlList;
444         }
445
446        // Find the channel message sink associated with a given proxy
447         // <
448         [System.Security.SecurityCritical]  // auto-generated
449         internal static IMessageSink GetChannelSinkForProxy(Object obj)
450         {
451             IMessageSink sink = null;
452             if (RemotingServices.IsTransparentProxy(obj))
453             {
454                 RealProxy rp = RemotingServices.GetRealProxy(obj);
455                 RemotingProxy remProxy = rp as RemotingProxy;
456                 if (null != remProxy)
457                 {
458                     Identity idObj = remProxy.IdentityObject;
459                     Contract.Assert(null != idObj,"null != idObj");
460                     sink = idObj.ChannelSink;
461                 }
462             }
463
464             return sink;
465         } // GetChannelSinkForProxy
466         
467
468         //  Get the message sink dictionary of properties for a given proxy
469
470         [System.Security.SecuritySafeCritical]  // auto-generated
471         [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
472         public static IDictionary GetChannelSinkProperties(Object obj)
473         {
474             IMessageSink sink = GetChannelSinkForProxy(obj);
475             IClientChannelSink chnlSink = sink as IClientChannelSink;
476             if (null != chnlSink)
477             {
478                 // collect dictionaries for all channel sinks and return
479                 //   aggregate dictionary
480                 ArrayList dictionaries = new ArrayList();
481
482                 do                
483                 { 
484                     IDictionary dict = chnlSink.Properties;
485                     if (dict != null)
486                         dictionaries.Add(dict);
487                 
488                     chnlSink = chnlSink.NextChannelSink;
489                 } while (chnlSink != null);
490                 
491                 return new AggregateDictionary(dictionaries);
492             }
493             else
494             {
495                 IDictionary dict = sink as IDictionary;
496                 if(null != dict)    
497                 {
498                     return dict;
499                 }
500                 else
501                 {
502                     return null;
503                 }
504             }
505         } // GetChannelSinkProperties
506
507     
508         internal static IMessageSink GetCrossContextChannelSink()
509         {
510             if(null == xCtxChannel)
511             {
512                 xCtxChannel = CrossContextChannel.MessageSink;
513             }
514     
515             return xCtxChannel;
516         } // GetCrossContextChannelSink
517                
518     
519 #if DEBUG
520         // A few methods to count the number of calls made across appdomains,
521         // processes and machines
522         internal static long GetNumberOfRemoteCalls()
523         {
524             return remoteCalls;
525         } // GetNumberOfRemoteCalls
526 #endif //DEBUG
527     
528         [System.Security.SecurityCritical]  // auto-generated
529         unsafe internal static void IncrementRemoteCalls(long cCalls)
530         {
531             remoteCalls += cCalls;
532             if (perf_Contexts != null)
533               perf_Contexts->cRemoteCalls += (int)cCalls;
534         } // IncrementRemoteCalls
535         
536         [System.Security.SecurityCritical]  // auto-generated
537         internal static void IncrementRemoteCalls()
538         {
539             IncrementRemoteCalls( 1 );
540         } // IncrementRemoteCalls
541
542
543         [System.Security.SecurityCritical]  // auto-generated
544         internal static void RefreshChannelData()
545         {
546             bool fLocked = false;
547             RuntimeHelpers.PrepareConstrainedRegions();
548             try
549             {
550                 Monitor.Enter(s_channelLock, ref fLocked);
551                 s_currentChannelData = CollectChannelDataFromChannels();
552             }
553             finally
554             {
555                 if (fLocked)
556                 {
557                     Monitor.Exit(s_channelLock);
558                 }
559             }
560         } // RefreshChannelData
561
562         [System.Security.SecurityCritical]  // auto-generated
563         private static Object[] CollectChannelDataFromChannels()
564         {
565             // Ensure that our native cross-context & cross-domain channels
566             // are registered
567             RemotingServices.RegisterWellKnownChannels();
568
569             RegisteredChannelList regChnlList = s_registeredChannels;
570             int count = regChnlList.Count;            
571
572             // Compute the number of channels that implement IChannelReceiver
573             int numChnls = regChnlList.ReceiverCount;
574
575             // Allocate array for channel data
576             Object[] data = new Object[numChnls];
577
578             // we need to remove null entries
579             int nonNullDataCount = 0;                        
580
581             // Set the channel data, names and mime types
582             for (int i = 0, j = 0; i < count; i++)
583             {
584
585                 IChannel chnl = regChnlList.GetChannel(i);
586
587                 if (null == chnl)
588                 {
589                     throw new RemotingException(Environment.GetResourceString("Remoting_ChannelNotRegistered", ""));
590                 }
591
592                 if (regChnlList.IsReceiver(i))
593                 {
594                     BCLDebug.Trace("REMOTE", "Setting info for receiver " + j.ToString(CultureInfo.InvariantCulture) + "\n");
595                     // Extract the data
596                     Object channelData = ((IChannelReceiver)chnl).ChannelData;                    
597                     data[j] = channelData;
598                     if (channelData != null)
599                         nonNullDataCount++;
600
601                     // Increment the counter
602                     j++;
603                 }
604             }
605
606             if (nonNullDataCount != numChnls)
607             {
608                 // there were null entries, so remove them.
609                 Object[] nonNullData = new Object[nonNullDataCount];
610                 int nonNullCounter = 0;
611                 for (int co = 0; co < numChnls; co++)
612                 {
613                     Object channelData = data[co];
614                     if (channelData != null)
615                         nonNullData[nonNullCounter++] = channelData;
616                 }
617
618                 data = nonNullData;
619             }
620             
621             return data;
622         } // CollectChannelDataFromChannels
623
624         // Checks to make sure the remote method being invoked is callable
625         static bool IsMethodReallyPublic(MethodInfo mi)
626         {
627             if (!mi.IsPublic || mi.IsStatic)
628                 return false;
629      
630             if (!mi.IsGenericMethod)
631                 return true;
632      
633             foreach (Type t in mi.GetGenericArguments())
634                 if (!t.IsVisible)
635                     return false;
636      
637             return true;
638         }
639
640         //--------------------------------------------------------------------
641         //-----------------------  Dispatch Support   ------------------------
642         //--------------------------------------------------------------------
643
644         [System.Security.SecurityCritical]  // auto-generated_required
645         public static ServerProcessing DispatchMessage(
646             IServerChannelSinkStack sinkStack,
647             IMessage msg, 
648             out IMessage replyMsg)
649         {
650             ServerProcessing processing = ServerProcessing.Complete;
651             replyMsg = null;
652             
653             try
654             {            
655                 if(null == msg)
656                 {
657                     throw new ArgumentNullException("msg");
658                 }
659
660                 BCLDebug.Trace("REMOTE", "Dispatching for URI " + InternalSink.GetURI(msg));
661
662                 // we must switch to the target context of the object and call the context chains etc...
663                 // Currenly XContextChannel does exactly so. So this method is just a wrapper..
664     
665                 // <
666
667                 
668                 // Make sure that incoming calls are counted as a remote call. This way it 
669                 // makes more sense on a server.
670                 IncrementRemoteCalls();
671         
672                 // Check if the object has been disconnected or if it is 
673                 // a well known object then we have to create it lazily.
674                 ServerIdentity srvId = CheckDisconnectedOrCreateWellKnownObject(msg);
675
676                 // Make sure that this isn't an AppDomain object since we don't allow
677                 //   calls to the AppDomain from out of process (and x-process calls
678                 //   are always dispatched through this method)
679                 if (srvId.ServerType == typeof(System.AppDomain))
680                 {
681                     throw new RemotingException(
682                         Environment.GetResourceString(
683                             "Remoting_AppDomainsCantBeCalledRemotely"));
684                 }
685                 
686
687                 IMethodCallMessage mcm = msg as IMethodCallMessage;
688
689                 if (mcm == null)
690                 {
691                     // It's a plain IMessage, so just check to make sure that the
692                     //   target object implements IMessageSink and dispatch synchronously.
693
694                     if (!typeof(IMessageSink).IsAssignableFrom(srvId.ServerType))
695                     {
696                         throw new RemotingException(
697                             Environment.GetResourceString(
698                                 "Remoting_AppDomainsCantBeCalledRemotely"));
699                     }
700
701                     processing = ServerProcessing.Complete;
702                     replyMsg = ChannelServices.GetCrossContextChannelSink().SyncProcessMessage(msg);
703                 }
704                 else
705                 {
706                     // It's an IMethodCallMessage.
707                 
708                     // Check if the method is one way. Dispatch one way calls in 
709                     // an asynchronous manner
710                     MethodInfo method = (MethodInfo)mcm.MethodBase;                                  
711     
712                     // X-process / X-machine calls should be to non-static
713                     // public methods only! Non-public or static methods can't
714                     // be called remotely.
715                     if (!IsMethodReallyPublic(method) && 
716                           !RemotingServices.IsMethodAllowedRemotely(method))
717                     {
718                         throw new RemotingException(
719                             Environment.GetResourceString(
720                                 "Remoting_NonPublicOrStaticCantBeCalledRemotely"));
721                     }
722
723                     RemotingMethodCachedData cache = (RemotingMethodCachedData)
724                         InternalRemotingServices.GetReflectionCachedData(method);
725                         
726                     /*
727                         
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754 */                  
755                     if(RemotingServices.IsOneWay(method))                    
756                     {
757                         processing = ServerProcessing.OneWay;
758                         ChannelServices.GetCrossContextChannelSink().AsyncProcessMessage(msg, null);
759                     }
760                     else
761                     {                    
762                         // regular processing
763                         processing = ServerProcessing.Complete;
764                         if (!srvId.ServerType.IsContextful)
765                         {
766                             Object[] args = new Object[]{msg, srvId.ServerContext};
767                             replyMsg = (IMessage) CrossContextChannel.SyncProcessMessageCallback(args);                            
768                         }
769                         else 
770                             replyMsg = ChannelServices.GetCrossContextChannelSink().SyncProcessMessage(msg);
771                     }
772                 } // end of case for IMethodCallMessage
773             }
774             catch(Exception e)
775             {
776                 if(processing != ServerProcessing.OneWay)
777                 {
778                     try
779                     {                    
780                         IMethodCallMessage mcm = 
781                             (IMethodCallMessage) ((msg!=null)?msg:new ErrorMessage());
782                         replyMsg = (IMessage)new ReturnMessage(e, mcm);
783                         if (msg != null)
784                         {
785                             ((ReturnMessage)replyMsg).SetLogicalCallContext(
786                                     (LogicalCallContext)
787                                         msg.Properties[Message.CallContextKey]);
788                         }
789                     }
790                     catch(Exception )
791                     {
792                         // Fatal exception .. ignore
793                     }
794                 }
795             }               
796
797             return processing;
798         } // DispatchMessage
799         
800        // This method is used by the channel to dispatch the incoming messages
801        // to the server side chain(s) based on the URI embedded in the message.
802        // The URI uniquely identifies the receiving object.
803        // 
804         [System.Security.SecurityCritical]  // auto-generated_required
805         public static IMessage SyncDispatchMessage(IMessage msg)
806         {            
807             IMessage msgRet = null;
808             bool fIsOneWay = false;
809             
810             try
811             {            
812                 if(null == msg)
813                 {
814                     throw new ArgumentNullException("msg");
815                 }
816
817
818
819                 // For ContextBoundObject's,
820                 // we must switch to the target context of the object and call the context chains etc...
821                 // Currenly XContextChannel does exactly so. So this method is just a wrapper..
822     
823                 
824                 // Make sure that incoming calls are counted as a remote call. This way it 
825                 // makes more sense on a server.
826                 IncrementRemoteCalls();
827
828                 // <
829                 if (!(msg is TransitionCall))
830                 {
831                     // Check if the object has been disconnected or if it is 
832                     // a well known object then we have to create it lazily.
833                     CheckDisconnectedOrCreateWellKnownObject(msg);
834
835                     MethodBase method = ((IMethodMessage)msg).MethodBase;
836
837                     // Check if the method is one way. Dispatch one way calls in 
838                     // an asynchronous manner                    
839                     fIsOneWay = RemotingServices.IsOneWay(method);
840                 }
841
842                 // <
843                 IMessageSink nextSink = ChannelServices.GetCrossContextChannelSink();
844                 
845                 if(!fIsOneWay)
846                 {                    
847                     msgRet = nextSink.SyncProcessMessage(msg);  
848                 }
849                 else
850                 {
851                     nextSink.AsyncProcessMessage(msg, null);
852                 }
853             }
854             catch(Exception e)
855             {
856                 if(!fIsOneWay)
857                 {
858                     try
859                     {                    
860                         IMethodCallMessage mcm = 
861                             (IMethodCallMessage) ((msg!=null)?msg:new ErrorMessage());
862                         msgRet = (IMessage)new ReturnMessage(e, mcm);
863                         if (msg!=null)
864                         {
865                             ((ReturnMessage)msgRet).SetLogicalCallContext(
866                                 mcm.LogicalCallContext);
867                         }
868                     }
869                     catch(Exception )
870                     {
871                         // Fatal exception .. ignore
872                     }
873                 }
874             }               
875
876             return msgRet;
877         }
878
879        // This method is used by the channel to dispatch the incoming messages
880        // to the server side chain(s) based on the URI embedded in the message.
881        // The URI uniquely identifies the receiving object.
882        // 
883         [System.Security.SecurityCritical]  // auto-generated_required
884         public static IMessageCtrl AsyncDispatchMessage(IMessage msg, IMessageSink replySink)
885         {
886             IMessageCtrl ctrl = null;
887
888             try
889             {
890                 if(null == msg)
891                 {
892                     throw new ArgumentNullException("msg");
893                 }
894             
895                 // we must switch to the target context of the object and call the context chains etc...
896                 // Currenly XContextChannel does exactly so. So this method is just a wrapper..
897     
898                 // Make sure that incoming calls are counted as a remote call. This way it 
899                 // makes more sense on a server.
900                 IncrementRemoteCalls();
901                 
902                 if (!(msg is TransitionCall))
903                 {
904                     // Check if the object has been disconnected or if it is 
905                     // a well known object then we have to create it lazily.
906                     CheckDisconnectedOrCreateWellKnownObject(msg);    
907                 }
908     
909                 // <
910
911                 ctrl = ChannelServices.GetCrossContextChannelSink().AsyncProcessMessage(msg, replySink);
912             }
913             catch(Exception e)
914             {
915                 if(null != replySink)
916                 {
917                     try
918                     {
919                         IMethodCallMessage mcm = (IMethodCallMessage)msg;
920                         ReturnMessage retMsg = new ReturnMessage(e, (IMethodCallMessage)msg);
921                         if (msg!=null)
922                         {
923                             retMsg.SetLogicalCallContext(mcm.LogicalCallContext);
924                         }
925                         replySink.SyncProcessMessage(retMsg);
926                     }
927                     catch(Exception )
928                     {
929                         // Fatal exception... ignore
930                     }                    
931                 }
932             }
933
934             return ctrl;
935         } // AsyncDispatchMessage
936
937
938         // Creates a channel sink chain (adds special dispatch sink to the end of the chain)
939         [System.Security.SecurityCritical]  // auto-generated_required
940         public static IServerChannelSink CreateServerChannelSinkChain(
941             IServerChannelSinkProvider provider, IChannelReceiver channel)
942         {
943             if (provider == null)
944                 return new DispatchChannelSink();       
945             
946             // add dispatch provider to end (first find last provider)
947             IServerChannelSinkProvider lastProvider = provider;
948             while (lastProvider.Next != null)
949                 lastProvider = lastProvider.Next;
950             lastProvider.Next = new DispatchChannelSinkProvider();
951
952             IServerChannelSink sinkChain = provider.CreateSink(channel);
953
954             // remove dispatch provider from end
955             lastProvider.Next = null;            
956
957             return sinkChain;
958         } // CreateServerChannelSinkChain
959         
960         
961
962         // Check if the object has been disconnected or if it is 
963         // a well known object then we have to create it lazily.
964         [System.Security.SecurityCritical]  // auto-generated
965         internal static ServerIdentity CheckDisconnectedOrCreateWellKnownObject(IMessage msg)
966         {
967             ServerIdentity ident = InternalSink.GetServerIdentity(msg);
968             
969             BCLDebug.Trace("REMOTE", "Identity found = " + (ident == null ? "null" : "ServerIdentity"));
970
971             // If the identity is null, then we should check whether the 
972             // request if for a well known object. If yes, then we should 
973             // create the well known object lazily and marshal it.
974             if ((ident == null) || ident.IsRemoteDisconnected())
975             {
976                 String uri = InternalSink.GetURI(msg);
977                 BCLDebug.Trace("REMOTE", "URI " + uri);
978                 if (uri != null)
979                 {
980                     ServerIdentity newIdent = RemotingConfigHandler.CreateWellKnownObject(uri);
981                     if (newIdent != null)
982                     {
983                         // The uri was a registered wellknown object.
984                         ident = newIdent;
985                         BCLDebug.Trace("REMOTE", "Identity created = " + (ident == null ? "null" : "ServerIdentity"));
986                     }
987                 }  
988
989             }
990
991
992             if ((ident == null) || (ident.IsRemoteDisconnected()))
993             {
994                 String uri = InternalSink.GetURI(msg);
995                 throw new RemotingException(Environment.GetResourceString("Remoting_Disconnected",uri));                
996             }
997             return ident;
998         }
999         
1000         // Channel Services AppDomain Unload Event Handler
1001         [System.Security.SecurityCritical]  // auto-generated
1002         internal static void UnloadHandler(Object sender, EventArgs e)
1003         {
1004             StopListeningOnAllChannels();
1005         }
1006
1007         [System.Security.SecurityCritical]  // auto-generated
1008         private static void StopListeningOnAllChannels()
1009         {
1010             try
1011             {
1012                 RegisteredChannelList regChnlList = s_registeredChannels;
1013                 int count = regChnlList.Count;    
1014             
1015                 for(int i = 0; i < count; i++)
1016                 {
1017                     if(regChnlList.IsReceiver(i))
1018                     {
1019                         IChannelReceiver chnl = (IChannelReceiver)regChnlList.GetChannel(i);
1020                         chnl.StopListening(null);
1021                     }
1022                 }
1023             }
1024             catch (Exception)
1025             {
1026                 // Ignore ... appdomain is shutting down..
1027             }
1028         }
1029
1030
1031
1032
1033         //
1034         // INTERNAL PROFILER NOTIFICATION SERVICES
1035         //
1036
1037         [System.Security.SecurityCritical]  // auto-generated
1038         internal static void NotifyProfiler(IMessage msg, RemotingProfilerEvent profilerEvent)
1039         {
1040             switch (profilerEvent)
1041             {
1042             
1043             case RemotingProfilerEvent.ClientSend:
1044             {
1045                 if (RemotingServices.CORProfilerTrackRemoting())
1046                 {
1047                     Guid g;
1048
1049                     RemotingServices.CORProfilerRemotingClientSendingMessage(out g, false);
1050
1051                     if (RemotingServices.CORProfilerTrackRemotingCookie())
1052                         msg.Properties["CORProfilerCookie"] = g;
1053                 }
1054                 break;
1055             } // case RemotingProfilerEvent.ClientSend
1056
1057             case RemotingProfilerEvent.ClientReceive:
1058             {
1059                 if (RemotingServices.CORProfilerTrackRemoting())
1060                 {
1061                     Guid g = Guid.Empty;
1062
1063                     if (RemotingServices.CORProfilerTrackRemotingCookie())
1064                     {
1065                         Object obj = msg.Properties["CORProfilerCookie"];
1066
1067                         if (obj != null)
1068                         {
1069                             g = (Guid) obj;
1070                         }
1071                     }
1072
1073                     RemotingServices.CORProfilerRemotingClientReceivingReply(g, false);
1074                 }
1075                 break;
1076             } // case RemotingProfilerEvent.ClientReceive
1077             
1078             } // switch (event)
1079         } // NotifyProfiler        
1080
1081
1082
1083         // This is a helper used by UrlObjRef's.
1084         // Finds an http channel and returns first url for this object.
1085         [System.Security.SecurityCritical]  // auto-generated
1086         internal static String FindFirstHttpUrlForObject(String objectUri)
1087         {                    
1088             if (objectUri == null)
1089                 return null;       
1090
1091             RegisteredChannelList regChnlList = s_registeredChannels;
1092             int count = regChnlList.Count;    
1093
1094             for (int i = 0; i < count; i++)
1095             {
1096                 if(regChnlList.IsReceiver(i))
1097                 {       
1098                     IChannelReceiver chnl = (IChannelReceiver)regChnlList.GetChannel(i);
1099                     String chnlType = chnl.GetType().FullName;
1100                     if ((String.CompareOrdinal(chnlType, "System.Runtime.Remoting.Channels.Http.HttpChannel") == 0) ||
1101                         (String.CompareOrdinal(chnlType, "System.Runtime.Remoting.Channels.Http.HttpServerChannel") == 0))
1102                     {                                            
1103                         String[] urls = chnl.GetUrlsForUri(objectUri);
1104                         if ((urls != null) && (urls.Length > 0))
1105                             return urls[0];
1106                     }
1107                 }                               
1108             }      
1109
1110             return null;
1111         } // FindFirstHttpUrlForObject
1112
1113
1114         //
1115         // DEBUG Helpers
1116         //   Note: These methods should be included even in retail builds so that 
1117         //     they can be called from the debugger.
1118         //
1119 #if DEBUG
1120         internal static void DumpRegisteredChannels()
1121         {
1122             // To use from cordbg: 
1123             //   f System.Runtime.Remoting.Channels.ChannelServices::DumpRegisteredChannels
1124
1125             RegisteredChannelList regChnlList = s_registeredChannels;
1126             int count = regChnlList.Count; 
1127         
1128             Console.Error.WriteLine("Registered Channels:");            
1129         
1130             for (int i = 0; i < count; i++)
1131             {
1132                 IChannel chnl = regChnlList.GetChannel(i);
1133                 Console.Error.WriteLine(chnl);
1134             }
1135         } // DumpRegisteredChannels
1136 #endif // DEBUG
1137
1138
1139     } // class ChannelServices
1140
1141
1142     // used by ChannelServices.NotifyProfiler
1143     [Serializable]
1144     internal enum RemotingProfilerEvent
1145     {
1146         ClientSend,
1147         ClientReceive
1148     } // RemotingProfilerEvent
1149
1150     
1151     
1152     
1153     internal class RegisteredChannel
1154     {
1155         // private member variables
1156         private IChannel channel;
1157         private byte flags;
1158         private const byte SENDER      = 0x1;
1159         private const byte RECEIVER    = 0x2;
1160     
1161         internal RegisteredChannel(IChannel chnl)
1162         {
1163             channel = chnl;
1164             flags = 0;
1165             if(chnl is IChannelSender)
1166             {
1167                 flags |= SENDER;
1168             }
1169             if(chnl is IChannelReceiver)
1170             {
1171                 flags |= RECEIVER;
1172             }
1173         }
1174     
1175         internal virtual IChannel Channel
1176         {
1177             get { return channel; }
1178         }
1179     
1180         internal virtual bool IsSender()
1181         {
1182             return ((flags & SENDER) != 0);
1183         }
1184     
1185         internal virtual bool IsReceiver()
1186         {
1187             return ((flags & RECEIVER) != 0);
1188         }
1189     }// class RegisteredChannel
1190
1191
1192
1193     // This list should be considered immutable once created.
1194     //   <
1195
1196
1197     internal class RegisteredChannelList
1198     {
1199         private RegisteredChannel[] _channels;
1200
1201         internal RegisteredChannelList()
1202         {
1203             _channels = new RegisteredChannel[0];
1204         } // RegisteredChannelList
1205
1206         internal RegisteredChannelList(RegisteredChannel[] channels)
1207         {
1208             _channels = channels;
1209         } // RegisteredChannelList
1210
1211         internal RegisteredChannel[] RegisteredChannels
1212         {
1213             get { return _channels; }
1214         } // RegisteredChannels
1215
1216         internal int Count
1217         {
1218             get 
1219             {
1220                 if (_channels == null)
1221                     return 0;
1222
1223                 return _channels.Length;
1224             }
1225         } // Count
1226
1227         internal IChannel GetChannel(int index)
1228         {                
1229             return _channels[index].Channel;
1230         } // GetChannel
1231
1232         internal bool IsSender(int index)
1233         {
1234             return _channels[index].IsSender();
1235         } // IsSender
1236
1237         internal bool IsReceiver(int index)
1238         {
1239             return _channels[index].IsReceiver();
1240         } // IsReceiver        
1241
1242         internal int ReceiverCount
1243         {
1244             get 
1245             {
1246                 if (_channels == null)
1247                     return 0;
1248                 
1249                 int total = 0;
1250                 for (int i = 0; i < _channels.Length; i++)
1251                 {
1252                     if (IsReceiver(i))
1253                         total++;
1254                 }
1255                 
1256                 return total;
1257             }
1258         } // ReceiverCount
1259     
1260         internal int FindChannelIndex(IChannel channel)
1261         {
1262             Object chnlAsObject = (Object)channel;
1263         
1264             for (int i = 0; i < _channels.Length; i++)
1265             {
1266                 if (chnlAsObject == (Object)GetChannel(i))
1267                     return i;                    
1268             }
1269
1270             return -1;
1271         } // FindChannelIndex
1272
1273         [System.Security.SecurityCritical]  // auto-generated
1274         internal int FindChannelIndex(String name)
1275         {        
1276             for (int i = 0; i < _channels.Length; i++)
1277             {
1278                 if(String.Compare(name, GetChannel(i).ChannelName, StringComparison.OrdinalIgnoreCase) == 0)
1279                     return i;                
1280             }
1281
1282             return -1;
1283         } // FindChannelIndex
1284         
1285         
1286     } // class RegisteredChannelList
1287     
1288
1289
1290
1291     internal class ChannelServicesData
1292     {        
1293         internal long remoteCalls = 0;
1294         internal CrossContextChannel xctxmessageSink = null;
1295         internal CrossAppDomainChannel xadmessageSink = null;
1296         internal bool fRegisterWellKnownChannels = false;
1297     }
1298
1299    //
1300    // Terminator sink used for profiling so that we can intercept asynchronous
1301    // replies on the server side.
1302    //  
1303     
1304     /* package scope */
1305     internal class ServerAsyncReplyTerminatorSink : IMessageSink
1306     {
1307         internal IMessageSink _nextSink;
1308
1309         internal ServerAsyncReplyTerminatorSink(IMessageSink nextSink)
1310         {
1311             Contract.Assert(nextSink != null,
1312                             "null IMessageSink passed to ServerAsyncReplyTerminatorSink ctor.");
1313             _nextSink = nextSink;
1314         }
1315
1316         [System.Security.SecurityCritical]  // auto-generated
1317         public virtual IMessage SyncProcessMessage(IMessage replyMsg)
1318         {
1319             // If this class has been brought into the picture, then the following must be true.
1320             Contract.Assert(RemotingServices.CORProfilerTrackRemoting(),
1321                             "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");
1322             Contract.Assert(RemotingServices.CORProfilerTrackRemotingAsync(),
1323                             "CORProfilerTrackRemoting returned false, but we're in AsyncProcessMessage!");
1324
1325             Guid g;
1326
1327             // Notify the profiler that we are receiving an async reply from the server-side
1328             RemotingServices.CORProfilerRemotingServerSendingReply(out g, true);
1329
1330             // If GUID cookies are active, then we save it for the other end of the channel
1331             if (RemotingServices.CORProfilerTrackRemotingCookie())
1332                 replyMsg.Properties["CORProfilerCookie"] = g;
1333
1334             // Now that we've done the intercepting, pass the message on to the regular chain
1335             return _nextSink.SyncProcessMessage(replyMsg);
1336         }
1337     
1338         [System.Security.SecurityCritical]  // auto-generated
1339         public virtual IMessageCtrl AsyncProcessMessage(IMessage replyMsg, IMessageSink replySink)
1340         {
1341             // Since this class is only used for intercepting async replies, this function should
1342             // never get called. (Async replies are synchronous, ironically)
1343             Contract.Assert(false, "ServerAsyncReplyTerminatorSink.AsyncProcessMessage called!");
1344
1345             return null;
1346         }
1347     
1348         public IMessageSink NextSink
1349         {
1350             [System.Security.SecurityCritical]  // auto-generated
1351             get
1352             {
1353                 return _nextSink;
1354             }
1355         }
1356
1357         // Do I need a finalize here?
1358     }
1359 }