The Labs \ Source Viewer \ SSCLI \ System.Runtime.Remoting \ LastCalledType

  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. namespace System.Runtime.Remoting
  16. {
  17.     using System;
  18.     using System.Collections;
  19.     using System.Threading;
  20.     using System.Runtime.InteropServices;
  21.     using System.Runtime.Serialization;
  22.     using System.Runtime.Remoting.Activation;
  23.     using System.Runtime.Remoting.Contexts;
  24.     using System.Runtime.Remoting.Messaging;
  25.     using System.Runtime.Remoting.Proxies;
  26.     using System.Runtime.ConstrainedExecution;
  27.     using System.Runtime.CompilerServices;
  28.     using System.Globalization;
  29.    
  30.    
  31.     // ServerIdentity derives from Identity and holds the extra server specific information
  32.     // associated with each instance of a remoted server object.
  33.     //
  34.     internal class ServerIdentity : Identity
  35.     {
  36.         // Internal members
  37.         internal Context _srvCtx;
  38.        
  39.         // This is used to cache the last server type
  40.         private class LastCalledType
  41.         {
  42.             public string typeName;
  43.             public Type type;
  44.         }
  45.         // These two fields are used for (purely) MarshalByRef object identities
  46.         // For context bound objects we have corresponding fields in RemotingProxy
  47.         // that are used instead. This is done to facilitate GC in x-context cases.
  48.         internal IMessageSink _serverObjectChain;
  49.         internal StackBuilderSink _stackBuilderSink;
  50.        
  51.         // This manages the dynamic properties registered on per object/proxy basis
  52.         internal DynamicPropertyHolder _dphSrv;
  53.        
  54.         internal Type _srvType;
  55.         // type of server object
  56.         private LastCalledType _lastCalledType;
  57.         // cache the last type object
  58.         internal bool _bMarshaledAsSpecificType = false;
  59.         internal int _firstCallDispatched = 0;
  60.        
  61.         internal GCHandle _srvIdentityHandle;
  62.        
  63.         internal Type GetLastCalledType(string newTypeName)
  64.         {
  65.             LastCalledType lastType = _lastCalledType;
  66.             if (lastType == null)
  67.                 return null;
  68.            
  69.             string typeName = lastType.typeName;
  70.             Type t = lastType.type;
  71.            
  72.             if (typeName == null || t == null)
  73.                 return null;
  74.            
  75.             if (typeName.Equals(newTypeName))
  76.                 return t;
  77.            
  78.             return null;
  79.         }
  80.         // GetLastCalledMethod
  81.         internal void SetLastCalledType(string newTypeName, Type newType)
  82.         {
  83.             LastCalledType lastType = new LastCalledType();
  84.             lastType.typeName = newTypeName;
  85.             lastType.type = newType;
  86.            
  87.             _lastCalledType = lastType;
  88.         }
  89.         // SetLastCalledMethod
  90.         internal void SetHandle()
  91.         {
  92.             bool fLocked = false;
  93.             RuntimeHelpers.PrepareConstrainedRegions();
  94.             try {
  95.                 Monitor.ReliableEnter(this, ref fLocked);
  96.                 if (!_srvIdentityHandle.IsAllocated)
  97.                     _srvIdentityHandle = new GCHandle(this, GCHandleType.Normal);
  98.                 else
  99.                     _srvIdentityHandle.Target = this;
  100.             }
  101.             finally {
  102.                 if (fLocked) {
  103.                     Monitor.Exit(this);
  104.                 }
  105.             }
  106.         }
  107.        
  108.         internal void ResetHandle()
  109.         {
  110.             bool fLocked = false;
  111.             RuntimeHelpers.PrepareConstrainedRegions();
  112.             try {
  113.                 Monitor.ReliableEnter(this, ref fLocked);
  114.                 _srvIdentityHandle.Target = null;
  115.             }
  116.             finally {
  117.                 if (fLocked) {
  118.                     Monitor.Exit(this);
  119.                 }
  120.             }
  121.         }
  122.        
  123.         internal GCHandle GetHandle()
  124.         {
  125.             return _srvIdentityHandle;
  126.         }
  127.        
  128.        
  129.         // Creates a new server identity. This form is used by RemotingServices.Wrap
  130.         //
  131.         internal ServerIdentity(MarshalByRefObject obj, Context serverCtx) : base(obj is ContextBoundObject)
  132.         {
  133.             if (null != obj) {
  134.                 if (!RemotingServices.IsTransparentProxy(obj)) {
  135.                     _srvType = obj.GetType();
  136.                 }
  137.                 else {
  138.                     RealProxy rp = RemotingServices.GetRealProxy(obj);
  139.                     _srvType = rp.GetProxiedType();
  140.                 }
  141.             }
  142.            
  143.             _srvCtx = serverCtx;
  144.             _serverObjectChain = null;
  145.             _stackBuilderSink = null;
  146.         }
  147.        
  148.         // This is used by RS::SetObjectUriForMarshal
  149.         internal ServerIdentity(MarshalByRefObject obj, Context serverCtx, string uri) : this(obj, serverCtx)
  150.         {
  151.             SetOrCreateURI(uri, true);
  152.             // calling from the constructor
  153.         }
  154.        
  155.        
  156.         // Informational methods on the ServerIdentity.
  157.         // Get the native context for the server object.
  158.         internal Context ServerContext {
  159.             [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
  160.             get { return _srvCtx; }
  161.         }
  162.        
  163.         internal void SetSingleCallObjectMode()
  164.         {
  165.             BCLDebug.Assert(!IsSingleCall() && !IsSingleton(), "Bad serverID");
  166.             _flags |= IDFLG_SERVER_SINGLECALL;
  167.         }
  168.        
  169.         internal void SetSingletonObjectMode()
  170.         {
  171.             BCLDebug.Assert(!IsSingleCall() && !IsSingleton(), "Bad serverID");
  172.             _flags |= IDFLG_SERVER_SINGLETON;
  173.         }
  174.        
  175.         internal bool IsSingleCall()
  176.         {
  177.             return ((_flags & IDFLG_SERVER_SINGLECALL) != 0);
  178.         }
  179.        
  180.         internal bool IsSingleton()
  181.         {
  182.             return ((_flags & IDFLG_SERVER_SINGLETON) != 0);
  183.         }
  184.        
  185.         internal IMessageSink GetServerObjectChain(out MarshalByRefObject obj)
  186.         {
  187.             obj = null;
  188.             // NOTE: Lifetime relies on the Identity flags for
  189.             // SingleCall and Singleton being set by the time this getter
  190.             // is called.
  191.             if (!this.IsSingleCall()) {
  192.                 // This is the common case
  193.                 if (_serverObjectChain == null) {
  194.                     bool fLocked = false;
  195.                     RuntimeHelpers.PrepareConstrainedRegions();
  196.                     try {
  197.                         Monitor.ReliableEnter(this, ref fLocked);
  198.                         if (_serverObjectChain == null) {
  199.                             MarshalByRefObject srvObj = (MarshalByRefObject)this.TPOrObject;
  200.                            
  201.                             _serverObjectChain = _srvCtx.CreateServerObjectChain(srvObj);
  202.                            
  203.                         }
  204.                     }
  205.                     finally {
  206.                         if (fLocked) {
  207.                             Monitor.Exit(this);
  208.                         }
  209.                     }
  210.                 }
  211.                 BCLDebug.Assert(null != _serverObjectChain, "null != _serverObjectChain");
  212.                
  213.                 return _serverObjectChain;
  214.             }
  215.             else {
  216.                 // ---------- SINGLE CALL WKO --------------
  217.                 // In this case, we are expected to provide
  218.                 // a fresh server object for each dispatch.
  219.                 // Since the server object chain is object
  220.                 // specific, we must create a fresh chain too.
  221.                
  222.                 // We must be in the correct context for this
  223.                 // to succeed.
  224.                
  225.                
  226.                 BCLDebug.Assert(Thread.CurrentContext == _srvCtx, "Bad context mismatch");
  227.                
  228.                 MarshalByRefObject srvObj = null;
  229.                 IMessageSink objChain = null;
  230.                 if (_tpOrObject != null && _firstCallDispatched == 0 && Interlocked.CompareExchange(ref _firstCallDispatched, 1, 0) == 0) {
  231.                     // use the instance of server object created to
  232.                     // set up the pipeline.
  233.                     srvObj = (MarshalByRefObject)_tpOrObject;
  234.                    
  235.                     objChain = _serverObjectChain;
  236.                    
  237.                     if (objChain == null) {
  238.                         objChain = _srvCtx.CreateServerObjectChain(srvObj);
  239.                     }
  240.                 }
  241.                 else {
  242.                     // For singleCall we create a fresh object & its chain
  243.                     // on each dispatch!
  244.                     srvObj = (MarshalByRefObject)Activator.CreateInstance((Type)_srvType, true);
  245.                    
  246.                     // make sure that object didn't Marshal itself.
  247.                     // (well known objects should live up to their promise
  248.                     // of exporting themselves through exactly one url)
  249.                     string tempUri = RemotingServices.GetObjectUri(srvObj);
  250.                     if (tempUri != null) {
  251.                         throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_WellKnown_CtorCantMarshal"), this.URI));
  252.                     }
  253.                    
  254.                     // Set the identity depending on whether we have the server
  255.                     // or proxy
  256.                     if (!RemotingServices.IsTransparentProxy(srvObj)) {
  257.                        
  258.                         #if _DEBUG
  259.                         Identity idObj = srvObj.__RaceSetServerIdentity(this);
  260.                         #else
  261.                         srvObj.__RaceSetServerIdentity(this);
  262.                         #endif
  263.                         #if _DEBUG
  264.                         BCLDebug.Assert(idObj == this, "Bad ID state!");
  265.                         BCLDebug.Assert(idObj == MarshalByRefObject.GetIdentity(srvObj), "Bad ID state!");
  266.                         #endif
  267.                     }
  268.                     else {
  269.                         RealProxy rp = null;
  270.                         rp = RemotingServices.GetRealProxy(srvObj);
  271.                         BCLDebug.Assert(null != rp, "null != rp");
  272.                         // #if _DEBUG
  273.                         // Identity idObj = (ServerIdentity) rp.SetIdentity(this);
  274.                         // #else
  275.                         rp.IdentityObject = this;
  276.                         // #endif
  277.                     }
  278.                     // Create the object chain and return it
  279.                     objChain = _srvCtx.CreateServerObjectChain(srvObj);
  280.                 }
  281.                
  282.                 // This is passed out to the caller so that for single-call
  283.                 // case we can call Dispose when the incoming call is done
  284.                 obj = srvObj;
  285.                 return objChain;
  286.             }
  287.         }
  288.        
  289.         internal Type ServerType {
  290.             get { return _srvType; }
  291.             set { _srvType = value; }
  292.         }
  293.         // ServerType
  294.         internal bool MarshaledAsSpecificType {
  295.             get { return _bMarshaledAsSpecificType; }
  296.             set { _bMarshaledAsSpecificType = value; }
  297.         }
  298.         // MarshaledAsSpecificType
  299.        
  300.         internal IMessageSink RaceSetServerObjectChain(IMessageSink serverObjectChain)
  301.         {
  302.             if (_serverObjectChain == null) {
  303.                 bool fLocked = false;
  304.                 RuntimeHelpers.PrepareConstrainedRegions();
  305.                 try {
  306.                     Monitor.ReliableEnter(this, ref fLocked);
  307.                     if (_serverObjectChain == null) {
  308.                         _serverObjectChain = serverObjectChain;
  309.                     }
  310.                 }
  311.                 finally {
  312.                     if (fLocked) {
  313.                         Monitor.Exit(this);
  314.                     }
  315.                 }
  316.             }
  317.             return _serverObjectChain;
  318.         }
  319.        
  320. /*package*/       
  321.         internal bool AddServerSideDynamicProperty(IDynamicProperty prop)
  322.         {
  323.             if (_dphSrv == null) {
  324.                 DynamicPropertyHolder dphSrv = new DynamicPropertyHolder();
  325.                 bool fLocked = false;
  326.                 RuntimeHelpers.PrepareConstrainedRegions();
  327.                 try {
  328.                     Monitor.ReliableEnter(this, ref fLocked);
  329.                     if (_dphSrv == null) {
  330.                         _dphSrv = dphSrv;
  331.                     }
  332.                 }
  333.                 finally {
  334.                     if (fLocked) {
  335.                         Monitor.Exit(this);
  336.                     }
  337.                 }
  338.             }
  339.             return _dphSrv.AddDynamicProperty(prop);
  340.         }
  341.        
  342. /*package*/       
  343.         internal bool RemoveServerSideDynamicProperty(string name)
  344.         {
  345.             if (_dphSrv == null) {
  346.                 throw new ArgumentException(Environment.GetResourceString("Arg_PropNotFound"));
  347.             }
  348.             return _dphSrv.RemoveDynamicProperty(name);
  349.         }
  350.        
  351.         internal ArrayWithSize ServerSideDynamicSinks {
  352.             get {
  353.                 if (_dphSrv == null) {
  354.                     return null;
  355.                 }
  356.                 else {
  357.                     return _dphSrv.DynamicSinks;
  358.                 }
  359.             }
  360.         }
  361.        
  362.         internal override void AssertValid()
  363.         {
  364.             base.AssertValid();
  365.             if ((null != this.TPOrObject) && !RemotingServices.IsTransparentProxy(this.TPOrObject)) {
  366.                 BCLDebug.Assert(MarshalByRefObject.GetIdentity((MarshalByRefObject)this.TPOrObject) == this, "Server ID mismatch with Object");
  367.             }
  368.         }
  369.     }
  370. }

Developer Fusion