⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 finder.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// 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 + -