Identity.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FXUpdate3074 / FXUpdate3074 / 1.1 / untmp / whidbey / QFE / ndp / clr / src / BCL / System / Runtime / Remoting / Identity.cs / 2 / Identity.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
namespace System.Runtime.Remoting {
    using System.Globalization; 
    using System.Runtime.Remoting; 
    using System.Runtime.Remoting.Contexts;
    using System.Runtime.Remoting.Messaging; 
    using System.Runtime.Remoting.Activation;
    using System.Runtime.Remoting.Lifetime;
    using System.Security.Cryptography;
    using Microsoft.Win32; 
    using System.Threading;
    using System; 
    //  Identity is the base class for remoting identities. An instance of Identity (or a derived class) 
    //  is associated with each instance of a remoted object. Likewise, an instance of Identity is
    //  associated with each instance of a remoting proxy. 
    //
    using System.Collections;
    internal class Identity {
        // We use a Guid to create a URI from. Each time a new URI is needed we increment 
        // the sequence number and append it to the statically inited Guid.
        // private static readonly Guid IDGuid = Guid.NewGuid(); 
 
        internal static String ProcessIDGuid
        { 
            get
            {
                return SharedStatics.Remoting_Identity_IDGuid;
            } 
        }
 
        // We need the original and the configured one because we have to compare 
        //   both when looking at a uri since something might be marshalled before
        //   the id is set. 
        private static String s_originalAppDomainGuid = Guid.NewGuid().ToString().Replace('-', '_');
        private static String s_configuredAppDomainGuid = null;

        internal static String AppDomainUniqueId 
        {
            get 
            { 
                if (s_configuredAppDomainGuid != null)
                    return s_configuredAppDomainGuid; 
                else
                    return s_originalAppDomainGuid;
            } // get
 
        } // AppDomainGuid
 
        private static String s_originalAppDomainGuidString = "/" + s_originalAppDomainGuid.ToLower(CultureInfo.InvariantCulture) + "/"; 
        private static String s_configuredAppDomainGuidString = null;
 
        private static String s_IDGuidString = "/" + s_originalAppDomainGuid.ToLower(CultureInfo.InvariantCulture) + "/";

        // Used to get random numbers
        private static RNGCryptoServiceProvider s_rng = new RNGCryptoServiceProvider(); 

        internal static String IDGuidString 
        { 
            get { return s_IDGuidString; }
        } 


        internal static String RemoveAppNameOrAppGuidIfNecessary(String uri)
        { 
            // uri is assumed to be in lower-case at this point
 
            // If the uri starts with either, "//" or "//" we 
            //   should strip that off.
 
            // We only need to look further if the uri starts with a "/".
            if ((uri == null) || (uri.Length <= 1) || (uri[0] != '/'))
                return uri;
 
            // compare to process guid (guid string already has slash at beginnning and end)
            String guidStr; 
            if (s_configuredAppDomainGuidString != null) 
            {
                guidStr = s_configuredAppDomainGuidString; 
                if (uri.Length > guidStr.Length)
                {
                    if (StringStartsWith(uri, guidStr))
                    { 
                        // remove "//"
                        return uri.Substring(guidStr.Length); 
                    } 
                }
            } 

            // always need to

            guidStr = s_originalAppDomainGuidString; 
            if (uri.Length > guidStr.Length)
            { 
                if (StringStartsWith(uri, guidStr)) 
                {
                    // remove "//" 
                    return uri.Substring(guidStr.Length);
                }
            }
 
            // compare to application name (application name will never have slashes)
            String appName = RemotingConfiguration.ApplicationName; 
            if (appName != null) 
            {
                // add +2 to appName length for surrounding slashes 
                if (uri.Length > (appName.Length + 2))
                {
                    if (String.Compare(uri, 1, appName, 0, appName.Length, true, CultureInfo.InvariantCulture) == 0)
                    { 
                        // now, make sure there is a slash after "/" in uri
                        if (uri[appName.Length + 1] == '/') 
                        { 
                            // remove "//"
                            return uri.Substring(appName.Length + 2); 
                        }
                    }
                }
            } 

            // it didn't start with "//" or "//", so just remove the 
            //   first slash and return. 
            uri = uri.Substring(1);
            return uri; 
        } // RemoveAppNameOrAppGuidIfNecessary


