AuthenticationManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / Net / System / Net / AuthenticationManager.cs / 3 / AuthenticationManager.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Net { 
 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Configuration;
    using System.Globalization;
    using System.Net.Configuration; 
    using System.Reflection;
    using System.Security.Authentication.ExtendedProtection; 
    using System.Security.Permissions; 
    using System;
    using System.Threading; 


    //
    // A contract that applications can use to restrict auth scenarios in current appDomain 
    //
    public interface ICredentialPolicy 
    { 
        bool ShouldSendCredential(Uri challengeUri, WebRequest request, NetworkCredential credential, IAuthenticationModule authenticationModule);
    } 

    /// 
    ///    Manages the authentication modules called during the client authentication
    ///       process. 
    /// 
    public class AuthenticationManager { 
 
        //also used as a lock object
        private static PrefixLookup s_ModuleBinding = new PrefixLookup(); 

        private static ArrayList s_ModuleList;
        private static ICredentialPolicy s_ICredentialPolicy;
        private static SpnDictionary m_SpnDictionary = new SpnDictionary(); 

        // not creatable... 
        // 
        private AuthenticationManager() {
        } 

        //
        //
        // 
        public static ICredentialPolicy CredentialPolicy {
            get { 
                return s_ICredentialPolicy; 
            }
            set { 
                ExceptionHelper.ControlPolicyPermission.Demand();
                s_ICredentialPolicy = value;
            }
        } 
        //
        // 
        public static StringDictionary CustomTargetNameDictionary { 
            get {return m_SpnDictionary;}
        } 
        //
        // This will give access to some internal methods
        //
        internal static SpnDictionary SpnDictionary { 
            get {return m_SpnDictionary;}
        } 
 
        //
        // 
        internal static void EnsureConfigLoaded() {
            try {
                object o = ModuleList;
            } 
            catch (Exception e) {
                if (e is ThreadAbortException || e is OutOfMemoryException || e is StackOverflowException) 
                    throw; 
                // A Config System has circular dependency on HttpWebRequest so they call this method to
                // trigger the config. For some reason they don't want any exceptions from here. 
            }
            catch {
                // A Config System has circular dependency on HttpWebRequest so they call this method to
                // trigger the config. For some reason they don't want any exceptions from here. 
            }
        } 
 
        //
        // ModuleList - static initialized property - 
        //  contains list of Modules used for Authentication
        //

        private static ArrayList ModuleList { 

            get { 
 
                //
                // GetConfig() might use us, so we have a circular dependency issue, 
                // that causes us to nest here, we grab the lock, only
                // if we haven't initialized, or another thread is busy in initialization
                //
 
                if (s_ModuleList == null) {
                    lock (s_ModuleBinding) { 
                        if (s_ModuleList == null) { 
                            GlobalLog.Print("AuthenticationManager::Initialize(): calling ConfigurationManager.GetSection()");
 
                            // This will never come back as null. Additionally, it will
                            // have the items the user wants available.
                            List authenticationModuleTypes =  AuthenticationModulesSectionInternal.GetSection().AuthenticationModules;
 
                            //
                            // Should be registered in a growing list of encryption/algorithm strengths 
                            //  basically, walk through a list of Types, and create new Auth objects 
                            //  from them.
                            // 
                            // order is meaningful here:
                            // load the registered list of auth types
                            // with growing level of encryption.
                            // 

                            ArrayList moduleList = new ArrayList(); 
                            IAuthenticationModule moduleToRegister; 
                            foreach (Type type in authenticationModuleTypes){
                                try { 
                                    moduleToRegister = Activator.CreateInstance(type,
                                                        BindingFlags.CreateInstance
                                                        | BindingFlags.Instance
                                                        | BindingFlags.NonPublic 
                                                        | BindingFlags.Public,
                                                        null,          // Binder 
                                                        new object[0], // no arguments 
                                                        CultureInfo.InvariantCulture
                                                        ) as IAuthenticationModule; 
                                    if (moduleToRegister != null) {
                                        GlobalLog.Print("WebRequest::Initialize(): Register:" + moduleToRegister.AuthenticationType);
                                        RemoveAuthenticationType(moduleList, moduleToRegister.AuthenticationType);
                                        moduleList.Add(moduleToRegister); 
                                    }
                                } 
                                catch (Exception exception) { 
                                    //
                                    // ignore failure (log exception for debugging) 
                                    //
                                    GlobalLog.Print("AuthenticationManager::constructor failed to initialize: " + exception.ToString());
                                }
                                catch { 
                                    //
                                    // ignore failure (log exception for debugging) 
                                    // 
                                    GlobalLog.Print("AuthenticationManager::constructor failed to initialize:  Non-CLS Compliant Exception");
                                } 
                            }

                            s_ModuleList = moduleList;
                        } 
                    }
                } 
 
                return s_ModuleList;
            } 
        }


        private static void RemoveAuthenticationType(ArrayList list, string typeToRemove) { 
            for (int i=0; i< list.Count; ++i) {
                if (string.Compare(((IAuthenticationModule)list[i]).AuthenticationType, typeToRemove, StringComparison.OrdinalIgnoreCase) ==0) { 
                    list.RemoveAt(i); 
                    break;
                } 

            }
        }
 
        /// 
        ///    Call each registered authentication module to determine the first module that 
        ///       can respond to the authentication request. 
        /// 
        public static Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials) { 
            //
            // parameter validation
            //
            if (request == null) { 
                throw new ArgumentNullException("request");
            } 
            if (credentials == null) { 
                throw new ArgumentNullException("credentials");
            } 
            if (challenge==null) {
                throw new ArgumentNullException("challenge");
            }
 
            GlobalLog.Print("AuthenticationManager::Authenticate() challenge:[" + challenge + "]");
 
            Authorization response = null; 

            HttpWebRequest httpWebRequest = request as HttpWebRequest; 
            if (httpWebRequest != null && httpWebRequest.CurrentAuthenticationState.Module != null)
            {
                response = httpWebRequest.CurrentAuthenticationState.Module.Authenticate(challenge, request, credentials);
            } 
            else
            { 
                // This is the case where we would try to find the module on the first server challenge 
                lock (s_ModuleBinding) {
                    // 
                    // fastest way of iterating on the ArryList
                    //
                    for (int i = 0; i < ModuleList.Count; i++) {
                        IAuthenticationModule authenticationModule = (IAuthenticationModule)ModuleList[i]; 
                        //
                        // the AuthenticationModule will 
                        // 1) return a valid string on success 
                        // 2) return null if it knows it cannot respond
                        // 3) throw if it could have responded but unexpectedly failed to do so 
                        //
                        if (httpWebRequest != null) {
                            httpWebRequest.CurrentAuthenticationState.Module = authenticationModule;
                        } 
                        response = authenticationModule.Authenticate(challenge, request, credentials);
 
                        if (response!=null) { 
                            //
                            // found the Authentication Module, return it 
                            //
                            GlobalLog.Print("AuthenticationManager::Authenticate() found IAuthenticationModule:[" + authenticationModule.AuthenticationType + "]");
                            break;
                        } 
                    }
                } 
            } 

            return response; 
        }

        // These four authentication modules require a Channel Binding Token to be able to preauthenticate over https.
        // After a successful authentication, they will cache the CBT used on the ServicePoint.  In order to PreAuthenticate, 
        // they require that a CBT has previously been cached.  Any other module should be allowed to try preauthentication
        // without a cached CBT. 
        private static bool ModuleRequiresChannelBinding(IAuthenticationModule authenticationModule) 
        {
            return (authenticationModule is NtlmClient || authenticationModule is KerberosClient || 
                    authenticationModule is NegotiateClient || authenticationModule is DigestClient);
        }

        ///  
        ///    Pre-authenticates a request.
        ///  
        public static Authorization PreAuthenticate(WebRequest request, ICredentials credentials) { 
            GlobalLog.Print("AuthenticationManager::PreAuthenticate() request:" + ValidationHelper.HashString(request) + " credentials:" + ValidationHelper.HashString(credentials));
            if (request == null) { 
                throw new ArgumentNullException("request");
            }
            if (credentials == null) {
                return null; 
            }
 
            HttpWebRequest httpWebRequest = request as HttpWebRequest; 
            IAuthenticationModule authenticationModule;
            if (httpWebRequest == null) 
                return null;

            //
            // PrefixLookup is thread-safe 
            //
            string moduleName = s_ModuleBinding.Lookup(httpWebRequest.ChallengedUri.AbsoluteUri) as string; 
            GlobalLog.Print("AuthenticationManager::PreAuthenticate() s_ModuleBinding.Lookup returns:" + ValidationHelper.ToString(moduleName)); 
            if (moduleName == null)
                return null; 
            authenticationModule = findModule(moduleName);
            if (authenticationModule == null)
            {
                // The module could have been unregistered 
                // No preauthentication is possible
                return null; 
            } 

            // prepopulate the channel binding token so we can try preauth 
            if (httpWebRequest.ChallengedUri.Scheme == Uri.UriSchemeHttps)
            {
                object binding = httpWebRequest.ServicePoint.CachedChannelBinding;
 
                // If the authentication module does CBT, we require that it also caches channel bindings.
                System.Diagnostics.Debug.Assert(!(binding == null && ModuleRequiresChannelBinding(authenticationModule))); 
 
                // can also be DBNull.Value, indicating "we previously succeeded without getting a CBT."
                // (ie, unpatched SSP talking to a partially-hardened server) 
                ChannelBinding channelBinding = binding as ChannelBinding;
                if (channelBinding != null)
                {
                    httpWebRequest.CurrentAuthenticationState.TransportContext = new CachedTransportContext(channelBinding); 
                }
            } 
 
            // Otherwise invoke the PreAuthenticate method
            // we're guaranteed that CanPreAuthenticate is true because we check before calling BindModule() 
            Authorization authorization = authenticationModule.PreAuthenticate(request, credentials);

            if (authorization != null && !authorization.Complete && httpWebRequest != null)
                httpWebRequest.CurrentAuthenticationState.Module = authenticationModule; 

            GlobalLog.Print("AuthenticationManager::PreAuthenticate() IAuthenticationModule.PreAuthenticate() returned authorization:" + ValidationHelper.HashString(authorization)); 
            return authorization; 
        }
 

        /// 
        ///    Registers an authentication module with the authentication manager.
        ///  
        public static void Register(IAuthenticationModule authenticationModule) {
            ExceptionHelper.UnmanagedPermission.Demand(); 
            if (authenticationModule == null) { 
                throw new ArgumentNullException("authenticationModule");
            } 
            GlobalLog.Print("AuthenticationManager::Register() registering :[" + authenticationModule.AuthenticationType + "]");
            lock (s_ModuleBinding) {
                IAuthenticationModule existentModule = findModule(authenticationModule.AuthenticationType);
                if (existentModule != null) { 
                    ModuleList.Remove(existentModule);
                } 
                ModuleList.Add(authenticationModule); 
            }
        } 

        /// 
        ///    Unregisters authentication modules for an authentication scheme.
        ///  
        public static void Unregister(IAuthenticationModule authenticationModule) {
            ExceptionHelper.UnmanagedPermission.Demand(); 
            if (authenticationModule == null) { 
                throw new ArgumentNullException("authenticationModule");
            } 
            GlobalLog.Print("AuthenticationManager::Unregister() unregistering :[" + authenticationModule.AuthenticationType + "]");
            lock (s_ModuleBinding) {
                if (!ModuleList.Contains(authenticationModule)) {
                    throw new InvalidOperationException(SR.GetString(SR.net_authmodulenotregistered)); 
                }
                ModuleList.Remove(authenticationModule); 
            } 
        }
        ///  
        ///    Unregisters authentication modules for an authentication scheme.
        /// 
        public static void Unregister(string authenticationScheme) {
            ExceptionHelper.UnmanagedPermission.Demand(); 
            if (authenticationScheme == null) {
                throw new ArgumentNullException("authenticationScheme"); 
            } 
            GlobalLog.Print("AuthenticationManager::Unregister() unregistering :[" + authenticationScheme + "]");
            lock (s_ModuleBinding) { 
                IAuthenticationModule existentModule = findModule(authenticationScheme);
                if (existentModule == null) {
                    throw new InvalidOperationException(SR.GetString(SR.net_authschemenotregistered));
                } 
                ModuleList.Remove(existentModule);
            } 
        } 

        ///  
        ///    
        ///       Returns a list of registered authentication modules.
        ///    
        ///  
        public static IEnumerator RegisteredModules {
            get { 
                return ModuleList.GetEnumerator(); 
            }
        } 

        /// 
        ///    
        ///       Binds an authentication response to a request for pre-authentication. 
        ///    
        ///  
        // Create binding between an authorization response and the module 
        // generating that response
        // This association is used for deciding which module to invoke 
        // for preauthentication purposes
        internal static void BindModule(Uri uri, Authorization response, IAuthenticationModule module) {
            GlobalLog.Assert(module.CanPreAuthenticate, "AuthenticationManager::BindModule()|module.CanPreAuthenticate == false");
            if (response.ProtectionRealm!=null) { 
                // The authentication module specified which Uri prefixes
                // will be preauthenticated 
                string[] prefix = response.ProtectionRealm; 

                for (int k=0; k=signature.Length) {
                int firstQuote = -1, secondQuote = -1;
                for (int i = 0; i < challenge.Length; i++) 
                {
                    if (challenge[i]=='\"') 
                    { 
                        if (firstQuote <= secondQuote)
                            firstQuote = i; 
                        else
                            secondQuote = i;
                    }
 
                    if (i==challenge.Length-1 || (challenge[i]=='\"' && firstQuote>secondQuote))
                    { 
                        // see if the portion of challenge out of the quotes contains 
                        // the signature of the IAuthenticationModule
                        if (i==challenge.Length-1) 
                            firstQuote = challenge.Length;

                        if (firstQuote=0)
                        { 
                            if ((index==0 || challenge[index-1]==' ' || challenge[index-1]==',') &&
                                (index+signature.Length==challenge.Length || challenge[index+signature.Length]==' ' || challenge[index+signature.Length]==','))
                            {
                                break; 
                            }
                            index = -1; 
                        } 
                    }
                } 
            }
            GlobalLog.Print("AuthenticationManager::FindSubstringNotInQuotes(" + challenge + ", " + signature + ")=" + index.ToString());
            return index;
        } 
        //
        private static int IndexOf(string challenge, string lwrCaseSignature, int start, int count) 
        { 
            count += start + 1 - lwrCaseSignature.Length;
            for (; start < count; ++start) 
            {
                int i = 0;
                for (; i < lwrCaseSignature.Length; ++i)
                { 
                    // force a challenge char to lowecase (safe assuming it works on trusted ASCII source)
                    if ((challenge[start+i] | 0x20) != lwrCaseSignature[i]) 
                        break; 
                }
                if (i == lwrCaseSignature.Length) 
                    return start;
            }
            return -1;
        } 
        //
        // this method is called by the IAuthenticationModule implementations 
        // (mainly Digest) to safely find their list of parameters in a challenge. 
        // it returns the index of the first ',' that is not included in quotes,
        // -1 is returned on error or end of string. on return offset contains the 
        // index of the first '=' that is not included in quotes, -1 if no '=' was found.
        //
        internal static int SplitNoQuotes(string challenge, ref int offset) {
            // GlobalLog.Print("SplitNoQuotes([" + challenge + "], " + offset.ToString() + ")"); 
            //
            // save offset 
            // 
            int realOffset = offset;
            // 
            // default is not found
            //
            offset = -1;
 
            if (challenge != null && realOffsetsecondQuote means we are in a quoted string
                    //
                    if (firstQuote>secondQuote && challenge[i]=='\\' && i+1 < challenge.Length && challenge[i+1]=='\"') {
                        // 
                        // skip <\"> when in a quoted string
                        // 
                        i++; 
                    }
                    else if (challenge[i]=='\"') { 
                        if (firstQuote <= secondQuote) {
                            firstQuote = i;
                        }
                        else { 
                            secondQuote = i;
                        } 
                    } 
                    else if (challenge[i]=='=' && firstQuote<=secondQuote && offset<0) {
                        offset = i; 
                    }
                    else if (challenge[i]==',' && firstQuote<=secondQuote) {
                        return i;
                    } 
                }
            } 
 
            return -1;
        } 

#if !FEATURE_PAL
        internal static Authorization GetGroupAuthorization(IAuthenticationModule thisModule, string token, bool finished, NTAuthentication authSession, bool shareAuthenticatedConnections, bool mutualAuth) {
            return 
                new Authorization(
                    token, 
                    finished, 
                    (shareAuthenticatedConnections) ? null : (thisModule.GetType().FullName + "/" + authSession.UniqueUserId),
                    mutualAuth); 

        }
#endif // !FEATURE_PAL
 

    }; // class AuthenticationManager 
 
    //
    // This internal class implements a data structure which can be 
    // used for storing a set of objects keyed by string prefixes
    // Looking up an object given a string returns the value associated
    // with the longest matching prefix
    // (A prefix "matches" a string IFF the string starts with that prefix 
    // The degree of the match is prefix length)
    // 
    internal class PrefixLookup { 
        //
        // our prefix store (a Hashtable) needs to support multiple readers and multiple writers. 
        // the documentation on Hashtable says:
        // "A Hashtable can safely support one writer and multiple readers concurrently.
        // To support multiple writers, all operations must be done through the wrapper
        // returned by the Synchronized method." 
        // it's safe enough, for our use, to just synchronize (with a call to lock()) all write operations
        // so we always fall in the supported "one writer and multiple readers" scenario. 
        // 
        private Hashtable m_Store = new Hashtable();
 
        internal void Add(string prefix, object value) {
            // Hashtable will overwrite existing key
            lock (m_Store) {
                // writers are locked 
                m_Store[prefix] = value;
            } 
        } 

        /* 
        internal void Remove(string prefix) {
            // Hashtable will be unchanged if key is not existing
            lock (m_Store) {
                // writers are locked 
                m_Store.Remove(prefix);
            } 
        } 
        */
 
        internal object Lookup(string lookupKey) {
            if (lookupKey==null) {
                return null;
            } 
            object mostSpecificMatch = null;
            int longestMatchPrefix = 0; 
            int prefixLen; 
            lock (m_Store) {
                // 
                // readers don't need to be locked, but we lock() because:
                // "The enumerator does not have exclusive access to the collection.
                //
                // When an enumerator is instantiated, it takes a snapshot of the current state 
                // of the collection. If changes are made to the collection, such as adding,
                // modifying or deleting elements, the snapshot gets out of [....] and the 
                // enumerator throws an InvalidOperationException. Two enumerators instantiated 
                // from the same collection at the same time can have different snapshots of the
                // collection." 
                //
                // enumerate through every credential in the cache
                //
                string prefix; 
                foreach (DictionaryEntry entry in m_Store) {
                    prefix = (string)entry.Key; 
                    if (lookupKey.StartsWith(prefix)) { 
                        prefixLen = prefix.Length;
                        // 
                        // check if the match is better than the current-most-specific match
                        //
                        if (prefixLen>longestMatchPrefix) {
                            // 
                            // Yes-- update the information about currently preferred match
                            // 
                            longestMatchPrefix = prefixLen; 
                            mostSpecificMatch = entry.Value;
                        } 
                    }
                }
            }
            return mostSpecificMatch; 
        }
 
/* 
    //
    // This is the core implementation of a general prefix string table 
    // The keys are all converted to lowercase
    //
    internal struct PrefixTable: ICollection {
 
        internal enum Action {
            Find, 
            Insert, 
            Remove
        } 

        private DictionaryEntry[]  m_Entries;

        internal object this[string key] { 
            get {
                DictionaryEntry[] local = m_Entries; 
                int idx = BinaryFindInsertRemove(ref local, key, Action.Find); 
                if (idx < 0) {
                    return null; 
                }
                return local[idx].Value;
            }
        } 

        internal void Set(string key, object value) { 
            DictionaryEntry[] local = m_Entries; 
            int idx = BinaryFindInsertRemove(ref local, key, Action.Insert);
            if (idx < 0) { 
                //need to add a new entry
                local[~idx].Key   = key;
                local[~idx].Value = value;
                m_Entries = local; 
            }
            else { 
                local[idx].Value  = value; 
            }
        } 

        internal void Remove(string key) {
            DictionaryEntry[] local = m_Entries;
            int idx = BinaryFindInsertRemove(ref local, key, Action.Remove); 
            if (idx >= 0) {
                //found and removed, update entries. 
                m_Entries = local; 
            }
        } 


        //
        // ICollection interfaces 
        //
 
        int ICollection.Count { 
            get {
                DictionaryEntry[] local = m_Entries; 
                return local == null? 0: local.Length;
            }
        }
 
        public bool IsSynchronized {
            get {return true;} 
        } 

        public IEnumerator GetEnumerator() { 
            return new DictionaryEnumerator(m_Entries);
        }

        object ICollection.SyncRoot { 
            get {return this;}
        } 
 
        void ICollection.CopyTo (Array array, int index) {
            DictionaryEntry[] local = m_Entries; 
            if (local == null) {
                return;
            }
            local.CopyTo(array, index); 
        }
 
        // 
        // Binary search and performing an action on a sorted array of prefixes
        // Derived from Array code, adopted for multithreading and substring search. 
        //
        // For Find returns either the matching prefix index or -1
        // For Insert returns either the matching index or ~pos for the first larger prefix in which case the slot is allocated.
        // For Remove returns -1 if not found or pos of successfully removed slot 
        //
        private unsafe static int BinaryFindInsertRemove(ref DictionaryEntry[] entries, string key, Action action) { 
 
            if (entries == null || entries.Length == 0) {
                if (action != Action.Insert) { 
                    return -1;
                }
                entries = new DictionaryEntry[1];
                return ~0; 
            }
 
            int lo = 0; 
            int hi = entries.Length-1;
 
            int lastPrefix = -1;
            fixed (char* pKey = key) {
                while (lo <= hi) {
                    int i = (lo + hi) >> 1; 
                    int c = ComparePrefix((string)entries[i].Key, pKey, key.Length);
                    if (c < 0) { 
                        if (c < -1) { 
                            lastPrefix = i;
                        } 
                        lo = i + 1;
                    }
                    else if (c > 0) {
                        hi = i - 1; 
                    }
                    else { 
                        //Exact match 
                        if (action == Action.Remove) {
                            DictionaryEntry[] newEntries = new DictionaryEntry[entries.Length-1]; 
                            if (i != 0) {
                                Array.Copy(entries, 0, newEntries, 0, i);
                            }
                            if (i != entries.Length-1) { 
                                Array.Copy(entries, i+1, newEntries, i, entries.Length-i-1);
                            } 
                            entries = newEntries; 
                        }
                        return i; 
                    }
                }
            }
 
            // Here 'lo' points to the closest "larger" key, i.e. the place to insert an new element to.
            // The lastPrefix if not -1, will point to the closest prefix match if found. 
 
            switch (action) {
            case Action.Remove: 
                            return -1;
            case Action.Insert:
                            DictionaryEntry[] newEntries = new DictionaryEntry[entries.Length+1];
                            if (lo != 0) { 
                                Array.Copy(entries, 0, newEntries, 0, lo);
                            } 
                            if (lo != entries.Length) { 
                                Array.Copy(entries, lo, newEntries, lo+1, entries.Length-lo);
                            } 
                            entries = newEntries;
                            break;
            default:
                    // Assuming Find. 
                    if (lastPrefix >= 0) {
                        return lastPrefix; 
                    } 
                    return -1;
            } 
            return ~lo;
        }

 
        //
        // Performs bitwise string comparison assuming that both parameteres are in lower case 
        // +1  prefix is greater 
        // >+1 prefix is greater but only because the prefix length is greater
        // 0   equal 
        // -1  prefix is less
        // <-1 prefix is less but is THE prefix for the key
        private unsafe static int ComparePrefix(string prefix, char* key, int keyLength) {
            int len = prefix.Length < keyLength? prefix.Length: keyLength; 

            fixed (char* pPrefix = prefix) { 
                for (int i =0; i < len; ++i) { 
                    if (pPrefix[i] == key[i]) {
                        continue; 
                    }
                    else if (pPrefix[i] > key[i]) {
                        return 1;
                    } 
                    else {
                        return -1; 
                    } 
                }
            } 
            return (len == keyLength)
                        ? prefix.Length == keyLength ? 0: 8
                        : -8;
        } 
    }
 
    internal class DictionaryEnumerator: IDictionaryEnumerator { 
        DictionaryEntry[]   m_Entries;
        int                 m_CurIdx; 

        internal DictionaryEnumerator(DictionaryEntry[] entries) {
            if (entries == null) {
                entries = new DictionaryEntry[0]; 
            }
            m_Entries = entries; 
            m_CurIdx = -1; 
        }
 
        public Object Current {
            get {
                if (m_CurIdx < 0 || m_CurIdx >= m_Entries.Length) {
                    throw new InvalidOperationException("index"); 
                }
                return m_Entries[m_CurIdx]; 
            } 
        }
 
        public void Reset() {
            m_CurIdx = -1;
        }
 
        public bool MoveNext() {
            if (m_CurIdx >= m_Entries.Length) { 
                return false; 
            }
            ++m_CurIdx; 
            return m_CurIdx < m_Entries.Length;
        }

        public DictionaryEntry Entry { 
            get {
                if (m_CurIdx < 0 || m_CurIdx >= m_Entries.Length) { 
                    throw new InvalidOperationException("index"); 
                }
                return m_Entries[m_CurIdx]; 
            }
        }

        public object Key { 
            get {
                if (m_CurIdx < 0 || m_CurIdx >= m_Entries.Length) { 
                    throw new InvalidOperationException("index"); 
                }
                return m_Entries[m_CurIdx].Key; 
            }
        }

        public object Value { 
            get {
                if (m_CurIdx < 0 || m_CurIdx >= m_Entries.Length) { 
                    throw new InvalidOperationException("index"); 
                }
                return m_Entries[m_CurIdx].Value; 
            }
        }
    }
 
*/
 
    } // class PrefixLookup 

 
} // namespace System.Net

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

