2 // System.Runtime.Remoting.Channels.CrossAppDomainChannel.cs
4 // Author: Patrik Torstensson (totte_mono@yahoo.com)
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
;
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)
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
)
63 _processGuid
= RemotingConfiguration
.ProcessId
;
68 get { return _DomainID; }
71 internal string ProcessID
73 get { return _processGuid; }
77 // Responsible for marshalling objects between appdomains
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()
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
106 public String
Parse(String url
, out String objectURI
)
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");
124 public virtual void StartListening(Object data
) {}
125 public virtual void StopListening(Object data
) {}
128 public virtual IMessageSink
CreateMessageSink(String url
, Object data
, out String uri
)
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");
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
];
173 CrossAppDomainSink sink
= new CrossAppDomainSink(domainID
);
174 s_sinks
[domainID
] = 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 (
193 CADMethodCallMessage cadMsg
)
195 ProcessMessageRes res
= new ProcessMessageRes ();
199 AppDomain
.CurrentDomain
.ProcessMessageInDomain (arrRequest
, cadMsg
, out res
.arrResponse
, out res
.cadMrm
);
203 IMessage errorMsg
= new MethodResponse (e
, new ErrorMessage());
204 res
.arrResponse
= CADSerializer
.SerializeMessage (errorMsg
).GetBuffer();
208 #pragma warning restore 169
210 public virtual IMessage
SyncProcessMessage(IMessage msgRequest
)
212 IMessage retMessage
= null;
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
;
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
;
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
);
250 retMessage
= new MethodResponse (msgRequest
as IMethodCallMessage
, cadMrm
);
256 retMessage
= new ReturnMessage (e
, msgRequest
as IMethodCallMessage
);
260 // this is just to be sure
267 public virtual IMessageCtrl
AsyncProcessMessage (IMessage reqMsg
, IMessageSink replySink
)
269 AsyncRequest req
= new AsyncRequest (reqMsg
, replySink
);
270 ThreadPool
.QueueUserWorkItem (new WaitCallback (SendAsyncMessage
), req
);
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;
294 return (IMessage
) serializer
.Deserialize(mem
, null);
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
);
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
);
325 internal static object DeserializeObject(MemoryStream mem
)
327 BinaryFormatter serializer
= new BinaryFormatter();
329 serializer
.SurrogateSelector
= null;
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
;