|
|
/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
ripmain.c
Abstract:
Contains the rcv and worker threads
Author:
Stefan Solomon 07/06/1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
DWORD APIENTRY RegisterProtocol( IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar, IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar );
DWORD APIENTRY StartProtocol( IN HANDLE hMgrNotifyEvent, IN PSUPPORT_FUNCTIONS pSupportFunctions, IN PVOID pConfig );
DWORD APIENTRY StopProtocol( VOID );
DWORD APIENTRY GetGlobalInfo( IN OUT PVOID pConfig, IN OUT PDWORD pdwSize );
DWORD APIENTRY SetGlobalInfo( IN PVOID pConfig );
DWORD APIENTRY AddInterface( IN PWCHAR pwszInterfaceName, IN DWORD dwIndex, IN NET_INTERFACE_TYPE dwIfType, IN PVOID pConfig );
DWORD APIENTRY DeleteInterface( IN DWORD dwIndex );
DWORD APIENTRY GetEventMessage( OUT ROUTING_PROTOCOL_EVENTS *pEvent, OUT MESSAGE *pResult );
DWORD APIENTRY GetInterfaceConfigInfo( IN DWORD dwIndex, IN OUT PVOID pConfig, IN OUT PDWORD pdwSize );
DWORD APIENTRY SetInterfaceConfigInfo( IN DWORD dwIndex, IN PVOID pConfig );
DWORD APIENTRY BindInterface( IN DWORD dwIndex, IN PVOID pBinding );
DWORD APIENTRY UnbindInterface( IN DWORD dwIndex );
DWORD APIENTRY EnableInterface( IN DWORD dwIndex );
DWORD APIENTRY DisableInterface( IN DWORD dwIndex );
DWORD APIENTRY DoUpdateRoutes( IN DWORD dwIndex );
DWORD APIENTRY MibCreate( IN DWORD dwInputSize, IN PVOID pInputData );
DWORD APIENTRY MibDelete( IN DWORD dwInputSize, IN PVOID pInputData );
DWORD APIENTRY MibGet( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData );
DWORD APIENTRY MibSet( IN DWORD dwInputSize, IN PVOID pInputData );
DWORD APIENTRY MibGetFirst( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData );
DWORD APIENTRY MibGetNext( IN DWORD dwInputSize, IN PVOID pInputData, IN OUT PDWORD pdwOutputSize, OUT PVOID pOutputData );
// Router Manager Notification Event
HANDLE RM_Event;
TCHAR ModuleName[MAX_PATH+1];
VOID WorkerThread(VOID);
DWORD CreateWorkerThreadObjects(VOID);
VOID DestroyWorkerThreadObjects(VOID);
VOID ProcessDequeuedIoPacket(DWORD ErrorCode, DWORD BytesTransferred, LPOVERLAPPED Overlappedp);
BOOL WINAPI IpxRipDllEntry(HINSTANCE hInstDll, DWORD fdwReason, LPVOID pReserved) { switch (fdwReason) { case DLL_PROCESS_ATTACH:
GetModuleFileName (hInstDll, ModuleName, sizeof (ModuleName)/sizeof (ModuleName[0])); SS_DBGINITIALIZE;
RipOperState = OPER_STATE_DOWN;
// Create the database lock
InitializeCriticalSection(&DbaseCritSec);
// Create the queues lock
InitializeCriticalSection(&QueuesCritSec);
// Create the RIP changed list lock
InitializeCriticalSection(&RipChangedListCritSec);
break;
case DLL_PROCESS_DETACH:
// delete the RIP changed list lock
DeleteCriticalSection(&RipChangedListCritSec);
// delete the database lock
DeleteCriticalSection(&DbaseCritSec);
// delete the queues lock
DeleteCriticalSection(&QueuesCritSec);
break;
default:
break; }
return TRUE; }
DWORD WINAPI RegisterProtocol( IN OUT PMPR_ROUTING_CHARACTERISTICS pRoutingChar, IN OUT PMPR_SERVICE_CHARACTERISTICS pServiceChar ) { if(pRoutingChar->dwProtocolId != IPX_PROTOCOL_RIP) { return ERROR_NOT_SUPPORTED; }
pServiceChar->fSupportedFunctionality = 0;
pRoutingChar->fSupportedFunctionality = (ROUTING | DEMAND_UPDATE_ROUTES);
pRoutingChar->pfnStartProtocol = StartProtocol; pRoutingChar->pfnStopProtocol = StopProtocol; pRoutingChar->pfnAddInterface = AddInterface; pRoutingChar->pfnDeleteInterface = DeleteInterface; pRoutingChar->pfnGetEventMessage = GetEventMessage; pRoutingChar->pfnGetInterfaceInfo = GetInterfaceConfigInfo; pRoutingChar->pfnSetInterfaceInfo = SetInterfaceConfigInfo; pRoutingChar->pfnBindInterface = BindInterface; pRoutingChar->pfnUnbindInterface = UnbindInterface; pRoutingChar->pfnEnableInterface = EnableInterface; pRoutingChar->pfnDisableInterface = DisableInterface; pRoutingChar->pfnGetGlobalInfo = GetGlobalInfo; pRoutingChar->pfnSetGlobalInfo = SetGlobalInfo; pRoutingChar->pfnMibCreateEntry = MibCreate; pRoutingChar->pfnMibDeleteEntry = MibDelete; pRoutingChar->pfnMibGetEntry = MibGet; pRoutingChar->pfnMibSetEntry = MibSet; pRoutingChar->pfnMibGetFirstEntry = MibGetFirst; pRoutingChar->pfnMibGetNextEntry = MibGetNext; pRoutingChar->pfnUpdateRoutes = DoUpdateRoutes;
return NO_ERROR; }
DWORD WINAPI StartProtocol(IN HANDLE NotificationEvent, IN PSUPPORT_FUNCTIONS SupportFunctions, IN PVOID GlobalInfo) { #define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
DWORD threadid, i; HANDLE ThreadHandle;
RipEventLogMask = ripGlobalInfo->EventLogMask; StartTracing();
Trace(INIT_TRACE, "StartProtocol: Entered\n");
ACQUIRE_DATABASE_LOCK; ACQUIRE_QUEUES_LOCK;
RipOperState = OPER_STATE_STARTING;
GetIpxRipRegistryParameters();
RM_Event = NotificationEvent;
//init the interfaces database
InitIfDbase();
//
// init all the queues
//
// InitializeListHead(&WorkersQueue);
InitializeListHead(&TimerQueue); InitializeListHead(&RepostRcvPacketsQueue); InitializeListHead(&RipMessageQueue);
// create the workers work items heap
if(CreateWorkItemsManager() != NO_ERROR) {
goto ErrorExit; }
// open the RIP socket for I/O
if(OpenRipSocket() != NO_ERROR) {
Trace(INIT_TRACE, "Cannot open RIP socket\n");
goto ErrorExit; }
if(! BindIoCompletionCallback(RipSocketHandle, ProcessDequeuedIoPacket, 0)) {
Trace(INIT_TRACE, "Cannot associate IO Completion Port\n");
goto ErrorExit; }
// create synchronization objects for the rip threads
if(CreateWorkerThreadObjects() != NO_ERROR) {
Trace(INIT_TRACE, "Cannot create synchronization objects\n");
goto ErrorExit; }
// Open RTM for RIP
if(OpenRTM()) {
Trace(INIT_TRACE, "Cannot open RTM\n");
goto ErrorExit; }
// create the Worker thread
if ((ThreadHandle = CreateThread( (LPSECURITY_ATTRIBUTES) NULL, 0, (LPTHREAD_START_ROUTINE) WorkerThread, NULL, 0, &threadid)) == NULL) {
// !!! log error cannot create the worker thread !!!
goto ErrorExit; } else CloseHandle (ThreadHandle);
RipOperState = OPER_STATE_UP;
RELEASE_QUEUES_LOCK; RELEASE_DATABASE_LOCK;
CreateStartChangesBcastWi();
Trace(INIT_TRACE, "Started successfully\n");
return NO_ERROR;
ErrorExit:
RELEASE_QUEUES_LOCK; RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE; #undef ripGlobalInfo
}
DWORD WINAPI StopProtocol(VOID) { PWORK_ITEM wip;
Trace(INIT_TRACE, "StopProtocol: Entered\n");
ACQUIRE_DATABASE_LOCK;
if(RipOperState != OPER_STATE_UP) {
SS_ASSERT(FALSE); goto ErrorExit; }
RipOperState = OPER_STATE_STOPPING;
// send interfaces shutdown work item to the workers
if((wip = AllocateWorkItem(SHUTDOWN_INTERFACES_TYPE)) == NULL) {
goto ErrorExit; }
wip->WorkItemSpecific.WIS_ShutdownInterfaces.ShutdownState = SHUTDOWN_START;
RtlQueueWorkItem(ProcessWorkItem, wip, 0);
RELEASE_DATABASE_LOCK;
return NO_ERROR;
ErrorExit:
RELEASE_DATABASE_LOCK;
return ERROR_CAN_NOT_COMPLETE; }
VOID WorkerThread(VOID) { DWORD rc; DWORD signaled_event, delay; ULONG dueTime = GetTickCount() + MAXULONG/2; PWORK_ITEM wip; PLIST_ENTRY lep; HANDLE hModuleReference;
hModuleReference = LoadLibrary (ModuleName); StartReceiver();
while(TRUE) { delay = dueTime - GetTickCount(); if(delay < MAXULONG/2) {
// dueTime is later then present time
while((rc = WaitForMultipleObjects( MAX_WORKER_THREAD_OBJECTS, WorkerThreadObjects, FALSE, // wait any
delay // timeout
)) == WAIT_IO_COMPLETION); } else { // dueTime already happened
rc = WAIT_TIMEOUT; }
if(rc == WAIT_TIMEOUT) {
dueTime = ProcessTimerQueue(); } else { signaled_event = rc - WAIT_OBJECT_0;
if(signaled_event < MAX_WORKER_THREAD_OBJECTS) {
switch(signaled_event) {
case TIMER_EVENT:
dueTime = ProcessTimerQueue(); break;
case REPOST_RCV_PACKETS_EVENT:
RepostRcvPackets(); break;
// case WORKERS_QUEUE_EVENT:
// dequeue only one item from the work items queue
// ACQUIRE_QUEUES_LOCK;
// while(!IsListEmpty(&WorkersQueue)) {
// lep = RemoveHeadList(&WorkersQueue);
// wip = CONTAINING_RECORD(lep, WORK_ITEM, Linkage);
// RELEASE_QUEUES_LOCK;
// Queue the work item for processing by the
// worker threads
// RtlQueueWorkItem(ProcessWorkItem,
// wip,
// WT_EXECUTEINIOTHREAD); // never dieing workers so we can do send submits
// and the thread won't die before send completes
// ACQUIRE_QUEUES_LOCK;
// }
// RELEASE_QUEUES_LOCK;
// break;
case RTM_EVENT:
ProcessRTMChanges(); break;
case RIP_CHANGES_EVENT:
ProcessRIPChanges(); break;
case TERMINATE_WORKER_EVENT:
// stop the StartChangesBcast work item
DestroyStartChangesBcastWi = TRUE;
// close the rip socket
CloseRipSocket();
FlushTimerQueue(); CloseRTM();
// wait until no more work items
while(WorkItemsCount != 0) {
Trace(INIT_TRACE, "Terminating: Waiting for work items to be freed: %d outstanding ...\n", WorkItemsCount);
Sleep(1000); }
// destroy worker thread objects
DestroyWorkerThreadObjects();
// destroy workers heap
DestroyWorkItemsManager();
// post stop complete message
PostEventMessage(ROUTER_STOPPED, NULL);
Trace(INIT_TRACE, "Terminating: Stop completed and STOP Event Message posted\n"); FreeLibraryAndExitThread(hModuleReference, 0); break;
default:
break; } } } } }
// table of handlers for work items which keep a reference to the if CB
typedef VOID (* IF_WORK_ITEM_HANDLER)(PWORK_ITEM wip);
IF_WORK_ITEM_HANDLER IfWorkItemHandler[] = {
IfPeriodicBcast, IfCompleteGenResponse, IfChangeBcast, IfCheckUpdateStatus, IfPeriodicGenRequest
};
#define MAX_IF_WORK_ITEM_HANDLERS sizeof(IfWorkItemHandler)/sizeof(IF_WORK_ITEM_HANDLER)
VOID ProcessWorkItem(PWORK_ITEM wip) { PLIST_ENTRY lep; PICB icbp;
switch(wip->Type) {
case RECEIVE_PACKET_TYPE:
// this work item references the interface via the adapter index
ACQUIRE_DATABASE_LOCK;
if(RipOperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK; } else { if((icbp = GetInterfaceByAdapterIndex(wip->AdapterIndex)) != NULL) {
wip->icbp = icbp;
ACQUIRE_IF_LOCK(icbp);
RELEASE_DATABASE_LOCK;
ProcessReceivedPacket(wip);
RELEASE_IF_LOCK(icbp); } else { RELEASE_DATABASE_LOCK; } }
// queue the receive packet back to recv thread for reposting
EnqueueRcvPacketToRepostQueue(wip);
break;
case START_CHANGES_BCAST_TYPE:
ACQUIRE_DATABASE_LOCK;
StartChangesBcast(wip);
RELEASE_DATABASE_LOCK;
break;
case SHUTDOWN_INTERFACES_TYPE:
ACQUIRE_DATABASE_LOCK;
ShutdownInterfaces(wip);
RELEASE_DATABASE_LOCK;
break;
case DEBUG_TYPE:
FreeWorkItem(wip); break;
default:
// all these work items reference the interface via an if CB pointer
icbp = wip->icbp;
ACQUIRE_IF_LOCK(icbp);
(*IfWorkItemHandler[wip->Type])(wip);
if(icbp->Discarded) {
RELEASE_IF_LOCK(icbp);
ACQUIRE_DATABASE_LOCK;
ACQUIRE_IF_LOCK(icbp);
if(--icbp->RefCount == 0) {
// remove the if CB from the discarded queue and free it
RemoveEntryList(&icbp->IfListLinkage);
// free the interface CB
Trace(INIT_TRACE, "ProcessWorkItem: Free DISCARDED if CB for if # %d\n", icbp->InterfaceIndex);
DestroyInterfaceCB(icbp); } else { RELEASE_IF_LOCK(icbp); }
RELEASE_DATABASE_LOCK; } else { icbp->RefCount--; RELEASE_IF_LOCK(icbp); } } }
DWORD WINAPI GetEventMessage(ROUTING_PROTOCOL_EVENTS *Event, PMESSAGE Result) { PRIP_MESSAGE emp; PLIST_ENTRY lep;
Trace(INIT_TRACE, "GetEventMessage: Entered\n");
ACQUIRE_DATABASE_LOCK;
if((RipOperState == OPER_STATE_DOWN) || (RipOperState == OPER_STATE_STARTING)) {
RELEASE_DATABASE_LOCK; return ERROR_CAN_NOT_COMPLETE; }
ACQUIRE_QUEUES_LOCK;
if(IsListEmpty(&RipMessageQueue)) {
RELEASE_QUEUES_LOCK;
RELEASE_DATABASE_LOCK; return ERROR_NO_MORE_ITEMS; }
lep = RemoveHeadList(&RipMessageQueue); emp = CONTAINING_RECORD(lep, RIP_MESSAGE, Linkage);
*Event = emp->Event; if(Result != NULL) {
*Result = emp->Result; }
if(emp->Event == ROUTER_STOPPED) {
RipOperState = OPER_STATE_DOWN; StopTracing(); }
GlobalFree(emp);
RELEASE_QUEUES_LOCK;
RELEASE_DATABASE_LOCK; return NO_ERROR; }
VOID PostEventMessage(ROUTING_PROTOCOL_EVENTS Event, PMESSAGE Result) { PRIP_MESSAGE emp;
if((emp = GlobalAlloc(GPTR, sizeof(RIP_MESSAGE))) == NULL) {
return; }
emp->Event = Event;
if(Result != NULL) {
emp->Result = *Result; }
ACQUIRE_QUEUES_LOCK;
InsertTailList(&RipMessageQueue, &emp->Linkage);
RELEASE_QUEUES_LOCK;
SetEvent(RM_Event); }
DWORD CreateWorkerThreadObjects(VOID) { int i;
for(i=0; i<MAX_WORKER_THREAD_OBJECTS; i++) {
if((WorkerThreadObjects[i] = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) { return ERROR_CAN_NOT_COMPLETE; } }
return NO_ERROR; }
VOID DestroyWorkerThreadObjects(VOID) { int i;
for(i=0; i<MAX_WORKER_THREAD_OBJECTS; i++) {
CloseHandle(WorkerThreadObjects[i]); } }
DWORD WINAPI SetGlobalInfo(PVOID GlobalInfo) { #define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
ACQUIRE_DATABASE_LOCK;
if(RipOperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK; return ERROR_CAN_NOT_COMPLETE; }
RipEventLogMask = ripGlobalInfo->EventLogMask; RELEASE_DATABASE_LOCK;
return NO_ERROR; #undef ripGlobalInfo
}
DWORD WINAPI GetGlobalInfo( IN PVOID GlobalInfo, IN OUT PULONG GlobalInfoSize ) { ACQUIRE_DATABASE_LOCK; if(RipOperState != OPER_STATE_UP) {
RELEASE_DATABASE_LOCK; return ERROR_CAN_NOT_COMPLETE; }
if ((*GlobalInfoSize>=sizeof (RIP_GLOBAL_INFO)) && (GlobalInfo!=NULL)) { #define ripGlobalInfo ((PRIP_GLOBAL_INFO)GlobalInfo)
ripGlobalInfo->EventLogMask = RipEventLogMask; #undef ripGlobalInfo
} *GlobalInfoSize = sizeof (RIP_GLOBAL_INFO);
RELEASE_DATABASE_LOCK; return NO_ERROR; }
VOID ProcessDequeuedIoPacket(DWORD ErrorCode, DWORD BytesTransferred, LPOVERLAPPED Overlappedp) { PWORK_ITEM wip;
wip = CONTAINING_RECORD(Overlappedp, WORK_ITEM, Overlapped); wip->IoCompletionStatus = (DWORD)Overlappedp->Internal;
switch(wip->Type) {
case RECEIVE_PACKET_TYPE:
ReceiveComplete(wip); break;
default:
SendComplete(wip); break; } }
|