THREAD.C

/*++ 

Copyright 1997 - 1998 Microsoft Corporation

Module Name:

sample\ip\thread.c

Abstract:
Functions related to the main processing thread

Revision History:


--*/

#include "sampinc.h"

VOID
Shutdown();

VOID
ProcessRouteChange();

VOID
ProcessReadNotification();

VOID
CleanupProtocol(
BOOL bWinsockLoaded
);

DWORD WINAPI
MainThread(
PVOID pvContext
)
/*++
Routine Description
This is the main thread created by the protocol. In general, an
implementor should avoid creating too many threads. A dedicated
thread should only be created if there is regular work that the
protocol needs to be doing. If the protocol is more "interrupt driven",
it is much better to use the WorkerFunction routines provided in
rtutils.h
The

Arguments
pvContext Unused

Return Value
NO_ERROR

--*/
{
DWORD dwRet, dwTimeOut;
ULONG ulPoll;
HANDLE hOwnModule;
HANDLE rgWaitObjects[NUM_WAIT_EVENTS] = {g_hStopProtocolEvent,
g_hRtmEvent,
g_hSocketEvent};


//
// The parameter is never used. The following macro
// kills lint/compiler warnings
//

UNREFERENCED_PARAMETER(pvContext);

//
// We dont need to EnterProtocolApi() for this thread
// since this is the thread that shuts the DLL down
//

//
// Now we try and load ourself. This is an NT trick to stop the OS loader
// from cleaning out the DLL from under you after you have SetEvent()
// Doing SetEvent() may cause another thread to execute which may then
// unload you. However you still have some epilogue code after the SetEvent()
// that needs to be executed. Putting a ref count on your DLL is a
// way of stopping this from happening
//

hOwnModule = NULL;

hOwnModule = LoadLibraryEx("IPRTSAMP.DLL",
NULL,
0);

if(hOwnModule == NULL)
{
Trace1(ERR,
"MainThread: Unable to load itself. May cause problems at stop. Error %d",
GetLastError());
}

//
// We initially block on the wait call. When we are told
// to stop, we go into a polling mode
//

dwTimeOut = INFINITE;
ulPoll = 0;

while(TRUE)
{
dwRet = WaitForMultipleObjectsEx(NUM_WAIT_EVENTS,
rgWaitObjects,
FALSE,
dwTimeOut,
TRUE);

switch(dwRet)
{
case WAIT_IO_COMPLETION:
{
break;
}

case WAIT_OBJECT_0: // Stop Protocol Event
{
//
// See if the number of threads in the DLL are down to 0
//

EnterCriticalSection(&g_csProtocolStateLock);

if(g_dwProtocolRefCount > 0)
{
//
// There is someone other than us in the DLL.
// We go into polling mode
//

dwTimeOut = 1000;

LeaveCriticalSection(&g_csProtocolStateLock);

break;
}

Shutdown();

LeaveCriticalSection(&g_csProtocolStateLock);

break;
}

case (WAIT_OBJECT_0 + 1): // RTM Event
{
ProcessRouteChange();

break;
}

case (WAIT_OBJECT_0 + 2): // Socket Event
{
ProcessReadNotification();

break;
}

case WAIT_TIMEOUT:
{
EnterCriticalSection(&g_csProtocolStateLock);

if(g_dwProtocolRefCount > 0)
{
ulPoll++;

if(ulPoll > 5)
{
//
// 5 seconds have gone by but there are still
// threads executing in our DLL. This is usually
// a sign of deadlock, or infinite looping
//

Trace1(ERR,
"MainThread: Ref count is not decreasing. Count is %d",
g_dwProtocolRefCount);
}

LeaveCriticalSection(&g_csProtocolStateLock);

break;
}

Shutdown();

LeaveCriticalSection(&g_csProtocolStateLock);

break;
}
}
}

if(hOwnModule)
{
//
// This is an atomic call that frees the library and
// returns from the thread.
//

FreeLibraryAndExitThread(hOwnModule,
NO_ERROR);
}

return NO_ERROR;
}

VOID
Shutdown()
/*++
Routine Description


Arguments


Return Value
NO_ERROR

--*/
{

TraceEnter("Shutdown");

CleanupProtocol(TRUE);


g_pmmStopMsg->rreEvent = ROUTER_STOPPED;

EnterCriticalSection(&g_csQueueLock);

InsertHeadList(&g_leMsgQueue,
&g_pmmStopMsg->leMsgLink);

LeaveCriticalSection(&g_csQueueLock);


g_dwProtocolState = PROTOCOL_STATE_STOPPED;

SetEvent(g_hMgrNotifyEvent);

TraceLeave("ShutDown");
}


