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

📄 announce.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 <bldver.h>
#include "ipsupport.h"

#define BUF_SIZE 40

static LIST_ENTRY listAnnounce;
static CRITICAL_SECTION CSListAnnounce;
static CHAR *AliveHeader = "ssdp:alive";
static CHAR *ByebyeHeader = "ssdp:byebye";
static CHAR *MulticastUri = "*";
static const CHAR c_szHttpLocalHost[] = "http://localhost";
static const CHAR c_szServerVersion[] = "Microsoft-WinCE/%d.%02d UPnP/1.0 UPnP-Device-Host/1.0";

static SSDP_HEADER AliveHeaders[] = {SSDP_HOST, SSDP_CACHECONTROL, SSDP_LOCATION, SSDP_NT, SSDP_NTS, SSDP_SERVER, SSDP_USN, SSDP_LAST, SSDP_LAST, SSDP_LAST};
static SSDP_HEADER ByeByeHeaders[] = {SSDP_HOST, SSDP_NT, SSDP_NTS, SSDP_USN, SSDP_LAST, SSDP_LAST, SSDP_LAST};
static SSDP_HEADER ResponseHeaders[] = {SSDP_CACHECONTROL, SSDP_EXT, SSDP_LOCATION, SSDP_SERVER, SSDP_ST, SSDP_USN, SSDP_LAST, SSDP_LAST, SSDP_LAST};


extern LONG_PTR bShutdown;
extern CHAR g_pszExtensionURI[500];
extern CHAR g_pszHeaderPrefix[10];
extern CHAR g_lpszNls[100];

SVSThreadPool* g_pThreadPool;

BOOL InitializeSsdpRequestFromMessage(SSDP_REQUEST *pRequest,
                                      const SSDP_MESSAGE *pssdpSrc);
VOID PrintList(LIST_ENTRY *pListHead);
VOID PrintSSDPService (const SSDP_SERVICE *pSSDPService);

VOID InitializeListAnnounce()
{
    InitializeCriticalSection(&CSListAnnounce);
    EnterCriticalSection(&CSListAnnounce);
    InitializeListHead(&listAnnounce);
    LeaveCriticalSection(&CSListAnnounce);
}

