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

📄 subs.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// 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:       S U B S . C P P
//
//  Contents:   Functions to send and receive (process) subscription requests
//
//  Notes:
//
//  Author:     danielwe   7 Oct 1999
//
//----------------------------------------------------------------------------

#include <ssdppch.h>
#pragma hdrstop

#include <httpext.h>

#include "ssdpparser.h"
#include "ssdpnetwork.h"

#include "http_status.h"
#include "url_verifier.h"
#include "upnp_config.h"

extern url_verifier* g_pURL_Verifier;

const CHAR c_szUrlPrefix[]             = "http://";

const DWORD g_cDefaultSubTimeout = 1800;
const DWORD g_cDefaultMaxSubTimeout = 3600;
const DWORD g_cMaxSubTimeout = 0xFFFFFFFF / 1000;

LONG g_nSubscribers = 0;

#define DEFAULT_HEADERS_SIZE    512

// SubscriptionExtensionProc
DWORD SubscriptionExtensionProc(LPEXTENSION_CONTROL_BLOCK pecb, DWORD dwIndex)
{
    BOOL fRet;
    HSE_SEND_HEADER_EX_INFO hse = {0};
    CHAR szHeaders[DEFAULT_HEADERS_SIZE];
    CHAR *pszHeaders = &szHeaders[0];
    DWORD cbHeaders = sizeof(szHeaders);
    PSTR pszResponse = NULL;
    DWORD cbResponse;
    SSDP_REQUEST* pSsdpReq;
    BOOL fNotifyNeeded = FALSE;

    if(pSsdpReq = new SSDP_REQUEST)
    {
        SSDP_REQUEST& ssdpReq = *pSsdpReq;
    
        InitializeSsdpRequest(&ssdpReq);

        ssdpReq.status = HTTP_STATUS_OK;
        
        if (VerifySsdpMethod(pecb->lpszMethod, &ssdpReq)
            && (ssdpReq.Method == GENA_SUBSCRIBE || ssdpReq.Method == GENA_UNSUBSCRIBE)) 
        {
            // Get request URI
            if (pecb->lpszQueryString)
                ssdpReq.RequestUri = SsdpDup(pecb->lpszQueryString);

            fRet = pecb->GetServerVariable(pecb->ConnID, "ALL_RAW", pszHeaders, &cbHeaders);

            if (!fRet && (ERROR_INSUFFICIENT_BUFFER == GetLastError()))
            {
                pszHeaders = (CHAR *)SsdpAlloc(cbHeaders);
                if (pszHeaders)
                {
                    fRet = pecb->GetServerVariable(pecb->ConnID, "ALL_RAW", pszHeaders, &cbHeaders);
                }
            }

            // no body for SUBSCRIBE and UNSUBSCRIBE
            ASSERT(pecb->cbTotalBytes == 0);
            ASSERT(pecb->cbAvailable == 0);

            ssdpReq.ContentLength = 0;

            if (fRet)
                if(ParseHeaders(pszHeaders, &ssdpReq))
                {
                    fRet = FProcessSubscribeRequest(&ssdpReq, &pszResponse, &fNotifyNeeded, dwIndex);
                }
                else
                {
                    if (ssdpReq.status == HTTP_STATUS_OK)
                        ssdpReq.status = HTTP_STATUS_BAD_REQUEST;
                }

            if (!fRet && ssdpReq.status == HTTP_STATUS_OK)
                ssdpReq.status = HTTP_STATUS_SERVER_ERROR;
        }
        else
        {
            ssdpReq.status = HTTP_STATUS_BAD_METHOD;
        }
        
        pecb->dwHttpStatusCode = ssdpReq.status;
    }
    else
    {
        pecb->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
    }
  
    cbResponse = pszResponse ? strlen(pszResponse) : 0;

    hse.pszStatus = ce::http_status_string(pecb->dwHttpStatusCode);
    hse.cchStatus = strlen(hse.pszStatus);
    hse.pszHeader = pszResponse; // Should be empty for HTTP errors.
    hse.cchHeader = cbResponse;
    hse.fKeepConn = FALSE;

    pecb->ServerSupportFunction(pecb->ConnID, HSE_REQ_SEND_RESPONSE_HEADER_EX, &hse, NULL, NULL);  

    if (fNotifyNeeded)
    {
        assert(pSsdpReq);
        
        // The first event has to be sent *after* subscription response.
        // BUGBUG - web server doesn't currently have a way to close the connection before returning 
        // from ISAPI extension proc; as a work-around we schedule to send the first event in 1s.
        g_pThreadPool->StartTimer((LPTHREAD_START_ROUTINE)SendInitialEventNotification, pSsdpReq, 1000);
    }
    else
    {
        if(pSsdpReq)
        {
            FreeSsdpRequest(pSsdpReq);
            delete pSsdpReq;
        }
    }
    
    if (pszHeaders != &szHeaders[0])
        SsdpFree(pszHeaders);

    if (pszResponse)
        SsdpFree(pszResponse);

    return HSE_STATUS_SUCCESS;
}