namespace System.Net { 
 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.Specialized;
    using System.Configuration;
    using System.Globalization;
    using System.Net.Configuration; 
    using System.Reflection;
    using System.Security.Authentication.ExtendedProtection; 
    using System.Security.Permissions; 
    using System;
    using System.Threading; 


    //
    // A contract that applications can use to restrict auth scenarios in current appDomain 
    //
    public interface ICredentialPolicy 
    { 
        bool ShouldSendCredential(Uri challengeUri, WebRequest request, NetworkCredential credential, IAuthenticationModule authenticationModule);
    } 

    /// 
    ///    Manages the authentication modules called during the client authentication
    ///       process. 
    /// 
    public class AuthenticationManager { 
 
        //also used as a lock object
        private static PrefixLookup s_ModuleBinding = new PrefixLookup(); 

        private static ArrayList s_ModuleList;
        private static ICredentialPolicy s_ICredentialPolicy;
        private static SpnDictionary m_SpnDictionary = new SpnDictionary(); 

        // not creatable... 
        // 
        private AuthenticationManager() {
        } 

        //
        //
        // 
        public static ICredentialPolicy CredentialPolicy {
            get { 
                return s_ICredentialPolicy; 
            }
            set { 
                ExceptionHelper.ControlPolicyPermission.Demand();
                s_ICredentialPolicy = value;
            }
        } 
        //
        // 
        public static StringDictionary CustomTargetNameDictionary { 
            get {return m_SpnDictionary;}
        } 
        //
        // This will give access to some internal methods
        //
        internal static SpnDictionary SpnDictionary { 
            get {return m_SpnDictionary;}
        } 
 