BOOL SendAnnouncementOrResponse(
    SSDP_SERVICE *pssdpService,
    SOCKET sock,                    // socket to send response (INVALID_SOCKET if multicast announcement)
    PSOCKADDR_STORAGE pSockAddr)    // destination addr (NULL if mulicast announcement)
{
    PSSDPNetwork            pNet = NULL;
    CHAR                   *pszOrigLocation = pssdpService->SsdpRequest.Headers[SSDP_LOCATION];
    CHAR                   *pszBytes = NULL;
    ce::istring             strLocation;
    ce::istring::size_type  nReplaceAt, nReplaceLen, nReplaceAddrAt;

    Assert(pszOrigLocation);
    Assert(pssdpService->SsdpRequest.Headers[SSDP_NLS] == NULL);
    Assert(pssdpService->SsdpRequest.Headers[SSDP_HOST] == NULL);
    Assert(pssdpService->SsdpRequest.Headers[SSDP_OPT] == NULL);

    strLocation = pszOrigLocation;

    nReplaceAt = strLocation.find(c_szReplaceGuid);
    nReplaceLen = strlen(c_szReplaceGuid);

    nReplaceAddrAt = strLocation.find(c_szReplaceAddrGuid);
    assert(nReplaceLen == strlen(c_szReplaceAddrGuid));

    // set OPT header
    if(*g_pszHeaderPrefix && *g_lpszNls)
    {
        if(pssdpService->SsdpRequest.Headers[SSDP_OPT] = (CHAR*)malloc(strlen(g_pszExtensionURI) + strlen(g_pszHeaderPrefix) + sizeof("; ns=") + 1))
            sprintf(pssdpService->SsdpRequest.Headers[SSDP_OPT], "%s; ns=%s", g_pszExtensionURI, g_pszHeaderPrefix);
    }

    GetNetworkLock();

    while(pNet = GetNextNetwork(pNet))
    {
        if(sock != INVALID_SOCKET && pNet->socket != sock)
            continue;

        if(nReplaceAt != ce::istring::npos)
        {
            strLocation = pszOrigLocation;

            // Repalce c_szReplaceGuid with IP address for this network
            strLocation.replace(nReplaceAt, nReplaceLen, pNet->pszIPString);
            
            pssdpService->SsdpRequest.Headers[SSDP_LOCATION] = const_cast<LPSTR>(static_cast<LPCSTR>(strLocation));
        }
        else if(nReplaceAddrAt != ce::istring::npos)
        {
            strLocation = pszOrigLocation;

            // Repalce c_szReplaceAddrGuid with address (IP and port) for this network
            strLocation.replace(nReplaceAddrAt, nReplaceLen, pNet->pszAddressString);

            pssdpService->SsdpRequest.Headers[SSDP_LOCATION] = const_cast<LPSTR>(static_cast<LPCSTR>(strLocation));
        }


        // set NLS header
        if(*g_lpszNls)
            pssdpService->SsdpRequest.Headers[SSDP_NLS] = g_lpszNls;

        if(pSockAddr)
        {
            // ResponseHeaders has space for 3 optional headers: AL, OPT and NLS
            int nHeaders = sizeof(ResponseHeaders)/sizeof(*ResponseHeaders) - 3;

            // add optional AL header if specified
            if(pssdpService->SsdpRequest.Headers[SSDP_AL])
            {
                PREFAST_SUPPRESS(394, "optional header");
                ResponseHeaders[nHeaders++] = SSDP_AL;
            }

            // add optional OPT header if specified
            if(pssdpService->SsdpRequest.Headers[SSDP_OPT])
            {
                PREFAST_SUPPRESS(394, "optional header");
                ResponseHeaders[nHeaders++] = SSDP_OPT;
            }

            // add optional NLS header if specified
            if(pssdpService->SsdpRequest.Headers[SSDP_NLS])
            {
                PREFAST_SUPPRESS(394, "optional header");
                ResponseHeaders[nHeaders++] = SSDP_NLS;
            }

            // compose response message
            ComposeSsdpResponse(&pssdpService->SsdpRequest, ResponseHeaders, nHeaders, &pszBytes);

            // send unicast response
            SocketSend(pszBytes, pNet->socket, (PSOCKADDR)pSockAddr);
        }
        else
        {
            int nHeaders;
            SSDP_HEADER *pIncludedHeaders;

            // set HOST header
            pssdpService->SsdpRequest.Headers[SSDP_HOST] = pNet->pszMulticastAddr;

            // set list of headers to be included in the message
            if(pssdpService->SsdpRequest.Headers[SSDP_NTS] == ByebyeHeader)
            {
                pIncludedHeaders = ByeByeHeaders;
                nHeaders = sizeof(ByeByeHeaders)/sizeof(*ByeByeHeaders);
            }
            else
            {
                assert(pssdpService->SsdpRequest.Headers[SSDP_NTS] == AliveHeader);

                pIncludedHeaders = AliveHeaders;
                nHeaders = sizeof(AliveHeaders)/sizeof(*AliveHeaders);
            }

            // AliveHeaders and ByeByeHeaders has space for 3 optional headers: AL, OPT and NLS
            nHeaders -= 3;

            // add optional AL header if specified
            if(pssdpService->SsdpRequest.Headers[SSDP_AL])
                pIncludedHeaders[nHeaders++] = SSDP_AL;

            // add optional OPT header if specified
            if(pssdpService->SsdpRequest.Headers[SSDP_OPT])
                pIncludedHeaders[nHeaders++] = SSDP_OPT;

            // add optional NLS header if specified
            if(pssdpService->SsdpRequest.Headers[SSDP_NLS])
                pIncludedHeaders[nHeaders++] = SSDP_NLS;

            // compose request message
            ComposeSsdpRequest(&pssdpService->SsdpRequest, pIncludedHeaders, nHeaders, &pszBytes);

            // send multicast announcement
            SocketSend(pszBytes, pNet->socket, pNet->pMulticastAddr);
        }

        if (pszBytes)
        {
            free(pszBytes);
            pszBytes = NULL;
        }
    }

    FreeNetworkLock();

    // restore LOCATION header
    pssdpService->SsdpRequest.Headers[SSDP_LOCATION] = pszOrigLocation;

    // restore NLS header
    pssdpService->SsdpRequest.Headers[SSDP_NLS] = NULL;

    // restore HOST header
    pssdpService->SsdpRequest.Headers[SSDP_HOST] = NULL;

    // free OPT header
    if(pssdpService->SsdpRequest.Headers[SSDP_OPT])
    {
        free(pssdpService->SsdpRequest.Headers[SSDP_OPT]);
        pssdpService->SsdpRequest.Headers[SSDP_OPT] = NULL;
    }

    return TRUE;
}



