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

📄 notify.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 <ssdppch.h>
#pragma hdrstop

#include "http_status.h"
#include "notify.h"


// Forward Declarations
void DebugMessageQueueSize(msg_queue msgQueue, const char* function);


/******************************************************************************
 *  g_pNotificationMgr:
 *
 *      - single notification manager externally referenced
 *      - manages HTTP NOTIFY requests into the upnpsvc
 *
 ******************************************************************************/
notification_mgr* g_pNotificationMgr;



/******************************************************************************
 *  EventsExtensionProc:
 *
 *      - HTTP NOTIFY ISAPI Extension entry point
 *      - passes the NOTIFY message to the notification manager
 *      - sends the HTTP response
 *      
 ******************************************************************************/
DWORD EventsExtensionProc(LPEXTENSION_CONTROL_BLOCK pecb)
{
    if(g_pNotificationMgr)
    {
        pecb->dwHttpStatusCode = g_pNotificationMgr->event(pecb);

        HSE_SEND_HEADER_EX_INFO hse = {0};

        hse.pszStatus = ce::http_status_string(pecb->dwHttpStatusCode);
        hse.cchStatus = strlen(hse.pszStatus);

        // send response
        pecb->ServerSupportFunction(pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &hse, NULL, NULL);
    }

    return HSE_STATUS_SUCCESS;
}


// NotifyAliveByebye
bool NotifyAliveByebye(PSSDP_REQUEST pSsdpRequest)
{
    bool retCode = false;

    if(g_pNotificationMgr)
    {
        retCode = g_pNotificationMgr->alive_byebye(pSsdpRequest);
    }

    return retCode;
}


// RegisterNotificationSink
BOOL RegisterNotificationSink(
    __in HANDLE                                  hOwner, 
    __in DWORD                                   dwNotificationType, 
    __in ce::marshal_arg<ce::copy_in, LPCWSTR>   pwszUSN, 
    __in ce::marshal_arg<ce::copy_in, LPCWSTR>   pwszQueryString, 
    __in ce::marshal_arg<ce::copy_in, LPCWSTR>   pwszMsgQueue, 
    __out ce::marshal_arg<ce::copy_out, HANDLE*> phNotify)
{
    // the buffer for the output handle must be valid
    if(!phNotify)
    {
        goto Finish;
    }

    // the buffer for the message queue must be valid
    if(!pwszMsgQueue || !*pwszMsgQueue)
    {
        goto Finish; 
    }

    // the universal service number for alive/bye-bye messages must be valid to determine source
    if(!pwszUSN || !*pwszUSN)
    {
        goto Finish;
    }

    // the query string for event messages must be valid to determine event source
    if(!pwszQueryString || !*pwszQueryString)
    {
        goto Finish;
    }

    if(g_pNotificationMgr) 
    {
        *phNotify = g_pNotificationMgr->register_notification(dwNotificationType, pwszUSN, pwszQueryString, pwszMsgQueue, hOwner);
    }

    return (*phNotify != NULL);

Finish:
    SetLastError(ERROR_INVALID_PARAMETER); 
    return FALSE;
}


// DeregisterNotificationSink
BOOL DeregisterNotificationSink(ce::PSL_HANDLE hSubscription)
{
    if(g_pNotificationMgr) 
    {
        g_pNotificationMgr->deregister_notification((HANDLE)hSubscription);
    }

    return TRUE;
}


// CleanupNotifications
void CleanupNotifications(HANDLE hOwner)
{
    if(g_pNotificationMgr) 
    {
        g_pNotificationMgr->cleanup_notifications(hOwner);
    }
}


// CheckListNotifyForAliveByebye
VOID CheckListNotifyForAliveByebye(PSSDP_REQUEST pSsdpRequest)
{
}



/******************************************************************************
 *  notification_mgr::event:
 *
 *      - handle event notification
 *      - find the associated notification_sink based on the QueryString SID (subscription ID)
 *
 ******************************************************************************/