        //
        // 
        internal static void EnsureConfigLoaded() {
            try {
                object o = ModuleList;
            } 
            catch (Exception e) {
                if (e is ThreadAbortException || e is OutOfMemoryException || e is StackOverflowException) 
                    throw; 
                // A Config System has circular dependency on HttpWebRequest so they call this method to
                // trigger the config. For some reason they don't want any exceptions from here. 
            }
            catch {
                // A Config System has circular dependency on HttpWebRequest so they call this method to
                // trigger the config. For some reason they don't want any exceptions from here. 
            }
        } 
 
        //
        // ModuleList - static initialized property - 
        //  contains list of Modules used for Authentication
        //

        private static ArrayList ModuleList { 

            get { 
 
                //
                // GetConfig() might use us, so we have a circular dependency issue, 
                // that causes us to nest here, we grab the lock, only
                // if we haven't initialized, or another thread is busy in initialization
                //
 
                if (s_ModuleList == null) {
                    lock (s_ModuleBinding) { 
                        if (s_ModuleList == null) { 
                            GlobalLog.Print("AuthenticationManager::Initialize(): calling ConfigurationManager.GetSection()");
 
                            // This will never come back as null. Additionally, it will
                            // have the items the user wants available.
                            List authenticationModuleTypes =  AuthenticationModulesSectionInternal.GetSection().AuthenticationModules;
 
                            //
                            // Should be registered in a growing list of encryption/algorithm strengths 
                            //  basically, walk through a list of Types, and create new Auth objects 
                            //  from them.
                            // 
                            // order is meaningful here:
                            // load the registered list of auth types
                            // with growing level of encryption.
                            // 

                            ArrayList moduleList = new ArrayList(); 
                            IAuthenticationModule moduleToRegister; 
                            foreach (Type type in authenticationModuleTypes){
                                try { 
                                    moduleToRegister = Activator.CreateInstance(type,
                                                        BindingFlags.CreateInstance
                                                        | BindingFlags.Instance
                                                        | BindingFlags.NonPublic 
                                                        | BindingFlags.Public,
                                                        null,          // Binder 
                                                        new object[0], // no arguments 
                                                        CultureInfo.InvariantCulture
                                                        ) as IAuthenticationModule; 
                                    if (moduleToRegister != null) {
                                        GlobalLog.Print("WebRequest::Initialize(): Register:" + moduleToRegister.AuthenticationType);
                                        RemoveAuthenticationType(moduleList, moduleToRegister.AuthenticationType);
                                        moduleList.Add(moduleToRegister); 
                                    }
                                } 
                                catch (Exception exception) { 
                                    //
                                    // ignore failure (log exception for debugging) 
                                    //
                                    GlobalLog.Print("AuthenticationManager::constructor failed to initialize: " + exception.ToString());
                                }
                                catch { 
                                    //
                                    // ignore failure (log exception for debugging) 
                                    // 
                                    GlobalLog.Print("AuthenticationManager::constructor failed to initialize:  Non-CLS Compliant Exception");
                                } 
                            }

                            s_ModuleList = moduleList;
                        } 
                    }
                } 
 
                return s_ModuleList;
            } 
        }


