2004-11-04 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Channels / ChannelServices.cs
index 9a0ca54f5b7a1a34ad2bc3b203201c40738dd150..124d01a44294f656c7278191d65f4bf86d5acec5 100644 (file)
@@ -8,6 +8,29 @@
 // 2002 (C) Copyright, Ximian, Inc.
 //
 
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
 using System.Collections;
 using System.Reflection;
 using System.Runtime.Remoting;
@@ -85,6 +108,7 @@ namespace System.Runtime.Remoting.Channels
                                }
                                
                                // Not found. Try now creation delayed channels
+                               RemotingConfiguration.LoadDefaultDelayedChannels ();
                                foreach (IChannelSender sender in delayedClientChannels) 
                                {
                                        IMessageSink sink = CreateClientChannelSinkChain (sender, url, channelDataArray, out objectUri);
@@ -130,13 +154,6 @@ namespace System.Runtime.Remoting.Channels
                        }
                }
 
-               [MonoTODO]
-               public static IMessageCtrl AsyncDispatchMessage (IMessage msg,
-                                                                IMessageSink replySink)
-               {
-                       throw new NotImplementedException ();
-               }
-
                public static IServerChannelSink CreateServerChannelSinkChain (
                        IServerChannelSinkProvider provider, IChannelReceiver channel)
            {
@@ -148,13 +165,15 @@ namespace System.Runtime.Remoting.Channels
                        return  provider.CreateSink (channel);
                }
 
-               [MonoTODO]
                public static ServerProcessing DispatchMessage (
                        IServerChannelSinkStack sinkStack,
                        IMessage msg,
                        out IMessage replyMsg)
                {
-                       // TODO: Async processing
+                       if (msg == null) throw new ArgumentNullException ("msg");
+                       
+                       // Async processing is not done here because there isn't any way
+                       // to know if a message is to be dispatched sync or asynchronously.
 
                        replyMsg = SyncDispatchMessage (msg);
 
@@ -175,10 +194,30 @@ namespace System.Runtime.Remoting.Channels
                        }
                }
 
-               [MonoTODO]
                public static IDictionary GetChannelSinkProperties (object obj)
                {
-                       throw new NotImplementedException ();
+                       if (!RemotingServices.IsTransparentProxy (obj))
+                               throw new ArgumentException ("obj must be a proxy","obj");
+                               
+                       ClientIdentity ident = (ClientIdentity) RemotingServices.GetRealProxy (obj).ObjectIdentity;
+                       IMessageSink sink = ident.ChannelSink;
+                       ArrayList dics = new ArrayList ();
+                       
+                       while (sink != null && !(sink is IClientChannelSink))
+                               sink = sink.NextSink;
+
+                       if (sink == null)
+                               return new Hashtable ();
+
+                       IClientChannelSink csink = sink as IClientChannelSink;
+                       while (csink != null)
+                       {
+                               dics.Add (csink.Properties);
+                               csink = csink.NextChannelSink;
+                       }
+
+                       IDictionary[] adics = (IDictionary[]) dics.ToArray (typeof(IDictionary[]));
+                       return new AggregateDictionary (adics);
                }
 
                public static string[] GetUrlsForObject (MarshalByRefObject obj)
@@ -215,7 +254,7 @@ namespace System.Runtime.Remoting.Channels
                                {
                                        IChannel regc = (IChannel) registeredChannels[n];
                                        
-                                       if (regc.ChannelName == chnl.ChannelName)
+                                       if (regc.ChannelName == chnl.ChannelName && chnl.ChannelName != "")
                                                throw new RemotingException ("Channel " + regc.ChannelName + " already registered");
                                                
                                        if (regc.ChannelPriority < chnl.ChannelPriority && pos==-1)
@@ -319,13 +358,67 @@ namespace System.Runtime.Remoting.Channels
                }
 
                public static IMessage SyncDispatchMessage (IMessage msg)
