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

📄 cbtarget.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.
//
//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  File:       CALLBACK.CPP
//
//  Contents:   Application LPC callback processing for UPnP device notifications
//
//  Notes:
//      Plays the role of a LPC server, although we are running in client (application) space.
//      The LPC client in this case is the UPNPSVC service.
//
//  Author:     
//
//----------------------------------------------------------------------------
#include <windows.h>
#include <ssdppch.h>
#include <upnpdevapi.h>
#include <ssdpapi.h>
#include <sax.h>
#include <string.hxx>
#include <psl_marshaler.hxx>
#include <UpnpInvokeRequest.hpp>


struct CoGate
{
    CoGate(DWORD dwCoInit = COINIT_MULTITHREADED)
        {CoInitializeEx(NULL, dwCoInit); }

    ~CoGate()
        {CoUninitialize(); }
};

extern CRITICAL_SECTION g_csUPNPAPI;

class SOAPHandler : ce::SAXContentHandler
{
    friend BOOL WINAPI UpnpSetRawControlResponse(UPNPSERVICECONTROL *pSvcCtl, DWORD dwHttpStatus, PCWSTR pszResp);
private:

    DWORD               m_hSource;          // handle to the request object in the UPNPSVC server
    PCWSTR              m_pszUDN;
    PCWSTR              m_pszServiceId;     // UPnP service id (memory not alloced)
    PCWSTR              m_pszRequestXML;    // request body  (memory not alloced)
    PWSTR               m_pszAction;        // action name 
    DWORD               m_cParams;          // number of input parameters 
    DWORD               m_cArgsMax;         // size of the m_pParams array
    UPNPPARAM           *m_pParams;         // input parameters (parsed from request body)
    PWSTR               m_pszServiceType;   // service type(from the UPNP device description)  
    BOOL                m_fResponse;        // TRUE if SetResponse has been called
    // the UPNPSERVICECONTROL struct is used for callbacks into the device implementation.
    // It contains mapped aliases to the actionName, args etc and should not be freed or generally
    // touched.
    UPNPSERVICECONTROL  m_SvcCtl;
    ce::wstring         m_strArgumentValue;
    ce::wstring         m_strArgumentElement;
    ce::wstring         m_strActionElement;
    bool                m_bParsingBody;
    bool                m_bParsingAction;
    bool                m_bParsingArgument;

public:
    SOAPHandler(DWORD hSource, PCWSTR pszUDN, PCWSTR pszServiceId, PCWSTR pszRequestXML);
    ~SOAPHandler();

    BOOL Parse();

    UPNPSERVICECONTROL *GetServiceControl() { return &m_SvcCtl; }
    BOOL SetResponse(DWORD dwHttpStatus, PCWSTR pszResp);
    BOOL Done(BOOL fRet);

    static ce::SAXReader* m_pReader;

// ISAXContentHandler
private:
    virtual HRESULT STDMETHODCALLTYPE startElement(
        /* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
        /* [in] */ int cchNamespaceUri,
        /* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
        /* [in] */ int cchLocalName,
        /* [in] */ const wchar_t __RPC_FAR *pwchQName,
        /* [in] */ int cchQName,
        /* [in] */ ISAXAttributes __RPC_FAR *pAttributes);
    
    virtual HRESULT STDMETHODCALLTYPE endElement( 
        /* [in] */ const wchar_t __RPC_FAR *pwchNamespaceUri,
        /* [in] */ int cchNamespaceUri,
        /* [in] */ const wchar_t __RPC_FAR *pwchLocalName,
        /* [in] */ int cchLocalName,
        /* [in] */ const wchar_t __RPC_FAR *pwchQName,
        /* [in] */ int cchQName);
    
    virtual HRESULT STDMETHODCALLTYPE characters( 
        /* [in] */ const wchar_t __RPC_FAR *pwchChars,
        /* [in] */ int cchChars);
};


ce::SAXReader* SOAPHandler::m_pReader;

