2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Channels / CrossAppDomainChannel.cs
index fa19e647ae64b789fdbbd8aea1382b6da0029f32..836ce0f8c2af5358688dcfe3eae7f78b9fff120f 100755 (executable)
@@ -1,38 +1,72 @@
 //
-// System.Runtime.Remoting.Channels.CrossDomainChannel.cs
+// System.Runtime.Remoting.Channels.CrossAppDomainChannel.cs
 //
-// Author: Patrik Torstensson (totte_mono@yahoo.com)
+// Author: Patrik Torstensson (totte_mono@yahoo.com)\r
+//         Lluis Sanchez Gual (lluis@ximian.com)
 //
 // 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
 using System.Runtime.Remoting;\r
 using System.Runtime.Remoting.Messaging;   \r
 using System.Runtime.Remoting.Channels; \r
+using System.Runtime.Remoting.Contexts; \r
 using System.Runtime.Serialization;\r
 using System.Runtime.Serialization.Formatters.Binary;\r
+using System.Reflection;\r
 
 namespace System.Runtime.Remoting.Channels \r
 {
 
        // Holds the cross appdomain channel data (used to get/create the correct sink)
        [Serializable]
-       internal class CrossAppDomainChannelData \r
+       internal class CrossAppDomainData \r
        {
                // TODO: Add context support
-               private int _domainId;\r
+               private int _ContextID;\r
+               private int _DomainID;\r
+               private string _processGuid;\r
 \r
-               internal CrossAppDomainChannelData(int domainId) \r
+               internal CrossAppDomainData(int domainId) \r
                {\r
-                       _domainId = domainId;\r
+                       _DomainID = domainId;\r
+                       _processGuid = RemotingConfiguration.ProcessId;\r
                }\r
 \r
                internal int DomainID \r
                {  \r
-                       get { return _domainId; }\r
+                       get { return _DomainID; }\r
+               }\r
+\r
+               internal string ProcessID\r
+               {\r
+                       get { return _processGuid; }\r
                }\r
        }
 
@@ -75,7 +109,7 @@ namespace System.Runtime.Remoting.Channels
                // IChannelReceiver\r
                public virtual Object ChannelData \r
                {\r
-                       get { return new CrossAppDomainChannelData(Thread.GetDomainID()); }\r
+                       get { return new CrossAppDomainData(Thread.GetDomainID()); }\r
                }       \r
                \r
                public virtual String[] GetUrlsForUri(String objectURI) \r
@@ -91,36 +125,30 @@ 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
-                               CrossAppDomainChannelData cadData = data as CrossAppDomainChannelData;\r
-                               if (cadData != null\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
-\r
-                       return sink;\r
-               }\r
+                       if (url != null && url.StartsWith(_strName)) \r
+                               throw new NotSupportedException("Can't create a named channel via crossappdomain");\r
 \r
+                       return null;\r
+               }
        }
        \r
        [MonoTODO("Handle domain unloading?")]\r
        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
@@ -145,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
@@ -153,42 +208,44 @@ namespace System.Runtime.Remoting.Channels
 \r
                        try \r
                        {\r
-                               // Serialize the request message\r
-                               MemoryStream reqMsgStream = CADSerializer.SerializeMessage(msgRequest);\r
-\r
                                // Time to transit into the "our" domain\r
                                byte [] arrResponse = null;\r
-                               byte [] arrRequest = reqMsgStream.GetBuffer();\r
-                               
-                               // TODO: Enable again when we have support in the runtime
-                               //AppDomain currentDomain = AppDomain.EnterDomain ( _domainID );
-                               try 
-                               {
-                                       IMessage reqDomMsg = CADSerializer.DeserializeMessage (new MemoryStream(arrRequest), null);
-
-                                       IMessage retDomMsg = ChannelServices.SyncDispatchMessage (reqDomMsg);
-\r
-                                       arrResponse = CADSerializer.SerializeMessage (retDomMsg).GetBuffer();
-                               }
-                               catch (Exception e) 
-                               {
-                                       IMessage errorMsg = new ReturnMessage (e, new ErrorMessage());
-                                       arrResponse = CADSerializer.SerializeMessage (errorMsg).GetBuffer(); \r
-                               }   
-                               finally 
-                               {
-                                       // TODO: Enable again when we have support in the runtime
-                                       // AppDomain.EnterDomain (AppDomain.getIDFromDomain (currentDomain));
+                               byte [] arrRequest = null; \r
+                               \r
+                               CADMethodReturnMessage cadMrm = null;\r
+                               CADMethodCallMessage cadMsg;\r
+                               \r
+                               cadMsg = CADMethodCallMessage.Create (msgRequest);\r
+                               if (null == cadMsg) {\r
+                                       // Serialize the request message\r
+                                       MemoryStream reqMsgStream = CADSerializer.SerializeMessage(msgRequest);\r
+                                       arrRequest = reqMsgStream.GetBuffer();\r
                                }\r
 \r
-                               if (null != arrResponse) \r
-                               {\r
+                               object threadStatus = Thread.ResetDataStoreStatus ();\r
+                               Context currentContext = Thread.CurrentContext;
+
+                               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;
+                               }
+                               finally {
+                                       AppDomain.InternalSetContext (currentContext);
+                                       Thread.RestoreDataStoreStatus (threadStatus);
+                               }                                       
+
+                               \r
+                               if (null != arrResponse) {\r
                                        // Time to deserialize the message\r
                                        MemoryStream respMsgStream = new MemoryStream(arrResponse);\r
 \r
                                        // Deserialize the response message\r
                                        retMessage = CADSerializer.DeserializeMessage(respMsgStream, msgRequest as IMethodCallMessage);\r
-                               }\r
+                               } else\r
+                                       retMessage = new MethodResponse (msgRequest as IMethodCallMessage, cadMrm);\r
                        }\r
                        catch (Exception e) \r
                        {\r
@@ -202,14 +259,23 @@ namespace System.Runtime.Remoting.Channels
                                }\r
                        }\r
 \r
-                       return retMessage;\r
+               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
        }
 
@@ -222,20 +288,59 @@ namespace System.Runtime.Remoting.Channels
                        serializer.SurrogateSelector = null;\r
                        mem.Position = 0;\r
 \r
-                       return (IMessage) serializer.Deserialize(mem);\r
+                       if (msg == null)\r
+                               return (IMessage) serializer.Deserialize(mem, null);\r
+                       else\r
+                               return (IMessage) serializer.DeserializeMethodResponse(mem, null, msg);\r
                }\r
                \r
                internal static MemoryStream SerializeMessage(IMessage msg)\r
                {\r
-                       MemoryStream mem = new MemoryStream();\r
-                       BinaryFormatter serializer = new BinaryFormatter();                \r
+                       MemoryStream mem = new MemoryStream ();\r
+                       BinaryFormatter serializer = new BinaryFormatter ();                \r
+\r
+                       serializer.SurrogateSelector = new RemotingSurrogateSelector ();\r
+                       serializer.Serialize (mem, msg);\r
+\r
+                       mem.Position = 0;\r
+\r
+                       return mem;\r
+               }
+
+               internal static MemoryStream SerializeObject(object obj)\r
+               {\r
+                       MemoryStream mem = new MemoryStream ();\r
+                       BinaryFormatter serializer = new BinaryFormatter ();                \r
 \r
-                       serializer.SurrogateSelector = new RemotingSurrogateSelector();\r
-                       serializer.Serialize(mem, msg);\r
+                       serializer.SurrogateSelector = new RemotingSurrogateSelector ();\r
+                       serializer.Serialize (mem, obj);\r
 \r
                        mem.Position = 0;\r
 \r
                        return mem;\r
                }
+\r
+               internal static object DeserializeObject(MemoryStream mem)\r
+               {\r
+                       BinaryFormatter serializer = new BinaryFormatter();                \r
+\r
+                       serializer.SurrogateSelector = null;\r
+                       mem.Position = 0;\r
+\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
        }
+
 }