PnrpPeerResolver.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / PnrpPeerResolver.cs / 1 / PnrpPeerResolver.cs

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

namespace System.ServiceModel.Channels 
{
    using Microsoft.Win32.SafeHandles; 
    using System.ServiceModel; 
    using System.Collections;
    using System.Collections.Generic; 
    using System.Collections.ObjectModel;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO; 
    using System.Net;
    using System.Net.Sockets; 
    using System.Runtime.CompilerServices; 
    using System.Runtime.ConstrainedExecution;
    using System.Runtime.InteropServices; 
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary;
    using System.Security;
    using System.ServiceModel.Diagnostics; 
    using System.ServiceModel.PeerResolvers;
    using System.ServiceProcess; 
    using System.Text; 
    using System.Threading;
    using System.Xml.Serialization; 

    sealed class PnrpPeerResolver : PeerResolver

    { 
        UnsafePnrpNativeMethods.PeerNameRegistrar registrar = new UnsafePnrpNativeMethods.PeerNameRegistrar();
        static bool isPnrpAvailable; 
        static bool isPnrpInstalled; 
        const UnsafePnrpNativeMethods.PnrpResolveCriteria resolutionScope = UnsafePnrpNativeMethods.PnrpResolveCriteria.NearestNonCurrentProcess;
        public const int PNRPINFO_HINT = 0x00000001; 

        internal const int CommentLength = 80;
        internal const byte TcpTransport = 0x01;
        internal const byte PayloadVersion = 0x01; 
        internal const char PathSeparator = '/';
        internal const int MinGuids = 1; 
        internal const int MaxGuids = 2; 
        internal const byte GuidEscape = 0xFF;
        internal const int MaxAddressEntries = 10; 
        internal const int MaxAddressEntriesV1 = 4;
        internal const int MaxPathLength = 200; //this is known prefix+any guids
        static TimeSpan MaxTimeout = new TimeSpan(0, 10, 0); //PNRP validates the timeout to be no greater than 10 minutes
        static TimeSpan MaxResolveTimeout = new TimeSpan(0, 0, 45); 
        internal const string GlobalCloudName = "Global_";
        static object SharedLock = new object(); 
        static Random randomGenerator = new Random(); 
        static TimeSpan TimeToWaitForStatus = TimeSpan.FromSeconds(15);
        PeerReferralPolicy referralPolicy = PeerReferralPolicy.Share; 

        [Flags]
        internal enum PnrpResolveScope
        { 
            None = 0,
            Global = 1, 
            SiteLocal = 2, 
            LinkLocal = 4,
            All = Global | SiteLocal | LinkLocal 
        }

        static PnrpPeerResolver()
        { 
            // determine if PNRP is installed
            isPnrpAvailable = false; 
            using (UnsafePnrpNativeMethods.DiscoveryBase db = new UnsafePnrpNativeMethods.DiscoveryBase()) 
            {
                isPnrpInstalled = db.IsPnrpInstalled(); 
                isPnrpAvailable = db.IsPnrpAvailable(TimeToWaitForStatus);
            }
        }
 
        internal PnrpPeerResolver():this(PeerReferralPolicy.Share){}
        internal PnrpPeerResolver(PeerReferralPolicy referralPolicy) 
        { 
            this.referralPolicy = referralPolicy;
        } 

        static Encoding PnrpEncoder
        {
            get 
            {
                return System.Text.Encoding.UTF8; 
            } 
        }
 
        public static bool IsPnrpAvailable
        {
            get { return isPnrpAvailable; }
        } 

        public static bool IsPnrpInstalled 
        { 
            get { return isPnrpInstalled; }
        } 

        public static IPEndPoint GetHint()
        {
            byte[] bytes = new byte[16]; 
            lock(SharedLock)
            { 
                randomGenerator.NextBytes(bytes); 
            }
            return new IPEndPoint(new IPAddress(bytes), 0); 
        }

        // Get the hint for the node in this process that handles this meshid
        // Get the nodeid for the current node - If the factory is using PrivatePeerNode then this can throw. 
        // in which case use a hint of 0
        // The resolver prepends 0. to the meshid so we strip it off before locating the node. 
        // false means that the search must include the current process. 
        public static bool HasPeerNodeForMesh(string meshId)
        { 
            PeerNodeImplementation node = null;
            return PeerNodeImplementation.TryGet(meshId, out node);
        }
 
        // PNRP doesn't support registering the same peername by the same identity in the same process.
        // Thus, we cannot test the PNRP resolver between two nodes in the same process without a little help. 
        // By calling SetMeshExtensions, the resolver will register and resolver different ids, allowing two 
        // nodes to work in the same process.
        string localExtension; 
        string remoteExtension;
        internal void SetMeshExtensions(string local, string remote)
        {
            localExtension = local; 
            remoteExtension = remote;
        } 
 