class CallbackTarget
{
    private:
    LIST_ENTRY m_link;
    PWSTR m_pszName;
    PUPNPCALLBACK m_pfCallback;
    PVOID m_pvUserContext;
    DWORD m_Id;

    public:

    CallbackTarget(PCWSTR pszName, PUPNPCALLBACK pfCallback, PVOID pvUserContext)
        : m_pfCallback(pfCallback),
          m_pvUserContext(pvUserContext)
    {
        InitializeListHead(&m_link);
        m_pszName = new WCHAR [wcslen(pszName)+1];
        m_Id = InterlockedIncrement(&lastId);
        if (m_pszName)
            wcscpy(m_pszName, pszName);
    }
    ~CallbackTarget()
    {
        // should be unlinked by now
        if (m_pszName)
            delete [] m_pszName;
    }

    PCWSTR Name() { return m_pszName; }
    DWORD  Handle() { return m_Id; }

    DWORD DoCallback(UPNPCB_ID, PVOID pvPara);
    // since there is only one list, the list manipulation methods are added to this
    // class as statics.
    static LIST_ENTRY list;
    static LONG lastId;
    static CallbackTarget *SearchByName(PCWSTR pszName);
    static CallbackTarget *SearchByHandle(DWORD handle);
    static void  Link(CallbackTarget *pCallback) // add to list
        {
            InsertHeadList(&list, &pCallback->m_link);     
        }
    static void Unlink(CallbackTarget *pCallback)    // remove from list
        {
            RemoveEntryList(&pCallback->m_link);
        }
        
    static void LockList(void)
    {
        EnterCriticalSection(&g_csUPNPAPI);
    }
    static void UnlockList(void)
    {
        LeaveCriticalSection(&g_csUPNPAPI);
    }
    static BOOL CleanupList();
    
};

extern ce::psl_proxy<> proxy;

HANDLE g_hLPCThread;
static BOOL g_Stopped;
static DWORD g_dwLPCThreadId;
static UpnpInvokeRequest *g_pReq;
static DWORD g_cbReqSize;


// TODO: move to common library
static PWSTR
StrDupW(LPCWSTR pwszSource)
{
    PWSTR pwsz;
    size_t nBytes;
    if (!pwszSource)
        return NULL;
    nBytes =  wcslen(pwszSource)+1;
    if (pwsz = new WCHAR [nBytes])
        memcpy(pwsz,pwszSource,nBytes*sizeof(WCHAR));
    return pwsz;
}


LIST_ENTRY CallbackTarget::list = {&CallbackTarget::list, &CallbackTarget::list};
LONG CallbackTarget::lastId;

CallbackTarget *
CallbackTarget::SearchByName(PCWSTR pszName)
{
    LIST_ENTRY *pLink = CallbackTarget::list.Flink;
    CallbackTarget *pCallback;
    // assume lock is held
    while (pLink != &CallbackTarget::list)
    {
        pCallback = CONTAINING_RECORD(pLink, CallbackTarget, m_link);
        if (wcscmp(pszName, pCallback->m_pszName) == 0)
            return pCallback;
        pLink = pLink->Flink;
    }
    return NULL;
}

CallbackTarget *
CallbackTarget::SearchByHandle(DWORD handle)
{
    LIST_ENTRY *pLink = CallbackTarget::list.Flink;
    CallbackTarget *pCallback;
    // assume lock is held
    while (pLink != &CallbackTarget::list)
    {
        pCallback = CONTAINING_RECORD(pLink, CallbackTarget, m_link);
        if (pCallback->Handle() == handle)
            return pCallback;
        pLink = pLink->Flink;
    }
    return NULL;
}

BOOL
CallbackTarget::CleanupList()
{
    
    CallbackTarget *pCallback;
    while (CallbackTarget::list.Flink != &CallbackTarget::list)
    {
        pCallback = CONTAINING_RECORD(CallbackTarget::list.Flink, CallbackTarget, m_link);
        if (pCallback)
        {
            CallbackTarget::Unlink(pCallback);  // remove from list
            delete pCallback;
        }
    }
    return TRUE;
}
    
