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;
                }
 public static extern int WSALookupServiceBegin(
     WsaQuerySet qsRestrictions,
     WasLookupControlOptions dwControlControlOptions,
     ref IntPtr lphLookup);
 public PeerNameResolver(string peerName, int numberOfResultsRequested,
     PnrpResolveCriteria resolveCriteria, uint scopeId, string cloudName, TimeSpan timeout, List<PnrpRegistration> 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;
     ActionItem.Schedule(new Action<object>(SyncEnumeration), null);
 }
                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 (Fx.IsFatal(e)) throw;
                        DiagnosticUtility.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,
                                    SR.GetString(SR.TraceCodePnrpResolveException), record, this, null);
                            }
                        }
                        lastException = e;
                    }
                    finally
                    {
                        Complete(false, lastException);
                    }
                }
 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);
         }
     }
 }
                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<CsAddrInfo> infos = new List<CsAddrInfo>(registerQuery.CsAddrInfos);
             infos.RemoveRange(PnrpPeerResolver.MaxAddressEntriesV1, registerQuery.CsAddrInfos.Length - PnrpPeerResolver.MaxAddressEntriesV1);
             registerQuery.CsAddrInfos = infos.ToArray();
             InvokeService(registerQuery, WsaSetServiceOp.Register, 0);
         }
         else
             throw;
     }
 }
                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)
                    {
                        Fx.Assert(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);
                }
                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));
                }
 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 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;

                }
                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;
                }