// optional function that is called when a subscribe request is received
BOOL  (*pfSubscribeCallback)(BOOL fSubscribe, PSTR pszUri);
//+---------------------------------------------------------------------------
//
//  Function:   FProcessSubscribeRequest
//
//  Purpose:    Given an SSDP_REQUEST, determines whether it is a subscribe,
//              re-subscribe, or unsubscribe and passes it on for further
//              processing.
//
//  Arguments:
//      socket   [in]   Socket to send response to
//      pRequest [in]   Request to be processed
//
//  Returns:    TRUE if successful, FALSE if not. GetLastError() has error
//              code.
//
//  Author:     danielwe   13 Oct 1999
//
//  Notes:
//
BOOL FProcessSubscribeRequest(SSDP_REQUEST * pRequest, PSTR *ppszResponse, BOOL *pfNotifyNeeded, DWORD dwIndex)
{
    BOOL    fResult = FALSE;
    *pfNotifyNeeded = FALSE;

    AssertSz((pRequest->Method == GENA_SUBSCRIBE) ||
             (pRequest->Method == GENA_UNSUBSCRIBE), "I thought you told me "
             "this was a subscription request!");

    if (pRequest->Method == GENA_SUBSCRIBE)
    {
        // Figure out if this is a re-subscribe request or not
        if (pRequest->Headers[GENA_SID])
        {
            if (!pRequest->Headers[GENA_CALLBACK] &&
                !pRequest->Headers[SSDP_NT])
            {
                // Having a SID header means this is supposed to be a
                // re-subscribe request
                fResult = FProcessResubscribeRequest( pRequest, ppszResponse);
            }
            else
            {
                // but, they included an NT or Callback header so this is
                // confusing and invalid.
                //
                SetLastError(ERROR_HTTP_INVALID_HEADER);
                pRequest->status =  HTTP_STATUS_BAD_REQUEST;
            }
        }
        else
        {
            // No SID header on a SUBSCRIBE request means this must be an
            // initial subscribe. 
            //
            if(g_nSubscribers < upnp_config::max_subscribers())
            {
                fResult = FAddSubscriberFromRequest(pRequest, ppszResponse, dwIndex);

                if (fResult)
                {
                    // need to send initial notification AFTER sending the response
                    *pfNotifyNeeded = TRUE;
                }
            }
            else
            {
                pRequest->status = HTTP_STATUS_SERVICE_UNAVAIL;
                fResult = FALSE;
            }
        }
    }
    else
    {
        fResult = FRemoveSubscriberFromRequest(pRequest, ppszResponse);
    }

    TraceResult("FProcessSubscribeRequest", fResult);
    return fResult;
}

