2025-11-28 00:35:46 +09:00

414 lines
11 KiB
C

/********************************************************************++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) Microsoft Corporation. All Rights Reserved.
Module Name:
PNRP.c
Abstract:
This C file includes sample code which wraps winsock calls for
using PNRP functionality.
--********************************************************************/
#pragma warning(disable:4201) // nameless struct/union
#include "graphchat.h"
#include <initguid.h>
#include <pnrpns.h>
#include "pnrp.h"
const DWORD REGISTRATION_LIFETIME = 60 * 60 * 8; // 8 hours
//-------------------------------------------------------------------------
// Function: PnrpRegister
//
// Purpose: Register the given name in the PNRP cloud
//
// Arguments:
// pwzIdentity : identity string created using PeerIdentityCreate
// pwzName : name to register in PNRP, generally the graph id
// pwzCloud : name of cloud to register in, NULL = global cloud
// pNodeInfo : local node info returned from PeerGraphGetNodeInfo
//
// Returns: HRESULT
//
HRESULT PnrpRegister(PCWSTR pwzIdentity, PCWSTR pwzName,
PCWSTR pwzCloud, __in PEER_NODE_INFO* pNodeInfo)
{
HRESULT hr = S_OK;
CSADDR_INFO* pCsaAddr = NULL;
PNRPINFO pnrpInfo = {0};
BLOB blPnrpData = {0};
WSAQUERYSET querySet = {0};
ULONG nAddrs = 0;
ULONG i;
INT iRet;
//
// build a CSADDR_INFO array from the PEER_NODE_INFO
//
if (pNodeInfo->cAddresses < 1)
{
// need at least one address to register
hr = E_INVALIDARG;
}
if (SUCCEEDED(hr))
{
// do not attempt to register more addresses than PNRP allows
if (pNodeInfo->cAddresses > PNRP_MAX_ENDPOINT_ADDRESSES)
{
nAddrs = PNRP_MAX_ENDPOINT_ADDRESSES;
}
else
{
nAddrs = pNodeInfo->cAddresses;
}
pCsaAddr = (CSADDR_INFO*)malloc(sizeof(CSADDR_INFO) * nAddrs);
if (pCsaAddr != NULL)
{
// copy the addresses from PEER_NODE_INFO into CSADDR_INFO format
for (i = 0; i < nAddrs; i++)
{
pCsaAddr[i].iProtocol = IPPROTO_TCP;
pCsaAddr[i].iSocketType = SOCK_STREAM;
pCsaAddr[i].LocalAddr.iSockaddrLength = sizeof(SOCKADDR_IN6);
pCsaAddr[i].LocalAddr.lpSockaddr = (LPSOCKADDR) &pNodeInfo->pAddresses[i].sin6;
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
if (SUCCEEDED(hr))
{
//
// build the WSAQUERYSET required to register
//
pnrpInfo.dwSize = sizeof(pnrpInfo);
pnrpInfo.dwLifetime = REGISTRATION_LIFETIME;
pnrpInfo.lpwszIdentity = (PWSTR) pwzIdentity;
blPnrpData.cbSize = sizeof(pnrpInfo);
blPnrpData.pBlobData = (BYTE*)&pnrpInfo;
querySet.dwSize = sizeof(querySet);
querySet.dwNameSpace = NS_PNRPNAME;
querySet.dwNumberOfCsAddrs = nAddrs;
querySet.lpServiceClassId = (LPGUID)&SVCID_PNRPNAME;
querySet.lpszServiceInstanceName = (PWSTR) pwzName;
querySet.lpszContext = (PWSTR) pwzCloud;
querySet.lpszComment = L"GraphChatMember";
querySet.lpcsaBuffer = pCsaAddr;
querySet.lpBlob = &blPnrpData;
// register the name with PNRP
iRet = WSASetService(&querySet, RNRSERVICE_REGISTER, 0);
if (iRet != 0)
{
hr = HRESULT_FROM_WIN32(WSAGetLastError());
}
}
if (pCsaAddr != NULL)
{
free(pCsaAddr);
}
return hr;
}
//-------------------------------------------------------------------------
// Function: PnrpResolve
//
// Purpose: Resolve the given name within a PNRP cloud
//
// Arguments:
// pwzName : name to resolve in PNRP, generally the graph id
// pwzCloud : name of cloud to resolve in, NULL = global cloud
// pAddr : pointer to result buffer
//
// Returns: HRESULT
//
HRESULT PnrpResolve(PCWSTR pwzName, PCWSTR pwzCloud, __out SOCKADDR_IN6* pAddr)
{
HRESULT hr = S_OK;
PNRPINFO pnrpInfo = {0};
BLOB blPnrpData = {0};
WSAQUERYSET querySet = {0};
WSAQUERYSET* pResults = NULL;
WSAQUERYSET tempResultSet = {0};
HANDLE hLookup = NULL;
BOOL fFound = FALSE;
DWORD dwError;
INT iRet;
ULONG i;
DWORD dwSize = 0;
//
// fill in the WSAQUERYSET
//
pnrpInfo.dwSize = sizeof(pnrpInfo);
pnrpInfo.nMaxResolve = 1;
pnrpInfo.dwTimeout = 30;
pnrpInfo.enResolveCriteria = PNRP_RESOLVE_CRITERIA_NON_CURRENT_PROCESS_PEER_NAME;
blPnrpData.cbSize = sizeof(pnrpInfo);
blPnrpData.pBlobData = (BYTE*)&pnrpInfo;
querySet.dwSize = sizeof(querySet);
querySet.dwNameSpace = NS_PNRPNAME;
querySet.lpServiceClassId = (LPGUID)&SVCID_PNRPNAME;
querySet.lpszServiceInstanceName = (PWSTR) pwzName;
querySet.lpszContext = (PWSTR) pwzCloud;
querySet.lpBlob = &blPnrpData;
// start resolve
iRet = WSALookupServiceBegin(
&querySet,
LUP_RETURN_NAME | LUP_RETURN_ADDR | LUP_RETURN_COMMENT,
&hLookup);
if (iRet != 0)
{
hr = HRESULT_FROM_WIN32(WSAGetLastError());
}
if (SUCCEEDED(hr))
{
dwSize = sizeof(tempResultSet);
// retrieve the required size
iRet = WSALookupServiceNext(hLookup, 0, &dwSize, &tempResultSet);
dwError = WSAGetLastError();
if (dwError == WSAEFAULT)
{
// allocate space for the results
pResults = (WSAQUERYSET*)malloc(dwSize);
if (pResults == NULL)
{
hr = HRESULT_FROM_WIN32(WSAGetLastError());
}
}
else
{
hr = HRESULT_FROM_WIN32(dwError);
}
}
if (SUCCEEDED(hr))
{
// retrieve the addresses
iRet = WSALookupServiceNext(hLookup, 0, &dwSize, pResults);
if (iRet != 0)
{
hr = HRESULT_FROM_WIN32(WSAGetLastError());
}
}
if (SUCCEEDED(hr))
{
// return the first IPv6 address found
for (i = 0; i < pResults->dwNumberOfCsAddrs; i++)
{
if (pResults->lpcsaBuffer[i].iProtocol == IPPROTO_TCP &&
pResults->lpcsaBuffer[i].RemoteAddr.iSockaddrLength == sizeof(SOCKADDR_IN6))
{
CopyMemory(pAddr, pResults->lpcsaBuffer[i].RemoteAddr.lpSockaddr, sizeof(SOCKADDR_IN6));
fFound = TRUE;
break;
}
}
if (!fFound)
{
// unable to find an IPv6 address
hr = HRESULT_FROM_WIN32(WSA_E_NO_MORE);
}
}
if (hLookup != NULL)
{
WSALookupServiceEnd(hLookup);
}
free(pResults);
return hr;
}
//-------------------------------------------------------------------------
// Function: PnrpUnregister
//
// Purpose: Unregister the given name from the PNRP cloud
//
// Arguments:
// pwzIdentity : identity string originally used to register the name
// pwzName : name to unregister from PNRP
// pwzCloud : name of cloud to unregister from, NULL = global cloud
//
// Returns: HRESULT
//
HRESULT PnrpUnregister(PCWSTR pwzIdentity, PCWSTR pwzName, PCWSTR pwzCloud)
{
HRESULT hr = S_OK;
PNRPINFO pnrpInfo = {0};
BLOB blPnrpData = {0};
WSAQUERYSET querySet = {0};
INT iRet;
//
// build the WSAQUERYSET required to unregister
//
pnrpInfo.dwSize = sizeof(pnrpInfo);
pnrpInfo.dwLifetime = REGISTRATION_LIFETIME;
pnrpInfo.lpwszIdentity = (PWSTR) pwzIdentity;
blPnrpData.cbSize = sizeof(pnrpInfo);
blPnrpData.pBlobData = (BYTE*)&pnrpInfo;
querySet.dwSize = sizeof(querySet);
querySet.dwNameSpace = NS_PNRPNAME;
querySet.lpServiceClassId = (LPGUID)&SVCID_PNRPNAME;
querySet.lpszServiceInstanceName = (PWSTR) pwzName;
querySet.lpszContext = (PWSTR) pwzCloud;
querySet.lpBlob = &blPnrpData;
// unregister the name with PNRP
iRet = WSASetService(&querySet, RNRSERVICE_DELETE, 0);
if (iRet != 0)
{
hr = HRESULT_FROM_WIN32(WSAGetLastError());
}
return hr;
}
//-------------------------------------------------------------------------
// Function: GetLocalCloudInfo
//
// Purpose: Retrieve scope ID and/or local cloud name for use in creating
// and connecting to link local graphs
//
// Arguments:
// pdwLocalScopeID[out]: Identifier of local connection
// pwzCloudName[out] : Name of local connection
// (NULL results in no value returned)
// cchCloudNameSize[in]: number of characters in pwzCloudName
// (usually MAX_CLOUD_NAME)
//
// Returns: HRESULT
//
HRESULT GetLocalCloudInfo(DWORD cchCloudName,
__out_ecount_opt(cchCloudName) PWSTR pwzCloudName,
__out_opt DWORD* pdwLocalScopeID)
{
HRESULT hr = S_OK;
PNRPCLOUDINFO CloudInfo = {0};
BLOB blPnrpData = {0};
WSAQUERYSET querySet = {0};
WSAQUERYSET* pResults = NULL;
WSAQUERYSET tempResultSet = {0};
HANDLE hLookup = NULL;
INT iErr;
DWORD dwErr;
DWORD dwResultSize;
// Fill out information for WSA query
CloudInfo.dwSize = sizeof(CloudInfo);
CloudInfo.Cloud.Scope = PNRP_LINK_LOCAL_SCOPE;
blPnrpData.cbSize = sizeof(CloudInfo);
blPnrpData.pBlobData = (LPBYTE)&CloudInfo;
querySet.dwSize = sizeof(querySet);
querySet.dwNameSpace = NS_PNRPCLOUD;
querySet.lpServiceClassId = (LPGUID)&SVCID_PNRPCLOUD;
querySet.lpBlob = &blPnrpData;
iErr = WSALookupServiceBegin(
&querySet,
LUP_RETURN_NAME|LUP_RETURN_BLOB,
&hLookup);
if (iErr != 0)
{
hr = HRESULT_FROM_WIN32(WSAGetLastError());
}
if (SUCCEEDED(hr))
{
dwResultSize = sizeof(tempResultSet);
// Get size of results
iErr = WSALookupServiceNext(hLookup, 0, &dwResultSize, &tempResultSet);
if (iErr != 0)
{
dwErr = WSAGetLastError();
if (dwErr == WSAEFAULT)
{
// allocate space for results
pResults = (WSAQUERYSET*) malloc(dwResultSize);
if (pResults == NULL)
{
hr = HRESULT_FROM_WIN32(WSAGetLastError());
}
}
else
{
hr = HRESULT_FROM_WIN32(dwErr);
}
}
}
if (SUCCEEDED(hr))
{
// retrieve the local cloud information
iErr = WSALookupServiceNext(hLookup, 0, &dwResultSize, pResults);
if (iErr != 0)
{
hr = HRESULT_FROM_WIN32(WSAGetLastError());
}
}
// Copy the cloud name (if applicable) and scope ID
if (SUCCEEDED(hr))
{
if (pwzCloudName)
{
hr = StringCchCopy(pwzCloudName, cchCloudName, pResults->lpszServiceInstanceName);
if (FAILED(hr))
{
DisplayHrError(L"Failed to copy cloud name", hr);
}
}
if (pdwLocalScopeID)
{
*pdwLocalScopeID = ((PNRPCLOUDINFO*)pResults->lpBlob->pBlobData)->Cloud.ScopeId;
}
}
if (hLookup != NULL)
{
(void) WSALookupServiceEnd(hLookup);
}
free(pResults);
return hr;
}