        private static bool StringStartsWith(String s1, String prefix) 
        {
            // String.StartsWith uses String.Compare instead of String.CompareOrdinal, 
            //   so we provide our own implementation of StartsWith. 

            if (s1.Length < prefix.Length) 
                return false;

            return (String.CompareOrdinal(s1, 0, prefix, 0, prefix.Length) == 0);
        } // StringStartsWith 

 
 
        // DISCONNECTED_FULL denotes that the object is disconnected
        // from both local & remote (x-appdomain & higher) clients 

        // DISCONNECTED_REM denotes that the object is disconnected
        // from remote (x-appdomain & higher) clients ... however
        // x-context proxies continue to work as expected. 

        protected const int IDFLG_DISCONNECTED_FULL= 0x00000001; 
        protected const int IDFLG_DISCONNECTED_REM = 0x00000002; 
        protected const int IDFLG_IN_IDTABLE       = 0x00000004;
 
        protected const int IDFLG_CONTEXT_BOUND    = 0x00000010;
        protected const int IDFLG_WELLKNOWN        = 0x00000100;
        protected const int IDFLG_SERVER_SINGLECALL= 0x00000200;
        protected const int IDFLG_SERVER_SINGLETON = 0x00000400; 

        internal int _flags; 
 
        internal Object _tpOrObject;
        protected String _ObjURI; 
        protected String _URL;

        // These have to be "Object" to use Interlocked operations
        internal Object _objRef; 
        internal Object _channelSink;
 
        // Remoting proxy has this field too, we use the latter only for 
        // ContextBoundObject identities.
        internal Object _envoyChain; 

        // This manages the dynamically registered sinks for the proxy.
        internal DynamicPropertyHolder _dph;
 
        // Lease for object
        internal Lease _lease; 
 
        internal static String ProcessGuid {get {return ProcessIDGuid;}}
 
        private static int GetNextSeqNum()
        {
            return SharedStatics.Remoting_Identity_GetNextSeqNum();
        } 

        private static Byte[] GetRandomBytes() 
        { 
            // PERF? In a situation where objects need URIs at a very fast
            // rate, we will end up creating too many of these tiny byte-arrays 
            // causing pressure on GC!
            // One option would be to have a buff in the managed thread class
            // and use that to get a chunk of random bytes consuming
            // 18 bytes at a time. 
            // This would avoid the need to have a lock across threads.
            Byte[] randomBytes = new byte[18]; 
            s_rng.GetBytes(randomBytes); 
            return randomBytes;
        } 


        // Constructs a new identity using the given the URI. This is used for
        // creating client side identities. 
        //
        // 
        internal Identity(String objURI, String URL) 
        {
            BCLDebug.Assert(objURI!=null,"objURI should not be null here"); 
            if (URL != null)
            {
                _flags |= IDFLG_WELLKNOWN;
                _URL = URL; 
            }
            SetOrCreateURI(objURI, true /*calling from ID ctor*/); 
        } 

        // Constructs a new identity. This is used for creating server side 
        // identities. The URI for server side identities is lazily generated
        // during the first call to Marshal because if we associate a URI with the
        // object at the time of creation then you cannot call Marshal with a
        // URI of your own choice. 
        //
        // 
        internal Identity(bool bContextBound) 
        {
            if(bContextBound) 
                _flags |= IDFLG_CONTEXT_BOUND;
        }

        internal bool IsContextBound { 
            get  {
                return (_flags&IDFLG_CONTEXT_BOUND) == IDFLG_CONTEXT_BOUND; 
            } 
        }
 
        internal bool IsWellKnown()
        {
            return (_flags&IDFLG_WELLKNOWN) == IDFLG_WELLKNOWN;
        } 

        internal void SetInIDTable() 
        { 
            while(true) {
                int currentFlags = _flags; 
                int newFlags = _flags | IDFLG_IN_IDTABLE;
                if(currentFlags == Interlocked.CompareExchange(ref _flags, newFlags, currentFlags))
                    break;
            } 
        }
 
