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