New test.
[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                 
78                 // Helper to marshal properties
79                 internal static int MarshalProperties (IDictionary dict, ref ArrayList args) {
80                         IDictionary serDict = dict;
81                         int count = 0;
82
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++;
93                                                 }
94                                         }
95                                 }
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++;
103                                         }
104                                 }
105                         }
106
107                         return count;
108                 }
109
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;
114                         }
115                 }
116
117                 // We can ignore marshalling for string and primitive types
118                 private static bool IsPossibleToIgnoreMarshal (object obj) {
119
120                         Type objType = obj.GetType();
121                         if (objType.IsPrimitive || objType == typeof(void))
122                                 return true;
123                         
124                         if (objType.IsArray && objType.GetElementType().IsPrimitive && ((Array)obj).Rank == 1)
125                                 return true;
126                                 
127                         if (obj is string || obj is DateTime || obj is TimeSpan)
128                                 return true;
129                                 
130                         return false;
131                 }
132
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;
138
139                         if (IsPossibleToIgnoreMarshal (arg))
140                                 return arg;
141
142                         MarshalByRefObject mbr = arg as MarshalByRefObject;
143                         if (null != mbr)
144                         {
145                                 if (RemotingServices.IsTransparentProxy(mbr)) {
146                                         // We don't deal with this case yet
147                                 }
148                                 else {
149                                         ObjRef objRef = RemotingServices.Marshal(mbr);
150                                         return new CADObjRef(objRef, System.Threading.Thread.GetDomainID());
151                                 }
152                         }
153
154                         if (null == args)
155                                 args = new ArrayList();
156                         
157                         args.Add (arg);
158                         
159                         // return position that the arg exists in the serialized list
160                         return new CADArgHolder(args.Count - 1);
161                 }
162
163                 protected object UnmarshalArgument (object arg, ArrayList args) {
164                         if (arg == null) return null;
165                         
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];
170                         }
171
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;
177                                 
178                                 ChannelInfo cinfo = new ChannelInfo (new CrossAppDomainData (domid));
179                                 ObjRef localRef = new ObjRef (typeName, uri, cinfo);
180                                 return RemotingServices.Unmarshal (localRef);
181                         }
182                         
183                         if (arg is Array)
184                         {
185                                 Array argb = (Array)arg;
186                                 Array argn;
187                                 
188                                 // We can't use Array.CreateInstance (arg.GetType().GetElementType()) because
189                                 // GetElementType() returns a type from the source domain.
190                                 
191                                 switch (Type.GetTypeCode (arg.GetType().GetElementType()))
192                                 {
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 ();
207                                 }
208                                 
209                                 argb.CopyTo (argn, 0);
210                                 return argn;
211                         }
212
213                         switch (Type.GetTypeCode (arg.GetType()))
214                         {
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;
234                         }       
235
236                         throw new NotSupportedException ("Parameter of type " + arg.GetType () + " cannot be unmarshalled");
237                 }
238
239                 internal object [] MarshalArguments (object [] arguments, ref ArrayList args) {
240                         object [] marshalledArgs = new object [arguments.Length];
241
242                         int total = arguments.Length;
243                         for (int i = 0; i < total; i++)
244                                 marshalledArgs [i] = MarshalArgument (arguments [i], ref args);
245
246                         return marshalledArgs;
247                 }
248
249                 internal object [] UnmarshalArguments (object [] arguments, ArrayList args) {
250                         object [] unmarshalledArgs = new object [arguments.Length];
251
252                         int total = arguments.Length;
253                         for (int i = 0; i < total; i++)
254                                 unmarshalledArgs [i] = UnmarshalArgument (arguments [i], args);
255
256                         return unmarshalledArgs;
257                 }
258                 
259                 protected void SaveLogicalCallContext (IMethodMessage msg, ref ArrayList serializeList)
260                 {
261                         if (msg.LogicalCallContext != null && msg.LogicalCallContext.HasInfo) 
262                         {
263                                 if (serializeList == null)
264                                         serializeList = new ArrayList();
265
266                                 _callContext = new CADArgHolder (serializeList.Count);
267                                 serializeList.Add (msg.LogicalCallContext);
268                         }
269                 }
270                 
271                 internal LogicalCallContext GetLogicalCallContext (ArrayList args) 
272                 {
273                         if (null == _callContext)
274                                 return null;
275
276                         return (LogicalCallContext) args [_callContext.index];
277                 }
278         }
279
280         // Used when passing a IMethodCallMessage between appdomains
281         internal class CADMethodCallMessage : CADMessageBase {
282                 string _uri;
283                 
284                 internal RuntimeMethodHandle MethodHandle;
285                 internal string FullTypeName;
286                 
287                 internal string Uri {
288                         get {
289                                 return _uri;
290                         }
291                 }
292
293                 static internal CADMethodCallMessage Create (IMessage callMsg) {
294                         IMethodCallMessage msg = callMsg as IMethodCallMessage;
295                         if (null == msg)
296                                 return null;
297
298                         return new CADMethodCallMessage (msg);
299                 }
300
301                 internal CADMethodCallMessage (IMethodCallMessage callMsg) {
302                         _uri = callMsg.Uri;
303                         MethodHandle = callMsg.MethodBase.MethodHandle;
304                         FullTypeName = callMsg.MethodBase.DeclaringType.AssemblyQualifiedName;
305
306                         ArrayList serializeList = null; 
307                         
308                         _propertyCount = MarshalProperties (callMsg.Properties, ref serializeList);
309
310                         _args = MarshalArguments ( callMsg.Args, ref serializeList);
311
312                         // Save callcontext
313                         SaveLogicalCallContext (callMsg, ref serializeList);
314                         
315                         // Serialize message data if needed
316
317                         if (null != serializeList) {
318                                 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
319                                 _serializedArgs = stm.GetBuffer();
320                         }
321                 }
322
323                 internal ArrayList GetArguments () {
324                         ArrayList ret = null;
325
326                         if (null != _serializedArgs) {
327                                 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
328                                 ret = new ArrayList (oret);
329                                 _serializedArgs = null;
330                         }
331
332                         return ret;
333                 }
334
335                 internal object [] GetArgs (ArrayList args) {
336                         return UnmarshalArguments (_args, args);
337                 }
338
339                 internal int PropertiesCount {
340                         get {
341                                 return _propertyCount;
342                         }
343                 }
344                 
345                 internal MethodBase GetMethod ()
346                 {
347                         MethodBase methodBase = MethodBase.GetMethodFromHandle (MethodHandle);
348                         Type tt = Type.GetType (FullTypeName);
349                         
350                         if (tt != methodBase.DeclaringType) {
351                                 // The target domain has loaded the type from a different assembly.
352                                 // We need to locate the correct type and get the method from it
353                                 ParameterInfo[] pars = methodBase.GetParameters ();
354                                 Type[] signature = new Type [pars.Length];
355                                 for (int n=0; n<pars.Length; n++) {
356                                         // The parameter types may also be loaded from a different assembly, so we need
357                                         // to load them again
358                                         signature [n] = Type.GetType (pars [n].ParameterType.AssemblyQualifiedName, true);
359                                 }
360                                 MethodBase mb = tt.GetMethod (methodBase.Name, BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Instance, null, signature, null);
361                                 if (mb == null)
362                                         throw new RemotingException ("Method '" + methodBase.Name + "' not found in type '" + tt + "'");
363                                 return mb;
364                         }
365                         return methodBase;
366                 }
367         }
368         
369         // Used when passing a IMethodReturnMessage between appdomains
370         internal class CADMethodReturnMessage : CADMessageBase {
371                 object _returnValue;
372                 CADArgHolder _exception = null;
373
374                 static internal CADMethodReturnMessage Create (IMessage callMsg) {
375                         IMethodReturnMessage msg = callMsg as IMethodReturnMessage;
376                         if (null == msg)
377                                 return null;
378
379                         return new CADMethodReturnMessage (msg);
380                 }
381
382                 internal CADMethodReturnMessage(IMethodReturnMessage retMsg) {
383                         ArrayList serializeList = null; 
384                         
385                         _propertyCount = MarshalProperties (retMsg.Properties, ref serializeList);
386
387                         _returnValue = MarshalArgument ( retMsg.ReturnValue, ref serializeList);
388                         _args = MarshalArguments ( retMsg.Args, ref serializeList);
389
390                         if (null != retMsg.Exception) {
391                                 if (null == serializeList)
392                                         serializeList = new ArrayList();
393                                 
394                                 _exception = new CADArgHolder (serializeList.Count);
395                                 serializeList.Add(retMsg.Exception);
396                         }
397
398                         // Save callcontext
399                         SaveLogicalCallContext (retMsg, ref serializeList);
400
401                         if (null != serializeList) {
402                                 MemoryStream stm = CADSerializer.SerializeObject (serializeList.ToArray());
403                                 _serializedArgs = stm.GetBuffer();
404                         }
405                 }
406
407                 internal ArrayList GetArguments () {
408                         ArrayList ret = null;
409
410                         if (null != _serializedArgs) {
411                                 object[] oret = (object[]) CADSerializer.DeserializeObject (new MemoryStream (_serializedArgs));
412                                 ret = new ArrayList (oret);
413                                 _serializedArgs = null;
414                         }
415
416                         return ret;
417                 }
418
419                 internal object [] GetArgs (ArrayList args) {
420                         return UnmarshalArguments (_args, args);
421                 }
422                         
423                 internal object GetReturnValue (ArrayList args) {
424                         return UnmarshalArgument (_returnValue, args);
425                 }
426
427                 internal Exception GetException(ArrayList args) {
428                         if (null == _exception)
429                                 return null;
430
431                         return (Exception) args [_exception.index]; 
432                 }
433
434                 internal int PropertiesCount {
435                         get {
436                                 return _propertyCount;
437                         }
438                 }
439         }
440 }