+               {
+                       IMessage ret = CheckIncomingMessage (msg);
+                       if (ret != null) return CheckReturnMessage (msg, ret);
+                       ret = _crossContextSink.SyncProcessMessage (msg);
+                       return CheckReturnMessage (msg, ret);
+               }
+
+               public static IMessageCtrl AsyncDispatchMessage (IMessage msg, IMessageSink replySink)
+               {
+                       IMessage ret = CheckIncomingMessage (msg);
+                       if (ret != null) {
+                               replySink.SyncProcessMessage (CheckReturnMessage (msg, ret));
+                               return null;
+                       }
+                       
+#if NET_1_1
+                       if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (msg)))
+                               replySink = new ExceptionFilterSink (msg, replySink);
+#endif
+                       
+                       return _crossContextSink.AsyncProcessMessage (msg, replySink);          
+               }
+               
+               static ReturnMessage CheckIncomingMessage (IMessage msg)
                {
                        IMethodMessage call = (IMethodMessage)msg;
-                       ServerIdentity identity = RemotingServices.GetIdentityForUri(call.Uri) as ServerIdentity;
-                       if (identity == null) return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg);
+                       ServerIdentity identity = RemotingServices.GetIdentityForUri (call.Uri) as ServerIdentity;
+
+                       if (identity == null) 
+                               return new ReturnMessage (new RemotingException ("No receiver for uri " + call.Uri), (IMethodCallMessage) msg);
 
                        RemotingServices.SetMessageTargetIdentity (msg, identity);
-                       return _crossContextSink.SyncProcessMessage (msg);
+                       return null;
+               }
+
+               internal static IMessage CheckReturnMessage (IMessage callMsg, IMessage retMsg)
+               {
+#if NET_1_1
+                       IMethodReturnMessage ret = retMsg as IMethodReturnMessage;
+                       if (ret != null && ret.Exception != null)
+                       {
+                               if (RemotingConfiguration.CustomErrorsEnabled (IsLocalCall (callMsg)))
+                               {
+                                       Exception ex = new Exception ("Server encountered an internal error. For more information, turn off customErrors in the server's .config file.");
+                                       retMsg = new MethodResponse (ex, (IMethodCallMessage)callMsg);
+                               }
+                       }
+#endif
+                       return retMsg;
+               }
+               
+               static bool IsLocalCall (IMessage callMsg)
+               {
+                       return true;
+                       
+/*                     How can I know if a call is local?!?
+                       
+                       object isLocal = callMsg.Properties ["__isLocalCall"];
+                       if (isLocal == null) return false;
+                       return (bool)isLocal;
+*/
                }
 
                public static void UnregisterChannel (IChannel chnl)
@@ -335,14 +428,19 @@ namespace System.Runtime.Remoting.Channels
                                
                        lock (registeredChannels.SyncRoot)
                        {
-                               if (!registeredChannels.Contains ((object) chnl))
-                                       throw new RemotingException ();
-       
-                               registeredChannels.Remove ((object) chnl);
+                               for (int n=0; n<registeredChannels.Count; n++) 
+                               {
+                                       if (registeredChannels [n] == (object)chnl) {
+                                               registeredChannels.RemoveAt (n);
+                                               IChannelReceiver chnlReceiver = chnl as IChannelReceiver;
+                                               if(chnlReceiver != null)
+                                                       chnlReceiver.StopListening(null);
+                                               return;
+                                       }
+                               }
+                               
+                               throw new RemotingException ("Channel not registered");
        
-                               IChannelReceiver chnlReceiver = chnl as IChannelReceiver;
-                               if(chnlReceiver != null)
-                                       chnlReceiver.StopListening(null);
                        }
                }
 
@@ -366,4 +464,31 @@ namespace System.Runtime.Remoting.Channels
                        return  list.ToArray ();
                }
        }
+       
+       internal class ExceptionFilterSink: IMessageSink
+       {
+               IMessageSink _next;
+               IMessage _call;
+               
+               public ExceptionFilterSink (IMessage call, IMessageSink next)
+               {
+                       _call = call;
+                       _next = next;
+               }
+               
+               public IMessage SyncProcessMessage (IMessage msg)
+               {
+                       return _next.SyncProcessMessage (ChannelServices.CheckReturnMessage (_call, msg));
+               }
+
+               public IMessageCtrl AsyncProcessMessage (IMessage msg, IMessageSink replySink)
+               {
+                       throw new InvalidOperationException();
+               }
+
+               public IMessageSink NextSink 
+               { 
+                       get { return _next; }
+               }
+       }
 }