VOID
ProcessRouteChange()
{
DWORD dwResult, dwFlags;

RTM_IP_ROUTE ripCurr, ripPrev;

dwResult = RtmDequeueRouteChangeMessage(g_hRtmHandle,
&dwFlags,
&ripCurr,
&ripPrev);

if(dwResult != NO_ERROR)
{
Trace1(ERR,
"ProcessRouteChange: Error %d dequeueing message from RTM",
dwResult);

return;
}

switch(dwFlags)
{
case RTM_ROUTE_ADDED:
{
Trace0(ROUTE,
"ProcessRouteChange: New route was added");

PrintRoute(ROUTE, &ripCurr);

break;
}

case RTM_ROUTE_DELETED:
{
Trace0(ROUTE,
"ProcessRouteChange: Old route was deleted");

PrintRoute(ROUTE, &ripPrev);

break;
}

case RTM_ROUTE_CHANGED:
{
Trace0(ROUTE,
"ProcessRouteChange: A best route was changed");

Trace0(ROUTE,
"Old route--");

PrintRoute(ROUTE, &ripPrev);

Trace0(ROUTE,
"New route--");

PrintRoute(ROUTE, &ripCurr);

break;
}
}
}

VOID
ProcessReadNotification()
{
PNT_IF pIf;
PINTRNL_IF pBind;
PRECEIVE_BUFFER prbBuffer;
DWORD dwFlags,dwBytesRead;
INT iRecvAddrLen;
PLIST_ENTRY pleNode1, pleNode2;

WSANETWORKEVENTS wsaNetworkEvents;
struct sockaddr_in siFrom;

EnterCriticalSection(&g_csIfListLock);

for(pleNode1 = g_leIfListHead.Flink;
pleNode1 != &g_leIfListHead;
pleNode1 = pleNode1->Flink)
{
pIf = CONTAINING_RECORD(pleNode1,
NT_IF,
leNtIfLink);


if(!IsNtEnabledAndBound(pIf))
{
continue;
}

for(pleNode2 = pIf->leInternalIfHead.Flink;
pleNode2 != &pIf->leInternalIfHead;
pleNode2 = pleNode2->Flink)
{
pBind = CONTAINING_RECORD(pleNode2, INTRNL_IF, leInternalIfLink);

if(pBind->sSocket == INVALID_SOCKET)
{
ASSERT(pBind->dwState != BINDING_UP);

continue;
}
}


if(WSAEnumNetworkEvents(pBind->sSocket,
(WSAEVENT)NULL,
&wsaNetworkEvents) == SOCKET_ERROR)
{
Trace1(ERR,
"ProcessRead: WSAEnumNetworkEvents() returned %d",
WSAGetLastError());

continue;
}

if(!(wsaNetworkEvents.lNetworkEvents & FD_READ))
{
//
// Read bit isnot set and we arent interested in
// anything else
//

continue;
}

if(wsaNetworkEvents.iErrorCode[FD_READ_BIT] != NO_ERROR)
{
Trace2(ERR,
"ProcessRead: Error %d associated with socket %d.%d.%d.%d for FD_READ",
wsaNetworkEvents.iErrorCode[FD_READ_BIT],
PRINT_ADDRESS(pBind->dwAddress));

continue;
}


//
// Create a buffer to receive data
//

prbBuffer = HeapAlloc(g_hPrivateHeap,
0,
sizeof(RECEIVE_BUFFER));


if(prbBuffer == NULL)
{
Trace1(ERR,
"ProcessRead: Error %d allocating memory for read buffer",
GetLastError());

continue;
}

prbBuffer->wbBuffer.buf = prbBuffer->rgbyData;

iRecvAddrLen = sizeof(struct sockaddr_in);

if(WSARecvFrom(pBind->sSocket,
&(prbBuffer->wbBuffer),
1,
&dwBytesRead,
&dwFlags,
(struct sockaddr *)&siFrom,
&iRecvAddrLen,
NULL,
NULL) != NO_ERROR)
{
Trace1(ERR,
"ProcessRead. Error %d reading data",
WSAGetLastError());

HeapFree(g_hPrivateHeap,
0,
prbBuffer);


continue;
}

//ValidateAndQueuePacket();


}

}