2 // System.Runtime.Remoting.Channels.CrossAppDomainChannel.cs
4 // Author: Patrik Torstensson (totte_mono@yahoo.com)
\r
5 // Lluis Sanchez Gual (lluis@ximian.com)
7 // 2003 (C) Copyright, Ximian, Inc.
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
35 using System.Threading;
\r
36 using System.Runtime.Remoting;
\r
37 using System.Runtime.Remoting.Messaging;
\r
38 using System.Runtime.Remoting.Channels;
\r
39 using System.Runtime.Remoting.Contexts;
\r
40 using System.Runtime.Serialization;
\r
41 using System.Runtime.Serialization.Formatters.Binary;
\r
42 using System.Reflection;
\r
44 namespace System.Runtime.Remoting.Channels
\r
47 // Holds the cross appdomain channel data (used to get/create the correct sink)
49 internal class CrossAppDomainData
\r
51 // TODO: Add context support
52 private int _ContextID;
\r
53 private int _DomainID;
\r
54 private string _processGuid;
\r
56 internal CrossAppDomainData(int domainId)
\r
58 _DomainID = domainId;
\r
59 _processGuid = RemotingConfiguration.ProcessId;
\r
62 internal int DomainID
\r
64 get { return _DomainID; }
\r
67 internal string ProcessID
\r
69 get { return _processGuid; }
\r
73 // Responsible for marshalling objects between appdomains
75 internal class CrossAppDomainChannel : IChannel, IChannelSender, IChannelReceiver
\r
77 private const String _strName = "MONOCAD";
78 private const String _strBaseURI = "MONOCADURI";
80 private static Object s_lock = new Object();
82 internal static void RegisterCrossAppDomainChannel()
\r
86 // todo: make singleton
\r
87 CrossAppDomainChannel monocad = new CrossAppDomainChannel();
\r
88 ChannelServices.RegisterChannel ((IChannel) monocad);
\r
92 // IChannel implementation
\r
93 public virtual String ChannelName
\r
95 get { return _strName; }
\r
98 public virtual int ChannelPriority
\r
100 get { return 100; }
\r
103 public String Parse(String url, out String objectURI)
\r
109 // IChannelReceiver
\r
110 public virtual Object ChannelData
\r
112 get { return new CrossAppDomainData(Thread.GetDomainID()); }
\r
115 public virtual String[] GetUrlsForUri(String objectURI)
\r
117 throw new NotSupportedException("CrossAppdomain channel dont support UrlsForUri");
\r
121 public virtual void StartListening(Object data) {}
\r
122 public virtual void StopListening(Object data) {}
\r
125 public virtual IMessageSink CreateMessageSink(String url, Object data, out String uri)
\r
128 IMessageSink sink = null;
\r
130 if (url == null && data != null)
\r
132 // Get the data and then get the sink
\r
133 CrossAppDomainData cadData = data as CrossAppDomainData;
\r
134 if (cadData != null && cadData.ProcessID == RemotingConfiguration.ProcessId)
\r
135 // GetSink creates a new sink if we don't have any (use contexts here later)
\r
136 sink = CrossAppDomainSink.GetSink(cadData.DomainID);
\r
140 if (url != null && data == null)
\r
142 if (url.StartsWith(_strName))
\r
144 throw new NotSupportedException("Can't create a named channel via crossappdomain");
\r
153 [MonoTODO("Handle domain unloading?")]
\r
154 internal class CrossAppDomainSink : IMessageSink
\r
156 private static Hashtable s_sinks = new Hashtable();
\r
158 private static MethodInfo processMessageMethod =
159 typeof (CrossAppDomainSink).GetMethod ("ProcessMessageInDomain", BindingFlags.NonPublic|BindingFlags.Static);
162 private int _domainID;
\r
164 internal CrossAppDomainSink(int domainID)
\r
166 _domainID = domainID;
\r
169 internal static CrossAppDomainSink GetSink(int domainID)
\r
171 // Check if we have a sink for the current domainID
\r
172 // note, locking is not to bad here, very few class to GetSink
\r
173 lock (s_sinks.SyncRoot)
\r
175 if (s_sinks.ContainsKey(domainID))
\r
176 return (CrossAppDomainSink) s_sinks[domainID];
\r
179 CrossAppDomainSink sink = new CrossAppDomainSink(domainID);
\r
180 s_sinks[domainID] = sink;
\r
187 private struct ProcessMessageRes {
188 public byte[] arrResponse;
189 public CADMethodReturnMessage cadMrm;
192 private static ProcessMessageRes ProcessMessageInDomain (
194 CADMethodCallMessage cadMsg)
196 ProcessMessageRes res = new ProcessMessageRes ();
200 AppDomain.CurrentDomain.ProcessMessageInDomain (arrRequest, cadMsg, out res.arrResponse, out res.cadMrm);
204 IMessage errorMsg = new MethodResponse (e, new ErrorMessage());
205 res.arrResponse = CADSerializer.SerializeMessage (errorMsg).GetBuffer();
\r
210 public virtual IMessage SyncProcessMessage(IMessage msgRequest)
\r
212 IMessage retMessage = null;
\r
216 // Time to transit into the "our" domain
\r
217 byte [] arrResponse = null;
\r
218 byte [] arrRequest = null;
\r
220 CADMethodReturnMessage cadMrm = null;
\r
221 CADMethodCallMessage cadMsg;
\r
223 cadMsg = CADMethodCallMessage.Create (msgRequest);
\r
224 if (null == cadMsg) {
\r
225 // Serialize the request message
\r
226 MemoryStream reqMsgStream = CADSerializer.SerializeMessage(msgRequest);
\r
227 arrRequest = reqMsgStream.GetBuffer();
\r
230 object threadStatus = Thread.ResetDataStoreStatus ();
\r
231 Context currentContext = Thread.CurrentContext;
234 // InternalInvoke can't handle out arguments, this is why
235 // we return the results in a structure
236 ProcessMessageRes res = (ProcessMessageRes)AppDomain.InvokeInDomainByID (_domainID, processMessageMethod, null, new object [] { arrRequest, cadMsg });
237 arrResponse = res.arrResponse;
241 AppDomain.InternalSetContext (currentContext);
242 Thread.RestoreDataStoreStatus (threadStatus);
246 if (null != arrResponse) {
\r
247 // Time to deserialize the message
\r
248 MemoryStream respMsgStream = new MemoryStream(arrResponse);
\r
250 // Deserialize the response message
\r
251 retMessage = CADSerializer.DeserializeMessage(respMsgStream, msgRequest as IMethodCallMessage);
\r
253 retMessage = new MethodResponse (msgRequest as IMethodCallMessage, cadMrm);
\r
255 catch (Exception e)
\r
259 retMessage = new ReturnMessage (e, msgRequest as IMethodCallMessage);
263 // this is just to be sure
\r
270 public virtual IMessageCtrl AsyncProcessMessage (IMessage reqMsg, IMessageSink replySink)
\r
272 AsyncRequest req = new AsyncRequest (reqMsg, replySink);
\r
273 ThreadPool.QueueUserWorkItem (new WaitCallback (SendAsyncMessage), req);
\r
277 public void SendAsyncMessage (object data)
\r
279 AsyncRequest req = (AsyncRequest)data;
\r
280 IMessage response = SyncProcessMessage (req.MsgRequest);
\r
281 req.ReplySink.SyncProcessMessage (response);
\r
284 public IMessageSink NextSink { get { return null; } }
\r
287 internal class CADSerializer
289 internal static IMessage DeserializeMessage(MemoryStream mem, IMethodCallMessage msg)
\r
291 BinaryFormatter serializer = new BinaryFormatter();
\r
293 serializer.SurrogateSelector = null;
\r
297 return (IMessage) serializer.Deserialize(mem, null);
\r
299 return (IMessage) serializer.DeserializeMethodResponse(mem, null, msg);
\r
302 internal static MemoryStream SerializeMessage(IMessage msg)
\r
304 MemoryStream mem = new MemoryStream ();
\r
305 BinaryFormatter serializer = new BinaryFormatter ();
\r
307 serializer.SurrogateSelector = new RemotingSurrogateSelector ();
\r
308 serializer.Serialize (mem, msg);
\r
315 internal static MemoryStream SerializeObject(object obj)
\r
317 MemoryStream mem = new MemoryStream ();
\r
318 BinaryFormatter serializer = new BinaryFormatter ();
\r
320 serializer.SurrogateSelector = new RemotingSurrogateSelector ();
\r
321 serializer.Serialize (mem, obj);
\r
328 internal static object DeserializeObject(MemoryStream mem)
\r
330 BinaryFormatter serializer = new BinaryFormatter();
\r
332 serializer.SurrogateSelector = null;
\r
335 return serializer.Deserialize (mem);
\r
339 internal class AsyncRequest
\r
341 internal IMessageSink ReplySink;
\r
342 internal IMessage MsgRequest;
\r
344 public AsyncRequest (IMessage msgRequest, IMessageSink replySink)
\r
346 ReplySink = replySink;
\r
347 MsgRequest = msgRequest;
\r