        internal PnrpResolveScope EnumerateClouds(bool forResolve, Dictionary LinkCloudNames, Dictionary SiteCloudNames)
        { 
            bool foundActive = false;
            PnrpResolveScope currentScope = PnrpResolveScope.None;
            LinkCloudNames.Clear();
            SiteCloudNames.Clear(); 
            UnsafePnrpNativeMethods.CloudInfo[] cloudInfos = UnsafePnrpNativeMethods.PeerCloudEnumerator.GetClouds();
 
            // If we are resolving we should first look for active clouds only 
            // If we find some then we should return those to the caller
            // otherwise we should just load up with clouds 
            if (forResolve)
            {
                foreach (UnsafePnrpNativeMethods.CloudInfo cloud in cloudInfos)
                { 
                    if (cloud.State == UnsafePnrpNativeMethods.PnrpCloudState.Active)
                    { 
                        if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.Global) 
                        {
                            currentScope |= PnrpResolveScope.Global; 
                            foundActive = true;
                        }
                        else if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.LinkLocal)
                        { 
                            DiagnosticUtility.DebugAssert(!String.IsNullOrEmpty(cloud.Name), "Unknown scope id in the IPAddress");
                            LinkCloudNames.Add(cloud.ScopeId, cloud.Name); 
                            currentScope |= PnrpResolveScope.LinkLocal; 
                            foundActive = true;
                        } 
                        else if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.SiteLocal)
                        {
                            DiagnosticUtility.DebugAssert(!String.IsNullOrEmpty(cloud.Name), "Unknown scope id in the IPAddress");
                            SiteCloudNames.Add(cloud.ScopeId, cloud.Name); 
                            currentScope |= PnrpResolveScope.SiteLocal;
                            foundActive = true; 
                        } 
                    }
                } 
            }

            if (!foundActive)
            { 
                foreach (UnsafePnrpNativeMethods.CloudInfo cloud in cloudInfos)
                { 
                    if (!((cloud.State == UnsafePnrpNativeMethods.PnrpCloudState.Dead) 
                        || (cloud.State == UnsafePnrpNativeMethods.PnrpCloudState.Disabled)
                        || (cloud.State == UnsafePnrpNativeMethods.PnrpCloudState.NoNet)) 
                       )
                    {
                        if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.Global)
                        { 
                            currentScope |= PnrpResolveScope.Global;
                            continue; 
                        } 
                        if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.LinkLocal)
                        { 
                            DiagnosticUtility.DebugAssert(!String.IsNullOrEmpty(cloud.Name), "Unknown scope id in the IPAddress");
                            LinkCloudNames.Add(cloud.ScopeId, cloud.Name);
                            currentScope |= PnrpResolveScope.LinkLocal;
                        } 
                        else if (cloud.Scope == UnsafePnrpNativeMethods.PnrpScope.SiteLocal)
                        { 
                            DiagnosticUtility.DebugAssert(!String.IsNullOrEmpty(cloud.Name), "Unknown scope id in the IPAddress"); 
                            SiteCloudNames.Add(cloud.ScopeId, cloud.Name);
                            currentScope |= PnrpResolveScope.SiteLocal; 
                        }
                    }
                }
            } 
            return currentScope;
        } 
 
        class RegistrationHandle
        { 
            public string PeerName;
            public List Clouds;
            public RegistrationHandle(string peerName)
            { 
                this.PeerName = peerName;
                Clouds = new List(); 
            } 
            public void AddCloud(string name)
            { 
                this.Clouds.Add(name);
            }
        }
 
        public override bool CanShareReferrals
        { 
            get 
            {
                return referralPolicy != PeerReferralPolicy.DoNotShare; 
            }
        }
        public override object Register(string meshId, PeerNodeAddress nodeAddress, TimeSpan timeout)
        { 
            ThrowIfNoPnrp();
 
            PnrpRegistration globalEntry = null; 
            PnrpRegistration[] linkEntries = null;
            PnrpRegistration[] siteEntries = null; 

            RegistrationHandle regHandle = new RegistrationHandle(meshId);
            Dictionary SiteCloudNames = new Dictionary();
            Dictionary LinkCloudNames = new Dictionary(); 

            PnrpResolveScope availableScope = EnumerateClouds(false, LinkCloudNames, SiteCloudNames); 
 
            if(availableScope == PnrpResolveScope.None)
            { 
                //could not find any clouds.
                PeerExceptionHelper.ThrowInvalidOperation_PnrpNoClouds();
            }
 
            if (localExtension != null)
                meshId += localExtension; 
 
            try
            { 
                PeerNodeAddressToPnrpRegistrations(meshId, LinkCloudNames, SiteCloudNames, nodeAddress, out linkEntries, out siteEntries, out globalEntry);
            }
            catch(Exception e)
            { 
                if(DiagnosticUtility.IsFatal(e)) throw;
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerPnrpIllegalUri), e)); 
            } 
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
            try
            {
                PnrpResolveScope currentScope = PnrpResolveScope.None;
                if(globalEntry != null) 
                {
                    if(globalEntry.Addresses.Length > 0 && (availableScope & PnrpResolveScope.Global) != 0) 
                    { 
                        registrar.Register(globalEntry, timeoutHelper.RemainingTime());
                        regHandle.AddCloud(globalEntry.CloudName); 
                        currentScope |= PnrpResolveScope.Global;
                    }
                }
                if(linkEntries.Length > 0) 
                {
                    foreach(PnrpRegistration entry in linkEntries) 
                    { 
                        if(entry.Addresses.Length > 0)
                        { 
                            registrar.Register(entry, timeoutHelper.RemainingTime());
                            regHandle.AddCloud(entry.CloudName);
                        }
                    } 
                    currentScope |= PnrpResolveScope.LinkLocal;
                } 
                if(siteEntries.Length > 0) 
                {
                    foreach(PnrpRegistration entry in siteEntries) 
                    {
                        if(entry.Addresses.Length > 0)
                        {
                            registrar.Register(entry, timeoutHelper.RemainingTime()); 
                            regHandle.AddCloud(entry.CloudName);
                        } 
                    } 
                    currentScope |= PnrpResolveScope.SiteLocal;
                } 
                if(currentScope == PnrpResolveScope.None)
                {
                    // We have addresses but no cloud that corresponds to them
                    // so we should throw an exception 
                    PeerExceptionHelper.ThrowInvalidOperation_PnrpAddressesUnsupported();
                } 
            } 
            catch(SocketException)
            { 
                try
                {
                    Unregister(regHandle,timeoutHelper.RemainingTime());
                } 
                catch(SocketException e)
                { 
                    DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); 
                }
                throw; 
            }

            if (DiagnosticUtility.ShouldTraceInformation)
            { 
                PnrpRegisterTraceRecord record = new PnrpRegisterTraceRecord(meshId,globalEntry,siteEntries,linkEntries);
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PnrpRegisteredAddresses, 
                    record, this, null); 
            }
 
            return regHandle;
        }

        void ThrowIfNoPnrp() 
        {
            if (!isPnrpAvailable) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR.GetString(SR.PeerPnrpNotAvailable))); 
            }
        }

        public override void Unregister(object registrationId, TimeSpan timeout) 
        {
            RegistrationHandle regHandle = registrationId as RegistrationHandle; 
            if(regHandle == null || String.IsNullOrEmpty(regHandle.PeerName)) 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerInvalidRegistrationId, regHandle), "registrationId"));
            string meshId = regHandle.PeerName; 

            // prepend a 0. for unsecured peername
            string peerName = string.Format(CultureInfo.InvariantCulture, "0.{0}", meshId);
            registrar.Unregister(peerName, regHandle.Clouds, timeout); 

            if (DiagnosticUtility.ShouldTraceInformation) 
            { 
                PnrpPeerResolverTraceRecord record = new PnrpPeerResolverTraceRecord(meshId, new List());
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PnrpUnregisteredAddresses, 
                    record, this, null);
            }
        }
 
        public override void Update(object registrationId, PeerNodeAddress updatedNodeAddress, TimeSpan timeout)
        { 
            RegistrationHandle regHandle = registrationId as RegistrationHandle; 
            if (regHandle == null || string.IsNullOrEmpty(regHandle.PeerName))
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerInvalidRegistrationId, regHandle), "registrationId")); 

            string meshId = regHandle.PeerName;
            Register(meshId, updatedNodeAddress, timeout);
        } 

        //return null in case of unrecognized format. consider adding logging. 
        PeerNodeAddress PeerNodeAddressFromPnrpRegistration(PnrpRegistration input) 
        {
            List addresses = new List(); 
            PeerNodeAddress result = null;
            Guid[] guids ;
            StringBuilder pathBuilder = new StringBuilder(MaxPathLength);
            int version=0; 
            string protocolScheme;
 
            try 
            {
                if (input == null || String.IsNullOrEmpty(input.Comment)) 
                    return null;
                Array.ForEach(input.Addresses,delegate(IPEndPoint obj){ addresses.Add(obj.Address);});
                if (addresses.Count != 0)
                { 
                    UriBuilder uriBuilder = new UriBuilder();
                    uriBuilder.Port = input.Addresses[0].Port; 
                    uriBuilder.Host = addresses[0].ToString(); 
                    pathBuilder.Append(PeerStrings.KnownServiceUriPrefix);
                    CharEncoder.Decode(input.Comment, out version, out protocolScheme, out guids); 

                    if (
                        (version == PayloadVersion) &&
                        (guids != null) && (guids.Length <= MaxGuids) && 
                        (guids.Length >= MinGuids)
                    ) 
                    { 
                        uriBuilder.Scheme = protocolScheme;
                        Array.ForEach(guids,delegate(Guid guid) 
                                            {
                                                pathBuilder.Append(PathSeparator + String.Format(CultureInfo.InvariantCulture,"{0}",guid.ToString()));
                                            }
                        ); 
                        uriBuilder.Path = String.Format(CultureInfo.InvariantCulture,"{0}", pathBuilder.ToString());
                        result = new PeerNodeAddress(new EndpointAddress(uriBuilder.Uri), new ReadOnlyCollection(addresses)); 
                    } 
                }
            } 
            catch (ArgumentException e)
            {
                DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
            } 
            catch (FormatException e)
            { 
                DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); 
            }
            catch (IndexOutOfRangeException e) 
            {
                DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
            }
 
            return result;
 
        } 

        void TrimToMaxAddresses(List addressList) 
        {
            if(addressList.Count > MaxAddressEntries)
            {
                addressList.RemoveRange(MaxAddressEntries, addressList.Count-MaxAddressEntries); 
            }
        } 
 
        void PeerNodeAddressToPnrpRegistrations(string meshName, Dictionary LinkCloudNames, Dictionary SiteCloudNames, PeerNodeAddress input, out PnrpRegistration[] linkRegs, out PnrpRegistration[] siteRegs, out PnrpRegistration global)
        { 
            PnrpRegistration reg = new PnrpRegistration();

            Dictionary resultsLink = new Dictionary();
            Dictionary resultsSite = new Dictionary(); 
            PnrpRegistration entry = null;
            string scheme; 
            Guid[] guids; 
            ParseServiceUri(input.EndpointAddress.Uri, out scheme, out guids);
            int port = input.EndpointAddress.Uri.Port; 
            if (port <= 0)
                port = TcpUri.DefaultPort;
            string peerName = string.Format(CultureInfo.InvariantCulture, "0.{0}", meshName);
            string comment = CharEncoder.Encode(PayloadVersion, scheme, guids); 
            global = null;
            string cloudName = string.Empty; 
            foreach(IPAddress address in input.IPAddresses) 
            {
                if(address.AddressFamily == AddressFamily.InterNetworkV6 
                    &&
                    ((address.IsIPv6LinkLocal) || (address.IsIPv6SiteLocal))
                )
                { 
                    if(address.IsIPv6LinkLocal)
                    { 
                        if(!resultsLink.TryGetValue((uint)address.ScopeId, out entry)) 
                        {
                            if(!LinkCloudNames.TryGetValue((uint)address.ScopeId, out cloudName)) 
                            {
                                continue;
                            }
                            entry = PnrpRegistration.Create(peerName,comment,cloudName); 
                            resultsLink.Add((uint)address.ScopeId, entry);
                        } 
                    } 
                    else
                    { 
                        if (!resultsSite.TryGetValue((uint)address.ScopeId, out entry))
                        {
                            if(!SiteCloudNames.TryGetValue((uint)address.ScopeId, out cloudName))
                            { 
                                continue;
                            } 
                            entry = PnrpRegistration.Create(peerName,comment,cloudName); 
                            resultsSite.Add((uint)address.ScopeId, entry);
                        } 
                    }
                    entry.addressList.Add(new IPEndPoint(address,port));
                }
                else 
                {
                    if(global == null) 
                    { 
                        global = PnrpRegistration.Create(peerName,comment,GlobalCloudName);
                    } 
                    global.addressList.Add(new IPEndPoint(address,port));
                }
            }
            if(global != null) 
            {
                if(global.addressList != null) 
                { 
                    TrimToMaxAddresses(global.addressList);
                    global.Addresses = global.addressList.ToArray(); 
                }
                else
                    global.Addresses = new IPEndPoint[0];
            } 

            if(resultsLink.Count != 0) 
            { 
                foreach(PnrpRegistration tempLink in resultsLink.Values)
                { 
                    if(tempLink.addressList != null)
                    {
                        TrimToMaxAddresses(tempLink.addressList);
                        tempLink.Addresses = tempLink.addressList.ToArray(); 
                    }
                    else 
                    { 
                        tempLink.Addresses = new IPEndPoint[0];
                    } 
                }
                linkRegs = new PnrpRegistration[resultsLink.Count];
                resultsLink.Values.CopyTo(linkRegs,0);
            } 
            else
                linkRegs = new PnrpRegistration[0]; 
            if(resultsSite.Count != 0) 
            {
                foreach(PnrpRegistration tempSite in resultsSite.Values) 
                {
                    if(tempSite.addressList != null)
                    {
                        TrimToMaxAddresses(tempSite.addressList); 
                        tempSite.Addresses = tempSite.addressList.ToArray();
                    } 
                    else 
                    {
                        tempSite.Addresses = new IPEndPoint[0]; 
                    }
                }
                siteRegs = new PnrpRegistration[resultsSite.Count];
                resultsSite.Values.CopyTo(siteRegs,0); 
            }
            else 
                siteRegs = new PnrpRegistration[0]; 
        }
 
        static int ProtocolFromName(string name)
        {
            if (name == Uri.UriSchemeNetTcp)
            { 
                return TcpTransport;
            } 
 
            throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("name", SR.GetString(SR.PeerPnrpIllegalUri));
        } 

        static string NameFromProtocol(byte number)
        {
            switch(number) 
            {
                case TcpTransport: 
                    return Uri.UriSchemeNetTcp; 
                default:
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerPnrpIllegalUri))); 
            }
        }

        void ParseServiceUri(Uri uri, out string scheme, out Guid[] result) 
        {
            if(uri != null) 
            { 
                if((ProtocolFromName(uri.Scheme)!=0) && !String.IsNullOrEmpty(uri.AbsolutePath))
                { 
                    scheme = uri.Scheme;
                    string[] parts = uri.AbsolutePath.Trim(new char[] { ' ',PathSeparator }).Split(PathSeparator);
                    if((0 == String.Compare(parts[0],PeerStrings.KnownServiceUriPrefix,StringComparison.OrdinalIgnoreCase)))
                    { 
                        if(parts.Length >= MinGuids && parts.Length <= MaxGuids+1)
                        { 
                            result = new Guid[parts.Length-1]; 
                            try
                            { 
                                for(int i=1;i results, List regs) 
        {
            PnrpRegistration entry = null; 
            foreach(PnrpRegistration reg in regs)
            {
                if(!results.TryGetValue(reg.Comment, out entry))
                { 
                    entry = reg;
                    results.Add(reg.Comment,reg); 
                    entry.addressList = new List(); 
                }
                entry.addressList.AddRange(reg.Addresses); 
                reg.Addresses = null;
            }
        }
 
        void MergeResults(List nodeAddressList, List globalRegistrations, List linkRegistrations, ListsiteRegistrations)
        { 
            Dictionary results = new Dictionary(); 
            MergeResults(results,globalRegistrations);
            MergeResults(results,siteRegistrations); 
            MergeResults(results,linkRegistrations);
            PeerNodeAddress result;
            foreach(PnrpRegistration reg in results.Values)
            { 
                reg.Addresses = reg.addressList.ToArray();
                result = PeerNodeAddressFromPnrpRegistration(reg); 
                if(result != null) 
                    nodeAddressList.Add(result);
            } 
        }

        public override ReadOnlyCollection Resolve(string meshId, int maxAddresses, TimeSpan timeout)
        { 
            ThrowIfNoPnrp();
            UnsafePnrpNativeMethods.PeerNameResolver resolver; 
            List resolvers =new  List(); 
            List globalRegistrations = new List();
            List linkRegistrations = new List(); 
            List siteRegistrations = new List();
            List handles = new List();
            Dictionary SiteCloudNames = new Dictionary();
            Dictionary LinkCloudNames = new Dictionary(); 
            UnsafePnrpNativeMethods.PnrpResolveCriteria targetScope = resolutionScope;
            TimeoutHelper timeoutHelper = new TimeoutHelper(TimeSpan.Compare(timeout, MaxResolveTimeout) <= 0  ? timeout : MaxResolveTimeout); 
 
            if(!HasPeerNodeForMesh(meshId))
                targetScope = UnsafePnrpNativeMethods.PnrpResolveCriteria.Any; 
            PnrpResolveScope currentScope = EnumerateClouds(true, LinkCloudNames, SiteCloudNames);

            if (remoteExtension != null)
                meshId += remoteExtension; 

            // prepend a 0. for unsecured peername 
            string peerName = string.Format(CultureInfo.InvariantCulture, "0.{0}", meshId); 
            if((currentScope & PnrpResolveScope.Global) != 0)
            { 
                resolver = new UnsafePnrpNativeMethods.PeerNameResolver(
                                    peerName, maxAddresses, targetScope,0, GlobalCloudName, timeoutHelper.RemainingTime(), globalRegistrations);
                handles.Add(resolver.AsyncWaitHandle);
                resolvers.Add(resolver); 
            }
 
            if((currentScope & PnrpResolveScope.LinkLocal) != 0) 
            {
                foreach(KeyValuePair linkEntry in LinkCloudNames) 
                {
                    resolver = new UnsafePnrpNativeMethods.PeerNameResolver(
                                    peerName, maxAddresses, targetScope, linkEntry.Key, linkEntry.Value, timeoutHelper.RemainingTime(), linkRegistrations);
                    handles.Add(resolver.AsyncWaitHandle); 
                    resolvers.Add(resolver);
                } 
            } 

            if((currentScope & PnrpResolveScope.SiteLocal) != 0) 
            {
                foreach(KeyValuePair siteEntry in SiteCloudNames)
                {
                    resolver = new UnsafePnrpNativeMethods.PeerNameResolver( 
                                    peerName, maxAddresses, targetScope, siteEntry.Key, siteEntry.Value, timeoutHelper.RemainingTime(), siteRegistrations);
                    handles.Add(resolver.AsyncWaitHandle); 
                    resolvers.Add(resolver); 
                }
            } 
            if(handles.Count == 0)
            {
                //could not find any clouds.
                if (DiagnosticUtility.ShouldTraceWarning) 
                {
                    Exception exception = new InvalidOperationException(SR.GetString(SR.PnrpNoClouds)); 
                    PnrpResolveExceptionTraceRecord record = new PnrpResolveExceptionTraceRecord(meshId, string.Empty,exception); 
                    TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.PnrpResolvedAddresses,
                        record, this, null); 
                }
                return new ReadOnlyCollection(new List());
            }
 
            Exception lastException = null;
            foreach(UnsafePnrpNativeMethods.PeerNameResolver handle in resolvers) 
            { 
                try
                { 
                    handle.End();
                }
                catch(SocketException e)
                { 
                    DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
                    lastException = e; 
                } 
            }
 
            List nodeAddressList = new List();
            MergeResults(nodeAddressList, globalRegistrations, linkRegistrations, siteRegistrations);
            if((lastException != null) && (nodeAddressList.Count == 0))
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(lastException); 
            if (DiagnosticUtility.ShouldTraceInformation)
            { 
                PnrpPeerResolverTraceRecord record = new PnrpPeerResolverTraceRecord(meshId, nodeAddressList); 
                TraceUtility.TraceEvent(TraceEventType.Information, TraceCode.PnrpResolvedAddresses,
                    record, this, null); 
            }
            return new ReadOnlyCollection(nodeAddressList);
        }
 

        // contains the friendly PNRP information 
        internal class PnrpRegistration 
        {
            public string PeerName; 
            public string CloudName;
            public string Comment;
            public IPEndPoint[] Addresses;
            public List addressList; 

            internal static PnrpRegistration Create(string peerName, string comment, string cloudName) 
            { 
                PnrpRegistration reg = new PnrpRegistration();
                reg.Comment = comment; 
                reg.CloudName = cloudName;
                reg.PeerName = peerName;
                reg.addressList = new List();
                return reg; 
            }
        } 
 
        internal class CharEncoder
        { 
            static void CheckAtLimit(int current)
            {
                if (current + 1 >= CommentLength)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.PeerPnrpIllegalUri))); 
            }
            static void EncodeByte(byte b, ref int offset, byte[] bytes) 
            { 
                if (b == 0 || b == GuidEscape)
                { 
                    CheckAtLimit(offset);
                    bytes[offset++] = GuidEscape;
                }
                CheckAtLimit(offset); 
                bytes[offset++] = b;
            } 
 
            static internal string Encode(int version, string protocolName, Guid[] guids)
            { 
                byte[] bytes = new byte[CommentLength];
                int i = 0;
                int protocol = ProtocolFromName(protocolName);
                EncodeByte(Convert.ToByte(version), ref i, bytes); 
                EncodeByte(Convert.ToByte(protocol), ref i, bytes);
                EncodeByte(Convert.ToByte(guids.Length), ref i, bytes); 
                foreach (Guid guid in guids) 
                {
                    foreach (byte b in guid.ToByteArray()) 
                    {
                        EncodeByte(Convert.ToByte(b), ref i, bytes);
                    }
                } 
                if (i % 2 != 0 && i < bytes.Length)
                    bytes[i] = GuidEscape; 
                // Now we have a collection of bytes lets turn it into a string 
                int length = i;
                int clength = (length / 2) + (length % 2);         // Pack 2 bytes per char 
                char[] chars = new char[clength];
                i = 0;
                for (int j = 0; j < clength; j++)
                { 
                    chars[j] = Convert.ToChar(bytes[i++] * 0x100 + bytes[i++]);
                } 
                return new string(chars); 
            }
 
            static byte GetByte(int offset, char[] chars)
            {
                int p = offset / 2;
                int lo = offset % 2; 
                return Convert.ToByte(lo == 1 ? chars[p] & GuidEscape: chars[p] / 0x100);
            } 
 
            static byte DecodeByte(ref int offset, char[] chars)
            { 
                byte b = GetByte(offset++, chars);
                if (b == 0xff)
                {
                    b = GetByte(offset++, chars); 
                }
                return b; 
            } 

            static internal void Decode(string buffer, out int version, out string protocolName, out Guid[] guids) 
            {
                char[] chars = buffer.ToCharArray();
                byte protocol;
                int i = 0; 

                version = DecodeByte(ref i, chars); 
                protocol = DecodeByte(ref i, chars); 
                protocolName = NameFromProtocol(protocol);
                int length = DecodeByte(ref i, chars); 
                guids = new Guid[length];

                for (int g = 0; g < length; g++)
                { 
                    byte[] bytes = new byte[16];
                    for (int j = 0; j < 16; j++) 
                    { 
                        bytes[j] = DecodeByte(ref i, chars);
                    } 
                    guids[g] = new Guid(bytes);
                }
            }
        } 

        internal enum PnrpErrorCodes 
        { 
            WSA_PNRP_ERROR_BASE = 11500,
            WSA_PNRP_CLOUD_NOT_FOUND = 11501, 
            WSA_PNRP_CLOUD_DISABLED = 11502,
            //these error codes are not relevant for now
//            WSA_PNRP_INVALID_IDENTITY = 11503,
//            WSA_PNRP_TOO_MUCH_LOAD = 11504, 
            WSA_PNRP_CLOUD_IS_RESOLVE_ONLY = 11505,
//            WSA_PNRP_CLIENT_INVALID_COMPARTMENT_ID = 11506, 
            WSA_PNRP_FW_PORT_BLOCKED = 11507, 
            WSA_PNRP_DUPLICATE_PEER_NAME = 11508,
        } 

        internal class PnrpException : SocketException
        {
            string message; 

            internal PnrpException(int errorCode, string cloud) : base(errorCode) 
            { 
                LoadMessage(errorCode, cloud);
            } 

            public override string Message
            {
                get 
                {
                    if(!String.IsNullOrEmpty(message)) 
                        return message; 
                    else
                        return base.Message; 
                }
            }

            void LoadMessage(int errorCode, string cloud) 
            {
                string formatString; 
                switch((PnrpErrorCodes)errorCode) 
                {
                    case PnrpErrorCodes.WSA_PNRP_CLOUD_DISABLED: 
                        formatString = SR.PnrpCloudDisabled;
                        break;
                    case PnrpErrorCodes.WSA_PNRP_CLOUD_NOT_FOUND:
                        formatString = SR.PnrpCloudNotFound; 
                        break;
                    case PnrpErrorCodes.WSA_PNRP_CLOUD_IS_RESOLVE_ONLY: 
                        formatString = SR.PnrpCloudResolveOnly; 
                        break;
                    case PnrpErrorCodes.WSA_PNRP_FW_PORT_BLOCKED: 
                        formatString = SR.PnrpPortBlocked;
                        break;
                    case PnrpErrorCodes.WSA_PNRP_DUPLICATE_PEER_NAME:
                        formatString = SR.PnrpDuplicatePeerName; 
                        break;
                    default: 
                        formatString = null; 
                        break;
                } 
                if(formatString != null)
                    message = SR.GetString(formatString, cloud);
            }
        } 

        internal static class UnsafePnrpNativeMethods 
        { 
            // WSA import functions
            [DllImport("ws2_32.dll", CharSet = CharSet.Unicode)] 
            static extern int WSASetService(CriticalAllocHandle querySet, WsaSetServiceOp essOperation, int dwControlFlags);

            [DllImport("ws2_32.dll", CharSet = CharSet.Unicode)]
            static extern int WSALookupServiceNext(CriticalLookupHandle hLookup, 
                WsaNspControlFlags dwControlFlags, ref int lpdwBufferLength, IntPtr Results);
            [DllImport("ws2_32.dll", CharSet = CharSet.Unicode), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] 
            static extern int WSALookupServiceEnd(IntPtr hLookup); 
            [DllImport("ws2_32.dll", CharSet = CharSet.Unicode)]
            static extern int WSALookupServiceBegin(CriticalAllocHandle query,WsaNspControlFlags dwControlFlags, out CriticalLookupHandle hLookup); 
            [DllImport("ws2_32.dll", CharSet = CharSet.Ansi)]
            static extern int WSAStartup(Int16 wVersionRequested, ref WsaData lpWSAData);
            [DllImport("ws2_32.dll", CharSet = CharSet.Ansi)]
            static extern int WSACleanup(); 
            [DllImport("ws2_32.dll", CharSet = CharSet.Ansi)]
            static extern int WSAGetLastError(); 
            [DllImport("ws2_32.dll", CharSet = CharSet.Unicode)] 
            static extern int WSAEnumNameSpaceProviders(ref int lpdwBufferLength, IntPtr lpnspBuffer);
 
            // PNRP namespace identifiers
            static Guid SvcIdCloud = new Guid(0xc2239ce6, 0x00c0, 0x4fbf, 0xba, 0xd6, 0x18, 0x13, 0x93, 0x85, 0xa4, 0x9a);
            static Guid SvcIdNameV1 = new Guid(0xc2239ce5, 0x00c0, 0x4fbf, 0xba, 0xd6, 0x18, 0x13, 0x93, 0x85, 0xa4, 0x9a);
            static Guid SvcIdName = new Guid(0xc2239ce7, 0x00c0, 0x4fbf, 0xba, 0xd6, 0x18, 0x13, 0x93, 0x85, 0xa4, 0x9a); 
            static Guid NsProviderName = new Guid(0x03fe89cd, 0x766d, 0x4976, 0xb9, 0xc1, 0xbb, 0x9b, 0xc4, 0x2c, 0x7b, 0x4d);
            static Guid NsProviderCloud = new Guid(0x03fe89ce, 0x766d, 0x4976, 0xb9, 0xc1, 0xbb, 0x9b, 0xc4, 0x2c, 0x7b, 0x4d); 
 
            const int MaxAddresses = 10;
            const int MaxAddressesV1 = 4; 
            const Int16 RequiredWinsockVersion = 0x0202;

            // specifies the namespace used used by a specified WSAQUERYSET
            [Serializable] 
            internal enum NspNamespaces
            { 
                Cloud = 39, 
                Name = 38,
            } 

            [Serializable]
            [Flags]
            internal enum PnrpCloudFlags 
            {
                None = 0x0000, 
                LocalName = 0x0001, //  Name not valid on other computers 
            }
 
            [Serializable]
            internal enum PnrpCloudState
            {
                Virtual = 0,        //  Not initialized 
                Synchronizing = 1,  //  The cache is initializing
                Active = 2,         //  Cloud is active 
                Dead = 3,            //  Initialized but lost network 
                Disabled = 4,       //disabled in the registry
                NoNet = 5,          //active but lost network 
                Alone = 6,
            }

            [Serializable] 
            internal enum PnrpExtendedPayloadType
            { 
                None = 0, 
                Binary,
                String 
            }

            // internal because it is exposed by PeerNameResolver
            [Serializable] 
            internal enum PnrpResolveCriteria
            { 
                Default = 0,                    // Default = PNRP_RESOLVE_CRITERIA_NON_CURRENT_PROCESS_PEER_NAME 
                Remote = 1,                     // match first 128 bits (remote node)
                NearestRemote = 2,              // match first 128 bits, and close to top 64 bits 
                                                // of the second 128 bits (remote node)
                NonCurrentProcess = 3,          //  match first 128 bits (not in the current process)
                NearestNonCurrentProcess = 4,   // match first 128 bits, and close to top 64 bits
                                                // of the second 128 bits (not in the current process) 
                Any = 5,                        // match first 128 bits (any node)
                Nearest = 6                     // match first 128 bits, and close to top 64 bits 
                                                // of the second 128 bits (any node) 
            }
 
            [Serializable]
            internal enum PnrpRegisteredIdState
            {
                Ok = 1,     //  Id is active in cloud 
                Problem = 2 //  Id is no longer registered in cloud
            } 
 
            internal enum PnrpScope
            { 
                Any = 0,
                Global = 1,
                SiteLocal = 2,
                LinkLocal = 3, 
            }
 
            // primary use in this code is to specify what information should be returned by WSALookupServiceNext 
            [Flags]
            internal enum WsaNspControlFlags 
            {
                Deep = 0x0001,
                Containers = 0x0002,
                NoContainers = 0x0004, 
                Nearest = 0x0008,
                ReturnName = 0x0010, 
                ReturnType = 0x0020, 
                ReturnVersion = 0x0040,
                ReturnComment = 0x0080, 
                ReturnAddr = 0x0100,
                ReturnBlob = 0x0200,
                ReturnAliases = 0x0400,
                ReturnQueryString = 0x0800, 
                ReturnAll = 0x0FF0,
                ResService = 0x8000, 
                FlushCache = 0x1000, 
                FlushPrevious = 0x2000,
            } 

            internal enum WsaError
            {
                WSAEINVAL = 10022, 
                WSAEFAULT = 10014,
                WSAENOMORE = 10102, 
                WSA_E_NO_MORE = 10110, 
                WSANO_DATA = 11004
            } 

            // specifies the operation of WSASetService
            internal enum WsaSetServiceOp
            { 
                Register = 0,
                Deregister, 
                Delete 
            }
 
            internal struct BlobSafe
            {
                public int cbSize;
                public CriticalAllocHandle pBlobData; 
            }
 
            internal struct BlobNative 
            {
                public int cbSize; 
                public IntPtr pBlobData;
            }

 
            // PnrpResolver does not currently support any cloud except Global. If this needs to be changed, we will
            // need to be able to enumerate clouds. 
 
            // managed equivalent of both PNRPCLOUDINFO and PNRP_CLOUD_ID
            // internal because it is exposed by PeerCloudEnumerator 
            internal class CloudInfo
            {
                public string Name;
                public PnrpScope Scope; 
                public uint ScopeId;
                public PnrpCloudState State; 
                public PnrpCloudFlags Flags; 
            }
 
            [Serializable]
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            internal struct CsAddrInfo
            { 
                public IPEndPoint LocalAddr;
                public IPEndPoint RemoteAddr; 
                public int iSocketType; 
                public int iProtocol;
            } 

            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            internal class CsAddrInfoSafe : IDisposable
            { 
                public SOCKET_ADDRESS_SAFE LocalAddr;
                public SOCKET_ADDRESS_SAFE RemoteAddr; 
                public int iSocketType; 
                public int iProtocol;
                bool disposed; 

                public static CsAddrInfoSafe[] FromAddresses(CsAddrInfo[] addresses)
                {
                    CsAddrInfoSafe addr; 
                    CsAddrInfoSafe[] result = null;
                    if(addresses == null || addresses.Length == 0) 
                        return null; 

                    result = new CsAddrInfoSafe[addresses.Length]; 
                    int i=0;
                    foreach(CsAddrInfo info in addresses)
                    {
                        addr = new CsAddrInfoSafe(); 
                        addr.LocalAddr = SOCKET_ADDRESS_SAFE.SocketAddressFromIPEndPoint(info.LocalAddr);
                        addr.RemoteAddr = SOCKET_ADDRESS_SAFE.SocketAddressFromIPEndPoint(info.RemoteAddr); 
                        addr.iProtocol = info.iProtocol; 
                        addr.iSocketType = info.iSocketType;
                        result[i++] = addr; 
                    }
                    return result;
                }
                public static void StructureToPtr(CsAddrInfoSafe input, IntPtr target) 
                {
                    CsAddrInfoNative native; 
                    native.iProtocol = input.iProtocol; 
                    native.iSocketType = input.iSocketType;
                    native.LocalAddr.iSockaddrLength = input.LocalAddr.iSockaddrLength; 
                    native.LocalAddr.lpSockAddr = input.LocalAddr.lpSockAddr;
                    native.RemoteAddr.iSockaddrLength = input.RemoteAddr.iSockaddrLength;
                    native.RemoteAddr.lpSockAddr = input.RemoteAddr.lpSockAddr;
 
                    Marshal.StructureToPtr(native, target, false);
                } 
                ~CsAddrInfoSafe() 
                {
                    Dispose(false); 
                }
                public virtual void Dispose()
                {
                    Dispose(true); 
                    GC.SuppressFinalize(this);
                } 
                void Dispose(bool disposing) 
                {
                    if(disposed) 
                    {
                        if(disposing)
                        {
                            LocalAddr.Dispose(); 
                            RemoteAddr.Dispose();
                        } 
                    } 
                    disposed = true;
                } 

            }

            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
            internal struct CsAddrInfoNative
            { 
                public SOCKET_ADDRESS_NATIVE LocalAddr; 
                public SOCKET_ADDRESS_NATIVE RemoteAddr;
                public int iSocketType; 
                public int iProtocol;
            }

            [Serializable] 
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            internal struct PnrpCloudId 
            { 
                public int AddressFamily; // should be AF_INET6
                public PnrpScope Scope;     // Global, site, or link 
                public uint ScopeId;       // specifies interface

            }
 
            internal struct PnrpCloudInfo
            { 
                public int dwSize;            // size of this struct 
                public PnrpCloudId Cloud;       // network cloud information
                public PnrpCloudState dwCloudState; // state of cloud 
                public PnrpCloudFlags Flags;
            }

            //native equivalent for easy marshalling. 
            //should be exactly like PnrpInfo except CriticalHandles
            internal struct PnrpInfoNative 
            { 
                public int dwSize;            // size of this struct
                public string lpwszIdentity;  // identity name string 
                public int nMaxResolve;       // number of desired resolutions
                public int dwTimeout;         // time in seconds to wait for responses
                public int dwLifetime;        // time in seconds for validity
                public PnrpResolveCriteria enResolveCriteria; // criteria for resolve matches 
                public int dwFlags;           // set of flags
                public SOCKET_ADDRESS_NATIVE saHint; // IPv6 addr use for location 
                public PnrpRegisteredIdState enNameState; // state of registered name 
            }
 
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            internal struct PnrpInfo
            {
                public int dwSize;            // size of this struct 
                public string lpwszIdentity;  // identity name string
                public int nMaxResolve;       // number of desired resolutions 
                public int dwTimeout;         // time in seconds to wait for responses 
                public int dwLifetime;        // time in seconds for validity
                public PnrpResolveCriteria enResolveCriteria; // criteria for resolve matches 
                public int dwFlags;           // set of flags
                public SOCKET_ADDRESS_SAFE saHint; // IPv6 addr use for location
                public PnrpRegisteredIdState enNameState; // state of registered name
                public static void ToPnrpInfoNative(PnrpInfo source, ref PnrpInfoNative target) 
                {
                    target.dwSize = source.dwSize; 
                    target.lpwszIdentity = source.lpwszIdentity; 
                    target.nMaxResolve = source.nMaxResolve;
                    target.dwTimeout = source.dwTimeout; 
                    target.dwLifetime = source.dwLifetime;
                    target.enResolveCriteria = source.enResolveCriteria;
                    target.dwFlags = source.dwFlags;
                    if (source.saHint != null) 
                    {
                        target.saHint.lpSockAddr = source.saHint.lpSockAddr; 
                        target.saHint.iSockaddrLength = source.saHint.iSockaddrLength; 
                    }
                    else 
                    {
                        target.saHint.lpSockAddr = IntPtr.Zero;
                        target.saHint.iSockaddrLength = 0;
                    } 
                    target.enNameState = source.enNameState;
                } 
            } 

            [Serializable] 
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            internal struct sockaddr_in
            {
                public short sin_family; 
                public ushort sin_port;
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 
                public byte[] sin_addr; 
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
                public byte[] sin_zero; 
            }

            [Serializable]
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
            internal struct sockaddr_in6
            { 
                public short sin6_family; 
                public ushort sin6_port;
                public uint sin6_flowinfo; 
                [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
                public byte[] sin6_addr;
                public uint sin6_scope_id;
            } 

            internal class SOCKET_ADDRESS_SAFE : IDisposable 
            { 
                public CriticalAllocHandle lpSockAddr;
                public int iSockaddrLength; 
                bool disposed;
                public static SOCKET_ADDRESS_SAFE SocketAddressFromIPEndPoint(IPEndPoint endpoint)
                {
                    SOCKET_ADDRESS_SAFE socketAddress = new SOCKET_ADDRESS_SAFE(); 
                    if (endpoint == null)
                        return socketAddress; 
 
                    if (endpoint.AddressFamily == AddressFamily.InterNetwork)
                    { 
                        socketAddress.iSockaddrLength = Marshal.SizeOf(typeof(sockaddr_in));
                        socketAddress.lpSockAddr = CriticalAllocHandle.FromSize(socketAddress.iSockaddrLength);
                        sockaddr_in sa = new sockaddr_in();
                        sa.sin_family = (short)AddressFamily.InterNetwork; 
                        sa.sin_port = (ushort)endpoint.Port;
                        sa.sin_addr = endpoint.Address.GetAddressBytes(); 
                        Marshal.StructureToPtr(sa, (IntPtr)socketAddress.lpSockAddr, false); 
                    }
                    else if (endpoint.AddressFamily == AddressFamily.InterNetworkV6) 
                    {
                        socketAddress.iSockaddrLength = Marshal.SizeOf(typeof(sockaddr_in6));
                        socketAddress.lpSockAddr = CriticalAllocHandle.FromSize(socketAddress.iSockaddrLength);
                        sockaddr_in6 sa = new sockaddr_in6(); 
                        sa.sin6_family = (short)AddressFamily.InterNetworkV6;
                        sa.sin6_port = (ushort)endpoint.Port; 
                        sa.sin6_addr = endpoint.Address.GetAddressBytes(); 
                        sa.sin6_scope_id = (uint)endpoint.Address.ScopeId;
                        Marshal.StructureToPtr(sa, (IntPtr)socketAddress.lpSockAddr, false); 
                    }
                    return socketAddress;
                }
 
                ~SOCKET_ADDRESS_SAFE()
                { 
                    Dispose(false); 
                }
 
                public virtual void Dispose()
                {
                    Dispose(true);
                    GC.SuppressFinalize(this); 
                }
 
                void Dispose(bool disposing) 
                {
                    if(!disposed) 
                    {
                        if(disposing)
                            lpSockAddr.Dispose();
                    } 
                    disposed = true;
                } 
 
            }
 
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
            internal struct SOCKET_ADDRESS_NATIVE
            {
                public IntPtr lpSockAddr; 
                public int iSockaddrLength;
            } 
 
            [Serializable]
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
            internal struct WsaData
            {
                public Int16 wVersion;
                public Int16 wHighVersion; 
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)]
                public string szDescription; 
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] 
                public string szSystemStatus;
 
                public Int16 iMaxSockets;
                public Int16 iMaxUdpDg;
                public IntPtr lpVendorInfo;
            } 

            [Serializable] 
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
            internal struct WsaNamespaceInfo
            { 
                public Guid NSProviderId;
                public int dwNameSpace;
                public int fActive;
                public int dwVersion; 
                // don't bother marshalling this as a string since we don't need to look at it
                public IntPtr lpszIdentifier; 
            } 

            // managed equivalent of WSAQUERYSET 
            internal class WsaQuerySet
            {
                public string ServiceInstanceName;
                public Guid ServiceClassId; 
                public string Comment;
                public NspNamespaces NameSpace; 
                public Guid NSProviderId; 
                public string Context;
                public CsAddrInfo[] CsAddrInfos; 
                public object Blob;
                static public WsaQuerySetSafe ToWsaQuerySetSafe(WsaQuerySet input)
                {
 
                    WsaQuerySetSafe result = new WsaQuerySetSafe();
                    if(input == null) 
                        return result; 

                    result.dwSize = Marshal.SizeOf(typeof(WsaQuerySetNative)); 
                    result.lpszServiceInstanceName = CriticalAllocHandleString.FromString(input.ServiceInstanceName);
                    result.lpServiceClassId = CriticalAllocHandleGuid.FromGuid(input.ServiceClassId);
                    result.lpszComment = CriticalAllocHandleString.FromString(input.Comment);
                    result.dwNameSpace = input.NameSpace; 
                    result.lpNSProviderId = CriticalAllocHandleGuid.FromGuid(input.NSProviderId);
                    result.lpszContext = CriticalAllocHandleString.FromString(input.Context); 
                    result.dwNumberOfProtocols = 0; 
                    result.lpafpProtocols = IntPtr.Zero; // not used
                    result.lpszQueryString = IntPtr.Zero; 

                    if (input.CsAddrInfos != null)
                    {
                        result.dwNumberOfCsAddrs = input.CsAddrInfos.Length; 
                        result.addressList = CsAddrInfoSafe.FromAddresses(input.CsAddrInfos);
                    } 
                    result.dwOutputFlags = 0; 
                    result.lpBlob = CriticalAllocHandlePnrpBlob.FromPnrpBlob(input.Blob);
 
                    return result;
                }
            }
 
            internal class CriticalAllocHandlePnrpBlob : CriticalAllocHandle
            { 
                public static CriticalAllocHandle FromPnrpBlob(object input) 
                {
                    BlobSafe blob = new BlobSafe(); 
                    if (input != null)
                    {
                        if (input.GetType() == typeof(PnrpInfo))
                        { 
                            int blobSize = Marshal.SizeOf(typeof(PnrpInfoNative));
                            blob.pBlobData = CriticalAllocHandle.FromSize(blobSize + Marshal.SizeOf(typeof(BlobNative))); 
 
                            //write the BlobSafe fields first,
                            BlobNative nativeBlob; 
                            nativeBlob.cbSize = blobSize;
                            nativeBlob.pBlobData = (IntPtr)(((IntPtr)blob.pBlobData).ToInt64()+Marshal.SizeOf(typeof(BlobNative)));
                            Marshal.StructureToPtr(nativeBlob,(IntPtr)blob.pBlobData,false);
                            PnrpInfo pnrpInfo = (PnrpInfo)input; 
                            pnrpInfo.dwSize = blobSize;
                            PnrpInfoNative nativeInfo = new PnrpInfoNative(); 
                            PnrpInfo.ToPnrpInfoNative(pnrpInfo, ref nativeInfo); 
                            Marshal.StructureToPtr(nativeInfo, (IntPtr)nativeBlob.pBlobData, false);
                            blob.cbSize = blobSize; 
                        }
                        else if(input.GetType() == typeof(PnrpCloudInfo))
                        {
                            int blobSize = Marshal.SizeOf(input.GetType()); 
                            blob.pBlobData = CriticalAllocHandle.FromSize(blobSize + Marshal.SizeOf(typeof(BlobNative)));
 
                            //write the BlobSafe fields first, 
                            BlobNative nativeBlob;
                            nativeBlob.cbSize = blobSize; 
                            nativeBlob.pBlobData = (IntPtr)(((IntPtr)blob.pBlobData).ToInt64()+Marshal.SizeOf(typeof(BlobNative)));
                            Marshal.StructureToPtr(nativeBlob,(IntPtr)blob.pBlobData,false);
                            PnrpCloudInfo cloudInfo = (PnrpCloudInfo)input;
                            cloudInfo.dwSize = Marshal.SizeOf(typeof(PnrpCloudInfo)); 
                            Marshal.StructureToPtr(cloudInfo, (IntPtr)nativeBlob.pBlobData,false);
                            blob.cbSize = blobSize; 
                        } 
                        else
                        { 
                            DiagnosticUtility.DebugAssert("Unknown payload type!");
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperInternal(false);
                        }
                    } 
                    return blob.pBlobData;
 
                } 
            }
 
            internal class CriticalAllocHandleString : CriticalAllocHandle
            {
                public static CriticalAllocHandle FromString(string input)
                { 
                    CriticalAllocHandleString result = new CriticalAllocHandleString();
                    RuntimeHelpers.PrepareConstrainedRegions(); 
                    try{} 
                    finally
                    { 
                        result.SetHandle(Marshal.StringToHGlobalUni(input));
                    }
                    return result;
                } 
            }
 
            internal class CriticalAllocHandleWsaQuerySetSafe : CriticalAllocHandle 
            {
                static int CalculateSize(WsaQuerySetSafe safeQuerySet) 
                {
                    int structSize = Marshal.SizeOf(typeof(WsaQuerySetNative));
                    if(safeQuerySet.addressList != null)
                        structSize += safeQuerySet.addressList.Length * Marshal.SizeOf(typeof(CsAddrInfoNative)); 
                    return structSize;
                } 
 
                public static CriticalAllocHandle FromWsaQuerySetSafe(WsaQuerySetSafe safeQuerySet)
                { 
                    CriticalAllocHandle result = CriticalAllocHandle.FromSize(CalculateSize(safeQuerySet));
                    WsaQuerySetSafe.StructureToPtr(safeQuerySet, (IntPtr)result);
                    return result;
                } 
            }
 
            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] 
            internal class WsaQuerySetSafe : IDisposable
            { 
                public int dwSize;
                public CriticalAllocHandle lpszServiceInstanceName;
                public CriticalAllocHandle lpServiceClassId;
                public IntPtr lpVersion; // not used 
                public CriticalAllocHandle lpszComment;
                public NspNamespaces dwNameSpace; 
                public CriticalAllocHandle lpNSProviderId; 
                public CriticalAllocHandle lpszContext;
                public int dwNumberOfProtocols; // 0 
                public IntPtr lpafpProtocols; // not used
                public IntPtr lpszQueryString; // not used
                public int dwNumberOfCsAddrs;
                public CsAddrInfoSafe[] addressList; 
                public int dwOutputFlags; // 0
                public CriticalAllocHandle lpBlob; 
                bool disposed; 

                ~WsaQuerySetSafe() 
                {
                    Dispose(false);
                }
 
                public virtual void Dispose()
                { 
                    Dispose(true); 
                    GC.SuppressFinalize(this);
                } 

                void Dispose(bool disposing)
                {
                    if(!disposed) 
                    {
                        if(disposing) 
                        { 
                            if(lpszServiceInstanceName != null)
                                lpszServiceInstanceName.Dispose(); 
                            if(lpServiceClassId != null)
                                lpServiceClassId.Dispose();
                            if(lpszComment != null)
                                lpszComment.Dispose(); 
                            if(lpNSProviderId != null)
                                lpNSProviderId.Dispose(); 
                            if(lpBlob != null) 
                                lpBlob.Dispose();
                            if(addressList != null) 
                            {
                                foreach(CsAddrInfoSafe addr in addressList)
                                {
                                    addr.Dispose(); 
                                }
                            } 
                        } 
                    }
                    disposed = true; 
                }

                static public void StructureToPtr(WsaQuerySetSafe input, IntPtr target)
                { 
                    WsaQuerySetNative native = new WsaQuerySetNative();
                    native.dwSize = input.dwSize; 
                    native.lpszServiceInstanceName = input.lpszServiceInstanceName; 
                    native.lpServiceClassId = input.lpServiceClassId;
                    native.lpVersion = IntPtr.Zero; // not used 
                    native.lpszComment = input.lpszComment;
                    native.dwNameSpace = input.dwNameSpace;
                    native.lpNSProviderId = input.lpNSProviderId;
                    native.lpszContext = input.lpszContext; 
                    native.dwNumberOfProtocols = 0; // 0
                    native.lpafpProtocols = IntPtr.Zero; // not used 
                    native.lpszQueryString = IntPtr.Zero; // not used 
                    native.dwNumberOfCsAddrs = input.dwNumberOfCsAddrs;
                    native.dwOutputFlags = 0; // 0 
                    native.lpBlob = input.lpBlob;

                    Int64 sockAddressStart = target.ToInt64()+Marshal.SizeOf(typeof(WsaQuerySetNative));
                    native.lpcsaBuffer = (IntPtr)sockAddressStart; 

                    Marshal.StructureToPtr(native, target, false); 
                    MarshalSafeAddressesToNative(input,(IntPtr)sockAddressStart); 

                } 

                public static void MarshalSafeAddressesToNative(WsaQuerySetSafe safeQuery, IntPtr target)
                {
                   // marshal the addresses 
                    if (safeQuery.addressList != null && safeQuery.addressList.Length > 0)
                    { 
                        int sizeOfCsAddrInfo = Marshal.SizeOf(typeof(CsAddrInfoNative)); 
                        Int64 start = target.ToInt64();
                        DiagnosticUtility.DebugAssert(start%IntPtr.Size == 0, "Invalid alignment!!"); 
                        foreach(CsAddrInfoSafe safeAddress in safeQuery.addressList)
                        {
                            CsAddrInfoSafe.StructureToPtr(safeAddress,(IntPtr)start);
                            start += sizeOfCsAddrInfo; 
                        }
                    } 
                } 

            } 

            [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
            internal struct WsaQuerySetNative
            { 
                public int dwSize;
                public IntPtr lpszServiceInstanceName; 
                public IntPtr lpServiceClassId; 
                public IntPtr lpVersion; // not used
                public IntPtr lpszComment; 
                public NspNamespaces dwNameSpace;
                public IntPtr lpNSProviderId;
                public IntPtr lpszContext;
                public int dwNumberOfProtocols; // 0 
                public IntPtr lpafpProtocols; // not used
                public IntPtr lpszQueryString; // not used 
                public int dwNumberOfCsAddrs; 
                public IntPtr lpcsaBuffer;
                public int dwOutputFlags; // 0 
                public IntPtr lpBlob;
            }

            internal class CriticalLookupHandle : CriticalHandleZeroOrMinusOneIsInvalid 
            {
                protected override bool ReleaseHandle() 
                { 
                    return WSALookupServiceEnd(handle) == 0;
                } 
            }

            // base class for ref-counting WSA uses and calling WSAStartup/WSAShutdown
            internal class DiscoveryBase : MarshalByRefObject, IDisposable 
            {
                static int refCount = 0; 
                static object refCountLock = new object(); 
                bool disposed;
 
                public DiscoveryBase()
                {
                    lock (refCountLock)
                    { 
                        if (refCount == 0)
                        { 
                            WsaData WinsockVersion = new WsaData(); 
                            int ret = WSAStartup(UnsafePnrpNativeMethods.RequiredWinsockVersion, ref WinsockVersion);
                            if (ret != 0) 
                            {
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException(ret));
                            }
                        } 
                        refCount++;
                    } 
                } 

                public void Dispose() 
                {
                    Dispose(true);
                    GC.SuppressFinalize(this);
                } 

                public void Dispose(bool disposing) 
                { 
                    if(!disposed)
                    { 
                        lock (refCountLock)
                        {
                            refCount--;
                            if (refCount == 0) 
                            {
                                WSACleanup(); 
                            } 
                        }
                    } 
                    disposed = true;
                }

                ~DiscoveryBase() 
                {
                    this.Dispose(false); 
                } 

                public bool IsPnrpServiceRunning(TimeSpan waitForService) 
                {
                    TimeoutHelper timeoutHelper = new TimeoutHelper(waitForService);
                    try
                    { 
                        using (ServiceController sc = new ServiceController("pnrpsvc"))
                        { 
                            try 
                            {
                                if(sc.Status == ServiceControllerStatus.StopPending) 
                                {
                                    sc.WaitForStatus(ServiceControllerStatus.Stopped, timeoutHelper.RemainingTime());
                                }
                                if(sc.Status == ServiceControllerStatus.Stopped) 
                                {
                                    sc.Start(); 
                                } 
                                sc.WaitForStatus(ServiceControllerStatus.Running, timeoutHelper.RemainingTime());
                            } 
                            catch(Exception e)
                            {
                                if(DiagnosticUtility.IsFatal(e)) throw;
                                if(e is InvalidOperationException || e is TimeoutException) 
                                    return false;
                                else 
                                    throw; 
                            }
                            return (sc.Status == ServiceControllerStatus.Running); 
                        }
                    }
                    catch(InvalidOperationException e)
                    { 
                        DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
                        DiagnosticUtility.DebugAssert("IsPnrpServiceRunning should be called after IsPnrpInstalled"); 
                        return false; 
                    }
                } 

                public bool IsPnrpAvailable(TimeSpan waitForService)
                {
                    if (!IsPnrpInstalled()) 
                        return false;
 
                    //make sure that the service is running 
                    if (!IsPnrpServiceRunning(waitForService))
                        return false; 
                    // If PNRP is installed, ensure that it supports extended payload by attempting to register with
                    // an invalid query set. If extended payload is not available, "WSASERVICE_NOT_FOUND" is returned.
                    // Otherwise, "WSAEINVAL" is returned.
 
                    //UPDATE: we will work with PNRP 1.0 if it is available.
                    // a separate implementation will work with payload support when available. 
                    WsaQuerySet querySet = new WsaQuerySet(); 
                    querySet.NSProviderId = NsProviderName;
                    querySet.ServiceClassId = SvcIdNameV1; 
                    int res = InvokeService(querySet, WsaSetServiceOp.Register,0);
 					
                    //on xp 64bit, WSANO_DATA is returned
                    if (res == (int)WsaError.WSAEINVAL || res == (int)WsaError.WSANO_DATA) 
                        return true;
 
                    // if the call didn't fail or returned any other error, PNRP clearly isn't working properly 
                    return false;
 
                }

                // determine if any version of PNRP is installed and available
                public bool IsPnrpInstalled() 
                {
                    int size = 0; 
                    int nProviders; 
                    CriticalAllocHandle dataPtr = null;
                    // retrieve the list of installed namespace providers 
                    // implemented in a loop in case the size changes between the first and second calls
                    while (true)
                    {
                        nProviders = WSAEnumNameSpaceProviders(ref size, (IntPtr)dataPtr); 
                        if (nProviders != -1) // success
                            break; 
 
                        int error = WSAGetLastError();
                        if (error != (int)WsaError.WSAEFAULT) // buffer length to small 
                            return false; // any other error effectively means that PNRP isn't usable

                        dataPtr = CriticalAllocHandle.FromSize(size);
                    } 

                    // loop through the providers 
                    for (int i = 0; i < nProviders; i++) 
                    {
                        IntPtr nsInfoPtr = (IntPtr)(((IntPtr)dataPtr).ToInt64() + i * 
                            Marshal.SizeOf(typeof(WsaNamespaceInfo)));
                        WsaNamespaceInfo nsInfo = (WsaNamespaceInfo)Marshal.PtrToStructure(nsInfoPtr,
                            typeof(WsaNamespaceInfo));
 
                        // if this is the PNRP name namespace provider and it is active, it is installed
                        if (nsInfo.NSProviderId == NsProviderName && nsInfo.fActive != 0) 
                            return true; 
                    }
 
                    // no PNRP name namespace provider found
                    return false;
                }
 
                int InvokeService(WsaQuerySet registerQuery, WsaSetServiceOp op, int flags)
                { 
                    WsaQuerySetSafe native = WsaQuerySet.ToWsaQuerySetSafe(registerQuery); 
                    int error = 0;
                    using (native) 
                    {
                        CriticalAllocHandle handle = CriticalAllocHandleWsaQuerySetSafe.FromWsaQuerySetSafe(native);
                        using(handle)
                        { 
                            int retval = WSASetService(handle, op, flags);
                            if (retval != 0) 
                            { 
                                error = WSAGetLastError();
                            } 
                        }
                    }
                    return error;
                } 

            } 
 
            public class PeerCloudEnumerator : DiscoveryBase
            { 
                static public CloudInfo[] GetClouds()
                {
                    int retval = 0;
                    ArrayList clouds = new ArrayList(); 
                    WsaQuerySet querySet = new WsaQuerySet();
                    CriticalLookupHandle hLookup; 
 
                    PnrpCloudInfo cloudInfo = new PnrpCloudInfo();
                    cloudInfo.dwSize = Marshal.SizeOf(typeof(PnrpCloudInfo)); 
                    cloudInfo.Cloud.Scope = PnrpScope.Any;
                    cloudInfo.dwCloudState = (PnrpCloudState)0;
                    cloudInfo.Flags = PnrpCloudFlags.None;
                    querySet.NameSpace = NspNamespaces.Cloud; 
                    querySet.NSProviderId = NsProviderCloud;
                    querySet.ServiceClassId = SvcIdCloud; 
                    querySet.Blob = cloudInfo; 

                    WsaQuerySetSafe native = WsaQuerySet.ToWsaQuerySetSafe(querySet); 
                    using(native)
                    {
                        CriticalAllocHandle handle = CriticalAllocHandleWsaQuerySetSafe.FromWsaQuerySetSafe(native);
                        retval = WSALookupServiceBegin(handle, WsaNspControlFlags.ReturnAll, out hLookup); 
                    }
                    if (retval != 0) 
                    { 
                        // unable to start the enumeration
                        SocketException exception = new SocketException(WSAGetLastError()); 
                        Utility.CloseInvalidOutCriticalHandle(hLookup);
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
                    }
 
                    // start with a sensible default size
                    int size = Marshal.SizeOf(typeof(WsaQuerySetSafe)) + 200; 
                    //wrap in CriticalAllocHandle when PAYLOAD is enabled 
                    CriticalAllocHandle nativeQuerySetPtr = CriticalAllocHandle.FromSize(size);
                    using(hLookup) 
                    {
                        while (true)
                        {
                            retval = WSALookupServiceNext(hLookup, 0, ref size, (IntPtr)nativeQuerySetPtr); 
                            if (retval != 0)
                            { 
                                int error = WSAGetLastError(); 
                                if (error == (int)WsaError.WSAENOMORE || error == (int)WsaError.WSA_E_NO_MORE)
                                { 
                                    // no more
                                    break;
                                }
                                if (error == (int)WsaError.WSAEFAULT) 
                                {
                                    // buffer too small, allocate a bigger one of the specified size 
                                    if(nativeQuerySetPtr != null) 
                                    {
                                        nativeQuerySetPtr.Dispose(); 
                                        nativeQuerySetPtr = null;
                                    }
                                    //wrap in CriticalAllocHandle when PAYLOAD is enabled
                                    nativeQuerySetPtr = CriticalAllocHandle.FromSize(size); 
                                    continue;
                                } 
 
                                // unexpected error
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SocketException(error)); 
                            }
                            else
                            {
                                if (nativeQuerySetPtr != IntPtr.Zero) 
                                {
                                    // marshal the results into something usable 
                                    WsaQuerySet resultQuerySet = PeerNameResolver.MarshalWsaQuerySetNativeToWsaQuerySet(nativeQuerySetPtr,0); 
                                    // extract out the friendly cloud attributes
                                    CloudInfo resultCloudInfo = new CloudInfo(); 
                                    PnrpCloudInfo prnpCloudInfo = (PnrpCloudInfo)resultQuerySet.Blob;
                                    resultCloudInfo.Name = resultQuerySet.ServiceInstanceName;
                                    resultCloudInfo.Scope = prnpCloudInfo.Cloud.Scope;
                                    resultCloudInfo.ScopeId = prnpCloudInfo.Cloud.ScopeId; 
                                    resultCloudInfo.State = prnpCloudInfo.dwCloudState;
                                    resultCloudInfo.Flags = prnpCloudInfo.Flags; 
 
                                    // add it to the list to return later
                                    clouds.Add(resultCloudInfo); 
                                }
                            }
                        }
                    } 

                    // package up the results into a nice array 
                    return (CloudInfo[])clouds.ToArray(typeof(CloudInfo)); 
                }
 
            }

            internal class PeerNameRegistrar : DiscoveryBase
            { 
                const int RegistrationLifetime = 60 * 60; // 1 hour
 
                public PeerNameRegistrar() : base() 
                {
                } 

                public void Register(PnrpRegistration registration, TimeSpan timeout)
                {
                    // fill in the PnrpInfo blob using the defaults 
                    PnrpInfo pnrpInfo = new PnrpInfo();
                    pnrpInfo.dwLifetime = RegistrationLifetime; 
                    pnrpInfo.lpwszIdentity = null; 
                    pnrpInfo.dwSize = Marshal.SizeOf(pnrpInfo);
                    pnrpInfo.dwFlags = PNRPINFO_HINT; 
                    IPEndPoint hint = PnrpPeerResolver.GetHint();
                    pnrpInfo.saHint = SOCKET_ADDRESS_SAFE.SocketAddressFromIPEndPoint(hint);

                    // fill in the query set 
                    WsaQuerySet registerQuery = new WsaQuerySet();
                    registerQuery.NameSpace = NspNamespaces.Name; 
                    registerQuery.NSProviderId = NsProviderName; 
                    registerQuery.ServiceClassId = SvcIdNameV1;
                    registerQuery.ServiceInstanceName = registration.PeerName; 
                    registerQuery.Comment = registration.Comment;
                    registerQuery.Context = registration.CloudName;

                    // copy over the addresses 
                    if (registration.Addresses != null)
                    { 
                        DiagnosticUtility.DebugAssert(registration.Addresses.Length <= 4, "Pnrp supports only 4 addresses"); 
                        registerQuery.CsAddrInfos = new CsAddrInfo[registration.Addresses.Length];
                        for (int i = 0; i < registration.Addresses.Length; i++) 
                        {
                            // the only interesting part of the CsAddrInfo is the LocalAddress
                            registerQuery.CsAddrInfos[i].LocalAddr = registration.Addresses[i];
                            registerQuery.CsAddrInfos[i].iProtocol = (int)ProtocolType.Tcp; 
                            registerQuery.CsAddrInfos[i].iSocketType = (int)SocketType.Stream;
                        } 
                    } 

                    // copy the blob 
                    registerQuery.Blob = pnrpInfo;
                    RegisterService(registerQuery);
                }
 
                public void Unregister(string peerName, List clouds, TimeSpan timeout)
                { 
                    TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
                    foreach(string cloud in clouds)
                    { 
                        try
                        {
                            Unregister(peerName, cloud, timeoutHelper.RemainingTime());
                        } 
                        catch(SocketException e)
                        { 
                            DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information); 
                        }
                    } 
                }

                public void Unregister(string peerName, string cloudName, TimeSpan timeout)
                { 
                    // fill in the PnrpInfo with defaults
                    PnrpInfo identityInfo = new PnrpInfo(); 
                    identityInfo.lpwszIdentity = null; 
                    identityInfo.dwSize = Marshal.SizeOf(typeof(PnrpInfo));
 
                    // fill in the query set
                    WsaQuerySet registerQuery = new WsaQuerySet();
                    registerQuery.NameSpace = NspNamespaces.Name;
                    registerQuery.NSProviderId = NsProviderName; 
                    registerQuery.ServiceClassId = SvcIdNameV1;
                    registerQuery.ServiceInstanceName = peerName; 
                    registerQuery.Context = cloudName; 
                    registerQuery.Blob = identityInfo;
 
                    DeleteService(registerQuery);
                }

                void RegisterService(WsaQuerySet registerQuery) 
                {
                    try 
                    { 
                        InvokeService(registerQuery, WsaSetServiceOp.Register, 0);
                    } 
                    catch(PnrpException)
                    {
                        if(PnrpPeerResolver.MaxAddressEntriesV1 < registerQuery.CsAddrInfos.Length)
                        { 
                            List infos = new List(registerQuery.CsAddrInfos);
                            infos.RemoveRange(PnrpPeerResolver.MaxAddressEntriesV1, registerQuery.CsAddrInfos.Length-PnrpPeerResolver.MaxAddressEntriesV1); 
                            registerQuery.CsAddrInfos = infos.ToArray(); 
                            InvokeService(registerQuery, WsaSetServiceOp.Register, 0);
                        } 
                        else
                            throw;
                    }
                } 

                void DeleteService(WsaQuerySet registerQuery) 
                { 
                    InvokeService(registerQuery, WsaSetServiceOp.Delete, 0);
                } 

                static void InvokeService(WsaQuerySet registerQuery, WsaSetServiceOp op, int flags)
                {
                    WsaQuerySetSafe native = WsaQuerySet.ToWsaQuerySetSafe(registerQuery); 
                    using(native)
                    { 
                        CriticalAllocHandle handle = CriticalAllocHandleWsaQuerySetSafe.FromWsaQuerySetSafe(native); 
                        int retval = WSASetService(handle, op, flags);
                        if (retval != 0) 
                        {
                            int error = WSAGetLastError();
                            PeerExceptionHelper.ThrowPnrpError(error, registerQuery.Context);
                        } 
                    }
                } 
            } 

            internal class PeerNameResolver : AsyncResult //: DiscoveryBase 
            {
                WsaQuerySet resolveQuery;
                List results;
                uint scopeId; 
                Exception lastException;
                TimeoutHelper timeoutHelper; 
 
                public PeerNameResolver(string peerName, int numberOfResultsRequested,
                    PnrpResolveCriteria resolveCriteria, TimeSpan timeout, List results) 
                    : this(peerName, numberOfResultsRequested, resolveCriteria, 0, GlobalCloudName, timeout, results)
                {
                }
 
                public PeerNameResolver(string peerName, int numberOfResultsRequested,
                    PnrpResolveCriteria resolveCriteria, uint scopeId, string cloudName, TimeSpan timeout, List results) 
                    : base(null,null) 
                {
                    // pnrp has a hard-coded limit on the timeout value that can be passed to it 
                    // maximum value is 10 minutes
                    if (timeout > MaxTimeout)
                    {
                        timeout = MaxTimeout; 
                    }
                    timeoutHelper = new TimeoutHelper(timeout); 
                    PnrpInfo resolveQueryInfo = new PnrpInfo(); 
                    resolveQueryInfo.dwSize = Marshal.SizeOf(typeof(PnrpInfo));
                    resolveQueryInfo.nMaxResolve = numberOfResultsRequested; 
                    resolveQueryInfo.dwTimeout = (int)timeout.TotalSeconds;
                    resolveQueryInfo.dwLifetime = 0;
                    resolveQueryInfo.enNameState = 0;
                    resolveQueryInfo.lpwszIdentity = null; 
                    resolveQueryInfo.dwFlags = PNRPINFO_HINT;
                    IPEndPoint hint = PnrpPeerResolver.GetHint(); 
                    resolveQueryInfo.enResolveCriteria = resolveCriteria ; 
                    resolveQueryInfo.saHint = SOCKET_ADDRESS_SAFE.SocketAddressFromIPEndPoint(hint);
                    resolveQuery = new WsaQuerySet(); 
                    resolveQuery.ServiceInstanceName = peerName;
                    resolveQuery.ServiceClassId = SvcIdNameV1;
                    resolveQuery.NameSpace = NspNamespaces.Name;
                    resolveQuery.NSProviderId = NsProviderName; 
                    resolveQuery.Context = cloudName;
                    resolveQuery.Blob = resolveQueryInfo; 
                    this.results = results; 
                    this.scopeId = scopeId;
                    IOThreadScheduler.ScheduleCallback(new WaitCallback(SyncEnumeration),null); 
                }

                public void End()
                { 
                    AsyncResult.End(this);
                } 
 
                public void SyncEnumeration(object state)
                { 
                    int retval = 0;
                    CriticalLookupHandle hLookup;
                    WsaQuerySetSafe native = WsaQuerySet.ToWsaQuerySetSafe(resolveQuery);
                    using(native) 
                    {
                        CriticalAllocHandle handle = CriticalAllocHandleWsaQuerySetSafe.FromWsaQuerySetSafe(native); 
                        retval = WSALookupServiceBegin(handle, WsaNspControlFlags.ReturnAll, out hLookup); 
                    }
                    if (retval != 0) 
                    {
                        lastException = new PnrpException(WSAGetLastError(), resolveQuery.Context);
                        Utility.CloseInvalidOutCriticalHandle(hLookup);
                        Complete(false,lastException); 
                        return;
                    } 
                    WsaQuerySet querySet = new WsaQuerySet(); 

                    // start with a sensible default size 
                    int size = Marshal.SizeOf(typeof(WsaQuerySetSafe)) + 400;
                    CriticalAllocHandle nativeQuerySetPtr = CriticalAllocHandle.FromSize(size);
                    try
                    { 
                        using(hLookup)
                        { 
                            while (true) 
                            {
                                if (timeoutHelper.RemainingTime() == TimeSpan.Zero) 
                                {
                                    break;
                                }
                                retval = WSALookupServiceNext(hLookup, 0, ref size, (IntPtr)nativeQuerySetPtr); 
                                if (retval != 0)
                                { 
                                    int error = WSAGetLastError(); 
                                    if (error == (int)WsaError.WSAENOMORE || error == (int)WsaError.WSA_E_NO_MORE)
                                    { 
                                        // no more
                                        break;
                                    }
 
                                    if (error == (int)WsaError.WSAEFAULT)
                                    { 
                                        nativeQuerySetPtr = CriticalAllocHandle.FromSize(size); 
                                        continue;
                                    } 

                                    // unexpected error
                                    PeerExceptionHelper.ThrowPnrpError(error, querySet.Context);
                                } 
                                else
                                { 
                                    if (nativeQuerySetPtr != IntPtr.Zero) 
                                    {
                                        // marshal the results into something useful 
                                        querySet = MarshalWsaQuerySetNativeToWsaQuerySet(nativeQuerySetPtr,scopeId);

                                        // allocate the friendly PnrpRegistration and fill it in
                                        PnrpRegistration pnrpRegistration = new PnrpRegistration(); 
                                        pnrpRegistration.CloudName = querySet.Context;
                                        pnrpRegistration.Comment = querySet.Comment; 
                                        pnrpRegistration.PeerName = querySet.ServiceInstanceName; 
                                        pnrpRegistration.Addresses = new IPEndPoint[querySet.CsAddrInfos.Length];
                                        for (int i = 0; i < querySet.CsAddrInfos.Length; i++) 
                                            pnrpRegistration.Addresses[i] = querySet.CsAddrInfos[i].LocalAddr;

                                        // add it to the list to return later.
                                        // all cloud enumeratos in the same scope will reference the same list and hence the lock. 
                                        lock (results)
                                        { 
                                            results.Add(pnrpRegistration); 
                                        }
                                    } 
                                }
                            }
                        }
                    } 
                    catch(Exception e)
                    { 
                        if(DiagnosticUtility.IsFatal(e)) throw; 
                        DiagnosticUtility.ExceptionUtility.TraceHandledException(e, TraceEventType.Information);
                        if (DiagnosticUtility.ShouldTraceInformation) 
                        {
                            PnrpResolveExceptionTraceRecord record = new PnrpResolveExceptionTraceRecord(resolveQuery.ServiceInstanceName,resolveQuery.Context,e);
                            if (DiagnosticUtility.ShouldTraceError)
                            { 
                                TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.PnrpResolveException, record, this, null);
                            } 
                        } 
                        lastException = e;
                    } 
                    finally
                    {
                        Complete(false, lastException);
                    } 
                }
 
                static internal WsaQuerySet MarshalWsaQuerySetNativeToWsaQuerySet(IntPtr pNativeData) 
                {
                    return MarshalWsaQuerySetNativeToWsaQuerySet(pNativeData,0); 
                }

                static internal WsaQuerySet MarshalWsaQuerySetNativeToWsaQuerySet(IntPtr pNativeData, uint scopeId)
                { 
                    if (pNativeData == IntPtr.Zero)
                        return null; 
 
                    WsaQuerySet querySet = new WsaQuerySet();
                    // build a native structure from the raw memory 
                    WsaQuerySetNative nativeQuerySet;
                    nativeQuerySet = (WsaQuerySetNative)Marshal.PtrToStructure(pNativeData,
                        typeof(WsaQuerySetNative));
                    CsAddrInfoNative nativeCsAddrInfo; 
                    int sizeOfCsAddrInfo = Marshal.SizeOf(typeof(CsAddrInfoNative));
 
                    // copy over the simple fields 
                    querySet.Context = Marshal.PtrToStringUni(nativeQuerySet.lpszContext);
                    querySet.NameSpace = nativeQuerySet.dwNameSpace; 
                    querySet.ServiceInstanceName = Marshal.PtrToStringUni(nativeQuerySet.lpszServiceInstanceName);
                    querySet.Comment = Marshal.PtrToStringUni(nativeQuerySet.lpszComment);

                    // copy the addresses 
                    querySet.CsAddrInfos = new CsAddrInfo[nativeQuerySet.dwNumberOfCsAddrs];
                    for (int i = 0; i < nativeQuerySet.dwNumberOfCsAddrs; i++) 
                    { 
                        IntPtr addressPtr = (IntPtr)(nativeQuerySet.lpcsaBuffer.ToInt64() + (i * sizeOfCsAddrInfo));
                        nativeCsAddrInfo = (CsAddrInfoNative)Marshal.PtrToStructure(addressPtr, 
                            typeof(CsAddrInfoNative));
                        querySet.CsAddrInfos[i].iProtocol = nativeCsAddrInfo.iProtocol;
                        querySet.CsAddrInfos[i].iSocketType = nativeCsAddrInfo.iSocketType;
                        querySet.CsAddrInfos[i].LocalAddr = IPEndPointFromSocketAddress(nativeCsAddrInfo.LocalAddr,scopeId); 
                        querySet.CsAddrInfos[i].RemoteAddr = IPEndPointFromSocketAddress(nativeCsAddrInfo.RemoteAddr,scopeId);
                    } 
 
                    // copy the GUIDs
                    if (nativeQuerySet.lpNSProviderId != IntPtr.Zero) 
                        querySet.NSProviderId = (Guid)Marshal.PtrToStructure(nativeQuerySet.lpNSProviderId,
                            typeof(Guid));

                    if (nativeQuerySet.lpServiceClassId != IntPtr.Zero) 
                        querySet.ServiceClassId = (Guid)Marshal.PtrToStructure(nativeQuerySet.lpServiceClassId,
                            typeof(Guid)); 
 
                    // marshal the BLOB according to namespace
                    if (querySet.NameSpace == NspNamespaces.Cloud) 
                    {
                        if (nativeQuerySet.lpBlob != IntPtr.Zero)
                        {
                            // give it a default value 
                            querySet.Blob = new PnrpCloudInfo();
                            // marshal the blob in order to get the pointer 
                            BlobNative blob = (BlobNative)Marshal.PtrToStructure(nativeQuerySet.lpBlob, typeof(BlobNative)); 
                            // marshal the actual PnrpCloudInfo
                            if (blob.pBlobData != IntPtr.Zero) 
                                querySet.Blob = (PnrpCloudInfo)Marshal.PtrToStructure(blob.pBlobData,
                                    typeof(PnrpCloudInfo));
                        }
                    } 

                    else if (querySet.NameSpace == NspNamespaces.Name) 
                    { 
                        if (nativeQuerySet.lpBlob != IntPtr.Zero)
                        { 
                            // give it a default value
                            querySet.Blob = new PnrpInfo();
                            // marshal the blob in order to get the pointer
                            BlobSafe blob = (BlobSafe)Marshal.PtrToStructure(nativeQuerySet.lpBlob, typeof(BlobSafe)); 
                            // marshal the actual PnrpInfo
                            if (blob.pBlobData != IntPtr.Zero) 
                            { 
                                PnrpInfo pnrpInfo = (PnrpInfo)Marshal.PtrToStructure(blob.pBlobData,
                                    typeof(PnrpInfo)); 
                                querySet.Blob = pnrpInfo;
                            }
                        }
                    } 

                    return querySet; 
                } 

                static IPEndPoint IPEndPointFromSocketAddress(SOCKET_ADDRESS_NATIVE socketAddress, uint scopeId) 
                {
                    IPEndPoint endPoint = null;
                    if (socketAddress.lpSockAddr != IntPtr.Zero)
                    { 
                        AddressFamily addressFamily = (AddressFamily)Marshal.ReadInt16(socketAddress.lpSockAddr);
                        if (addressFamily == AddressFamily.InterNetwork) 
                        { 
                            // if the sockaddr length is not the sizeof(sockaddr_in), the data is invalid so
                            // return an null endpoint 
                            if (socketAddress.iSockaddrLength == Marshal.SizeOf(typeof(sockaddr_in)))
                            {
                                sockaddr_in sa = (sockaddr_in)Marshal.PtrToStructure(socketAddress.lpSockAddr,
                                    typeof(sockaddr_in)); 
                                endPoint = new IPEndPoint(new IPAddress(sa.sin_addr), sa.sin_port);
                            } 
                        } 
                        else if (addressFamily == AddressFamily.InterNetworkV6)
                        { 
                            // if the sockaddr length is not the sizeof(sockaddr_in6), the data is invalid so
                            // return an null endpoint
                            if (socketAddress.iSockaddrLength == Marshal.SizeOf(typeof(sockaddr_in6)))
                            { 
                                sockaddr_in6 sa = (sockaddr_in6)Marshal.PtrToStructure(socketAddress.lpSockAddr,
                                    typeof(sockaddr_in6)); 
                                if(scopeId != 0 && sa.sin6_scope_id != 0) 
                                    scopeId = sa.sin6_scope_id;
                                endPoint = new IPEndPoint(new IPAddress(sa.sin6_addr, scopeId), sa.sin6_port); 
                            }
                        }
                        // else this is an unknown address family, so return null
                    } 

                    return endPoint; 
                } 

            } 
        }
        public override bool Equals(object other)
        {
            return ((other as PnrpPeerResolver) != null); 
        }
 
        public override int GetHashCode() 
        {
            return base.GetHashCode(); 
        }

    }
} 

// 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