        private static void RemoveAuthenticationType(ArrayList list, string typeToRemove) { 
            for (int i=0; i< list.Count; ++i) {
                if (string.Compare(((IAuthenticationModule)list[i]).AuthenticationType, typeToRemove, StringComparison.OrdinalIgnoreCase) ==0) { 
                    list.RemoveAt(i); 
                    break;
                } 

            }
        }
 
        /// 
        ///    Call each registered authentication module to determine the first module that 
        ///       can respond to the authentication request. 
        /// 
        public static Authorization Authenticate(string challenge, WebRequest request, ICredentials credentials) { 
            //
            // parameter validation
            //
            if (request == null) { 
                throw new ArgumentNullException("request");
            } 
            if (credentials == null) { 
                throw new ArgumentNullException("credentials");
            } 
            if (challenge==null) {
                throw new ArgumentNullException("challenge");
            }
 
            GlobalLog.Print("AuthenticationManager::Authenticate() challenge:[" + challenge + "]");
 
            Authorization response = null; 

            HttpWebRequest httpWebRequest = request as HttpWebRequest; 
            if (httpWebRequest != null && httpWebRequest.CurrentAuthenticationState.Module != null)
            {
                response = httpWebRequest.CurrentAuthenticationState.Module.Authenticate(challenge, request, credentials);
            } 
            else
            { 
                // This is the case where we would try to find the module on the first server challenge 
                lock (s_ModuleBinding) {
                    // 
                    // fastest way of iterating on the ArryList
                    //
                    for (int i = 0; i < ModuleList.Count; i++) {
                        IAuthenticationModule authenticationModule = (IAuthenticationModule)ModuleList[i]; 
                        //
                        // the AuthenticationModule will 
                        // 1) return a valid string on success 
                        // 2) return null if it knows it cannot respond
                        // 3) throw if it could have responded but unexpectedly failed to do so 
                        //
                        if (httpWebRequest != null) {
                            httpWebRequest.CurrentAuthenticationState.Module = authenticationModule;
                        } 
                        response = authenticationModule.Authenticate(challenge, request, credentials);
 
                        if (response!=null) { 
                            //
                            // found the Authentication Module, return it 
                            //
                            GlobalLog.Print("AuthenticationManager::Authenticate() found IAuthenticationModule:[" + authenticationModule.AuthenticationType + "]");
                            break;
                        } 
                    }
                } 
            } 

            return response; 
        }

