/*++

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;
}