The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting.Messaging \ SmuggledMethodReturnMessage

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

Developer Fusion