        internal void ResetInIDTable(bool bResetURI) 
        {
            BCLDebug.Assert(IdentityHolder.TableLock.IsWriterLockHeld, "IDTable should be write-locked"); 
            while(true) {
                int currentFlags = _flags;
                int newFlags = _flags & (~IDFLG_IN_IDTABLE);
                if(currentFlags == Interlocked.CompareExchange(ref _flags, newFlags, currentFlags)) 
                    break;
            } 
            // bResetURI is true for the external API call to Disconnect, it is 
            // false otherwise. Thus when a user Disconnects an object
            // its URI will get reset but if lifetime service times it out 
            // it will not clear out the URIs
            if (bResetURI)
            {
                ((ObjRef)_objRef).URI = null; 
                _ObjURI = null;
            } 
        } 

        internal bool IsInIDTable() 
        {
            return((_flags & IDFLG_IN_IDTABLE) == IDFLG_IN_IDTABLE);
        }
 
        internal void SetFullyConnected()
        { 
            BCLDebug.Assert( 
                this is ServerIdentity,
                "should be setting these flags for srvIDs only!"); 
            BCLDebug.Assert(
                (_ObjURI != null),
                "Object must be assigned a URI to be fully connected!");
 
            while(true) {
                int currentFlags = _flags; 
                int newFlags = _flags & (~(IDFLG_DISCONNECTED_FULL | IDFLG_DISCONNECTED_REM)); 
                if(currentFlags == Interlocked.CompareExchange(ref _flags, newFlags, currentFlags))
                    break; 
            }
        }

        internal bool IsFullyDisconnected() 
        {
            BCLDebug.Assert( 
                this is ServerIdentity, 
                "should be setting these flags for srvIDs only!");
            return (_flags&IDFLG_DISCONNECTED_FULL) == IDFLG_DISCONNECTED_FULL; 
        }

        internal bool IsRemoteDisconnected()
        { 
            BCLDebug.Assert(
                this is ServerIdentity, 
                "should be setting these flags for srvIDs only!"); 
            return (_flags&IDFLG_DISCONNECTED_REM) == IDFLG_DISCONNECTED_REM;
        } 

        internal bool IsDisconnected()
        {
            BCLDebug.Assert( 
                this is ServerIdentity,
                "should be setting these flags for srvIDs only!"); 
            return (IsFullyDisconnected() || IsRemoteDisconnected()); 
        }
 
        // Get the URI
        internal String URI
        {
            get 
            {
                if(IsWellKnown()) 
                { 
                    return _URL;
                } 
                else
                {
                    return _ObjURI;
                } 
            }
        } 
 
        internal String ObjURI
        { 
            get { return _ObjURI; }
        }

        internal MarshalByRefObject TPOrObject 
        {
            get 
            { 
                return (MarshalByRefObject) _tpOrObject;
            } 
        }

       //   Set the transparentProxy field protecting against races. The returned transparent
       //   proxy could be different than the one the caller is attempting to set. 
       //
        internal Object  RaceSetTransparentProxy(Object tpObj) 
        { 
            if (_tpOrObject == null)
                Interlocked.CompareExchange(ref _tpOrObject, tpObj, null); 
            return _tpOrObject;
        }

        // Get the ObjRef. 
        internal ObjRef ObjectRef
        { 
            get 
            {
                return (ObjRef) _objRef; 
            }
        }

       //   Set the objRef field protecting against races. The returned objRef 
       //   could be different than the one the caller is attempting to set.
       // 
        internal ObjRef  RaceSetObjRef(ObjRef objRefGiven) 
        {
            if (_objRef == null) 
            {
                Interlocked.CompareExchange(ref _objRef, objRefGiven, null);
            }
            return (ObjRef) _objRef; 
        }
 
 
        // Get the ChannelSink.
        internal IMessageSink ChannelSink 
        {
            get { return (IMessageSink) _channelSink;}
        }
 
       //   Set the channelSink field protecting against races. The returned
       //   channelSink proxy could be different than the one the caller is 
       //   attempting to set. 
       //
        internal IMessageSink  RaceSetChannelSink(IMessageSink channelSink) 
        {
            if (_channelSink == null)
            {
                Interlocked.CompareExchange( 
                                        ref _channelSink,
                                        channelSink, 
                                        null); 
            }
            return (IMessageSink) _channelSink; 
        }

