2010-05-27 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.Runtime.Remoting.Channels / CrossAppDomainChannel.cs
blob033977fb79c17b464cc33647a063830f5c65caca
1 //
2 // System.Runtime.Remoting.Channels.CrossAppDomainChannel.cs
3 //
4 // Author: Patrik Torstensson (totte_mono@yahoo.com)
5 // Lluis Sanchez Gual (lluis@ximian.com)
6 //
7 // 2003 (C) Copyright, Ximian, Inc.
8 //
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:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
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;
34 using System.IO;
35 using System.Threading;
36 using System.Runtime.Remoting;
37 using System.Runtime.Remoting.Messaging;
38 using System.Runtime.Remoting.Channels;
39 using System.Runtime.Remoting.Contexts;
40 using System.Runtime.Serialization;
41 using System.Runtime.Serialization.Formatters.Binary;
42 using System.Reflection;
44 namespace System.Runtime.Remoting.Channels
47 // Holds the cross appdomain channel data (used to get/create the correct sink)
48 [Serializable]
49 internal class CrossAppDomainData
51 // TODO: Add context support
52 // Required for .NET compatibility
53 #pragma warning disable 0414
54 private object _ContextID;
55 #pragma warning restore
56 private int _DomainID;
57 private string _processGuid;
59 internal CrossAppDomainData(int domainId)
61 _ContextID = (int) 0;
62 _DomainID = domainId;
63 _processGuid = RemotingConfiguration.ProcessId;
66 internal int DomainID
68 get { return _DomainID; }
71 internal string ProcessID
73 get { return _processGuid; }
77 // Responsible for marshalling objects between appdomains
78 [Serializable]
79 internal class CrossAppDomainChannel : IChannel, IChannelSender, IChannelReceiver
81 private const String _strName = "MONOCAD";
83 private static Object s_lock = new Object();
85 internal static void RegisterCrossAppDomainChannel()
87 lock (s_lock)
89 // todo: make singleton
90 CrossAppDomainChannel monocad = new CrossAppDomainChannel();
91 ChannelServices.RegisterChannel ((IChannel) monocad);
95 // IChannel implementation
96 public virtual String ChannelName
98 get { return _strName; }
101 public virtual int ChannelPriority
103 get { return 100; }
106 public String Parse(String url, out String objectURI)
108 objectURI = url;
109 return null;
112 // IChannelReceiver
113 public virtual Object ChannelData
115 get { return new CrossAppDomainData(Thread.GetDomainID()); }
118 public virtual String[] GetUrlsForUri(String objectURI)
120 throw new NotSupportedException("CrossAppdomain channel dont support UrlsForUri");
123 // Dummies
124 public virtual void StartListening(Object data) {}
125 public virtual void StopListening(Object data) {}
127 // IChannelSender
128 public virtual IMessageSink CreateMessageSink(String url, Object data, out String uri)
130 uri = null;
132 if (data != null)
134 // Get the data and then get the sink
135 CrossAppDomainData cadData = data as CrossAppDomainData;
136 if (cadData != null && cadData.ProcessID == RemotingConfiguration.ProcessId)
137 // GetSink creates a new sink if we don't have any (use contexts here later)
138 return CrossAppDomainSink.GetSink(cadData.DomainID);
140 if (url != null && url.StartsWith(_strName))
141 throw new NotSupportedException("Can't create a named channel via crossappdomain");
143 return null;
147 [MonoTODO("Handle domain unloading?")]
148 internal class CrossAppDomainSink : IMessageSink
150 private static Hashtable s_sinks = new Hashtable();
152 private static MethodInfo processMessageMethod =
153 typeof (CrossAppDomainSink).GetMethod ("ProcessMessageInDomain", BindingFlags.NonPublic|BindingFlags.Static);
156 private int _domainID;
158 internal CrossAppDomainSink(int domainID)
160 _domainID = domainID;
163 internal static CrossAppDomainSink GetSink(int domainID)
165 // Check if we have a sink for the current domainID
166 // note, locking is not to bad here, very few class to GetSink
167 lock (s_sinks.SyncRoot)
169 if (s_sinks.ContainsKey(domainID))
170 return (CrossAppDomainSink) s_sinks[domainID];
171 else
173 CrossAppDomainSink sink = new CrossAppDomainSink(domainID);
174 s_sinks[domainID] = sink;
176 return sink;
181 internal int TargetDomainId {
182 get { return _domainID; }
185 private struct ProcessMessageRes {
186 public byte[] arrResponse;
187 public CADMethodReturnMessage cadMrm;
190 #pragma warning disable 169
191 private static ProcessMessageRes ProcessMessageInDomain (
192 byte[] arrRequest,
193 CADMethodCallMessage cadMsg)
195 ProcessMessageRes res = new ProcessMessageRes ();
197 try
199 AppDomain.CurrentDomain.ProcessMessageInDomain (arrRequest, cadMsg, out res.arrResponse, out res.cadMrm);
201 catch (Exception e)
203 IMessage errorMsg = new MethodResponse (e, new ErrorMessage());
204 res.arrResponse = CADSerializer.SerializeMessage (errorMsg).GetBuffer();
206 return res;
208 #pragma warning restore 169
210 public virtual IMessage SyncProcessMessage(IMessage msgRequest)
212 IMessage retMessage = null;
214 try
216 // Time to transit into the "our" domain
217 byte [] arrResponse = null;
218 byte [] arrRequest = null;
220 CADMethodReturnMessage cadMrm = null;
221 CADMethodCallMessage cadMsg;
223 cadMsg = CADMethodCallMessage.Create (msgRequest);
224 if (null == cadMsg) {
225 // Serialize the request message
226 MemoryStream reqMsgStream = CADSerializer.SerializeMessage(msgRequest);
227 arrRequest = reqMsgStream.GetBuffer();
230 Context currentContext = Thread.CurrentContext;
232 try {
233 // InternalInvoke can't handle out arguments, this is why
234 // we return the results in a structure
235 ProcessMessageRes res = (ProcessMessageRes)AppDomain.InvokeInDomainByID (_domainID, processMessageMethod, null, new object [] { arrRequest, cadMsg });
236 arrResponse = res.arrResponse;
237 cadMrm = res.cadMrm;
238 } finally {
239 AppDomain.InternalSetContext (currentContext);
243 if (null != arrResponse) {
244 // Time to deserialize the message
245 MemoryStream respMsgStream = new MemoryStream(arrResponse);
247 // Deserialize the response message
248 retMessage = CADSerializer.DeserializeMessage(respMsgStream, msgRequest as IMethodCallMessage);
249 } else
250 retMessage = new MethodResponse (msgRequest as IMethodCallMessage, cadMrm);
252 catch (Exception e)
256 retMessage = new ReturnMessage (e, msgRequest as IMethodCallMessage);
258 catch (Exception)
260 // this is just to be sure
264 return retMessage;
267 public virtual IMessageCtrl AsyncProcessMessage (IMessage reqMsg, IMessageSink replySink)
269 AsyncRequest req = new AsyncRequest (reqMsg, replySink);
270 ThreadPool.QueueUserWorkItem (new WaitCallback (SendAsyncMessage), req);
271 return null;
274 public void SendAsyncMessage (object data)
276 AsyncRequest req = (AsyncRequest)data;
277 IMessage response = SyncProcessMessage (req.MsgRequest);
278 req.ReplySink.SyncProcessMessage (response);
281 public IMessageSink NextSink { get { return null; } }
284 internal class CADSerializer
286 internal static IMessage DeserializeMessage(MemoryStream mem, IMethodCallMessage msg)
288 BinaryFormatter serializer = new BinaryFormatter();
290 serializer.SurrogateSelector = null;
291 mem.Position = 0;
293 if (msg == null)
294 return (IMessage) serializer.Deserialize(mem, null);
295 else
296 return (IMessage) serializer.DeserializeMethodResponse(mem, null, msg);
299 internal static MemoryStream SerializeMessage(IMessage msg)
301 MemoryStream mem = new MemoryStream ();
302 BinaryFormatter serializer = new BinaryFormatter ();
304 serializer.SurrogateSelector = new RemotingSurrogateSelector ();
305 serializer.Serialize (mem, msg);
307 mem.Position = 0;
309 return mem;
312 internal static MemoryStream SerializeObject(object obj)
314 MemoryStream mem = new MemoryStream ();
315 BinaryFormatter serializer = new BinaryFormatter ();
317 serializer.SurrogateSelector = new RemotingSurrogateSelector ();
318 serializer.Serialize (mem, obj);
320 mem.Position = 0;
322 return mem;
325 internal static object DeserializeObject(MemoryStream mem)
327 BinaryFormatter serializer = new BinaryFormatter();
329 serializer.SurrogateSelector = null;
330 mem.Position = 0;
332 return serializer.Deserialize (mem);
336 internal class AsyncRequest
338 internal IMessageSink ReplySink;
339 internal IMessage MsgRequest;
341 public AsyncRequest (IMessage msgRequest, IMessageSink replySink)
343 ReplySink = replySink;
344 MsgRequest = msgRequest;