        // These four authentication modules require a Channel Binding Token to be able to preauthenticate over https.
        // After a successful authentication, they will cache the CBT used on the ServicePoint.  In order to PreAuthenticate, 
        // they require that a CBT has previously been cached.  Any other module should be allowed to try preauthentication
        // without a cached CBT. 
        private static bool ModuleRequiresChannelBinding(IAuthenticationModule authenticationModule) 
        {
            return (authenticationModule is NtlmClient || authenticationModule is KerberosClient || 
                    authenticationModule is NegotiateClient || authenticationModule is DigestClient);
        }

        ///  
        ///    Pre-authenticates a request.
        ///  
        public static Authorization PreAuthenticate(WebRequest request, ICredentials credentials) { 
            GlobalLog.Print("AuthenticationManager::PreAuthenticate() request:" + ValidationHelper.HashString(request) + " credentials:" + ValidationHelper.HashString(credentials));
            if (request == null) { 
                throw new ArgumentNullException("request");
            }
            if (credentials == null) {
                return null; 
            }
 
            HttpWebRequest httpWebRequest = request as HttpWebRequest; 
            IAuthenticationModule authenticationModule;
            if (httpWebRequest == null) 
                return null;

            //
            // PrefixLookup is thread-safe 
            //
            string moduleName = s_ModuleBinding.Lookup(httpWebRequest.ChallengedUri.AbsoluteUri) as string; 
            GlobalLog.Print("AuthenticationManager::PreAuthenticate() s_ModuleBinding.Lookup returns:" + ValidationHelper.ToString(moduleName)); 
            if (moduleName == null)
                return null; 
            authenticationModule = findModule(moduleName);
            if (authenticationModule == null)
            {
                // The module could have been unregistered 
                // No preauthentication is possible
                return null; 
            } 

            // prepopulate the channel binding token so we can try preauth 
            if (httpWebRequest.ChallengedUri.Scheme == Uri.UriSchemeHttps)
            {
                object binding = httpWebRequest.ServicePoint.CachedChannelBinding;
 
                // If the authentication module does CBT, we require that it also caches channel bindings.
                System.Diagnostics.Debug.Assert(!(binding == null && ModuleRequiresChannelBinding(authenticationModule))); 
 
                // can also be DBNull.Value, indicating "we previously succeeded without getting a CBT."
                // (ie, unpatched SSP talking to a partially-hardened server) 
                ChannelBinding channelBinding = binding as ChannelBinding;
                if (channelBinding != null)
                {
                    httpWebRequest.CurrentAuthenticationState.TransportContext = new CachedTransportContext(channelBinding); 
                }
            } 
 
            // Otherwise invoke the PreAuthenticate method
            // we're guaranteed that CanPreAuthenticate is true because we check before calling BindModule() 
            Authorization authorization = authenticationModule.PreAuthenticate(request, credentials);

            if (authorization != null && !authorization.Complete && httpWebRequest != null)
                httpWebRequest.CurrentAuthenticationState.Module = authenticationModule; 

            GlobalLog.Print("AuthenticationManager::PreAuthenticate() IAuthenticationModule.PreAuthenticate() returned authorization:" + ValidationHelper.HashString(authorization)); 
            return authorization; 
        }
 