// Announce all registered services on all active networks
// This is called when there is a network change, for example, 
// an IP address change or a new network card
// This is implemented as a synchronous call, since it is called
// infrequently.
VOID SendAllAnnouncements()
{
    PLIST_ENTRY p;
    PLIST_ENTRY pListHead = &listAnnounce;
    TraceTag(ttidSsdpAnnounce, "SendAllAnnouncements entered");
    EnterCriticalSection(&CSListAnnounce);
    for (p = pListHead->Flink; p != pListHead; p = p->Flink)
    {
        SSDP_SERVICE *pService;

        pService = CONTAINING_RECORD (p, SSDP_SERVICE, linkage);

        EnterCriticalSection(&pService->CSService);
        pService->SsdpRequest.Headers[SSDP_NTS] = AliveHeader;
        SendAnnouncement(pService);
        LeaveCriticalSection(&pService->CSService);

    }

    TraceTag(ttidSsdpAnnounce, "SendAllAnnouncements done");
    LeaveCriticalSection(&CSListAnnounce);
}

DWORD AnnounceTimerProc (VOID *Arg)
{
    SSDP_SERVICE *pssdpService = (SSDP_SERVICE *) Arg;
    unsigned long Timeout;

    EnterCriticalSection(&(pssdpService->CSService));

    TraceTag(ttidSsdpTimer, "Announcement timer of %x expired with count = %d",
             pssdpService,pssdpService->iRetryCount );

    if (pssdpService->state == SERVICE_NO_MASTER_CLEANUP)
    {
        SetEvent(pssdpService->CleanupEvent);
        LeaveCriticalSection(&(pssdpService->CSService));
        return 0;
    }

    pssdpService->SsdpRequest.Headers[SSDP_NTS] = AliveHeader;
    SendAnnouncement(pssdpService);
    pssdpService->iRetryCount--;

    if (pssdpService->iRetryCount == 0)
    {
        // To-Do: The current limit on life time is 49.7 days.  (32 bits in milliseconds)
        // 32 bit in seconds should be enough.
        // Need to add field remaining time ...

        pssdpService->iRetryCount = NUM_RETRIES;
        Timeout = (pssdpService->iLifeTime - ANNOUNCE_MARGIN) * 1000;

        if(!(pssdpService->dwTimerCookie = g_pThreadPool->StartTimer(AnnounceTimerProc, pssdpService, Timeout)))
        {
            TraceTag(ttidError, "Failed to start cache timer for %x.",
                     pssdpService);
        }
        else
        {
            TraceTag(ttidSsdpTimer, "Started cache timer.");
        }
    }
    else
    {
        Timeout = RETRY_INTERVAL;

        if(!(pssdpService->dwTimerCookie = g_pThreadPool->StartTimer(AnnounceTimerProc, pssdpService, Timeout)))
        {
            TraceTag(ttidError, "Failed to start retry timer.");
        }
        else
        {
            TraceTag(ttidSsdpTimer, "Started retry timer.");
        }
    }

    LeaveCriticalSection(&(pssdpService->CSService));

    return 0;
}

DWORD ByebyeTimerProc (VOID *Arg)
{
    SSDP_SERVICE *pssdpService = (SSDP_SERVICE *) Arg;
    unsigned long Timeout;

    if (InterlockedExchange(&bShutdown, bShutdown) != 0)
    {
        FreeSSDPService(pssdpService);
        return 0;
    }

    //GetNetworkLock();

    EnterCriticalSection(&(pssdpService->CSService));

    TraceTag(ttidSsdpTimer, "Byebye timer of %x expired with count = %d",
             pssdpService,pssdpService->iRetryCount );

    pssdpService->SsdpRequest.Headers[SSDP_NTS] = ByebyeHeader;
    SendAnnouncement(pssdpService);

    //FreeNetworkLock();
    pssdpService->iRetryCount--;

    if (pssdpService->iRetryCount == 0)
    {
        TraceTag(ttidSsdpAnnounce, "Done with sending byebyes.");
        LeaveCriticalSection(&(pssdpService->CSService));
        FreeSSDPService(pssdpService);
    }
    else
    {
        Timeout = RETRY_INTERVAL;

        if(!(pssdpService->dwTimerCookie = g_pThreadPool->StartTimer(ByebyeTimerProc, pssdpService, Timeout)))
        {
            TraceTag(ttidError, "Failed to start byebye retry timer.");
        }
        else
        {
            TraceTag(ttidSsdpTimer, "Started byebye retry timer.");
        }

        LeaveCriticalSection(&(pssdpService->CSService));
    }

    return 0;
}

VOID StartAnnounceTimer(PSSDP_SERVICE pssdpSvc, LPTHREAD_START_ROUTINE pCallback)
{
    EnterCriticalSection(&(pssdpSvc->CSService));

    // Assume send will be called once before start the timer
    pssdpSvc->iRetryCount = NUM_RETRIES-1;

    if(!(pssdpSvc->dwTimerCookie = g_pThreadPool->StartTimer(pCallback, pssdpSvc, RETRY_INTERVAL)))
    {
        TraceTag(ttidError, "Announcement timer failed to start "
                 "for service %x", pssdpSvc);
    }
    else
    {
        TraceTag(ttidSsdpTimer, "Announcement timer started for service "
                 "%x", pssdpSvc);
    }

    LeaveCriticalSection(&(pssdpSvc->CSService));
}

VOID StopAnnounceTimer(SSDP_SERVICE *pSSDPSvc)
{
    EnterCriticalSection(&(pSSDPSvc->CSService));

    Assert(pSSDPSvc->state == SERVICE_NO_MASTER_CLEANUP);

    TraceTag(ttidSsdpTimer, "Stopping Announcement timer for service %x", pSSDPSvc);

    if (g_pThreadPool->StopTimer(pSSDPSvc->dwTimerCookie))
    {
        TraceTag(ttidSsdpTimer, "Announcement timer stopped for service %x", pSSDPSvc);
        LeaveCriticalSection(&(pSSDPSvc->CSService));
    }
    else
    {
        // Timer is running, wait for CleanupEvent
        TraceTag(ttidSsdpAnnounce, "Announcement timer is running, wait ...%x", pSSDPSvc);
        LeaveCriticalSection(&(pSSDPSvc->CSService));
        WaitForSingleObject(pSSDPSvc->CleanupEvent, INFINITE);
    }
}


PSSDP_SERVICE AddToListAnnounce(SSDP_MESSAGE *pssdpMsg, DWORD flags, PCONTEXT_HANDLE_TYPE *pphContext)
{
    SSDP_SERVICE *pssdpService;

    // To-Do: Check for duplicates.

    // To-Do: QueryState

    // Create SSDPService from SSDP_MESSAGE

    pssdpService = (SSDP_SERVICE *) malloc (sizeof(SSDP_SERVICE));

    if (pssdpService == NULL)
    {
        return NULL;
    }

    pssdpService->Type = SSDP_SERVICE_SIGNATURE;

    if (InitializeSsdpRequestFromMessage(&(pssdpService->SsdpRequest),
                                         pssdpMsg) == FALSE)
    {
        free(pssdpService);
        return NULL;
    };

    pssdpService->iLifeTime = pssdpMsg->iLifeTime;

    pssdpService->iRetryCount = 0;

    pssdpService->dwTimerCookie = 0;

    pssdpService->CleanupEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    if (pssdpService->CleanupEvent == NULL)
    {
        free(pssdpService);
        return NULL;
    }

    pssdpService->flags = flags;
    pssdpService->RpcContextHandle = pphContext;




    // Important: Set to NULL to prevent freeing memory.
    pssdpService->SsdpRequest.Headers[SSDP_NTS] = NULL;
   
    pssdpService->SsdpRequest.RequestUri = MulticastUri; // for notify
   
    // To-Do: Query Per Network State Matrix state
    pssdpService->state = SERVICE_ACTIVE_NO_MASTER;

    InitializeCriticalSection(&(pssdpService->CSService));
    InitializeListHead(&(pssdpService->listSearchResponse));

    // ALWAYS get the list lock before the service lock.

    EnterCriticalSection(&CSListAnnounce);

    // read the LIST_ENTRY
    EnterCriticalSection(&(pssdpService->CSService));
    InsertHeadList(&listAnnounce, &(pssdpService->linkage));
    LeaveCriticalSection(&(pssdpService->CSService));

    //PrintList(&listAnnounce);
    TraceTag(ttidSsdpAnnounce, "New SSDP service announcement:\n");
#ifdef DEBUG

⌨️ 快捷键说明

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