2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Channels / CrossAppDomainChannel.cs
index 4cbd740788fe4d0dadd261d58b2fccd61f3fc176..836ce0f8c2af5358688dcfe3eae7f78b9fff120f 100755 (executable)
@@ -7,6 +7,29 @@
 // 2003 (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.IO;\r
 using System.Threading;\r
@@ -102,28 +125,19 @@ namespace System.Runtime.Remoting.Channels
                public virtual IMessageSink CreateMessageSink(String url, Object data, out String uri) \r
                {\r
                        uri = null;\r
-                       IMessageSink sink = null;\r
             \r
-                       if (url == null && data != null) \r
+                       if (data != null) \r
                        {\r
                                // Get the data and then get the sink\r
                                CrossAppDomainData cadData = data as CrossAppDomainData;\r
                                if (cadData != null && cadData.ProcessID == RemotingConfiguration.ProcessId)\r
                                        // GetSink creates a new sink if we don't have any (use contexts here later)\r
-                                       sink = CrossAppDomainSink.GetSink(cadData.DomainID);\r
+                                       return CrossAppDomainSink.GetSink(cadData.DomainID);\r
                        } \r
-                       else \r
-                       {\r
-                               if (url != null && data == null) \r
-                               {\r
-                                       if (url.StartsWith(_strName)) \r
-                                       {\r
-                                               throw new NotSupportedException("Can't create a named channel via crossappdomain");\r
-                                       }\r
-                               }\r
-                       }\r
+                       if (url != null && url.StartsWith(_strName)) \r
+                               throw new NotSupportedException("Can't create a named channel via crossappdomain");\r
 \r
-                       return sink;\r
+                       return null;\r
                }
        }
        \r
@@ -131,6 +145,10 @@ namespace System.Runtime.Remoting.Channels
        internal class CrossAppDomainSink : IMessageSink \r
        {\r
                private static Hashtable s_sinks = new Hashtable();\r
+
+               private static MethodInfo processMessageMethod =
+                       typeof (CrossAppDomainSink).GetMethod ("ProcessMessageInDomain", BindingFlags.NonPublic|BindingFlags.Static);
+
 \r
                private int _domainID;\r
 \r
@@ -155,6 +173,33 @@ namespace System.Runtime.Remoting.Channels
                                        return sink;\r
                                }\r
                        }\r
+               }\r
+               \r
+               internal int TargetDomainId {\r
+                       get { return _domainID; }\r
+               }
+
+               private struct ProcessMessageRes {
+                       public byte[] arrResponse;
+                       public CADMethodReturnMessage cadMrm;
+               }
+
+               private static ProcessMessageRes ProcessMessageInDomain (
+                       byte[] arrRequest,
+                       CADMethodCallMessage cadMsg)
+           {
+                       ProcessMessageRes res = new ProcessMessageRes ();
+
+                       try 
+                       {
+                               AppDomain.CurrentDomain.ProcessMessageInDomain (arrRequest, cadMsg, out res.arrResponse, out res.cadMrm);
+                       }
+                       catch (Exception e) 
+                       {
+                               IMessage errorMsg = new MethodResponse (e, new ErrorMessage());
+                               res.arrResponse = CADSerializer.SerializeMessage (errorMsg).GetBuffer(); \r
+                       }
+                       return res;
                }
 \r
                public virtual IMessage SyncProcessMessage(IMessage msgRequest) \r
@@ -179,23 +224,19 @@ namespace System.Runtime.Remoting.Channels
 \r
                                object threadStatus = Thread.ResetDataStoreStatus ();\r
                                Context currentContext = Thread.CurrentContext;
-                               AppDomain currentDomain = AppDomain.InternalSetDomainByID ( _domainID );\r
 
-                               try 
-                               {
-                                       AppDomain.CurrentDomain.ProcessMessageInDomain (arrRequest, cadMsg, out arrResponse, out cadMrm);
+                               try {
+                                       // InternalInvoke can't handle out arguments, this is why
+                                       // we return the results in a structure
+                                       ProcessMessageRes res = (ProcessMessageRes)AppDomain.InvokeInDomainByID (_domainID, processMessageMethod, null, new object [] { arrRequest, cadMsg });
+                                       arrResponse = res.arrResponse;
+                                       cadMrm = res.cadMrm;
                                }
-                               catch (Exception e) 
-                               {
-                                       IMessage errorMsg = new MethodResponse (e, new ErrorMessage());
-                                       arrResponse = CADSerializer.SerializeMessage (errorMsg).GetBuffer(); \r
-                               }   
-                               finally 
-                               {
-                                       AppDomain.InternalSetDomain (currentDomain);
+                               finally {
                                        AppDomain.InternalSetContext (currentContext);
-                                       Thread.RestoreDataStoreStatus (threadStatus);\r
-                               }\r
+                                       Thread.RestoreDataStoreStatus (threadStatus);
+                               }                                       
+
                                \r
                                if (null != arrResponse) {\r
                                        // Time to deserialize the message\r
@@ -210,7 +251,6 @@ namespace System.Runtime.Remoting.Channels
                        {\r
                                try\r
                                {\r
-                                       Console.WriteLine("Exception in base domain");
                                        retMessage = new ReturnMessage (e, msgRequest as IMethodCallMessage);
                                }\r
                                catch (Exception)\r
@@ -222,11 +262,20 @@ namespace System.Runtime.Remoting.Channels
                return retMessage;\r
                }
 
-               public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink) \r
+               public virtual IMessageCtrl AsyncProcessMessage (IMessage reqMsg, IMessageSink replySink) \r
                {\r
-                       throw new NotSupportedException();\r
+                       AsyncRequest req = new AsyncRequest (reqMsg, replySink);\r
+                       ThreadPool.QueueUserWorkItem (new WaitCallback (SendAsyncMessage), req);\r
+                       return null;\r
                }
                \r
+               public void SendAsyncMessage (object data)\r
+               {\r
+                       AsyncRequest req = (AsyncRequest)data;\r
+                       IMessage response = SyncProcessMessage (req.MsgRequest);\r
+                       req.ReplySink.SyncProcessMessage (response);\r
+               }\r
+               \r
                public IMessageSink NextSink { get { return null; } }\r
        }
 
@@ -280,6 +329,18 @@ namespace System.Runtime.Remoting.Channels
 \r
                        return serializer.Deserialize (mem);\r
                }
+       }\r
+       \r
+       internal class AsyncRequest\r
+       {\r
+               internal IMessageSink ReplySink;\r
+               internal IMessage MsgRequest;\r
+               \r
+               public AsyncRequest (IMessage msgRequest, IMessageSink replySink)\r
+               {\r
+                       ReplySink = replySink;\r
+                       MsgRequest = msgRequest;\r
+               }\r
        }
 
 }