        /// 
        ///    Registers an authentication module with the authentication manager.
        ///  
        public static void Register(IAuthenticationModule authenticationModule) {
            ExceptionHelper.UnmanagedPermission.Demand(); 
            if (authenticationModule == null) { 
                throw new ArgumentNullException("authenticationModule");
            } 
            GlobalLog.Print("AuthenticationManager::Register() registering :[" + authenticationModule.AuthenticationType + "]");
            lock (s_ModuleBinding) {
                IAuthenticationModule existentModule = findModule(authenticationModule.AuthenticationType);
                if (existentModule != null) { 
                    ModuleList.Remove(existentModule);
                } 
                ModuleList.Add(authenticationModule); 
            }
        } 

        /// 
        ///    Unregisters authentication modules for an authentication scheme.
        ///  
        public static void Unregister(IAuthenticationModule authenticationModule) {
            ExceptionHelper.UnmanagedPermission.Demand(); 
            if (authenticationModule == null) { 
                throw new ArgumentNullException("authenticationModule");
            } 
            GlobalLog.Print("AuthenticationManager::Unregister() unregistering :[" + authenticationModule.AuthenticationType + "]");
            lock (s_ModuleBinding) {
                if (!ModuleList.Contains(authenticationModule)) {
                    throw new InvalidOperationException(SR.GetString(SR.net_authmodulenotregistered)); 
                }
                ModuleList.Remove(authenticationModule); 
            } 
        }
        ///  
        ///    Unregisters authentication modules for an authentication scheme.
        /// 
        public static void Unregister(string authenticationScheme) {
            ExceptionHelper.UnmanagedPermission.Demand(); 
            if (authenticationScheme == null) {
                throw new ArgumentNullException("authenticationScheme"); 
            } 
            GlobalLog.Print("AuthenticationManager::Unregister() unregistering :[" + authenticationScheme + "]");
            lock (s_ModuleBinding) { 
                IAuthenticationModule existentModule = findModule(authenticationScheme);
                if (existentModule == null) {
                    throw new InvalidOperationException(SR.GetString(SR.net_authschemenotregistered));
                } 
                ModuleList.Remove(existentModule);
            } 
        } 

        ///  
        ///    
        ///       Returns a list of registered authentication modules.
        ///    
        ///  
        public static IEnumerator RegisteredModules {
            get { 
                return ModuleList.GetEnumerator(); 
            }
        } 