        // Get/Set the Envoy Sink chain..
        internal IMessageSink EnvoyChain 
        {
            get 
            { 
                return (IMessageSink)_envoyChain;
            } 
        }

        // Get/Set Lease
        internal Lease Lease 
        {
            get 
            { 
                return _lease;
            } 
            set
            {
                _lease = value;
            } 
        }
 
 
       //   Set the channelSink field protecting against races. The returned
       //   channelSink proxy could be different than the one the caller is 
       //   attempting to set.
       //
        internal IMessageSink RaceSetEnvoyChain(
                    IMessageSink envoyChain) 
        {
            if (_envoyChain == null) 
            { 
                Interlocked.CompareExchange(
                                ref _envoyChain, 
                                envoyChain,
                                null);
            }
            return (IMessageSink) _envoyChain; 
        }
 
        // A URI is lazily generated for the identity based on a GUID. 
        // Well known objects supply their own URI
        internal void SetOrCreateURI(String uri) 
        {
            SetOrCreateURI(uri, false);
        }
 
        internal void SetOrCreateURI(String uri, bool bIdCtor)
        { 
            if(bIdCtor == false) 
            {
                // This method is called either from the ID Constructor or 
                // with a writeLock on the ID Table
                BCLDebug.Assert(IdentityHolder.TableLock.IsWriterLockHeld, "IDTable should be write-locked");
                if (null != _ObjURI) {
                    throw new RemotingException( 
                        Environment.GetResourceString("Remoting_SetObjectUriForMarshal__UriExists"));
                } 
            } 

            if(null == uri) 
            {
                // We insert the tick count, so that the uri is not 100% predictable.
                // (i.e. perhaps we should
                String random = System.Convert.ToBase64String(GetRandomBytes()); 
                // Need to replace the '/' with '_' since '/' is not a valid uri char
                _ObjURI = (IDGuidString + random.Replace('/',  '_') + "_" + GetNextSeqNum() + ".rem").ToLower(CultureInfo.InvariantCulture); 
            } 
            else
            { 
                if (this is ServerIdentity)
                    _ObjURI = IDGuidString + uri;
                else
                    _ObjURI = uri; 
            }
        } // SetOrCreateURI 
 
        // This is used by ThreadAffinity/Synchronization contexts
        // (Shares the seqNum space with URIs) 
        internal static String GetNewLogicalCallID()
        {
            return IDGuidString + GetNextSeqNum();
        } 

        [System.Diagnostics.Conditional("_DEBUG")] 
        internal virtual void AssertValid() 
        {
            if (URI != null) 
            {
                Identity resolvedIdentity = IdentityHolder.ResolveIdentity(URI);
                BCLDebug.Assert(
                    (resolvedIdentity == null) || (resolvedIdentity == this), 
                    "Server ID mismatch with URI");
            } 
        } 

        internal bool AddProxySideDynamicProperty(IDynamicProperty prop) 
        {
            lock(this)
            {
                if (_dph == null) 
                {
                    DynamicPropertyHolder dph = new DynamicPropertyHolder(); 
                    lock(this) 
                    {
                        if (_dph == null) 
                        {
                            _dph = dph;
                        }
                    } 
                }
                return _dph.AddDynamicProperty(prop); 
            } 
        }
 
        internal bool RemoveProxySideDynamicProperty(String name)
        {
            lock(this)
            { 
                if (_dph == null)
                { 
                    throw new RemotingException( 
                        String.Format(
                            CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Contexts_NoProperty"), 
                            name));
                }
                return _dph.RemoveDynamicProperty(name);
            } 
        }
 
        internal ArrayWithSize ProxySideDynamicSinks 
        {
            get 
            {
                if (_dph == null)
                {
                    return null; 
                }
                else 
                { 
                    return _dph.DynamicSinks;
                } 
            }
        }

    #if _DEBUG 
        public override String ToString()
        { 
            return ("IDENTITY: " + " URI = " + _ObjURI); 
        }
    #endif 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK