Remove the mono-profiler- prefix from all source files in the profiler subdir.
[mono.git] / mcs / class / corlib / System.Runtime.Remoting.Messaging / CADMessages.cs
1 //
2 // System.Runtime.Remoting.Messaging.CADMessages.cs
3 //
4 // Author:
5 //   Patrik Torstensson
6 //
7 // (C) Patrik Torstensson
8 //
9
10 //
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
12 //
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.
31 //
32
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;
42
43 namespace System.Runtime.Remoting.Messaging {
44
45         internal class CADArgHolder {
46                 public int index;
47
48                 public CADArgHolder (int i) {
49                         index = i;
50                 }
51         }
52         
53         internal class CADObjRef {
54                 internal ObjRef objref;
55                 internal int SourceDomain;
56                 internal byte[] TypeInfo;
57
58                 public CADObjRef (ObjRef o, int sourceDomain) {
59                         objref = o;
60                         TypeInfo = o.SerializeType ();
61                         SourceDomain = sourceDomain;
62                 }
63
64                 public string TypeName {
65                         get { return objref.TypeInfo.TypeName; }
66                 }
67                 
68                 public string URI {
69                         get { return objref.URI; }
70                 }
71         }
72
73         [Serializable]
74         internal class CADMethodRef
75         {
76                 internal string FullTypeName;
77                 internal IntPtr MethodHandlePtr;
78
79                 public RuntimeMethodHandle MethodHandle {
80                         get {
81                                 return new RuntimeMethodHandle (MethodHandlePtr);
82                         }
83                 }
84
85                 public CADMethodRef (IMethodMessage msg)
86                 {
87                         MethodHandlePtr = msg.MethodBase.MethodHandle.Value;
88                         FullTypeName = msg.MethodBase.DeclaringType.AssemblyQualifiedName;
89                 }
90         }
91
92         internal class CADMessageBase {
93
94                 protected object [] _args;
95                 protected byte [] _serializedArgs = null;
96                 protected int _propertyCount = 0;
97                 protected CADArgHolder _callContext;
98                 internal byte[] serializedMethod;
99
100                 public CADMessageBase (IMethodMessage msg) {
101                         CADMethodRef methodRef = new CADMethodRef (msg);
102                         serializedMethod = CADSerializer.SerializeObject (methodRef).GetBuffer ();
103                 }
104
105                 internal MethodBase method {
106                         get { return GetMethod (); }
107                 }
108
109                 internal MethodBase GetMethod ()
110                 {
111                         CADMethodRef methRef = (CADMethodRef)CADSerializer.DeserializeObjectSafe (serializedMethod);
112
113                         MethodBase _method;
114
115                         Type tt = Type.GetType (methRef.FullTypeName, true);
116                         if (tt.IsGenericType || tt.IsGenericTypeDefinition) {
117                                 _method = MethodBase.GetMethodFromHandleNoGenericCheck (methRef.MethodHandle);
118                         } else {
119                                 _method = MethodBase.GetMethodFromHandle (methRef.MethodHandle);
120                         }
121
122                         if (tt != _method.DeclaringType) {
123                                 // The target domain has loaded the type from a different assembly.
124                                 // We need to locate the correct type and get the method from it
125                                 Type [] signature = GetSignature (_method, true);
126                                 if (_method.IsGenericMethod) {
127                                         MethodBase [] methods = tt.GetMethods (BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance);
128                                         Type [] base_args = _method.GetGenericArguments ();
129                                         foreach (MethodBase method in methods) {
130                                                 if (!method.IsGenericMethod || method.Name != _method.Name)
131                                                         continue;
132                                                 Type [] method_args = method.GetGenericArguments ();
133                                                 if (base_args.Length != method_args.Length)
134                                                         continue;
135
136                                                 MethodInfo method_instance = ((MethodInfo) method).MakeGenericMethod (base_args);
137                                                 Type [] base_sig = GetSignature (method_instance, false);
138                                                 if (base_sig.Length != signature.Length) {
139                                                         continue;
140                                                 }
141                                                 bool dont = false;
142                                                 for (int i = base_sig.Length - 1; i >= 0; i--) {
143                                                         if (base_sig [i] != signature [i]) {
144                                                                 dont = true;
145                                                                 break;
146                                                         }
147                                                 }
148                                                 if (dont)
149                                                         continue;
150                                                 return method_instance;
151                                         }
152                                         return _method;
153                                 }
154
155                                 MethodBase mb = tt.GetMethod (_method.Name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance, null, signature, null);
156                                 if (mb == null)
157                                         throw new RemotingException ("Method '" + _method.Name + "' not found in type '" + tt + "'");
158                                 return mb;
159                         }
160                         return _method;
161                 }
162
163                 static protected Type [] GetSignature (MethodBase methodBase, bool load)
164                 {
165                         ParameterInfo[] pars = methodBase.GetParameters ();
166                         Type[] signature = new Type [pars.Length];
167                         for (int n=0; n<pars.Length; n++) {
168                                 // The parameter types may also be loaded from a different assembly, so we need
169                                 // to load them again
170                                 if (load)
171                                         signature [n] = Type.GetType (pars [n].ParameterType.AssemblyQualifiedName, true);
172                                 else
173                                         signature [n] = pars [n].ParameterType;
174                         }
175                         return signature;
176                 }
177                 // Helper to marshal properties
178                 internal static int MarshalProperties (IDictionary dict, ref ArrayList args) {
179                         IDictionary serDict = dict;
180                         int count = 0;
181
182                         MessageDictionary msgDict = dict as MessageDictionary;
183                         if (null != msgDict) {
184                                 if (msgDict.HasUserData ()) {
185                                         serDict = msgDict.InternalDictionary;
186                                         if (null != serDict) {
187                                                 foreach (DictionaryEntry e in serDict) {
188                                                         if (null == args)
189                                                                 args = new ArrayList();
190                                                         args.Add(e);
191                                                         count++;
192                                                 }
193                                         }
194                                 }
195                         } else {
196                                 if (null != dict) {
197                                         foreach (DictionaryEntry e in serDict) {
198                                                 if (null == args)
199                                                         args = new ArrayList();
200                                                 args.Add(e);
201                                                 count++;
202                                         }
203                                 }
204                         }
205
206                         return count;
207                 }
208
209                 internal static void UnmarshalProperties (IDictionary dict, int count, ArrayList args) {
210                         for (int i = 0; i < count; i++) {
211                                 DictionaryEntry e = (DictionaryEntry) args [i];
212                                 dict [e.Key] = e.Value;
213                         }
214                 }
215
216                 // We can ignore marshalling for string and primitive types
217                 private static bool IsPossibleToIgnoreMarshal (object obj) {
218
219                         Type objType = obj.GetType();
220                         if (objType.IsPrimitive || objType == typeof(void))
221                                 return true;
222                         
223                         if (objType.IsArray && objType.GetElementType().IsPrimitive && ((Array)obj).Rank == 1)
224                                 return true;
225                                 
226                         if (obj is string || obj is DateTime || obj is TimeSpan)
227                                 return true;
228                                 
229                         return false;
230                 }
231
232                 // Checks an argument if it's possible to pass without marshalling and
233                 // if not it will be added to arguments to be serialized
234                 protected object MarshalArgument (object arg, ref ArrayList args) {
235                         if (null == arg)
236                                 return null;
237
238                         if (IsPossibleToIgnoreMarshal (arg))
239                                 return arg;
240
241                         MarshalByRefObject mbr = arg as MarshalByRefObject;
242                         if (null != mbr)
243                         {
244                                 if (RemotingServices.IsTransparentProxy(mbr)) {
245                                         // We don't deal with this case yet
246                                 }
247                                 else {
248                                         ObjRef objRef = RemotingServices.Marshal(mbr);
249                                         return new CADObjRef(objRef, System.Threading.Thread.GetDomainID());
250                                 }
251                         }
252
253                         if (null == args)
254                                 args = new ArrayList();
255                         
256                         args.Add (arg);
257                         
258                         // return position that the arg exists in the serialized list
259                         return new CADArgHolder(args.Count - 1);
260                 }
261
262                 protected object UnmarshalArgument (object arg, ArrayList args) {
263                         if (arg == null) return null;
264                         
265                         // Check if argument is an holder (then we know that it's a serialized argument)
266                         CADArgHolder holder = arg as CADArgHolder;
267                         if (null != holder) {
268                                 return args [holder.index];
269                         }
270
271                         CADObjRef objref = arg as CADObjRef;
272                         if (null != objref) {
273                                 ObjRef localRef = objref.objref.DeserializeInTheCurrentDomain (objref.SourceDomain, objref.TypeInfo);
274                                 return RemotingServices.Unmarshal (localRef);
275                         }
276                         
277                         if (arg is Array)
278                         {
279                                 Array argb = (Array)arg;
280                                 Array argn;
281                                 
282                                 // We can't use Array.CreateInstance (arg.GetType().GetElementType()) because
283                                 // GetElementType() returns a type from the source domain.
284                                 
285                                 switch (Type.GetTypeCode (arg.GetType().GetElementType()))
286                                 {
287                                         case TypeCode.Boolean: argn = new bool [argb.Length]; break;
288                                         case TypeCode.Byte: argn = new Byte [argb.Length]; break;
289                                         case TypeCode.Char: argn = new Char [argb.Length]; break;
290                                         case TypeCode.Decimal: argn = new Decimal [argb.Length]; break;
291                                         case TypeCode.Double: argn = new Double [argb.Length]; break;
292                                         case TypeCode.Int16: argn = new Int16 [argb.Length]; break;
293                                         case TypeCode.Int32: argn = new Int32 [argb.Length]; break;
294                                         case TypeCode.Int64: argn = new Int64 [argb.Length]; break;
295                                         case TypeCode.SByte: argn = new SByte [argb.Length]; break;
296                                         case TypeCode.Single: argn = new Single [argb.Length]; break;
297                                         case TypeCode.UInt16: argn = new UInt16 [argb.Length]; break;
298                                         case TypeCode.UInt32: argn = new UInt32 [argb.Length]; break;
299                                         case TypeCode.UInt64: argn = new UInt64 [argb.Length]; break;
300                                         default: throw new NotSupportedException ();
301                                 }
302                                 
303                                 argb.CopyTo (argn, 0);
304                                 return argn;
305                         }
306
307                         switch (Type.GetTypeCode (arg.GetType()))
308                         {
309                                 case TypeCode.Boolean: return (bool)arg;
310                                 case TypeCode.Byte: return (byte)arg;
311                                 case TypeCode.Char: return (char)arg;
312                                 case TypeCode.Decimal: return (decimal)arg;
313                                 case TypeCode.Double: return (double)arg;
314                                 case TypeCode.Int16: return (Int16)arg;
315                                 case TypeCode.Int32: return (Int32)arg;
316                                 case TypeCode.Int64: return (Int64)arg;
317                                 case TypeCode.SByte: return (SByte)arg;
318                                 case TypeCode.Single: return (Single)arg;
319                                 case TypeCode.UInt16: return (UInt16)arg;
320                                 case TypeCode.UInt32: return (UInt32)arg;
321                                 case TypeCode.UInt64: return (UInt64)arg;
322                                 case TypeCode.String: return string.Copy ((string) arg);
323                                 case TypeCode.DateTime: return new DateTime (((DateTime)arg).Ticks);
324                                 default:
325                                         if (arg is TimeSpan) return new TimeSpan (((TimeSpan)arg).Ticks);
326                                         if (arg is IntPtr) return (IntPtr) arg;
327                                         break;
328                         }       
329
330                         throw new NotSupportedException ("Parameter of type " + arg.GetType () + " cannot be unmarshalled");
331                 }
332
333                 internal object [] MarshalArguments (object [] arguments, ref ArrayList args) {
334                         object [] marshalledArgs = new object [arguments.Length];
335
336                         int total = arguments.Length;
337                         for (int i = 0; i < total; i++)
338                                 marshalledArgs [i] = MarshalArgument (arguments [i], ref args);
339
340                         return marshalledArgs;
341                 }
342
343                 internal object [] UnmarshalArguments (object [] arguments, ArrayList args) {
344                         object [] unmarshalledArgs = new object [arguments.Length];
345
346                         int total = arguments.Length;
347                         for (int i = 0; i < total; i++)
348                                 unmarshalledArgs [i] = UnmarshalArgument (arguments [i], args);
349
350                         return unmarshalledArgs;
351                 }
352
353                 protected void SaveLogicalCallContext (IMethodMessage msg, ref ArrayList serializeList)
354                 {
355                         if (msg.LogicalCallContext != null && msg.LogicalCallContext.HasInfo) 
356                         {
357                                 if (serializeList == null)
358                                         serializeList = new ArrayList();
359
360                                 _callContext = new CADArgHolder (serializeList.Count);
361                                 serializeList.Add (msg.LogicalCallContext);
362                         }
363                 }
364                 
365                 internal LogicalCallContext GetLogicalCallContext (ArrayList args) 
366                 {
367                         if (null == _callContext)
368                                 return null;
369
370                         return (LogicalCallContext) args [_callContext.index];
371                 }
372         }
373
374         // Used when passing a IMethodCallMessage between appdomains
375         internal class CADMethodCallMessage : CADMessageBase {
376                 string _uri;
377
378                 internal string Uri {
379                         get {
380                                 return _uri;
381                         }
382                 }
383
384                 static internal CADMethodCallMessage Create (IMessage callMsg) {
385                         IMethodCallMessage msg = callMsg as IMethodCallMessage;
386                         if (null == msg)
387                                 return null;
388
389                         return new CADMethodCallMessage (msg);
390                 }
391
392                 internal CADMethodCallMessage (IMethodCallMessage callMsg): base (callMsg) {
393                         _uri = callMsg.Uri;
394
395                         ArrayList serializeList = null; 
396                         
397                         _propertyCount = MarshalProperties (callMsg.Properties, ref serializeList);
398
399                         _args = MarshalArguments ( callMsg.Args, ref serializeList);
400
401                         // Save callcontext
402                         SaveLogicalCallContext (callMsg, ref serializeList);
403                         
404                         // Serialize message data if needed
405
406                         if (null != serializeList) {
407                                 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
408                                 _serializedArgs = stm.GetBuffer();
409                         }
410                 }
411
412                 internal ArrayList GetArguments () {
413                         ArrayList ret = null;
414
415                         if (null != _serializedArgs) {
416                                 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
417                                 ret = new ArrayList (oret);
418                                 _serializedArgs = null;
419                         }
420
421                         return ret;
422                 }
423
424                 internal object [] GetArgs (ArrayList args) {
425                         return UnmarshalArguments (_args, args);
426                 }
427
428                 internal int PropertiesCount {
429                         get {
430                                 return _propertyCount;
431                         }
432                 }
433                 
434         }
435         
436         // Used when passing a IMethodReturnMessage between appdomains
437         internal class CADMethodReturnMessage : CADMessageBase {
438                 object _returnValue;
439                 CADArgHolder _exception = null;
440 #pragma warning disable 414
441                 Type [] _sig;
442 #pragma warning restore
443
444                 static internal CADMethodReturnMessage Create (IMessage callMsg) {
445                         IMethodReturnMessage msg = callMsg as IMethodReturnMessage;
446                         if (null == msg)
447                                 return null;
448
449                         return new CADMethodReturnMessage (msg);
450                 }
451
452                 internal CADMethodReturnMessage(IMethodReturnMessage retMsg): base (retMsg) {
453                         ArrayList serializeList = null; 
454                         
455                         _propertyCount = MarshalProperties (retMsg.Properties, ref serializeList);
456
457                         _returnValue = MarshalArgument ( retMsg.ReturnValue, ref serializeList);
458                         _args = MarshalArguments ( retMsg.Args, ref serializeList);
459
460                         _sig = GetSignature (method, true);
461
462                         if (null != retMsg.Exception) {
463                                 if (null == serializeList)
464                                         serializeList = new ArrayList();
465                                 
466                                 _exception = new CADArgHolder (serializeList.Count);
467                                 serializeList.Add(retMsg.Exception);
468                         }
469
470                         // Save callcontext
471                         SaveLogicalCallContext (retMsg, ref serializeList);
472
473                         if (null != serializeList) {
474                                 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
475                                 _serializedArgs = stm.GetBuffer();
476                         }
477                 }
478
479                 internal ArrayList GetArguments () {
480                         ArrayList ret = null;
481
482                         if (null != _serializedArgs) {
483                                 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
484                                 ret = new ArrayList (oret);
485                                 _serializedArgs = null;
486                         }
487
488                         return ret;
489                 }
490
491                 internal object [] GetArgs (ArrayList args) {
492                         return UnmarshalArguments (_args, args);
493                 }
494
495                 internal object GetReturnValue (ArrayList args) {
496                         return UnmarshalArgument (_returnValue, args);
497                 }
498
499                 internal Exception GetException(ArrayList args) {
500                         if (null == _exception)
501                                 return null;
502
503                         return (Exception) args [_exception.index]; 
504                 }
505
506                 internal int PropertiesCount {
507                         get {
508                                 return _propertyCount;
509                         }
510                 }
511         }
512 }