        /// 
        ///    
        ///       Binds an authentication response to a request for pre-authentication. 
        ///    
        ///  
        // Create binding between an authorization response and the module 
        // generating that response
        // This association is used for deciding which module to invoke 
        // for preauthentication purposes
        internal static void BindModule(Uri uri, Authorization response, IAuthenticationModule module) {
            GlobalLog.Assert(module.CanPreAuthenticate, "AuthenticationManager::BindModule()|module.CanPreAuthenticate == false");
            if (response.ProtectionRealm!=null) { 
                // The authentication module specified which Uri prefixes
                // will be preauthenticated 
                string[] prefix = response.ProtectionRealm; 

                for (int k=0; k=signature.Length) {
                int firstQuote = -1, secondQuote = -1;
                for (int i = 0; i < challenge.Length; i++) 
                {
                    if (challenge[i]=='\"') 
                    { 
                        if (firstQuote <= secondQuote)
                            firstQuote = i; 
                        else
                            secondQuote = i;
                    }
 
                    if (i==challenge.Length-1 || (challenge[i]=='\"' && firstQuote>secondQuote))
                    { 
                        // see if the portion of challenge out of the quotes contains 
                        // the signature of the IAuthenticationModule
                        if (i==challenge.Length-1) 
                            firstQuote = challenge.Length;

                        if (firstQuote=0)
                        { 
                            if ((index==0 || challenge[index-1]==' ' || challenge[index-1]==',') &&
                                (index+signature.Length==challenge.Length || challenge[index+signature.Length]==' ' || challenge[index+signature.Length]==','))
                            {
                                break; 
                            }
                            index = -1; 
                        } 
                    }
                } 
            }
            GlobalLog.Print("AuthenticationManager::FindSubstringNotInQuotes(" + challenge + ", " + signature + ")=" + index.ToString());
            return index;
        } 
        //
        private static int IndexOf(string challenge, string lwrCaseSignature, int start, int count) 
        { 
            count += start + 1 - lwrCaseSignature.Length;
            for (; start < count; ++start) 
            {
                int i = 0;
                for (; i < lwrCaseSignature.Length; ++i)
                { 
                    // force a challenge char to lowecase (safe assuming it works on trusted ASCII source)
                    if ((challenge[start+i] | 0x20) != lwrCaseSignature[i]) 
                        break; 
                }
                if (i == lwrCaseSignature.Length) 
                    return start;
            }
            return -1;
        } 
        //
        // this method is called by the IAuthenticationModule implementations 
        // (mainly Digest) to safely find their list of parameters in a challenge. 
        // it returns the index of the first ',' that is not included in quotes,
        // -1 is returned on error or end of string. on return offset contains the 
        // index of the first '=' that is not included in quotes, -1 if no '=' was found.
        //
        internal static int SplitNoQuotes(string challenge, ref int offset) {
            // GlobalLog.Print("SplitNoQuotes([" + challenge + "], " + offset.ToString() + ")"); 
            //
            // save offset 
            // 
            int realOffset = offset;
            // 
            // default is not found
            //
            offset = -1;
 
            if (challenge != null && realOffsetsecondQuote means we are in a quoted string
                    //
                    if (firstQuote>secondQuote && challenge[i]=='\\' && i+1 < challenge.Length && challenge[i+1]=='\"') {
                        // 
                        // skip <\"> when in a quoted string
                        // 
                        i++; 
                    }
                    else if (challenge[i]=='\"') { 
                        if (firstQuote <= secondQuote) {
                            firstQuote = i;
                        }
                        else { 
                            secondQuote = i;
                        } 
                    } 
                    else if (challenge[i]=='=' && firstQuote<=secondQuote && offset<0) {
                        offset = i; 
                    }
                    else if (challenge[i]==',' && firstQuote<=secondQuote) {
                        return i;
                    } 
                }
            } 
 
            return -1;
        } 

#if !FEATURE_PAL
        internal static Authorization GetGroupAuthorization(IAuthenticationModule thisModule, string token, bool finished, NTAuthentication authSession, bool shareAuthenticatedConnections, bool mutualAuth) {
            return 
                new Authorization(
                    token, 
                    finished, 
                    (shareAuthenticatedConnections) ? null : (thisModule.GetType().FullName + "/" + authSession.UniqueUserId),
                    mutualAuth); 

        }
#endif // !FEATURE_PAL
 

    }; // class AuthenticationManager 
 
    //
    // This internal class implements a data structure which can be 
    // used for storing a set of objects keyed by string prefixes
    // Looking up an object given a string returns the value associated
    // with the longest matching prefix
    // (A prefix "matches" a string IFF the string starts with that prefix 
    // The degree of the match is prefix length)
    // 
    internal class PrefixLookup { 
        //
        // our prefix store (a Hashtable) needs to support multiple readers and multiple writers. 
        // the documentation on Hashtable says:
        // "A Hashtable can safely support one writer and multiple readers concurrently.
        // To support multiple writers, all operations must be done through the wrapper
        // returned by the Synchronized method." 
        // it's safe enough, for our use, to just synchronize (with a call to lock()) all write operations
        // so we always fall in the supported "one writer and multiple readers" scenario. 
        // 
        private Hashtable m_Store = new Hashtable();
 
        internal void Add(string prefix, object value) {
            // Hashtable will overwrite existing key
            lock (m_Store) {
                // writers are locked 
                m_Store[prefix] = value;
            } 
        } 

        /* 
        internal void Remove(string prefix) {
            // Hashtable will be unchanged if key is not existing
            lock (m_Store) {
                // writers are locked 
                m_Store.Remove(prefix);
            } 
        } 
        */
 
