1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 //==========================================================================
7 //  File:       MessageSmuggler.cs
8 //
9 //  Summary:    Implements objects necessary to smuggle messages across
10 //              AppDomains and determine when it's possible.
11 //
12 //==========================================================================
13 
14 using System;
15 using System.Collections;
16 using System.IO;
17 using System.Runtime.Remoting;
18 using System.Runtime.Remoting.Channels;
19 using System.Runtime.Remoting.Messaging;
20 using System.Runtime.Remoting.Proxies;
21 
22 
23 namespace System.Runtime.Remoting.Messaging
24 {
25 
26     internal class MessageSmuggler
27     {
CanSmuggleObjectDirectly(Object obj)28         private static bool CanSmuggleObjectDirectly(Object obj)
29         {
30             if ((obj is String) ||
31                 (obj.GetType() == typeof(void)) ||
32                 obj.GetType().IsPrimitive)
33             {
34                 return true;
35             }
36 
37             return false;
38         } // CanSmuggleObjectDirectly
39 
40 
41         [System.Security.SecurityCritical]  // auto-generated
FixupArgs(Object[] args, ref ArrayList argsToSerialize)42         protected static Object[] FixupArgs(Object[] args, ref ArrayList argsToSerialize)
43         {
44             Object[] newArgs = new Object[args.Length];
45 
46             int total = args.Length;
47             for (int co = 0; co < total; co++)
48             {
49                 newArgs[co] = FixupArg(args[co], ref argsToSerialize);
50             }
51 
52             return newArgs;
53         } // FixupArgs
54 
55 
56         [System.Security.SecurityCritical]  // auto-generated
FixupArg(Object arg, ref ArrayList argsToSerialize)57         protected static Object FixupArg(Object arg, ref ArrayList argsToSerialize)
58         {
59             // This method examines an argument and sees if it can be smuggled in some form.
60             //   If it can directly be smuggled (i.e. it is a primitive or string), we
61             //   just return the same object. If it's a marshal by ref object, we
62             //   see if we can smuggle the obj ref. If it's a primitive or string array,
63             //   we can smuggle a cloned copy of the array. In all other cases,
64             //   we add it to the list of args we want serialized, and return a
65             //   placeholder element (SerializedArg).
66 
67             if (arg == null)
68                 return null;
69 
70             int index;
71 
72             // IMPORTANT!!! This should be done first because CanSmuggleObjectDirectly
73             //   calls GetType() and that would slow this down.
74             MarshalByRefObject mbo = arg as MarshalByRefObject;
75             if (mbo != null)
76             {
77                 // We can only try to smuggle objref's for actual CLR objects
78                 //   or for RemotingProxy's.
79                 if (!RemotingServices.IsTransparentProxy(mbo) ||
80                     RemotingServices.GetRealProxy(mbo) is RemotingProxy)
81                 {
82                     ObjRef objRef = RemotingServices.MarshalInternal(mbo, null, null);
83                     if (objRef.CanSmuggle())
84                     {
85                         if (!RemotingServices.IsTransparentProxy(mbo))
86                         {
87                             ServerIdentity srvId = (ServerIdentity)MarshalByRefObject.GetIdentity(mbo);
88                             srvId.SetHandle();
89                             objRef.SetServerIdentity(srvId.GetHandle());
90                             objRef.SetDomainID(AppDomain.CurrentDomain.GetId());
91                         }
92                         ObjRef smugObjRef = objRef.CreateSmuggleableCopy();
93                         smugObjRef.SetMarshaledObject();
94                         return new SmuggledObjRef(smugObjRef);
95                     }
96                 }
97 
98                 // Add this arg to list of one's to serialize and return a placeholder
99                 //   since we couldn't smuggle the objref.
100                 if (argsToSerialize == null)
101                     argsToSerialize = new ArrayList();
102                 index = argsToSerialize.Count;
103                 argsToSerialize.Add(arg);
104                 return new SerializedArg(index);
105             }
106 
107             if (CanSmuggleObjectDirectly(arg))
108                 return arg;
109 
110             // if this is a primitive array, we can just make a copy.
111             //   (IMPORTANT: We can directly use this copy from the
112             //    other app domain, there is no reason to make another
113             //    copy once we are on the other side)
114             Array array = arg as Array;
115             if (array != null)
116             {
117                 Type elementType = array.GetType().GetElementType();
118                 if (elementType.IsPrimitive || (elementType == typeof(String)))
119                     return array.Clone();
120             }
121 
122 
123             // Add this arg to list of one's to serialize and return a placeholder.
124             if (argsToSerialize == null)
125                 argsToSerialize = new ArrayList();
126             index = argsToSerialize.Count;
127             argsToSerialize.Add(arg);
128             return new SerializedArg(index);
129         } // FixupArg
130 
131 
132         [System.Security.SecurityCritical]  // auto-generated
UndoFixupArgs(Object[] args, ArrayList deserializedArgs)133         protected static Object[] UndoFixupArgs(Object[] args, ArrayList deserializedArgs)
134         {
135             Object[] newArgs = new Object[args.Length];
136             int total = args.Length;
137             for (int co = 0; co < total; co++)
138             {
139                 newArgs[co] = UndoFixupArg(args[co], deserializedArgs);
140             }
141 
142             return newArgs;
143         } // UndoFixupArgs
144 
145 
146         [System.Security.SecurityCritical]  // auto-generated
UndoFixupArg(Object arg, ArrayList deserializedArgs)147         protected static Object UndoFixupArg(Object arg, ArrayList deserializedArgs)
148         {
149             SmuggledObjRef smuggledObjRef = arg as SmuggledObjRef;
150             if (smuggledObjRef != null)
151             {
152                 // We call GetRealObject here ... that covers any
153                 // special unmarshaling we need to do for _ComObject
154                 return smuggledObjRef.ObjRef.GetRealObjectHelper();
155             }
156 
157             SerializedArg serializedArg = arg as SerializedArg;
158             if (serializedArg != null)
159             {
160                 return deserializedArgs[serializedArg.Index];
161             }
162 
163             return arg;
164         } // UndoFixupArg
165 
166 
167         // returns number of entries added to argsToSerialize
168         [System.Security.SecurityCritical]  // auto-generated
StoreUserPropertiesForMethodMessage( IMethodMessage msg, ref ArrayList argsToSerialize)169         protected static int StoreUserPropertiesForMethodMessage(
170             IMethodMessage msg,
171             ref ArrayList argsToSerialize)
172         {
173             IDictionary properties = msg.Properties;
174             MessageDictionary dict = properties as MessageDictionary;
175             if (dict != null)
176             {
177                 if (dict.HasUserData())
178                 {
179                     int co = 0;
180                     foreach (DictionaryEntry entry in dict.InternalDictionary)
181                     {
182                         if (argsToSerialize == null)
183                             argsToSerialize = new ArrayList();
184                         argsToSerialize.Add(entry);
185                         co++;
186                     }
187 
188                     return co;
189                 }
190                 else
191                 {
192                     return 0;
193                 }
194             }
195             else
196             {
197                 // <
198 
199                 int co = 0;
200                 foreach (DictionaryEntry entry in properties)
201                 {
202                     if (argsToSerialize == null)
203                         argsToSerialize = new ArrayList();
204                     argsToSerialize.Add(entry);
205                     co++;
206                 }
207 
208                 return co;
209             }
210         } // StoreUserPropertiesForMethodMessage
211 
212 
213         //
214         // Helper classes used to smuggle transformed arguments
215         //
216 
217         protected class SerializedArg
218         {
219             private int _index;
220 
SerializedArg(int index)221             public SerializedArg(int index)
222             {
223                 _index = index;
224             }
225 
226             public int Index { get { return _index; } }
227         }
228 
229         //
230         // end of Helper classes used to smuggle transformed arguments
231         //
232 
233     } // class MessageSmuggler
234 
235 
236 
237     // stores an object reference
238     internal class SmuggledObjRef
239     {
240         [System.Security.SecurityCritical] // auto-generated
241         ObjRef _objRef;
242 
243         [System.Security.SecurityCritical]  // auto-generated
SmuggledObjRef(ObjRef objRef)244         public SmuggledObjRef(ObjRef objRef)
245         {
246             _objRef = objRef;
247         }
248 
249         public ObjRef ObjRef
250         {
251             [System.Security.SecurityCritical]  // auto-generated
252             get { return _objRef; }
253         }
254     } // SmuggledObjRef
255 
256 
257 
258 
259 
260     internal class SmuggledMethodCallMessage : MessageSmuggler
261     {
262         private String   _uri;
263         private String   _methodName;
264         private String   _typeName;
265         private Object[] _args;
266 
267         private byte[] _serializedArgs = null;
268 #if false // This field isn't currently used
269         private Object[] _serializerSmuggledArgs = null;
270 #endif
271 
272         // other things that might need to go through serializer
273         private SerializedArg _methodSignature = null;
274         private SerializedArg _instantiation = null;
275         private Object        _callContext = null; // either a call id string or a SerializedArg pointing to CallContext object
276 
277         private int _propertyCount = 0; // <n> = # of user properties in dictionary
278                                         //   note: first <n> entries in _deserializedArgs will be the property entries
279 
280 
281         // always use this helper method to create
282         [System.Security.SecurityCritical]  // auto-generated
SmuggleIfPossible(IMessage msg)283         internal static SmuggledMethodCallMessage SmuggleIfPossible(IMessage msg)
284         {
285             IMethodCallMessage mcm = msg as IMethodCallMessage;
286             if (mcm == null)
287                 return null;
288 
289             return new SmuggledMethodCallMessage(mcm);
290         }
291 
292         // hide default constructor
SmuggledMethodCallMessage()293         private SmuggledMethodCallMessage(){}
294 
295         [System.Security.SecurityCritical]  // auto-generated
SmuggledMethodCallMessage(IMethodCallMessage mcm)296         private SmuggledMethodCallMessage(IMethodCallMessage mcm)
297         {
298             _uri = mcm.Uri;
299             _methodName = mcm.MethodName;
300             _typeName = mcm.TypeName;
301 
302             ArrayList argsToSerialize = null;
303 
304             IInternalMessage iim = mcm as IInternalMessage;
305 
306             // user properties (everything but special entries)
307             if ((iim == null) || iim.HasProperties())
308                 _propertyCount = StoreUserPropertiesForMethodMessage(mcm, ref argsToSerialize);
309 
310             // generic instantiation information
311             if (mcm.MethodBase.IsGenericMethod)
312             {
313                 Type[] inst = mcm.MethodBase.GetGenericArguments();
314                 if (inst != null && inst.Length > 0)
315                 {
316                     if (argsToSerialize == null)
317                         argsToSerialize = new ArrayList();
318                     _instantiation = new SerializedArg(argsToSerialize.Count);
319                     argsToSerialize.Add(inst);
320                 }
321             }
322 
323             // handle method signature
324             if (RemotingServices.IsMethodOverloaded(mcm))
325             {
326                 if (argsToSerialize == null)
327                     argsToSerialize = new ArrayList();
328                 _methodSignature = new SerializedArg(argsToSerialize.Count);
329                 argsToSerialize.Add(mcm.MethodSignature);
330             }
331 
332             // handle call context
333             LogicalCallContext lcc = mcm.LogicalCallContext;
334             if (lcc == null)
335             {
336                 _callContext = null;
337             }
338             else
339             if (lcc.HasInfo)
340             {
341                 if (argsToSerialize == null)
342                     argsToSerialize = new ArrayList();
343                 _callContext = new SerializedArg(argsToSerialize.Count);
344                 argsToSerialize.Add(lcc);
345             }
346             else
347             {
348                 // just smuggle the call id string
349                 _callContext = lcc.RemotingData.LogicalCallID;
350             }
351 
352             _args = FixupArgs(mcm.Args, ref argsToSerialize);
353 
354             if (argsToSerialize != null)
355             {
356                 //MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize, out _serializerSmuggledArgs);
357                 MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize);
358                 _serializedArgs = argStm.GetBuffer();
359             }
360 
361         } // SmuggledMethodCallMessage
362 
363 
364         // returns a list of the deserialized arguments
365         [System.Security.SecurityCritical]  // auto-generated
FixupForNewAppDomain()366         internal ArrayList FixupForNewAppDomain()
367         {
368             ArrayList deserializedArgs = null;
369 
370             if (_serializedArgs != null)
371             {
372                 deserializedArgs =
373                     CrossAppDomainSerializer.DeserializeMessageParts(
374                         new MemoryStream(_serializedArgs));
375                 //deserializedArgs =
376                 //    CrossAppDomainSerializer.DeserializeMessageParts(
377                 //        new MemoryStream(_serializedArgs), _serializerSmuggledArgs);
378                 _serializedArgs = null;
379             }
380 
381             return deserializedArgs;
382         } // FixupForNewAppDomain
383 
384 
385         internal String Uri { get { return _uri; } }
386         internal String MethodName { get { return _methodName; } }
387         internal String TypeName { get { return _typeName; } }
388 
GetInstantiation(ArrayList deserializedArgs)389         internal Type[] GetInstantiation(ArrayList deserializedArgs)
390         {
391             if (_instantiation != null)
392                 return (Type[])deserializedArgs[_instantiation.Index];
393             else
394                return null;
395         }
396 
GetMethodSignature(ArrayList deserializedArgs)397         internal Object[] GetMethodSignature(ArrayList deserializedArgs)
398         {
399             if (_methodSignature != null)
400                 return (Object[])deserializedArgs[_methodSignature.Index];
401             else
402                return null;
403         }
404 
405         [System.Security.SecurityCritical]  // auto-generated
GetArgs(ArrayList deserializedArgs)406         internal Object[] GetArgs(ArrayList deserializedArgs)
407         {
408             return UndoFixupArgs(_args, deserializedArgs);
409         } // GetArgs
410 
411         [System.Security.SecurityCritical]  // auto-generated
GetCallContext(ArrayList deserializedArgs)412         internal LogicalCallContext GetCallContext(ArrayList deserializedArgs)
413         {
414             if (_callContext == null)
415             {
416                 return null;
417             }
418             if (_callContext is String)
419             {
420                 LogicalCallContext callContext = new LogicalCallContext();
421                 callContext.RemotingData.LogicalCallID = (String)_callContext;
422                 return callContext;
423             }
424             else
425                 return (LogicalCallContext)deserializedArgs[((SerializedArg)_callContext).Index];
426         }
427 
428         internal int MessagePropertyCount
429         {
430             get { return _propertyCount; }
431         }
432 
PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs)433         internal void PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs)
434         {
435             for (int co = 0; co < _propertyCount; co++)
436             {
437                 DictionaryEntry de = (DictionaryEntry)deserializedArgs[co];
438                 dict[de.Key] = de.Value;
439             }
440         }
441 
442     } // class SmuggledMethodCallMessage
443 
444 
445 
446     internal class SmuggledMethodReturnMessage : MessageSmuggler
447     {
448         private Object[]  _args;
449         private Object    _returnValue;
450 
451         private byte[] _serializedArgs = null;
452 #if false // This field isn't currently used
453         private Object[] _serializerSmuggledArgs = null;
454 #endif
455 
456         // other things that might need to go through serializer
457         private SerializedArg _exception = null;
458         private Object        _callContext = null; // either a call id string or a SerializedArg pointing to CallContext object
459 
460         private int _propertyCount; // <n> = # of user properties in dictionary
461                                     //   note: first <n> entries in _deserializedArgs will be the property entries
462 
463 
464         // always use this helper method to create
465         [System.Security.SecurityCritical]  // auto-generated
SmuggleIfPossible(IMessage msg)466         internal static SmuggledMethodReturnMessage SmuggleIfPossible(IMessage msg)
467         {
468             IMethodReturnMessage mrm = msg as IMethodReturnMessage;
469             if (mrm == null)
470                 return null;
471 
472             return new SmuggledMethodReturnMessage(mrm);
473         }
474 
475         // hide default constructor
SmuggledMethodReturnMessage()476         private SmuggledMethodReturnMessage(){}
477 
478         [System.Security.SecurityCritical]  // auto-generated
SmuggledMethodReturnMessage(IMethodReturnMessage mrm)479         private SmuggledMethodReturnMessage(IMethodReturnMessage mrm)
480         {
481             ArrayList argsToSerialize = null;
482 
483             ReturnMessage retMsg = mrm as ReturnMessage;
484 
485             // user properties (everything but special entries)
486             if ((retMsg == null) || retMsg.HasProperties())
487                 _propertyCount = StoreUserPropertiesForMethodMessage(mrm, ref argsToSerialize);
488 
489             // handle exception
490             Exception excep = mrm.Exception;
491             if (excep != null)
492             {
493                 if (argsToSerialize == null)
494                     argsToSerialize = new ArrayList();
495                 _exception = new SerializedArg(argsToSerialize.Count);
496                 argsToSerialize.Add(excep);
497             }
498 
499             // handle call context
500             LogicalCallContext lcc = mrm.LogicalCallContext;
501             if (lcc == null)
502             {
503                 _callContext = null;
504             }
505             else
506             if (lcc.HasInfo)
507             {
508                 if (lcc.Principal != null)
509                     lcc.Principal = null;
510 
511                 if (argsToSerialize == null)
512                     argsToSerialize = new ArrayList();
513                 _callContext = new SerializedArg(argsToSerialize.Count);
514                 argsToSerialize.Add(lcc);
515             }
516             else
517             {
518                 // just smuggle the call id string
519                 _callContext = lcc.RemotingData.LogicalCallID;
520             }
521 
522             _returnValue = FixupArg(mrm.ReturnValue, ref argsToSerialize);
523             _args = FixupArgs(mrm.Args, ref argsToSerialize);
524 
525             if (argsToSerialize != null)
526             {
527                 MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize);
528                 //MemoryStream argStm = CrossAppDomainSerializer.SerializeMessageParts(argsToSerialize, out _serializerSmuggledArgs);
529                 _serializedArgs = argStm.GetBuffer();
530             }
531 
532         } // SmuggledMethodReturnMessage
533 
534 
535         [System.Security.SecurityCritical]  // auto-generated
FixupForNewAppDomain()536         internal ArrayList FixupForNewAppDomain()
537         {
538             ArrayList deserializedArgs = null;
539 
540             if (_serializedArgs != null)
541             {
542                 deserializedArgs =
543                     CrossAppDomainSerializer.DeserializeMessageParts(
544                         new MemoryStream(_serializedArgs));
545                 //deserializedArgs =
546                 //    CrossAppDomainSerializer.DeserializeMessageParts(
547                 //        new MemoryStream(_serializedArgs), _serializerSmuggledArgs);
548                 _serializedArgs = null;
549             }
550 
551             return deserializedArgs;
552         } // FixupForNewAppDomain
553 
554         [System.Security.SecurityCritical]  // auto-generated
GetReturnValue(ArrayList deserializedArgs)555         internal Object GetReturnValue(ArrayList deserializedArgs)
556         {
557             return UndoFixupArg(_returnValue, deserializedArgs);
558         } // GetReturnValue
559 
560         [System.Security.SecurityCritical]  // auto-generated
GetArgs(ArrayList deserializedArgs)561         internal Object[] GetArgs(ArrayList deserializedArgs)
562         {
563             Object[] obj = UndoFixupArgs(_args, deserializedArgs);
564             return obj;
565         } // GetArgs
566 
GetException(ArrayList deserializedArgs)567         internal Exception GetException(ArrayList deserializedArgs)
568         {
569             if (_exception != null)
570                 return (Exception)deserializedArgs[_exception.Index];
571             else
572                 return null;
573         } // Exception
574 
575         [System.Security.SecurityCritical]  // auto-generated
GetCallContext(ArrayList deserializedArgs)576         internal LogicalCallContext GetCallContext(ArrayList deserializedArgs)
577         {
578             if (_callContext == null)
579             {
580                 return null;
581             }
582             if (_callContext is String)
583             {
584                 LogicalCallContext callContext = new LogicalCallContext();
585                 callContext.RemotingData.LogicalCallID = (String)_callContext;
586                 return callContext;
587             }
588             else
589                 return (LogicalCallContext)deserializedArgs[((SerializedArg)_callContext).Index];
590         }
591 
592         internal int MessagePropertyCount
593         {
594             get { return _propertyCount; }
595         }
596 
PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs)597         internal void PopulateMessageProperties(IDictionary dict, ArrayList deserializedArgs)
598         {
599             for (int co = 0; co < _propertyCount; co++)
600             {
601                 DictionaryEntry de = (DictionaryEntry)deserializedArgs[co];
602                 dict[de.Key] = de.Value;
603             }
604         }
605 
606     } // class SmuggledMethodReturnMessage
607 
608 
609 } // namespace System.Runtime.Remoting.Messaging
610 
611