DWORD
CallbackTarget::DoCallback(UPNPCB_ID cbId, PVOID pvPara)
{
    DWORD dwRet = 0;
    __try {
        dwRet = (*m_pfCallback)(cbId, m_pvUserContext, pvPara);
    }
    __except (EXCEPTION_EXECUTE_HANDLER)
    {
        dwRet = ERROR_GEN_FAILURE;
    }
    return dwRet;
}


static BOOL
UnmarshalCallbackRequest(PBYTE pbReq, DWORD cbReq, UpnpRequest **ppUpnpReq, PWSTR *ppszUDN, PWSTR *ppszServiceId, PWSTR *ppszReqXML)
{
    UpnpInvokeRequestContainer_t upnpInvokeRequestContainer;

    if(upnpInvokeRequestContainer.CreateUpnpInvokeRequest(pbReq, cbReq) == FALSE) {
        return FALSE;
    }

    *ppUpnpReq = upnpInvokeRequestContainer.GetUpnpRequest();
    *ppszServiceId = static_cast<PWSTR>(const_cast<WCHAR*>(upnpInvokeRequestContainer.GetServiceID()));
    *ppszUDN = static_cast<PWSTR>(const_cast<WCHAR*>(upnpInvokeRequestContainer.GetUDN()));
    *ppszReqXML = static_cast<PWSTR>(const_cast<WCHAR*>(upnpInvokeRequestContainer.GetRequestXML()));

    return TRUE;        
}


static DWORD CALLBACK UPNPCallback(PVOID pvContext, PBYTE pbInBuf, DWORD cbInBuf)
{
    UpnpRequest *pReq = NULL;
    CallbackTarget *pCallback;
    BOOL fRet = FALSE;
    PWSTR pszServiceId = NULL;
    PWSTR pszReqXML = NULL;
    PWSTR pszUDN = NULL;

    TraceTag(ttidControl, "UPNPCallback: ");
    if (cbInBuf < sizeof(UpnpRequest))
        return FALSE;

    if (UnmarshalCallbackRequest( pbInBuf, cbInBuf, &pReq, &pszUDN, &pszServiceId, &pszReqXML) && pReq)
    {
        TraceTag(ttidControl, "UPNPCallback: CB_ID(%d), service %S, hTarget(%x)", pReq->cbId, (pszServiceId ? pszServiceId : L"NULL"), pReq->hTarget);
        // which of the callback targets is this msg directed to?
        CallbackTarget::LockList();
        pCallback = CallbackTarget::SearchByHandle(pReq->hTarget);
        if (pCallback)
        {
            switch (pReq->cbId)
            {
                case UPNPCB_INIT:
                case UPNPCB_SHUTDOWN:
                    
                    fRet = pCallback->DoCallback(pReq->cbId, NULL);
                    break;

                case UPNPCB_SUBSCRIBING:
                case UPNPCB_UNSUBSCRIBING:
                    
                    {
                        UPNPSUBSCRIPTION UPnPSubscription;
                        UPnPSubscription.pszSID = pszServiceId;
                        UPnPSubscription.pszUDN = pszUDN;
                    
                        fRet = pCallback->DoCallback(pReq->cbId, &UPnPSubscription);
                    }
                    break;

                case UPNPCB_CONTROL:
                {
                    SOAPHandler soapHandler(pReq->hSource, pszUDN, pszServiceId, pszReqXML);
                    if (soapHandler.Parse())
                    {
                        fRet = pCallback->DoCallback(pReq->cbId, soapHandler.GetServiceControl());
                        soapHandler.Done(fRet);
                    }
                    break;
                }
            }
        }
        CallbackTarget::UnlockList();
        
    }
    return fRet;
}



