|
|
/*++
Copyright (c) 1999, Microsoft Corporation
Module Name:
sample\configurationentry.c
Abstract:
The file contains functions to deal with the configuration entry.
--*/
#include "pchsample.h"
#pragma hdrstop
static VOID DisplayEventEntry ( IN PQUEUE_ENTRY pqeEntry) /*++
Routine Description Displays an EVENT_ENTRY object.
Locks None
Arguments
pqeEntry address of the 'leEventQueueLink' field
Return Value None
--*/ { EE_Display(CONTAINING_RECORD(pqeEntry, EVENT_ENTRY, qeEventQueueLink)); }
static VOID FreeEventEntry ( IN PQUEUE_ENTRY pqeEntry) /*++
Routine Description Frees an EVENT_ENTRY object.
Locks None
Arguments
pqeEntry address of the 'leEventQueueLink' field
Return Value None
--*/ { EE_Destroy(CONTAINING_RECORD(pqeEntry, EVENT_ENTRY, qeEventQueueLink)); }
DWORD EE_Create ( IN ROUTING_PROTOCOL_EVENTS rpeEvent, IN MESSAGE mMessage, OUT PEVENT_ENTRY *ppeeEventEntry) /*++
Routine Description Creates an event entry.
Locks None
Arguments rpeEvent mMessage ppEventEntry pointer to the event entry address
Return Value NO_ERROR if success Failure code o/w
--*/ { DWORD dwErr = NO_ERROR; PEVENT_ENTRY peeEntry; // scratch
// validate parameters
if (!ppeeEventEntry) return ERROR_INVALID_PARAMETER;
*ppeeEventEntry = NULL;
// allocate the interface entry structure
MALLOC(&peeEntry, sizeof(EVENT_ENTRY), &dwErr); if (dwErr != NO_ERROR) return dwErr;
// initialize various fields
InitializeQueueHead(&(peeEntry->qeEventQueueLink)); peeEntry->rpeEvent = rpeEvent; peeEntry->mMessage = mMessage;
*ppeeEventEntry = peeEntry; return dwErr; }
DWORD EE_Destroy ( IN PEVENT_ENTRY peeEventEntry) /*++
Routine Description Destroys an event entry.
Locks None.
Arguments peeEventEntry pointer to the event entry
Return Value NO_ERROR always
--*/ { if (!peeEventEntry) return NO_ERROR;
FREE(peeEventEntry); return NO_ERROR; }
#ifdef DEBUG
DWORD EE_Display ( IN PEVENT_ENTRY peeEventEntry) /*++
Routine Description Displays an event entry.
Locks None.
Arguments peeEventEntry pointer to the event entry
Return Value NO_ERROR always
--*/ { if (!peeEventEntry) return NO_ERROR;
TRACE1(CONFIGURATION, "Event %u", peeEventEntry->rpeEvent);
if (peeEventEntry->rpeEvent is SAVE_INTERFACE_CONFIG_INFO) TRACE1(CONFIGURATION, "Index %u", (peeEventEntry->mMessage).InterfaceIndex);
return NO_ERROR; } #endif // DEBUG
DWORD EnqueueEvent( IN ROUTING_PROTOCOL_EVENTS rpeEvent, IN MESSAGE mMessage) /*++
Routine Description Queues an event entry in g_ce.lqEventQueue.
Locks Locks and unlocks the locked queue g_ce.lqEventQueue.
Arguments rpeEvent mMessage
Return Value NO_ERROR success Error Code o/w
--*/ { DWORD dwErr = NO_ERROR; PEVENT_ENTRY peeEntry = NULL;
dwErr = EE_Create(rpeEvent, mMessage, &peeEntry); // destroyed in EE_DequeueEvent
if (dwErr is NO_ERROR) { ACQUIRE_QUEUE_LOCK(&(g_ce.lqEventQueue)); Enqueue(&(g_ce.lqEventQueue.head), &(peeEntry->qeEventQueueLink));
RELEASE_QUEUE_LOCK(&(g_ce.lqEventQueue)); } return dwErr; }
DWORD DequeueEvent( OUT ROUTING_PROTOCOL_EVENTS *prpeEvent, OUT MESSAGE *pmMessage) /*++
Routine Description Dequeues an event entry from g_ce.lqEventQueue.
Locks Locks and unlocks the locked queue g_ce.lqEventQueue.
Arguments prpeEvent pmMessage
Return Value NO_ERROR success ERROR_NO_MORE_ITEMS o/w
--*/ { DWORD dwErr = NO_ERROR; PQUEUE_ENTRY pqe = NULL; PEVENT_ENTRY pee = NULL;
ACQUIRE_QUEUE_LOCK(&(g_ce.lqEventQueue));
do // breakout loop
{ if (IsQueueEmpty(&(g_ce.lqEventQueue.head))) { dwErr = ERROR_NO_MORE_ITEMS; TRACE0(CONFIGURATION, "Error no events in the queue"); LOGWARN0(EVENT_QUEUE_EMPTY, dwErr); break; }
pqe = Dequeue(&(g_ce.lqEventQueue.head));
pee = CONTAINING_RECORD(pqe, EVENT_ENTRY, qeEventQueueLink); *(prpeEvent) = pee->rpeEvent; *(pmMessage) = pee->mMessage;
// created in EE_EnqueueEvent
EE_Destroy(pee); pee = NULL; } while (FALSE);
RELEASE_QUEUE_LOCK(&(g_ce.lqEventQueue)); return dwErr; }
DWORD CE_Create ( IN PCONFIGURATION_ENTRY pce) /*++
Routine Description Creates a configuration entry on DLL_PROCESS_ATTACH.
Locks None
Arguments pce pointer to the configuration entry
Return Value NO_ERROR if success Failure code o/w
--*/ { DWORD dwErr = NO_ERROR;
// initialize to default values
ZeroMemory(pce, sizeof(CONFIGURATION_ENTRY)); pce->dwTraceID = INVALID_TRACEID; do // breakout loop
{ // initialize the read-write lock
CREATE_READ_WRITE_LOCK(&(pce->rwlLock)); if (!READ_WRITE_LOCK_CREATED(&(pce->rwlLock))) { dwErr = GetLastError(); TRACE1(CONFIGURATION, "Error %u creating read-write-lock", dwErr); LOGERR0(CREATE_RWL_FAILED, dwErr);
break; }
// initialize the global heap
pce->hGlobalHeap = HeapCreate(0, 0, 0); if (pce->hGlobalHeap is NULL) { dwErr = GetLastError(); TRACE1(CONFIGURATION, "Error %u creating global heap", dwErr); LOGERR0(HEAP_CREATE_FAILED, dwErr);
break; }
//
// initialize the count of threads that are active in IPSAMPLE
// create the semaphore released by each thread when it is done
// required for clean stop to the protocol
//
pce->ulActivityCount = 0; pce->hActivitySemaphore = CreateSemaphore(NULL, 0, 0xfffffff, NULL); if (pce->hActivitySemaphore is NULL) { dwErr = GetLastError(); TRACE1(CONFIGURATION, "Error %u creating semaphore", dwErr); LOGERR0(CREATE_SEMAPHORE_FAILED, dwErr); break; }
// Logging & Tracing Information
pce->dwLogLevel = IPSAMPLE_LOGGING_INFO; pce->hLogHandle = RouterLogRegister("IPSAMPLE"); pce->dwTraceID = TraceRegister("IPSAMPLE");
// Event Queue
INITIALIZE_LOCKED_QUEUE(&(pce->lqEventQueue)); if (!LOCKED_QUEUE_INITIALIZED(&(pce->lqEventQueue))) { dwErr = GetLastError(); TRACE1(CONFIGURATION, "Error %u initializing locked queue", dwErr); LOGERR0(INIT_CRITSEC_FAILED, dwErr); break; }
// Protocol State
pce->iscStatus = IPSAMPLE_STATUS_STOPPED;
// Store of Dynamic Locks
// pce->dlsDynamicLocksStore zero'ed out
// Timer Entry
// pce->hTimerQueue = NULL;
// Router Manager Information (later)
// pce->hMgrNotificationEvent = NULL
// pce->sfSupportFunctions zero'ed out
// RTMv2 Information
// pce->reiRtmEntity zero'ed out
// pce->rrpRtmProfile zero'ed out
// pce->hRtmHandle = NULL
// pce->hRtmNotificationHandle = NULL
// MGM Information
// pce->hMgmHandle = NULL
// Network Entry
// pce->pneNetworkEntry = NULL;
// Global Statistics
// pce->igsStats zero'ed out
} while (FALSE);
if (dwErr != NO_ERROR) { // something went wrong, so cleanup.
TRACE0(CONFIGURATION, "Failed to create configuration entry"); CE_Destroy(pce); } return dwErr; }
DWORD CE_Destroy ( IN PCONFIGURATION_ENTRY pce) /*++
Routine Description Destroys a configuration entry on DLL_PROCESS_DEATTACH
Locks Assumes exclusive access to rwlLock with no waiting thread.
Arguments pce pointer to the configuration entry
Return Value NO_ERROR always
--*/ { // Network Entry
// MGM Information
// RTMv2 Information
// Router Manager Information
// Timer Entry
// Store of Dynamic Locks
// protocol state should be such...
RTASSERT(pce->iscStatus is IPSAMPLE_STATUS_STOPPED);
// Event Queue
if (LOCKED_QUEUE_INITIALIZED(&(pce->lqEventQueue))) DELETE_LOCKED_QUEUE((&(pce->lqEventQueue)), FreeEventEntry); // Logging & Tracing Information
if (pce->dwTraceID != INVALID_TRACEID) { TraceDeregister(pce->dwTraceID); pce->dwTraceID = INVALID_TRACEID; } if (pce->hLogHandle != NULL) { RouterLogDeregister(pce->hLogHandle); pce->hLogHandle = NULL; }
// destroy the semaphore released by each thread when it is done
if (pce->hActivitySemaphore != NULL) { CloseHandle(pce->hActivitySemaphore); pce->hActivitySemaphore = NULL; }
if (pce->hGlobalHeap != NULL) { HeapDestroy(pce->hGlobalHeap); pce->hGlobalHeap = NULL; }
// delete the read-write lock
if (READ_WRITE_LOCK_CREATED(&(pce->rwlLock))) DELETE_READ_WRITE_LOCK(&(pce->rwlLock));
return NO_ERROR; }
DWORD CE_Initialize ( IN PCONFIGURATION_ENTRY pce, IN HANDLE hMgrNotificationEvent, IN PSUPPORT_FUNCTIONS psfSupportFunctions, IN PIPSAMPLE_GLOBAL_CONFIG pigc) /*++
Routine Description Initializes a configuration entry on StartProtocol.
Locks Assumes exclusive access to pce->rwlLock
Arguments pce pointer to the configuration entry hMgrNotificationEvent event used to notify ip router manager psfSupportFunctions functions exported by ip router manager pigc global configuration set in registry Return Value NO_ERROR if success Failure code o/w
--*/ { WORD wVersionRequested = MAKEWORD(1,1); WSADATA wsaData; BOOL bCleanupWinsock = FALSE; DWORD dwErr = NO_ERROR;
// validate environment
RTASSERT(pce->ulActivityCount is 0); RTASSERT(pce->iscStatus is IPSAMPLE_STATUS_STOPPED); do // breakout loop
{ pce->ulActivityCount = 0; pce->dwLogLevel = pigc->dwLoggingLevel;
dwErr = (DWORD) WSAStartup(wVersionRequested, &wsaData); if (dwErr != 0) { TRACE1(CONFIGURATION, "Error %u starting windows sockets", dwErr); LOGERR0(WSASTARTUP_FAILED, dwErr); break; } bCleanupWinsock = TRUE;
// Store of Dynamic Locks
dwErr = InitializeDynamicLocksStore(&(pce->dlsDynamicLocksStore), GLOBAL_HEAP); if (dwErr != NO_ERROR) { TRACE1(CONFIGURATION, "Error %u initializing locks store", dwErr); LOGERR0(INIT_CRITSEC_FAILED, dwErr); break; }
// Timer Entry
pce->hTimerQueue = CreateTimerQueue(); if (!pce->hTimerQueue) { dwErr = GetLastError(); TRACE1(CONFIGURATION, "Error %u registering timer queue", dwErr); LOGERR0(CREATE_TIMER_QUEUE_FAILED, dwErr); break; }
// Router Manager Information
pce->hMgrNotificationEvent = hMgrNotificationEvent; if (psfSupportFunctions) pce->sfSupportFunctions = *psfSupportFunctions;
// RTMv2 Information
pce->reiRtmEntity.RtmInstanceId = 0; pce->reiRtmEntity.AddressFamily = AF_INET; pce->reiRtmEntity.EntityId.EntityProtocolId = PROTO_IP_SAMPLE; pce->reiRtmEntity.EntityId.EntityInstanceId = 0;
dwErr = RTM_RegisterEntity( &pce->reiRtmEntity, // IN my RTM_ENTITY_INFO
NULL, // IN my exported methods
RTM_CallbackEvent, // IN my callback function
TRUE, // IN reserve opaque pointer?
&pce->rrpRtmProfile, // OUT my RTM_REGN_PROFILE
&pce->hRtmHandle); // OUT my RTMv2 handle
if (dwErr != NO_ERROR) { TRACE1(CONFIGURATION, "Error %u registering with RTM", dwErr); LOGERR0(RTM_REGISTER_FAILED, dwErr); break; }
dwErr = RTM_RegisterForChangeNotification( pce->hRtmHandle, // IN my RTMv2 handle
RTM_VIEW_MASK_MCAST, // IN route table views relevant to moi
RTM_CHANGE_TYPE_BEST, // IN change types interesting to moi
NULL, // IN context in callback function
&pce->hRtmNotificationHandle); // OUT my notification handle
if (dwErr != NO_ERROR) { TRACE1(CONFIGURATION, "Error %u registering for change with RTM", dwErr); LOGERR0(RTM_REGISTER_FAILED, dwErr); break; }
// MGM Information
// pce->hMgmHandle (later)
// Network Entry
dwErr = NE_Create(&(pce->pneNetworkEntry)); if (dwErr != NO_ERROR) break;
// Global Statistics
ZeroMemory(&(pce->igsStats), sizeof(IPSAMPLE_GLOBAL_STATS));
pce->iscStatus = IPSAMPLE_STATUS_RUNNING; } while (FALSE);
// something went wrong, cleanup
if (dwErr != NO_ERROR) CE_Cleanup(pce, bCleanupWinsock);
return dwErr; }
DWORD CE_Cleanup ( IN PCONFIGURATION_ENTRY pce, IN BOOL bCleanupWinsock) /*++
Routine Description Cleans up a configuration entry on StopProtocol.
Locks Exclusive access to pce->rwlLock by virtue of no competing threads.
NOTE: However, pce->rwlLock should NOT actually be held! The call to DeleteTimerQueueEx blocks till all queued callbacks finish execution. These callbacks may acquire pce->rwlLock, causing deadlock. Arguments pce pointer to the configuration entry bCleanupWinsock Return Value NO_ERROR always
--*/ { DWORD dwErr = NO_ERROR;
// Network Entry
NE_Destroy(pce->pneNetworkEntry); pce->pneNetworkEntry = NULL;
// MGM Information (later)
pce->hMgmHandle = NULL;
// RTMv2 Information
if (pce->hRtmNotificationHandle) { dwErr = RTM_DeregisterFromChangeNotification( pce->hRtmHandle, pce->hRtmNotificationHandle);
if (dwErr != NO_ERROR) TRACE1(CONFIGURATION, "Error %u deregistering for change from RTM", dwErr); } pce->hRtmNotificationHandle = NULL;
if (pce->hRtmHandle) { dwErr = RTM_DeregisterEntity(pce->hRtmHandle);
if (dwErr != NO_ERROR) TRACE1(CONFIGURATION, "Error %u deregistering from RTM", dwErr); } pce->hRtmHandle = NULL;
// Router Manager Information
// valid till overwritten, needed to signal the ip router manager
// pce->hMgrNotificationEvent
// pce->sfSupportFunctions
// Timer Entry
if (pce->hTimerQueue) DeleteTimerQueueEx(pce->hTimerQueue, INVALID_HANDLE_VALUE); pce->hTimerQueue = NULL;
// Store of Dynamic Locks
if (DYNAMIC_LOCKS_STORE_INITIALIZED(&(pce->dlsDynamicLocksStore))) { dwErr = DeInitializeDynamicLocksStore(&(pce->dlsDynamicLocksStore));
// all dynamic locks should have been free
RTASSERT(dwErr is NO_ERROR); }
if (bCleanupWinsock) WSACleanup(); // protocol state
pce->iscStatus = IPSAMPLE_STATUS_STOPPED;
return NO_ERROR; }
#ifdef DEBUG
DWORD CE_Display ( IN PCONFIGURATION_ENTRY pce) /*++
Routine Description Displays a configuration entry.
Locks Acquires shared pce->rwlLock Releases pce->rwlLock
Arguments pce pointer to the configuration entry to be displayed
Return Value NO_ERROR always
--*/ { if (!pce) return NO_ERROR;
ACQUIRE_READ_LOCK(&(pce->rwlLock)); TRACE0(CONFIGURATION, "Configuration Entry...");
TRACE3(CONFIGURATION, "ActivityCount %u, LogLevel %u, NumInterfaces %u", pce->ulActivityCount, pce->dwLogLevel, pce->igsStats.ulNumInterfaces);
NE_Display(pce->pneNetworkEntry);
RELEASE_READ_LOCK(&(pce->rwlLock));
TRACE0(CONFIGURATION, "EventQueue..."); ACQUIRE_QUEUE_LOCK(&(pce->lqEventQueue)); MapCarQueue(&((pce->lqEventQueue).head), DisplayEventEntry); RELEASE_QUEUE_LOCK(&(pce->lqEventQueue));
return NO_ERROR; } #endif // DEBUG
|