2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.Runtime.Remoting.Messaging / CADMessages.cs
blob83c3db550e7b6a8cf5ecd324104c4edd27460273
1 //
2 // System.Runtime.Remoting.Messaging.CADMessages.cs
3 //
4 // Author:
5 // Patrik Torstensson
6 //
7 // (C) Patrik Torstensson
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;
34 using System.Collections;
35 using System.IO;
36 using System.Reflection;
37 using System.Runtime.Serialization;
38 using System.Runtime.Remoting;
39 using System.Runtime.Remoting.Channels;
40 using System.Runtime.Remoting.Messaging;
41 using System.Runtime.Remoting.Proxies;
43 namespace System.Runtime.Remoting.Messaging {
45 internal class CADArgHolder {
46 public int index;
48 public CADArgHolder (int i) {
49 index = i;
53 internal class CADObjRef {
54 ObjRef objref;
55 public int SourceDomain;
57 public CADObjRef (ObjRef o, int sourceDomain) {
58 objref = o;
59 SourceDomain = sourceDomain;
62 public string TypeName {
63 get { return objref.TypeInfo.TypeName; }
66 public string URI {
67 get { return objref.URI; }
71 internal class CADMessageBase {
73 protected object [] _args;
74 protected byte [] _serializedArgs = null;
75 protected int _propertyCount = 0;
76 protected CADArgHolder _callContext;
78 // Helper to marshal properties
79 internal static int MarshalProperties (IDictionary dict, ref ArrayList args) {
80 IDictionary serDict = dict;
81 int count = 0;
83 MethodDictionary msgDict = dict as MethodDictionary;
84 if (null != msgDict) {
85 if (msgDict.HasInternalProperties) {
86 serDict = msgDict.InternalProperties;
87 if (null != serDict) {
88 foreach (DictionaryEntry e in serDict) {
89 if (null == args)
90 args = new ArrayList();
91 args.Add(e);
92 count++;
96 } else {
97 if (null != dict) {
98 foreach (DictionaryEntry e in serDict) {
99 if (null == args)
100 args = new ArrayList();
101 args.Add(e);
102 count++;
107 return count;
110 internal static void UnmarshalProperties (IDictionary dict, int count, ArrayList args) {
111 for (int i = 0; i < count; i++) {
112 DictionaryEntry e = (DictionaryEntry) args [i];
113 dict [e.Key] = e.Value;
117 // We can ignore marshalling for string and primitive types
118 private static bool IsPossibleToIgnoreMarshal (object obj) {
120 Type objType = obj.GetType();
121 if (objType.IsPrimitive || objType == typeof(void))
122 return true;
124 if (objType.IsArray && objType.GetElementType().IsPrimitive && ((Array)obj).Rank == 1)
125 return true;
127 if (obj is string || obj is DateTime || obj is TimeSpan)
128 return true;
130 return false;
133 // Checks an argument if it's possible to pass without marshalling and
134 // if not it will be added to arguments to be serialized
135 protected object MarshalArgument (object arg, ref ArrayList args) {
136 if (null == arg)
137 return null;
139 if (IsPossibleToIgnoreMarshal (arg))
140 return arg;
142 MarshalByRefObject mbr = arg as MarshalByRefObject;
143 if (null != mbr)
145 if (RemotingServices.IsTransparentProxy(mbr)) {
146 // We don't deal with this case yet
148 else {
149 ObjRef objRef = RemotingServices.Marshal(mbr);
150 return new CADObjRef(objRef, System.Threading.Thread.GetDomainID());
154 if (null == args)
155 args = new ArrayList();
157 args.Add (arg);
159 // return position that the arg exists in the serialized list
160 return new CADArgHolder(args.Count - 1);
163 protected object UnmarshalArgument (object arg, ArrayList args) {
164 if (arg == null) return null;
166 // Check if argument is an holder (then we know that it's a serialized argument)
167 CADArgHolder holder = arg as CADArgHolder;
168 if (null != holder) {
169 return args [holder.index];
172 CADObjRef objref = arg as CADObjRef;
173 if (null != objref) {
174 string typeName = string.Copy (objref.TypeName);
175 string uri = string.Copy (objref.URI);
176 int domid = objref.SourceDomain;
178 ChannelInfo cinfo = new ChannelInfo (new CrossAppDomainData (domid));
179 ObjRef localRef = new ObjRef (typeName, uri, cinfo);
180 return RemotingServices.Unmarshal (localRef);
183 if (arg is Array)
185 Array argb = (Array)arg;
186 Array argn;
188 // We can't use Array.CreateInstance (arg.GetType().GetElementType()) because
189 // GetElementType() returns a type from the source domain.
191 switch (Type.GetTypeCode (arg.GetType().GetElementType()))
193 case TypeCode.Boolean: argn = new bool [argb.Length]; break;
194 case TypeCode.Byte: argn = new Byte [argb.Length]; break;
195 case TypeCode.Char: argn = new Char [argb.Length]; break;
196 case TypeCode.Decimal: argn = new Decimal [argb.Length]; break;
197 case TypeCode.Double: argn = new Double [argb.Length]; break;
198 case TypeCode.Int16: argn = new Int16 [argb.Length]; break;
199 case TypeCode.Int32: argn = new Int32 [argb.Length]; break;
200 case TypeCode.Int64: argn = new Int64 [argb.Length]; break;
201 case TypeCode.SByte: argn = new SByte [argb.Length]; break;
202 case TypeCode.Single: argn = new Single [argb.Length]; break;
203 case TypeCode.UInt16: argn = new UInt16 [argb.Length]; break;
204 case TypeCode.UInt32: argn = new UInt32 [argb.Length]; break;
205 case TypeCode.UInt64: argn = new UInt64 [argb.Length]; break;
206 default: throw new NotSupportedException ();
209 argb.CopyTo (argn, 0);
210 return argn;
213 switch (Type.GetTypeCode (arg.GetType()))
215 case TypeCode.Boolean: return (bool)arg;
216 case TypeCode.Byte: return (byte)arg;
217 case TypeCode.Char: return (char)arg;
218 case TypeCode.Decimal: return (decimal)arg;
219 case TypeCode.Double: return (double)arg;
220 case TypeCode.Int16: return (Int16)arg;
221 case TypeCode.Int32: return (Int32)arg;
222 case TypeCode.Int64: return (Int64)arg;
223 case TypeCode.SByte: return (SByte)arg;
224 case TypeCode.Single: return (Single)arg;
225 case TypeCode.UInt16: return (UInt16)arg;
226 case TypeCode.UInt32: return (UInt32)arg;
227 case TypeCode.UInt64: return (UInt64)arg;
228 case TypeCode.String: return string.Copy ((string) arg);
229 case TypeCode.DateTime: return new DateTime (((DateTime)arg).Ticks);
230 default:
231 if (arg is TimeSpan) return new TimeSpan (((TimeSpan)arg).Ticks);
232 if (arg is IntPtr) return (IntPtr) arg;
233 break;
236 throw new NotSupportedException ("Parameter of type " + arg.GetType () + " cannot be unmarshalled");
239 internal object [] MarshalArguments (object [] arguments, ref ArrayList args) {
240 object [] marshalledArgs = new object [arguments.Length];
242 int total = arguments.Length;
243 for (int i = 0; i < total; i++)
244 marshalledArgs [i] = MarshalArgument (arguments [i], ref args);
246 return marshalledArgs;
249 internal object [] UnmarshalArguments (object [] arguments, ArrayList args) {
250 object [] unmarshalledArgs = new object [arguments.Length];
252 int total = arguments.Length;
253 for (int i = 0; i < total; i++)
254 unmarshalledArgs [i] = UnmarshalArgument (arguments [i], args);
256 return unmarshalledArgs;
259 protected void SaveLogicalCallContext (IMethodMessage msg, ref ArrayList serializeList)
261 if (msg.LogicalCallContext != null && msg.LogicalCallContext.HasInfo)
263 if (serializeList == null)
264 serializeList = new ArrayList();
266 _callContext = new CADArgHolder (serializeList.Count);
267 serializeList.Add (msg.LogicalCallContext);
271 internal LogicalCallContext GetLogicalCallContext (ArrayList args)
273 if (null == _callContext)
274 return null;
276 return (LogicalCallContext) args [_callContext.index];
280 // Used when passing a IMethodCallMessage between appdomains
281 internal class CADMethodCallMessage : CADMessageBase {
282 string _uri;
284 internal RuntimeMethodHandle MethodHandle;
285 internal string FullTypeName;
287 internal string Uri {
288 get {
289 return _uri;
293 static internal CADMethodCallMessage Create (IMessage callMsg) {
294 IMethodCallMessage msg = callMsg as IMethodCallMessage;
295 if (null == msg)
296 return null;
298 return new CADMethodCallMessage (msg);
301 internal CADMethodCallMessage (IMethodCallMessage callMsg) {
302 _uri = callMsg.Uri;
303 MethodHandle = callMsg.MethodBase.MethodHandle;
304 FullTypeName = callMsg.MethodBase.DeclaringType.AssemblyQualifiedName;
306 ArrayList serializeList = null;
308 _propertyCount = MarshalProperties (callMsg.Properties, ref serializeList);
310 _args = MarshalArguments ( callMsg.Args, ref serializeList);
312 // Save callcontext
313 SaveLogicalCallContext (callMsg, ref serializeList);
315 // Serialize message data if needed
317 if (null != serializeList) {
318 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
319 _serializedArgs = stm.GetBuffer();
323 internal ArrayList GetArguments () {
324 ArrayList ret = null;
326 if (null != _serializedArgs) {
327 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
328 ret = new ArrayList (oret);
329 _serializedArgs = null;
332 return ret;
335 internal object [] GetArgs (ArrayList args) {
336 return UnmarshalArguments (_args, args);
339 internal int PropertiesCount {
340 get {
341 return _propertyCount;
345 static Type [] GetSignature (MethodBase methodBase, bool load)
347 ParameterInfo[] pars = methodBase.GetParameters ();
348 Type[] signature = new Type [pars.Length];
349 for (int n=0; n<pars.Length; n++) {
350 // The parameter types may also be loaded from a different assembly, so we need
351 // to load them again
352 if (load)
353 signature [n] = Type.GetType (pars [n].ParameterType.AssemblyQualifiedName, true);
354 else
355 signature [n] = pars [n].ParameterType;
357 return signature;
360 internal MethodBase GetMethod ()
362 MethodBase methodBase = null;
363 Type tt = Type.GetType (FullTypeName, true);
364 if (tt.IsGenericType || tt.IsGenericTypeDefinition) {
365 methodBase = MethodBase.GetMethodFromHandleNoGenericCheck (MethodHandle);
366 } else {
367 methodBase = MethodBase.GetMethodFromHandle (MethodHandle);
370 if (tt != methodBase.DeclaringType) {
371 // The target domain has loaded the type from a different assembly.
372 // We need to locate the correct type and get the method from it
373 Type [] signature = GetSignature (methodBase, true);
374 if (methodBase.IsGenericMethod) {
375 MethodBase [] methods = tt.GetMethods (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
376 Type [] base_args = methodBase.GetGenericArguments ();
377 foreach (MethodBase method in methods) {
378 if (!method.IsGenericMethod || method.Name != methodBase.Name)
379 continue;
380 Type [] method_args = method.GetGenericArguments ();
381 if (base_args.Length != method_args.Length)
382 continue;
384 MethodInfo method_instance = ((MethodInfo) method).MakeGenericMethod (base_args);
385 Type [] base_sig = GetSignature (method_instance, false);
386 if (base_sig.Length != signature.Length) {
387 continue;
389 bool dont = false;
390 for (int i = base_sig.Length - 1; i >= 0; i--) {
391 if (base_sig [i] != signature [i]) {
392 dont = true;
393 break;
396 if (dont)
397 continue;
398 return method_instance;
400 return methodBase;
403 MethodBase mb = tt.GetMethod (methodBase.Name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance, null, signature, null);
404 if (mb == null)
405 throw new RemotingException ("Method '" + methodBase.Name + "' not found in type '" + tt + "'");
406 return mb;
408 return methodBase;
412 // Used when passing a IMethodReturnMessage between appdomains
413 internal class CADMethodReturnMessage : CADMessageBase {
414 object _returnValue;
415 CADArgHolder _exception = null;
417 static internal CADMethodReturnMessage Create (IMessage callMsg) {
418 IMethodReturnMessage msg = callMsg as IMethodReturnMessage;
419 if (null == msg)
420 return null;
422 return new CADMethodReturnMessage (msg);
425 internal CADMethodReturnMessage(IMethodReturnMessage retMsg) {
426 ArrayList serializeList = null;
428 _propertyCount = MarshalProperties (retMsg.Properties, ref serializeList);
430 _returnValue = MarshalArgument ( retMsg.ReturnValue, ref serializeList);
431 _args = MarshalArguments ( retMsg.Args, ref serializeList);
433 if (null != retMsg.Exception) {
434 if (null == serializeList)
435 serializeList = new ArrayList();
437 _exception = new CADArgHolder (serializeList.Count);
438 serializeList.Add(retMsg.Exception);
441 // Save callcontext
442 SaveLogicalCallContext (retMsg, ref serializeList);
444 if (null != serializeList) {
445 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
446 _serializedArgs = stm.GetBuffer();
450 internal ArrayList GetArguments () {
451 ArrayList ret = null;
453 if (null != _serializedArgs) {
454 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
455 ret = new ArrayList (oret);
456 _serializedArgs = null;
459 return ret;
462 internal object [] GetArgs (ArrayList args) {
463 return UnmarshalArguments (_args, args);
466 internal object GetReturnValue (ArrayList args) {
467 return UnmarshalArgument (_returnValue, args);
470 internal Exception GetException(ArrayList args) {
471 if (null == _exception)
472 return null;
474 return (Exception) args [_exception.index];
477 internal int PropertiesCount {
478 get {
479 return _propertyCount;