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

  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.Globalization;
  18.     using System.Runtime.Remoting;
  19.     using System.Runtime.Remoting.Contexts;
  20.     using System.Runtime.Remoting.Messaging;
  21.     using System.Runtime.Remoting.Activation;
  22.     using System.Runtime.Remoting.Lifetime;
  23.     using System.Security.Cryptography;
  24.     using Microsoft.Win32;
  25.     using System.Threading;
  26.     using System;
  27.     // Identity is the base class for remoting identities. An instance of Identity (or a derived class)
  28.     // is associated with each instance of a remoted object. Likewise, an instance of Identity is
  29.     // associated with each instance of a remoting proxy.
  30.     //
  31.     using System.Collections;
  32.     internal class Identity
  33.     {
  34.         // We use a Guid to create a URI from. Each time a new URI is needed we increment
  35.         // the sequence number and append it to the statically inited Guid.
  36.         // private static readonly Guid IDGuid = Guid.NewGuid();
  37.        
  38.         static internal string ProcessIDGuid {
  39.             get { return SharedStatics.Remoting_Identity_IDGuid; }
  40.         }
  41.        
  42.         // We need the original and the configured one because we have to compare
  43.         // both when looking at a uri since something might be marshalled before
  44.         // the id is set.
  45.         private static string s_originalAppDomainGuid = Guid.NewGuid().ToString().Replace('-', '_');
  46.         private static string s_configuredAppDomainGuid = null;
  47.        
  48.         static internal string AppDomainUniqueId {
  49.             get {
  50.                 if (s_configuredAppDomainGuid != null)
  51.                     return s_configuredAppDomainGuid;
  52.                 else
  53.                     return s_originalAppDomainGuid;
  54.             }
  55.         }
  56.         // get
  57.         // AppDomainGuid
  58.         private static string s_originalAppDomainGuidString = "/" + s_originalAppDomainGuid.ToLower(CultureInfo.InvariantCulture) + "/";
  59.         private static string s_configuredAppDomainGuidString = null;
  60.        
  61.         private static string s_IDGuidString = "/" + s_originalAppDomainGuid.ToLower(CultureInfo.InvariantCulture) + "/";
  62.        
  63.         // Used to get random numbers
  64.         private static RNGCryptoServiceProvider s_rng = new RNGCryptoServiceProvider();
  65.        
  66.         static internal string IDGuidString {
  67.             get { return s_IDGuidString; }
  68.         }
  69.        
  70.        
  71.         static internal string RemoveAppNameOrAppGuidIfNecessary(string uri)
  72.         {
  73.             // uri is assumed to be in lower-case at this point
  74.            
  75.             // If the uri starts with either, "/<appname>/" or "/<appdomainguid>/" we
  76.             // should strip that off.
  77.            
  78.             // We only need to look further if the uri starts with a "/".
  79.             if ((uri == null) || (uri.Length <= 1) || (uri[0] != '/'))
  80.                 return uri;
  81.            
  82.             // compare to process guid (guid string already has slash at beginnning and end)
  83.             string guidStr;
  84.             if (s_configuredAppDomainGuidString != null) {
  85.                 guidStr = s_configuredAppDomainGuidString;
  86.                 if (uri.Length > guidStr.Length) {
  87.                     if (StringStartsWith(uri, guidStr)) {
  88.                         // remove "/<appdomainguid>/"
  89.                         return uri.Substring(guidStr.Length);
  90.                     }
  91.                 }
  92.             }
  93.            
  94.             // always need to check original guid as well in case the object with this
  95.             // uri was marshalled before we changed the app domain id
  96.             guidStr = s_originalAppDomainGuidString;
  97.             if (uri.Length > guidStr.Length) {
  98.                 if (StringStartsWith(uri, guidStr)) {
  99.                     // remove "/<appdomainguid>/"
  100.                     return uri.Substring(guidStr.Length);
  101.                 }
  102.             }
  103.            
  104.             // compare to application name (application name will never have slashes)
  105.             string appName = RemotingConfiguration.ApplicationName;
  106.             if (appName != null) {
  107.                 // add +2 to appName length for surrounding slashes
  108.                 if (uri.Length > (appName.Length + 2)) {
  109.                     if (String.Compare(uri, 1, appName, 0, appName.Length, true, CultureInfo.InvariantCulture) == 0) {
  110.                         // now, make sure there is a slash after "/<appname>" in uri
  111.                         if (uri[appName.Length + 1] == '/') {
  112.                             // remove "/<appname>/"
  113.                             return uri.Substring(appName.Length + 2);
  114.                         }
  115.                     }
  116.                 }
  117.             }
  118.            
  119.             // it didn't start with "/<appname>/" or "/<processguid>/", so just remove the
  120.             // first slash and return.
  121.             uri = uri.Substring(1);
  122.             return uri;
  123.         }
  124.         // RemoveAppNameOrAppGuidIfNecessary
  125.        
  126.         private static bool StringStartsWith(string s1, string prefix)
  127.         {
  128.             // String.StartsWith uses String.Compare instead of String.CompareOrdinal,
  129.             // so we provide our own implementation of StartsWith.
  130.            
  131.             if (s1.Length < prefix.Length)
  132.                 return false;
  133.            
  134.             return (String.CompareOrdinal(s1, 0, prefix, 0, prefix.Length) == 0);
  135.         }
  136.         // StringStartsWith
  137.        
  138.        
  139.         // DISCONNECTED_FULL denotes that the object is disconnected
  140.         // from both local & remote (x-appdomain & higher) clients
  141.        
  142.         // DISCONNECTED_REM denotes that the object is disconnected
  143.         // from remote (x-appdomain & higher) clients ... however
  144.         // x-context proxies continue to work as expected.
  145.        
  146.         protected const int IDFLG_DISCONNECTED_FULL = 1;
  147.         protected const int IDFLG_DISCONNECTED_REM = 2;
  148.         protected const int IDFLG_IN_IDTABLE = 4;
  149.        
  150.         protected const int IDFLG_CONTEXT_BOUND = 16;
  151.         protected const int IDFLG_WELLKNOWN = 256;
  152.         protected const int IDFLG_SERVER_SINGLECALL = 512;
  153.         protected const int IDFLG_SERVER_SINGLETON = 1024;
  154.        
  155.         internal int _flags;
  156.        
  157.         internal object _tpOrObject;
  158.         protected string _ObjURI;
  159.         protected string _URL;
  160.        
  161.         // These have to be "Object" to use Interlocked operations
  162.         internal object _objRef;
  163.         internal object _channelSink;
  164.        
  165.         // Remoting proxy has this field too, we use the latter only for
  166.         // ContextBoundObject identities.
  167.         internal object _envoyChain;
  168.        
  169.         // This manages the dynamically registered sinks for the proxy.
  170.         internal DynamicPropertyHolder _dph;
  171.        
  172.         // Lease for object
  173.         internal Lease _lease;
  174.        
  175.         static internal string ProcessGuid {
  176.             get { return ProcessIDGuid; }
  177.         }
  178.        
  179.         private static int GetNextSeqNum()
  180.         {
  181.             return SharedStatics.Remoting_Identity_GetNextSeqNum();
  182.         }
  183.        
  184.         private static byte[] GetRandomBytes()
  185.         {
  186.             // PERF? In a situation where objects need URIs at a very fast
  187.             // rate, we will end up creating too many of these tiny byte-arrays
  188.             // causing pressure on GC!
  189.             // One option would be to have a buff in the managed thread class
  190.             // and use that to get a chunk of random bytes consuming
  191.             // 18 bytes at a time.
  192.             // This would avoid the need to have a lock across threads.
  193.             byte[] randomBytes = new byte[18];
  194.             s_rng.GetBytes(randomBytes);
  195.             return randomBytes;
  196.         }
  197.        
  198.        
  199.         // Constructs a new identity using the given the URI. This is used for
  200.         // creating client side identities.
  201.         //
  202.         //
  203.         internal Identity(string objURI, string URL)
  204.         {
  205.             BCLDebug.Assert(objURI != null, "objURI should not be null here");
  206.             if (URL != null) {
  207.                 _flags |= IDFLG_WELLKNOWN;
  208.                 _URL = URL;
  209.             }
  210.                 /*calling from ID ctor*/            SetOrCreateURI(objURI, true);
  211.         }
  212.        
  213.         // Constructs a new identity. This is used for creating server side
  214.         // identities. The URI for server side identities is lazily generated
  215.         // during the first call to Marshal because if we associate a URI with the
  216.         // object at the time of creation then you cannot call Marshal with a
  217.         // URI of your own choice.
  218.         //
  219.         //
  220.         internal Identity(bool bContextBound)
  221.         {
  222.             if (bContextBound)
  223.                 _flags |= IDFLG_CONTEXT_BOUND;
  224.         }
  225.        
  226.         internal bool IsContextBound {
  227.             get { return (_flags & IDFLG_CONTEXT_BOUND) == IDFLG_CONTEXT_BOUND; }
  228.         }
  229.        
  230.         internal bool IsWellKnown()
  231.         {
  232.             return (_flags & IDFLG_WELLKNOWN) == IDFLG_WELLKNOWN;
  233.         }
  234.        
  235.         internal void SetInIDTable()
  236.         {
  237.             while (true) {
  238.                 int currentFlags = _flags;
  239.                 int newFlags = _flags | IDFLG_IN_IDTABLE;
  240.                 if (currentFlags == Interlocked.CompareExchange(ref _flags, newFlags, currentFlags))
  241.                     break;
  242.             }
  243.         }
  244.        
  245.         internal void ResetInIDTable(bool bResetURI)
  246.         {
  247.             BCLDebug.Assert(IdentityHolder.TableLock.IsWriterLockHeld, "IDTable should be write-locked");
  248.             while (true) {
  249.                 int currentFlags = _flags;
  250.                 int newFlags = _flags & (~IDFLG_IN_IDTABLE);
  251.                 if (currentFlags == Interlocked.CompareExchange(ref _flags, newFlags, currentFlags))
  252.                     break;
  253.             }
  254.             // bResetURI is true for the external API call to Disconnect, it is
  255.             // false otherwise. Thus when a user Disconnects an object
  256.             // its URI will get reset but if lifetime service times it out
  257.             // it will not clear out the URIs
  258.             if (bResetURI) {
  259.                 ((ObjRef)_objRef).URI = null;
  260.                 _ObjURI = null;
  261.             }
  262.         }
  263.        
  264.         internal bool IsInIDTable()
  265.         {
  266.             return ((_flags & IDFLG_IN_IDTABLE) == IDFLG_IN_IDTABLE);
  267.         }
  268.        
  269.         internal void SetFullyConnected()
  270.         {
  271.             BCLDebug.Assert(this is ServerIdentity, "should be setting these flags for srvIDs only!");
  272.             BCLDebug.Assert((_ObjURI != null), "Object must be assigned a URI to be fully connected!");
  273.            
  274.             while (true) {
  275.                 int currentFlags = _flags;
  276.                 int newFlags = _flags & (~(IDFLG_DISCONNECTED_FULL | IDFLG_DISCONNECTED_REM));
  277.                 if (currentFlags == Interlocked.CompareExchange(ref _flags, newFlags, currentFlags))
  278.                     break;
  279.             }
  280.         }
  281.        
  282.         internal bool IsFullyDisconnected()
  283.         {
  284.             BCLDebug.Assert(this is ServerIdentity, "should be setting these flags for srvIDs only!");
  285.             return (_flags & IDFLG_DISCONNECTED_FULL) == IDFLG_DISCONNECTED_FULL;
  286.         }
  287.        
  288.         internal bool IsRemoteDisconnected()
  289.         {
  290.             BCLDebug.Assert(this is ServerIdentity, "should be setting these flags for srvIDs only!");
  291.             return (_flags & IDFLG_DISCONNECTED_REM) == IDFLG_DISCONNECTED_REM;
  292.         }
  293.        
  294.         internal bool IsDisconnected()
  295.         {
  296.             BCLDebug.Assert(this is ServerIdentity, "should be setting these flags for srvIDs only!");
  297.             return (IsFullyDisconnected() || IsRemoteDisconnected());
  298.         }
  299.        
  300.         // Get the URI
  301.         internal string URI {
  302.             get {
  303.                 if (IsWellKnown()) {
  304.                     return _URL;
  305.                 }
  306.                 else {
  307.                     return _ObjURI;
  308.                 }
  309.             }
  310.         }
  311.        
  312.         internal string ObjURI {
  313.             get { return _ObjURI; }
  314.         }
  315.        
  316.         internal MarshalByRefObject TPOrObject {
  317.             get { return (MarshalByRefObject)_tpOrObject; }
  318.         }
  319.        
  320.         // Set the transparentProxy field protecting against races. The returned transparent
  321.         // proxy could be different than the one the caller is attempting to set.
  322.         //
  323.         internal object RaceSetTransparentProxy(object tpObj)
  324.         {
  325.             if (_tpOrObject == null)
  326.                 Interlocked.CompareExchange(ref _tpOrObject, tpObj, null);
  327.             return _tpOrObject;
  328.         }
  329.        
  330.         // Get the ObjRef.
  331.         internal ObjRef ObjectRef {
  332.             get { return (ObjRef)_objRef; }
  333.         }
  334.        
  335.         // Set the objRef field protecting against races. The returned objRef
  336.         // could be different than the one the caller is attempting to set.
  337.         //
  338.         internal ObjRef RaceSetObjRef(ObjRef objRefGiven)
  339.         {
  340.             if (_objRef == null) {
  341.                 Interlocked.CompareExchange(ref _objRef, objRefGiven, null);
  342.             }
  343.             return (ObjRef)_objRef;
  344.         }
  345.        
  346.        
  347.         // Get the ChannelSink.
  348.         internal IMessageSink ChannelSink {
  349.             get { return (IMessageSink)_channelSink; }
  350.         }
  351.        
  352.         // Set the channelSink field protecting against races. The returned
  353.         // channelSink proxy could be different than the one the caller is
  354.         // attempting to set.
  355.         //
  356.         internal IMessageSink RaceSetChannelSink(IMessageSink channelSink)
  357.         {
  358.             if (_channelSink == null) {
  359.                 Interlocked.CompareExchange(ref _channelSink, channelSink, null);
  360.             }
  361.             return (IMessageSink)_channelSink;
  362.         }
  363.        
  364.         // Get/Set the Envoy Sink chain..
  365.         internal IMessageSink EnvoyChain {
  366.             get { return (IMessageSink)_envoyChain; }
  367.         }
  368.        
  369.         // Get/Set Lease
  370.         internal Lease Lease {
  371.             get { return _lease; }
  372.             set { _lease = value; }
  373.         }
  374.        
  375.        
  376.         // Set the channelSink field protecting against races. The returned
  377.         // channelSink proxy could be different than the one the caller is
  378.         // attempting to set.
  379.         //
  380.         internal IMessageSink RaceSetEnvoyChain(IMessageSink envoyChain)
  381.         {
  382.             if (_envoyChain == null) {
  383.                 Interlocked.CompareExchange(ref _envoyChain, envoyChain, null);
  384.             }
  385.             return (IMessageSink)_envoyChain;
  386.         }
  387.        
  388.         // A URI is lazily generated for the identity based on a GUID.
  389.         // Well known objects supply their own URI
  390.         internal void SetOrCreateURI(string uri)
  391.         {
  392.             SetOrCreateURI(uri, false);
  393.         }
  394.        
  395.         internal void SetOrCreateURI(string uri, bool bIdCtor)
  396.         {
  397.             if (bIdCtor == false) {
  398.                 // This method is called either from the ID Constructor or
  399.                 // with a writeLock on the ID Table
  400.                 BCLDebug.Assert(IdentityHolder.TableLock.IsWriterLockHeld, "IDTable should be write-locked");
  401.                 if (null != _ObjURI) {
  402.                     throw new RemotingException(Environment.GetResourceString("Remoting_SetObjectUriForMarshal__UriExists"));
  403.                 }
  404.             }
  405.            
  406.             if (null == uri) {
  407.                 string random = System.Convert.ToBase64String(GetRandomBytes());
  408.                 // Need to replace the '/' with '_' since '/' is not a valid uri char
  409.                 _ObjURI = (IDGuidString + random.Replace('/', '_') + "_" + GetNextSeqNum() + ".rem").ToLower(CultureInfo.InvariantCulture);
  410.             }
  411.             else {
  412.                 if (this is ServerIdentity)
  413.                     _ObjURI = IDGuidString + uri;
  414.                 else
  415.                     _ObjURI = uri;
  416.             }
  417.         }
  418.         // SetOrCreateURI
  419.         // This is used by ThreadAffinity/Synchronization contexts
  420.         // (Shares the seqNum space with URIs)
  421.         static internal string GetNewLogicalCallID()
  422.         {
  423.             return IDGuidString + GetNextSeqNum();
  424.         }
  425.        
  426.         [System.Diagnostics.Conditional("_DEBUG")]
  427.         internal virtual void AssertValid()
  428.         {
  429.             if (URI != null) {
  430.                 Identity resolvedIdentity = IdentityHolder.ResolveIdentity(URI);
  431.                 BCLDebug.Assert((resolvedIdentity == null) || (resolvedIdentity == this), "Server ID mismatch with URI");
  432.             }
  433.         }
  434.        
  435.         internal bool AddProxySideDynamicProperty(IDynamicProperty prop)
  436.         {
  437.             lock (this) {
  438.                 if (_dph == null) {
  439.                     DynamicPropertyHolder dph = new DynamicPropertyHolder();
  440.                     lock (this) {
  441.                         if (_dph == null) {
  442.                             _dph = dph;
  443.                         }
  444.                     }
  445.                 }
  446.                 return _dph.AddDynamicProperty(prop);
  447.             }
  448.         }
  449.        
  450.         internal bool RemoveProxySideDynamicProperty(string name)
  451.         {
  452.             lock (this) {
  453.                 if (_dph == null) {
  454.                     throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Contexts_NoProperty"), name));
  455.                 }
  456.                 return _dph.RemoveDynamicProperty(name);
  457.             }
  458.         }
  459.        
  460.         internal ArrayWithSize ProxySideDynamicSinks {
  461.             get {
  462.                 if (_dph == null) {
  463.                     return null;
  464.                 }
  465.                 else {
  466.                     return _dph.DynamicSinks;
  467.                 }
  468.             }
  469.         }
  470.        
  471.         #if _DEBUG
  472.         public override string ToString()
  473.         {
  474.             return ("IDENTITY: " + " URI = " + _ObjURI);
  475.         }
  476.         #endif
  477.     }
  478. }

Developer Fusion