DWORD notification_mgr::event(LPEXTENSION_CONTROL_BLOCK pecb)
{
    ce::wstring strQueryString;
    DWORD       dw;
    DWORD        dwEventSEQ;
    char        pszHeaderBuf[22] = {0};
    int         status = HTTP_STATUS_PRECOND_FAILED;

    ///////////////////////
    // verify body length
    if(pecb->cbAvailable != pecb->cbTotalBytes)
        if(pecb->cbTotalBytes == 0)
            // CONTENT-LENGTH header missing (required by UPnP spec)
            return HTTP_STATUS_LENGTH_REQUIRED;
        else
            // event body larger than data preloaded by web server (48K by default)
            // reject the event for security reasons
            return HTTP_STATUS_REQUEST_TOO_LARGE;

    ///////////////////////
    // verify headers

    // NT: upnp:event
    if(!pecb->GetServerVariable(pecb->ConnID, "HTTP_NT", pszHeaderBuf, &(dw = sizeof(pszHeaderBuf) - 1)))
        if(ERROR_NO_DATA == GetLastError())
            // missing NT header -> 400 Bad request
            return HTTP_STATUS_BAD_REQUEST;
        else
            // invalid NT header -> 412 Precondition failed
            return HTTP_STATUS_PRECOND_FAILED;
    else
        if(strcmp(pszHeaderBuf, "upnp:event"))
            // invalid NT header -> 412 Precondition failed
            return HTTP_STATUS_PRECOND_FAILED;


    // NTS: upnp:propchange
    if(!pecb->GetServerVariable(pecb->ConnID, "HTTP_NTS", pszHeaderBuf, &(dw = sizeof(pszHeaderBuf) - 1)))
        if(ERROR_NO_DATA == GetLastError())
            // missing NT header -> 400 Bad request
            return HTTP_STATUS_BAD_REQUEST;
        else
            // invalid NTS header -> 412 Precondition failed
            return HTTP_STATUS_PRECOND_FAILED;
    else
           if(strcmp(pszHeaderBuf, "upnp:propchange"))
            // invalid NTS header -> 412 Precondition failed
            return HTTP_STATUS_PRECOND_FAILED;


    // SID:
    if(!pecb->GetServerVariable(pecb->ConnID, "HTTP_SID", pszHeaderBuf, &(dw = sizeof(pszHeaderBuf) - 1)))
        if(GetLastError() == ERROR_NO_DATA)
            // missing SID header -> 400 Bad request
            return HTTP_STATUS_BAD_REQUEST;


    // SEQ:
    if(!pecb->GetServerVariable(pecb->ConnID, "HTTP_SEQ", pszHeaderBuf, &(dw = sizeof(pszHeaderBuf) - 1)))
        // invalid or missing SEQ -> 412 Precondition failed
        return HTTP_STATUS_BAD_REQUEST;
    else
        dwEventSEQ = atoi(pszHeaderBuf);

    // convert query string to unicode - it is part of URL so it is limited to ANSI code page
    ce::MultiByteToWideChar(CP_ACP, pecb->lpszQueryString, -1, &strQueryString);

    ce::gate<ce::critical_section> _gate(m_cs);

    // find notification sink for the query string
    for(ce::list<notification_sink>::iterator it = m_listSinks.begin(), itEnd = m_listSinks.end(); it != itEnd; ++it)
        if(it->getQueryString() == strQueryString && (it->getType() & NOTIFY_PROP_CHANGE))
        {
            Assert(pecb->cbAvailable == pecb->cbTotalBytes);

            ce::wstring    strMessage;

            // assuming UTF8 for content encoding but fallback to ANSI if UTF8 is not available
            if(ce::MultiByteToWideChar(CP_UTF8, (LPCSTR)pecb->lpbData, pecb->cbAvailable, &strMessage))
            {
                // watermark
                if(it->getWatermark().IncrementWatermark())
                {
                    it->event(strMessage, dwEventSEQ);
                    status = HTTP_STATUS_OK;
                }
                else
                {
                    status = HTTP_STATUS_SERVICE_UNAVAIL;
                }
                it->getWatermark().DecrementWatermark();
            }
        }

    return status;
}



/******************************************************************************
 *  notification_mgr::alive_byebye:
 *
 *      - handle alive/byebye notification
 *      - find the associated notification_sink based on the USN
 *
 ******************************************************************************/
bool notification_mgr::alive_byebye(PSSDP_REQUEST pSsdpRequest)
{
    Assert(pSsdpRequest->Headers[SSDP_NTS]);

    bool        bFound = false;
    ce::wstring strUSN;
    ce::wstring strNT;

    // ANSI code page for USN
    ce::MultiByteToWideChar(CP_ACP, pSsdpRequest->Headers[SSDP_USN], -1, &strUSN);

    // ANSI code page for NT
    ce::MultiByteToWideChar(CP_ACP, pSsdpRequest->Headers[SSDP_NT], -1, &strNT);

    ce::gate<ce::critical_section> _gate(m_cs);

    // find notification sink for the Unique Service Name
    for(ce::list<notification_sink>::iterator it = m_listSinks.begin(), itEnd = m_listSinks.end(); it != itEnd; ++it)
        if(it->getUSN() == strUSN || 0 == wcsncmp(it->getUSN(), strNT, wcslen(it->getUSN())))
        {
            bFound = true;

            if(it->getWatermark().IncrementWatermark())
            {
                if((it->getType() & NOTIFY_BYEBYE) && 0 == strcmp("ssdp:byebye", pSsdpRequest->Headers[SSDP_NTS]))
                    it->byebye(pSsdpRequest);

                if((it->getType() & NOTIFY_ALIVE) && 0 == strcmp("ssdp:alive", pSsdpRequest->Headers[SSDP_NTS]))
                    it->alive(pSsdpRequest);
            }
            it->getWatermark().DecrementWatermark();
        }

    return bFound;
}



/******************************************************************************
 *  notification_mgr::register_notification:
 *
 *      - registers a new control point for notifications
 *      
 ******************************************************************************/
HANDLE notification_mgr::register_notification(DWORD dwNotificationType, LPCWSTR pwszUSN, LPCWSTR pwszQueryString, LPCWSTR pwszMsgQueue, HANDLE hOwner)
{
    ce::gate<ce::critical_section> _gate(m_cs);

    ce::list<msg_queue>::iterator it, itEnd;

    // find message queue
    for(it = m_listMsgQueues.begin(), itEnd = m_listMsgQueues.end(); it != itEnd; ++it)
        if(it->name() == pwszMsgQueue)
            break;

    if(it == itEnd)
    {
        // not found -> new message queue
        if(m_listMsgQueues.push_front(msg_queue(pwszMsgQueue, hOwner)))
        {

⌨️ 快捷键说明

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