windows-nt/Source/XPSP1/NT/net/rras/ip/sample/configentry.c
2020-09-26 16:20:57 +08:00

760 lines
17 KiB
C

/*++
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