windows-nt/Source/XPSP1/NT/net/wins/server/msc/winsque.c
2020-09-26 16:20:57 +08:00

1727 lines
37 KiB
C

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
queue.c
Abstract:
Contains functions for queuing and dequeuing to/from the various
work queues
Functions:
QueInsertNbtWrkItm
QueRemoveNbtWrkItm
QueInsertChlReqWrkItm
QueRemoveChlReqWrkItm
QueInsertChlRspWrkItm
QueRemoveChlRspWrkItm
QueInsertWrkItm
QueGetWrkItm
QueAllocWrkItm
QueDeallocWrkItm
QueInsertWrkItmAtHdOfList
Portability:
This module is portable
Author:
Pradeep Bahl (pradeepb) 18-Nov-1992
Revision History:
Modification date Person Description of modification
----------------- ------- ----------------------------
--*/
/*
* Includes
*/
#include "wins.h"
#include "comm.h"
//#include "winsque.h"
#include "nms.h"
#include "nmsdb.h"
#include "nmschl.h"
#include "winsmsc.h"
#include "winsevt.h"
#include "rplpush.h"
#include "rplmsgf.h"
#include "winsque.h"
/*
* Local Macro Declarations
*/
/*
* Local Typedef Declarations
*/
/*
* Global Variable Definitions
*/
//
// The various queue heads
//
QUE_HD_T QueNbtWrkQueHd; //head for nbt req queue
#if REG_N_QUERY_SEP > 0
QUE_HD_T QueOtherNbtWrkQueHd; //head for nbt req queue
#endif
DWORD QueOtherNbtWrkQueMaxLen;
QUE_HD_T QueRplPullQueHd; //head for rpl pull thread's queue
QUE_HD_T QueRplPushQueHd; //head for rpl push thread's queue
QUE_HD_T QueNmsNrcqQueHd; //head for challenge queue used by NBT
QUE_HD_T QueNmsRrcqQueHd; //head for challenge queue used by Replicator
QUE_HD_T QueNmsCrqQueHd; //head for response queue to challenges sent
QUE_HD_T QueWinsTmmQueHd; //head for timer manager's queue
QUE_HD_T QueWinsScvQueHd; //head for Scavenger's queue
QUE_HD_T QueInvalidQueHd; //head for an invalid queue
HANDLE QueBuffHeapHdl; //handle to heap for use for nbt queue items
/*
* Local Variable Definitions
*/
/*
pWinsQueQueHd
Array indexed by the enumerator QUE_TYP_E values. This array
maps the QUE_TYP_E to the address of the queue head
*/
PQUE_HD_T pWinsQueQueHd[QUE_E_TOTAL_NO_QS] = {
&QueNbtWrkQueHd, //nbt requests
#if REG_N_QUERY_SEP > 0
&QueOtherNbtWrkQueHd, //nbt requests
#endif
&QueRplPullQueHd, //Pull requests
&QueRplPushQueHd, //Push requests
&QueNmsNrcqQueHd, //Chl request from nbt thds
&QueNmsRrcqQueHd, //Chl req. from Pull thd
&QueNmsCrqQueHd, //Chl rsp from UDP thd
&QueWinsTmmQueHd, //timer queue
&QueWinsScvQueHd, //Scavenger queue
&QueInvalidQueHd
};
STATIC fsChlWaitForRsp = FALSE;
CHECK("The timer queue may not be a PLIST_ENTRY queue. We may not")
CHECK("just insert the work item at the end")
/*
* Local Function Prototype Declarations
*/
STATIC
BOOL
ChlRspDropped(
MSG_T pMsg
);
//
// Function definitions start here
//
STATUS
QueInsertNbtWrkItm(
IN PCOMM_HDL_T pDlgHdl,
IN MSG_T pMsg,
IN MSG_LEN_T MsgLen
)
/*++
Routine Description:
This function inserts a work item on the nbt request queue
Arguments:
pDlgHdl - Handle to dialogue under which the nbt request was received
pMsg - Nbt work item
MsgLen - Size of work item
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
QueNbtReq in nms.c
Side Effects:
Comments:
None
--*/
{
PNBT_REQ_WRK_ITM_T pNbtWrkItm = NULL;
STATUS RetStat;
QueAllocWrkItm(
QueBuffHeapHdl,
sizeof(NBT_REQ_WRK_ITM_T),
(LPVOID *)&pNbtWrkItm
);
pNbtWrkItm->DlgHdl = *pDlgHdl;
pNbtWrkItm->pMsg = pMsg;
pNbtWrkItm->MsgLen = MsgLen;
RetStat = QueInsertWrkItm(
(PLIST_ENTRY)pNbtWrkItm,
QUE_E_NBT_REQ,
NULL /*ptr to que head*/
);
return(RetStat);
}
STATUS
QueRemoveNbtWrkItm(
OUT PCOMM_HDL_T pDlgHdl,
OUT PMSG_T ppMsg,
OUT PMSG_LEN_T pMsgLen
)
/*++
Routine Description:
This function removes a work item from the nbt queue.
Arguments:
pDlgHdl - Handle to dialogue of nbt request dequeued
pMsg - Nbt work item
MsgLen - Size of work item
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
NbtThdInitFn() in nms.c
Side Effects:
Comments:
None
--*/
{
PNBT_REQ_WRK_ITM_T pNbtWrkItm = NULL;
STATUS RetStat;
RetStat = QueGetWrkItm(QUE_E_NBT_REQ, &pNbtWrkItm);
if (RetStat != WINS_SUCCESS)
{
*ppMsg = NULL;
}
else
{
*ppMsg = pNbtWrkItm->pMsg;
*pMsgLen = pNbtWrkItm->MsgLen;
*pDlgHdl = pNbtWrkItm->DlgHdl;
QueDeallocWrkItm( QueBuffHeapHdl, pNbtWrkItm );
}
return(RetStat);
}
#if REG_N_QUERY_SEP > 0
STATUS
QueInsertOtherNbtWrkItm(
IN PCOMM_HDL_T pDlgHdl,
IN MSG_T pMsg,
IN MSG_LEN_T MsgLen
)
/*++
Routine Description:
This function inserts a work item on the nbt request queue
Arguments:
pDlgHdl - Handle to dialogue under which the nbt request was received
pMsg - Nbt work item
MsgLen - Size of work item
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
QueNbtReq in nms.c
Side Effects:
Comments:
None
--*/
{
PNBT_REQ_WRK_ITM_T pNbtWrkItm = NULL;
STATUS RetStat;
static BOOL SpoofingStarted = FALSE;
QueAllocWrkItm(
QueBuffHeapHdl,
sizeof(NBT_REQ_WRK_ITM_T),
(LPVOID *)&pNbtWrkItm
);
pNbtWrkItm->DlgHdl = *pDlgHdl;
pNbtWrkItm->pMsg = pMsg;
pNbtWrkItm->MsgLen = MsgLen;
RetStat = QueInsertWrkItm(
(PLIST_ENTRY)pNbtWrkItm,
QUE_E_OTHER_NBT_REQ,
NULL /*ptr to que head*/
);
//
// If the queue is full, the request was not inserted, so
// drop it. Log an event after every 100 requests have
// been dropped
//
if (RetStat == WINS_QUEUE_FULL)
{
static DWORD sNoOfReqSpoofed = 0;
static DWORD sBlockOfReq = 1;
#if DBG
static DWORD sNoOfReqDropped = 0;
#endif
if (!WinsCnf.fDoSpoofing)
{
#if DBG
NmsRegReqQDropped++;
if (sNoOfReqDropped++ == 5000)
{
sNoOfReqDropped = 0;
DBGPRINT1(ERR, "ENmsHandleMsg: REG QUEUE FULL. REQUESTS DROPPED = (%d\n", NmsRegReqQDropped);
}
#endif
//
// NOTE : freeing the buffers here takes away from modularity aspects
// of code but saves us cycles on the critical path
//
ECommFreeBuff(pMsg);
ECommEndDlg(pDlgHdl);
}
else
{
//
// we respond to groups of 300
// refresh/reg requests with a refresh interval of a multiple of
// 5 mts. The multiple is based on the group #. The refresh interval
// is not allowed to go over 1-2 hrs .
//
if (sNoOfReqSpoofed > 100)
{
if (sBlockOfReq == 10)
{
sBlockOfReq = 1;
}
else
{
sBlockOfReq++;
}
sNoOfReqSpoofed = 0;
}
else
{
sNoOfReqSpoofed++;
}
if (!SpoofingStarted)
{
WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_SPOOFING_STARTED);
SpoofingStarted = TRUE;
}
DBGPRINT1(DET, "QueInsertOtherNbtWrkItm: Spoofing - SpoofBlockNum %d\n", sBlockOfReq);
NmsMsgfSndNamRsp(pDlgHdl, pMsg, MsgLen, sBlockOfReq);
}
QueDeallocWrkItm( QueBuffHeapHdl, pNbtWrkItm );
}
if ((WINS_SUCCESS == RetStat) && SpoofingStarted && QueOtherNbtWrkQueHd.NoOfEntries < (QueOtherNbtWrkQueMaxLen >> 2))
{
WINSEVT_LOG_INFO_D_M(WINS_SUCCESS, WINS_EVT_SPOOFING_COMPLETED);
SpoofingStarted = FALSE;
}
return(RetStat);
}
STATUS
QueRemoveOtherNbtWrkItm(
OUT PCOMM_HDL_T pDlgHdl,
OUT PMSG_T ppMsg,
OUT PMSG_LEN_T pMsgLen
)
/*++
Routine Description:
This function removes a work item from the nbt queue.
Arguments:
pDlgHdl - Handle to dialogue of nbt request dequeued
pMsg - Nbt work item
MsgLen - Size of work item
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
NbtThdInitFn() in nms.c
Side Effects:
Comments:
None
--*/
{
PNBT_REQ_WRK_ITM_T pNbtWrkItm = NULL;
STATUS RetStat;
RetStat = QueGetWrkItm(QUE_E_OTHER_NBT_REQ, &pNbtWrkItm);
if (RetStat != WINS_SUCCESS)
{
*ppMsg = NULL;
}
else
{
*ppMsg = pNbtWrkItm->pMsg;
*pMsgLen = pNbtWrkItm->MsgLen;
*pDlgHdl = pNbtWrkItm->DlgHdl;
QueDeallocWrkItm( QueBuffHeapHdl, pNbtWrkItm );
}
return(RetStat);
}
#endif
STATUS
QueInsertChlReqWrkItm(
IN NMSCHL_CMD_TYP_E CmdTyp_e,
IN WINS_CLIENT_E Client_e,
IN PCOMM_HDL_T pDlgHdl,
IN MSG_T pMsg,
IN MSG_LEN_T MsgLen,
IN DWORD QuesNamSecLen,
IN PNMSDB_ROW_INFO_T pNodeToReg,
IN PNMSDB_STAT_INFO_T pNodeInCnf,
//IN PCOMM_ADD_T pAddOfNodeInCnf,
IN PCOMM_ADD_T pAddOfRemWins
)
/*++
Routine Description:
This function inserts a work item on the nbt request queue
Arguments:
pDlgHdl - Handle to dialogue under which the nbt request was received
pMsg - Nbt work item
MsgLen - Size of work item
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
NmsChlHdlNamReg
Side Effects:
Comments:
None
--*/
{
PCHL_REQ_WRK_ITM_T pWrkItm = NULL;
STATUS RetStat = WINS_SUCCESS;
DWORD Error = 0;
BOOL fLvCrtSec = FALSE;
DWORD i;
QueAllocWrkItm(
NmsChlHeapHdl,
sizeof(CHL_REQ_WRK_ITM_T),
(LPVOID *)&pWrkItm
);
pWrkItm->CmdTyp_e = CmdTyp_e;
pWrkItm->Client_e = Client_e;
if (pDlgHdl != NULL)
{
pWrkItm->DlgHdl = *pDlgHdl;
}
pWrkItm->pMsg = pMsg;
pWrkItm->MsgLen = MsgLen;
pWrkItm->QuesNamSecLen = QuesNamSecLen;
pWrkItm->NodeToReg = *pNodeToReg;
pWrkItm->NodeAddsInCnf.NoOfMems = pNodeInCnf->NodeAdds.NoOfMems;
for (i=0; i < pNodeInCnf->NodeAdds.NoOfMems; i++)
{
pWrkItm->NodeAddsInCnf.Mem[i] = pNodeInCnf->NodeAdds.Mem[i];
}
pWrkItm->NoOfAddsToUse = pNodeInCnf->NodeAdds.NoOfMems;
pWrkItm->NoOfAddsToUseSv = pNodeInCnf->NodeAdds.NoOfMems;
pWrkItm->OwnerIdInCnf = pNodeInCnf->OwnerId;
pWrkItm->fGroupInCnf = NMSDB_ENTRY_GRP_M(pNodeInCnf->EntTyp);
// pWrkItm->NodeTypInCnf = pNodeInCnf->NodeTyp;
// pWrkItm->EntTypInCnf = pNodeInCnf->EntTyp;
if (pNodeToReg->pNodeAdd != NULL)
{
pWrkItm->AddToReg = *(pNodeToReg->pNodeAdd);
}
if (pAddOfRemWins != NULL)
{
pWrkItm->AddOfRemWins = *pAddOfRemWins;
}
switch(Client_e)
{
case(WINS_E_NMSNMH):
pWrkItm->QueTyp_e = QUE_E_NMSNRCQ;
break;
case(WINS_E_RPLPULL):
pWrkItm->QueTyp_e = QUE_E_NMSRRCQ;
break;
default:
DBGPRINT0(ERR, "QueInsertChlWrkItm: Invalid Client\n");
WINSEVT_LOG_M(WINS_FAILURE, WINS_EVT_SFT_ERR);
break;
}
RetStat = QueInsertWrkItm(
(PLIST_ENTRY)pWrkItm,
pWrkItm->QueTyp_e,
NULL /*ptr to que head*/
);
return(RetStat);
}
STATUS
QueRemoveChlReqWrkItm(
IN HANDLE EvtHdl,
IN OUT LPVOID *ppaWrkItm,
OUT LPDWORD pNoOfReqs
)
/*++
Routine Description:
This function removes a work item from the nbt queue.
Arguments:
EvtHdl - handle of event signaled (not used currently)
ppaWrkItm - pointer to array of pointers (to work items) to
initialize
pNoOfReqs - No of Requests acquired (in the array pointed by
the ppaWrkItm arg
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ChlThdInitFn() in nmschl.c
Side Effects:
Comments:
None
--*/
{
STATUS RetStat = WINS_SUCCESS;
PQUE_HD_T pQueHd;
UNREFERENCED_PARAMETER(EvtHdl);
*pNoOfReqs = 0;
//
// EvtHdl is the handle of the event signaled. We don't use
// it since we always need to check the queues in the sequence
// Nrcq, Rrcq, Srcq irrespective of the event that got signaled.
//
// EvtHdl is passed as an input argument for future extensibility
//
// We could have had one critical section for both the queues but that
// could slow NBT threads due to replication. We don't
// want that.
//
//
// First check the NBT Request challenge queue
//
pQueHd = &QueNmsNrcqQueHd;
EnterCriticalSection(&pQueHd->CrtSec);
try {
//
// We have a limit to the number of nodes
// we will challenge at any one time
//
while (
(!IsListEmpty(&pQueHd->Head)) &&
(*pNoOfReqs < NMSCHL_MAX_CHL_REQ_AT_ONE_TIME)
)
{
*ppaWrkItm++ = RemoveHeadList(&pQueHd->Head);
(*pNoOfReqs)++;
}
}
finally {
LeaveCriticalSection(&pQueHd->CrtSec);
}
//
// if we have reached the limit return
//
if (*pNoOfReqs == NMSCHL_MAX_CHL_REQ_AT_ONE_TIME)
{
DBGPRINT0(CHL, "QueRemoveChlReqWrkItm: Limit reached with just nbt requests\n");
*ppaWrkItm = NULL; //delimiter to the list
return(WINS_SUCCESS);
}
//
// Now check the Replicator request challenge queue (populated
// by the Pull handler
//
pQueHd = &QueNmsRrcqQueHd;
EnterCriticalSection(&pQueHd->CrtSec);
try {
while(
(!IsListEmpty(&pQueHd->Head)) &&
(*pNoOfReqs < NMSCHL_MAX_CHL_REQ_AT_ONE_TIME)
)
{
*ppaWrkItm++ = RemoveHeadList(&pQueHd->Head);
(*pNoOfReqs)++;
}
}
finally {
LeaveCriticalSection(&pQueHd->CrtSec);
}
if (*pNoOfReqs == 0)
{
RetStat = WINS_NO_REQ;
}
else
{
*ppaWrkItm = NULL; //delimiter to the list
}
return(RetStat);
}
STATUS
QueInsertChlRspWrkItm(
IN PCOMM_HDL_T pDlgHdl,
IN MSG_T pMsg,
IN MSG_LEN_T MsgLen
)
/*++
Routine Description:
This function inserts a work item on the challenge response queue
Arguments:
pDlgHdl - Handle to dialogue under which the nbt response was received
pMsg - response message
MsgLen - response msg length
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ENmsHdlMsg in nms.c
Side Effects:
Comments:
None
--*/
{
PCHL_REQ_WRK_ITM_T pWrkItm = NULL;
STATUS RetStat = WINS_SUCCESS;
DWORD Error = 0;
if (!ChlRspDropped(pMsg))
{
QueAllocWrkItm(
NmsChlHeapHdl,
sizeof(CHL_RSP_WRK_ITM_T),
(LPVOID *)&pWrkItm
);
pWrkItm->DlgHdl = *pDlgHdl;
pWrkItm->pMsg = pMsg;
pWrkItm->MsgLen = MsgLen;
RetStat = QueInsertWrkItm(
(PLIST_ENTRY)pWrkItm,
QUE_E_NMSCRQ,
NULL /*ptr to que head*/
);
}
return(RetStat);
}
STATUS
QueRemoveChlRspWrkItm(
IN LPVOID *ppWrkItm
)
/*++
Routine Description:
This function removes a work item from the nbt queue.
Arguments:
ppaWrkItm - address of an array of pointers to chl request work items
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ChlThdInitFn() in nmschl.c
Side Effects:
Comments:
None
--*/
{
STATUS RetStat;
RetStat = QueGetWrkItm(QUE_E_NMSCRQ, ppWrkItm);
return(RetStat);
}
STATUS
QueInsertWrkItm (
IN PLIST_ENTRY pWrkItm,
IN OPTIONAL QUE_TYP_E QueTyp_e,
IN OPTIONAL PQUE_HD_T pQueHdPassed
)
/*++
Routine Description:
This function is called to queue a work item on
a queue. If the pQueHdPassed is Non NULL, the work item is queued
on that queue, else, it is queued on the queue specified by
QueTyp_e.
TMM will use pQueHdPassed to specify the queue while other clients
of the queue services will specify QueTyp_e
Arguments:
pWrkItm - Work Item to queue
QueTyp_e - Type of queue to queue it on (may or may not have valid value)
pQueHdPassed - Head of queue (may or may not be passed)
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ERplInsertQue, QueInsertNbtWrkItm
Side Effects:
Comments:
None
--*/
{
STATUS RetStat = WINS_SUCCESS;
PQUE_HD_T pQueHd = NULL;
// DWORD Error;
if (pQueHdPassed == NULL)
{
pQueHd = pWinsQueQueHd[QueTyp_e];
}
else
{
pQueHd = pQueHdPassed;
}
EnterCriticalSection(&pQueHd->CrtSec);
try {
//
// If we are surpassing the limit in the Reg/Ref/Rel queue,
// don't insert the wrk. item.
//
if ((pQueHd == &QueOtherNbtWrkQueHd) &&
(pQueHd->NoOfEntries > QueOtherNbtWrkQueMaxLen))
{
RetStat = WINS_QUEUE_FULL;
}
else
{
InsertTailList(&pQueHd->Head, pWrkItm);
pQueHd->NoOfEntries++;
if (!SetEvent(pQueHd->EvtHdl))
{
// Error = GetLastError();
RetStat = WINS_FAILURE;
}
}
}
finally {
LeaveCriticalSection(&pQueHd->CrtSec);
}
return(RetStat);
}
STATUS
QueGetWrkItm (
IN QUE_TYP_E QueTyp_e,
OUT LPVOID *ppWrkItm
)
/*++
Routine Description:
This function is called to dequeue a work item from
a queue
Arguments:
QueTyp_e - Type of queue to get the wrk item from
ppWrkItm - Work Item
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS or WINS_NO_REQ
Error status codes -- None at present
Error Handling:
Called by:
RplPullInit, QueNbtRemoveWrkItm
Side Effects:
Comments:
None
--*/
{
STATUS RetStat = WINS_SUCCESS;
PQUE_HD_T pQueHd;
pQueHd = pWinsQueQueHd[QueTyp_e];
EnterCriticalSection(&pQueHd->CrtSec);
try {
if (IsListEmpty(&pQueHd->Head))
{
*ppWrkItm = NULL;
RetStat = WINS_NO_REQ;
}
else
{
*ppWrkItm = RemoveHeadList(&pQueHd->Head);
pQueHd->NoOfEntries--;
}
}
finally {
LeaveCriticalSection(&pQueHd->CrtSec);
}
return(RetStat);
}
__inline
VOID
QueAllocWrkItm(
IN HANDLE HeapHdl,
IN DWORD Size,
OUT LPVOID *ppBuf
)
/*++
Routine Description:
This function allocates a work item. The work item is allocated
from a heap
Arguments:
ppBuf - Buffer (work item) allocated
Externals Used:
None
Return Value:
None
Error Handling:
Called by:
QueInsertNbtWrkItm
Side Effects:
Comments:
None
--*/
{
//
// WinsMscHeapAlloc will return an exception if it is not able to
// allocate a buffer. So there is no need to check the return value
// for NULL.
//
*ppBuf = WinsMscHeapAlloc(HeapHdl, Size );
return;
}
__inline
VOID
QueDeallocWrkItm(
IN HANDLE HeapHdl,
IN PVOID pBuff
)
/*++
Routine Description:
This function deallcoated a nbt request work item
Arguments:
pBuff - Nbt req. work item to deallocate
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- none currently
Error Handling:
Called by:
QueRemoveNbtWrkItm
Side Effects:
Comments:
None
--*/
{
WinsMscHeapFree(
HeapHdl,
pBuff
);
return;
}
STATUS
QueInsertWrkItmAtHdOfList (
IN PLIST_ENTRY pWrkItm,
IN QUE_TYP_E QueTyp_e,
IN PQUE_HD_T pQueHdPassed
)
/*++
Routine Description:
This function is called to queue a work item
at the head of a queue. If the pQueHdPassed is Non NULL,
the work item is queued on that queue, else, it is queued on
the queue specified by QueTyp_e.
TMM will use pQueHdPassed to specify the queue while other clients
of the queue services will specify QueTyp_e
Arguments:
pWrlItm - Work Item to queue
QueTyp_e - Type of queue to queue it on (may or may not have valid value)
pQueHdPassed - ListHead of queue (may or may not be passed)
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ProcRsp in nmschl.c
Side Effects:
Comments:
This function differs from QueInsertWrkItm in that it inserts
the work item at the head of a queue versus at the tail. I
prefered to create this function rather than have an extra
argument to QueInsertWrkItm to save an if test. QueInsertWrkItm
is used by the UDP listener thread and I want to do the minimum
work I can in that thread.
--*/
{
FUTURES("I may get rid of this function since it is very similar to QueInsertWrkItm")
STATUS RetStat = WINS_SUCCESS;
PQUE_HD_T pQueHd = NULL;
DWORD Error;
if (pQueHdPassed == NULL)
{
pQueHd = pWinsQueQueHd[QueTyp_e];
}
else
{
pQueHd = pQueHdPassed;
}
EnterCriticalSection(&pQueHd->CrtSec);
try {
InsertHeadList(&pQueHd->Head, pWrkItm);
if (!SetEvent(pQueHd->EvtHdl))
{
Error = GetLastError();
RetStat = WINS_FAILURE;
}
}
finally {
LeaveCriticalSection(&pQueHd->CrtSec);
}
#ifdef WINSDBG
NmsChlNoReqAtHdOfList++;
#endif
return(RetStat);
}
STATUS
QueInsertRplPushWrkItm (
IN PLIST_ENTRY pWrkItm,
IN BOOL fAlreadyInCrtSec
)
/*++
Routine Description:
This function is called to queue a work item on
the Push thread's queue.
Arguments:
pWrkItm - Work Item to queue
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ERplInsertQue
Side Effects:
Comments:
None
--*/
{
STATUS RetStat = WINS_SUCCESS;
PQUE_HD_T pQueHd = pWinsQueQueHd[QUE_E_RPLPUSH];
//
// if we are already in the critical section, no need to enter it
// again
//
if (!fAlreadyInCrtSec)
{
EnterCriticalSection(&pQueHd->CrtSec);
}
try {
//
// if the push thread does not exist, create it.
//
if (!fRplPushThdExists)
{
WinsThdPool.RplThds[WINSTHD_RPL_PUSH_INDEX].ThdHdl =
WinsMscCreateThd(
RplPushInit,
NULL,
&WinsThdPool.RplThds[WINSTHD_RPL_PUSH_INDEX].ThdId
);
fRplPushThdExists = TRUE;
WinsThdPool.RplThds[WINSTHD_RPL_PUSH_INDEX].fTaken = TRUE;
WinsThdPool.ThdCount++;
}
//
// Insert the work item and signal the thread.
//
InsertTailList(&pQueHd->Head, pWrkItm);
if (!SetEvent(pQueHd->EvtHdl))
{
WINSEVT_LOG_M(WINS_EVT_SFT_ERR, GetLastError());
RetStat = WINS_FAILURE;
}
}
except(EXCEPTION_EXECUTE_HANDLER) {
DWORD ExcCode = GetExceptionCode();
DBGPRINT1(EXC, "QueInsertRplPushWrkItm: Got exception (%d)\n",ExcCode);
//
// no need to log an event. WinsMscCreateThd logs it
//
}
//
// If we entered the critical section, we should get out of it
//
if (!fAlreadyInCrtSec)
{
LeaveCriticalSection(&pQueHd->CrtSec);
}
return(RetStat);
}
VOID
QueChlWaitForRsp(
VOID
)
{
EnterCriticalSection(&QueNmsCrqQueHd.CrtSec);
fsChlWaitForRsp = TRUE;
LeaveCriticalSection(&QueNmsCrqQueHd.CrtSec);
return;
}
VOID
QueChlNoWaitForRsp(
VOID
)
{
EnterCriticalSection(&QueNmsCrqQueHd.CrtSec);
fsChlWaitForRsp = FALSE;
LeaveCriticalSection(&QueNmsCrqQueHd.CrtSec);
return;
}
BOOL
ChlRspDropped(
MSG_T pMsg
)
{
BOOL fFreeBuff = FALSE;
EnterCriticalSection(&QueNmsCrqQueHd.CrtSec);
//
// If the challenge thread is not wait for responses, drop the
// datagram
//
if (!fsChlWaitForRsp)
{
fFreeBuff = TRUE;
}
LeaveCriticalSection(&QueNmsCrqQueHd.CrtSec);
if (fFreeBuff)
{
#ifdef WINSDBG
NmsChlNoRspDropped++;
#endif
ECommFreeBuff(pMsg);
return(TRUE);
}
return(FALSE);
}
STATUS
QueInsertNetNtfWrkItm (
IN PLIST_ENTRY pWrkItm
)
/*++
Routine Description:
This function is called to queue a push ntf work item on
the RPLPULL queue. It checks if there is another push ntf
work item from the same WINS on the queue. If there is, it is replaced
with this new one. This is done because the new one has more information
than the previous one. The old one is terminated to free up the connection.
Arguments:
pWrkItm - Work Item to queue
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ERplInsertQue, QueInsertNbtWrkItm
Side Effects:
Comments:
None
--*/
{
STATUS RetStat = WINS_SUCCESS;
PQUE_HD_T pQueHd = NULL;
PQUE_RPL_REQ_WRK_ITM_T pTmp;
COMM_IP_ADD_T IpAddNew;
COMM_IP_ADD_T IpAddInList;
BOOL fBreak = FALSE;
PRPL_CONFIG_REC_T pCnfRec;
//
// Get address of the WINS sending the notfication
//
pTmp = (PQUE_RPL_REQ_WRK_ITM_T)pWrkItm;
pCnfRec = pTmp->pClientCtx;
COMM_GET_IPADD_M(&pTmp->DlgHdl, &IpAddNew);
pQueHd = pWinsQueQueHd[QUE_E_RPLPULL];
EnterCriticalSection(&pQueHd->CrtSec);
try {
for(pTmp = (PQUE_RPL_REQ_WRK_ITM_T)pQueHd->Head.Flink;
pTmp != (PQUE_RPL_REQ_WRK_ITM_T)pQueHd;
pTmp = (PQUE_RPL_REQ_WRK_ITM_T)pTmp->Head.Flink)
{
if ( pTmp->CmdTyp_e == QUE_E_CMD_HDL_PUSH_NTF )
{
//
// Get address of the WINS that sent this notification
//
COMM_GET_IPADD_M(&pTmp->DlgHdl, &IpAddInList);
if (IpAddInList == IpAddNew)
{
DBGPRINT1(DET, "QueInsertNetNtfWrkItm: Found an earlier Net Ntf work item. Replacing it. WINS address = (%x)\n", IpAddInList);
//
// switch the work items since the new one takes precedence
// over the old one.
//
pWrkItm->Flink = pTmp->Head.Flink;
pWrkItm->Blink = pTmp->Head.Blink;
pTmp->Head.Blink->Flink = pWrkItm;
pTmp->Head.Flink->Blink = pWrkItm;
fBreak = TRUE;
break;
}
}
}
//
// If there was no match, insert at tail end of list
//
if (!fBreak)
{
InsertTailList(&pQueHd->Head, pWrkItm);
}
if (!SetEvent(pQueHd->EvtHdl))
{
// Error = GetLastError();
RetStat = WINS_FAILURE;
}
} // end of try
finally {
LeaveCriticalSection(&pQueHd->CrtSec);
}
//
// If we found a match, terminate the old work item
//
// Do this outside the critical section
//
if (fBreak)
{
CHECK("Can we avoid the try block")
try {
#if PRSCONN
RPLMSGF_MSG_OPCODE_E Opcode_e;
BOOL fPrsDlg;
#endif
#if PRSCONN
//
// If the ntf was sent on a persistent dlg, we do not terminate it since
// it will be terminated by the remote WINS when it so chooses. This
// dlg is used for multiple such notifications. If
// it was sent on a non-persistent dlg, we will terminate it since the
// remote WINS create a dlg for each such notification
//
RPLMSGF_GET_OPC_FROM_MSG_M(pTmp->pMsg, Opcode_e);
fPrsDlg = ((Opcode_e == RPLMSGF_E_UPDATE_NTF_PRS) || (Opcode_e == RPLMSGF_E_UPDATE_NTF_PROP_PRS));
if (!fPrsDlg)
{
ECommEndDlg(&pTmp->DlgHdl);
}
#else
ECommEndDlg(&pTmp->DlgHdl);
#endif
//
// Terminate the dequeued request.
//
ECommFreeBuff(pTmp->pMsg - COMM_HEADER_SIZE);
QueDeallocWrkItm(RplWrkItmHeapHdl, pTmp);
}
except (EXCEPTION_EXECUTE_HANDLER) {
DBGPRINTEXC("QueInsertNtfWrkItm");
}
}
return(RetStat);
}
STATUS
QueInsertSndNtfWrkItm (
IN PLIST_ENTRY pWrkItmp
)
/*++
Routine Description:
This function is called to queue a send push ntf work item on
the RPLPULL queue. It checks if there is another send push ntf
work item from the same WINS on the queue. If there is, it is replaced
with this new one. This is done because the new one has more information
than the previous one. The old one is terminated to free up the connection.
Arguments:
pWrkItm - Work Item to queue
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ERplInsertQue, QueInsertNbtWrkItm
Side Effects:
Comments:
None
--*/
{
STATUS RetStat = WINS_SUCCESS;
PQUE_HD_T pQueHd = NULL;
PQUE_RPL_REQ_WRK_ITM_T pTmp;
PQUE_RPL_REQ_WRK_ITM_T pWrkItm = (PQUE_RPL_REQ_WRK_ITM_T)pWrkItmp;
COMM_IP_ADD_T IpAddNew;
COMM_IP_ADD_T IpAddInList;
BOOL fBreak = FALSE;
PRPL_CONFIG_REC_T pCnfRec;
pTmp = (PQUE_RPL_REQ_WRK_ITM_T)pWrkItm;
pCnfRec = pTmp->pClientCtx;
IpAddNew = pCnfRec->WinsAdd.Add.IPAdd;
pQueHd = pWinsQueQueHd[QUE_E_RPLPULL];
EnterCriticalSection(&pQueHd->CrtSec);
try {
for(
pTmp = (PQUE_RPL_REQ_WRK_ITM_T)pQueHd->Head.Flink;
pTmp != (PQUE_RPL_REQ_WRK_ITM_T)pQueHd;
// no 3rd expression
)
{
//
// If this is a push ntf item, then go on to the next if test
//
if (( pTmp->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF ) ||
(pTmp->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF_PROP))
{
IpAddInList = ((PRPL_CONFIG_REC_T)(pTmp->pClientCtx))->WinsAdd.Add.IPAdd;
//
// If the push is to the same WINS, replace the work item
//
if (IpAddInList == IpAddNew)
{
if (pTmp->CmdTyp_e == QUE_E_CMD_SND_PUSH_NTF_PROP)
{
pWrkItm->CmdTyp_e = pTmp->CmdTyp_e;
}
DBGPRINT1(DET, "QueInsertSndNtfWrkItm: Found an earlier Snd Ntf work item. Replacing it. WINS address = (%x)\n", IpAddInList);
//
// switch the work items since the new one takes precedence
// over the old one.
//
pWrkItmp->Flink = pTmp->Head.Flink;
pWrkItmp->Blink = pTmp->Head.Blink;
pTmp->Head.Blink->Flink = pWrkItmp;
pTmp->Head.Flink->Blink = pWrkItmp;
fBreak = TRUE;
break;
}
}
pTmp = (PQUE_RPL_REQ_WRK_ITM_T)pTmp->Head.Flink;
}
if (!fBreak)
{
InsertTailList(&pQueHd->Head, pWrkItmp);
}
if (!SetEvent(pQueHd->EvtHdl))
{
// Error = GetLastError();
RetStat = WINS_FAILURE;
}
}
finally {
LeaveCriticalSection(&pQueHd->CrtSec);
//
// if we replaced an item, we need to deallocate it here.
//
if (fBreak)
{
QueDeallocWrkItm(RplWrkItmHeapHdl, pTmp);
}
}
return(RetStat);
}
__inline
STATUS
QueInsertScvWrkItm (
IN PLIST_ENTRY pWrkItm
)
/*++
Routine Description:
This function is called to queue a work item on
the Push thread's queue.
Arguments:
pWrkItm - Work Item to queue
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
ERplInsertQue
Side Effects:
Comments:
None
--*/
{
return(QueInsertWrkItm ( pWrkItm, QUE_E_WINSSCVQ, NULL));
}
__inline
STATUS
QueRemoveScvWrkItm(
IN OUT LPVOID *ppWrkItm
)
/*++
Routine Description:
This function removes a work item from the nbt queue.
Arguments:
ppWrkItm - pointer to array of pointers (to work items) to
initialize
Externals Used:
None
Return Value:
Success status codes -- WINS_SUCCESS
Error status codes -- WINS_FAILURE
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
return(QueGetWrkItm(QUE_E_WINSSCVQ, ppWrkItm));
}
VOID
WinsQueInit(
LPTSTR pName,
PQUE_HD_T pQueHd
)
/*++
Routine Description:
Function to init a queue
Arguments:
Externals Used:
None
Return Value:
Success status codes --
Error status codes --
Error Handling:
Called by:
Side Effects:
Comments:
None
--*/
{
//
// Create the response event handle. This event is signaled
// by the UDP listener thread when it stores a response
// in the spReqWrkItmArr array
//
WinsMscCreateEvt(
pName,
FALSE, //auto-reset
&pQueHd->EvtHdl
);
//
// Initialize the critical section for the response queue
//
InitializeCriticalSection(&pQueHd->CrtSec);
//
//Initialize the queue head for the response queue
//
InitializeListHead(&pQueHd->Head);
pQueHd->NoOfEntries = 0; //not required really since QueHd structures
//are externs
return;
}