PSTR
ComposeSubscribeResponse(UPNP_SUBSCRIBER* pSub)
{
    // DATE: when response was generated
    // SERVER: OS/version UPnP/1.0 product/version
    // SID: uuid:subscription-UUID
    // TIMEOUT: Second-actual subscription duration

    CHAR szResp[512];   // adequate
    sprintf(szResp, "SID:%s\r\n"
                    "TIMEOUT:Second-%d\r\n"
                    "\r\n",
                    pSub->szSid,pSub->csecTimeout);

    return _strdup(szResp);
}
//+---------------------------------------------------------------------------
//
//  Function:   FProcessResubscribeRequest
//
//  Purpose:    Given an SSDP_REQUEST that has been determined to be a re-
//              subscribe request, processes the message.
//
//  Arguments:
//      pRequest [in]   Request to be processed
//      ppResp   [out]  Response
//
//  Returns:    TRUE if successful, FALSE if not. GetLastError() has error
//              code.
//
//  Author:     danielwe   13 Oct 1999
//
//  Notes:
//
BOOL FProcessResubscribeRequest(SSDP_REQUEST * pRequest, PSTR *ppResp)
{
    BOOL                fResult = FALSE;
    UPNP_EVENT_SOURCE * pes;
    UPNP_SUBSCRIBER *   pSub = NULL;
    PLIST_ENTRY         pListHead;
    PLIST_ENTRY         p;

    AssertSz(pRequest->Method == GENA_SUBSCRIBE, "I thought you told me "
             "this was a subscribe request!");
    AssertSz(pRequest->Headers[GENA_SID], "Why don't I have a SID header??!?!");

    if (!pRequest->RequestUri || !(*pRequest->RequestUri))
    {
        TraceTag(ttidEvents, "Didn't get a Reqeust-Uri!");
        pRequest->status =  HTTP_STATUS_BAD_REQUEST;
        SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
        goto cleanup;
    }

    EnterCriticalSection(&g_csListEventSource);

    // Find the event source based on the URI
    //
    pes = PesFindEventSource(pRequest->RequestUri);
    if (!pes)
    {
        TraceTag(ttidEvents, "Re-subscribe sent to unknown Request URI: %s ",
                 pRequest->RequestUri);

        // No event source registered matches this Request URI. We'll
        // retrun 404 Not Found.
        //
        pRequest->status =  HTTP_STATUS_SERVER_ERROR;
        SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
        goto cleanup;
    }

    // Found the event source this SUBSCRIBE was sent to. Now find the
    // subscriber.
    //
    //EnterCriticalSection(&pes->cs);
    pListHead = &pes->listSubs;

    for (p = pListHead->Flink; p != pListHead; p = p->Flink)
    {
        pSub = CONTAINING_RECORD (p, UPNP_SUBSCRIBER, linkage);
        if (!_stricmp(pSub->szSid, pRequest->Headers[GENA_SID]))
        {
            // Found the subscriber they were looking for!

            break;
        }
    }

    if (p == pListHead)
    {
        TraceTag(ttidEvents, "Re-subscribe sent to unknown SID: %s. Maybe "
                 "its timer ran out?",
                 pRequest->Headers[GENA_SID]);

        // Didn't find the subscriber. We should return 412 precondition
        // failed
        //
        pRequest->status = HTTP_STATUS_PRECOND_FAILED;
        SetLastError(ERROR_INTERNET_ITEM_NOT_FOUND);
        fResult = FALSE;
    }
    else
    {
        // Reset the timeout on the subscription
        //
        SetSubscriptionTimeout(pSub, pRequest->Headers[GENA_TIMEOUT]);
        *ppResp = ComposeSubscribeResponse(pSub);
        
        if (*ppResp)
        {
            // Restart the subscription timer

            StopResubscribeTimer(pSub);

            StartResubscribeTimer(pSub);

            TraceTag(ttidEvents, "Re-subscribe for %s successful.",
                     pRequest->Headers[GENA_SID]);
            fResult = TRUE;
        }
    }

    //LeaveCriticalSection(&pes->cs);

cleanup:
    LeaveCriticalSection(&g_csListEventSource);
    TraceResult("FProcessResubscribeRequest", fResult);
    return fResult;
}

//+---------------------------------------------------------------------------
//
//  Function:   SetSubscriptionTimeout
//
//  Purpose:    Sets the internal timeout for a subscription.
//
//  Arguments:
//      pSub            [in]    Subscription to set
//      szTimeoutHeader [in]    Timeout header from SSDP_REQUEST message
//
//  Returns:    Nothing
//
//  Author:     danielwe   13 Oct 1999
//
//  Notes:
//
VOID SetSubscriptionTimeout(UPNP_SUBSCRIBER * pSub, LPCSTR szTimeoutHeader)
{
    // Parse the Timeout header and convert it to seconds
    //
    pSub->csecTimeout = DwParseTime(szTimeoutHeader);
}

//+---------------------------------------------------------------------------
//
//  Function:   FAddSubscriberFromRequest
//
//  Purpose:    Given a SUBSCRIBE request, adds a subscriber to the event
//              source the request indicates.
//
//  Arguments:
//
//      pRequest [in]   Raw SUBSCRIBE message.
//      ppResp   [out]  Response
//

⌨️ 快捷键说明

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