        internal object Lookup(string lookupKey) {
            if (lookupKey==null) {
                return null;
            } 
            object mostSpecificMatch = null;
            int longestMatchPrefix = 0; 
            int prefixLen; 
            lock (m_Store) {
                // 
                // readers don't need to be locked, but we lock() because:
                // "The enumerator does not have exclusive access to the collection.
                //
                // When an enumerator is instantiated, it takes a snapshot of the current state 
                // of the collection. If changes are made to the collection, such as adding,
                // modifying or deleting elements, the snapshot gets out of [....] and the 
                // enumerator throws an InvalidOperationException. Two enumerators instantiated 
                // from the same collection at the same time can have different snapshots of the
                // collection." 
                //
                // enumerate through every credential in the cache
                //
                string prefix; 
                foreach (DictionaryEntry entry in m_Store) {
                    prefix = (string)entry.Key; 
                    if (lookupKey.StartsWith(prefix)) { 
                        prefixLen = prefix.Length;
                        // 
                        // check if the match is better than the current-most-specific match
                        //
                        if (prefixLen>longestMatchPrefix) {
                            // 
                            // Yes-- update the information about currently preferred match
                            // 
                            longestMatchPrefix = prefixLen; 
                            mostSpecificMatch = entry.Value;
                        } 
                    }
                }
            }
            return mostSpecificMatch; 
        }
 
/* 
    //
    // This is the core implementation of a general prefix string table 
    // The keys are all converted to lowercase
    //
    internal struct PrefixTable: ICollection {
 
        internal enum Action {
            Find, 
            Insert, 
            Remove
        } 

        private DictionaryEntry[]  m_Entries;

        internal object this[string key] { 
            get {
                DictionaryEntry[] local = m_Entries; 
                int idx = BinaryFindInsertRemove(ref local, key, Action.Find); 
                if (idx < 0) {
                    return null; 
                }
                return local[idx].Value;
            }
        } 

        internal void Set(string key, object value) { 
            DictionaryEntry[] local = m_Entries; 
            int idx = BinaryFindInsertRemove(ref local, key, Action.Insert);
            if (idx < 0) { 
                //need to add a new entry
                local[~idx].Key   = key;
                local[~idx].Value = value;
                m_Entries = local; 
            }
            else { 
                local[idx].Value  = value; 
            }
        } 

        internal void Remove(string key) {
            DictionaryEntry[] local = m_Entries;
            int idx = BinaryFindInsertRemove(ref local, key, Action.Remove); 
            if (idx >= 0) {
                //found and removed, update entries. 
                m_Entries = local; 
            }
        } 


        //
        // ICollection interfaces 
        //
 
        int ICollection.Count { 
            get {
                DictionaryEntry[] local = m_Entries; 
                return local == null? 0: local.Length;
            }
        }
 
        public bool IsSynchronized {
            get {return true;} 
        } 

        public IEnumerator GetEnumerator() { 
            return new DictionaryEnumerator(m_Entries);
        }

        object ICollection.SyncRoot { 
            get {return this;}
        } 
 
        void ICollection.CopyTo (Array array, int index) {
            DictionaryEntry[] local = m_Entries; 
            if (local == null) {
                return;
            }
            local.CopyTo(array, index); 
        }
 
        // 
        // Binary search and performing an action on a sorted array of prefixes
        // Derived from Array code, adopted for multithreading and substring search. 
        //
        // For Find returns either the matching prefix index or -1
        // For Insert returns either the matching index or ~pos for the first larger prefix in which case the slot is allocated.
        // For Remove returns -1 if not found or pos of successfully removed slot 
        //
        private unsafe static int BinaryFindInsertRemove(ref DictionaryEntry[] entries, string key, Action action) { 
 
            if (entries == null || entries.Length == 0) {
                if (action != Action.Insert) { 
                    return -1;
                }
                entries = new DictionaryEntry[1];
                return ~0; 
            }
 
            int lo = 0; 
            int hi = entries.Length-1;
 
            int lastPrefix = -1;
            fixed (char* pKey = key) {
                while (lo <= hi) {
                    int i = (lo + hi) >> 1; 
                    int c = ComparePrefix((string)entries[i].Key, pKey, key.Length);
                    if (c < 0) { 
                        if (c < -1) { 
                            lastPrefix = i;
                        } 
                        lo = i + 1;
                    }
                    else if (c > 0) {
                        hi = i - 1; 
                    }
                    else { 
                        //Exact match 
                        if (action == Action.Remove) {
                            DictionaryEntry[] newEntries = new DictionaryEntry[entries.Length-1]; 
                            if (i != 0) {
                                Array.Copy(entries, 0, newEntries, 0, i);
                            }
                            if (i != entries.Length-1) { 
                                Array.Copy(entries, i+1, newEntries, i, entries.Length-i-1);
                            } 
                            entries = newEntries; 
                        }
                        return i; 
                    }
                }
            }
 
            // Here 'lo' points to the closest "larger" key, i.e. the place to insert an new element to.
            // The lastPrefix if not -1, will point to the closest prefix match if found. 
 
            switch (action) {
            case Action.Remove: 
                            return -1;
            case Action.Insert:
                            DictionaryEntry[] newEntries = new DictionaryEntry[entries.Length+1];
                            if (lo != 0) { 
                                Array.Copy(entries, 0, newEntries, 0, lo);
                            } 
                            if (lo != entries.Length) { 
                                Array.Copy(entries, lo, newEntries, lo+1, entries.Length-lo);
                            } 
                            entries = newEntries;
                            break;
            default:
                    // Assuming Find. 
                    if (lastPrefix >= 0) {
                        return lastPrefix; 
                    } 
                    return -1;
            } 
            return ~lo;
        }

 
        //
        // Performs bitwise string comparison assuming that both parameteres are in lower case 
        // +1  prefix is greater 
        // >+1 prefix is greater but only because the prefix length is greater
        // 0   equal 
        // -1  prefix is less
        // <-1 prefix is less but is THE prefix for the key
        private unsafe static int ComparePrefix(string prefix, char* key, int keyLength) {
            int len = prefix.Length < keyLength? prefix.Length: keyLength; 

            fixed (char* pPrefix = prefix) { 
                for (int i =0; i < len; ++i) { 
                    if (pPrefix[i] == key[i]) {
                        continue; 
                    }
                    else if (pPrefix[i] > key[i]) {
                        return 1;
                    } 
                    else {
                        return -1; 
                    } 
                }
            } 
            return (len == keyLength)
                        ? prefix.Length == keyLength ? 0: 8
                        : -8;
        } 
    }
 
    internal class DictionaryEnumerator: IDictionaryEnumerator { 
        DictionaryEntry[]   m_Entries;
        int                 m_CurIdx; 

        internal DictionaryEnumerator(DictionaryEntry[] entries) {
            if (entries == null) {
                entries = new DictionaryEntry[0]; 
            }
            m_Entries = entries; 
            m_CurIdx = -1; 
        }
 
        public Object Current {
            get {
                if (m_CurIdx < 0 || m_CurIdx >= m_Entries.Length) {
                    throw new InvalidOperationException("index"); 
                }
                return m_Entries[m_CurIdx]; 
            } 
        }
 
        public void Reset() {
            m_CurIdx = -1;
        }
 
        public bool MoveNext() {
            if (m_CurIdx >= m_Entries.Length) { 
                return false; 
            }
            ++m_CurIdx; 
            return m_CurIdx < m_Entries.Length;
        }

        public DictionaryEntry Entry { 
            get {
                if (m_CurIdx < 0 || m_CurIdx >= m_Entries.Length) { 
                    throw new InvalidOperationException("index"); 
                }
                return m_Entries[m_CurIdx]; 
            }
        }

        public object Key { 
            get {
                if (m_CurIdx < 0 || m_CurIdx >= m_Entries.Length) { 
                    throw new InvalidOperationException("index"); 
                }
                return m_Entries[m_CurIdx].Key; 
            }
        }

        public object Value { 
            get {
                if (m_CurIdx < 0 || m_CurIdx >= m_Entries.Length) { 
                    throw new InvalidOperationException("index"); 
                }
                return m_Entries[m_CurIdx].Value; 
            }
        }
    }
 
*/
 
    } // class PrefixLookup 

 
} // namespace System.Net

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

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