//
-// System.Runtime.Remoting.Channels.CrossDomainChannel.cs
+// System.Runtime.Remoting.Channels.CrossAppDomainChannel.cs
//
// Author: Patrik Torstensson (totte_mono@yahoo.com)
+// 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
+using System.IO;
+using System.Threading;
+using System.Runtime.Remoting;
+using System.Runtime.Remoting.Messaging;
+using System.Runtime.Remoting.Channels;
+using System.Runtime.Remoting.Contexts;
+using System.Runtime.Serialization;
+using System.Runtime.Serialization.Formatters.Binary;
+using System.Reflection;
+
+namespace System.Runtime.Remoting.Channels
{
// Holds the cross appdomain channel data (used to get/create the correct sink)
[Serializable]
- internal class CrossAppDomainData \r
+ internal class CrossAppDomainData
{
// TODO: Add context support
- private int _ContextID;\r
- private int _DomainID;\r
- private string _processGuid;\r
-\r
- internal CrossAppDomainData(int domainId) \r
- {\r
- _DomainID = domainId;\r
- _processGuid = RemotingConfiguration.ProcessId;\r
- }\r
-\r
- internal int DomainID \r
- { \r
- get { return _DomainID; }\r
- }\r
-\r
- internal string ProcessID\r
- {\r
- get { return _processGuid; }\r
- }\r
+ // Required for .NET compatibility
+#pragma warning disable 0414
+ private object _ContextID;
+#pragma warning restore
+ private int _DomainID;
+ private string _processGuid;
+
+ internal CrossAppDomainData(int domainId)
+ {
+ _ContextID = (int) 0;
+ _DomainID = domainId;
+ _processGuid = RemotingConfiguration.ProcessId;
+ }
+
+ internal int DomainID
+ {
+ get { return _DomainID; }
+ }
+
+ internal string ProcessID
+ {
+ get { return _processGuid; }
+ }
}
// Responsible for marshalling objects between appdomains
- [Serializable]\r
- internal class CrossAppDomainChannel : IChannel, IChannelSender, IChannelReceiver \r
+ [Serializable]
+ internal class CrossAppDomainChannel : IChannel, IChannelSender, IChannelReceiver
{
private const String _strName = "MONOCAD";
- private const String _strBaseURI = "MONOCADURI";
private static Object s_lock = new Object();
-\r
- internal static void RegisterCrossAppDomainChannel() \r
- {\r
- lock (s_lock) \r
- {\r
- // todo: make singleton\r
- CrossAppDomainChannel monocad = new CrossAppDomainChannel();\r
- ChannelServices.RegisterChannel ((IChannel) monocad);\r
- }\r
- } \r
-\r
- // IChannel implementation\r
- public virtual String ChannelName \r
- {\r
- get { return _strName; }\r
- }\r
- \r
- public virtual int ChannelPriority \r
- {\r
- get { return 100; }\r
- }\r
- \r
- public String Parse(String url, out String objectURI) \r
- {\r
- objectURI = url;\r
- return null;\r
- } \r
-\r
- // IChannelReceiver\r
- public virtual Object ChannelData \r
- {\r
- get { return new CrossAppDomainData(Thread.GetDomainID()); }\r
- } \r
- \r
- public virtual String[] GetUrlsForUri(String objectURI) \r
- {\r
- throw new NotSupportedException("CrossAppdomain channel dont support UrlsForUri");\r
- } \r
- \r
- // Dummies\r
- public virtual void StartListening(Object data) {}\r
- public virtual void StopListening(Object data) {} \r
-\r
- // IChannelSender\r
- 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
- {\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
- } \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
+
+ internal static void RegisterCrossAppDomainChannel()
+ {
+ lock (s_lock)
+ {
+ // todo: make singleton
+ CrossAppDomainChannel monocad = new CrossAppDomainChannel();
+ ChannelServices.RegisterChannel ((IChannel) monocad);
+ }
+ }
+
+ // IChannel implementation
+ public virtual String ChannelName
+ {
+ get { return _strName; }
+ }
+
+ public virtual int ChannelPriority
+ {
+ get { return 100; }
+ }
+
+ public String Parse(String url, out String objectURI)
+ {
+ objectURI = url;
+ return null;
+ }
+
+ // IChannelReceiver
+ public virtual Object ChannelData
+ {
+ get { return new CrossAppDomainData(Thread.GetDomainID()); }
+ }
+
+ public virtual String[] GetUrlsForUri(String objectURI)
+ {
+ throw new NotSupportedException("CrossAppdomain channel dont support UrlsForUri");
+ }
+
+ // Dummies
+ public virtual void StartListening(Object data) {}
+ public virtual void StopListening(Object data) {}
+
+ // IChannelSender
+ public virtual IMessageSink CreateMessageSink(String url, Object data, out String uri)
+ {
+ uri = null;
+
+ if (data != null)
+ {
+ // Get the data and then get the sink
+ CrossAppDomainData cadData = data as CrossAppDomainData;
+ if (cadData != null && cadData.ProcessID == RemotingConfiguration.ProcessId)
+ // GetSink creates a new sink if we don't have any (use contexts here later)
+ return CrossAppDomainSink.GetSink(cadData.DomainID);
+ }
+ if (url != null && url.StartsWith(_strName))
+ throw new NotSupportedException("Can't create a named channel via crossappdomain");
+
+ return null;
}
}
- \r
- [MonoTODO("Handle domain unloading?")]\r
- internal class CrossAppDomainSink : IMessageSink \r
- {\r
- private static Hashtable s_sinks = new Hashtable();\r
-\r
- private int _domainID;\r
-\r
- internal CrossAppDomainSink(int domainID) \r
- {\r
- _domainID = domainID;\r
- }\r
- \r
- internal static CrossAppDomainSink GetSink(int domainID) \r
- {\r
- // Check if we have a sink for the current domainID\r
- // note, locking is not to bad here, very few class to GetSink\r
- lock (s_sinks.SyncRoot) \r
- {\r
- if (s_sinks.ContainsKey(domainID)) \r
- return (CrossAppDomainSink) s_sinks[domainID];\r
- else \r
- {\r
- CrossAppDomainSink sink = new CrossAppDomainSink(domainID);\r
- s_sinks[domainID] = sink;\r
-\r
- return sink;\r
- }\r
- }\r
+
+ [MonoTODO("Handle domain unloading?")]
+ internal class CrossAppDomainSink : IMessageSink
+ {
+ private static Hashtable s_sinks = new Hashtable();
+
+ private static MethodInfo processMessageMethod =
+ typeof (CrossAppDomainSink).GetMethod ("ProcessMessageInDomain", BindingFlags.NonPublic|BindingFlags.Static);
+
+
+ private int _domainID;
+
+ internal CrossAppDomainSink(int domainID)
+ {
+ _domainID = domainID;
+ }
+
+ internal static CrossAppDomainSink GetSink(int domainID)
+ {
+ // Check if we have a sink for the current domainID
+ // note, locking is not to bad here, very few class to GetSink
+ lock (s_sinks.SyncRoot)
+ {
+ if (s_sinks.ContainsKey(domainID))
+ return (CrossAppDomainSink) s_sinks[domainID];
+ else
+ {
+ CrossAppDomainSink sink = new CrossAppDomainSink(domainID);
+ s_sinks[domainID] = sink;
+
+ return sink;
+ }
+ }
+ }
+
+ internal int TargetDomainId {
+ get { return _domainID; }
+ }
+
+ private struct ProcessMessageRes {
+ public byte[] arrResponse;
+ public CADMethodReturnMessage cadMrm;
}
-\r
- public virtual IMessage SyncProcessMessage(IMessage msgRequest) \r
- {\r
- IMessage retMessage = null;\r
-\r
- try \r
- {\r
- // Time to transit into the "our" domain\r
- byte [] arrResponse = null;\r
- 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
+
+#pragma warning disable 169
+ 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();
+ }
+ return res;
+ }
+#pragma warning restore 169
+
+ public virtual IMessage SyncProcessMessage(IMessage msgRequest)
+ {
+ IMessage retMessage = null;
+
+ try
+ {
+ // Time to transit into the "our" domain
+ byte [] arrResponse = null;
+ byte [] arrRequest = null;
+
+ CADMethodReturnMessage cadMrm = null;
+ CADMethodCallMessage cadMsg;
+
+ cadMsg = CADMethodCallMessage.Create (msgRequest);
+ if (null == cadMsg) {
+ // Serialize the request message
+ MemoryStream reqMsgStream = CADSerializer.SerializeMessage(msgRequest);
+ arrRequest = reqMsgStream.GetBuffer();
+ }
+
Context currentContext = Thread.CurrentContext;
- AppDomain currentDomain = AppDomain.InternalSetDomainByID ( _domainID );
- try
+ 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);
+ }
+
+
+ if (null != arrResponse) {
+ // Time to deserialize the message
+ MemoryStream respMsgStream = new MemoryStream(arrResponse);
+
+ // Deserialize the response message
+ retMessage = CADSerializer.DeserializeMessage(respMsgStream, msgRequest as IMethodCallMessage);
+ } else
+ retMessage = new MethodResponse (msgRequest as IMethodCallMessage, cadMrm);
+ }
+ catch (Exception e)
+ {
+ try
{
- AppDomain.CurrentDomain.ProcessMessageInDomain (arrRequest, cadMsg, out arrResponse, out cadMrm);
+ retMessage = new ReturnMessage (e, msgRequest as IMethodCallMessage);
}
- catch (Exception e)
- {
- IMessage errorMsg = new MethodResponse (e, new ErrorMessage());
- arrResponse = CADSerializer.SerializeMessage (errorMsg).GetBuffer(); \r
- }
- finally
+ catch (Exception)
{
- AppDomain.InternalSetDomain (currentDomain);
- AppDomain.InternalSetContext (currentContext);
- }\r
- \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
- } else\r
- retMessage = new MethodResponse (msgRequest as IMethodCallMessage, cadMrm);\r
- }\r
- catch (Exception e) \r
- {\r
- try\r
- {\r
- Console.WriteLine("Exception in base domain");
- retMessage = new ReturnMessage (e, msgRequest as IMethodCallMessage);
- }\r
- catch (Exception)\r
- {\r
- // this is just to be sure\r
- }\r
- }\r
-\r
- return retMessage;\r
+ // this is just to be sure
+ }
+ }
+
+ return retMessage;
}
- public virtual IMessageCtrl AsyncProcessMessage(IMessage reqMsg, IMessageSink replySink) \r
- {\r
- throw new NotSupportedException();\r
+ public virtual IMessageCtrl AsyncProcessMessage (IMessage reqMsg, IMessageSink replySink)
+ {
+ AsyncRequest req = new AsyncRequest (reqMsg, replySink);
+ ThreadPool.QueueUserWorkItem (new WaitCallback (SendAsyncMessage), req);
+ return null;
+ }
+
+ public void SendAsyncMessage (object data)
+ {
+ AsyncRequest req = (AsyncRequest)data;
+ IMessage response = SyncProcessMessage (req.MsgRequest);
+ req.ReplySink.SyncProcessMessage (response);
}
- \r
- public IMessageSink NextSink { get { return null; } }\r
+
+ public IMessageSink NextSink { get { return null; } }
}
internal class CADSerializer
{
- internal static IMessage DeserializeMessage(MemoryStream mem, IMethodCallMessage msg)\r
- {\r
- BinaryFormatter serializer = new BinaryFormatter(); \r
-\r
- serializer.SurrogateSelector = null;\r
- mem.Position = 0;\r
-\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
-\r
- serializer.SurrogateSelector = new RemotingSurrogateSelector ();\r
- serializer.Serialize (mem, msg);\r
-\r
- mem.Position = 0;\r
-\r
- return mem;\r
+ internal static IMessage DeserializeMessage(MemoryStream mem, IMethodCallMessage msg)
+ {
+ BinaryFormatter serializer = new BinaryFormatter();
+
+ serializer.SurrogateSelector = null;
+ mem.Position = 0;
+
+ if (msg == null)
+ return (IMessage) serializer.Deserialize(mem, null);
+ else
+ return (IMessage) serializer.DeserializeMethodResponse(mem, null, msg);
+ }
+
+ internal static MemoryStream SerializeMessage(IMessage msg)
+ {
+ MemoryStream mem = new MemoryStream ();
+ BinaryFormatter serializer = new BinaryFormatter ();
+
+ serializer.SurrogateSelector = new RemotingSurrogateSelector ();
+ serializer.Serialize (mem, msg);
+
+ mem.Position = 0;
+
+ return mem;
+ }
+
+ internal static MemoryStream SerializeObject(object obj)
+ {
+ MemoryStream mem = new MemoryStream ();
+ BinaryFormatter serializer = new BinaryFormatter ();
+
+ serializer.SurrogateSelector = new RemotingSurrogateSelector ();
+ serializer.Serialize (mem, obj);
+
+ mem.Position = 0;
+
+ return mem;
}
- 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, obj);\r
-\r
- mem.Position = 0;\r
-\r
- return mem;\r
+ internal static object DeserializeObject(MemoryStream mem)
+ {
+ BinaryFormatter serializer = new BinaryFormatter();
+
+ serializer.SurrogateSelector = null;
+ mem.Position = 0;
+
+ return serializer.Deserialize (mem);
}
-\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
+ }
+
+ internal class AsyncRequest
+ {
+ internal IMessageSink ReplySink;
+ internal IMessage MsgRequest;
+
+ public AsyncRequest (IMessage msgRequest, IMessageSink replySink)
+ {
+ ReplySink = replySink;
+ MsgRequest = msgRequest;
}
}