static DWORD WINAPI LPCInvokeRequestHandlerThread(PVOID pvPara)
{
    CoGate  co;
    BOOL fRet = TRUE;
    DWORD cbWrittenReqSize;
    DWORD errCode = ERROR_SUCCESS;

    TraceTag(ttidControl, "%s: Beginning Invoke Request Handler Thread\n", __FUNCTION__);
    Assert(!g_pReq);
    g_cbReqSize = MAXIMUM_UPNP_MESSAGE_LENGTH;
    g_pReq = static_cast<UpnpInvokeRequest*>(VirtualAlloc(NULL,g_cbReqSize,MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE));

    if(!g_pReq)
    {
        errCode = ERROR_OUTOFMEMORY;
        TraceTag(ttidError, "%s: OOM allocating request buffer [%d]\n", __FUNCTION__, errCode);
        goto Finish;
    }

    SOAPHandler::m_pReader = new ce::SAXReader;
    if(!SOAPHandler::m_pReader)
    {
        errCode = ERROR_OUTOFMEMORY;
        TraceTag(ttidError, "%s: Invoke Request Handler Thread error OOM m_pReader [%d]\n", __FUNCTION__, errCode);
        goto Finish;
    }

    {
        while(g_Stopped == FALSE)
        {
            SetSentinel(g_pReq);
            fRet = (ERROR_SUCCESS == proxy.call(UPNP_IOCTL_RECV_INVOKE_REQUEST, errCode, ce::psl_buffer(g_pReq, g_cbReqSize), &cbWrittenReqSize));
            errCode = ERROR_SUCCESS;
            TraceTag(ttidControl, "%s: Received Next Invoke Request [%S]\n", __FUNCTION__, fRet ? L"TRUE" : L"FALSE");
            Assert((!SentinelSet(g_pReq) && fRet) || (SentinelSet(g_pReq) && !fRet));

            if(g_Stopped == TRUE)
                break;

            if(fRet)
            {
                fRet = UPNPCallback(NULL, (PBYTE) g_pReq, cbWrittenReqSize);
                if(!fRet)
                {
                    errCode = GetLastError();
                    if(errCode == ERROR_SUCCESS) 
                    {
                        errCode = E_FAIL;
                    }
                    TraceTag(ttidError,"%s: Error processing handler Callback[%d]\n", __FUNCTION__, errCode);
                }
            }
            else
            {
                errCode = GetLastError();
                if(errCode == ERROR_SUCCESS)
                {
                    errCode = E_FAIL;
                }
                TraceTag(ttidError,"%s: Error Receiving Next Invoke Request [%d]\n", __FUNCTION__, errCode);
            }
        }

    }

Finish:
    if(SOAPHandler::m_pReader)
    {
        delete SOAPHandler::m_pReader;
        SOAPHandler::m_pReader = NULL;
    }

    if(g_pReq)
    {
        VirtualFree(g_pReq, g_cbReqSize, MEM_DECOMMIT);
        VirtualFree(g_pReq, 0, MEM_RELEASE);
        g_pReq = NULL;
    }

    TraceTag(ttidError,"%s: Exiting Receive Invoke Request Thread [%d]\n", __FUNCTION__, errCode);
    if(errCode != ERROR_SUCCESS)
        SetLastError(errCode);
    return fRet;
}


static BOOL
LPCInit()
{
    BOOL fRet = TRUE;
    TraceTag(ttidDevice,"%s: Initializing LPCInvokeRequestHandler Thread\n", __FUNCTION__);

    // create an empty list of callback targets
    InitializeListHead(&CallbackTarget::list);

    Assert(g_hLPCThread == NULL);

    g_Stopped = FALSE;

    // initialize the service for UPNP message requests
    fRet = (ERROR_SUCCESS == proxy.call(UPNP_IOCTL_INIT_RECV_INVOKE_REQUEST));
    Assert(fRet);

    // create a thread to listen on the port
    g_hLPCThread = CreateThread(NULL,0, LPCInvokeRequestHandlerThread, NULL, 0, &g_dwLPCThreadId);

    return ((g_hLPCThread != NULL) && fRet);
}


static BOOL
CancelCallbacks()
{
    TraceTag(ttidDevice,"%s: Cancelling UPnP Service Callbacks\n", __FUNCTION__);
    return (ERROR_SUCCESS == proxy.call(UPNP_IOCTL_CANCEL_RECV_INVOKE_REQUEST));
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -