📄 finder.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
#include "pch.h"
#pragma hdrstop
#include "ncbase.h"
#include "upnp.h"
#include "auto_xxx.hxx"
#include "variant.h"
#include "url_verifier.h"
#include "upnp_config.h"
#include "main.h"
#include "finder.h"
#include "device.h"
#define FINDERCBSIG 'UPNP'
extern url_verifier* g_pURL_Verifier;
void ServiceCallback(SSDP_CALLBACK_TYPE cbType, CONST SSDP_MESSAGE *pSsdpService, void *pContext);
static void GetUDN(LPCSTR pszUSN, ce::string* pstr);
// StateVariableChanged
void FinderCallback::StateVariableChanged(LPCWSTR pwszName, LPCWSTR pwszValue)
{
Assert(FALSE);
}
// ServiceInstanceDied
void FinderCallback::ServiceInstanceDied(LPCWSTR pszUSN)
{
SSDP_MESSAGE SsdpService;
ce::string strUSN;
memset(&SsdpService, 0, sizeof(SsdpService));
if(!ce::WideCharToMultiByte(CP_ACP, pszUSN, -1, &strUSN))
return;
RemoveReportedDevice(strUSN);
SsdpService.szUSN = const_cast<LPSTR>(static_cast<LPCSTR>(strUSN));
ServiceCallback(SSDP_BYEBYE, &SsdpService, this);
}
// AliveNotification
void FinderCallback::AliveNotification(LPCWSTR pszUSN, LPCWSTR pszLocation, LPCWSTR pszNls, DWORD dwLifeTime)
{
SSDP_MESSAGE SsdpService;
ce::string strUSN;
ce::string strLocation;
ce::string strNls;
memset(&SsdpService, 0, sizeof(SsdpService));
if(!ce::WideCharToMultiByte(CP_ACP, pszUSN, -1, &strUSN))
return;
if(!ce::WideCharToMultiByte(CP_ACP, pszLocation, -1, &strLocation))
return;
ce::WideCharToMultiByte(CP_ACP, pszNls, -1, &strNls);
SsdpService.szUSN = const_cast<LPSTR>(static_cast<LPCSTR>(strUSN));
SsdpService.szLocHeader = const_cast<LPSTR>(static_cast<LPCSTR>(strLocation));
SsdpService.szNls = const_cast<LPSTR>(static_cast<LPCSTR>(strNls));
SsdpService.iLifeTime = dwLifeTime;
ServiceCallback(SSDP_ALIVE, &SsdpService, this);
}
void FinderCallback::GetUPnPDeviceAsync(LPCSTR pszUSN, LPCSTR pszUrl, LPCSTR pszNls, UINT nLifeTime)
{
ASSERT(pszUSN && pszUrl && *pszUSN && *pszUrl);
//
// Validate URL
//
if(!g_pURL_Verifier->is_url_ok(pszUrl))
{
TraceTag(ttidError, "GetUPnPDeviceAsync: invalid device description URL");
return;
}
//
// ANSI code page for UDN
//
ce::wstring wstrURL;
ce::MultiByteToWideChar(CP_ACP, pszUrl, -1, &wstrURL);
if(AsyncDeviceLoader* pAsyncDeviceLoader = new AsyncDeviceLoader(this, pszUSN, pszUrl, pszNls, nLifeTime))
{
HRESULT hr;
// hold reference to device loader object for the time of loading
pAsyncDeviceLoader->AddRef();
// parse device description
if(FAILED(hr = pAsyncDeviceLoader->LoadAsync(wstrURL)))
{
DEBUGMSG(ZONE_ERROR, (L"UPNP: LoadAsync failed 0x%x\n", hr));
pAsyncDeviceLoader->Release();
RemoveReportedDevice(pszUSN);
}
}
else
{
DEBUGMSG(ZONE_ERROR, (L"UPNP: OOM creating AsyncDeviceLoader\n"));
RemoveReportedDevice(pszUSN);
}
}
HRESULT STDMETHODCALLTYPE FinderCallback::AsyncDeviceLoader::LoadComplete(/* [in] */HRESULT hrLoadResult)
{
if(SUCCEEDED(hrLoadResult))
{
IUPnPDevice *pUPnPDevice = NULL;
ce::wstring wstrUDN;
ce::string strUDN;
ce::auto_bstr bstrUDN;
HRESULT hr;
// find UDN from USN
GetUDN(m_strUSN, &strUDN);
// ANSI code page for UDN
ce::MultiByteToWideChar(CP_ACP, strUDN, -1, &wstrUDN);
bstrUDN = SysAllocString(wstrUDN);
ASSERT(m_pDescription);
// find device with given UDN
if(SUCCEEDED(hr = m_pDescription->DeviceByUDN(bstrUDN, &pUPnPDevice)))
{
ASSERT(pUPnPDevice);
m_pfcb->Lock();
m_pfcb->PerformCallback(SSDP_ALIVE, bstrUDN, pUPnPDevice);
m_pfcb->Unlock();
pUPnPDevice->Release();
pUPnPDevice = NULL;
}
else
{
DEBUGMSG(ZONE_ERROR, (L"UPNP: Error 0x%x getting device by UDN %a\n", hr, static_cast<LPCSTR>(strUDN)));
m_pfcb->RemoveReportedDevice(m_strUSN);
}
ASSERT(!pUPnPDevice);
}
else
{
DEBUGMSG(ZONE_ERROR, (L"UPNP: Error 0x%x loading device description from %a\n", hrLoadResult, static_cast<LPCSTR>(m_strLocHeader)));
m_pfcb->RemoveReportedDevice(m_strUSN);
}
// release the reference
Release();
return S_OK;
}
// DumpSSDPMessage
void DumpSSDPMessage(PSSDP_MESSAGE pMsg)
{
WCHAR szBuf[512];
DEBUGMSG(ZONE_TRACE, (L"SSDP Message\n"));
MultiByteToWideChar(CP_ACP, 0, pMsg->szType, -1, szBuf, 512);
DEBUGMSG(ZONE_TRACE, (L"szType = %s\n", szBuf));
MultiByteToWideChar(CP_ACP, 0, pMsg->szLocHeader, -1, szBuf, 512);
DEBUGMSG(ZONE_TRACE, (L"szLocHeader = %s\n", szBuf));
MultiByteToWideChar(CP_ACP, 0, pMsg->szAltHeaders, -1, szBuf, 512);
DEBUGMSG(ZONE_TRACE, (L"szAltHeaders = %s\n", szBuf));
MultiByteToWideChar(CP_ACP, 0, pMsg->szNls, -1, szBuf, 512);
DEBUGMSG(ZONE_TRACE, (L"szNls = %s\n", szBuf));
MultiByteToWideChar(CP_ACP, 0, pMsg->szUSN, -1, szBuf, 512);
DEBUGMSG(ZONE_TRACE, (L"szUSN = %s\n", szBuf));
MultiByteToWideChar(CP_ACP, 0, pMsg->szSid, -1, szBuf, 512);
DEBUGMSG(ZONE_TRACE, (L"szSid = %s\n", szBuf));
DEBUGMSG(ZONE_TRACE, (L"iSeq = %d\n", pMsg->iSeq));
DEBUGMSG(ZONE_TRACE, (L"iLifeTime = %d\n\n", pMsg->iLifeTime));
}
// GetUDN
static void GetUDN(LPCSTR pszUSN, ce::string* pstr)
{
LPCSTR psz = strstr(pszUSN, "::");
if(psz)
pstr->assign(pszUSN, psz - pszUSN);
else
pstr->assign(pszUSN);
}
// GetUPnPDevice
HRESULT GetUPnPDevice(LPCSTR pszUSN, LPCSTR pszUrl, UINT nLifeTime, IUPnPDevice **ppUPnPDevice)
{
ASSERT(pszUSN && pszUrl && ppUPnPDevice && *pszUSN && *pszUrl);
ce::wstring wstrURL;
ce::wstring wstrUDN;
ce::string strUDN;
// ANSI code page for UDN
ce::MultiByteToWideChar(CP_ACP, pszUrl, -1, &wstrURL);
if(!g_pURL_Verifier->is_url_ok(pszUrl))
{
TraceTag(ttidError, "GetUPnPDevice: invalid device description URL");
return E_FAIL;
}
// find UDN from USN
GetUDN(pszUSN, &strUDN);
// ANSI code page for UDN
ce::MultiByteToWideChar(CP_ACP, strUDN, -1, &wstrUDN);
if(DeviceDescription* pDescription = new DeviceDescription(nLifeTime))
{
// hold reference to device description object for the time of parsing
pDescription->AddRef();
// parse device description
pDescription->Load(const_cast<BSTR>(static_cast<LPCWSTR>(wstrURL)));
// find device with given UDN
pDescription->DeviceByUDN(const_cast<BSTR>(static_cast<LPCWSTR>(wstrUDN)), ppUPnPDevice);
// release the reference
// if device with given UDN was found it will hold reference to device description
// otherwise device description will be deleted at this moment
pDescription->Release();
}
return *ppUPnPDevice ? S_OK : E_FAIL;
}
// ServiceCallback
void ServiceCallback(SSDP_CALLBACK_TYPE cbType, CONST SSDP_MESSAGE *pSsdpService, void *pContext)
{
ce::string strUDN;
ce::auto_bstr bstrUDN;
ASSERT((cbType == SSDP_DONE) || (pSsdpService != NULL));
FinderCallback *pfcb = reinterpret_cast<FinderCallback*>(pContext);
if ((pfcb == NULL) || (pfcb->dwSig != FINDERCBSIG))
return;
pfcb->AddRef();
pfcb->Lock();
HRESULT hr = S_OK;
if (cbType == SSDP_FOUND || cbType == SSDP_ALIVE)
{
// check if device has already been reported
for(ce::list<FinderCallback::Device>::iterator it = pfcb->listReported.begin(), itEnd = pfcb->listReported.end(); it != itEnd; ++it)
if(it->strUSN == pSsdpService->szUSN)
{
if(it->strLocation == pSsdpService->szLocHeader ||
pSsdpService->szNls != NULL && it->strNls == pSsdpService->szNls)
{
if(pSsdpService->szNls != NULL)
it->strNls = pSsdpService->szNls;
pfcb->Unlock();
pfcb->Release();
return;
}
pfcb->listReported.erase(it);
pfcb->Unlock();
ServiceCallback(SSDP_BYEBYE, pSsdpService, pContext);
pfcb->Lock();
break;
}
pfcb->listReported.push_front(FinderCallback::Device(pSsdpService->szUSN, pSsdpService->szLocHeader, pSsdpService->szNls));
if(cbType == SSDP_ALIVE)
{
// delay processing of unsolicited announcement by random number of seconds
int nDelay = (10 * rand()) % upnp_config::max_control_point_delay();
DEBUGMSG(ZONE_CALLBACK, (L"UPNP:ServiceCallback delaying control point response by %d ms\n", nDelay));
Sleep(nDelay);
}
DEBUGMSG(ZONE_CALLBACK, (L"UPNP:ServiceCallback-Found device :%a of type %a at %a.\n", pSsdpService->szUSN, pSsdpService->szType, pSsdpService->szLocHeader));
DEBUGMSG(ZONE_CALLBACK, (L"UPNP:ServiceCallback-Attempting to load device description\n"));
pfcb->GetUPnPDeviceAsync(pSsdpService->szUSN, pSsdpService->szLocHeader, pSsdpService->szNls, pSsdpService->iLifeTime);
}
else if (cbType == SSDP_BYEBYE)
{
ce::wstring wstrUDN;
ce::string strUDN;
GetUDN(pSsdpService->szUSN, &strUDN);
// ANSI code page for UDN
ce::MultiByteToWideChar(CP_ACP, strUDN, -1, &wstrUDN);
DEBUGMSG(ZONE_CALLBACK, (L"UPNP:ServiceCallback-Device (%s) going away.\n", static_cast<LPCWSTR>(wstrUDN)));
bstrUDN = SysAllocString(wstrUDN);
pfcb->Unlock();
// we must not hold the lock when calling into the users callback
pfcb->PerformCallback(cbType, bstrUDN, NULL);
pfcb->Lock();
}
else if (cbType == SSDP_DONE)
{
pfcb->Unlock();
// we must not hold the lock when calling into the users callback
pfcb->PerformCallback(cbType, NULL, NULL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -