📄 evtsrc.cpp
字号:
//
// 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: E V T S R C . C P P
//
// Contents:
//
// Notes:
//
// Author: danielwe 8 Oct 1999
//
//----------------------------------------------------------------------------
#include <ssdppch.h>
#pragma hdrstop
#include <ssdpnetwork.h>
#include <safeint.hxx>
extern LONG cInitialized;
LIST_ENTRY g_listEventSource;
CRITICAL_SECTION g_csListEventSource;
static HANDLE g_hThrdEventSource;
static DWORD g_fShutdownEventThread;
HANDLE g_hEvtEventSource;
static long g_lOutstandingEvents;
DWORD SendEventMessage(EventData* pEvent)
{
assert(pEvent);
InterlockedIncrement(&g_lOutstandingEvents);
HRESULT hr = HrSubmitEventToSubscriber(0, pEvent->dwTimeout, pEvent->strSid, pEvent->iSeq, pEvent->pszBody, pEvent->strUrl);
//
// Find the subscriber by Sid and update its state
//
EnterCriticalSection(&g_csListEventSource);
UPNP_EVENT_SOURCE *pes;
UPNP_SUBSCRIBER *pSub;
PLIST_ENTRY p, p2;
PLIST_ENTRY pListHead = &g_listEventSource;
for (p = pListHead->Flink; p != pListHead; p = p->Flink)
{
pes = CONTAINING_RECORD (p, UPNP_EVENT_SOURCE, linkage);
for (p2 = pes->listSubs.Flink; p2 != &pes->listSubs; p2 = p2->Flink)
{
pSub = CONTAINING_RECORD(p2, UPNP_SUBSCRIBER, linkage);
if(pEvent->strSid == pSub->szSid)
{
// Clear the F_UPNPSUB_SENDING_EVENT flag
pSub->flags &= ~F_UPNPSUB_SENDING_EVENT;
// increment the subscriber's sequence number - handle overflow
if(++pSub->iSeq == 0)
pSub->iSeq = 1;
// If the event message has timed out mark the subscriber as non-responsive and decrease the timeout
if(hr == HRESULT_FROM_WIN32(ERROR_INTERNET_TIMEOUT))
{
pSub->flags |= F_UPNPSUB_NOTRESPONDING;
// cut the time by half but don't go below MINIMAL_EVENT_TIMEOUT
if(pSub->dwEventTimeout >= 2 * MINIMAL_EVENT_TIMEOUT)
pSub->dwEventTimeout /= 2;
TraceTag(ttidEvents, "Subscriber %s is not responding. Event timeout set to %d.", pSub->szSid, pSub->dwEventTimeout);
}
else
{
// Clear the F_UPNPSUB_NOTRESPONDING flag
pSub->flags &= ~F_UPNPSUB_NOTRESPONDING;
// restore DEFAULT_EVENT_TIMEOUT
pSub->dwEventTimeout = DEFAULT_EVENT_TIMEOUT;
}
goto Cleanup;
}
}
}
Cleanup:
LeaveCriticalSection(&g_csListEventSource);
SetEvent(pEvent->hEventSent);
delete pEvent;
InterlockedDecrement(&g_lOutstandingEvents);
return 0;
}
//
// Worker thread responsible for sending events to all subscribers
//
DWORD
WINAPI
EventSourceWorkerThread(PVOID )
{
ce::auto_handle hEventSent(CreateEvent(NULL, FALSE, FALSE, NULL));
PLIST_ENTRY p, p2;
PLIST_ENTRY pListHead = &g_listEventSource;
while (!g_fShutdownEventThread)
{
UPNP_EVENT_SOURCE *pes;
UPNP_SUBSCRIBER *pSub;
bool bPendingEvents = false;
EnterCriticalSection(&g_csListEventSource);
//
// Walk the list of event sources searching for the first source with pending events
// If we find one, move it to the end of the list
// (For this to work consistently, new event sources must be added to the head of the list)
for (p = pListHead->Flink; p != pListHead; p = p->Flink)
{
pes = CONTAINING_RECORD (p, UPNP_EVENT_SOURCE, linkage);
// Check if there events pending for any subscribers;
// Flag all subscribers with event pending
// If a new subscriber is added to this event source while we are sending an event
// it will not have the flag set, which is correct.
for (p2 = pes->listSubs.Flink; p2 != &pes->listSubs; p2 = p2->Flink)
{
pSub = CONTAINING_RECORD(p2, UPNP_SUBSCRIBER, linkage);
if(pSub->iSeq == 0)
{
TraceTag(ttidEvents, "EventSourceWorkerThread: Skipping subscriber with iSeq == 0");
continue;
}
if(pSub->flags & F_UPNPSUB_SENDING_EVENT)
{
TraceTag(ttidEvents, "EventSourceWorkerThread: Skipping subscriber with unsent message");
continue;
}
for(unsigned i = 0; i < pSub->cProps; ++i)
if(pSub->rgesModified[i])
{
pSub->flags |= F_UPNPSUB_PENDINGEVENT;
bPendingEvents = true;
break;
}
}
if(bPendingEvents)
{
// round robin scheduling of event source: put this event source at the end of the list
// This also makes it possible to locate the event source in the next while loop
RemoveEntryList(p);
InsertTailList(pListHead, p);
break;
}
}
if (bPendingEvents)
{
TraceTag(ttidEvents, "Processing Event for %s:\n-------------------", pes->szRequestUri);
// we have an event to send to one or more subscribers
// We give up the critical section while iterating through the subscriber list so
// make sure the event source at the tail of the list is the same one we are
// processing. If it's not then the event source must have been deleted!
while (!IsListEmpty(pListHead)
&& CONTAINING_RECORD(pListHead->Blink, UPNP_EVENT_SOURCE, linkage) == pes)
{
// go through each subscriber, and pick out the first one with PENDINGEVENT
// flag set.
for (p2 = pes->listSubs.Flink; p2 != &pes->listSubs; p2 = p2->Flink)
{
pSub = CONTAINING_RECORD(p2, UPNP_SUBSCRIBER, linkage);
if (pSub->flags & F_UPNPSUB_PENDINGEVENT)
{
break;
}
}
if (p2 != &pes->listSubs)
{
// we broke out of the above for loop => we found a subscriber to send to
// clear the PENDINGEVENT flag, so we skip past this subscriber next time.
pSub->flags &= ~F_UPNPSUB_PENDINGEVENT;
if(EventData* pEvent = new EventData)
{
assert(pSub->dwEventTimeout == DEFAULT_EVENT_TIMEOUT || (pSub->flags & F_UPNPSUB_NOTRESPONDING));
// make a copy of the destination URL and SID since we can't touch the subscriber
// fields after leaving the Critical Section.
pEvent->strUrl = pSub->szDestUrl;
pEvent->strSid = pSub->szSid;
pEvent->iSeq = pSub->iSeq;
pEvent->dwTimeout = pSub->dwEventTimeout;
pEvent->hEventSent = hEventSent;
// create event body
if(SUCCEEDED(HrComposeXmlBodyFromEventSource(pes, pSub, false, &pEvent->pszBody)))
{
// mark that we are in process of sending event to the subscriber
assert(!(pSub->flags & F_UPNPSUB_SENDING_EVENT));
pSub->flags |= F_UPNPSUB_SENDING_EVENT;
ResetEvent(hEventSent);
// SendEventMessage is reponsible for deleting pEvent
if(g_pThreadPool->StartTimer((LPTHREAD_START_ROUTINE)SendEventMessage, pEvent, 0))
{
// now leave the critical section.
// All event source and subscriber pointers are off limits after this.
//
LeaveCriticalSection(&g_csListEventSource);
TraceTag(ttidEvents, "EventSourceWorkerThread: --- There is %d outstanding event messages ---", g_lOutstandingEvents);
// Wait a bit so that all the event messeges don't go out at the same time
WaitForSingleObject(hEventSent, 10 * g_lOutstandingEvents);
EnterCriticalSection(&g_csListEventSource);
}
else
{
// Since we couldn't schedule the SendEventMessage we must delete pEvent ...
delete pEvent;
// ... and clear the F_UPNPSUB_SENDING_EVENT flag
pSub->flags &= ~F_UPNPSUB_SENDING_EVENT;
}
}
else
delete pEvent;
}
}
else
{
// there are no more subscribers to send this event
break;
}
}
TraceTag(ttidEvents, "EventSourceWorkerThread: ---Done sending event ----");
}
LeaveCriticalSection(&g_csListEventSource);
if (!bPendingEvents)
{
// no more events to be sent to anyone. Go to sleep ....
TraceTag(ttidEvents, "EventSourceWorkerThread: Sleeping...");
WaitForSingleObject(g_hEvtEventSource,INFINITE);
}
}
return 0;
}
//+---------------------------------------------------------------------------
//
// Function: InitializeListEventSource
//
// Purpose: Initializes the event source list structures
//
// Arguments:
// (none)
//
// Returns: Nothing
//
// Author: danielwe 13 Oct 1999
//
// Notes:
//
BOOL InitializeListEventSource()
{
DWORD dwThreadId;
InitializeCriticalSection(&g_csListEventSource);
EnterCriticalSection(&g_csListEventSource);
InitializeListHead(&g_listEventSource);
g_fShutdownEventThread = FALSE;
g_hEvtEventSource = CreateEvent(NULL,FALSE, FALSE, NULL);
if (g_hEvtEventSource)
g_hThrdEventSource = CreateThread(NULL, 0, EventSourceWorkerThread, NULL, 0, &dwThreadId);
LeaveCriticalSection(&g_csListEventSource);
return g_hEvtEventSource && g_hThrdEventSource;
}
//+---------------------------------------------------------------------------
//
// Function: RegisterUpnpEventSource
//
// Purpose: Public API to register a URI as a UPnP event source
//
// Arguments:
// szRequestUri [in] URI to register as an event source
// cProps [in] Number of properties this event source supplies
// rgProps [in] List of properties
//
// Returns: TRUE if successful, FALSE if not. GetLastError() contains the
// error code.
//
// Author: danielwe 13 Oct 1999
//
// Notes:
//
BOOL WINAPI RegisterUpnpEventSource(
/* [string][in] */ LPCSTR szRequestUri,
/* [in] */ DWORD cProps,
/* [in] */ UPNP_PROPERTY __RPC_FAR *rgProps)
{
UPNP_EVENT_SOURCE * pes = NULL;
DWORD iProp;
DWORD dwError = NOERROR;
if (InterlockedExchange(&cInitialized, cInitialized) == 0)
{
dwError = ERROR_NOT_READY;
}
// Validate params
//
else if (!szRequestUri )
{
TraceTag(ttidError, "_RegisterUpnpEventSourceRpc: error %ld.",
HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
dwError = ERROR_INVALID_PARAMETER;
}
// Validate property info
//
else for (iProp = 0; iProp < cProps; iProp++)
{
if (!FValidateUpnpProperty(&rgProps[iProp]))
{
TraceTag(ttidError, "_RegisterUpnpEventSourceRpc: error %ld.",
HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
dwError = ERROR_INVALID_PARAMETER;
break;
}
}
if (dwError)
{
SetLastError(dwError);
return FALSE;
}
EnterCriticalSection(&g_csListEventSource);
// Look to see if they've already registered this event source
//
if (PesFindEventSource(szRequestUri))
{
TraceTag(ttidError, "_RegisterUpnpEventSourceRpc: error %ld.",
HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS));
dwError = ERROR_ALREADY_EXISTS;
}
else if (!(pes = (UPNP_EVENT_SOURCE *) malloc(sizeof(UPNP_EVENT_SOURCE))))
{
TraceTag(ttidError, "_RegisterUpnpEventSourceRpc: error %ld.",
HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY));
dwError = ERROR_OUTOFMEMORY;
}
else
{
pes->cProps = 0;
pes->rgesProps = NULL;
pes->fCleanup = FALSE;
pes->szRequestUri = _strdup(szRequestUri);
if (cProps && cProps < ULONG_MAX / sizeof(UPNP_PROPERTY)) // protect against integer overflow
{
if(pes->rgesProps = (UPNP_PROPERTY*) malloc(sizeof(UPNP_PROPERTY) * cProps))
{
// Copy in property information
//
for (iProp = 0; iProp < cProps; iProp++)
{
if(CopyUpnpProperty(&pes->rgesProps[pes->cProps], &rgProps[iProp]))
pes->cProps++;
}
}
}
//InitializeCriticalSection(&(pes->cs));
InitializeListHead(&(pes->listSubs));
// read the LIST_ENTRY
InsertHeadList(&g_listEventSource, &(pes->linkage));
PrintListEventSource(&g_listEventSource);
}
LeaveCriticalSection(&g_csListEventSource);
TraceError("_RegisterUpnpEventSourceRpc", HRESULT_FROM_WIN32(dwError));
if (dwError)
{
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Function: DeregisterUpnpEventSource
//
// Purpose: Public API to remove an event source
//
// Arguments:
// szRequestUri [in] URI to identify event source to remove
//
// Returns: TRUE if successful, FALSE if not. GetLastError() contains the
// error code.
//
// Author: danielwe 13 Oct 1999
//
// Notes:
//
BOOL WINAPI DeregisterUpnpEventSource(
/* [string][in] */ LPCSTR szRequestUri)
{
DWORD dwError = NOERROR;
UPNP_EVENT_SOURCE * pes;
if (InterlockedExchange(&cInitialized, cInitialized) == 0)
{
SetLastError(ERROR_NOT_READY);
return FALSE;
}
EnterCriticalSection(&g_csListEventSource);
pes = PesFindEventSource(szRequestUri);
if (pes)
{
TraceTag(ttidEvents, "DeregisterUpnpEventSource: removing event "
"source %s.", szRequestUri);
CleanupEventSourceEntry(pes);
FreeEventSource(pes);
}
else
{
TraceTag(ttidError, "DeregisterUpnpEventSource: unknown URI %s.",
szRequestUri);
dwError = ERROR_INTERNET_ITEM_NOT_FOUND;
}
LeaveCriticalSection(&g_csListEventSource);
TraceError("_RegisterUpnpEventSourceRpc", HRESULT_FROM_WIN32(dwError));
if (dwError)
{
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -